diff -Nru fotoxx-11.11.1/debian/changelog fotoxx-12.01.2/debian/changelog --- fotoxx-11.11.1/debian/changelog 2011-11-07 22:49:42.000000000 +0000 +++ fotoxx-12.01.2/debian/changelog 2012-01-04 16:18:22.000000000 +0000 @@ -1,3 +1,12 @@ +fotoxx (12.01.2-0ubuntu1) precise; urgency=low + + * New upstream release. + * Refreshed patch: + - debian/patches/makefile_changes.patch + - debian/patches/docs_dir.patch + + -- Mahyuddin Susanto Wed, 04 Jan 2012 23:14:41 +0700 + fotoxx (11.11.1-1) unstable; urgency=low * New upstream release diff -Nru fotoxx-11.11.1/debian/control fotoxx-12.01.2/debian/control --- fotoxx-11.11.1/debian/control 2011-11-03 02:43:54.000000000 +0000 +++ fotoxx-12.01.2/debian/control 2012-01-04 16:18:37.000000000 +0000 @@ -1,7 +1,8 @@ Source: fotoxx Section: graphics Priority: extra -Maintainer: Santiago Torres Batan +Maintainer: Ubuntu Developers +XSBC-Original-Maintainer: Santiago Torres Batan Build-Depends: debhelper (>= 7), libgtk2.0-dev, libtiff4-dev Standards-Version: 3.9.2 Homepage: http://kornelix.squarespace.com/downloads/ diff -Nru fotoxx-11.11.1/debian/patches/docs_dir.patch fotoxx-12.01.2/debian/patches/docs_dir.patch --- fotoxx-11.11.1/debian/patches/docs_dir.patch 2011-11-07 23:35:24.000000000 +0000 +++ fotoxx-12.01.2/debian/patches/docs_dir.patch 2012-01-04 16:11:04.000000000 +0000 @@ -1,15 +1,16 @@ -Description: This patch edit the documentation's path for the program to use it. +Description: Description: This patch edit the documentation's path for the program to use it. Author: Santiago Torres Batán -Index: fotoxx-11.11.1/zfuncs.cc + +Index: fotoxx/zfuncs.cc =================================================================== ---- fotoxx-11.11.1.orig/zfuncs.cc 2011-11-07 20:20:38.000000000 -0300 -+++ fotoxx-11.11.1/zfuncs.cc 2011-11-07 20:31:07.000000000 -0300 -@@ -3117,7 +3117,7 @@ - strncatv(zdatadir,199,work,"/share/",zappname,"/data",null); // /installoc/share/appname/data - strncatv(zicondir,199,work,"/share/",zappname,"/icons",null); // /installoc/share/appname/icons - strncatv(zlocalesdir,199,work,"/share/",zappname,"/locales",null); // /installoc/share/appname/locales -- strncatv(zdocdir,199,work,"/share/doc/",zappname,null); // /installoc/share/doc/appname -+ strncatv(zdocdir,199,work,"/share/doc/",zappname,"/extras",null); // /installoc/share/doc/appname +--- fotoxx.orig/zfuncs.cc 2012-01-04 22:52:43.032487979 +0700 ++++ fotoxx/zfuncs.cc 2012-01-04 22:58:03.590077556 +0700 +@@ -3167,7 +3167,7 @@ + strncatv(zdatadir,199,work,"/share/",zappname,"/data",null); // /prefix/share/appname/data + strncatv(zicondir,199,work,"/share/",zappname,"/icons",null); // /prefix/share/appname/icons + strncatv(zlocalesdir,199,work,"/share/",zappname,"/locales",null); // /prefix/share/appname/locales +- strncatv(zdocdir,199,work,"/share/doc/",zappname,null); // /prefix/share/doc/appname ++ strncatv(zdocdir,199,work,"/share/doc/",zappname,"/extras", null); // /prefix/share/doc/appname snprintf(zuserdir,199,"%s/.%s",getenv("HOME"),zappname); // /home/user/.appname/ v.4.3 err = stat(zuserdir,&statdat); // does it exist already? diff -Nru fotoxx-11.11.1/debian/patches/makefile_changes.patch fotoxx-12.01.2/debian/patches/makefile_changes.patch --- fotoxx-11.11.1/debian/patches/makefile_changes.patch 2011-11-07 23:35:44.000000000 +0000 +++ fotoxx-12.01.2/debian/patches/makefile_changes.patch 2012-01-04 16:11:45.000000000 +0000 @@ -1,11 +1,10 @@ Desciption: This patch removes the usage of xgd-desktop-menu and the dependencies check (by dependencies.h) from the makefile. Author: Santiago Torres Batán - -Index: fotoxx-11.11.1/Makefile +Index: fotoxx/Makefile =================================================================== ---- fotoxx-11.11.1.orig/Makefile 2011-11-07 20:20:38.000000000 -0300 -+++ fotoxx-11.11.1/Makefile 2011-11-07 20:26:36.000000000 -0300 +--- fotoxx.orig/Makefile 2012-01-04 22:52:42.996487807 +0700 ++++ fotoxx/Makefile 2012-01-04 22:55:57.161450604 +0700 @@ -12,7 +12,7 @@ SHAREDIR = $(PREFIX)/share/fotoxx ICONDIR = $(SHAREDIR)/icons @@ -15,15 +14,15 @@ MANDIR = $(PREFIX)/share/man/man1 MENUFILE = $(PREFIX)/share/applications/kornelix-fotoxx.desktop -@@ -26,7 +26,6 @@ - fotoxx_retouch.o fotoxx_transform.o fotoxx_art.o fotoxx_comp.o \ - zfuncs.o \ - $(LIBS) -ltiff -o fotoxx +@@ -24,7 +24,6 @@ + $(CXX) $(LDFLAGS) -o fotoxx fotoxx.o f.file.o f.tools.o f.select.o f.info.o \ + f.retouch.o f.transform.o f.art.o f.comp.o f.navi.o zfuncs.o \ + $(LIBS) -ltiff - @ ./dependencies.sh - fotoxx.o: $(PROGRAM) fotoxx.h - $(CXX) $(CFLAGS) -o fotoxx.o $(PROGRAM) -@@ -73,18 +72,14 @@ + fotoxx.o: fotoxx-$(VERSION) fotoxx.h + $(CXX) $(CFLAGS) -o fotoxx.o fotoxx-$(VERSION) +@@ -77,14 +76,12 @@ rm -f fotoxx.1.gz # menu (desktop) file cp -f desktop $(DESTDIR)$(MENUFILE) @@ -38,7 +37,3 @@ rm -f $(DESTDIR)$(MENUFILE) clean: - rm -f fotoxx - rm -f *.o -- -- diff -Nru fotoxx-11.11.1/debian-control fotoxx-12.01.2/debian-control --- fotoxx-11.11.1/debian-control 1970-01-01 00:00:00.000000000 +0000 +++ fotoxx-12.01.2/debian-control 2012-01-04 08:47:11.000000000 +0000 @@ -0,0 +1,25 @@ +Package: fotoxx +Version: 12.01.2 +Architecture: amd64 +Section: graphics +Installed-Size: 2900 +Maintainer: Mike Cornelison +Depends: libgtk2.0-0 (>= 2.20.1), libatk1.0-0 (>= 1.30.0), + libglib2.0-0 (>= 2.24.1), libpango1.0-0 (>= 1.28.0), libcairo2 (>= 1.8.10), + libfreetype6 (>= 2.3.11), libfontconfig1 (>= 2.8.0), libc6 (>= 2.11.1), + libtiff4 (>= 3.9.2), libstdc++6 (>= 4.4.3), libgcc1 (>= 1:4.4.3), + xdg-utils (>= 1.0.2), libimage-exiftool-perl (>= 7.89), ufraw (>= 0.16) +Description: photo editor and collection manager + Navigate your image collection using a thumbnail browser. View and + edit images. Convert RAW files to TIFF and edit with 16-bit color. + Edit a selected area or object within an image. Edit using movable + curves with fast full-screen feedback. Adjust brightness, color, + contrast, gamma. Perform tone mapping, trim, rescale, rotate, warp, + sharpen, blur. Reduce noise, fix red-eyes, erase power lines, fix + perspective. Make composite images: HDR, HDF, stack, and panorama. + Annotate images. Make artful transforms. Do a slide show. Create + named collections. Burn a CD or DVD. Edit tags, comments, captions, + dates and star-ratings. Search images using these criteria plus + directory and file names. + + diff -Nru fotoxx-11.11.1/doc/changelog fotoxx-12.01.2/doc/changelog --- fotoxx-11.11.1/doc/changelog 2011-11-05 05:30:36.000000000 +0000 +++ fotoxx-12.01.2/doc/changelog 2012-01-04 08:47:10.000000000 +0000 @@ -1,11 +1,66 @@ -fotoxx change log +Fotoxx change log ================= +2012.01.04 v.12.01.2 ++ Italian user guide was updated. ++ Swedish translation was updated. + +2012.01.04 v.12.01.1 ++ Bugfix: zoom causes infinite loop after new installation. + +2012.01.01 v.12.01 ++ New function Search Metadata: search and report image metadata + (EXIF/IPTC/etc.), using a combined image and text display format. ++ Synchronize Files is 2x faster for an initial installation or after + importing a large number of new photos (>1000/min. on a fast PC). ++ "my mouse" was removed from all edit and selection dialogs. The mouse + belongs to the last widget clicked. The main window can be zoomed and + scrolled during such dialogs by using CTRL + mouse click or drag. ++ Mouse wheel can do zoom-in and zoom-out. ++ Zooming an image re-centers it on the mouse position, and the mouse + position follows the zoom center to the middle of the window. ++ Zoom ratio configurable: choose 1-4 zooms for each 2x increase in size. ++ DRGB (print color adjust) can save corrections to a file for re-use. ++ Some user settings in various menus were collected together in the + new menu function Tools > User Settings. ++ Bugfix: Search Image was finding false matches for images with very + large caption or comments. ++ Bugfix: cannot escape file open dialog if open previous or open recent + is attempted when there are no previous files (initial installation). ++ Bugfix: interactive GUI translation function failed to initialize. + +2011.12.03 v.11.12.2 ++ Italian translation was updated. ++ Locale of lc_RC will prefer a .po file named "lc_RC", fallback to "lc". + +2011.12.02 v.11.12.1 ++ Bugfix: crash at startup - top image directory not correctly + initialized from previous fotoxx installation. + +2011.12.01 v.11.12 ++ New function Auto-Trim: automatically trim unused edge areas left over + from panorama, HDR, HDF, stack, warp and unbend functions. ++ New function: Find bright or dark "stuck" pixels (camera sensor defect) + (1x1/2x2/3x3 blocks) and fix them by interpolating neighboring pixels. + Pixel locations can be saved and applied later to other images. ++ Select Area was extended to both select and unselect by matching colors, + and the pixel search range was made adjustable 1-20x mouse radius. ++ Batch Resize/Export function now supports output of JPEG, PNG, TIFF. + This can be used to select and convert files to a different format. ++ Convert RAW Files now supports output of JPEG, PNG, TIFF-8, TIFF-16. ++ Warp Area algorithm was made a bit more intuitive and controllable. ++ GUI language translation procedure was simplified. ++ Bugfix: restored some lost translations of dialog buttons. ++ Bugfix: Trim dialog mouse ownership was sometimes misleading. ++ Bugfix: WarpArea did not reset itself if selected area was changed. ++ Bugfix: crash if parallel instances of fotoxx are simultaneously + editing images and using undo/redo. + 2011.11.05 v.11.11.1 -Fix some problems in v.11.11 released a few days ago: +Fix problems in v.11.11 released a few days ago: + Bugfix: crash in vertical panorama. -+ Bugfix: crash after moving images to trash and "Open Recent Files". -+ Restore user feedback for functions running more than a few seconds. ++ Bugfix: crash in Open Recent File if trashed image is attempted. ++ Restore lost BUSY indicator for functions needing significant time. 2011.11.01 v.11.11 + Creating and editing collections was made easier and more intuitive. diff -Nru fotoxx-11.11.1/doc/copyright fotoxx-12.01.2/doc/copyright --- fotoxx-11.11.1/doc/copyright 2011-11-05 05:30:36.000000000 +0000 +++ fotoxx-12.01.2/doc/copyright 2012-01-04 08:47:10.000000000 +0000 @@ -2,7 +2,7 @@ Michael Cornelison Copyright: - Copyright 2007, 2008, 2009, 2010, 2011 Michael Cornelison + Copyright 2007, 2008, 2009, 2010, 2011, 2012 Michael Cornelison The source program code can be found here: http://kornelix.squarespace.com/downloads diff -Nru fotoxx-11.11.1/doc/edit-menus fotoxx-12.01.2/doc/edit-menus --- fotoxx-11.11.1/doc/edit-menus 2011-11-05 05:30:36.000000000 +0000 +++ fotoxx-12.01.2/doc/edit-menus 2012-01-04 08:47:10.000000000 +0000 @@ -1,6 +1,22 @@ -Brightness, Contrast, Color -=========================== +Image Transform +=============== +Rotate Image Rotate an image any amount. +Trim Image Trim unwanted margins from an image. +Auto-Trim Image Trim leftover margins from panorama, warp, etc. +Resize Image Scale an image up or down. +Annotate Image Write text annotations on an image. +Flip Image Mirror an image horizontally or vertically. +Make Negative Make a black-white or color negative or positive. +Unbend Image Fix perspective problems (esp. panoramas). +Keystone Correction Straighten an object photographed from an angle. +Warp Image (area) Distort "rubber" image by pulling with the mouse. +Warp Image (curved) Distort entire image by pulling with the mouse. +Warp Image (linear) Distort entire image by pulling with the mouse. +Warp Image (affine) Distort entire image by pulling with the mouse. + +Image Retouch +============= Brightness/Color Edit brightness, contrast, color, saturation. Gamma Curve Edit brightness and color using gamma curves. Expand Brightness Clip low/high brightness and expand the middle. @@ -11,32 +27,24 @@ Match Colors Match the colors in one image to another image. DRGB Change brightness or RGB colors using OD units. Revise RGB Make color corrections that vary over the image. - -Image Repair -============ Red Eyes Remove red eyes from flash photos. Blur Image Blur an image (e.g. smoothen skin). Sharpen Image Sharpen a blurred image. Reduce Noise Reduce noise (speckles) in low-light images. Smart Erase Remove power lines and other spoilers. Remove Dust Remove spots on images made from dusty slides. +Fix Stuck Pixels Fix bright/dark pixels from camera sensor defects. Edit Pixels Edit pixels and paint areas using the mouse. -Image Transform -=============== -Trim Image Trim unwanted margins from an image. -Resize Image Scale an image up or down. -Batch Resize/Export Resize and export images for web upload, etc. -Annotate Image Write text annotations on an image. -Rotate Image Rotate an image any amount. -Flip Image Mirror an image horizontally or vertically. -Make Negative Make a black-white or color negative or positive. -Unbend Image Fix perspective problems (esp. panoramas). -Straighten Image Straighten an object photographed from an angle. -Warp Image (area) Distort "rubber" image by pulling with the mouse. -Warp Image (curved) Distort entire image by pulling with the mouse. -Warp Image (linear) Distort entire image by pulling with the mouse. -Warp Image (affine) Distort entire image by pulling with the mouse. +Apply Art Effects +================= +Color Depth Reduce the number of colors (aka "posterize"). +Drawing Convert to a simulated pencil or chalk drawing. +Outlines Convert into a colorful line drawing. +Embossing Convert into a simulated embossing (3D effect). +Tiles Convert into square tiles. +Dots Convert into dots (Roy Lichtenstein effect). +Painting Convert into a simulated painting. Combine Images ============== diff -Nru fotoxx-11.11.1/doc/fotoxx.man fotoxx-12.01.2/doc/fotoxx.man --- fotoxx-11.11.1/doc/fotoxx.man 2011-11-05 05:30:36.000000000 +0000 +++ fotoxx-12.01.2/doc/fotoxx.man 2012-01-04 08:47:10.000000000 +0000 @@ -6,8 +6,9 @@ .SH SYNOPSIS \fBFotoxx\fR [ \fB-v\fR ] [ \fB-lang\fR \fIcode\fR ] [ \fIfile\fR | \fIdirectory\fR ] - [ \fB-recent\fR ] [ \fB-prev\fR ] + [ \fB-recent\fR ] [ \fB-prev\fR ] [ \fB-blank\fR ] [ \fB-slideshow\fR [ \fB-music\fR ] ] + [ \fB-translate\fR ] .SH DESCRIPTION Fotoxx is a graphical menu-driven program which operates in @@ -44,12 +45,13 @@ - Search images by comments, tags, dates, star-ratings, file names - Rename images from camera using a base name and sequence number - Slide-show mode: automatic or keyboard control, optional music - - Batch convert multiple RAW files to tiff-16 - - Print image using standard or custom paper size - - Select images from the navigator and burn a CD or DVD - - Select images and send to preferred e-mail program + - Batch convert multiple RAW files to tiff-8/16, jpeg, png + - Print image using any format, make color adjustments + - Select images, convert format, resize, export, burn CD/DVD - Assign images to named collection, edit and view collection + - Edit image metadata, search and report any metadata - Tune monitor for color and gamma + - Context aware help available via the F1 key .SH OPTIONS Command line options @@ -61,6 +63,7 @@ \fB-recent\fR show a gallery of most recent files opened \fB-slideshow\fR is first image in a slide show \fB-music\fR is a music file or a playlist + \fB-translate\fR start in interactive translation mode .SH SEE ALSO The online user manual is available using the help menu. diff -Nru fotoxx-11.11.1/doc/freecode fotoxx-12.01.2/doc/freecode --- fotoxx-11.11.1/doc/freecode 1970-01-01 00:00:00.000000000 +0000 +++ fotoxx-12.01.2/doc/freecode 2012-01-04 08:47:10.000000000 +0000 @@ -0,0 +1,17 @@ + +A new capability was added to search for and report any image metadata +(EXIF/IPTC/etc.). The report shows thumbnail images and metadata text. + +Processing new photos is 2x faster (up to 1000/minute). + +The main window can be more easily zoomed and panned during a dialog +which is using the mouse. The mouse wheel can be used to zoom in/out. +The mouse pointer tracks the zoom center to the middle of the window. + +The zoom ratio is configurable: 1-4 zooms for each 2x increase. + +Print color adjustments can be saved to a file for re-use. + +Three minor bugs were fixed. + + Binary files /tmp/tO1AdX0GAK/fotoxx-11.11.1/doc/images/annotate.jpg and /tmp/PEei9XmU3C/fotoxx-12.01.2/doc/images/annotate.jpg differ Binary files /tmp/tO1AdX0GAK/fotoxx-11.11.1/doc/images/auto-trim.jpg and /tmp/PEei9XmU3C/fotoxx-12.01.2/doc/images/auto-trim.jpg differ Binary files /tmp/tO1AdX0GAK/fotoxx-11.11.1/doc/images/batch-rename.jpg and /tmp/PEei9XmU3C/fotoxx-12.01.2/doc/images/batch-rename.jpg differ Binary files /tmp/tO1AdX0GAK/fotoxx-11.11.1/doc/images/batch-resize-export.jpg and /tmp/PEei9XmU3C/fotoxx-12.01.2/doc/images/batch-resize-export.jpg differ Binary files /tmp/tO1AdX0GAK/fotoxx-11.11.1/doc/images/DRGB.jpg and /tmp/PEei9XmU3C/fotoxx-12.01.2/doc/images/DRGB.jpg differ Binary files /tmp/tO1AdX0GAK/fotoxx-11.11.1/doc/images/edit-caption-comments.jpg and /tmp/PEei9XmU3C/fotoxx-12.01.2/doc/images/edit-caption-comments.jpg differ Binary files /tmp/tO1AdX0GAK/fotoxx-11.11.1/doc/images/edit-pixels.jpg and /tmp/PEei9XmU3C/fotoxx-12.01.2/doc/images/edit-pixels.jpg differ Binary files /tmp/tO1AdX0GAK/fotoxx-11.11.1/doc/images/expand-brightness.jpg and /tmp/PEei9XmU3C/fotoxx-12.01.2/doc/images/expand-brightness.jpg differ Binary files /tmp/tO1AdX0GAK/fotoxx-11.11.1/doc/images/expand-brightness.png and /tmp/PEei9XmU3C/fotoxx-12.01.2/doc/images/expand-brightness.png differ Binary files /tmp/tO1AdX0GAK/fotoxx-11.11.1/doc/images/gammachart.png and /tmp/PEei9XmU3C/fotoxx-12.01.2/doc/images/gammachart.png differ Binary files /tmp/tO1AdX0GAK/fotoxx-11.11.1/doc/images/grid-lines.jpg and /tmp/PEei9XmU3C/fotoxx-12.01.2/doc/images/grid-lines.jpg differ Binary files /tmp/tO1AdX0GAK/fotoxx-11.11.1/doc/images/HDF-paint.jpg and /tmp/PEei9XmU3C/fotoxx-12.01.2/doc/images/HDF-paint.jpg differ Binary files /tmp/tO1AdX0GAK/fotoxx-11.11.1/doc/images/lens-parameters.jpg and /tmp/PEei9XmU3C/fotoxx-12.01.2/doc/images/lens-parameters.jpg differ Binary files /tmp/tO1AdX0GAK/fotoxx-11.11.1/doc/images/pano-color.jpg and /tmp/PEei9XmU3C/fotoxx-12.01.2/doc/images/pano-color.jpg differ Binary files /tmp/tO1AdX0GAK/fotoxx-11.11.1/doc/images/pano-dialog.jpeg and /tmp/PEei9XmU3C/fotoxx-12.01.2/doc/images/pano-dialog.jpeg differ Binary files /tmp/tO1AdX0GAK/fotoxx-11.11.1/doc/images/pano-pre-align.jpg and /tmp/PEei9XmU3C/fotoxx-12.01.2/doc/images/pano-pre-align.jpg differ Binary files /tmp/tO1AdX0GAK/fotoxx-11.11.1/doc/images/resize.jpg and /tmp/PEei9XmU3C/fotoxx-12.01.2/doc/images/resize.jpg differ Binary files /tmp/tO1AdX0GAK/fotoxx-11.11.1/doc/images/revise-RGB.jpg and /tmp/PEei9XmU3C/fotoxx-12.01.2/doc/images/revise-RGB.jpg differ Binary files /tmp/tO1AdX0GAK/fotoxx-11.11.1/doc/images/rotate.jpg and /tmp/PEei9XmU3C/fotoxx-12.01.2/doc/images/rotate.jpg differ Binary files /tmp/tO1AdX0GAK/fotoxx-11.11.1/doc/images/search-images2.jpg and /tmp/PEei9XmU3C/fotoxx-12.01.2/doc/images/search-images2.jpg differ Binary files /tmp/tO1AdX0GAK/fotoxx-11.11.1/doc/images/search-images.jpg and /tmp/PEei9XmU3C/fotoxx-12.01.2/doc/images/search-images.jpg differ Binary files /tmp/tO1AdX0GAK/fotoxx-11.11.1/doc/images/search_metadata.jpg and /tmp/PEei9XmU3C/fotoxx-12.01.2/doc/images/search_metadata.jpg differ Binary files /tmp/tO1AdX0GAK/fotoxx-11.11.1/doc/images/select-area.jpg and /tmp/PEei9XmU3C/fotoxx-12.01.2/doc/images/select-area.jpg differ Binary files /tmp/tO1AdX0GAK/fotoxx-11.11.1/doc/images/select-edit.jpg and /tmp/PEei9XmU3C/fotoxx-12.01.2/doc/images/select-edit.jpg differ Binary files /tmp/tO1AdX0GAK/fotoxx-11.11.1/doc/images/show-RGB.jpg and /tmp/PEei9XmU3C/fotoxx-12.01.2/doc/images/show-RGB.jpg differ Binary files /tmp/tO1AdX0GAK/fotoxx-11.11.1/doc/images/smart-erase.jpg and /tmp/PEei9XmU3C/fotoxx-12.01.2/doc/images/smart-erase.jpg differ Binary files /tmp/tO1AdX0GAK/fotoxx-11.11.1/doc/images/smart-erase.png and /tmp/PEei9XmU3C/fotoxx-12.01.2/doc/images/smart-erase.png differ Binary files /tmp/tO1AdX0GAK/fotoxx-11.11.1/doc/images/stack-noise.jpg and /tmp/PEei9XmU3C/fotoxx-12.01.2/doc/images/stack-noise.jpg differ Binary files /tmp/tO1AdX0GAK/fotoxx-11.11.1/doc/images/stack-paint.jpg and /tmp/PEei9XmU3C/fotoxx-12.01.2/doc/images/stack-paint.jpg differ Binary files /tmp/tO1AdX0GAK/fotoxx-11.11.1/doc/images/stack.png and /tmp/PEei9XmU3C/fotoxx-12.01.2/doc/images/stack.png differ Binary files /tmp/tO1AdX0GAK/fotoxx-11.11.1/doc/images/stuck-pixels.jpg and /tmp/PEei9XmU3C/fotoxx-12.01.2/doc/images/stuck-pixels.jpg differ Binary files /tmp/tO1AdX0GAK/fotoxx-11.11.1/doc/images/synchronize-files.jpg and /tmp/PEei9XmU3C/fotoxx-12.01.2/doc/images/synchronize-files.jpg differ Binary files /tmp/tO1AdX0GAK/fotoxx-11.11.1/doc/images/trim.jpg and /tmp/PEei9XmU3C/fotoxx-12.01.2/doc/images/trim.jpg differ Binary files /tmp/tO1AdX0GAK/fotoxx-11.11.1/doc/images/user-settings.jpg and /tmp/PEei9XmU3C/fotoxx-12.01.2/doc/images/user-settings.jpg differ Binary files /tmp/tO1AdX0GAK/fotoxx-11.11.1/doc/images/white-balance.jpg and /tmp/PEei9XmU3C/fotoxx-12.01.2/doc/images/white-balance.jpg differ diff -Nru fotoxx-11.11.1/doc/translations fotoxx-12.01.2/doc/translations --- fotoxx-11.11.1/doc/translations 2011-11-05 05:30:36.000000000 +0000 +++ fotoxx-12.01.2/doc/translations 2012-01-04 08:47:10.000000000 +0000 @@ -3,45 +3,31 @@ The instructions here apply to the GUI interface (menus and dialogs). For user guide translations, see below. -There are two GUI translation files (assuming a default installation): - /usr/share/fotoxx/locales/lc/fotoxx.po - /usr/share/fotoxx/locales/lc/zfuncs.po - -"fotoxx" is the main application program. "zfuncs" is a collection -of utility programs. "lc" is the standard 2-character language code: -de, es, fr, zh, etc. These two .po files contain the English phrases -used by fotoxx and zfuncs, with corresponding translations. They can -be edited with any text editor or one of the special .po file editors. - -In addition to these "lc" translation files, files for regional -languages or dialects may also be installed. These file names -include the region code as follows: - /usr/share/fotoxx/locales/lc_RC/fotoxx.po - /usr/share/fotoxx/locales/lc_RC/zfuncs.po - -"lc_RC" is a combined language and region code, e.g. "de_AT" for -Austrian German, or "zh_TW" for Taiwan Chinese. This is also the -locale of the target computer system, as shown by the following -command: $ echo $LANG - -If both standard and regional translation files are present, BOTH -are read and processed. If the same English text is translated in -both files, the regional translation will be used. Thus you can make -a regional .po file that contains only the exceptions to standard -translations. +Translation files are normally as follows: + /usr/share/fotoxx/locales/fotoxx-lc.po + +"lc" is a standard 2-character language code, e.g. "de" for German, +or a combination language and region code formatted "lc_RC", +e.g. "de_AT" for Austrian German. + +"lc" or "lc_RC" is also the locale of the target computer system, +as shown by the following command: $ echo $LANG + +The .po file contains the English phrases used by fotoxx, with the +corresponding translations for language "lc" or language and region +"lc_RC". It can be edited with any text editor or one of the special +editors for .po files (e.g. poedit). REVISE AN EXISTING LANGUAGE AND TRANSLATION - 1. Edit fotoxx.po and zfuncs.po to add or update translations. - 2. Open a terminal window and go to the location of these files. - 3. Compile the .po files to check for errors: - $ msgfmt -v --check-format -o /dev/null fotoxx.po - $ msgfmt -v --check-format -o /dev/null zfuncs.po + 1. Edit fotoxx-lc.po to add or update translation strings. + 2. Open a terminal window and go to the location of the .po file. + 3. Compile the .po file to check for errors: + $ msgfmt -v --check-format -o /dev/null fotoxx-lc.po 4. Run fotoxx and check how the translations look. - 5. Send the modified .po files to me (kornelix2@googlemail.com) - so they can be included in future releases. + 5. Send the modified .po file to me (kornelix2@gmail.com) + so it can be included in future releases. -NOTE: Steps 2 and 3 are optional. The usual binary translation files (.mo) that are output by msgfmt are not needed by fotoxx. The translation source files (.po) are read directly by fotoxx, and changes made to @@ -51,25 +37,20 @@ ADD A NEW LANGUAGE AND TRANSLATION -1. Move the source program files fotoxx-N.N.cc and zfuncs.cc from - the release tarball into some convenient directory. -2. Create template files (.pot) from the source programs (.cc) - $ xgettext -s --keyword=ZTX -o fotoxx.pot fotoxx-N.N.cc - $ xgettext -s --keyword=ZTX -o zfuncs.pot zfuncs.cc -3. Create translation files (.po) from the template files (.pot) - $ msginit -l lc -o fotoxx.po -i fotoxx.pot - $ msginit -l lc -o zfuncs.po -i zfuncs.pot - "lc" is the 2-character code for the new language. - If asked for an e-mail address, reply with Enter to ignore this. -4. Edit the two .po files to insert translations for all text. -5. Create an installation directory for the translation files: - /usr/share/fotoxx/locales/lc -6. Move the two .po files into the installation location: - /usr/share/fotoxx/locales/lc/fotoxx.po - /usr/share/fotoxx/locales/lc/zfuncs.po -7. Run fotoxx and check how the translations look. -8. Send the new .po files to me (kornelix2@googlemail.com) so they - can be included in future releases. + 1. Move the source program files *.cc and *.h from the release + tarball into some convenient directory. + 2. Create template files (.pot) from the source programs + $ xgettext -s --keyword=ZTX -o fotoxx.pot *.cc *.h + 3. Create translation files (.po) from the template files (.pot) + $ msginit -l lc -o fotoxx-lc.po -i fotoxx.pot + "lc" is the language and region code for the new language. + If asked for an e-mail address, reply with Enter to ignore. + 4. Edit the .po file to insert translations for all text. + 5. Move the .po file to the installation directory: + /usr/share/fotoxx/locales/fotoxx-lc.po + 6. Run fotoxx and check how the translations look. + 7. Send the new .po file to me (kornelix2@gmail.com) + so it can be included in future releases. PROBLEMS WITH LONG TRANSLATIONS @@ -90,72 +71,71 @@ text may include an extra string to distinguish different contexts. This context string is removed from the GUI output, so the user does not see it. The context string is any short string followed with the -special marker "::". To continue our example, the fotoxx.po file +special marker "::". To continue our example, the fotoxx-lc.po file might look like this: msgid "save file" msgstr "in Datei speichern" msgid "toolbar::save file" msgstr "speichern" In English, fotoxx would show "save file" for both cases, and in -German "in Datei speichern" or "speichern". Context strings may be -present in the .po files distributed with fotoxx, and also in a -newly created language .po file. +German "in Datei speichern" or "speichern". INTERACTIVE TRANSLATIONS -Use the fotoxx menu "Edit Translations" to start revising translations +Use the fotoxx menu "Edit Translations" to revise translations interactively as the application is being used. The advantage is that you can better understand the context, making translation easier and more accurate. The updated translations are also immediately seen in -the application dialogs. The starting point is the two .po files as -described above, which must be installed to start with. The translations +the application dialogs. The starting point is the fotoxx-lc.po file +as described above, which must be installed to start with. Translations may be partly or entirely missing at this point - it is only important -that all the English strings are present in the .po files. This method -is best suited for updating the translations after a new release of -fotoxx, or to improve the translations. +that all the English strings are present in the .po file. This method +is best suited for updating the translation after a new release of +fotoxx, or to improve the translation. Use the menu to start the process. A popup text window is created and displays all english strings and their present translations as they are being used in the application. The format is like the .po files. Missing translations will repeat the English phrase in place of the translation. The translations may be edited in the window as soon as they appear. -When the [apply] button is pressed, the original .po file(s) are copied -and updated from the edit window. These edited versions are placed in -/home//.fotoxx/locales/lc and .../lc_RC. Each time this process +When the [apply] button is pressed, the original .po file is copied +and updated from the edit window. This edited .po file is placed in +/home//.fotoxx/locales/fotoxx-lc.po. Each time this process is started, a new popup text window is created for new translations, -and these are accumulated in the .po files. A choice can be made to show -only missing translations or all translations. Normally only missing -translations are needed, but revisions in existing translations can also -be made. Once a translation is edited and the [apply] button is used, -the translation is no longer missing and will not appear again in the -edit window if 'only missing' was chosen. The function can be started -again (using the application's menu) to change the mode to show no -translations, all translations, or only missing translations. - -When finished, replace the installation .po files in - /usr/share/fotoxx/locales/lc and .../lc_RC -with the edited .po files in - /home//.fotoxx/locales/lc and .../lc_RC). -Delete the edited .po files to stop fotoxx from using them. +and these are accumulated in the .po file. + +When the interactive translation function is started, you can choose to +show only the missing translations or all translations. Normally only +missing translations are needed, but revisions in existing translations +can also be made. Once a translation is edited and the [apply] button is +used, the translation is no longer missing and will not appear again in +the edit window if 'only missing' was chosen at startup. If the function +is started again later, the option to show all translations or only the +missing translations can be set again. + +When finished, replace the installation .po file in + /usr/share/fotoxx/locales/fotoxx-lc.po +with the edited .po file in + /home//.fotoxx/locales/fotoxx-lc.po +Delete the edited .po file to stop fotoxx from using them. When fotoxx is started from a terminal window, any missing translations -will be listed in the window. Be sure to send the finished .po files to -me for inclusion in future releases (kornelix2@googlemail.com). +will be listed in the window. Be sure to send the finished .po file to +me for inclusion in future releases (kornelix2@gmail.com). USER GUIDE TRANSLATION -The user guide is named as follows (assuming a default installation): +The user guide is normally found here: /usr/share/doc/fotoxx/userguide-lc.html - /usr/share/doc/fotoxx/userguide-lc_RC.html The file is a text HTML file, which may be edited with any HTML editor. -"lc" is a standard language code, and "lc_RC" is a language and region -code combination. The user locale in $LANG or $LANGUAGE is used to find -"lc_RC". If a file with the region code is present, this file is used, -otherwise the standard language version is used. If this is not found, -the english file (userguide-en.html) is used. +"lc" (or "lc_RC") is the language code or language and region code. +The user locale in $LANG or $LANGUAGE is used to find "lc_RC". If a +file with the region code is present, this file is used, otherwise the +standard language version is used. If this is not found, the english +file (userguide-en.html) is used. If you make a new or revised translation, please send it to me so that -it can be included in future releases (kornelix2@googlemail.com). +it can be included in future releases (kornelix2@gmail.com). diff -Nru fotoxx-11.11.1/doc/userguide-changes.txt fotoxx-12.01.2/doc/userguide-changes.txt --- fotoxx-11.11.1/doc/userguide-changes.txt 2011-11-05 05:30:36.000000000 +0000 +++ fotoxx-12.01.2/doc/userguide-changes.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,165 +0,0 @@ -Fotoxx Userguide Revisions -========================== - -v.11.11 Nov. 2011 -================== - -The collection topics (concepts, create, opem, delete, edit) were all -replaced by a new topic Manage Collections. - -Getting Started topic: Initialization paragraph was modified for new -startup functionality to find and index new files. - -New menu and topic: Help > User Guide Changes. - -New menu and topic: Help > Edit Functions Summary. - -Synchronize Files topic: text regarding full and incremental modes was -removed, since incremental mode is now always used. - - -v.11.10 Oct. 2011 -================== - -The Getting Started topics Installation and Initialization have some -new text added about the Synchronize Files function. - -The topic Save Image File was updated for the new functionality to -warn about overwriting an original file. - -The topic Print Image File was revised to match revised functionality. - -The Slide Show topic was modified for the new option to show only the -latest version of each image file. - -The new topic Gamma Curve was added after Brightness/Color. - -The new topic Straighten Image was added after Unbend Image. - -The Slide Show topic has a new sentence explaining use of the P key. - - -v.11.09 Sep. 2011 -================== - -The two menus and topics Edit Caption and Edit Comments were combined -into the single menu and topic Edit Caption/Comments. The text in the -topic was changed to match. - -The menu and topic Open RAW File was eliminated. Open Image File can -be used to open a single RAW file, and this topic was modified to -reflect the added functionality. - -A paragraph about scanned images was added to the panorama topic. - -The topic Print an Image File was revised for the addition of print -margins. - - -V.11.08 Aug. 2011 -================== - -Getting Started: the paragraph Fotoxx Startup was added. - -General Editing Procedure: expanded for clarity. - -Select Area: -"Delete" was changed to "Unselect" in several places. -(some people thought it meant deleting a part of the image). -"Whole Image" was changed to "Select Whole Image" in several places. - -Slide Show: The first sentence was changed. - -Select Area: The file "/doc/images/gallery image selection.jpg" was -renamed "/doc/images/gallery-selection.jpg" (autotools compatibility). - -Add Menu and Launcher: one sentence was added. - -Add DRGB to Retouch menu (table). -Add DRGB topic after Expand Brightness. - -Show RGB: -One sentence was added at the end. The format for RGB data is xxx.dd -(not xxx.ddd) and the range is 0.00 to 255.99. The table was corrected. -(the EV value for RGB 64 is -1 not -2). - -A new item was added to the File menu (table): Open RAW File. -A corresponding topic was added following Open Recent File. - -Revise RGB: -A sentence was added for the new "delta" mode. - -Rename image File: -The 4th sentence was replaced. It now reads -"Use the [next] button to move to the next file if wanted". - -Synchronize Files: -Performace estimate in the 2nd paragraph was changed to read -"my 3.3 GHz PC does 570 images per minute". - - -v.11.07 July 2011 -================== - -"Memory Usage" was added to the Tools menu (table) and a new topic -was added following Synchronize Files. - -Brightness/Color topic: One sentence was added at the end to explain -the graph range and the step size for the buttons. - -Match Colors: This was added to the Retouch menu (table) and a new -topic was added following Expand Brightness. - -Save to New Version: This was added to the File menu (table) and a -new paragraph was added to the topic Save Image File. - -Show RGB: 4 sentences were added to explain the EV and OD units. - -"Clone" was moved from the Tools menu to the File menu (table) and -the Clone topic was moved in the text (now after Navigation topic). -There are now two menu entries, Clone 50/50 and Clone Overlay. The -Clone topic was edited to cover both variations. - -"Open in New Window" was added to the File menu (table) and the -Open Image File topic has a new paragraph for this function. - -Toolbar Buttons (table): update to: Save / Save+V / Save+F - -[Save As] and [Save-As] was replaced with [Save+F] in several places -(use the Find and Replace tool in Kompozer) - -The Pixel Edit function was moved from the Art menu to the Retouch menu. -The menu tables were changed and the topic was moved to the end of the -Retouch section. - -The Brightness Ramp topic has 4 sentences added at the end, explaining -the use of the RGB buttons. - -Keyboard Shortcuts (table): added entry "Control + v or V" - -Toolbar Buttons (table): Undo and Redo text revised for shift key. - -Replaced "Tools > Rebuild Search Index" with "Tools > Synchronize Files" -in two places in the topic Search Images. - -Replaced "Left drag acts as an un-select" with "Right drag ..." near -the end of the topic Select by Color (within Select Area). - -Replaced image for Select Area topic (new button Unfinish). - -The Select Area topic was audited and several small changes were made -to improve clarity. These need not affect translations. - -Select Area topic: an explanation for the unfinish button was added. - -New menu item Revise RGB was added to the Retouch menu table, and a -new topic was added following Edit Pixels (now the last topic in the -Retouch section). - -The topic Save to New File was revised (the last 2 sentences) to reflect -changed functionality. - -Technical Notes topic: command line options: add entry for -recent -Technical Notes Topic: Special Fotoxx Files: add zdialog_positions - - diff -Nru fotoxx-11.11.1/doc/userguide-en.html fotoxx-12.01.2/doc/userguide-en.html --- fotoxx-11.11.1/doc/userguide-en.html 2011-11-05 05:30:36.000000000 +0000 +++ fotoxx-12.01.2/doc/userguide-en.html 2012-01-04 08:47:10.000000000 +0000 @@ -1,88 +1,130 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - -fotoxx user guide -Fotoxx -User Guide  v.11.11
- + + + + + fotoxx user guide + + + +Fotoxx +User +Guide  +v.12.01

License and Warranty

- Fotoxx is licensed under the -GNU General Public License v3 (Free Software Foundation).
+GNU General Public License v3 (Free Software Foundation).
Fotoxx is not warranted for any purpose, but if you find a bug, I will try to fix it.
-
- -Origin and Contact
- +Origin and +Contact
Fotoxx originates from -the author's web site  http://kornelix.squarespace.com/fotoxx. Other web sites may -offer it for download. Modifications may have been made. If you have questions, -suggestions, or a bug to report, you may contact me.
- -
- -
- -
-Getting Started
-
-Installation
-
To install Fotoxx, try the appropriate package file first: packages. It may install OK with one click. If not, you must -install from source code. Instructions are here: downloads. -Fotoxx should show up in the system menu after installation -(or maybe -after a new login). If not, use the command "fotoxx" in a terminal -window or launcher. When started for the first time, Fotoxx will ask -you to run the Synchronize Files function. You can cancel this for now. -To test Fotoxx, use the toolbar button [open] to find an -image file (.JPG  .TIF  .PNG ...) and check that it is -displayed OK. -Use the menu Retouch > Brightness/Color and press the button [+++] a -few times - the image should brighten. Use the button [cancel] to exit -this function without changing the image file. Press the toolbar button -[gallery] to show all the image -files in the same directory as an array of thumbnail images. This may -be slow at first, since the thumbnails must be generated, but it will -be fast the next time you visit the same directory. Click on any -thumbnail to show the image full-size. If all this works OK, then -Fotoxx is working normally.
- +the author's web site 
http://kornelix.squarespace.com/fotoxx. Other web sites may +offer it for download. Modifications may have been made. If you have +questions, +suggestions, or a bug to report, you may contact me.
+
+User +Guide +changes for this version can be found here.
+
+
+
+Getting +Started
+
+When you see the word
directory, substitute folder + if this is your way of +thinking. The +terms file and image and image file mean a single computer +file of +type  .jpg  .png  .tif  +etc. +containing +a +single +image +(photograph). +
+
+Installation
+
To install Fotoxx, try the appropriate package file first: packages. +It +may +install +OK +with +one +click. +If +not, +you +must +install +from +source +code. +Instructions +are +here: +downloads. +Fotoxx +should +show +up +in +the +system +menu +after +installation +(or +maybe +after +a +new +login). +If +not, +use +the +command +"fotoxx" +in +a +terminal +window +or launcher.

Initialization
Fotoxx -needs to know where all your images are (directory and file +needs to know where all your image files are located (directory and +file names) and their imbedded metadata (if any): tags, captions, comments, -ratings and dates. These are indexed for fast searching. Fotoxx also needs to create thumbnail images so that +ratings and dates. These must be indexed for fast searching. Fotoxx +also needs to create thumbnail images so that the gallery windows (thumbnail pages) will work fast. When Fotoxx starts, it checks for a top image directory and index file. These will be missing the @@ -93,125 +135,172 @@ a directory containing all your image files (or subdirectories with image files). This is typically named "/home/<user>/Pictures" or similar. Use the [browse] button to locate this directory and press -[proceed]. A popup window will list the image files found and -processed. If you have many thousands of images, this will need some -time to finish (a fast computer will do around 500 images per minute). After +[proceed]. A popup window will list the image files as they are +indexed. If you have many thousands of images, this will need some +time to finish (a fast computer will do over 1000 images per minute). +Fotoxx does not change or copy the +image files - it only reads them to get data for the search index and +to make thumbnails. After this function has finished, the gallery windows will be fast -and the Search Images function will search thousands of -images per second.
+and the Search Images function will be very fast.

If you start Fotoxx after new image files have been added to your collection, the synchronize function starts automatically. A -popup window will list the new image files found and processed. You +popup window will list the new image files found. You can use Fotoxx normally to navigate and view images, but editing images will be blocked until the synchronize function is finished. This normally needs a few seconds unless there are hundreds of new images to process. The popup window is left open for your inspection. You can close it at any time, but synchronize will always continue to completion. For more details, -see  the topic
Synchronize Files.
- -
-Essential Information for those who hate big user manuals:

-  o  Menu functions have live help activated by keyboard F1.
- -  o  Mouse left click: zoom image bigger, centered at mouse position. 
- -o  Mouse drag across zoomed image: scroll the image.
  o  Mouse right click: restore image to fit in window.
  o  Gallery button: thumbnail browser: view all images in current directory.
- -  o  Click image in thumbnail browser: show image in main window.
  o  Menu: Tools > Change Language: switch between English and your language.
o  The status bar at the bottom of the main window tells you what is happening.
+see  the topic
Synchronize +Files.
+
+Test +Run
+After Fotoxx finishes initialization, use the [open] button on +the toolbar to select an image file to view in the main window. Choose +the menu Retouch > Brightness/Color, and in the dialog use the [+++] +button to brighten the image. Use the [cancel] button to leave the +dialog without changing the image file on disk. Use the [gallery] +toolbar button to see all the images in the current directory as +thumbnails in a new window. Use the navigation buttons on the gallery +window to navigate within the directory. Use the [parent] button to +leave this directory and choose another. Click on a thumbnail image to +view the image in the main window.

+
+Essential Information for those who hate big user manuals:

+  o  Menu functions and dialogs +have live help activated by keyboard F1.
+  o  Mouse left click: zoom image +bigger and move center to mouse position. 
+o  Mouse drag across a zoomed +image: scroll and pan the image.
+  o  Mouse right click: un-zoom +image to fit in the window.
+  o  Gallery button: thumbnail +browser: view all images in current directory.
+  o  Click image in thumbnail +browser: show image in main window.
+  o  The status bar +at the bottom of the main window contains status information.

-Fotoxx Startup: To start Fotoxx, use one of the following command lines in a launcher or terminal window: 
-
- - - - - - - - - - - - - - - - - - - - - - - -
  fotoxx
-
start with a blank window
-
  fotoxx /some/image/file.jpg  
-
open this image file if found
-
  fotoxx /some/directory/
-
show a gallery of image files in this directory
  fotoxx -prev (or -p)
-
open the last file viewed in the previous session
-
  fotoxx -recent (or -r)
-
show a gallery of recent files, click one to open it
-
-
-When you see the word
directory, substitute folder if this is your way of thinking.
- -
- -Many dialogs have a my mouse -checkbox. If checked, mouse clicks and drags are dialog inputs; if -unchecked, these will zoom and scroll the main window. You can toggle -back and forth.
- -
+Fotoxx +Startup: To start Fotoxx, +use the command "fotoxx" in a launcher or terminal +window. Command line options are listed in the Technical Notes section.
+

+This User Guide is available +in the menu Help > User Guide. The F1 +key will bring up a help topic for the current menu or dialog. +This appears in your chosen web browser (and can get hidden +under the Fotoxx window).
+
+Mouse Actions on Main Window
+To zoom the image in the main window, left-click a position on the +image. The image will grow with each click and +the clicked position will move toward the center. A right-click will +restore the image to fit within the window. To scroll a zoomed image, +left-drag the mouse across the image. This works like invisible scroll +bars: the image moves in the opposite direction of the mouse. Diagonal +scrolls work. The mouse wheel may also be used to zoom the image in or +out. The middle mouse button (wheel) will make a zoomed image re-center +at the mouse position.
+
+Mouse Ownership
+Some dialogs use the mouse to reference or alter the image +in the main window. There may be more than one such dialog active at +the same time. The mouse is also used to zoom and scroll the image, and +you may need to do this while using a dialog. Therefore it is important +to understand who owns the mouse (dialog or main window) and how to +change the ownership:
+
1. The mouse is +owned by the dialog that +was last clicked or modified. Mouse cllicks and drags on the main +window are +inputs to this dialog and DO +NOT zoom or scroll the image.
+2. To zoom or scroll the image while a mouse-using dialog is active, +press the CTRL key before clicking or dragging the mouse. The mouse +acts on the main window +and the dialog is not affected. The mouse wheel can always be used for +zooming the image - the CRTL key is not needed.

-Dialog buttons mostly work as follows:
   -Proceed - close dialog, proceed with lengthy task.
   -Apply - apply settings from dialog, leave dialog active.
   -Done - keep dialog changes and close dialog.
   -Cancel - discard changes and close dialog.
- +
+Dialog buttons mostly +work as follows:
+   +Proceed - close dialog, proceed +with lengthy task.
+   +Apply - apply settings from +dialog, leave dialog active.
+   +Done - keep dialog changes and +close dialog.
+   +Cancel - discard changes and +close dialog.

- General Editing Procedure
- The image in the main window (the current image) can be operated on with -the edit functions (in the menus Retouch, Transform, Art, Combine). +the edit functions (in the menus Transform, Retouch, Art, Combine). These functions modify the current image in memory. You can use these functions in any order, and the changes are accumulated for the current image and shown in the main window. The Toolbar [undo] and [redo] buttons can be used to review -the before/after results for the current active edit functioin. After -the function is closed (dialog [done] or [cancel] button), these +the before/after results for the current active edit function. After +the function is closed (dialog [done] or [cancel]), these buttons can be used to review all the edits done to the current image (up to 99). When finished editing an image, use [Save] to replace the original image file with the modified one. Use [Save+V] to save the modified image with the original file name -appended with a version number (and both are kept). Use [Save+F] to -save the modified image to a new file.
- +appended with a version number (both are kept). Use [Save+F] to +save the modified image to a new file.

Many image edit dialogs have sliders, spin buttons, or editable curves -that update the image in the main window. The reaction time depends on the size +that update the image in the main window. The reaction time depends on +the size of the image, the complexity of the function and the speed of your -computer. This is typically <1 second for a computer with 2+ GHz and 2+ processor cores.
- +computer. This is typically <1 second for a fast computer.

- Curve Editing:
-
+
Several image edit functions use editable curves. You can manipulate the curves @@ -227,18 +316,22 @@ it is pulled, and this becomes a constraint for subsequent pulls: the curve will continue to go through this point as -other parts of the curve are pulled. Anchor points can also be dragged. Delete by +other parts of the curve are pulled. Anchor points can also be dragged. +Delete by right-clicking them. The curve edit windows have buttons [open] and [save] which can be used to load a curve previously saved to a file. This may reduce the time to edit the curves for a -series of images receiving similar treatment.
-
Simple Workflow
+series of images receiving the same treatment.

+
+Simple +Workflow
Most of the time you -can just edit the JPEG file that comes out of the camera. Use the following +can just edit the JPEG file that comes out of the camera. Use the +following more complex procedure only if you see "color bands" after editing the image.
-
Complex Workflow
Convert the camera RAW @@ -249,34 +342,40 @@ shift the brightness distribution (especially Flatten and Tone Mapping). When finished, convert the final TIFF to JPEG (quality level 70+) to reduce the file size (from typically 50 MB to 2 MB). You will -not be able to see any difference between the final TIFF and JPEG +almost never be able to see any difference between the final TIFF and +JPEG images. To preserve the possibility of re-editing the image later, keep the RAW -file, which is much smaller than the TIFF file.
-
-Suggestions for how to organize a large image collection can be found here.
+file, which is much smaller than the TIFF file.

- -
- -Selecting Images from an Image Gallery Window

- - +Suggestions for how to organize +a large image collection can be found here.
+
+
+Selecting Images from an Image Gallery Window

This procedure is used in -several functions which use or modify multiple image files (batch add or delete tags, batch resize images, +several functions which use or modify multiple image files (batch add +or delete tags, batch convert images, others). It is explained once here, and this paragraph is linked from each of the -functions using this procedure.
- -
+functions using this procedure.
+
When image files are selected, a dialog box appears with an empty list for the selected image files. Behind it is a gallery window which permits the selection of multiple images. To select an image, click its thumbnail and the image file will be added to the list. You can -navigate the gallery window to other directories and choose images in any order. The +navigate the gallery window to other directories and choose images in +any order. The list of image files can also be manipulated to change the sequence or remove images added by mistake. Click @@ -298,1180 +397,1127 @@ image files in the current image gallery. After using Search Images to establish a set of images, the gallery window will contain this set. You can select individual images from the gallery, or -use [add all] and then delete unwanted images.
- +use [add all] and then delete unwanted images.

-
- -Fotoxx -Menus and Toolbar Buttons
- -
+Fotoxx +Menus +and +Toolbar +Buttons
+
- - - +
- + + - + + - + - - + - + + - - - - + + + - + + - - + - + + - - + - + + - - + + - + - + + - - + + - - - - - - - - + - - + + +
File menuFile +Menu File Management
-
-
Image Gallery
-
-
Show thumbnail images - + Show thumbnail +images - image files in the current directory (more).
-
-
Clone 50/50
Clone Fotoxx and share the desktop 50/50 with the old instance (more).Clone Fotoxx and +share the desktop 50/50 with the old instance (more).
Clone Overlay
Clone Fotoxx and open a new window slightly offset from the old one (more).
+
Clone Fotoxx and open a +new window slightly offset from the old one (more).
Open Image File
-
-
File open dialog - open + File open dialog +- open an image file to view or edit (more).
-
-
Open in New Window
File open dialog - open new file in a new window (more).
+
File open dialog - open +new file in a new window (more).
Open Previous File
-
-
Go back to the last image +
Open Previous +File
+
Go back to the +last image file opened (more).
-
-
Open Recent File
-
-
Choose from a list of the + Choose from a +list of the most recent image files opened (more).
-
-
Save to Same File
-
-
Save modified image to + Save modified +image to the same file (overwrite) (more).
-
-
Save to New Version
Save modified image to the same file with a new version number appended (more).
+
Save modified image to +the same file with a new version number appended (more).
Save to New File
-
-
Save modified image to a + Save modified +image to a new file (more).
-
-
Create Blank Image
-
-
Create a new blank image file (more).
-
-
Create Blank +Image
+
Create a new +blank image file (more).
+
Trash Image File
-
-
Move an image file into + Move an image +file into the trash bin (more).
Rename Image File
-
-
Rename image files, optionally add sequence numbers (more).
-
-
Rename image +files, optionally add sequence numbers (more).
+
Batch Rename Files
-
-
Rename many image files + Batch Rename +Files
+
Rename many +image files using a base name and sequence number (more).
-
-
Print Image FileSelect printer / paper + Select printer / +paper format / orientation and print image (more).
Quit Fotoxx
-
-
Exit from Fotoxx.
-
-
- -
+
- - - - - +
- - + + - - - - - + + + - - + + - - - + + + - - - + + - - + + - - + + - - + + - - + + - - + + - - - + + + - - + + - - + + - - + + - - - - + + + + - - + + - - - - - -
Tools -menu
-
-
Utilities and setup functions.
-
-
Tools Menu
+
Utilities and +setup functions.
+
Manage Collections
Assign images to named collections, arrange the sequence, etc. (more).
+
Make image collections, +arrange the sequence, etc. (more).
Move Collections
Update collections when image top directory is changes (more).
+
Update collections when +image top directory is changed (more).
Check Monitor
-
-
Display a color palette -for tuning your monitor (more).
-
-
Batch Convert
+
Convert / resize +/ export images +(for upload to the web, e-mail, etc.) (more).
Monitor Gamma
-
-
Adjust monitor gamma to optimum for image editing (more).
-
-
Convert RAW FilesConvert RAW +image files to tiff (more).
Brightness Graph
-
-
Show brightness -distribution graph of current image (more).
-
-
Slide ShowShow a series of +images full +screen +(no menu or toolbar) (more).
Slide Show
-
-
Show images full screen -(no menu or toolbar) (more).
-
-
Synchronize FilesRebuild the +image search index and refresh thumbnails (more). + + + + + + + + + + + + + + + + + + + + + + + + +
Show RGB
-
-
Show RGB values at -position of mouse click (more).
-
-
Show RGBShow RGB values +at +position of mouse click (more).
Grid Lines
-
-
Add or remove grid lines -for image alignment (unbend, rotate) (more).
-
-
Grid LinesAdd or remove +grid lines +for image alignment (warp, rotate) (more).
Lens Parameters
-
-
Edit parameters for your -cameras and lenses (more).
-
-
Burn Images to +CD/DVDSelect images +and write +them on a CD or DVD (more).
Change Language
-
-
Change the GUI language (more).
-
-
E-mail ImagesSelect images, +downsize, +send to your E-mail program (more).
Edit Translations
-
Revise the translations interactively (more).
-
Check Monitor
+
Display a color +palette +for tuning your monitor (more).
+
Add Menu and Launcher
-
-
Add a desktop menu entry and a desktop launcher (more).
-
-
Monitor Gamma
+
Adjust monitor +gamma for better image editing (more).
+
Convert RAW Files
-
-
Convert one or many RAW -image files to tiff (more).
-
-
Brightness +Distribution
+
Show brightness +distribution graph of current image (more).
+
Burn Images to CD/DVD
-
-
Select images and write -them on a CD or DVD (more).
-
-
Change Language
+
Change the GUI +language (more).
+
E-mail Images
-
-
Select images, downsize, -send to your E-mail program (more).
-
-
Edit Translations
+
Revise a translation +interactively (more).
+
Synchronize Files
-
-
Rebuild the image search index and refresh all thumbnails (more).
-
-
Toolbar Style
+
Menu and +Launcher
+
Add a system +menu entry and desktop launcher (more).
+
User Settings
Set toolbar style to text, icons, or both (more).
+
A collection of user +preferences and settings (more).
Memory Usage
Dump a memory usage table to the log file (more).
+
Dump a memory usage table +to the log file (more).
- -
+
- - - - - +
- - - - + + + - - + + - - + + - + - - + + - + - + - + - - + - + + - + + - + - - + + + + - + + + + + - -
Info Menu
-
-
View and edit image data and attributes
-
-
Info Menu
+
View and edit +image data and attributes
+
Edit Caption/Comments
-
-
Add or change descriptive text for an image (more).
-
-
Edit +Caption/Comments
+
Add or change +descriptive text for an image (more).
+
Tags Overview
-
-
Explanation of tags and how they are used (more).
-
-
Explanation of +tags and how they are used (more).
+
Edit Tags
-
-
Add or change image tags + Add or change +image tags (keywords), stars rating, or date (more).
Manage Tags
-
-
Create tags and tag categories (more).
-
-
Create tags and +tag categories (more).
+
Batch Add Tags
-
-
Add many tags to many + Add many tags to +many images at once (more).
Batch Delete Tag
-
-
Delete or replace one tag + Delete or +replace one tag for many images at once (more).
View Info (short)
-
-
View most important image data (more). View most +important image data (more).
View Info (long)
-
-
View all available image data (more). View all +available image data (more).
Edit Info
-
-
Add or change the data + Add or change +the data for a specific key (more).
Delete Info
-
-
Delete a specific key or all image data (more).
Delete a +specific key or all image data (more).
Search ImagesFind images with desired -tags / stars / dates / comments / captions (more).Find images with +desired +tags / stars / dates / comments / captions (more).
Search Metadata
+
Search and report any +desired metadata (EXIF/IPTC/etc.) (more).
+
- -
+
- - - - - +
- - + + - + + - + - + + - + + - + + - + + - + + - - - - - + + + + + + + + - + + - -
Select menu
-
-
Selected areas within images where edits + Select Menu
+
Selected areas +within images where edits are confined
-
-
Overview
-
-
Explanation of area + Explanation of +area selection and editing (more).
-
-
Select
-
-
Select an area for + Select an area +for subsequent editing (more).
Show / Hide
-
-
Show or hide an area + Show or hide an +area outline (more).
-
-
Enable / Disable
-
-
Enable or disable an area + Enable or +disable an area for subsequent editing (more).
-
-
Invert
-
-
Invert an area (more).
-
-
Invert an area (more).
+
Unselect
-
-
Unselect an area (more).
-
-
Unselect an area +(more).
+
Copy / Paste
-
-
Copy an area to memory + Copy an area to +memory and paste it somewhere else (more).
-
-
Open / Save
-
-
Save an area to a file and load it later to use in other images (more).
-
-
Select Whole Image
-
-
Select the whole image as a mask for retouch edit functions (more).
-
-
Save an area to +a file and load it later to use in other images (more).
+
Select Whole +Image
+
Select the whole +image as a mask for retouch edit functions (more).
+
Select and Edit
-
-
Mouse over an image area to apply an edit function incrementally (more).
-
-
Mouse over an +image area to apply an edit function incrementally (more).
+
- -
+
- - - - - - +
- - + + - + - + - - - + + - - + + - + + - + + - + - + - + - - + - + + - - + + - - + - - + +
Transform menuFunctions that change image + Transform MenuFunctions that +change image size, shape, content
-
-
Rotate ImageRotate an image (level an image or turn in 90 steps) (more).Rotate an image +(level an image or turn in 90° steps) (more).
Trim ImageCut out a rectangular + Cut out a +rectangular portion of an image (more).
Resize Image
-
-
Scale an image up or down -(more).
-
-
Auto-Trim Image
+
Auto-select trim margins +to remove after rotate, unbend, or warp functions (more).
+
Batch Resize / Export
-
-
Resize multiple images -(for upload to the web, e-mail, etc.) (more).
-
-
Resize Image
+
Scale an image +up or down +(more).
+
Annotate Image
-
-
Write text annotations on an image (more).
-
-
Write text +annotations on an image (more).
+
Flip Image
-
-
Mirror an image horizontally or vertically (more).
-
-
Make NegativeMake a black-white or -color negative, or a positive from a negative (more).Make a +black-white or +color negative, or a positive from a negative (more).
Unbend ImageFix perspective problems (more).Fix perspective +problems (more).
Keystone Correction
Straighten a photo made from an offset angle (more).
+
Straighten a photo made +from an offset angle (more).
Warp Image (area)
-
-
Distort image within an + Distort image +within an area by pulling with the mouse (more).
-
-
Warp Image (curved)
-
-
Distort entire image by + Warp Image +(curved)
+
Distort entire +image by pulling with the mouse (more).
-
-
Warp Image (linear)
-
-
Distort entire image by + Warp Image +(linear)
+
Distort entire +image by pulling with the mouse (more).
Warp Image (affine)
-
-
Distort entire image by + Warp Image +(affine)
+
Distort entire +image by pulling with the mouse (more).
-
-
- - -
- - - - - - +
+
- - + + - + +contrast, color saturation, color balance (more). - + +brightness levels and expand the rest (more). - - + - - + - + - + + - + - + - + - + - - - - - - - - - - - + + - + + - + - + + + - - + + + + - - + + + + + + + + - - - - -
Retouch menu
-
-
Functions that change image + Retouch Menu
+
Functions that +change image qualities
-
-
Brightness / ColorBrightness / +Color Edit brightness, -contrast, color saturation, color balance (more).
Gamma CurveEdit brightness and color using the classic gamma curve (more).Edit brightness and color +using the classic gamma curve (more).
Expand Brightness Clip low / high -brightness levels and expand the rest (more).
Flatten BrightnessFlatten the brightness + Flatten +BrightnessFlatten the +brightness distribution to enhance detail (more).
Brightness RampHorizontal / Vertical + Horizontal / +Vertical variation of brightness (more).
Tone MappingIncrease local contrast to to enhance details (more).Increase local +contrast to to enhance details (more).
White Balance
-
-
Remove false color from an image (more).
-
-
Remove false +color from an image (more).
+
Match ColorsMatch the colors in one image to those in another image (more).Match the colors in one +image to those in another image (more).
DRGBChange brightness or RGB colors using OD units (more).Change brightness or RGB +colors using OD units (more).
Revise RGBMake complex color corrections that vary over the image (more).Make complex color +corrections that vary over the image (more).
Red EyesRemove red eyes from flash photos (more).Remove red eyes +from flash photos (more).
Blur Image
-
-
Blur an image (e.g. smoothen + Blur an image +(e.g. smoothen skin) (more).
-
-
Sharpen Image
-
-
Sharpen a blurred image + Sharpen a +blurred image (more).
-
-
Reduce Noise
-
-
Reduce noise (speckles) + Reduce noise +(speckles) in low-light images (more).
-
-
Smart Erase
-
-
Remove power lines and other spoilers by substituting neighboring pixels (more).
-
-
Remove power +lines and other spoilers by substituting neighboring pixels (more).
+
Remove Dust
-
-
Remove dust spots on images made from scanned slides (more).
-
-
Remove dust +spots on images made from scanned slides (more).
+
Fix Stuck Pixels
+
Fix stuck pixels (always +bright or dark) from defective camera sensor (more).
+
Edit PixelsEdit pixels and paint + Edit pixels and +paint lines or areas using the mouse (more).
- -
-
-
Art menuFunctions that make artful +
+
+ + + + + + - + + - + + - + + - + - + + - + + - + + - + - + + -
Art MenuFunctions that +make artful transformations
-
-
Color Depth
-
-
Reduce color depth + Reduce color +depth (posterize) (more).
-
-
Drawing
-
-
Transform a photo into a + Transform a +photo into a simulated pencil or chalk drawing (more).
-
-
Outlines
-
-
Transform a photo into a colorized line drawing (more).
-
-
Transform a +photo into a colorized line drawing (more).
+
Embossing
-
-
Transform a photo into a + Transform a +photo into a simulated embossing (more).
-
-
Tiles
-
-
Transform a photo into + Transform a +photo into tiles (pixelate image) (more).
-
-
Dots
-
-
Transform a photo into an array of dots (more).
-
-
Transform a +photo into an array of dots (more).
+
Painting
-
-
Transform a photo into a + Transform a +photo into a simulated painting (more).
-
-
- -
+
- - - - - +
- - + + - - + + - - + + - + + - + - + + - - + + -
Combine menuFunctions that combine multiple + Combine MenuFunctions that +combine multiple images
-
-
High Dynamic Range
-
-
Make a high dynamic range + High Dynamic +Range
+
Make a high +dynamic range image from multiple images (more).
-
-
High Depth of Field
-
-
Make a high depth of + High Depth of +Field
+
Make a high +depth of field image from multiple images (more).
-
-
Stack / Paint
-
-
Combine multiple images to remove tourists and cars (more).
-
-
Combine multiple +images to remove tourists and cars (more).
+
Stack / Noise
-
-
Combine multiple images + Combine multiple +images to reduce noise (more).
-
-
Panorama / Vertical Panorama - Join 2-4 overlapping images + Panorama / +Vertical Panorama Join 2-4 +overlapping images to make an ultra-wide image (more).
-
-
 
+
+ 
- +
- - + + -
Plugins menu
-
-
Other image edit programs can be used as edit functions in foloxx (more).
-
-
Plugins Menu
+
Other image +edit programs can be used as edit functions in foloxx (more).
+

+ + 
- - - - - +
- - + + -
Help menuUser guide, README, + Help MenuUser guide, +README, change log  (more).
-
-
   - -
+ +   +
- - - - - +
- - + + + - - + + - + + - - - - + - - + + - - + + + - - - - - - + + - + + -
Toolbar Buttons
-
-

-
-
Toolbar +Buttons
+

+
Gallery
-
+
Show thumbnails +of image flles in the current directory (more). Show thumbnails of image flles in the current directory (more).
Open
-
-
File open dialog - open + File open dialog +- open an image file to view or edit (more).
-
-
Prev / Next
-
-
Go to previous or next image in + Go to previous +or next image in the current directory or search set.
-
-
Zoom+Magnify the image. A left + Magnify the +image. A left mouse click also magnifies.
Zoom-Reduce the image to fit window. A right + Reduce the image +to fit window. A right mouse click also reduces.
Undo / RedoUndo one edit / Redo one edit - up to 99 edits of the current image.Undo one edit / +Redo one edit - up to 99 edits of the current image.
Shift-key + Redo / RedoChanges the buttons to [undo all] and [redo all]. Shift-key + Redo +/ RedoChanges the +buttons to [undo all] and [redo all].
Save / Save+V / Save+F
-
-
Save / Save+V / +Save+F
+
Save image to the same file, to a new version, or to a new file (more).
-
-
TrashMove an image file into + Move an image +file into the trash bin (more).
Quit
-
-
Exit from Fotoxx.
-
-
Help
-
-
Show online user guide (more).
-
-
Show online user +guide (more).
+
 
- -
- - +
+  
+
+ - + + - - - + + + - - + + - - + + - + + - + + - + + - + + - + + - - - + - + + - + + - - + - + + - + + - - + + + @@ -1481,153 +1527,157 @@ - - - + + + - + + - - + + - - + - - + - - + + - + + - + + - + - + + + -
Keyboard Shortcuts
-
-
Keyboard Shortcuts
+

-
-
Main Window
-
-
shows current image file to view oe edit
-
-
Main Window
+
shows current +image file to view oe edit
+
left / right arrow keys
-
-
previous / next image
-
-
left / right +arrow keys
+
previous / next +image
+
plus(+) / minus(-)  + plus(+) / +minus(-)  keys
-
-
zoom image bigger / smaller
-
-
zoom image +bigger / smaller
+
Z  key
-
-
toggle: zoom image to 100% / fit image in + toggle: zoom +image to 100% / fit image in window
-
-
R / L  keys
-
-
rotate image 90 right / left (change is permanent)
-
-
rotate image +90° right / left (change is permanent)
+
G  key
-
-
toggle grid lines on or + toggle grid +lines on or off
-
-
T  key
-
-
shortcut for menu + shortcut for +menu Transform > Trim
-
-
B  key
-
-
shortcut for menu Retouch + shortcut for +menu Retouch > Brightness/Color
-
-
A key
change toolbar undo/redo buttons to undo/redo ALL edits
+
change toolbar undo/redo +buttons to undo/redo ALL edits
N key
shortcut for menu File > Rename Image File
+
shortcut for menu File +> Rename Image File
Delete key
-
-
move image to trash bin
-
-
move image to +trash bin
+
Escape key
-
-
Exit slide show mode
-
-
Exit slide show +mode
+
Spacebar
pause and resume slide show timer
+
pause and resume slide +show timer
Control + s
-
-
Save to original file (no + Save to original +file (no questions asked)
-
-
Control + S
-
-
Save+F: dialog to choose + Save+F: dialog +to choose a target file
-
-
Control + v or V
Save+V: save to new version (no questions asked)
+
Save+V: save to new +version (no questions asked)
Control + q or Q
-
-
Quit Fotoxx
-
-
Control + z or ZControl + Shift + z or Z redo one edit level
Image Gallery window
-
-
thumbnail images of current directory
-
-
Image Gallery window
+
thumbnail images +of current directory
+
Home / End keys
-
-
move to first / last page + move to first / +last page of image gallery
-
-
Page Up / Down keys
-
-
move to previous / next + Page Up / Down +keys
+
move to previous +/ next page of image gallery
-
-
up / down arrow keys
-
-
move up / down by one row + up / down arrow +keys
+
move up / down +by one row of image gallery
left / right arrow keys
-
-
move to previous / next + left / right +arrow keys
+
move to previous +/ next page of image gallery
plus(+) / minus(-)  + plus(+) / +minus(-)  keys
-
-
bigger / smaller thumbnail size
-
-
bigger / smaller +thumbnail size
+
Escape key
-
-
close image gallery window
-
-
close image +gallery window
+
Dialogs for User Input
-
-
Dialogs for User Input
+
 
-
-
F1 function key
-
-
display user guide + display user +guide section for current function
-
-
Escape key
cancel dialog
- -
+
- - - +
- + + - + - + + - + + - + +
Mouse Functions
-
-
Mouse Functions
+

-
-
left click
-
-
Zoom-in: magnify + Zoom-in: +magnify image, center at click position.
-
-
right click
-
-
Zoom-out: restore + Zoom-out: +restore image to window size.
-
-
drag on image
-
-
Scroll a zoomed image in the opposite direction, like a scroll bar.
-
-
Scroll a zoomed image in the opposite +direction, like a scroll bar.
+
- -
+

-Some supplimentary
technical notes -can be found here.
- -
- -
-
-File Menu
- -
- +Some supplimentary
technical notes +can be found here.
+
+ +
+
+File +Menu
+
Navigation

- -
+
Use the Image Gallery menu or the [gallery] toolbar button to open an image gallery window (thumbnails) showing -image files in the current directory, the latest search results, or the current named collection. Use this window to scroll +image files in the current directory, the latest search results, or the current named collection. Use this window to scroll around the directory and select image files by clicking thumbnails. The buttons at the top allow scrolling forward or back by rows or pages. Use the @@ -1635,11 +1685,12 @@ the [bigger] and [smaller] buttons to change the thumbnail size and the number of visible thumbnails. Pressing the [gallery] button in the Fotoxx main window -will bring the gallery window forward with the current image file in the top row. Clicking on a thumbnail will bring +will bring the gallery window forward with the current image file in +the top row. Clicking on a thumbnail will bring the Fotoxx main window forward with the selected image. The windows seem to replace each-other, but one is only on top of the other, and -they can be dragged apart if you want to view both.
- +they can be dragged apart if you want to view both.

There are three types of image gallery windows: (1) the image files in @@ -1649,10 +1700,9 @@ The title bar of the window will show the directory path, "Search Results", or the collection file name.

-

+

Clone Fotoxx

- - Start a new instance of Fotoxx in a new window. There are two variations: split the screen 50/50 between the two windows, or open the new window over the old @@ -1664,11 +1714,11 @@ edits have been done. If the same file is edited in both windows, the result will depend on whichever window saved it last. Use the toolbar button [Save+F] if you want to keep both -image files.
-
-
+image files.

+
+
Open Image File

- This function starts a standard file open dialog, allowing you to select an image file or navigate to another directory and select an @@ -1708,42 +1758,70 @@ of Fotoxx. The current file remains in the old instance. This function is a combination of open file and clone.

-

- -Open Previous File
- -Go back to the previously opened image file, also if this is in a +
+Open Previous +File
+Go back to the previously opened +image file, also if this is in a different directory. This differs from the toolbar button [Prev] which goes to -the previous image file in the same directory as the current image file, or the previous image in the last search results.
- -
- -
- -Open Recent File
- -The 99 previously opened image files are presented in a list, from -which you can select a file to open.
+the previous image file in the same directory as the current image +file, or the previous image in the last search results.
+
+
+Open Recent +File
+The 99 previously opened image +files are presented in a list, from +which you can select a file to open.

-
+
Save Image File
-
Menu -File >
Save to Same File  -or toolbar button [Save]
Save +File >
Save to Same File  +or toolbar button [Save]
+Save the current -image file back to itself.
If the file is a +image file back to itself. If the file is a JPEG -file, the default quality (90) is used. If this is an original file (not a versioned file), you will be warned that you are overwriting the +file, the default quality (90) is used. If this is an original file +(not a +versioned file), you will be warned that you are overwriting the original file. You can override the warning and continue. You can also -elect to permanently supress this warning if wanted. If you have disabled the warning and wish to reinstate it, you must edit the file /home/<user>/.fotoxx/parameters  and change the value of "warn overwrite" from "0" to "1".
-
-Menu File > Save to New Version  or toolbar button [Save+V]
-Save the current image file with a new version number. File names with +elect to permanently supress this warning if wanted. If you have +disabled the warning and +wish to reinstate it, you must edit the file /home/<user>/.fotoxx/parameters  +and +change +the +value +of +"warn +overwrite" +from +"0" +to +"1". +
+
+Menu File > Save to New Version  +or +toolbar +button +[Save+V]
+Save the current image file with a new version number. File names with version numbers are formatted "filename.vNN.ext" where NN is a version number 01 to 99.  The 4 characters .vNN are inserted between the file name and extension. If the file name has no versions, version .v01 @@ -1751,9 +1829,15 @@ next higher version number is used. There is no dialog or confirmation. If the file is a JPEG file, the default quality (90) is used.

-Menu File >
Save to New -File  or toolbar button [Save+F]
-
+Menu File > Save to New +File  or toolbar +button +[Save+F]
+
A dialog opens to save the current image @@ -1779,141 +1863,137 @@ an image with higher bits has more latitude when the brightness is altered with a program like Fotoxx. If "make current" is checked, the newly saved file will become the current file. In either case, the edit -history is retained (i.e. undo and redo still work).
- +history is retained (i.e. undo and redo still work).

File sizes for a 10 megapixel image are roughly as -follows (depending on amount of detail):
- - - - +follows (depending on amount of detail):
+
-
 tiff-16
-
 tiff-8
-
 png
-
 jpeg-100
-
 jpeg-90
-
 jpeg-80
-
 jpeg-70
-
 58 MB
-
 19 MB
-
 14 MB
-
 7 MB
-
 2 MB
-
 1 MB
-
 0.6 MB
-
  - -
+ +
+There is a technical note about JPEG files and loss +of image quality.
+  +

Create Blank Image

-Create a blank image with specified pixel dimensions and color. This +Create a blank image with +specified pixel dimensions and color. This can be used as a background for a mashup using cutouts taken from other images (via Select Area) and annotation text (via Annotate Image). Input a file name, choose a background color, and set the desired pixel dimensions.
-
- -
+
Trash Image File
- Fotoxx uses the Linux desktop standard for trash. If this works, trashed image files go into the -standard trash location and can be recovered later if wanted. Otherwise, Fotoxx puts trashed images into a desktop directory +standard trash location and can be recovered later if wanted. +Otherwise, Fotoxx puts trashed images into a desktop directory named "fotoxx-trash". You can delete it or move it to your Linux-specific trash. If standard trash does not work, you -may be able to fix this yourself. See the technical note about this.
- +may be able to fix this yourself. See the
technical note about this.

- -
+
Rename Image File

- -
+
This function can help automate the process of renaming a series of image files using a root name (e.g. an event or place name) and a sequence number. It is good for renaming a series of image files from a digital camera. Open the first image file in the series, input a new name, -and press the [rename to] button. Use the [next] button to move to the next file if wanted. You can +and press the [rename to] button. Use the [next] button to move to the +next file if wanted. You can use the same name again by pressing the [previous] button and then add a suffix or sequence number. If you are using sequence numbers, press the [ +1 ] button after the [previous] button to get the next sequence number added to the name.
-
- -
- +
Batch Rename -Files
- -This function is helpful if you want many image files (perhaps with the +Files
+
+This function is helpful +if you want many image files (perhaps with the same date or from the same event) to have the same names with an added sequence number. In the dialog, specify a base name, a starting sequence number, and an increment. For example, a base name of "arctic cruise-", a starting sequence number of 100, and an increment of 1 will -produce a series of file names like this: arctic cruise-100, arctic cruise-101, arctic +produce a series of file names like this: arctic cruise-100, arctic +cruise-101, arctic cruise-102, etc. (file extensions will not be changed). Use the button [select files] to open a file chooser dialog to select as many image files as you want. When done, press [proceed] to rename all the image files at once. Don't use this function to rename non-image files, since Fotoxx -will also try to update file name and tag associations in the search index file.

- +will also try to update file name and tag associations in the search +index file.


- -
+
Print Image File

- - The print menu brings up a standard Page Setup dialog where you can select a printer, a paper size (letter, A4 ...), and orientation (portrait or landscape). Select your printer (do not use a default setting). The paper size shown will be the one last set in the Printer Properties -dialog (a separate admin function in the System menu). If the paper -size is wrong, fix it using the Printer Properties dialog. Changing the paper in the Page Setup dialog may be ignored or lead to a "paper mismatch" failure. After +dialog (a separate admin function in the System menu). If the paper +size is wrong, fix it using the Printer Properties dialog. +Changing the paper in the Page Setup +dialog may be ignored or lead to a "paper mismatch" failure. After using the [apply] button, another dialog starts for entering the print margins. Use these to shrink the image size on the paper or shift the image position. When done, a Print dialog starts for the actual @@ -1921,16 +2001,15 @@ right orientation and position and cancel the print if not.


-
Tools Menu
+
Tools +Menu
- -
- - -Manage Collections - Concepts
- - -An image collection is an arbitrary collection of images that is +
+Manage +Collections - Concepts
+An image collection is an +arbitrary collection of images that is manually assembled from other images. This is one method to make groups of associated images (other methods are tags, captions and comments, directory and file names). An image @@ -1942,18 +2021,29 @@ collection, etc. Once a collection is made, you can call it up by name and use it for other purposes, e.g. view as a slide show or burn to a CD. You can add and remove images in a collection and rearrange the -order of the images. An image may also be present multiple times in a collection.
+order of the images. An image may also be present multiple times in a +collection.

-Manage Collections Dialog

+Manage Collections Dialog

- -
-New: Supply a new collection name. This will be named in the dialog as the "Editing" collection.
-Edit: Select an existing collection for editing.
This will become the "Editing" collection.
+
+New: +Supply a new collection name. This will be named in the dialog as the +"Editing" collection.
+Edit: Select an existing +collection for editing. This +will +become +the +"Editing" +collection.
View: Select a collection for viewing. The gallery window will show its thumbnails. This can be the collection being edited or any other.
-Delete: Select an existing collection to delete. The collection is deleted, not the images.
+Delete: Select an existing +collection to delete. The collection is deleted, not the images.

After a collection for editing is created or selected, you can add or remove images by right clicking on a gallery thumbnail or main window @@ -1989,51 +2079,69 @@ and new top directory names in the dialog and press [apply].

-

-Check Monitor

- -Eight color bands are written across the screen with brightness from -zero (black) to 100%. You can use this to adjust the brightness of your monitor. The left end of each stripe should be as black -as possible, but you should start to see some color within a few mm -from the left edge. If the completely black portion is wider than this, -adjust the monitor. There are 255 brightness steps from black to 100% -(8 bits per color). The steps are too small to distinguish with the -eye. This evaluation -should be done -in a darkened room (with little external light falling on the monitor).
- -
- -
- -Monitor Gamma
- -Gamma determines how RGB brightness values (0-255) are converted into -brightness as perceived by the eye. The standard value is 2.2 and this -should normally be used for image editing. An adjustment chart is provided, courtesy of Norman Koren. -Adjust the dialog slider until the shaded bands disappear at scale -location 2.2. The chart only works at 100% size, so do not zoom the -chart.
- -
- - - +
+Batch Convert +/ Resize +/ Export
+
- -
- -Brightness Graph

- -This function opens a small window that shows a brightness -distribution graph of the current image in the main window. This graph -updates immediately for new images or as edit functions change the image.
- -

+This function is used to +convert, resize +and export many image files at once (for planned +uploads +to a web site, to save disk space, etc.). The menu opens a dialog to +select image files and specify options. Use the button [select files] +to select image files from a gallery window (link). +Select a maximum width and height for the output files (use huge values +if no size reduction is wanted). Select the output file type. "same" +means the file type will not be changed, otherwise all files will be +converted to the specified type. Select the +option: "replace originals" +or "export to location". For the latter, input a directory where the +resized and converted image files will be written, or use the [browse] +button to +locate the +directory. Use the +checkbox to remove EXIF/IPTC data from the output files, if desired. +Finally, use the [proceed] button to +start the +resize process. A popup window shows the progress.
+
+
+Convert RAW +Files
+This function converts selected +RAW image files to +JPEG, PNG, TIFF-8 or TIFF-16 format, using the program ufraw-batch. The +two TIFF formats have respectively 8 and 16 bits per color. RAW files +generally have 10-12 bits, therefore use TIFF-16 to keep all of the +data available in a RAW file (the difference between 8 and 16 bit color +is rarely visible). A file chooser dialog +is +opened. Choose one or more RAW image files (hold down the CTRL key to +select +multiple files). Then you will be asked to choose one of the above +output formats. The image files are converted one at a time and +displayed in +the +main window. Depending on the number of files, this can take a long +time (my fast PC does about 24 image files per minute using +a mix +of raw file types and TIFF-16 output).
+
+
Slide Show
-
+
- The images in the current directory, from a named collection, or from a previous search function are shown one @@ -2054,7 +2162,9 @@ can still be used even if one of the other modes is selected. Use the escape key to get out of slide -show mode. The spacebar can be used to pause and resume the timer between slides. If an image search +show mode. The spacebar can be used to pause and resume the timer +between slides. If an image +search is done before a slide show, these images are shown. Before starting the slide show, you can use the function Info > Edit Comments or Edit Caption to @@ -2062,27 +2172,92 @@ push to the side. The text is updated for each image viewed in the slide show. The other Info menu displays will also update with each image. The slide show dialog also has an input for a music file or -playlist. If not blank, the music will be started with the slide show.
- +playlist. If not blank, the music will be started with the slide show.


-It is also possible to start a slide show with or without music from the command line:
-   $ fotoxx -slideshow /.../imagefile1.jpg  -music /.../musicfile.ogg
+It is also possible to start a slide show with or without music from +the command line:

+   $ fotoxx -slideshow +/.../imagefile1.jpg  -music /.../musicfile.ogg
The slide show begins with the given image file and proceeds to following files in the same directory. The -music parameter is optional. If present, the following file is a music file (.mp3 .ogg ...) or a playlist. xdg-open is used to open the file with the preferred music player.
-
- -
-Show RGB

+
+Synchronize +Files
+
+
+This is needed when Fotoxx is +started for the first time, if you add new image +files to your collection, or if you +move or rename image files or their directories. Nothing is lost when +image files are moved, but the image gallery (thumbnail) windows will +be +slow if a large number of files were added or moved, and the Search +Images +function will not find the new or moved files. The Synchronize Files +function will +create missing thumbnails, replace outdated ones, and refresh the +search index file using current data from your image files. On a fast +computer, new files +are processed at 1000+ per minute and old files at 1000+ per second.
+
+Images created (i.e. +edited and saved) or moved within Fotoxx are taken care of +automatically. +Synchronize Files is only needed when new image files are created from +outside Fotoxx (e.g. a new batch of files from a camera), or if files +are moved or renamed from outside Fotoxx.
+

+If you have +used directory +and/or file names to classify your images, you can make immediate use +of these in the Search Images function. If you have saved captions, +tags, titles, or ratings in your images (using Photoshop, Fotoxx, or +other +tools), these will also be searchable.
+
+Synchronize +Files starts +automatically at Fotoxx startup if image files are detected with a +date/time newer than the last Fotoxx session. It can also be started +manually from the Tools menu. A dialog will ask +for the topmost directory of your image files (e.g. +/home/<user>/Pictures). That directory and any +subdirectories containing images will be +processed. +It +does not matter if other files are mixed. A popup window shows the new +image files as they are found and processed. This window is left open +for your inspection after the synchronize function is finished. After +the images have been +indexed, +searching them (by captions/comments, file names, tags, date, rating) +is almost instantaneous.

+
+When Synchronize runs, you can +use Fotoxx normally to navigate and view images, but editing images and +metadata (tags, comments, etc.) is blocked until Synchronize is +finished. You can see in the status bar if Synchronize is running. +Unless there are hundreds of new images to process, this will be done +in a few seconds.
+
+
+Show RGB

-
+
- When a point on the image is clicked, the RGB values are shown in a dialog window. The values have the format @@ -2101,88 +2276,95 @@ the dialog window.

- +
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  RGB
+
  +RGB
0
+
0
1
+
1
2
+
2
4
+
4
8
+
8
16
+
16
32
+
32
64
+
64
128
+
128
256
+
256
  EV
+
  +EV
nan
+
nan
-7
+
-7
-6
+
-6
-5
+
-5
-4
+
-4
-3
+
-3
-2
+
-2
-1
+
-1
0
+
0
1
+
1
  OD
+
  +OD
nan
+
nan
2.41
+
2.41
2.11
+
2.11
1.81
+
1.81
1.51
+
1.51
1.20
+
1.20
0.90
+
0.90
0.60
+
0.60
0.30
+
0.30
0.0
+
0.0
-
- -
- -Grid Lines
- +
+
+Grid Lines
+
+
This function adds or removes horizontal and vertical lines across the image. The lines are @@ -2197,20 +2379,107 @@ y-grid checkboxes can be used to enable and disable the veritcal and horizontal lines separately. The keyboard key G can be used to toggle the grid lines on and off. -This works also during an edit function. If an image is printed with grid lines enabled, +This works also during an edit function. If an image is printed with +grid lines enabled, the grid lines are also printed.
-
- -
- - -Lens Parameters

- -This is a dialog for setting and saving the two lens parameters, +
+Burn Images to CD/DVD

+This function enables you to +choose image files and burn them into a CD +or DVD. When the function starts, an image +gallery window is displayed from which you can select the image files +to burn (link). When +done, the list of image files is sent to +Brasero to burn a CD or DVD.
+
+
+E-mail +Images
+This function enables you to +choose up to about 40 image files and send them to your preferred +e-mail program. In the dialog, press the [select files] button to +display an image +gallery window from which you can select the image files (
link). +After +selecting the images, set the desired +maximum width and height in the dialog. The [proceed] button will do +the image reductions and send them to the e-mail program. The reduced +images are put into a temporary directory (/tmp/<user>/fotoxx/) +and do not affect the original images. The e-mail program is started +with the selected image +files as attachments. You must then add the subject, text and +recipients, and finally send the e-mail.
+
+This function uses +xdg-email +(Linux Standards Base) which must be installed and work correctly. It +works for some Linux flavors with some e-mail programs and not for +others. If it does not work for you, then +the next best appproach is to use Transform > Batch Convert to +select, optionally reduce, and export the image files to your Desktop. +Then you can conveniently attach them from within your e-mail program.
+
+

+Check Monitor

+Eight color bands are written +across the screen with brightness from +zero (black) to 100%. You can use this to adjust the brightness of your +monitor. The left end of each stripe should be as black +as possible, but you should start to see some color within a few mm +from the left edge. If the completely black portion is wider than this, +adjust the monitor. There are 255 brightness steps from black to 100% +(8 bits per color). The steps are too small to distinguish with the +eye. This evaluation +should be done +in a darkened room (with little external light falling on the monitor).
+
+
+Monitor Gamma
+
+Gamma determines how RGB +brightness values (0-255) are converted into +brightness as perceived by the eye. The standard value is 2.2 and this +should normally be used for image editing. An adjustment chart is +provided, courtesy of Norman Koren. +Adjust the dialog slider until the shaded bands disappear at scale +location 2.2. The chart only works at 100% size, so do not zoom the +chart.
+
+ +
+Brightness Distribution

+This function opens a small +window that shows a brightness +distribution graph of the current image in the main window. This graph +updates immediately for new images or as edit functions change the +image.
+
+
+Lens Parameters
+
+
+This is a dialog for setting and +saving the two lens parameters, lens_mm and lens_bow, which must be set for each camera/lens used for -panoramas. These parameters govern how Fotoxx "bends" the panorama +panoramas. These parameters govern how Fotoxx warps the panorama input images so that they can fit together accurately. Enter a name for the lens/camera and the two parameters. Up to four lens/cameras may be entered. Lens_mm is roughly the focal length of the lens (35mm @@ -2218,60 +2487,27 @@ distortion (barrel and pincushion distortion). How to set these parameters is described here, but you should read the section on making panoramas first, in order to better -understand the following instructions.
+understand the following instructions.

-Setting Lens Parameters Automatically

- -The [search] button in the panorama pre-alignment dialog initiates an -automated -search for optimum lens parameters. Use a suitable image pair: the -subject is 50+ meters away, the images have a low horizon -difference and little relative rotation, and there is plenty of -high-contrast detail in the overlap area. Input your nominal lens focal -length -for lens_mm. Use zero for lens_bow. After doing a decent pre-align, -press the [search] button and wait a while for the results. Do this a -second time and observe the changes. If the values remain consistent, -you can use them for your panoramas. The search function steps through -a range of values for lens_mm, -lens_bow, and the image alignment offsets for x, y, and theta. It -searches for the lens values that give the best alignment results for -the given images. The process needs a minute or more, but you only -need to do this once to characterize a given camera lens. Be sure to -save the results using the lens parameters menu.
- -
- -Setting Lens Parameters Manually
-Make -a panorama image of a brick wall (or any wall with lots of detail) with -about 40% image -overlap. The wall should be 5+ meters away. Within the panorama -pre-align process, adjust lens_mm and -lens_bow until the overlapping bricks coincide. -When making the two images, be sure to turn the camera on a vertical -axis through the lens, minimizing lateral movement and rotation in -other axes - otherwise the images may fit poorly and your lens -parameters may -not be optimal. The result should roughly correspond to the nominal -focal length of your lens (35mm equivalent). It may be off somewhat (my -27mm lens works best with a lens_mm setting of 29-30mm). I speculate -that this is because wide-field camera lenses are not ideal lenses -(pinhole equivalent). Most panoramas will still work fine even if the -lens_mm setting is off by 10%.
- -
- -
+

+
Change Language

- -This function allows you to change the GUI to one of the available +This function allows you to +change the GUI to one of the available languages. If your language is not available or has missing -translations, consider making a translation, which is not difficult (more).
-
-
-Edit Translations
-
+translations, consider making a translation, which is not difficult (
more).
+
+
+Edit +Translations
+
This function is used to revise the GUI translations interactively, as Fotoxx is being used. @@ -2280,139 +2516,155 @@ translations look. The advantage with this new method is that the application context is experienced as the translation is made, which should result in easier and better translations. Also, the new -translations are immediately used by Fotoxx. For details about how to do translations -(including this interactive method), see the menu Help > Translate.
-
- -
-Add Menu and Launcher

- -This function puts a Fotoxx icon / launcher on the desktop -and adds Fotoxx to the desktop menu system under the category "Graphics". Your system must +translations are immediately used by Fotoxx. For details about how to +do translations, see the menu Help > Translations. This describes +how .po files work and the procedures for editing them. The section +"Interactive Translations" describes how to use this interactive method +to update .po files. You can also start Fotoxx with the command line +parameter "-translate" to make it start up in translation mode. This +will capture the main window menu and toolbar translations which would +be missed if the menu function is used.
+
+
+Menu and Launcher

+This function puts a Fotoxx icon +/ launcher on the desktop +and adds Fotoxx to the desktop menu system under the category +"Graphics". Your system must be LSB compliant (Linux Standards Base). The effectiveness of this has been sporadic. You may need to log off and back on to see the new menu -entry. A dialog allows you to customize the startup options.
- +entry. A dialog allows you to customize the startup options.


+
+User +Settings
+
+Various user preferences and settings are collected in this dialog.
+
+ + + + + + + + + + + + + + + + + + + + + + + +
 Startup +Display  + -
- -Convert RAW Files
-This function converts one or more RAW image files to -16-bit tiff format, using the program ufraw-batch. A file chooser dialog +
+
The +initial +window +content +when +Fotoxx is -opened. Choose one or more RAW image files (hold down the CTRL key to -select -multiple files). The image files are converted one at a time and -displayed in -the -main window. Depending on the number of files, this can take a long -time (my 3.3 GHz processor does about 24 image files per minute using -a mix -of raw file types). The ufraw program uses multiple threads, so the Fotoxx function does not in this case.
+started. Directory can be the top +image directory or any sub-subdirectory underneath. Image File is any +valid image file.
+
 Toolbar +Style -
-
-Burn Images to CD/DVD

-This function enables you to choose image files and burn them into a CD -or DVD. When the function starts, an image -gallery window is displayed from which you can select the image files -to burn (link). When -done, the list of image files is sent to -Brasero to burn a CD or DVD.
-
-
+
+
The +desired +toolbar +style +for +the +main +window and gallery window.
+
 Warn +Overwrite  -E-mail Images
-This function enables you to -choose up to about 40 image files and send them to your preferred -e-mail program. In the dialog, press the [select files] button to -display an image -gallery window from which you can select the image files (
link). -After -selecting the images, set the desired -maximum width and height in the dialog. The [proceed] button will do -the image reductions and send them to the e-mail program. The reduced -images are put into a temporary directory (/tmp/<user>/fotoxx/) -and do not affect the original images. This function uses xdg-email -(Linux Standards Base) which must be installed and must work correctly -for your Linux flavor (as of Jan. 2011 it works for Ubuntu 10.04 and -fails for 10.10). The e-mail program is started with the selected image -files as attachments. You must then add the subject, text and -recipients, and finally send the e-mail. 
-
+
+
Whether +attempts +to +save +a +modified +image +replacing the original image is +warned or not. Saving to a new version is never warned. Saving to a new +file name is warned only if the file already exists.
+
 Panorama - -
-Synchronize Files
-This is needed when Fotoxx is started for the first time, if you add new image -files to your collection, or if you -move or rename image files or their directories. Nothing is lost when -image files are moved, but the image gallery (thumbnail) windows will -be -slow if a large number of files were added or moved, and the Search Images -function will not find the new or moved files. The Synchronize Files -function will -create missing thumbnails, replace outdated ones, and refresh the -search index file using current data from your image files. On a fast computer, new files -are processed at 500+ per minute and old files at 1000+ per second.
-
-
Images created (i.e. edited and saved) or moved within Fotoxx are taken care of automatically. -Synchronize Files is only needed when new image files are created from -outside Fotoxx (e.g. a new batch of files from a camera), or if files -are moved or renamed from outside Fotoxx.
-

-If you have -used directory -and/or file names to classify your images, you can make immediate use -of these in the Search Images function. If you have saved captions, -tags, titles, or ratings in your images (using Photoshop, Fotoxx, or -other -tools), these will also be searchable.
-
Synchronize -Files starts -automatically at Fotoxx startup if image files are detected with a -date/time newer than the last Fotoxx session. It can also be started -manually from the Tools menu. A dialog will ask -for the topmost directory of your image files (e.g. -/home/<user>/Pictures). That directory and any -subdirectories containing images will be -processed. -It -does not matter if other files are mixed. A popup window shows the new -image files as they are found and processed. This window is left open -for your inspection after the synchronize function is finished. After -the images have been -indexed, -searching them (by captions/comments, file names, tags, date, rating) -is almost instantaneous.
-
-When Synchronize runs, you can -use Fotoxx normally to navigate and view images, but editing images and -metadata (tags, comments, etc.) is blocked until Synchronize is -finished. You can see in the status bar if Synchronize is running. -Unless there are hundreds of new images to process, this will be done -in a few seconds.
-

-Toolbar Style
-This is a dialog to set the toolbar to show icons only, text only, or -both icons and text. Select one of the three radio buttons.
-
-
-
-Memory Usage
+ +
+
The +two +lens +parameters +used +for +Panoramas. +Normally EXIF data is used for +lens mm (35mm focal length equivalent), and the value here is used only +if there is no EXIF (e.g. a scanned print from a film camera). Lens bow +is for compensation of barrel/pincushion distortion. There is no EXIF +for this, but fortunately it can usually be left at zero. There is a +way to measure this described in the Panorama topic.
+
 Zoom +Ratio + + + +
+
The +image +size +increase +with +each zoom-in. The choices are 4/3/2/1 zooms +for each 2x increase in size.
+
+
+
+Memory Usage
This is a diagnostic tool to detect memory leaks. A table is dumped to the log file (stdout) which shows total memory usage and usage by category. If any of these numbers @@ -2420,35 +2672,40 @@ leak bug.



- -Info Menu
- + 

+Info Menu

-Note: the program exiftool must +Note: the program exiftool must be installed for the following functions to work. Fotoxx uses this program to read and write text information stored within an image file (metadata: EXIF, IPTC, etc.). If exiftool is not installed, then modifying an image with Fotoxx will lose all metadata. For recent -Ubuntu, the package name is: libimage-exiftool-perl. Other distros may be different.
+Ubuntu, the package name is: libimage-exiftool-perl. Other distros may +be different.

I have provided a short analysis of the alternatives for organizing a large image collection so that it can be easily searched. If you are -interested, you can find it here.
+interested, you can find it here.
-
- -
- -Edit Caption/Comments
- -This is a special function for editing image text saved in IPTC "Captions" and EXIF "User +
+Edit +Caption/Comments
+
+
+This is a special function for +editing image text saved in IPTC "Captions" and EXIF "User Comments". Enter any text you want to associate with the current image. Multiple text lines of any length can be entered, up to an overall limit of 1000 characters. Press the [Apply] button to save the text in -the IPTC and EXIF data for the current image. The dialog can be left open while +the IPTC and EXIF data for the current image. The dialog can be left +open while navigating to different images, and the current text for each image is shown, if any. Enter or modify the text and press [Apply] to make the change permanent. If you need to enter (nearly) the same text for @@ -2457,15 +2714,14 @@ the monitor to show the comments as new images are viewed (also in Slide Show mode). You can search for images -based on captions and comments (see topic Search Images).
- +based on captions and comments (see topic Search Images).


- -
+
Tags Overview

- - -Image files can have classification tags (categories, keywords) +Image files can have +classification tags (categories, keywords) assigned to them. These can be used to search a large image collection for those images having desired tags. Typical tags: the main subject of a @@ -2476,10 +2732,10 @@ phrase with imbedded blanks or other delimiters can be used. Commas and semicolons are recognized internally as delimiters (separators) between tags, and therefore cannot be used within a tag. A compound tag like -"Arizona scenery" is allowed, but you should use two tags instead for more flexibility: you +"Arizona scenery" is allowed, but you should use two tags instead for +more flexibility: you can search for images having either tag or both tags.
-
You can use a directory hierarchy to @@ -2489,21 +2745,21 @@ are useful but optional: you can also put all your images in one giant directory and keep the numeric file names that come out of the camera. Regardless of the physical organization, tags can be used to create -other organizations, e.g. to label all the images of one person over all +other organizations, e.g. to label all the images of one person over +all years, events, locations, etc. All images having a desired tag or tags can be found quickly and displayed in an image gallery window (thumbnails), where you can further review the images and choose those for viewing, editing, or changing their tags.
-
If you have used directory and file names in a meaningful way, you can keep using these, and you can also search for images using these names as well as tags. There is no need to duplicate -information already available. See "Search Images" below.
- +information already available. See "Search Images" below.


Images may have a date (date of photo) which is pulled from the image @@ -2512,23 +2768,30 @@ importance or quality of an image. Dates and star ratings can also be used as search criteria.
-
-Limitations and +Limitations +and Practical Tips
The following are the default limits for tags. These are compile time constants which can be easily increased if needed, although I believe -they are large enough to exceed practical limits:
-     o   max. tag length: 50 characters per tag
-     o   max. tags for one image file: 1000 -characters
-     o   max. tags in a tag category: 50000 -characters
-     o   max. tags overall: 50000 characters
-     o   max. tags in a search: 200 characters
-     o   max. tags for Batch Add Tags: 200 -characters
+they are large enough to exceed practical limits:

+     +o   max. tag length: 50 characters per tag
+     +o   max. tags for one image file: 1000 +characters
+     +o   max. tags in a tag category: 50000 +characters
+     +o   max. tags overall: 50000 characters
+     +o   max. tags in a search: 200 characters
+     +o   max. tags for Batch Add Tags: 200 +characters

@@ -2549,14 +2812,16 @@ directories will also appear together in the gallery window). All in all, my recommendation for the casual photographer is to use fewer and broader tags.
-
- -
+
Edit Tags

- -
-To assign tags to the current image, select the menu Info > Edit Tags. Existing tags +
+To assign tags to the current +image, select the menu Info > Edit Tags. Existing tags are shown in "current tags". Available tags are shown in the "defined tags" window below. One of these tags can be added to the image by pointing and @@ -2568,22 +2833,24 @@ image, if available, is shown as "image date". This may be entered if missing, or changed. You can enter a full date in the format yyyymmdd or a shorter format yyyy or yyyymm. A missing month/day is logically -equivalent to 01/01 when used as a low limit for searching, or 12/31 when used as a high limit. The [use-last] button fills-in +equivalent to 01/01 when used as a low limit for searching, or 12/31 +when used as a high limit. The [use-last] button fills-in the date from the last date entered or shown. This is to allow easy dating of a series of images. You may enter an optional "stars" rating for the image. The dialog remains open if you navigate to a new image, and the current tags are filled-in from that image. The [Apply] button writes the tag information to the image file and to the search index -file used for searching images.
- +file used for searching images.


- -
- -Manage Tags
- -
+
+Manage Tags
+
To create new tags, use the menu Info > Manage Tags. You can also assign categories to tags to help organize them and @@ -2602,59 +2869,64 @@ both the Edit Tags and Manage Tags dialogs open if you need to create or change tags for immediate application to images. Tags used in images but not assigned to a -category will appear under "nocatg".
+category will appear under "nocatg".


-Note:
 a newly created tag is appended to the end of the tag list +Note:  a newly +created tag is appended to the end of the tag list for its category. The next time fotoxx is started, all categories and their tag lists are sorted alphabetically, except that "nocatg" is always last. A tag will also disappear from the list if it is no longer assigned to any image.
-
- - -
- -Batch Add Tags
- -When adding tags to a large number of images having many of +
+Batch Add Tags
+When adding tags to a large +number of images having many of the same tags (i.e. the same event or subject), use this function to speed up the process. In the dialog, use the [select files] button to open a gallery window with thumbnail images from which you can select -the image files (link). After +the image files (link). After selecting files, specify tags to add to the images by clicking tags in the "defined tags" list. If you need a new tag, input the tag and press [create tag] to add it to the list. When done specifying image files and -tags, press [proceed] to add the tags to the image files.
- - - +tags, press [proceed] to add the tags to the image files.


- -
- -Batch Delete/Replace Tag
- -This function is used to delete a single tag from many images at once, or +
+Batch +Delete/Replace Tag
+This function is used to delete +a single tag from many images at once, or replace a tag with another one. In the dialog, input a tag to delete and an optional replacement tag. Use the [select files] button to open a gallery window with thumbnail images from which you can select -the image files (link). Alternatively, use the "search all +the image files (link). Alternatively, use the "search all files" checkbox to specify that the tag will be removed/replaced for all image files in the image database (all image -files having the tag, as found with the Search Images function).
- +files having the tag, as found with the Search Images function).


- -
+
View Info (short)
View Info (long)

-The View Info functions +The View Info functions will display metadata for the current image file, if available. EXIF metadata contains the date and time of a photo, shutter speed, focal length, pixel @@ -2662,97 +2934,97 @@ metadata contains tags (from Fotoxx, Photoshop ...) and captions (often for published images). If an image is edited and then saved, the metadata is updated and stored -with the new image.
- +with the new image.


-The View Info short report outputs the most commonly needed +The View Info short report +outputs the most commonly needed data, including the photo date and time, exposure data, focal length -(real and 35mm equivalent), user-assigned tags and star rating, comments, caption, and a -history of Fotoxx edit functions that have been applied to the image. The long report reports all the data available.
- +(real and 35mm equivalent), user-assigned tags and star rating, +comments, caption, and a +history of Fotoxx edit functions that have been applied to the image. +The long report reports all the data available.


-Fotoxx uses the following EXIF / IPTC data items:
- - - - +Fotoxx uses the following EXIF / IPTC data items:
+
- - - - + - - - - + + - - + - + + -
    Key Name
- +
    Key Name
Fotoxx Usage
- +
Fotoxx Usage
    Date/Time Original
- +
   + Date/Time Original
Edit Tags function - image date
-
    Keywords
- +
   + Keywords
Edit Tags function - image tags
-
    Rating
-
Edit Tags function - image stars
-
    User Comments
- +
    User +Comments
Edit Comments function
-
    Caption-AbstractEdit Caption function    +Caption-AbstractEdit +Caption +function
    Edit Status
- +
    Edit +Status
History of Fotoxx edits applied to the image
-
    any key
-
Edit Info, Delete Info
-
-
- -
- -Edit Info
- -A specific metadata ID (key) can be added (if legitimate) or revised. Enter the key name and +
+Edit Info
+A specific metadata ID (key) can +be added (if legitimate) or revised. Enter the key name and press [fetch] to retrieve existing data, if any. Enter the new data and press [save] to save the new or revised data. You may enter the key name in lower case and without blanks, e.g. the @@ -2761,34 +3033,29 @@ automatically for each new image file opened, and it can then be revised and saved if wanted.
-
- -
- -Delete Info
- -This function allows deletion of a specified metadata key, or all metadata +
+Delete Info
+This function allows deletion of +a specified metadata key, or all metadata at once. Input a key name in lower case and without blanks, e.g. the -EXIF key "User Comment" is entered as "usercomment".
- +EXIF key "User Comment" is entered as "usercomment".


- -
+
Search Images

- - -
- -Example: +
+Example: select images in 2005 or later, with 4 stars or more, having tags buildings or monuments, and containing dresden in the directory or file name.
- -
- - A search index file is used for searching, which makes it very fast (thousands of images per second are searched). The index is @@ -2797,83 +3064,89 @@ can rearrange your image directories and image files without losing anything - -you must only regenerate the search index file, which is simple and fast. See -Tools > Synchronize Files.
- +you must only regenerate the search index file, which is simple and +fast. See +Tools > Synchronize Files.


- - Use the Search Images function to find images having desired tags, dates, stars, comments, captions, or file names. Available tags are shown and can be chosen with point and click. Use the radio -buttons "all" or "any" to indicate if all tags or any tag must be present for an image to be selected. Press the +buttons "all" or "any" to indicate if all tags or any tag must be +present for an image to be selected. Press the [search] button to perform the search. Matching images are displayed in a pageable image gallery window (thumbnails). Choose images to view or edit by -clicking the thumbnails. The set of matching images are used for the buttons [prev] and [next]. If an +clicking the thumbnails. The set of matching images are used for the +buttons [prev] and [next]. If an image file is selected with the File > Open function or toolbar -button [Open], then the current image set (gallery window list) is replaced +button [Open], then the current image set (gallery window list) is +replaced by the -directory of the newly opened image file.
- - +directory of the newly opened image file.


- A date range may be optionally entered, to further restrict the search to images within the date range. The format is yyyymmdd. Images are selected which have a date on or after the first date, if present, and on or before the second date, if present. Missing month/day default -to 01/01 for the low date limit and to 12/31 for the hight date limit.
- - +to 01/01 for the low date limit and to 12/31 for the hight date limit.


- A pair of star ratings may be optionally entered to restrict the results to images having a star rating within the given range. A missing low value implies zero, and a -missing high value means unlimited.
- - +missing high value means unlimited.


- Image directory and file names may also be searched. In the input field "file names", enter any number of names used for your image -directories and file names, separated by blanks. Wildcards (*) are -implied before and after every name, and you can also put wildcards -inside the names. Thus an input of [ egypt cairo ] would match all image -directory/file names against *egypt* and *cairo*, and any -directory/file -containing either of these strings would match. If you were to enter -[ egypt*cairo ] then a matching directory/file would have to contain both -strings in the same order. The matching rule is simple: * matches any -sequence of characters anywhere in the full /directory/file name. Name +directories and file names, separated by blanks. An input of [ egypt cairo ] would +match all +image +directory/file names containing either of these strings. Name matching is not -sensitive to case. If match names include blanks, use quote marks -around the -search string, otherwise the blank will result in two separate search -strings, e.g. a search for [ NYC parade ] would be interpreted as a -search for both *NYC* -and *parade*, so use [ "NYC parade" ] to keep the text together.
- - -
- - -Image comments and captions may also -be searched (see Edit Comments, Edit Captions). Enter the words to search -for in the dialog "search text" field, separated by blanks. These will be +sensitive to case.
+
+Image comments and captions may +also +be searched (see Edit Comments, Edit Captions). Enter the words to +search +for in the dialog "search text" field, separated by blanks. These will +be matched -to every word in the comments and captions of all images, and matching images -are selected. Wildcards can also be used here.
- - +to every word in the comments and captions of all images, and matching +images +are selected.


- The radio buttons "all" and "any" apply to all matching options: tags, text, and file names. You can select images @@ -2882,48 +3155,79 @@ search file field contains [egypt cairo] and "any" is selected, then image files with either of -these names within the directory or file name would be selected.
- - +these names within the directory or file name would be selected.


- You can use comments, captions and directory/file names as an alternative to using tags. Effective use of tags can require high organization and attention to detail, and therefore lots of time. Also revising your tag organization can be very hard if hundreds of images are affected. User comments and file names are -much easier, if less exacting. Simply name your image files with the key topic or -content, and add comments or captions with adequate descriptive words. You do not have to have +much easier, if less exacting. Simply name your image files with the +key topic or +content, and add comments or captions with adequate descriptive words. +You do not have to have an elaborate tag system, and revisions are easier. The tags system has -the advantage that a complete list of available tags is automatically -maintained and presented when you search images, and adding tags to new images is a point and click operation.
- - +the advantage that a complete list of defined tags is automatically +maintained and presented when you search images, and adding tags to new +images is a point and click operation.

+
+
+Search +Metadata
+
+Report any desired metadata +using a combined image and text layout. The starting point is always +the current image gallery list, which can be an image directory (the +normal case) or the results from an immediately preceeding Search Images. The selection criteria available in +Search Images is always shown first: file name, date, star rating, +caption, comments, and tags. When Search Metadata is started, you can +enter up to five more metadata items to report. The items available in +any given image file can be shown using View Info +(long). These include camera make and model, exposure time, F-number, +ISO, metering mode, focal length, shooting mode, etc. etc. You can +enter shortcut names like "exposuretime" instead of "Exposure Time". +You may also enter match criteria, if wanted, so that only the images +with matching metadata are reported. For example, if you enter "camera +model name" with the match value "DMC-FZ28" (my Panasonic) then +only the images taken with this camera will be reported. You can also +enter multiple match values for one key, separated by blanks.
+
+Performance: +If no extra metadata to report is entered, then 1000+ images/second are +searched and reported. If extra metadata is entered, the search +performance slows down to +something like 100 images/second. This is because +the image files are being read to extract the metadata, instead of +using the search index file. For +good performance, always use Search Images first to reduce the images +being searched as much as possible. Use dates, tags, file names, etc. +to reduce the image count. Then use Search Metadata to search for and +report additional metadata.

- -If you have added, -deleted, or moved image files outside of Fotoxx, be -sure to run  Tools > Synchronize Files  to get the -search index file synchronized with the actual image files. This is quite -fast if <1000 images are involved.
- - -

-
- -
Select Menu
- -
-Overview
+
+Select +Menu
+
+Overview
Edit functions normally apply to the entire image, but it is possible to edit part of an image -and leave the rest +(an "area") and leave the rest unchanged. If -an image area has been selected, then the Retouch and Art edit functions will work only within this area. Other +an image area has been selected, then the Retouch and Art edit +functions will work only within this area. Other functions ignore a selected area. An area may be selected before starting an edit function, or while an edit @@ -2931,93 +3235,193 @@ edits are retained, and future edits will apply only within the area. If another edit function is started, the selected area remains active, so it is -possible to carry out a series of edits on one area.
- -
- -
-Select Area

- -
- -In the select area dialog, if an area is already present, its outline will be -shown. You can continue to edit this area or use [Unselect] to discard it +possible to carry out a series of edits on one area.
+
+"Layers" in Photoshop and Gimp +are "areas" in Fotoxx. Instead of selecting something from the image, making a +separate layer from the selection, performing edit functions on the +layer and finally merging the layers, you select something in the image and +perform edit functions on the selection, with WYSIWYG feedback during the +edit. Areas can also be saved, pasted into other images, and edited +there.
+
+
+Select Area

+
+If an area is already present, +its outline will be +shown. You can continue to edit this area or use [Unselect] to discard +it and start a -new area. Select one of the six methods (explained below) and proceed -to define the area. Uncheck "my mouse" to suspend editing and free -the -mouse for zooming or scrolling to another position in -the window. Re-check to resume editing. The [Hide] +new area. Select one of the methods (explained below) and proceed +to define the area. The [Hide] button removes the area outline (for -better visibility of image edits and edge blending). Use the [Show] button to show the +better visibility of image edits and edge blending). Use the [Show] +button to show the outline. The select area dialog can be exited and -re-started later to modify a selected area or start a new one.
- +re-started later to modify a selected area or start a new one.


- -There are six methods to +Methods to enclose one or more spaces that will belong to the final area:
- +
- - - - - - + + - - + - - + - - + - - +
  Rectangledrag the mouse to enclose a -rectangular area
  Ellipse
-
drag the mouse to enclose an elliptical -area  +Rectangledrag +the +mouse +to +enclose +a +rectangular +area
  Freehand Draw
+
  +Ellipse
drag and click the mouse to draw lines that outline an enclosed -spacedrag the mouse to enclose +an +elliptical +area
  Follow Edge 
+
  +Freehand +Draw +  + + + + + + + + + + + + + + + + + + + + + +
click along the edge of an object in the image to draw lines that -follow the edge, or drag the mouse to draw freehand drag and click the mouse +to draw +lines that outline an enclosed +space
  Select by Mouse  
+
  +Follow +Edge  + + + + + + + + + + + + + + + + + + + + + + +
select or de-select a circular -area around the dragged mouse pointer click along the edge of +an object in +the image to draw lines that +follow the edge, or drag the mouse to draw freehand
  Select by Color
+
  +Select +by +Mouse +   + + + + + + + + + + + + + + + + + + + + +
select a small area of pixels around the mouse and aggregate adjacent -areas with pixels matching in color and brightness select a small area of +pixels around +the mouse and aggregate adjacent +areas with pixels matching in color and brightness
-The six -methods may be used in -any sequence to define spaces that are either joined or detached. The following paragraphs +Methods may be used in +any sequence to define spaces that are either joined or detached. The +following paragraphs explain the details of each method.
-
- -Rectangle: Drag the mouse from +Rectangle: Drag the mouse from one corner to the opposite corner of the desired rectangular area to select. A rectangle is drawn to enclose the area. Right-click to delete -and start over. Repeat the process to select more rectangular areas.
- +and start over. Repeat the process to select more rectangular areas.


- -Ellipse: This works the same as rectangle selection, except that the area enclosed is an ellipse that fits within the rectangle.
- +Ellipse: This works the same as rectangle +selection, except that the area enclosed is an ellipse that fits within +the rectangle.

- -Freehand draw: Drag the mouse +Freehand draw: Drag the mouse (left button down) to draw a freehand (curvey) line, or left-click to connect a straight line from the last point drawn to the point clicked. @@ -3038,17 +3442,17 @@ right-button drag can be used to erase small segments: right-drag closely along a line to erase it, then left-drag to re-draw the line. At the end, an area must be fully enclosed, with no gaps. -Lines that overlap a little at the ends are OK. Gaps +Lines that overlap a little at the ends are OK. Gaps can be difficult to find and correct, so work at 100% image size or greater and be careful. A series of lines automatically connected with left clicks will not leave gaps, but deviation from this sequence is likely to create gaps. To reduce the possibility of gaps, use deliberate overlaps when manually connecting lines.
-
- -Follow edge: High-contrast +Follow edge: High-contrast pixels (likely object edges) between the last point drawn and a newly clicked position are found and connected. This is effective for clear edges that are not too irregular. Fuzzy and ragged edges may not work @@ -3058,35 +3462,24 @@ mouse instead of clicking works like freehand draw, so you can switch back and forth.
-
-Select by mouse:
-Enter a value in the radius control. A corresponding circle -will appear around the mouse pointer. A left mouse click or drag will -select all pixels within the circle, and a right mouse click or drag -will un-select all pixels within the circle (i.e. those that were -previously selected). Use a large radius to rapidly enclose large -spaces, and a small one to carefully follow along the edge of a subject -in the image. For areas selected with one of the two "draw" methods, -un-selecting with this method will not work unless the area has -been finished beforehand (Finish button) - only then does the mouse -know what pixels -are already selected. Simply finish that area if you want to expand or -reduce it using this method.
- -
-Select by color:  The radius control will define a +Select +by mouse:  The +radius control will define a circle around the mouse pointer. Click the left mouse button somewhere on the image to define a group of pixels to -match. The group is all pixels inside the circle, and the degree of match is +match. The group is all pixels inside the circle, and the degree of +match is defined by the match control: 100 means a perfect match is required. Adjacent -areas with pixels matching any of the selected pixels will be selected and -shown. A bigger radius or a lesser match value will select more pixels. +areas (within search range) +with pixels matching any of the selected pixels will be selected. A +bigger radius or a lesser match value will select more pixels. If the mouse is dragged or clicked within the selected area, the selection will be -expanded to match new pixels enclosed by the mouse. Drag the mouse +expanded to match new pixels enclosed by the mouse and within the +search range. Drag the mouse over new areas you want to include, or over "islands" of non-matching pixels you want to include. Watch the selected area expand accordingly. If you @@ -3094,39 +3487,149 @@ to remove more previous selections. Reduce the radius or increase the match level to gain finer control - the selection will expand more slowly and stay closer to the mouse position. The -radius of selection is limited to 3 times the mouse radius. This means -that a small radius can be used to follow along an edge and select -pixels up to the edge with good precision. Change to a larger radius to +radius of selection is limited by search +range which is a multiplyer of the mouse radius. A small radius +and search range can be used to follow along an edge and select +pixels up to the edge with good precision. Change to a larger radius +and/or search range to select larger areas after the fine work is complete. If the "firewall" is enabled, then already-selected pixels will act as a barrier to stop the search for new pixels. This is sometimes useful, e.g. an existing selection boundary should remain -fixed and you want to extend the selection in the interior. Right drag acts as an -un-select: selected pixels within the mouse radius are un-selected. You may need some practice to get a +fixed and you want to extend the selection in the interior. Right drag +acts as an +un-select: pixels matching pixels inside the mouse radius and within +the search range are un-selected. You may need some practice to get a feeling for this and -be able to work efficiently.
+be able to work efficiently.
+
+Summary +
+ + + + + + + + + + + + + + + + + + + +
  +left +click +or +drag
+
select +pixels +inside +radius +and +those +with +matching +colors +inside +search +range
+
  +right +click
+
undo +previous +selection, +repeat +to +unselect +more
+
  +right +drag
+
unselect +pixels +inside +radius +and +those +with +matching +colors +inside +search +range
+
  +match +mouse +color   + + + + + + + + + + + + + + + +
+
uncheck +to +turn + + + + + + + + + + + + -
-my mouse: If checked, the mouse -belongs to the dialog and is used to select areas on the image. If not -checked, the mouse can be used to zoom or scroll the image to a new -position. If you are working with a large area that does not fit in the -window, you can alternate between selecting the area and moving the -image to a new position.
-
-Blend Width: Edits + color matching off: +only pixels within the mouse radius are selected or unselected
+
+
+Blend Width: Edits made within an area can be blended with the surrounding image over a distance called "blend width". At -the edge of the selected area, the image is the original (unedited) image. At a +the edge of the selected area, the image is the original (unedited) +image. At a distance of "blend width" from any edge inside the area, the image is the edited image. For distances in-between, the pixels are a mix of original and edited pixels with a gradual transition. Use the Blend Width control to -set the blend width for the current or subsequent edit functions. Zero blend width gives a hard edge to +set the blend width for the current or subsequent edit functions. Zero +blend width gives a hard edge to the area edit. Increasing blend width makes the edges of the edit more gradual and harder to distinguish from the original image. Changing the value for @@ -3135,25 +3638,33 @@ few seconds), but it may take minutes if the area is large and has a complex geometry (a very long edge). Whenever an area is re-edited or inverted, the edge calculation is -discarded and must be repeated if blending is wanted. If the edge of a selected area is +discarded and must be repeated if blending is wanted. If the edge of a +selected area is within 4 pixels of the image edge, it is no longer considered an edge for blending. If a selected area includes a portion of the image edge, and you do not want blending -along this edge (the normal case), be sure the edge of the area is within 4 pixels of the image edge.
+along this edge (the normal case), be sure the edge of the area is +within 4 pixels of the image edge.


- -Show / Hide: Use [Hide] to hide +Show / Hide: Use [Hide] to hide the area outlines. This is useful when editing the image/area, to better see the effects of the edit without interference from the area -outlines. Use [Show] to show the outlines and resume editing the area.
- -
- -Color: Alternates the color used to show the area outline (red, green, black).
- +outlines. Use [Show] to show the outlines and resume editing the area.


- -Finish: When +Color: Alternates the color used to show +the area outline (red, green, black).
+
+Finish: When you are finished selecting the enclosed spaces, use the [Finish] button to complete the process. A popup dialog will ask you to click the mouse inside each enclosed space in sequence. This action launches a search @@ -3173,105 +3684,104 @@ area can be selected, even those not explicitely outlined (e.g. if you use select by mouse to select a donut with a hole, you can -still click the hole to include it in the area).
+still click the hole to include it in the area).


-Unfinish:
To re-edit a finished area, it is sometimes necessary to un-finish it to make the edit functions work normally.
+Unfinish:
To re-edit a +finished area, it is sometimes necessary to un-finish it to make the +edit functions work normally.

- -Disable / Enable: Disable the +Disable / +Enable: Disable the current area and keep the data so that it can be re-activated later. This allows you to alternate edits -within a selected area and edits for the entire image.
- +within a selected area and edits for the entire image.


- -Invert: This +Invert: This function inverts an existing area: the entire image is selected except for the existing area. Using the function two times returns the original selected area. Inverting a selected area invalidates the edge calculation which will be repeated if edge blending is selected.
- - -
-Unselect: Discard the current area +
+Unselect: Discard the current area permanently.
-
- -
- -Area Show / Hide
- -Show or hide the outline of the current area. Hiding the area is useful +
+Area Show / +Hide
+Show or hide the outline of the +current area. Hiding the area is useful when the area is being modified with one of the edit functions. This makes it easier to judge the effects of the edit. These are also -available as buttons in the Select Area dialog.
- +available as buttons in the Select Area dialog.


- -
- -Area Enable / Disable
- -Disable the current area and keep the data so that it +
+Area Enable / +Disable
+Disable the current area and +keep the data so that it can be re-activated later (Enable menu). This allows you to alternate edits -within a selected area and edits for the entire image. These are also available as buttons +within a selected area and edits for the entire image. These are also +available as buttons in the Select Area dialog.
-
- -
- -Area Invert
- -Invert an existing area: the entire image +
+Area Invert
+Invert an existing area: the +entire image is selected except for the existing area. Using the function two times returns the original selected area. Inverting a selected area invalidates the edge calculation which must be repeated if edge blending is desired. -This is also available as a button in the Select Area dialog.
- +This is also available as a button in the Select Area dialog.


- -
- -Area Unselect
- +
+Area Unselect
Permenently discard the current area. This is also available as a button in the Select Area dialog.
-
- - +
- Area Copy / Paste
-
-Copy:
The current selected area -is copied and saved in memory.
- +Copy:
The current +selected area +is copied and saved in memory.

-Paste:
The saved area is pasted +Paste: The saved area is +pasted into the current image. It can be moved around by dragging with the mouse. Use the resize and angle buttons to resize or rotate the pasted object. Use the edge blend slider to make a blended edge if desired. Press the [done] -button in the popup dialog. The pasted area now behaves like a Select Area. You can edit within the area and use the [blend -width] control in the Select Area dialog.
- +button in the popup dialog. The pasted area now behaves like a Select +Area. You can edit within the area and use the [blend +width] control in the Select Area dialog.


- -
- +
Area Open and Save
-
If a selected area is active or has been saved with the menu Select @@ -3285,19 +3795,20 @@ to choose a saved area (choose the tiff file), which will be dumped into the image where it can be moved around, resized, etc. as with the copy and paste functions.
-
- -
- -Select Whole Image
- -
+
+Select Whole +Image
+
It is sometimes effective to apply a retouching function controlled by image brightness, e.g. apply noise reduction to darker areas of the image while leaving brighter -areas alone. To do this, use the menu Select > Select Whole Image. Choose +areas alone. To do this, use the menu Select > Select Whole Image. +Choose brightness or one of the RGB colors as the controller. The editable graph controls how subsequent edit functions are applied to the image. The x-axis is pixel brightness from dark to bright, or the selected RGB @@ -3305,20 +3816,22 @@ how strongly the edit function affects a corresponding pixel. A low value minimizes the effect, and a high value maximizes it. Example: -apply tone mapping primarily to dark pixels: Use Select > Select Whole Image +apply tone mapping primarily to dark pixels: Use Select > Select +Whole Image and drag the curve so that high values are on the left (dark pixels) and low values are in the middle and on the right (bright pixels). Now use Retouch > Tone Mapping to apply tone mapping to the darker areas of the image. You can edit either curve (whole image curve, tone -mapping curve) while watching the resulting image.
- +mapping curve) while watching the resulting image.


- -
- -Select and Edit
- -
+
+Select and +Edit
+
Use this function in combination with a retouch edit function. Specify a mouse radius and power factors for the mouse center and radius edge. @@ -3333,7 +3846,9 @@ repeatedly, the edits are slowly accumulated. For example, if the edit function is Brightness/Color, and the brightness curve is set to a high level, then the image will be slowly brightened in the area where the -mouse is dragged. This is called dodge and burn +mouse is dragged. This is called dodge and burn in other image editors, but other retouch functions can also be used, e.g. tone mapping or blur. Use the [undo] and [redo] toolbar buttons to monitor @@ -3341,35 +3856,37 @@ to 100 to make faster changes (with less fine control). Use a left-button drag to weaken the edit or ultimately erase it. When done using one edit function in one or more image areas, use the [done] -button on the edit dialog to complete the edit. Use the [reset area] button to erase the active area that is now left +button on the edit dialog to complete the edit. Use the [reset area] +button to erase the active area that is now left over from the mouse dragging. If you leave the area active and start a new -edit function, the results are unpredictable. A suggested approach is: (1) start the Select and Edit dialog, (2) start the -edit function with its initial settings (the effect on the image will be zero since no mouse dragging +edit function, the results are unpredictable. A suggested approach is: +(1) start the Select and Edit dialog, (2) start the +edit function with its initial settings (the effect on the image will +be zero since no mouse dragging has been done), (3) drag the mouse over the desired areas and watch the effect, (4) adjust the edit function settings, (5) -alternate between the previous two steps. This method to "paint" a retouch function incrementally can improve +alternate between the previous two steps. This method to "paint" a +retouch function incrementally can improve selected areas of an image quickly and easily. It works with any edit function that can use selected areas. The most useful are -Brightness/Color and Tone Mapping.
- +Brightness/Color and Tone Mapping.




-
Transform Menu
- - +
Transform +Menu
    - -
- -
- -Rotate Image

- - -The rotate menu function starts a dialog to rotate the image clockwise +
+Rotate Image
+
+
+The rotate menu function starts +a dialog to rotate the image clockwise (+) or counterclockwise (-) in steps of 0.1, 1, 10, or 90 degrees. For a tilted image, use the mouse to drag the right edge up or down until the image looks level. Use @@ -3379,13 +3896,13 @@ image is increased to accommodate the rotated input image without size reduction - e.g. a 100 x 100 image rotated 45 degrees will be inside a new image box of 141 x 141 pixels, and the unused areas will be black. -Use the [trim] button to remove these expanded margins.
- - -
-
-Trim Image
(aka crop)
- +Use the [trim] button to remove these expanded margins.

+
+
+Trim Image
(aka crop)
The HDR, HDF and panorama functions will leave some black margins around the @@ -3402,13 +3919,13 @@ opposite corner to keep the same ratio. You can also drag from the middle of the rectangle to shift the whole rectangle without changing its -dimensions. If "my mouse" is unchecked, the mouse is free to zoom and -scroll the image. When checked again, the selection rectangle may be -redrawn to fit within the newly visible part of the image. You can use +dimensions. You can use the width and height spin buttons to input desired pixel dimensions -directly, and the selection rectangle will adjust to these.
- -
+directly, and the selection rectangle will adjust to these.

+
The six ratio buttons allow you to choose a preset width/height ratio. The @@ -3417,18 +3934,37 @@ the button [customize] which starts the second dialog shown above. Enter desired button names in the first row of six text entry areas, and enter the corresponding width/height ratios in the second row (the -default names are the same as the ratios, except for "gold"). Use the ratio 16:9 for the HDTV format. The default +default names are the same as the ratios, except for "gold"). Use the +ratio 16:9 for the HDTV format. The default [gold] button uses the golden ratio, about 1.618:1. You do not have to -keep it.
- +keep it.
+
+
+Auto-Trim Image
+
+
The functions panorama, HDR/HDF, stack, unbend, and warp can +leave black margins where images did not overlay or were bent away from +the edge. Auto-Trim automatically sets trim +margins to omit these areas and then starts the Trim function (previous +topic) with the margins pre-set. If these are correct, press the [done] +button to finish. If not, change the margins as described above. +Auto-Trim tries to find a +maximum rectangle that does not overlap any of the black margin areas. +This +may or may not be the desired margins, so you can keep them or move +them with the mouse before comitting with the [done] button.
+

- - - +
-Resize Image
(aka rescale)
- -This function sets a new image +Resize Image +(aka +rescale)
+
+This function sets a new image width and height. You can input the new pixel width and height directly or choose a percent change for width and height. Buttons are present for setting the new size to 3/4, @@ -3442,41 +3978,18 @@ the dialog with [done] to save the changes or [cancel] to keep the original size. The image file size (status bar) is not -updated until the modified image is saved.

- -
- -
- -Batch Resize
- -This function is used to resize many image files at once (for planned -uploads -to a web site, to save disk space, etc.). The menu opens a dialog to -select image files and specify options. Use the button [select files] -to select image files from a gallery window (link). -You can select the -option: "replace originals" -or "export to location". For the latter, input a directory where the -resized image files will be written, or use the [browse] button to -locate the -directory. Finally, use the [proceed] button to start the -resize process. A popup window shows the progress. If the replace -option is chosen, EXIF data (including tags) will be preserved. If the -export option is chosen, use the checkbox to determine if the EXIF data -is exported or omitted. Restriction: resized image files are JPEG -regardless of -the file type of the input files.
- +updated until the modified image is saved.


- -
- -Annotate Image
- -
- -With this function you can edit +
+Annotate Image
+
+With this function you can edit descriptive text and write directly on the image. Enter the text into the dialog. Multiple lines can be used. After @@ -3496,56 +4009,55 @@ can load or save all annotation data from or to a file. All the items in the dialog are loaded or saved (text, font, etc.), so you can keep a -collection of often-used annotations.
- -
- -Making a Watermark: use a +collection of often-used annotations.
+
+Making a +Watermark: use a foreground transparency of 70% or more and a background transparency of 100%. The text should be faint but readable. To add a "relief" effect, use Select Area to put a box around the text and use the function Art > Simulate Embossing to raise the text (if brighter than the image) -or recess the text (if darker).
- +or recess the text (if darker).


- -
- -Flip Image
- -Choose either horizontal or vertical flip from the dialog. The image is -reversed (mirrored) vertically or horizontally. Repeating the flip restores the +
+Flip Image
+Choose either horizontal or +vertical flip from the dialog. The image is +reversed (mirrored) vertically or horizontally. Repeating the flip +restores the original image. Doing both a horizontal and vertical flip is the same -as a 180 degree rotation.
+as a 180 degree rotation.


- -
- - -Make Negative
- - -Use this function to make a black and white or color negative, or -convert a negative image into a positive image.
- +
+Make Negative
+Use this function to make a +black and white or color negative, or +convert a negative image into a positive image.
Select one of the four buttons:
-
    black/white -positive - convert a color image to black and white
- -    - - black/white negative - convert to black and white and reverse brightness
- -    - - color positive - do nothing at all, or undo one of the others
- -    - - color negative - replace each RGB color with its compliment
- - +    +black/white +positive - convert a color image to black and white

+    + black/white negative - convert to black and white and reverse +brightness
+    + color positive - do nothing at all, or undo one of the others
+    + color negative - replace each RGB color with its compliment
+
Color negative: Each RGB color is replaced with the maximum value - the color value. For example, if the RGB colors (% of maximum) are @@ -3553,14 +4065,13 @@ back the original colors. This produces complimentary colors as follows: red becomes cyan, green becomes magneta, and blue becomes yellow.
- -
- -
+
Unbend Image

- -
+
Panoramas of nearby subjects (typically buildings or interior rooms) @@ -3584,7 +4095,8 @@

Keystone Correction
-
+
This function can be used to straighten a photo made from an offset angle. The painting on the left is the original photo, taken from below and left of center, to reduce reflections. The painting on @@ -3598,14 +4110,13 @@ needed. The clicked corners are labeled with small letters A, B, C, D. The upper left corner of the square enclosing the letter precisely marks the corner position. Clicking near a corner will move it to the -new position. After the 4th corner is defined, a new click replaces the closest corner.
+new position. After the 4th corner is defined, a new click replaces the +closest corner.
-
- -
+
Warp Image (area)

- This function can be used to make distortions within an image. You can select an image area and drag the mouse to stretch this area @@ -3622,24 +4133,22 @@ accumulated and the original image is warped to the latest pixel positions. The pixels are interpolated to reduce jaggies and improve sharpness.
-
- -
+
Warp Image (curved)

- -This function is useful to correct perspective problems (see also +This function is useful to +correct perspective problems (see also "Unbend"). Drag the image from any position, using the mouse. The entire image will be pulled or pushed in the direction of the mouse, but areas near the mouse are moved more than more distant areas. You can -straighten curved lines or deliberately curve the image.
- +straighten curved lines or deliberately curve the image.


- -
+
Warp Image (linear)

- This function is useful to correct perspective problems (see also "Unbend"). Drag the image from any position, using the mouse. The @@ -3650,34 +4159,31 @@ works over a broader area than the curved warp and causes less image curvature. To minimize the addition of curvature, pull only on the image corners.
-
- -
- -Warp Image (affine)
- -This function can be used to warp an image in interesting ways. Drag +
+Warp Image +(affine)
+This function can be used to +warp an image in interesting ways. Drag the image from a corner or edge using the mouse. The changes are purely linear so straight lines remain straight. This transform is called -"affine". Technical details can be found with Google.
- -
+"affine". Technical details can be found with Google.


-
- -Retouch Menu
+
+Retouch +Menu
- -
- -
+
+
Brightness/Color
- -

- - +

This function is used to change brightness, contrast, color saturation, and @@ -3685,13 +4191,9 @@ as a function of the original image pixel brightness. To illustrate, you could increase color saturation in darker image areas and leave it -unchanged in brighter image areas.
- - - +unchanged in brighter image areas.


- - There are 5 response curves for the 5 image attributes of brightness, color saturation, and color balance (levels of red, @@ -3700,14 +4202,9 @@ image brightness (X-axis). The middle Y-value is neutral (no change from the initial value). Higher and lower Y-values represent corresponding higher and lower settings for the 5 attributes. The -initial curves are flat at the middle value.
- - - +initial curves are flat at the middle value.


- - - The curves can be dragged up or down with the mouse. An anchor point (black dot) is added to the curve wherever it is @@ -3717,12 +4214,7 @@ or deleted by right-clicking them.
- - -
- - The image changes in real-time as the curves are moved. Simply move the curves and observe the image until you are satisfied. For example, to @@ -3732,12 +4224,7 @@ used to shift the whole curve rapidly in various ways.
- - -
- - Brightness changes all RGB values for a pixel by the same factor. Color saturation changes the dominant RGB color(s) within each @@ -3752,7 +4239,8 @@

Gamma Curve
-
+
This is the classic gamma curve edit found in Photoshop and many other image edit programs. The x-axis maps the input pixel brightness and the y-axis the output or adjusted pixel brightness. The straight @@ -3770,26 +4258,17 @@ Edit the ALL curve while watching the image for instant feedback. You can also select and modify individual RGB colors after finishing the ALL color. Editing the ALL curve forces the RGB curves to match the ALL -curve, so do RGB curve adjustments after adjusting the ALL curve.
+curve, so do RGB curve adjustments after +adjusting the ALL curve.
-
- - - - - -
- - - -Expand Brightness
- - - -
- - +
+Expand +Brightness
+
This function expands the brightness range of an image that does not utilize the full brightness range available, possibly making it look @@ -3797,16 +4276,12 @@ If the distribution shows little or no area at the extreme low and high ends of the horizontal scale, the image may benefit from expanding the brightness range. This means that the darkest pixels are made darker -and/or the brightest pixels are made brighter. Move the sliders to extend the brightness range and observe the image.
+and/or the brightest pixels are made brighter. Move the sliders to +extend the brightness range and observe the image.

- - - -
+
Flatten Brightness

- - - This is a fast and easy way to compensate for a common limitation in photos: there is not enough @@ -3819,20 +4294,15 @@ images will show good results, others may not be helped or even become worse. Using this function within a selected area is often very effective. Edge blending may be needed to make the boundary invisible.
-
+
- -
- - - -Brightness Ramp
- - - -
- - +
+Brightness +Ramp
+
This function varies the brightness across an image, with the direction and magnitude of the brightness slope determined by editable curves. @@ -3857,51 +4327,40 @@ that color only, and the "all" curve is ignored. Any or all three RGB colors may be adjusted in this manner. You can use this to remove a color-caste that varies across an image or image area.
-
+
- -
- - - -Tone Mapping
- - - -
- - -Tone mapping increases the apparent brightness range of an image by +
+Tone +Mapping
+
+Tone mapping increases the +apparent brightness range of an image by increasing local contrast. It is especially useful to improve HDR images, but can also be applied to any image. HDR images often seem "flat" because the contrast between nearby pixels has been reduced to -make the overall contrast fit within the available range. Tone Mapping increases the contrast between nearby +make the overall contrast fit within the available range. Tone Mapping +increases the contrast between nearby pixels without increasing the overall contrast. It relies on the nature of human vision: contrast within a small angle is perceived more strongly than contrast over a large angle. Tone mapping also brings out -subtle details (low contrast) that would otherwise be hard to notice.
- - - +subtle details (low contrast) that would otherwise be hard to notice.


- - - Other methods can also be used: adjusting the brightness curve can increase contrast for a selected brightness range (possibly at the expense of others). Flattening the brightness distribution can spread the available -contrast (brightness range) more evenly. Increasing color saturation can +contrast (brightness range) more evenly. Increasing color saturation +can also bring out more detail. These methods operate globally: all pixels of a given color and brightness are processed the same. Tone mapping processes pixels differently depending on the brightness of surrounding -pixels and is more effective at enhancing detail and the perceived brightness range.
- - - +pixels and is more effective at enhancing detail and the perceived +brightness range.


- - In the dialog, the graphic curve determines how much local contrast is increased depending on initial local contrast. The left end of the @@ -3915,13 +4374,9 @@ too far to the right, the image may show artifacts (bright or dark "rays"), -so push it back until these disappear.
- - - +so push it back until these disappear.


- - The curve can be dragged with the mouse and its effect on the image will show up in a few seconds (depending on image size and CPU @@ -3931,16 +4386,16 @@ reduce amplification for low-contrast pixels. In some cases it will be best to select different areas of the image and process them separately, e.g. more conservative for sky, more aggressive for -textured surfaces like stone walls.
- - - -
- -
-White Balance

- - +textured surfaces like stone walls.

+
+
+White Balance

+
This function is an easy way to remove a false color-cast, e.g. the whole image has an overall blue or red tinge. After strarting the function, click @@ -3949,15 +4404,13 @@ be used as a measure of overall false color, and this amount of color will be removed from the whole image. You can click around on various areas and see the impact instantly. Press the [done] button when you -are satisfied, or [cancel] if not.
- - +are satisfied, or [cancel] if not.


- -
Match Colors
-
+
This function matches the colors in one image to those in another. A small spot, determined from a mouse click, is sampled from each image. The spot on the 2nd image will be made to have the same average color @@ -3981,7 +4434,9 @@ accordingly. Click the dialog [done] or [cancel] button to finish.


-DRGB

+DRGB
+
This function is used to change overall brightness or selected colors using OD (optical density) units. The input values range from -99 to +99 which represent -0.99 to +0.99 OD.  OD is a logarithmic @@ -3991,13 +4446,25 @@ side-by-side comparison. The contrast buttons change contrast by 0.01 OD per step, meaning that the brightest and darkest pixels are changed by 0.01 OD in opposite directions, with intermediate pixels changed -proportionally. This function was requested by a professional -photographer -to simplify brightness and color corrections before making prints.
-

+proportionally.
+
+DRGB is the tool for converting +color space between monitor and printer. Print a standard color chart, use +DRGB to adjust the Fotoxx image and print again until the printout is good. +Save the settings (color offsets) and use them to print subsequent images +with correct color the first time. The settings will be different for +different printers and paper types. Use [save] to save the settings to +a file, and use [open] to load the settings from a saved file.
+

Revise RGB
-
+
This function can be used to make complex color corrections, whereby different parts of the image need different corrections. Select up to 9 control points on the image by clicking them with the mouse. @@ -4010,25 +4477,19 @@ more influence than those farther away. The slider Soften Peaks determines how widely the control points spread their influence. If "delta" is checked, the values shown are the deltas (differences) from -the original image.
+the original image.
- - -
- -
+
+
Remove Red Eye

- - -This function reduces the red-eye effect from electronic flash photos. +This function reduces the +red-eye effect from electronic flash photos. Two methods are provided. The first is faster but will not handle difficult cases (e.g. the eyelids are almost as red as the eye). The second method is more robust but also needs more time and care.
- -
- To use the first function, left-click on a red-eye one or more times @@ -4036,11 +4497,9 @@ right-click to undo the change and then left-click more precisely on the center of the red-eye. If a red-eye cannot be fixed correctly, right-click to -undo the change and then use the second method.
- - +undo the change and then use the second method.


- The second method can better handle difficult cases where the red-eye is only slightly red and the color difference with the eyelids is too @@ -4051,21 +4510,19 @@ red eye. Repeat if needed to get the red eye centered in the ellipse (roughly). Note that the shape of the ellipse depends on the direction of the drag, -which can allow more precise enclosure of only the red-eye. Left-click inside the ellipse +which can allow more precise enclosure of only the red-eye. Left-click +inside the ellipse repeatedly while watching the red eye darken, and stop when it is dark enough. If you go too far, the eyelids may start -to darken. Right-click to undo and repeat if necessary.
- - +to darken. Right-click to undo and repeat if necessary.


- - -
+
Blur image

- - -This function can be used to blur or un-sharpen an image. Each pixel is +This function can be used to +blur or un-sharpen an image. Each pixel is mixed with neighboring pixels to reduce the differences, making edges fuzzy. Enter a value for blur radius and press [apply] to see the results. A small value mixes each pixel with its nearest neighbors and @@ -4075,18 +4532,15 @@ can use "select area" to limit the blur to a face or part of a face. This is also a way to cure "banding" in sky areas (this can happen if the flatten, brightness, or tone mapping functions cause the -distribution to spread out, making the brightness steps perceptible).
- - +distribution to spread out, making the brightness steps perceptible).


- - -
+
Sharpen Image

- - -
- +
This function sharpens a blurry image. Three methods are implemented: edge detection, unsharp mask, and gradient. Edge detection: find @@ -4100,11 +4554,9 @@ brightness difference (contrast) between each pixel and its prior neighbors (left and above) is increased, and the pixel brightness is modified to match. This brightness change is propagated to the next -pixel where the process is repeated.
- - +pixel where the process is repeated.


- The edge detection method gives sharper edges where the contrast is high and softer edges elsewhere, making it good for portraits (sharp @@ -4118,134 +4570,117 @@ distance over which pixels around an edge are changed. It should be small for images that are slightly fuzzy and larger for poorer images. Threshold suppresses changes to low-contrast pixels: a higher -values reduces the amplification of low-level irregularities.
- - +values reduces the amplification of low-level irregularities.


- -For the edge detection method, enter the following parameters:
- - +For the edge detection method, enter the following parameters:
+    cycles         -number of iterations
- +number of iterations
   reduce        -brightness reduction threshold per cycle, 80 means 0.80

- +brightness reduction threshold per cycle, 80 means 0.80
   threshold    brightness change low cutoff -threshold

+threshold

- -For the unsharp mask method, enter the following parameters:
- - +For the unsharp mask method, enter the following parameters:
+    radius          distance -pixels around an edge are changed
- +pixels around an edge are changed
   amount        amount of -correction, 100 = normal

- +correction, 100 = normal
   threshold     brightness change low -cutoff threshold

+cutoff threshold

- -For the gradient method, enter the following parameters:
- - +For the gradient method, enter the following parameters:
+    amount        amount of -correction, 100 = normal
- +correction, 100 = normal
   threshold     brightness change low -cutoff threshold

+cutoff threshold

- -Press the button for the method selected and wait a few seconds to see +Press the button for the method +selected and wait a few seconds to see the result. The default values are suggested starting points. Make changes and repeat the process until satisfied. You can go back and forth among the methods to compare which is best for a given image. Use Select Area to operate on different parts of the image with different methods and parameters.
- -
- - -
+
Reduce Noise

- - -This function reduces the noise present in photos taken under poor +This function reduces the noise +present in photos taken under poor lighting conditions, making uniform surfaces appear speckled. Choose one of the methods described below. Press the [reduce] button repeatedly while watching the image. If you go too far, sharpness and detail will be lost. The radius input determines the area around each pixel that is compared. A default radius is set when a -method is selected, but other values may work better. For a large image, these +method is selected, but other values may work better. For a large +image, these algorithms may run a long time. To save time, select a small area and experiment with the different methods and radius settings until you make a decision, then clear the selected area and apply the chosen method to the whole image. There are four different methods, and -each method applies to each RGB color independently.
- - -
- - - - - +each method applies to each RGB color independently.
+
- - + - - + - - - +
Flatten outliers (1)The highest and lowest pixel values within a radius are +   +Flatten +outliers (1)The highest and lowest +pixel values within a radius are moderated slightly.
-
Flatten outliers (2)Pixels are compared to the mean -and sigma of pixels within a radius. Those outside one sigma are moved back +   Flatten outliers +(2)Pixels are compared to +the mean +and sigma of pixels within a radius. Those outside one sigma are moved +back toward the mean.
-
Median brightness
- +
  Median brightness
Pixels are set to the median value of their neighbors within a radius.
-
Top hatDetect outliers by comparison with +   Top hatDetect outliers by +comparison with a band of pixels at a distance. The distance is increased in steps from 1 pixel to the radius limit.
-
- - -
- - -Smart Erase
- - -
- +
+Smart Erase
+
This function can be used to erase small objects that can spoil a good photo, such as power lines, trash on the ground, a sign, etc. The @@ -4264,26 +4699,20 @@ prior erased areas are now fixed and [Undo] will only work for the current selection. As with all edit functions, the toolbar buttons [Undo] and [Redo] can be used to review all changes. It is likely best -to work with an image zoomed to 200% or more. Uncheck "my mouse" to -allow scrolling a zoomed image to a new position. The Blur +to work with an image zoomed to 200% or more. The Blur control adds blur to the replacement pixels. This can reduce visible side-effects, since the replacement pixels may be sharper or have more contrast than the surroundings. Change the Blur setting and repeat the [Erase] button. A blur of 0.5 or 1 pixel is usually effective.
- -
- - -
- - -Remove Dust
- - -
- +
+Remove Dust
+
Images made from dusty scanned slides can have many small dark spots - shadows of the dust on the slides. This function can be used to @@ -4305,18 +4734,55 @@ persistent, you can treat them manually with Smart Erase: set a small mouse radius and click on each spot to remove it. Spots from fibers (long and thin) are usually not removed -automatically, but Smart Erase can be effective here.
- - -
- - - -
-Edit Pixels

- - - +automatically, but Smart Erase can be effective here.
+
+
+Fix Stuck Pixels (always bright or +dark)
+
+Camera sensors may have defects +causing isolated pixels to be always +bright or always dark. This may be one RGB color or all of them. I have +seen a case where a group of 3x3 pixels was always too red. This +function can find such pixels in an image and repair them by +substituting neighboring pixels.
+
+Select the defect sizes to search for: +1 pixel, 4 pixels in a 2x2 block, or 9 pixels in a 3x3 block. The +defects found are surrounded by small circles which you can toggle +between write, black and red. Zoom-in to inspect these and +determine if they are real defects. Use +the contrast control to precisely select the defects. If set too low, +small high-contrast spots in the image may be erroneously selected. If +set too high, real defects may be missed. Use the [apply] button to +erase the defects in the current image. You can apply the function many +times using different settings if needed. The currently shown +(encircled) defective pixels can be saved to a file by using the [save] +button. This file can be used later +to fix the defects in any image made by the same camera: use the [open] +button, select the saved defects file, then use the [apply] button to +fix the +current image. Using a saved defects file from one image to fix the +defects in another image will only work if the two images have never +been trimmed, or if exactly the same trim was applied to both images. +This is necessary because the defective pixels in the two images must +have the same locations. If more than one contrast setting or pixel +group selection is needed to accurately find all the defects in one +image, you can save the respective defect files and combine them +manually into one file. Use any text editor for this. I +suggest you make a test images to find +defects: Make a photo of a paper sheet or blank wall that is +underexpsed to come out gray. This image can be used to find both +bright and dark stuck pixels.

+
+
+Edit Pixels
+
+
This function changes individual pixels. There are three modes of operation: @@ -4335,8 +4801,7 @@ gradually change the color using many clicks or drags (analogous to spray painting from a distance). Erase also works this way: use zero transparency to immediately erase, and high transparency to erase -gradually. Uncheck "my mouse" to use the -mouse to scroll or zoom the image, then re-check to resume painting. The +gradually. The [undo-last] button removes the last edit (modifications from the last click or drag operation), and this can be repeated to remove many recent edits. The memory for undo operations is limited to 200 @@ -4346,7 +4811,9 @@ memory available is displayed in the dialog, so you can see when the limit is approaching. If a selected area is enabled, the painting is confined within the area. You can select an area by color and then -change the color without taking care about the edges. NOTE: +change the color without taking care about the edges. NOTE: zoom the image to 100% or more when using this function. If the mouse steps are larger than the image pixels and a small brush is being used, some pixels may be @@ -4355,29 +4822,27 @@


- -Art Menu
- +Art +Menu

- - +
Color Depth

- -This function changes the normal 16 bits per RGB color (red, green, +This function changes the normal +16 bits per RGB color (red, green, blue) to any value between 1 and 16 bits per color. At 8 bits per color, there are 16.8 million total color combinations. At 4 bits per color there are only 4096 total colors. Use 1-4 bits for an interesting "poster" effect.
-
- -
+
Drawing

- -This function transforms a photo into a black and white high-contrast +This function transforms a photo +into a black and white high-contrast image or into a line drawing where only the edges of objects are shown as black lines on white background or white lines on black background. The sliding control "contrast" will deepen dark areas to black. The @@ -4386,15 +4851,15 @@ high-contrast pixels (edges of objects) and suppress low-contrast pixels. This can be black on white or white on black, depending on the selection of the radio buttons "pencil" and "chalk". Manipulate both -"threshold" and "outlines" to find the best balance.
- +"threshold" and "outlines" to find the best balance.


- -
- -Outlines
- -This function transforms a photo into a colorized line drawing showing +
+Outlines
+This function transforms a photo +into a colorized line drawing showing outlines of objects within the image. Edges (sharp transitions in brightness or color) in the image are brightened, and the rest of the image is darkened. There are three sliding controls. Outline threshold: @@ -4402,48 +4867,45 @@ "show no edges" at the low end to "show all edges" (even faint ones) at the high end. Outline width: the width of the enhanced edges, from 1-pixel to about 5 pixels. Image brightness: the brightness of the -image itself, from dark (show only the outlines) to full brightness.
- - - +image itself, from dark (show only the outlines) to full brightness.


- -
+
Embossing

- -This function transforms a photo into a simulated relief or embossed +This function transforms a photo +into a simulated relief or embossed image. The "radius" setting determines the feature size or level of detail. The "depth" setting determines how deep the features go into the surface.
-
- -
+
Tiles

- -This function transforms a photo into an array of large monocolor +This function transforms a photo +into an array of large monocolor tiles. You can control the tile size and the thickness of the space between tiles (caulk, grout). This is also called "pixelate" or -"pixelize". Use Select Area to confine the transform to a limited area, such as a face.
- +"pixelize". Use Select Area to confine the transform to a limited area, +such as a face.


- -
- -Dots
- -This function transforms a photo into a array of dots, like +
+Dots
+This function transforms a photo +into a array of dots, like old-fashioned comic book pictures or Roy Lichtenstein paintings. The only control is the dot size. Also experiment with using color -saturation, color depth, or other functions before using Dots.
- +saturation, color depth, or other functions before using Dots.


- -
+
Painting
- -This function transform a photo into something looking more like a +This function transform a photo +into something looking more like a painting. It reduces the number of colors, maps each contiguous pixel area having the same color, and then consolidates smaller areas into adjacent larger areas having the best color match. Four user settings @@ -4460,22 +4922,22 @@ a thin black border, like irregular tiles in a mosaic. After using this function, using the Embossing function can add interesting texture to -the image.
-
+the image.


-
- -Combine Menu
- -
- - +Combine Menu
+
+
-Make a High Dynamic Range Image
(HDR)
- -Combine (overlay) multiple images of the same subject with +Make a High Dynamic Range Image (HDR)
+Combine (overlay) multiple +images of the same subject with different exposure levels. The combined image can show improved visibility of detail in both the darker and brighter areas, in @@ -4484,12 +4946,14 @@ do exposure bracketing: take multiple shots in quick succession with different exposure levels. You can combine such images to make a better one. If the camera is adjusted manually between shots, take care -to keep it level and aim at the same distant point. Some misalignment of the +to keep it level and aim at the same distant point. Some misalignment +of the two images can be tolerated. If things move between shots, fuzziness and ghosting cannot be avoided.
- -
+
Select the HDR menu function. A file open dialog is started to select up @@ -4517,8 +4981,8 @@ an anchor point to remove it. In general, the brightest image should have a higher contribution to the darker pixels, and the darkest image a higher contribution to the brighter pixels. You -will likely need practice to become effective at working the curves.
- +will likely need practice to become effective at working the curves.


A faster and easier alternative may work as well: after the images @@ -4529,21 +4993,21 @@ any area in the image which needs more brightness, color, or local contrast, so you can apply -different methods and parameters to different areas.
- +different methods and parameters to different areas.


- -
+
-Make a High Depth of Field Image (HDF)
- -Combine (overlay) multiple photos of the same subject with +Make a High Depth of Field Image (HDF)
+Combine (overlay) multiple +photos of the same subject with different focus settings from near to far. Different parts of the subject are in sharp focus in each image. Combine the images so that all parts of the subject are sharp. This technique is most useful for extreme close-ups.
-
Making the photos: choose a point for the center of the image. Aim @@ -4561,8 +5025,9 @@ shifted against farther objects). Such problems may be fixable later in Fotoxx, but this may require considerable time. It is better to avoid the problems.
- -
+
Processing the photos: in Fotoxx, choose the HDF menu function and select up to 9 images. @@ -4575,14 +5040,14 @@ complete, a dialog opens. You can select any input image and "paint" with the mouse on any area of the output image. This converts the original image mix to the selected image for the area -being painted. For each area or object in the image, choose an input image that is sharp in that area. The +being painted. For each area or object in the image, choose an input +image that is sharp in that area. The radius of the paintbrush can set larger or smaller, so you can paint large areas quickly and control fine detail when needed. If you have overlapping near and far objects, time and patience will be needed to make all of -them sharp. Uncheck "my mouse" to zoom or scroll the image, and re-check to resume painting.
- +them sharp.


Misalignments can be corrected by selecting the "warp" option in the @@ -4590,42 +5055,70 @@ mouse, and the composite output image is changed accordingly. The warp is limited to the area around the mouse. When a painted area is dragged, the corresponding image is automatically selected and -dragged, while areas painted with other images remain fixed. Areas that have not been painted +dragged, while areas painted with other images remain fixed. Areas that +have not been painted cannot be dragged. Move around to -different areas and make incremental drags until all areas are aligned.
- +different areas and make incremental drags until all areas are aligned.

 
- - -Suggested Workflow:
Using paint mode, -choose each image in sequence and paint all areas that look sharp with -that image. Any boundaries that are not well-aligned will show up -clearly as shifts in the edges of objects in the image. Some of these can be made +Suggested Workflow: Using +paint +mode, +choose +each +image +in +sequence +and +paint +all +areas +that +look +sharp +with +that +image. +Any +boundaries +that +are +not +well-aligned +will +show +up +clearly +as shifts in the edges of objects in the image. Some of these +can be made unimportant by changing the image used for painting (if more than one image is sharp enough). Using -warp mode, make fine adjustments as needed to eliminate visible shifts.
- +warp mode, make fine adjustments as needed to eliminate visible shifts.


- -
-Stack / Paint
- -Combine (overlay) multiple photos of the same subject taken at +
+Stack / Paint
+
+Combine (overlay) multiple +photos of the same subject taken at different times. Remove tourists and cars that come and go between -shots by painting them away with the mouse.
- +shots by painting them away with the mouse.


Making the photos: aim the camera at the same distant point and take multiple photos as tourists or cars move in front of the subject. Try to get at least one photo with each part of the subject not obscured by the moving objects.
-
-Processing the photos: in Fotoxx, choose the Stack / Paint menu function and select up to 9 images. +Processing the photos: in Fotoxx, choose the Stack / Paint menu +function and select up to 9 images. The images will now be aligned as well as possible. This may take a minute or more per image, depending on image size and CPU speed. The output @@ -4638,21 +5131,23 @@ is free from the moving objects. The radius of the paintbrush can set larger or smaller, so you can paint large -areas quickly and control fine detail when needed. Uncheck "my mouse" -to zoom or scroll the image, and re-check to resume painting.
+areas quickly and control fine detail when needed.


- -
-Stack / Noise
- -This function combines 2-9 images (photos) of the same subject. The +
+Stack / Noise
+This function combines 2-9 +images (photos) of the same subject. The photos should be nearly the same, except for small offsets caused by a hand-held camera. If the photos were made with a very high ISO setting (low light conditions), the pixels will have considerable noise. By making many photos and averaging them, the noise can be mostly eliminated.
- -
+
Making the photos: choose a point for the center of the image. Take several photos using the same center and being careful not to shift or @@ -4663,7 +5158,8 @@ exposure times. In Fotoxx, chose the Stack / Noise function and select up to nine image files. They will be combined automatically and shown, and -then a dialog will open. The initial output image is a combination of all the selected input +then a dialog will open. The initial output image is a combination of +all the selected input images, averaged together. This means that the RGB values for each output pixel are the average of the RGB values for the corresponding input pixels. A few alternative tools can be used to possibly reduce @@ -4675,72 +5171,94 @@ seconds). The checkboxes for "omit low pixel" and "omit high pixel" will cause the lowest and highest RGB input values to be discarded before the average is calculated. This may help to get noise spikes -removed from the mix. This has no effect if the median method is selected.
- +removed from the mix. This has no effect if the median method is +selected.


- -
+
Make a Panorama Image

- -This function stitches 2-4 images together to make a wide image or +This function stitches 2-4 +images together to make a wide image or panorama. The images must overlap by 15% or more, so that the program -can find where they coincide and put them together.
- -
+can find where they coincide and put them together.

+
Using the panorama menu function, select 2-4 image files. The images are initially joined and shown with a small transparent overlap. A pre-align dialog asks you to drag the images into rough alignment. Drag the images into the correct left to -right order, if needed. The image to drag may overlap other images. To +right order. The image to drag may overlap other images. To be clear about which image is being dragged, drag from near the center of the image. After the images are in the correct order, align each image to its left neighbor. It works best to proceed from left to right. Move an image horizontally and vertically into rough alignment with its neighbor to the left, then -rotate the image if needed by dragging its bottom edge. The image +rotate the image if needed by dragging its bottom edge left or right. +The image pivots around the mid-point of its overlap with the image to the left. The fastest method is to align the overlap middle region first, then rotate the right image if needed to bring the upper and lower overlap regions into alignment. Extreme accuracy is not needed. Use the [resize] button to get a bigger combined image after moving them closer together.
-
The images should be correctly curved and fit together well. If they do -not fit, you need to set the lens parameters as described Tools > Lens -Parameters (link). You -can adjust these parameters within the pre-align dialog until the -images fit -reasonably well, and this may be good enough. -The lens mm parameter (focal length, 35mm equivalent) is obtained from the EXIF data if -available. The lens bow parameter (barrel distortion) must be adjusted -manually, but this is often insignificant and can be left at zero.
- -
- -Press [proceed] when rough alignment is finished, and the program will +not, then the lens mm +parameter (focal length, +35mm equivalent) needs +adjustment. The curvature of the images changes as lens mm is adjusted. +The initial value is obtained from the EXIF data if +available, and this is normally good enough. The lens bow parameter +(barrel or pincushion distortion) is not available in EXIF and must be +adjusted +manually, but this is often insignificant and can be left at zero. You +can measure and set the lens +parameters manually as described below.
+
+If +an image was trimmed so that the greater dimension (width or +height) was reduced, then the EXIF focal length is no longer valid, and +the EXIF initial value may not work well. A section of an image taken +from the +middle has an effective focal length greater than the original. Use the +pre-align dialog to increase the lens mm +parameter until the images fit together reasonably well.
+
+Press [proceed] when pre-alignment is finished, and the program will do fine alignment and join the images. Internally, the images are shifted and rotated and the degree of match is evaluated. This is done with increasing image sizes until the best match is found within a -fraction of a pixel. This may take from 10 seconds to a minute or more per image, +fraction of a pixel. This may take from 10 seconds to a minute or more +per image, depending on -CPU speed and image size.

- -
- -When fine alignment is complete, the combined image is displayed. A +CPU speed and image size.
+
+When +fine alignment is complete, the combined image is displayed. A dialog pops up for fine adjustment of brightness and color match. You -may see a sharp border because the images do not have the same +may see a sharp border between images if the images do not have the +same brightness and color balance. The [auto color] button can be used to perform -an automatic color match, which is usually the best starting point. The +an automatic color match, which is often satisfactory by itself. The other controls -allow you to make additional changes to better match the images. Change +allow you to make additional changes to better match the images. Select +one of the images with the radio buttons at the top, change +the +values for brightness and color, and press the [apply] button to see the -values for brightness and color and press the [apply] button to see the results. Use [auto color] to match the other images to the one changed. Use [file color] to restore the original values from the input images. The "blend width" input governs how the images are blended @@ -4748,12 +5266,14 @@ over this many pixels, to mask imbalances that cannot be fully corrected. The default is 1 pixel, which makes any brightness or color differences look obvious. -When done, you can use unbend, image warp, rotate, trim, and other +
+
+When done, you can use unbend, warp, rotate, trim, and other functions -for final adjustments.

- +for final adjustments. Use the auto-trim function at the end to +automatically get rid of any leftover black margins.


- Vertical Panorama
This @@ -4762,38 +5282,82 @@ from near their centers. To rotate an image, drag the right edge up or down. It is best to align from the top down.

-Scanned Images
+Scanned Images
Scanned images can be combined if there is enough overlap. Set the lens -mm parameter to the maximum value, since there is no curvature in -scanned images.
+mm parameter to the maximum value (999 mm), since there is no curvature +in +scanned images.
-
- -Panorama Limitations
+Panorama +Limitations
Panoramas including nearby objects can be tricky: when -the photos are made, be careful to turn the camera on an axis through the lens, with minimum lateral movement, otherwise the +the photos are made, be careful to turn the camera on an axis through +the lens, with minimum lateral movement, otherwise the images may align poorly due to shifting foreground objects (parallax). This is not an issue when the subject is 50+ meters away, since a small lateral movement has little impact on the image.
- +
+Setting +Lens +Parameters +Automatically

+ +The [search] button in the panorama pre-alignment dialog initiates an +automated +search for optimum lens parameters. Use a suitable image pair: the +subject is 50+ meters away, the images have a low horizon +difference and little relative rotation, and there is plenty of +high-contrast detail in the overlap area. Input your nominal lens focal +length +for lens_mm. Use zero for lens_bow. After doing a decent pre-align, +press the [search] button and wait a while for the results. Do this a +second time and observe the changes. If the values remain consistent, +you can use them for your panoramas. The search function steps through +a range of values for lens_mm, +lens_bow, and the image alignment offsets for x, y, and theta. It +searches for the lens values that give the best alignment results for +the given images. The process needs a minute or more, but you only +need to do this once to characterize a given camera lens. Be sure to +save the results using the Tools > Settings menu.
+
+Setting Lens +Parameters Manually
+Make +a panorama image of a brick wall (or any wall with lots of detail) with +about 40% image +overlap. The wall should be 5+ meters away. Within the panorama +pre-align process, adjust lens_mm and +lens_bow until the overlapping bricks coincide. +When making the two images, be sure to turn the camera on a vertical +axis through the lens, minimizing lateral movement and rotation in +other axes - otherwise the images may fit poorly and your lens +parameters may +not be optimal. The result should roughly correspond to the nominal +focal length of your lens (35mm equivalent). It may be off somewhat (my +27mm lens works best with a lens_mm setting of 29-30mm). I speculate +that this is because wide-field camera lenses are not ideal lenses +(pinhole equivalent). Most panoramas will still work OK even if the +lens_mm setting is off by 10%.


-
- -
- -Plugins Menu
- +
+Plugins +Menu

Other image edit programs (e.g. Gimp) can be added to this menu. They will then work like any other edit function in Fotoxx. After using one of these external programs to modify an image, you can use the Fotoxx -[Undo] and [Redo] buttons to control the results, perform additional +[Undo] and [Redo] buttons to check the results, perform additional edits with Fotoxx, or use [Save] or [Save+F] to save the edited image. The image passed by Fotoxx to the external program is a TIFF file with 16 bits per color. Most programs can read this but may use only 8 bits. @@ -4801,15 +5365,14 @@ ("save" menu) and exit the program. Fotoxx will then pick up the revised file and use it as though the edit had been done in Fotoxx.
-
To add a new plugin, use the function Plugins > Edit Plugins. Input a menu name (e.g. "Gimp"), a command to start the program (e.g. "gimp") and press the [Add] button. You can also remove a plugin by selecting it from the list and pressing the [Remove] button. The Plugins menu -will not be updated until the next time Fotoxx is started.
- +will not be updated until the next time Fotoxx is started.


The plugins are saved in a file: /home/<user>/.fotoxx/plugins @@ -4817,50 +5380,44 @@ only way to change the sequence of the menu entries. Be careful not to screw up the format: menu = command (with exactly one space before and after the '=' character).
-
- -

- -
- - +
+
Help Menu

- -
About

This displays a short message about the Fotoxx version number, license, credits, and contact address.
-
- -User Guide
+User Guide
The user guide (this document) is displayed (created using the WYSIWYG -HTML editor KompoZer).
+HTML editor KompoZer).


-User Guide Changes
+User +Guide +Changes
This is a summary of changes in the User Guide for the most recent versions. The intent is to enable you to survey the changes without reading the whole document.

Edit Functions Summary
-A one-page "quick reference" summary of the image edit functions is displayed.
+A one-page "quick reference" summary of the image edit functions is +displayed.

- -README
+README
Displays the README file distributed with Fotoxx, which may contain new information about installation or dependencies. When you install a new release of Fotoxx, you should look at README and the Change Log to check if there is anything special you need to be aware of.
-
- Change Log
@@ -4868,30 +5425,29 @@ details about functional changes, additions, or bug fixes for the current and previous releases.
-
- -Translate
+Translate
Displays a short text file which explains how to make a new translation or change an existing one. This involves editing a text file that -contains English text messages with their corresponding translations (see technical notes, below).
- +contains English text messages with their corresponding translations +(see technical notes, below).


- -Home Page
+Home Page
Shows the Fotoxx home page from the Internet. Look here for program updates (the page named "recent changes"). This page is published via -RSS and you can subscribe to get timely notification of changes.
- -
+RSS and you can subscribe to get timely notification of changes.

+

-

-Organizing a Large Image Collection for Searching
+Organizing a Large Image +Collection for Searching

Fotoxx can edit and search for the following image attributes: photo date, "star" rating, tags, file names, and words appearing in captions @@ -4909,7 +5465,9 @@ The image files may further be organized in time sequence by using MM.DD as the start of the file name. The rest of the file name can be an event or place name, and a sequence number.
-    Example: /top-directory/2011/08.20 Spitzbergen 23.
+    Example: /top-directory/2011/08.20 +Spitzbergen +23
This very basic organization allows Fotoxx to find files by searching file names. In the above example, a search for "spitzbergen" or even "spitz" will produce all the images of Spitzbergen. The batch rename @@ -4922,7 +5480,8 @@ organization is to use captions and comments (Info > Edit Captions/Comments). These are arbitrary text strings that can be added to images in rapid sequence:
-   input some text, press [next], input some text, press [next] ... 
+   input some text, press [next], input some text, press +[next] ... 
Captions and comments are two separate inputs but treated logically the same. They are searchable: words appearing in captions and comments can be searched for. You can add the names of persons or other information @@ -4948,193 +5507,259 @@ list of defined tags. New tags can be defined as needed. Images can have many tags, and can be searched for AND/OR combinations of tags (along with date, star rating, file name, caption, comments). Tagging -is the fastest way to go through a large collection, needing a few +is the fastest way to classify a large collection, needing a few seconds per image. The hitch is the tagging system. You need to lay this out in advance and stick to it, otherwise things can get chaotic. -If you end up with 1000 tags they will not be too useful. If the images +If you end up with 1000 tags they will not be very useful. If the +images are physically organized by time, then groups of images will tend to have the same tags, which makes the process of adding tags faster.
+
+
+
+
+
User +Guide +Changes
+

+This section is +provided to help you quickly review the changes without reading +the whole manual. This also helps translators to find the topics +needing revision.

-
-
-
-
User Guide Changes
-
This section is provided to enable you to quickly review the changes without reading the whole manual.
-

-v.11.11
- +v.12.01
+
+
    +
  • The introductory sections were rearranged and revised for +functionality changes.
    +
  • +
  • The paragraph about "my mouse" was replaced with "mouse +ownership" and references to "my +mouse" elsewhere were removed. My mouse is dead.
    +
  • +
  • Select Area introduction - new paragraph about "layers" and +"areas".
    +
  • +
  • New topic: Search Metadata
  • +
  • Revised topic: Search Images
  • +
  • New Technical Notes: Preview Mode, File Size, Search Image +Benchmarks.
  • +
  • Technical Note deleted: Missing Toolbar Button Text (see Tools +> User Settings).
  • +
  • Technical Note deleted: How to get a traceback dump. This is now +automatic.
    +
  • +
  • Technical Note: Translations: file name for language xx changed +to fotoxx-xx.po.
    +
  • +
  • Lens Parameters topic was removed from Tools menu and added to +Panorama topic. 
  • +
  • Toolbar Style topic was removed from Tools menu and added to the User Settings topic.
    +
  • +
  • User Settings menu and topic was +added to the Tools menu.
    +
  • +
  • New Technical Note: Ubuntu Unity Launcher (drop-down menu with +options).
    +
  • +
  • Technical Note revised: The option -blank was added to Command +Line Options.
    +
  • +
+v.11.12
+
+ + +v.11.11
+
    -
- -v.11.10
-
    -
  • Getting Started: Installation and Initialization changes for Synchronize Files.
  • -
  • Save Image File: new functionality to warn about overwriting an original file.
  • -
  • Print Image File: revised to match revised functionality.
  • -
  • Slide Show: new option to show only the latest version of each image file.
  • -
  • Gamma Curve: new topic, added after Brightness/Color.
  • -
  • Straighten Image: new topic, added after Unbend Image.
  • -
  • Slide Show: a sentence was added to explain pause/resume via spacebar.
  • +v.11.10
    +
      +
    • Getting Started: +Installation and Initialization changes for Synchronize Files.
    • +
    • Save Image File: new +functionality to warn about overwriting an original file.
    • +
    • Print Image File: revised +to match revised functionality.
    • +
    • Slide Show: new option to +show only the latest version of each image file.
    • +
    • Gamma Curve: new topic, +added after Brightness/Color.
    • +
    • Straighten Image: new +topic, added after Unbend Image.
    • +
    • Slide Show: a sentence was +added to explain pause/resume via spacebar.
      • - - - - - - - -
    - - - - - - - - -v.11.09
    -
      -
    • The two menus Edit Caption and Edit Comments were combined.
    • -
    • The menu and topic Open RAW File was eliminated
      +v.11.09
      +
      +
        +
      • The two menus Edit Caption +and Edit Comments were combined.
      • +
      • The menu and topic Open +RAW File was eliminated and Open Image File was revised.
        (open Image File can be used to open a single RAW file).
        -
      • -
      • -A paragraph about scanned images was added to the panorama topic.
      • -
      • -The topic Print Image File was revised for the addition of print margins.
      • + +
      • A paragraph about scanned +images was added to the panorama topic.
      • +
      • The topic Print Image File +was revised for the addition of print margins.
      -v.11.08
      -
        -
      • -Getting Started: the paragraph Fotoxx Startup was added.
      • -
      • -General Editing Procedure: expanded for clarity.
      • -
      • -Select Area: "Delete" was changed to "Unselect" in several places
        -(some people thought it meant deleting a part of the image).
      • -
      • -"Whole Image" was changed to "Select Whole Image" in several places.
      • -
      • The new topic DRGB was added after Expand Brightness.
      • -
      • -Revise RGB: A sentence was added for the new "delta" mode.
      • +v.11.08
        + +
          +
        • Getting Started: the +paragraph Fotoxx Startup was added.
        • +
        • General Editing Procedure: +expanded for clarity.
        • +
        • Select Area: "Delete" was +changed to "Unselect" in several places
          +(some people thought it meant deleting a part of the image).
        • +
        • "Whole Image" was changed +to "Select Whole Image" in several places.
        • +
        • The new topic DRGB was +added after Expand Brightness.
        • +
        • Revise RGB: A sentence was +added for the new "delta" mode.
        • +
        • Show RGB: minor errors +corrected.
          +
        v.11.07
        -
          -
        • Brightness/Color: explain the graph range and the step size for the buttons.
        • -
        • -Match Colors: new topic for new function.
          -
        • -
        • -Save Image File: A new paragraph was added for Save to New Version.
          -
        • -
        • -Show RGB: expanded to explain the EV and OD units.
        • -
        • The Clone topic was expanded to cover the new function Clone Overlay.
          -
        • -
        • Open Image File topic was expanded to cover "Open in New Window".
        • -
        • -Toolbar Buttons (table): updated to: Save / Save+V / Save+F.
        • -
        • The Brightness Ramp topic was expanded to explain the new RGB buttons.
        • -
        • -Keyboard Shortcuts (table): added entry "Control + v or V".
        • -
        • -Toolbar Buttons (table): Undo and Redo text revised for shift key.
        • -
        • -Replaced "Tools > Rebuild Search Index" with "Tools > Synchronize Files".
        • -
        • The Select Area topic was revised to improve clarity.
        • -
        • -Select Area topic: an explanation for the unfinish button was added.
        • -
        • -The new topic Revise RGB was added.
        • -
        • -The topic Save to New File was revised to reflect changed functionality.
        • -
        • -Technical Notes: command line options: add entry for -recent
        • -

        -
        -
        -
        - - -Technical Notes
        - - +
          +
        • Brightness/Color: explain +the graph range and the step size for the buttons.
        • +
        • Match Colors: new topic +for new function.
          +
        • +
        • Save Image File: A new +paragraph was added for Save to New Version.
          +
        • +
        • Show RGB: expanded to +explain the EV and OD units.
        • +
        • The Clone topic was +expanded to cover the new function Clone Overlay.
          +
        • +
        • Open Image File topic was +expanded to cover "Open in New Window".
        • +
        • Toolbar Buttons (table): +updated to: Save / Save+V / Save+F.
        • +
        • The Brightness Ramp topic +was expanded to explain the new RGB buttons.
        • +
        • Keyboard Shortcuts +(table): added entry "Control + v or V".
        • +
        • Toolbar Buttons (table): +Undo and Redo text revised for shift key.
        • +
        • Replaced "Tools > +Rebuild Search Index" with "Tools > Synchronize Files".
        • +
        • The Select Area topic was +revised to improve clarity.
        • +
        • Select Area topic: an +explanation for the unfinish button was added.
        • +
        • The new topic Revise RGB +was added.
        • +
        • The topic Save to New File +was revised to reflect changed functionality.
        • +
        • Technical Notes: command +line options: add entry for -recent
        • +
        +
        +
        +
        +Technical +Notes

        Translations

        - - See the menu  -Help > Translations  or the text file -TRANSLATIONS for +Help > Translations  or the text file translations for guidance on how to modify an existing translation or make a new one. This is a fairly simple process: edit a text file with English text strings followed by their corresponding translations. See one of the existing translations as an example, e.g. -/usr/share/fotoxx/locales/de/fotoxx.po +/usr/share/fotoxx/locales/fotoxx-de.po (the German translation). A new translation for language code xx -would be saved at /usr/share/fotoxx/locales/xx. After making such +would be saved at /usr/share/fotoxx/locales/fotoxx-xx.po. After making +such a file, you can test it by starting Fotoxx on the command line: $ -fotoxx -l xx.
        - - +fotoxx -lang xx.

        - - -Hardware and Software Requirements
        - +Hardware and +Software Requirements
        -Fotoxx works best on a fast computer with at least a gigabyte of memory. Multiple CPU cores are utilized for compute -intensive functions (e.g. sharpen, blur, rotate, warp, tone mapping, HDR, +Fotoxx works best on a fast computer with at least a gigabyte of +memory. Multiple CPU cores are utilized for compute +intensive functions (e.g. sharpen, rotate, warp, tone mapping, +HDR, panorama). Slower computers (notebooks) will work, but will be quite slow for some functions. Monitors smaller than 1200x800 will feel confining for some -functions. The typical notebook screen with limited brightness and -color -should NOT be used for image retouching.
        - - -
        - - -Programs Required by Fotoxx
        - - -Fotoxx requires the following -libraries and programs to function at run time:
        - - - - - +functions. The typical notebook screen with limited brightness and +color +should NOT be used for image retouching.
        +
        +Programs +Required by Fotoxx

        +Fotoxx requires the following +libraries and programs to function at run time:
        +
        @@ -5143,159 +5768,185 @@ - + - - + - +
           libtiff4
           xdg-utilsopen text or html files with user's preferred applicationopen text or html files +with user's preferred application
           exiftool
        -
        read and write image metadata (tags, comments, etc.)
        -
           ufraw-batch 
        - +
           +ufraw-batch 
        import raw image files from a digital cameraimport raw image files +from a digital camera
           brasero burn a CD or DVD with selected imagesburn a CD or DVD with +selected images
        - -
        - -Packages Required for Fotoxx Source +
        +Packages +Required for Fotoxx Source Build

        - - See the README file for -instructions on compiling Fotoxx from source.
        - - +instructions on compiling Fotoxx from source.

        In addition to the -programs listed above, the following are also needed:
        - - - - - +programs listed above, the following are also needed:
        +
        - - +
           g++
        -
        GNU C++ compiler
           libgtk2.0-dev 
        - +
           +libgtk2.0-dev 
        Gnome GTK/GDK/Pixbuf/etc. development files
           libtiff4-devtiff library development files tiff library development +files
        - Note: package names and exactly which files are included in each package are decisions made by each Linux distro. The above names are valid for Debian-based distros (including Ubuntu). For other distros you may have to dig to find the right packages to install.
        - - -
        - -Command +
        +Command Line Options

        - - - - - - - - - - - - - - - - - - - - - - +
        + + - - + + - + + + - + - - + - - - + + + + + + + + + -
           -v
        output version and build date and exit
        +
        output version and build +date and exit
            /.../imagefile.jpg
        - - - -
        initial image directory or +
            +/.../imagefile.jpg
        +
        initial image directory +or image file to -open
           -recent  (or -r)
        +open
           +-recent  (or -r)
        show a gallery of recent files, most recent at the topshow a gallery of recent +files, most recent at the top
           -prev  (or -p)
        +
           -prev  +(or -p)
        show the last file viewed in the previous sessionshow the last file viewed +in the previous session
           -lang lc_RClanguage code (+ opt. region code) to use for GUI (de, de_AT, fr ...)
           -slideshow /.../image1.jpg
        -    [ -music /.../playlist.pls ]
        -
        start a slide show using image1 and following images
        optional music playlist for slide show

        -
           -blank (or +-b)
        +
        show a blank window
        +
           -lang lc_RClanguage code (+ opt. +region code) to use for GUI (de, de_AT, fr ...)
           +-slideshow +/.../image1.jpg + + + + + + + + + -
        -
        -Status Bar Information

        -Example:  CPU -123%  1234x987x24  0.45MB  56%  edits: -3   menu locked   area active   dialog -open
        - + + + + + + +
        +    [ -music /.../playlist.pls ]
        + + + + + + + + +
        start a slide show using +image1 and following images
        +optional music playlist for slide show

        +
           -translate +(or -t)
        +
        start in online +translation mode (to capture the initial menus)
        +
        +
        +Status Bar Information

        +Example:  CPU +123%  1234x987x8  0.45MB  56%  edits: +3   menu locked   area active   dialog +open
        + - - - + - @@ -5314,47 +5965,85 @@ - + - - + - - - - + - - + + + - -
           CPU 123%
        -
        current Fotoxx process CPU loading for all threads
        - +
        current Fotoxx process +CPU loading for all threads
           1234x987x8 
        - +
           +1234x987x8 
        image width x height x depth + image width x height x +depth (bits per color)
           edits: 3
        -
        3 edits have been made and can be reversed with the [undo] button
        -
        3 edits have been made +and can be reversed with the [undo] button
        +
           menu locked  
        - +
           menu +locked  
        an edit function is active; other edit functions are blockedan edit function is +active; other edit functions are blocked
           file sync busy
        +
           file sync +busy
        synchronize files operation is running; image edit functions are blocked
        +
        synchronize files +operation is running; image edit functions are blocked
           area active  
        - +
           area +active  
        a select area is present and enabled - edits are confined within the area
        a select area is present +and enabled - edits are confined within the area
           dialog open
        a dialog for user input is open and waiting
        +
        a dialog for user input +is open and waiting
        -
        - - -File Types Supported
        - +Ubuntu Unity +Launcher
        +The following launcher will have +a right-click dropdown menu with three different startup options: +blank window, last image viewed, and a gallery of up to 100 recent +images that can be selected. Save the following text as a file named +fotoxx.desktop, make it executable, and drag the file to the Unity left +side launcher list.
        +
        [Desktop Entry]
        +Name=fotoxx
        +GenericName=Photo Editor
        +Comment=Edit photos and manage collections
        +Categories=Photography;
        +Type=Application
        +Terminal=false
        +MimeType=image/bmp;image/gif;image/tiff;image/jpeg;image/png;
        +Exec=/usr/bin/fotoxx
        +Icon=/usr/share/fotoxx/icons/fotoxx.png
        +X-Ayatana-Desktop-Shortcuts=blank window;last image;recent images
        +
        +[blank window Shortcut Group]
        +Name=blank window
        +Exec=fotoxx -blank
        +TargetEnvironment=Unity
        +
        +[last image Shortcut Group]
        +Name=last image
        +Exec=fotoxx -prev
        +TargetEnvironment=Unity
        +
        +[recent images Shortcut Group]
        +Name=recent images
        +Exec=fotoxx -recent
        +TargetEnvironment=Unity
        +
        +
        +File Types +Supported
        Fotoxx uses two libraries to support reading and writing of image files: the GDK pixbuf library and libtiff. Pixbuf supports JPEG, PNG, -ICO and BMP files, all with 3 RGB colors and 8 bits per color. Libtiff +ICO and BMP files, with 3 RGB colors and 8 bits per color. Libtiff supports TIFF files with 1-bit depth (black/white), 8-bit and 16-bit grayscale, and 3 RGB colors with 8 or 16 bits per color. Other TIFF formats are not supported by Fotoxx, although they could be added if @@ -5363,25 +6052,9 @@ gray). Fotoxx converts camera RAW files to TIFF RGB with 16 bits per color, using the program ufraw-batch.
        - - -
        - - -Missing Toolbar Button Text
        - - -This is a Gnome configuration issue. The default varies with the phase -of the moon. Open a terminal window and give the command -"gconf-editor". In the dialog, select desktop > gnome > -interface. Set the toolbar style to "both", meaning icons and text.
        - -
        - - -Color Depth
        - +Color Depth
        8-bit color (256 brightness levels), as supported by JPEG files, is the norm for image files and is @@ -5396,17 +6069,13 @@ "banding" or "picket fence distribution". If the image was converted from RAW to 16-bit tiff before editing, this problem can be reduced, even when the image -is converted back to 8 bits for storage (JPEG) or display on a monitor. +is converted back to 8 bits for storage.
        - - -
        - - Alignment -Algorithm (HDR, HDF, Stack, Panorama)
        - +Algorithm
        (HDR, HDF, +Stack, Panorama)
        Relatively few high-contrast or "edge" pixels are selected to control alignment in HDR, HDF, Stack and Panorama. The actual @@ -5417,79 +6086,59 @@ tested. This is done because two photos made with slightly different horizons or rotations will not fit perfectly with simple translation and rotation. Also the cylindrical image projection used for panoramas -is only an approximation of what the camera lens actually does.
        - - +is only an approximation of what the camera lens actually does.

        - - -Tone Mapping Algorithm
        - +Tone Mapping +Algorithm
        The method used by Fotoxx is home-made, but inspired by Fattal and other gradient-based methods. It is not as effective as fattal in some -cases, but close. On the other hand, Fotoxx is both fast and simple.
        - - +cases, but close. On the other hand, Fotoxx is both fast and simple.

        - - -Alpha Channels
        - +Alpha Channels
        -Images having alpha channels (transparency information) can be -processed, but the alpha channel is lost when the processed image file +Images having alpha channels (transparency information) can be edited, +but the alpha channel is lost when the edited image file is saved.
        - -
        - - Image Deterioration From Repeated Editing
        - If you save an edited image file and then use this file later to perform additional edits, pixel resolution may be lost. It is better if you do all edits when the image files are first processed, to minimize image deterioration (or go back to the originals if you still have them). The following edit functions reduce resolution about 1/2 pixel, -and this error can accumulate if you save and open the image file -between edits: rotate (other than -90 degrees), HDR, HDF, stack, panorama, unbend, warp. Resize to a smaller size +and this error can accumulate if multiple functions are applied in +series: rotate (other than +90 degrees), HDR, HDF, stack, panorama, unbend, keystone, warp. Resize +to a smaller size will of course reduce resolution, but using the fraction 1/2, 1/3, or 1/4 gives the best -results. The following functions do not reduce resolution: white -balance, flatten, -brightness/color, brightness ramp, expand, tone mapping, red eye, -sharpen, reduce noise, trim, flip, and all art -functions.
        - - +results. Other functions do not reduce resolution (except for those +that do it deliberately).

        - - -Image Deterioration From Repeated Saving
        - - -Reading a compressed JPEG image and saving it again does lead to some -deterioration, but the effect is negligible - at least with the JPEG -algorithm used by Fotoxx (GTK Pixbuf library) and with JPEG-quality set -to a high value. I read and saved a JPEG image 20 times using a quality -of 90. A rapid A:B comparison with the original image showed a slight -reduction in the brightness of the brightest colors, and no detectable -loss of resolution. The TIFF and PNG formats are lossless and therefore -have no deterioration. They are only space hogs.
        - - +Image +Deterioration From Repeated Saving of JPEG files
        +Reading a compressed JPEG image +and saving it again can lead to loss of detail and increased JPEG +artifacts. The effect seems to be negligible if the JPEG-quality is set +to a high value. I read and saved a JPEG image 30 times using a quality +of 90 (the Fotoxx default). A rapid A:B comparison with the original +image showed no visually detectable +loss of quality. The TIFF and PNG formats are lossless and therefore +have no deterioration. They are only disk space hogs.

        - - -EXIF Errors
        - +EXIF Errors
        Cameras (esp. older ones) do not always produce structurally correct EXIF data, and the program exiftool (used by Fotoxx to manipulate EXIF @@ -5497,14 +6146,12 @@ by saving the image file on top of itself, which will replace the EXIF data with whatever exiftool was able to read -correctly. If tags get lost, you must restore them manually.
        - - +correctly. If desired tags get lost, you must restore them manually.

        - - -Newline characters in User Comments or Captions
        - +Newline +characters in User Comments or Captions
        When editing User Comments or Captions, if you need to align text in columns, you can use the [enter] key to @@ -5518,14 +6165,9 @@ requirement, then do not use the enter key to make new lines when entering long text - just let the text overflow to the next line by itself.
        - -
        - - -Standard Trash Directory
        - - +Standard +Trash Directory
        If the Fotoxx [trash] menu and toolbar button does not put trashed image files into the standard @@ -5540,190 +6182,258 @@ named /images/.Trash-1000, owned by UID 1000, with full permissions for UID 1000. The standard trash function will put trashed files there. Add -this directory manually if it is not there. This may fix the problem.
        - - +this directory manually if it is not there. This may fix the problem.

        - - -Special Fotoxx Files
        - +Special +Fotoxx Files
        The following files reside in /home/<user>/.fotoxx/. The search_index file duplicates data contained in the EXIF and IPTC metadata within the image files. It is there because it can be read 1000 times -faster than reading the image files.
        - - - - - - +faster than reading the image files.
        +
        - - - + - - + - - - + + + + + +
           /annotations/
        -
        annotations saved from Transform > Annotate Image
        - +
        annotations saved from +Transform > Annotate Image
           /collections/
        -
        image collections from File > Save Image Collection
        - +
        image collections from +Tools > Manage Collections
           /saved_areas/
        -
        "cutout" files saved from the Select > Save dialog
        -
           /saved_curves
        -
        curve data saved from Retouch curve edit dialogs
        - +
        curve data saved from +Retouch curve edit dialogs
           fotoxx.log
        -
        Fotoxx outputs that may be relevant for diagnosing problems
        - +
        Fotoxx outputs that may +be relevant for diagnosing problems
           parameters
        -
        setup parameters that are saved across Fotoxx sessions
        -
           -printfile.jpg
        - +printfile.png
        the last file printed with Fotoxx
        -
           recent_files
        -
        a list of the last 100 files opened by Fotoxx, saved when Fotoxx exits
        -
           search_results
        -
        a list of the last image files found with Info > Search Images
        -
           tags_defined
        -
        a list of all categories and tags currently used in all images
        -
           search_index
        -
        a large text file containing searchable data for all image files
        -
           zdialog_positions
        +
           +zdialog_positions
        +
        saved dialog window +positions (relative to main window)
        +
        +
        +Preview Mode
        +
        Some edit functions use a +reduced image size for a faster interactive response time. This reduced +size is shown on the status bar as "preview". When [done] is pressed, +the full-size image is then processed. This is why [done] sometimes +takes noticeable time. A monitor-size image (2 megapixels) is 5 times +faster to process than a 10 megapixel image. This method is used +whenever the preview edits can be applied to the full-size image +without visible impact (Rotate, Unbend, Warp and all brightness, +contrast and color related functions). It cannot be used for things +like sharpen and tone mapping because the results for a small image +cannot be converted for a larger image. Thus Tone Mapping is not as +responsive as Gamma Curve, for example.
        +
        +File Size in Status Bar
        +The file size shown on the status bar while an image is being edited is +the original (unedited) file size. The file size for an edited image is +not known until the image is compressed and saved on disk. In memory +the size is length x width x 3 colors x 2 bytes. A 10 megapixel image +uses 60 megabytes in memory and typically < 2 megabytes on disk (if +jpeg). When the edited image is saved, the correct file size is updated +on the status bar.
        +

        +Image Search Benchmarks

        +Here are a few benchmark numbers +for a test image collection of 29892 images and a total size of 25.6 +GB. The first benchmark is for a new install of Fotoxx on a computer +having nearly 30 thousand images. The next two represent subsequent +startups with no new image files and 15 new image files present. The +Search Image benchmarks show the fast search speed using data +that is in the search index file. The Search Metadata benchmark shows +the slower search speed when non-indexed metadata is +searched: the 4140 files from a prior Search Image were searched for +specific +EXIF data.
        + + + + + + + + - + + + + + + + + + + + + + + + + + + + + -
          +Synchronize +Files from initial status (no index file, no thumbnails)
        +
         28 +minutes
        +
          +Synchronize +Files at startup, no new files present
        saved dialog window positions (WRT main window)
        +
         < +1 +second
        +
          +Synchronize +Files at startup, 15 new files present
        +
         3 +seconds
        +
          +Search +Images by date range, find 2178 from 29892 with a date in 2006
        +
         < +1 +second
        +
          +Search +Images by file name, find 4140 from 29892 with "gallery" in +directory/file name
        +
         < +1 +second
        +
          +Search +Images by tags, find 258 from 29892 having both tags "alaska" +and "scenery"
        +
         < +1 +second
        +
          +Search +Metadata, find 228 of 4140 files having "2011" in EXIF: Modifiy +Date
        +
         30 +seconds
        - -
        Source Code

        - The C++ source code is heavily commented in the hope that others can understand and use the code for their own projects. If you have a technical question about how something works, or a better idea to pass -along, you can  contact me.
        - - +along, you can  contact me.

        - - Questions and Problems
        - -If you have a question or run into a problem, you may contact me. If you send me any images that +If you have a question or run into a problem, you may contact me. If you send me any images that work poorly, I can use these to try to improve Fotoxx. If there is a traceback dump on the screen, or error messages in the log file /home/<user>/.fotoxx/fotoxx.log, please send these -also. Please explain exactly how to produce the error, and what version of Fotoxx and what Linux flavor you are using.
        - - -
        - - -How to get a traceback with source -code line numbers
        - - -If -you have a "crash" problem, it is much easier for me to debug and -fix if I can get a traceback with source code line numbers. Here is a -method to produce this traceback: In a terminal, run the command: gdb -fotoxx. Fotoxx will start under control of the Gnu debugger program: -gdb. In Fotoxx, do whatever makes it crash. The gdb program will say -it crashed. In gdb, enter the command "backtrace". After this, enter -"q" (quit) and "y" (yes, really quit). Copy all the gdb output from the -terminal window, paste into an e-mail message and send it to me (e-mail), along -with a description of what you did leading to the crash.
        - - -
        - - -Technical Reference Book
        - +also. Please explain exactly how to produce the error, and what version +of Fotoxx and what Linux flavor you are using.
        +
        +Technical +Reference Book
        I recommend the book "Introduction to Image Processing and Analysis" by Russ and Russ, CRC Press. It is clear and concise. The following @@ -5732,23 +6442,36 @@ reduction (median smoothing, top hat), simulated embossing. The affine transform method for image warping and rotation was found via Google.
        - -
        - - -Acknowledgements
        - +Acknowledgements
        -The programs  libtiff, ufraw, exiftool have helped Fotoxx evolve much faster than otherwise possible. Of -course this also applies to GTK, -GDK, the pixbuf library, the GNU -tools and libraries, and the entire GNU/Linux +The programs  libtiff, ufraw, exiftool have helped Fotoxx evolve much faster +than otherwise possible. Of +course this also applies to GTK, +GDK, the pixbuf library, the GNU +tools and libraries, and the entire GNU/Linux ecosystem. Thanks to those -who have donated their time for translations and testing (see Help -> About), and those who have donated their ideas for development.
        -

        +who have donated their work for translations (see Fotoxx Help +> About), and those who have donated their ideas for development and +their time for testing.
        +

        -
        -
        \ No newline at end of file + + diff -Nru fotoxx-11.11.1/doc/userguide-it.html fotoxx-12.01.2/doc/userguide-it.html --- fotoxx-11.11.1/doc/userguide-it.html 2011-11-05 05:30:36.000000000 +0000 +++ fotoxx-12.01.2/doc/userguide-it.html 2012-01-04 08:47:10.000000000 +0000 @@ -1,1454 +1,1419 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + fotoxx - Guida utente + -fotoxx user guide + + + + + + Fotoxx -- Manuale utente v.11.06
        +- Manuale utente v.11.12


        Licenza e garanzia

        -Fotoxx ha la licenza GNU General Public License v3 (Free software foundation).
        +Fotoxx ha la licenza GNU General +Public License v3 (Free software foundation).
        + -Fotoxx non garantito per alcuno scopo ma, se trovate un difetto, prover a correggerlo.
        +Fotoxx non è garantito per alcuno scopo ma, se trovate un +difetto, proverò a correggerlo.

        -Origine e contatti
        +Origine e +contatti
        -Fotoxx ha origine dal sito web dell'autore http://kornelix.squarespace.com/fotoxx. +Fotoxx ha origine dal sito web +dell'autore http://kornelix.squarespace.com/fotoxx. Altri siti web possono offrirne il download. Possono esservi modifiche. -In caso di domande, suggerimenti, segnalazione errori, potete contattarmi.
        +In caso di domande, suggerimenti, segnalazione errori, potete
        contattarlo.
        + +
        + +La cronistoria delle versioni della guida utente possono essere +viste qui +(inglese).
        + +
        + +Alcune note tecniche addizionali possono essere trovate qui.
        -
        Alcune note tecniche addizionali possono essere trovate qui.


        -Informazioni di base
        + +Informazioni +di base
        +
        + Installazione
        -
        Per installare Fotoxx, provare prima il pacchetto appropriato: pacchetti: potrebbe installarsi bene con un singolo clic. Altrimenti, occorre installare usando i sorgenti: le istruzioni sono qui: downloads. -Fotoxx dovrebbe mostrarsi nel men sotto la voce Grafica, dopo +
        Per installare Fotoxx, provare prima il pacchetto appropriato: pacchetti: +potrebbe installarsi bene con un singolo clic. Altrimenti, occorre +installare usando i sorgenti: le istruzioni sono qui: downloads. +Fotoxx dovrebbe mostrarsi nel menù sotto la voce Grafica, dopo l'installazione (oppure dopo riavviata la sessione). Diversamente usare il comando "fotoxx" in una finestra di terminale o un lanciatore. Per -provare Fotoxx, usare il pulsante della barra [Apri] per trovare un file +provare Fotoxx, usare il pulsante della barra [Apri] per trovare un +file immagine (.JPG  .TIF  .PNG ...) e controllare che venga mostrato correttamente. -Usare il men Ritocco->Luminosit e colore e premere +Usare il menù Ritocco->Luminosità e colore e premere il pulsante [+++] alcune volte: l'immagine dovrebbe schiarirsi. Usare il pulsante [Annulla] per uscire dalla funzione senza alterare l'immagine. Premere il pulsante della barra [Galleria] per mostrare tutte i file immagine nella stessa cartella come una schiera di -miniature. Ci pu essere lento, perch le -miniature devono essere create, ma sar pi veloce la -volta successiva che si aprir la stessa cartella. Cliccare su +miniature. Ciò può essere lento, perché le +miniature devono essere create, ma sarà più veloce la +volta successiva che si aprirà la stessa cartella. Cliccare su una miniatura per mostrare l'immagine in dimensione reale. Se tutto questo funziona bene, allora Fotoxx sta funzionando normalmente.
        -
        + Iniziazione
        Fotoxx deve sapere dove si trovano le vostre immagini (cartelle e nomi file), e le informazioni al loro interno (se presenti): etichette, commenti, punteggi, date. Fotoxx ha bisogno anche di creare le miniature -cos che la galleria (pagine di miniature) possa funzionare -velocemente. Dovreste eseguire la funzione del men Strumenti->Sincronizza file prima di eseguire qualsiasi lavoro significativo. -Dopo eseguita questa funzione, la galleria funzioner molto -pi velocemente, e la funzione di Ricerca immagini potr +così che la galleria (pagine di miniature) possa funzionare +velocemente. Dovreste eseguire +la funzione del menù Strumenti->Sincronizza file prima di +eseguire qualsiasi lavoro significativo. +Dopo eseguita questa funzione, la galleria funzionerà molto +più velocemente, e la funzione di Ricerca immagini potrà analizzare migliaia di immagini al secondo. Per maggiori dettagli, -riferirsi all'argomento Sincronizza file.
        +riferirsi all'argomento Sincronizza +file.

        Informazioni essenziali per chi odia i manuali corposi:

        -  o  Le funzioni del men hanno l'aiuto contestuale attivato dal tasto F1.
        -  o  Clic sinistro del mouse: ingrandisce l'immagine, centrandola sulla posizione del mouse.
        +  o  Le funzioni del menù +hanno l'aiuto contestuale attivato dal tasto F1.
        + +  o  Clic sinistro del mouse: +ingrandisce l'immagine, centrandola sulla posizione del mouse.
        o  Trascinamento del mouse sull'immagine: fa scorrere l'immagine dentro la finestra.
          o  Clic destro del mouse: ripristina l'immagine in modo che stia dentro la finestra.
          o  Pulsante della Galleria: mostra miniature di tutte le immagini nella cartella corrente.
        o  Trascinamento del mouse +sull'immagine: fa scorrere l'immagine dentro la finestra.
        -  o  Clic di un'immagine nella Galleria: mostra l'immagine nella finestra principale.
          o  Menu: Strumenti -> Cambia lingua del programma: cambia da Inglese alla vostra lingua.
        +  o  Clic destro del mouse: +ripristina l'immagine in modo che stia dentro la finestra.
        + +  o  Pulsante della Galleria: +mostra miniature di tutte le immagini nella cartella corrente.
        + +  o  Clic di un'immagine nella +Galleria: mostra l'immagine nella finestra principale.
        + +  o  Menu: Strumenti -> Cambia +lingua del programma: cambia da Inglese alla vostra lingua.

        + -Le parole directory e cartella possono essere usate intercambiabilmente.
        +Le parole directory e cartella possono essere usate +intercambiabilmente.

        + Molte finestre di dialogo hanno una casella "Abilita mouse". Se spuntata, le operazioni con il mouse riguardano la funzione corrente -(della finestra di dialogo); se non spuntata, il mouse varier +(della finestra di dialogo); se non spuntata, il mouse varierà ingrandimento e scorrimento dell'immagine nella finestra principale. Si possono usare alternativamente entrambi i modi.

        + I pulsanti delle finestre di dialogo normalmente funzionano come segue:
        + -Prosegui - chiude il dialogo e continua con la funzione (se articolata o complessa).
        +Prosegui - chiude il dialogo e continua con la funzione (se articolata +o complessa).
        + -Applica - applica le impostazioni del dialogo, lasciandolo aperto.
        Fatto - mantiene le modifiche appena fatte e chiude il dialogo.
        Annulla - elimina l'ultima modifica e chiude il dialogo.
        +Applica - applica le impostazioni del dialogo, lasciandolo aperto.
        + +Fatto - mantiene le modifiche +appena fatte e chiude il dialogo.
        + +Annulla - elimina l'ultima +modifica e chiude il dialogo.

        -Procedure generali di editing
        +Procedure +generali di editing
        -L'immagine nella finestra principale (l'immagine corrente) -pu essere manipolata con le funzioni del men Ritocco, +L'immagine nella finestra +principale (l'immagine corrente) +può essere manipolata con le funzioni del menù Ritocco, Trasforma, Arte, Combina. Queste funzioni modificano l'immagine -corrente (solo in memoria); si possono usare pi volte in +corrente (solo in memoria); si possono usare più volte in qualsiasi ordine, e i loro effetti vengono accumulati e mostrati nella finestra principale. I pulsanti [Annulla] e [Ripeti] della barra principale possono essere usati per vedere i risultati "prima e dopo" delle ultime 99 modifiche. Essi possono essere usati pure per vedere gli stessi risultati "prima e dopo" mentre una funzione di modifica - in corso. Dopo aver modificato un'immagine, usare [Salva] o +è in corso. Dopo aver modificato un'immagine, usare [Salva] o [Salva nuovo...] per memorizzare l'immagine su disco (rispettivamente con sostituzione del vecchio file o creazione di uno nuovo).
        -
        Molte finestre di dialogo hanno +
        + +Molte finestre di dialogo hanno cursori, regolazioni o curve modificabili che aggiornano l'immagine nella finestra principale. Il tempo di reazione dipende dalle -dimensioni dell'immagine, la complessit della funzione e la -velocit del computer; di solito questo tempo inferiore -a un secondo, usando un computer con due processori a 2GHz o pi.
        +dimensioni dell'immagine, la complessità della funzione e la +velocità del computer; di solito questo tempo è inferiore +a un secondo, usando un computer con due processori a 2GHz o più.
        +
        -Modifica di curve:
        +Modifica di +curve:

        Molte funzioni usano curve modificabili. Si possono manipolare tali curve per cambiare alcune -propriet dell'immagine (es. la saturazione del colore) in -dipendenza di qualche altra propriet (es. la -luminosit). Come esempio, si potrebbe aumentare la saturazione +proprietà dell'immagine (es. la saturazione del colore) in +dipendenza di qualche altra proprietà (es. la +luminosità). Come esempio, si potrebbe aumentare la saturazione nelle aree scure di un'immagine senza toccare le aree chiare. In genere, l'asse X della curva (direzione da sinistra a destra) -rappresenta la propriet "d'ingresso" (luminosit +rappresenta la proprietà "d'ingresso" (luminosità nell'esempio precedente), e l'asse Y (dal basso verso l'alto) la -propriet che viene modificata (saturazione, nell'esempio di +proprietà che viene modificata (saturazione, nell'esempio di prima). Le curve possono essere trascinate con il mouse: verso l'alto per aumentare l'effetto della funzione, e verso il basso per diminuirne -l'effetto. Un punto di ancoraggio (quadratino nero) verr +l'effetto. Un punto di ancoraggio (quadratino nero) verrà aggiunto alla curva nella posizione in cui la si sta trascinando, e la -curva passer sempre attraverso il quadratino appena immesso, +curva passerà sempre attraverso il quadratino appena immesso, anche questa viene modificata in altri tratti. Anche i punti di -ancoraggio possono essere trascinati, e si pu eliminarli con un +ancoraggio possono essere trascinati, e si può eliminarli con un clic destro del mouse sopra di essi. Le finestre contenenti curve modificabili contengono anche i pulsanti [Carica da un file] e [Salva in un file], che permettono di memorizzare le curve in un file e -riutilizzarle in seguito. Questo pu far risparmiare il tempo -necessario a modificare una curva quando pi immagini devono +riutilizzarle in seguito. Questo può far risparmiare il tempo +necessario a modificare una curva quando più immagini devono ricevere lo stesso trattamento.
        -
        Procedura semplice
        +
        +
        Procedura +semplice
        Quasi sempre si possono -modificare le immagini JPEG cos come prodotte dalla macchina -fotografica. Si pu usare la procedura descritta qui sotto, -pi complessa, nel caso che si producano bande colorate dopo +modificare le immagini JPEG così come prodotte dalla macchina +fotografica. Si può usare la procedura descritta qui sotto, +più complessa, nel caso che si producano bande colorate dopo aver ritoccato la fotografia.

        Procedura complessa
        Convertire l'immagine RAW della macchina in formato TIFF, producendo un'immagine con 16 bit per -colore. La grande profondit (precisione) di colore riduce il +colore. La grande profondità (precisione) di colore riduce il rischio di creare bande colorate da parte di quelle funzioni che -possono spostare pesantemente la distribuzione della luminosit -(specialmente normalizzazione e mappatura di tonalit). Quando -terminato, convertire il TIFF risultante in JPEG, con qualit 70 -o pi, per ridurre la dimensione del file (tipicamente da 50 Mib -a 2 Mib). Difficilmente sar visibile qualche differenza tra il +possono spostare pesantemente la distribuzione della luminosità +(specialmente normalizzazione e mappatura di tonalità). Quando +terminato, convertire il TIFF risultante in JPEG, con qualità 70 +o più, per ridurre la dimensione del file (tipicamente da 50 Mib +a 2 Mib). Difficilmente sarà visibile qualche differenza tra il TIFF elaborato e il JPEG risultante. Per preservare la -possibilit di ritoccare nuovamente l'immagine in futuro, -conviene tenere il file RAW, che molto pi piccolo del +possibilità di ritoccare nuovamente l'immagine in futuro, +conviene tenere il file RAW, che è molto più piccolo del TIFF.
        +

        - Selezione di immagini da una Galleria di miniature

        - Questa procedura si usa in diverse funzioni che usano o ritoccano file multipli (creazione di una collezione, aggiunta/rimozione in blocco di etichette, ridimensionamento in blocco e simili). -Viene spiegata una volta sola qui, ma questo paragrafo +Viene spiegata una volta sola qui, ma questo paragrafo è collegato (raggiungibile) da ogni funzione che usa questa procedura.
        -
        Quando +
        + +Quando la procedura parte, appare una lista vuota per le immagini selezionate. Dietro la lista si trova la galleria che permette selezioni multiple. Per selezionare un'immagine, cliccarne la miniatura, e il file relativo -verr aggiunto alla lista. Si pu navigare nella galleria +verrà aggiunto alla lista. Si può navigare nella galleria verso altre cartelle e selezionare immagini in qualsiasi ordine. La -lista dei file pu essere manipolata anch'essa per variarne +lista dei file può essere manipolata anch'essa per variarne l'ordine o togliere le immagini inserite per sbaglio: cliccare un elemento della lista per mostrarne la miniatura e segnare, contemporaneamente, la posizione corrente di inserimento di nuovi -elementi. L'immagine successiva che verr aggiunta finir +elementi. L'immagine successiva che verrà aggiunta finirà in questa posizione. Premendo [Elimina], l'elemento corrente -verr tolto; premendo [Inserisci], l'ultimo elemento tolto -verr reimmesso nella posizione indicata. Quindi, per spostare +verrà tolto; premendo [Inserisci], l'ultimo elemento tolto +verrà reimmesso nella posizione indicata. Quindi, per spostare un'immagine in una nuova posizione: cliccare l'elemento (la sua -miniatura verr mostrata); premere [Elimina]; cliccare su una -nuova posizione e premere [Inserisci] (l'elemento tolto sar -reinserito prima della posizione selezionata). La lista pu +miniatura verrà mostrata); premere [Elimina]; cliccare su una +nuova posizione e premere [Inserisci] (l'elemento tolto sarà +reinserito prima della posizione selezionata). La lista può essere manipolata direttamente tramite "taglia e incolla" per ottenere l'ordine desiderato, ma fare attenzione a tagliare e incollare solo intere linee di testo (che sono nomi di file). Il pulsante [Aggiungi tutti] aggiunge tutte le immagini presenti in quel momento nella galleria. Dopo una ricerca immagini, per esempio, la galleria -conterr i risultati della ricerca: si possono aggiungere le +conterrà i risultati della ricerca: si possono aggiungere le immagini volute una per volta, oppure usare [Aggiungi tutti] e poi eliminare le immagini non volute.

        -
        Men e barra dei pulsanti di Fotoxx
        +
        + + +Menù e barra dei pulsanti di Fotoxx

        - - + + - + + - - - - - - - - - - - - - - + - - + + - - - + + + - - + + - - - + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - + - + - + +
        Men File
        -
        Menù +File
        +
        Gestione di file
        -
        -
        Galleria immagini
        -
        -
        Mostra la galleria di miniature corrispondenti alla directory corrente (dettagli).
        -
        -
        Mostra la +galleria di miniature corrispondenti alla directory corrente (dettagli).
        +
        Apri un'immagine
        -
        -
        Dialogo di apertura file: carica un'immagine da vedere o modificare (dettagli).
        -
        -
        Apri l'immagine precedente
        -
        -
        Torna all'ultimo file utilizzato (prima di quello corrente) (dettagli).
        -
        -
        Apri un file recente
        -
        -
        Sceglie da una lista delle immagini usate pi di recente (dettagli).
        -
        -
        Salva (sovrascrivi)
        -
        -
        Salva l'immagine corrente (modificata) nello stesso file originario (sovrascrivendolo) (dettagli).
        -
        +
        Clona (50/50)
        Apre un'ulteriore istanza di fotoxx: le due finestre sono grandi metà dello schermo
        +
        Salva nuovo...
        -
        -
        Salva l'immagine in un file nuovo (dettagli).
        -
        -
        Clona (sovrapposta)
        +
        Apre un'ulteriore istanza, sovrapponendola alla finestra originaria
        +
        Crea immagine vuota
        -
        -
        Crea un nuovo file di immagine (dettagli).
        -
        -
        Apri un'immagine
        +
        Dialogo di +apertura file: carica un'immagine da vedere o modificare (dettagli).
        +
        Cestina l'immagine
        -
        -
        Sposta un file immagine nel cestino (dettagli).Apri in nuova finestra
        +
        Apre un'immagine, ma usando un'ulteriore finestra
        +
        Rinomina l'immagine
        -
        -
        Cambia nome, opzionalmente usando un numero di sequenza (dettagli).
        -
        -
        Apri l'immagine +precedente
        +
        Torna all'ultimo +file utilizzato (prima di quello corrente) (dettagli).
        +
        Apri un file +recente
        +
        Sceglie da una +lista delle immagini usate più di recente (dettagli).
        +
        Salva +(sovrascrivi)
        +
        Salva l'immagine +corrente (modificata) nello stesso file originario (sovrascrivendolo) (dettagli).
        +
        Rinomina pi immagini
        -
        -
        Rinomina pi immagini usando una radice e un numero incrementale (dettagli).
        -
        -
        Salva nuovo...
        +
        Salva l'immagine +in un file nuovo (dettagli).
        +
        Crea immagine +vuota
        +
        Crea un nuovo +file di immagine (dettagli).
        +
        Cestina +l'immagine
        +
        Sposta un file +immagine nel cestino (dettagli).
        Rinomina +l'immagine
        +
        Cambia nome, +opzionalmente usando un numero di sequenza (dettagli).
        +
        Rinomina +più immagini
        +
        Rinomina +più immagini usando una radice e un numero incrementale (dettagli).
        +
        Crea collezione
        -
        -
        Crea una nuova collezione da immagini esistenti (dettagli).
        -
        -
        Apri collezione
        -
        -
        Apre una collezione di immagini (dettagli).
        -
        -
        Elimina collezione
        -
        -
        Elimina una collezione (dettagli).
        -
        -
        Modifica collezione
        -
        -
        Manipola una collezione: aggiunge, toglie o riordina le sue immagini (dettagli).
        -
        -
        Stampa immagineSeleziona stampante, carta, orientamento, e stampa l'immagine (dettagli).Seleziona +stampante, carta, orientamento, e stampa l'immagine (dettagli).
        Termina Fotoxx
        -
        -
        Esce dal prorgamma Fotoxx.
        -
        -
        Esce dal +progamma Fotoxx.
        +

        - - - - - - - - - + + - - + + - - - - - - + + + + + + + + + + + + + + - + + - - + + - - - - - - - - - + + + + + + + + + + - - - - + + + - - + + - - + + - - + + - - + + + + - - + + - - - - - -
        Men Strumenti
        -
        -
        Funzioni di utilit e di impostazione
        -
        -
        Verifica luminosit schermo
        -
        -
        Mostra delle barre di colore per regolare lo schermo (dettagli).
        -
        -
        Menù Strumenti
        +
        Funzioni di +utilità e di impostazione
        +
        Verifica gamma dello schermo
        -
        -
        Mostra un'immagine speciale per regolare la "gamma" dello schermo (dettagli).
        -
        -
        Gestione collezioniRiorganizza collezioni di foto (dettagli).
        Diagramma della luminosit
        -
        -
        Mostra il grafico della distribuzione di luminosit dell'immagine corrente (dettagli).
        -
        -
        Duplica Fotoxx (nuova finestra)
        -
        -
        Apre una nuova finestra (es. per confrontare due immagini) (dettagli).
        -
        -
        Verifica +luminosità schermo
        +
        Mostra delle +barre di colore per regolare lo schermo (dettagli).
        +
        Verifica gamma +dello schermo
        +
        Mostra +un'immagine speciale per regolare la "gamma" dello schermo (dettagli).
        +
        Diagramma della +luminosità
        +
        Mostra il +grafico della distribuzione di luminosità dell'immagine corrente +(dettagli).
        +
        Duplica Fotoxx +(nuova finestra)
        +
        Apre una nuova +finestra (es. per confrontare due immagini) (dettagli).
        +
        Slideshow
        -
        -
        Mostra diverse immagini a schermo pieno (senza men e barre) (dettagli).
        -
        -
        Mostra diverse +immagini a schermo pieno (senza menù e barre) (dettagli).
        +
        Esplora i colori RGB dei pixel
        -
        -
        Mostra i valori RGB alle posizioni cliccate (dettagli).
        -
        -
        Esplora i colori +RGB dei pixel
        +
        Mostra i valori +RGB alle posizioni cliccate (dettagli).
        +
        Linee griglia
        -
        -
        Mostra/nasconde linee di griglia di riferimento (per Svolgi/Ruota) (dettagli).
        -
        -
        Parametri dell'obbiettivo
        -
        -
        Modifica i parametri delle macchine e degli obbiettivi (dettagli).
        -
        -
        Cambia lingua del programma
        -
        -
        Cambia la lingua utilizzata dal programma (dettagli).
        -
        -
        Mostra/nasconde +linee di griglia di riferimento (per Svolgi/Ruota) (dettagli).
        +
        Parametri +dell'obbiettivo
        +
        Modifica i +parametri delle macchine e degli obbiettivi (dettagli).
        +
        Cambia lingua +del programma
        +
        Cambia la lingua +utilizzata dal programma (dettagli).
        +
        Edit Translations
        Permette di eseguire la traduzione della lingua interattivamente (dettagli).
        +
        Permette di eseguire la +traduzione della lingua interattivamente (dettagli).
        Crea men e lanciatore
        -
        -
        Crea una voce per il men del desktop e un'icona sul desktop (scrivania) (dettagli).
        -
        -
        Crea menù +e lanciatore
        +
        Crea una voce +per il menù del desktop e un'icona sul desktop (scrivania) (dettagli).
        +
        Conversione di pi immagini RAW
        -
        -
        Converte una o pi immagini da RAW a TIFF (dettagli).
        -
        -
        Conversione di +più immagini RAW
        +
        Converte una o +più immagini da RAW a TIFF (dettagli).
        +
        Masterizza immagini su CD/DVD
        -
        -
        Seleziona pi immagini e le scrive su un CD o DVD (dettagli).
        -
        -
        Masterizza +immagini su CD/DVD
        +
        Seleziona +più immagini e le scrive su un CD o DVD (dettagli).
        +
        Spedire immagini via e-mail
        -
        -
        Seleziona immagini, le ridimensiona, e le invia al programma di posta (dettagli).
        -
        -
        Spedire immagini +via e-mail
        +
        Seleziona +immagini, le ridimensiona, e le invia al programma di posta (dettagli).
        +
        Sincronizza file
        -
        -
        Ricostruisce miniature e indici (per la ricerca) delle immagini  (dettagli).
        -
        -
        Ricostruisce +miniature e indici (per la ricerca) delle immagini  (dettagli).
        +
        Toolbar Style
        Imposta il tipo di barra degli strumenti (Solo testo, solo icone, o entrambi)
        +
        Imposta il tipo di barra +degli strumenti (Solo testo, solo icone, o entrambi)
        Mostra uso memoria (in console)
        Mostra, nel terminale usato per lanciare Fotoxx, un sommario sull'uso della RAM
        +
        Mostra, nel terminale usato per lanciare +Fotoxx, un sommario sull'uso della RAM

        - - - - - - - + + + - + + - + + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - + + - - - + + + - - + + - - + + - - + + -
        Men Info
        -
        -
        Mostra e modifica i dati delle immagini e i loro attributi
        -
        -
        Menù Info
        +
        Mostra e +modifica i dati delle immagini e i loro attributi
        +
        Modifica commenti
        -
        -
        Add or change descriptive text for an image (dettagli).
        -
        -
        Add or change +descriptive text for an image (dettagli).
        +
        Modifica titolo
        -
        -
        Add or change an image caption (dettagli).
        -
        -
        Add or change an +image caption (dettagli).
        +
        (Introduzione)
        -
        -
        Spiegazione delle etichette e come vengono utilizzate (dettagli).
        -
        -
        Modifica etichette
        -
        -
        Aggiunge/modifica etichette, parole chiave, punteggio e data (dettagli).
        Gestione etichette
        -
        -
        Crea etichette e categorie di etichette (dettagli).
        -
        -
        Aggiungi etichette a pi immagini
        -
        -
        Aggiunge diverse etichette a pi immagini contemporaneamente (dettagli).
        Cancellazione in blocco di etichette
        -
        -
        Elimina o modifica una etichetta per pi immagini insieme (dettagli). Spiegazione +delle etichette e come vengono utilizzate (dettagli).
        +
        Modifica +etichette
        +
        Aggiunge/modifica +etichette, parole chiave, punteggio e data (dettagli).
        Gestione +etichette
        +
        Crea etichette e +categorie di etichette (dettagli).
        +
        Aggiungi +etichette a più immagini
        +
        Aggiunge diverse +etichette a più immagini contemporaneamente (dettagli).
        Cancellazione in +blocco di etichette
        +
        Elimina o +modifica una etichetta per più immagini insieme (dettagli).
        Ricerca immagini
        -
        -
        Cerca immagini con etichette/punteggio/data/commenti/titolo desiderati (dettagli). Cerca immagini +con etichette/punteggio/data/commenti/titolo desiderati (dettagli).
        Vedere informazioni (breve)
        -
        -
        Visualizza le informazioni basilari dell'immagine (dettagli).
        Vedere +informazioni (breve)
        +
        Visualizza le +informazioni basilari dell'immagine (dettagli).
        Vedere informazioni (lungo)
        -
        -
        Mostra tutte le informazioni disponibili sull'immagine (dettagli).Vedere +informazioni (lungo)
        +
        Mostra tutte le +informazioni disponibili sull'immagine (dettagli).
        Modifica informazioni
        -
        -
        Aggiunge o modifica i dati di una chiave (o campo) specifica (dettagli).Modifica +informazioni
        +
        Aggiunge o +modifica i dati di una chiave (o campo) specifica (dettagli).
        Elimina informazioni
        -
        -
        Elimina una chiave specifica o tutte le informazioni (dettagli).Elimina +informazioni
        +
        Elimina una +chiave specifica o tutte le informazioni (dettagli).

        - - - - - + + - + + - + + - + + - - + + + + + + - + + + + + + - - - - - - - + + + + + + - -
        Men Seleziona
        -
        -
        Seleziona aree dell'immagine dove confinare le operazioni di modifica
        -
        -
        Menù Seleziona
        +
        Seleziona aree +dell'immagine dove confinare le operazioni di modifica
        +
        (Introduzione)
        -
        -
        Spiegazione su selezione e modifica di aree (dettagli).
        -
        -
        Spiegazione su +selezione e modifica di aree (dettagli).
        +
        Seleziona
        -
        -
        Seleziona un'area per le successive funzioni di editing (dettagli). Seleziona +un'area per le successive funzioni di editing (dettagli).
        Mostra / Nascondi
        -
        -
        Mostra o nasconde il perimetro dell'area (dettagli).
        -
        -
        Mostra o +nasconde il perimetro dell'area (dettagli).
        +
        Abilita / Disabilita
        -
        -
        Attiva o disattiva il confinamento nell'area per le successive operazioni (dettagli).
        -
        -
        Abilita / +Disabilita
        +
        Attiva o +disattiva il confinamento nell'area per le successive operazioni (dettagli).
        +
        Inverti
        -
        -
        Inverte un'area (dettagli).
        -
        -
        Cancella
        -
        -
        Elimina un'area (dettagli).
        -
        -
        Copia / Incolla
        -
        -
        Copia un'area in memoria e la incolla (utilizza) in qualche altro punto (dettagli).
        -
        -
        Copia un'area in +memoria e la incolla (utilizza) in qualche altro punto (dettagli).
        +
        Carica / Salva +file
        +
        Salva un'area in +un file / la ricarica per usarla su altre immagini (o sulla stessa) (dettagli).
        +
        Carica / Salva file
        -
        -
        Salva un'area in un file / la ricarica per usarla su altre immagini (o sulla stessa) (dettagli).
        -
        -
        Immagine intera
        -
        -
        Seleziona l'intera immagine come maschera per le manipolazioni successive (dettagli).
        -
        -
        Seleziona a modifica
        -
        -
        Usare il mouse sopra l'immagine per fare modifiche incrementali (dettagli).
        -
        -
        Seleziona +l'intera immagine come maschera per le manipolazioni successive (dettagli).
        +
        Seleziona a +modifica
        +
        Usare il mouse +sopra l'immagine per fare modifiche incrementali (dettagli).
        +

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - + + - - - - - - - + + - -
        Men Ritocco
        -
        -
        Funzioni che cambiano alcune propriet dell'iimagine
        -
        -
        Bilanciamento del bianco
        -
        -
        Rimuove la sfasatura di colore (dettagli).
        -
        -
        Trasforma in negativo
        -
        -
        Produce il negativo (bianco e nero o a colori), o il positivo (da un negativo) (dettagli).
        -
        -
        Normalizza la luminosit
        -
        -
        Appiattisce la luminosit per migliorare i dettagli (dettagli).
        -
        -
        Luminosit e colore
        -
        -
        Modifica luminosit, contrasto, saturazione e bilanciamento dei colori (dettagli).
        -
        -
        Mappatura della luce
        -
        -
        Variazione della luminosit in senso orizzontale e verticale (dettagli).
        -
        -
        Espandi luminosit
        -
        -
        Taglia le luminosit estreme ed espande le altre (dettagli).
        -
        -
        Mappa tonalit
        -
        -
        Aumenta il contrasto locale per migliorare i dettagli (dettagli).
        -
        -
        Correzione occhi rossi
        -
        Rimuove gli "occhi rossi" dalle fotografie fatte col flash (dettagli).Menù Ritocco
        +
        Funzioni che +cambiano alcune proprietà dell'iimagine
        +
        Bilanciamento +del bianco
        +
        Rimuove la +sfasatura di colore (dettagli).
        +
        Trasforma in +negativo
        +
        Produce il +negativo (bianco e nero o a colori), o il positivo (da un negativo) (dettagli).
        +
        Normalizza la +luminosità
        +
        Appiattisce la +luminosità per migliorare i dettagli (dettagli).
        +
        Luminosità +e colore
        +
        Modifica +luminosità, contrasto, saturazione e bilanciamento dei colori (dettagli).
        +
        Mappatura della +luce
        +
        Variazione della +luminosità in senso orizzontale e verticale (dettagli).
        +
        Espandi +luminosità
        +
        Taglia le +luminosità estreme ed espande le altre (dettagli).
        +
        Mappa +tonalità
        +
        Aumenta il +contrasto locale per migliorare i dettagli (dettagli).
        +
        Correzione occhi +rossi
        +
        Rimuove gli +"occhi rossi" dalle fotografie fatte col flash (dettagli).
        Sfocatura +immagine
        +
        Sfuoca +l'immagine (es. liscia la pelle) (dettagli).
        +
        Contrasta +immagine
        +
        Acutizza +un'immagine sfuocata +(dettagli).
        +
        Sfocatura immagine
        -
        -
        Sfuoca l'immagine (es. liscia la pelle) (dettagli).
        -
        -
        Riduci disturbo
        +
        Riduce il rumore +(puntini/pallini) in immagini con luce scarsa (dettagli).
        +
        Contrasta immagine
        -
        -
        Acutizza un'immagine sfuocata -(dettagli).
        -
        -
        Cancellazione +intelligente
        +
        Rimuove pieghe e +altri disturbi sostituendoli con particolari adiacenti (dettagli).
        +
        Riduci disturbo
        -
        -
        Riduce il rumore (puntini/pallini) in immagini con luce scarsa (dettagli).
        -
        -
        Cancellazione intelligente
        -
        -
        Rimuove pieghe e altri disturbi sostituendoli con particolari adiacenti (dettagli).
        -
        -
        Rimozione polvere
        -
        -
        Rimuove macchioline da immagini acquisite tramite scanner (dettagli).
        -
        -
        Rimuove +macchioline da immagini acquisite tramite scanner (dettagli).
        +

        - - - - - + + - + + - - + + - - + + + + + + - - + + - + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + +
        Men Trasforma
        -
        Funzioni che cambiano dimensione, forma o contenuti di un'immagine
        -
        -
        Menù Trasforma
        +
        Funzioni che +cambiano dimensione, forma o contenuti di un'immagine
        +
        Ritaglia immagine
        -
        Ritaglia una porzione rettangolare dell'immagine (dettagli).Ritaglia una +porzione rettangolare dell'immagine (dettagli).
        Ridimensiona immagine
        -
        -
        Riscala un'immagine (con pi o meno pixel) + Ridimensiona +immagine
        +
        Riscala +un'immagine (con più o meno pixel) (dettagli).
        -
        -
        Ridimensiona/esporta in blocco
        -
        -
        Riscala molte immagini (per pubblicazione su web, email ecc.) (dettagli).
        -
        -
        Ritaglia automaticamenteSceglie margini automatici dopo ruota, raddrizza o deforma (dettagli).
        Ridimensiona/esporta +in blocco
        +
        Riscala molte +immagini (per pubblicazione su web, email ecc.) (dettagli).
        +
        Testo sulll'immagine
        -
        -
        Imprime testi/annotazioni sull'immagine (dettagli).
        -
        -
        Testo +sulll'immagine
        +
        Imprime +testi/annotazioni sull'immagine (dettagli).
        +
        Ruota immagine
        -
        -
        Ruota l'immagine con diversi passi di rotazione (non solo 90) (dettagli).
        -
        -
        Ruota l'immagine +con diversi passi di rotazione (non solo 90°) (dettagli).
        +
        Rifletti immagine
        -
        -
        Riflette l'immagine in orizzontale o in verticale (dettagli).
        -
        -
        Svolgi (raddrizza deformazioni obbiettivo)
        -
        Corregge problemi di prospettiva (dettagli).
        Deforma immagine (area)
        -
        -
        Distorce un'area trascinando con il mouse (dettagli).
        -
        -
        Deforma immagine (curve)
        -
        -
        Distorce l'intera immagine trascinando con il mouse (dettagli).
        -
        -
        Deforma immagine (lineare)
        -
        -
        Distorce l'intera immagine trascinando con il mouse (dettagli).
        Deforma immagine (speculare)
        -
        -
        Come sopra, in modo simmetrico (dettagli).
        -
        -
        Riflette +l'immagine in orizzontale o in verticale (dettagli).
        +
        Svolgi +(raddrizza deformazioni obbiettivo)
        +
        Corregge +problemi di prospettiva (dettagli).
        Deforma immagine +(area)
        +
        Distorce un'area +trascinando con il mouse (dettagli).
        +
        Deforma +immagine (curve)
        +
        Distorce +l'intera immagine trascinando con il mouse (dettagli).
        +
        Deforma immagine + (lineare)
        +
        Distorce +l'intera immagine trascinando con il mouse (dettagli).
        Deforma immagine + (speculare)
        +
        Come sopra, in +modo simmetrico (dettagli).
        +

        - - - - - + + - - + + - + + - + + - + - + + - + + - + + - + - + + - + +
        Men Arte
        -
        Funzioni che effettuano trasformazioni artistiche
        -
        -
        Menù Arte
        +
        Funzioni che +effettuano trasformazioni artistiche
        +
        Profondit di colore
        -
        -
        Riduce la profondit di colore (come un poster) (dettagli).
        -
        -
        Profondità +di colore
        +
        Riduce la +profondità di colore (come un poster) (dettagli).
        +
        Disegno
        -
        -
        Trasforma una foto in un disegno simulato a matita o gessetto (dettagli).
        -
        -
        Trasforma una +foto in un disegno simulato a matita o gessetto (dettagli).
        +
        Contorni
        -
        -
        Trasforma una foto in un disegno di linee colorate (dettagli).
        -
        -
        Trasforma una +foto in un disegno di linee colorate (dettagli).
        +
        Bassorilievo
        -
        -
        Trasforma una foto in un bassorilievo simulato (dettagli).
        -
        -
        Trasforma una +foto in un bassorilievo simulato (dettagli).
        +
        Mosaico
        -
        -
        Trasforma una foto in un mosaico di tessere (dettagli).
        -
        -
        Trasforma una +foto in un mosaico di tessere (dettagli).
        +
        Puntinismo
        -
        -
        Trasforma una foto in un insieme di molti puntini (dettagli).
        -
        -
        Trasforma una +foto in un insieme di molti puntini (dettagli).
        +
        Pittura
        -
        -
        Trasforma una foto in un disegno a olio (dettagli).
        -
        -
        Trasforma una +foto in un disegno a olio (dettagli).
        +
        Modifca dei pixel
        -
        -
        Modifica dei pixel e disegno di linee o aree con il mouse (dettagli).
        -
        -
        Modifica dei +pixel e disegno di linee o aree con il mouse (dettagli).
        +

        - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + -
        Men CombinaFunzioni che combinano/uniscono pi immagini in una
        -
        -
        Combina immagini (alta dinamica - HDR)
        -
        -
        Crea un'immagine con alta dinamica miscelando altre immagini (dettagli).
        -
        -
        Combina immagini (grande profondit - HDF)
        -
        -
        Crea un'immagine con grande profondit miscelandone altre (dettagli).
        -
        -
        Sovrapponi (interattivo con mouse)
        -
        -
        Miscela pi immagini per rimuovere elementi come turisti o veicoli (dettagli).
        -
        -
        Sovrapponi (rimozione disturbo)
        -
        -
        Miscela pi immagini per ridurre i disturbi (dettagli).
        -
        -
        Crea un panorama / Panorama verticale - Affianca 2..4 foto + Menù CombinaFunzioni che +combinano/uniscono più immagini in una
        +
        Combina immagini +(alta dinamica - HDR)
        +
        Crea un'immagine +con alta dinamica miscelando altre immagini (dettagli). +
        +
        Combina immagini +(grande profondità - HDF)
        +
        Crea un'immagine +con grande profondità miscelandone altre (dettagli).
        +
        Sovrapponi +(interattivo con mouse)
        +
        Miscela +più immagini per rimuovere elementi come turisti o veicoli (dettagli).
        +
        Sovrapponi +(rimozione disturbo)
        +
        Miscela +più immagini per ridurre i disturbi (dettagli).
        +
        Crea un panorama +/ Panorama verticale Affianca 2..4 +foto per produrne una larga o alta (dettagli).
        -
        -
         
        + + + 
        + - - + + -
        Men Plugins
        -
        -
        Altri programmi di fotoritocco possono essere usati come funzioni di manipolazione in Fotoxx (dettagli).
        -
        -
        Menù Plugins
        +
        Altri +programmi di fotoritocco possono essere usati come funzioni di +manipolazione in Fotoxx (dettagli).
        +

        -
        - - + + 
        +
        - - + + -
        Men Aiuto
        -
        Guida utente, file README, change log (dettagli).
        -
        -
        Menù Aiuto
        +
        Guida utente, +file README, change log (dettagli).
        +
           + +  
        - - - - + + - + + - - + + - + + - - - + + - - + + - + + - + + - + + - + - + + - + + -
        Pulsanti della barra
        -
        -
        Pulsanti +della barra
        +

        -
        -
        Miniature
        -
        -
        Mostra la galleria di miniature delle immagini nella cartella (directory) corrente (dettagli). Mostra la +galleria di miniature delle immagini nella cartella (directory) +corrente (dettagli).
        Carica da file
        -
        -
        Richiama un dialogo di selezione file per aprire o vedere un'immagine da disco (dettagli).
        -
        -
        Carica da file
        +
        Richiama un +dialogo di selezione file per aprire o vedere un'immagine da disco (dettagli).
        +
        Prec / Prossima
        -
        -
        Carica l'immagine precedente/successiva dalla directory corrente o del risultato della ricerca.
        -
        -
        Carica +l'immagine precedente/successiva dalla directory corrente o del risultato della ricerca.
        +
        Salva / Salva come
        -
        -
        Salva l'immagine corrente sullo stesso file (sovrascrivi) o un file nuovo (dettagli).
        -
        -
        Salva / Salva +come
        +
        Salva l'immagine +corrente sullo stesso file (sovrascrivi) o un file nuovo (dettagli).
        +
        Annulla
        -
        -
        Annulla l'effetto dell'ultima manipolazione eseguita. Annulla +l'effetto dell'ultima manipolazione eseguita.
        Ripeti
        -
        -
        Annulla l'ultimo annullamento. La memoria per gli annullamenti ha 99 passi. Annulla l'ultimo +annullamento. La memoria per gli annullamenti ha 99 passi.
        Zoom+
        -
        -
        Ingrandisce l'immagine. Anche un clic sinistro sull'immagine ha lo stesso effetto.
        -
        -
        Ingrandisce +l'immagine. Anche un clic sinistro sull'immagine ha lo stesso effetto.
        +
        Zoom-
        -
        -
        Riduce l'immagine fino ad adattarla alla finestra. Un clic destro ha lo stesso effetto.
        -
        -
        Riduce +l'immagine fino ad adattarla alla finestra. Un clic destro ha lo stesso +effetto.
        +
        CestinaCestina (sposta nel cestino) il file corrispondente all'immagine corrente (dettagli).Cestina (sposta +nel cestino) il file corrispondente all'immagine corrente (dettagli).
        Uscita
        -
        -
        Esce dal programma.
        -
        -
        Esce dal +programma.
        +
        Aiuto
        -
        -
        Mostra la guida utente (questo documento) (dettagli).
        -
        -
        Mostra la guida +utente (questo documento) (dettagli).
        +
         
        + +  
        + + - + + + - - + + - + + - + + - + + - + + - + + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + + - + + - - + + + + - - + +
        Scorciatoie da tastiera
        -
        -

        -
        -
        Finestra principale
        -
        -

        -
        -
        Frecce sinistra e destra
        -
        -
        Immagine precedente e prossima
        -
        -
        Frecce sinistra +e destra
        +
        Immagine +precedente e prossima
        +
        Tasti "+" e "-"
        -
        -
        Zoom pi o meno
        -
        -
        Zoom più +o meno
        +
        Tasto "Z"
        -
        -
        Ingrandimento ottimale (immagine completa nella finestra)
        -
        -
        Ingrandimento +ottimale (immagine completa nella finestra)
        +
        Tasti "R" / "L"
        -
        -
        Rotazione di 90 a destra o sinistra
        -
        -
        Rotazione di +90° a destra o sinistra
        +
        Tasto "G"
        -
        -
        Mostra o nasconde la griglia
        -
        -
        Mostra o +nasconde la griglia
        +
        Tasto "T"
        -
        -
        Richiama la funzione Trasforma -> Ritaglia immagine
        -
        -
        Richiama la +funzione Trasforma -> Ritaglia immagine
        +
        Tasto "B"
        -
        -
        Richiama la funzione Ritocco -> Luminosit e colore
        -
        -
        Tasto "Del" o "Canc"
        -
        -
        Cestina l'immagine
        -
        -
        Tasto "Esc" (Escape)
        -
        -
        Termina lo slide show
        -
        -
        Control + "s" (minuscolo)
        -
        -
        Salva l'immagine (riscrittura - senza chiedere conferma)
        -
        -
        Control + "S" (maiuscolo)
        -
        -
        Salva con nome (richiama un dialogo per inserire il nome)
        -
        -
        Control + "q" o Control + "Q"
        -
        -
        Richiama la +funzione Ritocco -> Luminosità e colore
        +
        Tasto "Del" o +"Canc"
        +
        Cestina +l'immagine
        +
        Tasto "Esc" +(Escape)
        +
        Termina lo slide +show
        +
        Control + "s" +(minuscolo)
        +
        Salva l'immagine +(riscrittura - senza chiedere conferma)
        +
        Control + "S" +(maiuscolo)
        +
        Salva con nome +(richiama un dialogo per inserire il nome)
        +
        Control + "q" o +Control + "Q"
        +
        Uscita da Fotoxx
        -
        -
        Galleria di immagini
        -
        -

        -
        -
        Home / Fine
        -
        -
        Salta alla prima o ultima pagina della galleria
        -
        -
        Pagina Su/Gi (PgSu/PgGi)
        -
        -
        Passa alla pagina precedente/successiva
        -
        -
        Frecce su/gi
        -
        -
        Scorre la galleria una riga per volta
        Frecce sinistra/destra
        -
        -
        Passa alla pagina precedente/successiva Salta alla prima +o ultima pagina della galleria
        +
        Pagina +Su/Giù (PgSu/PgGiù)
        +
        Passa alla +pagina precedente/successiva
        +
        Frecce +su/giù
        +
        Scorre la +galleria una riga per volta
        Frecce +sinistra/destra
        +
        Passa alla +pagina precedente/successiva
        Tasti "+" e "-"
        -
        -
        Dimensione delle miniature maggiore/minore
        -
        -
        Dimensione delle +miniature maggiore/minore
        +
        Tasto "Esc" (Escape)
        -
        -
        Chiude la galleria
        -
        -
        Tasto "Esc" +(Escape)
        +
        Chiude la +galleria
        +
        Dialoghi per l'inserimento di dati
        -
        -
         
        -
        -
        Tasto "F1"  (Tasto funzione F1)
        -
        -
        Mostra l'aiuto (la guida utente) sull'argomento corrente
        -
        -
        Tasto "F1"  +(Tasto funzione F1)
        +
        Mostra l'aiuto +(la guida utente) sull'argomento corrente
        +

        - + + - + - + + - + + - + +
        Funzioni del mouse
        -
        -

        -
        -
        Clic sinistro
        -
        -
        Aumenta l'ingrandimento, centrando l'immagine sulla posizione del clic
        -
        -
        Aumenta +l'ingrandimento, centrando l'immagine sulla posizione del clic
        +
        Clic destro
        -
        -
        Adatta l'ingrandimento alla finestra in modo da vedere tutta l'immagine
        -
        -
        Adatta +l'ingrandimento alla finestra in modo da vedere tutta l'immagine
        +
        Trascinamento sull'immagine
        -
        -
        Fa scorrere l'immagine nella direzione opposta, come le barre di scorrimento
        -
        -
        Fa scorrere l'immagine nella direzione +opposta, come le barre di scorrimento
        +
        @@ -1456,28 +1421,31 @@


        -
        Men File
        +
        +Menù +File

        - Navigazione


        + Usare la funzione del -men File -> Galleria immagini oppure il pulsante [Miniature] +menù File -> Galleria immagini oppure il pulsante [Miniature] per aprire una finestra di miniature dei file d'immagine nella -directory corrente, o l'ultimo risultato della ricerca, o la collezione +directory corrente, o l'ultimo risultato della +ricerca, o la collezione corrente. Usare questa finestra per navigare nelle directory e selezionare file di immagini cliccando sulle miniature. I pulsanti in alto permettono di scorrere avanti e indietro per righe o per pagine. Usare [Cartella superiore] e [Apri un file] per usare altre cartelle/directory. Usare i pulsanti [Aumenta] e [Riduci] per modificare la dimensione delle miniature. Il richiamo di questa -funzione dalla finestra principale mostrer la galleria con +funzione dalla finestra principale mostrerà la galleria con l'immagine corrente nella fila superiore; cliccando una delle miniature -riattiver la finestra principale, che conterr +riattiverà la finestra principale, che conterrà l'immagine appena cliccata. Le due finestre sembrano escludersi a -vicenda, ma in realt ognuna semplicemente davanti +vicenda, ma in realtà ognuna è semplicemente davanti all'altra, ed entrambe possono essere ridimensionate e spostate per vederle insieme, se si desidera.

        @@ -1497,172 +1465,195 @@ Questo comando mostra una finestra di dialogo standard, che permette di selezionare un file o spostarsi in un'altra directory per selezionare. Il file scelto viene -aperto nella finestra principale dove potr essere manipolato -usando il men e i pulsanti. La barra del titolo della finestra +aperto nella finestra principale dove potrà essere manipolato +usando il menù e i pulsanti. La barra del titolo della finestra principale mostra il nome del file e la directory di appartenenza dell'immagine corrente. Il trascinamento di file da altre applicazioni -(es. file manager come Nautilus o Konqueror) anche possibile: -Fotoxx aprir il file trascinato. Se si trascina del testo (per +(es. file manager come Nautilus o Konqueror) è anche possibile: +Fotoxx aprirà il file trascinato. Se si trascina del testo (per esempio il testo selezionato all'interno di un editor di testi), Fotoxx -assumer che il testo indica un nome di file, e prover -ad aprire tale file; quindi possibile creare una lista di nomi -di file e usarla con Fotoxx. Praticamente possibile usare file +assumerà che il testo indica un nome di file, e proverà +ad aprire tale file; quindi è possibile creare una lista di nomi +di file e usarla con Fotoxx. Praticamente è possibile usare file manager o file di testo per navigare un insieme di immagini in modo alternativo al sistema di navigazione interno di Fotoxx. Si aggiunga l'applicazione all'elenco di "Apri con..." del file manager. Se la galleria mostra il risultato di una ricerca o una collezione, e si apre un file che non appartiene all'elenco mostrato in quel momento dalla -galleria, allora la galleria verr ricaricata con le immagini +galleria, allora la galleria verrà ricaricata con le immagini della directory che contiene il file appena aperto; una conferma viene richiesta per dare modo di proseguire o interrompere l'operazione.


        -Apri l'immagine precedente
        +Apri +l'immagine precedente
        Torna all'immagine precedente, -anche se questa appartiene a una directory diversa. Ci +anche se questa appartiene a una directory diversa. Ciò è diverso dal pulsante della barra [Prec.], che carica l'immagine precedente della galleria.
        +

        -Apri file recente
        +Apri file +recente
        -Le ultime 99 immagini usate sono mostrate in una lista, dalla quale se ne pu scegliere una per aprirla.
        +Le ultime 99 immagini usate sono +mostrate in una lista, dalla quale se ne può scegliere una per +aprirla.


        + Salva immagine
        -
        Il men File >
        Salva (sovrascrivi) o il pulsante della barra [Salva] +Il menù [File > Salva (sovrascrivi)] o il pulsante della barra [Salva] eseguono la stessa funzione: salvano l'immagine corrente con lo stesso -nome, riscrivendo quindi file, senza chiedere conferma. Se il file - un JPEG, il fattore di qualit di default, cio -90, viene utilizzato.
        - +nome, riscrivendo quindi il file. Se il file +è un JPEG, il fattore di qualità di default, cioé +90, viene utilizzato. Se il file è originale (senza "versione"), +il programma avvertirà che lo si sta riscrivendo - si può +confermare e proseguire. Si può anche decidere di sopprimere +questo avviso in modo permanente. Se l'avvertimento è stato +disabilitato e lo si vuole riabilitare, occorre editare il file
        /home/<utente>/.fotoxx/parameters e cambiare il valore di "warn overwrite" da 0 a 1.
        +
        +Salva con versione
        +Menù [File > Salva con una nuova versione] o pulsante [Salva+V]
        +Salva l'immagine con un nuovo numero di versione. I nomi di file sono preparati come "nome_del_file.vNN.ext", dove NN è il numero di versione da 01 a 99. I quattro caratteri .vNN +vengono inseriti fra il nome_del_file e l'estensione. Se il file non ha +ancora un numero di versione, viene creata la ".v01". Se esistono +già nomi dello stesso file con un numero di versione, allora +viene usato il numero successivo al più alto. Il programma non +chiede conferme in questa operazione. Se il file è un JPEG, +viene usata la qualità di default: 90.
        +

        + -La funzione del men File > Salva nuovo... o il pulsante [Salva -come] mostrano questo dialogo:
        -
        Questo +La funzione del menù File > +Salva +nuovo... o il pulsante [Salva +come] mostrano questo +dialogo:
        + +
        + +Questo dialogo permette di scegliere un nome di file su cui salvare, che -pu essere il file originale, un altro file esistente, o uno -nuovo. Un'immagine pu essere salvata in tre formati diversi: -JPEG, PNG e TIFF. Il JPEG di solito la scelta migliore, -perch compresso in modo da risparmiare spazio. Si -pu scegliere un fattore di qualit da 1 a 100; valori -bassi producono file piccoli e minore qualit. Valori superiori +può essere il file originale, un altro file esistente, o uno +nuovo. Un'immagine può essere salvata in tre formati diversi: +JPEG, PNG e TIFF. Il JPEG è di solito la scelta migliore, +perché è compresso in modo da risparmiare spazio. Si +può scegliere un fattore di qualità da 1 a 100; valori +bassi producono file piccoli e minore qualità. Valori superiori a 70 danno risultati difficilmente distinguibili da quelli ottenuti con -100 (che indica la migliore qualit e il pi grosso file).
        -I file di tipo PNG vengono compressi senza perdita di qualit, -ma normalmente producono file pi grossi di un equivalente JPEG -a qualit massima.
        -I TIFF non sono compressi, e pi grandi sia dei PNG che dei +100 (che indica la migliore qualità e il più grosso file).
        +I file di tipo PNG vengono compressi senza perdita di qualità, +ma normalmente producono file più grossi di un equivalente JPEG +a qualità massima.
        +I TIFF non sono compressi, e più grandi sia dei PNG che dei JPEG. I TIFF possono essere salvati con 8 o 16 bit per colore. 16 bit per colore hanno senso solo per immagini convertite da un formato RAW -con pi di 8 bit per colore (i RAW prodotti da una macchina +con più di 8 bit per colore (i RAW prodotti da una macchina fotografica hanno solitamente 12 bit, dei quali l'ultimo o gli utimi -due contengono rumore). E' raro che differenze tra 8 bit e pi +due contengono rumore). E' raro che differenze tra 8 bit e più di otto bit per colore possano essere apprezzate a occhio; tuttavia -un'immagine con pi bit ha pi "latitudine" quando viene +un'immagine con più bit ha più "latitudine" quando viene usata da un programma di fotoritocco come Fotoxx (sopporta meglio le manipolazioni).

        -Se la casella "Creare nuova versione" spuntata, allora il nome -di file conterr un numero di versione suffisso: ".v01" se non -esistono altre versioni di questo file, o il prossimo numero pi -alto se una o pi versioni gi esistono. Questo rende +Se la casella "Creare nuova versione" è spuntata, allora il nome +di file conterrà un numero di versione suffisso: ".v01" se non +esistono altre versioni di questo file, o il prossimo numero più +alto se una o più versioni già esistono. Questo rende facile salvare una modifica senza perdere l'originale, o mantenere una -serie di modifiche. L'immagine corrente si riferir al nuovo -file se stato usato [Salva nuovo...] e la directory NON - stata cambiata. Se, invece, nel dialogo si fatto un -cambio di directory, l'immagine corrente continuer a rifersi al -vecchio file. Si pu usare il men [File -> Apri +serie di modifiche. L'immagine corrente si riferirà al nuovo +file se è stato usato [Salva nuovo...] e la directory NON +è stata cambiata. Se, invece, nel dialogo si è fatto un +cambio di directory, l'immagine corrente continuerà a rifersi al +vecchio file. Si può usare il menù [File -> Apri l'immagine precedente] per tornare all'immagine della versione precedente (e quindi all'immagine di prima delle ultime modifiche), se si desidera. Nome file e directory corrente vengono mostrati nella barra del titolo: controllarli sempre in caso di dubbio.

        - -Dimensioni di file indicative per un'immagine a 10 megapixel (dipendono dalla quantit di dettagli):
        + +Dimensioni di file indicative per un'immagine a 10 megapixel (dipendono +dalla quantità di dettagli):
        -
         tiff-16
        -
         tiff-8
        -
         png
        -
         jpeg-100
        -
         jpeg-90
        -
         jpeg-80
        -
         jpeg-70
        -
         58 MB
        -
         19 MB
        -
         14 MB
        -
         7 MB
        -
         2 MB
        -
         1 MB
        -
         0.6 MB
        -

        + + +
        +
        -Crea immagine vuota
        Crea + +Crea immagine +vuota
        + +Crea una nuova immagine, vuota, con le dimensioni e il colore specificato. -Si pu usare come sfondo per incollarci pezzi tratti da altre +Si può usare come sfondo per incollarci pezzi tratti da altre immagini (usando Selezione area) e annotazioni (usando testo sull'immagine).
        -Inserire un nome di file, scegliere un colore per lo sfondo, e impostare la dimensione in pixel.

        +Inserire un nome di file, scegliere un colore per lo sfondo, e +impostare la dimensione in pixel.



        + Cestina immagine
        Fotoxx usa per il cestino il "Linux desktop -standard". Se ci funziona, le immagini cestinate finiscono nel +standard". Se ciò funziona, le immagini cestinate finiscono nel cestino standard e possono essere recuperate. Altrimenti, Fotoxx sposta i file dentro una directory della scrivania nominata "fotoxx-trash". A -sua volta questa directory pu essere eliminata o spostata nel +sua volta questa directory può essere eliminata o spostata nel cestino specifico del tuo computer. Se il cestino standard non funziona, potreste forse provare a correggere il problema: fare riferimento a note tecniche a questo riguardo.
        @@ -1674,14 +1665,15 @@


        + -Questa funzione pu aiutare ad automatizzare il processo di +Questa funzione può aiutare ad automatizzare il processo di rinomina di una serie di immagini usando una base (es. un accadimento o un nome di luogo) e un numero di sequenza. Va bene per rinominare una serie di immagini prelevate da una macchina fotografica. Aprire il primo file della serie, immettere un nuovo nome, e premere [Rinominare in]. Il prossimo file viene quindi caricato. A questo punto si -pu usare lo stesso nome premendo il tasto [Prec.] e poi +può usare lo stesso nome premendo il tasto [Prec.] e poi aggiungendo un numero di sequenza. Se si usano numeri di sequenza, premere [+1] dopo [Prec.] per aggiungere la sequenza successiva al nome di base.
        @@ -1690,182 +1682,157 @@
        -Rinomina pi immagini
        +Rinomina +più immagini
        -Questa funzione utile +Questa funzione è utile se si vogliono rinominare in blocco molte immagini (probabilmente con la stessa data o riferite allo stesso evento), per dargli lo stesso nome e un numero di sequenza diverso. Nel dialogo, specificare una radice (nome), un numero di sequenza iniziale, e un incremento. Per esempio, usare una radice come "crociera artica-", un numero iniziale -di 100 e un incremento di 1 produrr una serie di file nominati -cos: "crociera artica-100", "crociera artica-101", "crociera artica-102" eccetera (le estensioni .JPG, .TIF e simili non verranno modificate). Usare +di 100 e un incremento di 1 produrrà una serie di file nominati +così: "crociera +artica-100", "crociera +artica-101", "crociera +artica-102" eccetera (le estensioni .JPG, .TIF e simili non verranno +modificate). Usare il pulsante [Seleziona i file] per aprire un dialogo di scelta file e selezionare quante immagini si vuole. Quando pronti, cliccare [Prosegui] per rinominare i file tutti insieme. Non usare questa -funzione per rinominare file che non siano fotografie, perch -Fotoxx cercher di aggiornare il suo catalogo interno di +funzione per rinominare file che non siano fotografie, perché +Fotoxx cercherà di aggiornare il suo catalogo interno di etichette e file relativi per la ricerca immagini.


        -Collezioni di immagini - Concetti
        Una -collezione un insieme arbitrario di immagini composta +Collezioni di +immagini - Concetti
        + +Una +collezione è un insieme arbitrario di immagini composta manualmente da immagini prelevate dal database di Fotoxx. Questo - uno dei metodi per creare gruppi di immagini (altri due sono +è uno dei metodi per creare gruppi di immagini (altri due sono etichette/titoli/commenti, e directory/nomi di file). Una collezione - semplicemente la lista dei suoi membri (file); i file stessi -non vengono mai copiati o modificati. Una data immagine pu fare +è semplicemente la lista dei suoi membri (file); i file stessi +non vengono mai copiati o modificati. Una data immagine può fare parte di diverse collezioni. Le collezioni possono essere usate per raggruppare immagini che condividono qualche caratteristica, come "foto di una vacanza", "foto di una certa persona" prese in momenti e occasioni diverse, "foto notevoli" e via dicendo. Quando una collezione -viene creata gli viene assegnato un nome, e pu essere +viene creata gli viene assegnato un nome, e può essere utilizzata per diversi scopi, come vedere uno slide show o inciderla su un CD. Si possono aggiungere e rimuovere foto da una collezione, o -variare il loro ordine. Una data singola immagine pu essere -presente pi volte nella stessa collezione.
        - -
        - - -
        - -Creare una collezione di immagini
        - -Un dialogo e una galleria vengono aperti per selezionare i file (dettagli). -Selezionare un certo numero di file. Quando finito, un dialogo di -salvataggio file viene mostrato; immettere un nome per la collezione: i -nomi di tutti i file scelti verranno salvati come lista, usando il nome -dato per la collezione appena creata.
         
        - - -
        - - -Aprire una collezione
        - -Una collezione creata in -precedenza pu essere richiamata per diventare la selezione -corrente. Un dialogo di apertura file viene presentato: selezionare una -delle collezioni mostrate. La galleria immagini viene mostrata, con -all'interno tutte le immagini della collezione. A questo punto si -pu scorrere avanti e indietro, eseguire uno slide show, -selezionare una o pi immagini per l'esportazione, eccetera.
        - -
        - -
        - -Eliminare una collezione
        - -Selezionare una delle collezioni mostrata per eliminarla.
        - -
        - -
        - -Modifica collezione
        - -
        Selezionare -una delle collezioni mostrate per modificarla; una galleria con la -collezione verr mostrata, insieme alla finestra di dialogo -visibile qui sopra. Per prima cosa, premere uno dei quattro pulsanti -per scegliere l'operazione da eseguire: le azioni successive saranno -determinate dal modo scelto. Qualsiasi modifica alla collezione -diventer permanente solo dopo aver premuto il pulsante [Fatto].
        +variare il loro ordine. Una certa singola immagine può essere +presente più volte nella stessa collezione.

        -
        [Aggiungere]: -un dialogo di scelta file viene mostrato. Selezionare una o pi -immagini da aggiungere alla collezione: esse verranno aggiunte da una -successiva operazione [Incolla]. I file selezionati devono risiedere -nella stessa directory; se si vogliono aggiungere file da directory -multiple, occorre ripetere [Aggiungere] e [Incolla] per ogni -differente directory. Quando finito di selezionare i file, chiudere il -dialogo. Le immagini marcate sono ricordate internamente. Usare il -pulsante [Incolla] per completare l'aggiunta.
        -
        -
        [Elimina]: dopo -premuto questo pulsante, cliccare qualsiasi immagine per toglierla -dalla collezione. Le immagini cliccate spariscono immediatamente e non -c' modo di annullare (a parte il riaggiungerle -successivamente). L'eliminazione, per, diventer -permanente solo premendo il pulsante [Fatto]; cliccando [Annulla] -nessuna modifica sar eseguita.
        -
        -
        [Taglia]: dopo -premuto il pulsante, cliccare su una o pi immagini per toglierle dalla -galleria e salvarle internamente. Usare poi il pulsante [Incolla] per -aggiungere tali immagini alla collezione.
        -
        -
        [Incolla]: dopo aver usato [Aggiungere] o [Taglia], ci sono immagini salvate -(ricordate) internamente. Cliccando su [Incolla], queste immagini -saranno inserite nella galleria nella posizione successiva all'immagine -che verr cliccata.
        +
        Dialogo di gestione collezioni
        +

        -
        -Sommario

        - -Per aggiungere nuove immagini: premere [Aggiungere], selezionare i file, e poi cliccare [Incolla].
        Per eliminare immagini: premere [Elimina], e poi cliccare la immagini da cancellare.
        - -Per spostare immagini: cliccare [Taglia], cliccare sulle immagini da -spostare (che scompariranno), premere [Incolla], e poi cliccare su -un'immagine per reimmettere le immagini tolte.
        +Nuovo: +specificare un nome per la nuova collezione; ulteriori operazioni verranno svolte sulla nuova collezione.
        +Modifica: selezionare una collezione esistente per le modifiche.
        +Vista: selezionare una collezione da visualizzare; la galleria mostrerà le miniature.
        +Elimina: selezionare una collezione (esistente) da eliminare. Viene cancellata la collezione, non le immagini che la formano.
        +

        +Dopo che una collezione è +stata creata o aperta, si possono aggiungere o rimuovere immagini +cliccando il tasto destro su una miniatura della galleria o nella +finestra principale: un menù a comparsa mostra le seguenti voci:
        +
        +    + aggiungi immagine alla collezione <nome della collezione>
        +    + rimuovi immagine dalla collezione
        +    + rimuovi immagine e ricordala
        +    + inserisci qui le immagini ricordate
        +
        +Procedure
        (1) Aggiungere +immagini: usare [Nuovo] o [Modifica] per stabilire la collezione da +creare o modificare. +Usare [Apri] or [Miniature] per navigare verso le immagini da +aggiungere. Cliccare col destro ogni immagine da aggiungere e +selezionare la voce per aggiungere. Si può anche usare [Vista] +per aggiungere immagini da un'altra collezione.
        +
        (2) Rimuovere immagini: usare [Modifica] per vedere una galleria, +cliccare le immagini da eliminare con il destro, e selezionare [Rimuovi +immagine dalla collezione].
        +
        (3) Riorganizzare immagini: usare [Modifica] per aprire una +galleria di foto; cliccare il destro su ogni immagine da spostare, e +selezionare [Rimuovi immagine e ricordala]. La miniatura viene +immediatamente rimossa dalla galleria, ma ricordata in una lista +interna. Cliccare infine col destro su un'immagine dopo la quale +collocare quelle ricordate, e scegliere [Inserisci qui le immagini +ricordate] dal menù.
        +

        +Sposta collezioni
        Un +database di foto può essere mosso rinominando o spostando la sua +cartella principale - le immagini lo seguiranno automaticamente. La +funzione [Sincronizza file] può riparare l'indice di ricerca, ma +le collezioni diventano invalide perché le directory memorizzate +saranno differenti. la funzione [Sposta collezioni] può essere +usata per spostare la cartella principale in tutte le collezioni +salvate. Immettere i nomi della cartella vecchia e nuova e cliccare +[Applica].
        +

        +
        -

        Stampa immagine

        - Questa funzione apre un dialogo dove si seleziona una stampante, un formato di carta (es. Lettera o A4), e un orientamento della carta (verticale o orizzontale). Usare il pulsante [Stampa] per stampare l'immagine corrente con le impostazioni scelte.
        -Tra i formati di carta si pu anche scegliere
        "custom +Tra i formati di carta si può anche scegliere "custom N.N x N.N cm" - senza modificare questa scritta, ma rimpiazzando i due "N.N" con con i valori desiderati in centimetri. A seconda del software di stampa installato, potrebbe apparire un'anteprima di stampa, e potrebbe essere possibile impostare ulteriori opzioni su carta, -qualit e stampante. Alcuni dei formati predefiniti potrebbero +qualità e stampante. Alcuni dei formati predefiniti potrebbero non funzionare con alcune stampanti. Anche i margini sembrano a volte -essere casuali; a volte si pu correggere il problema cambiando +essere casuali; a volte si può correggere il problema cambiando le dimensioni del foglio: usare il formato custom (speciale) aumentando -gradualmente le dimensioni per ottenere margini pi piccoli. Io +gradualmente le dimensioni per ottenere margini più piccoli. Io ho potuto sperimentare solo CUPS (software di stampa) con una stampante HP Officejet. Suggerisco di fare alcune prove con carta normale prima di usare la dispendiosa carta speciale fotografica.
        +
        -
        Men strumenti
        -
        +
        +Menù +strumenti
        +

        -Verifica luminosit schermo

        +Verifica luminosità schermo

        Otto bande colorate vengono -generate orizzontalmente sullo schermo, con luminosit crescente -da 0% (nero) al 100% (bianco). Si pu usare questa immagine per -regolare luminosit e contrasto dello schermo. L'estremo -sinistro di ogni banda dovrebbe essere pi nero possibile, ma il +generate orizzontalmente sullo schermo, con luminosità crescente +da 0% (nero) al 100% (bianco). Si può usare questa immagine per +regolare luminosità e contrasto dello schermo. L'estremo +sinistro di ogni banda dovrebbe essere più nero possibile, ma il colore dovrebbe cominciare a essere visibile entro pochi mm dal lato -sinistro. Se la porzione nera pi ampia, occorre -regolare lo schermo. Ci sono 255 passi di luminosit dal nero al -bianco (si usano 8 bit per colore), e queste gradazioni sono pi +sinistro. Se la porzione nera è più ampia, occorre +regolare lo schermo. Ci sono 255 passi di luminosità dal nero al +bianco (si usano 8 bit per colore), e queste gradazioni sono più sottili di quanto l'occhio umano possa cogliere. Questa regolazione va eseguita in una stanza abbastanza scura, con poca luce che cade sul video.

        -
        Gamma del monitor
        +
        + +Gamma del +monitor
        Il fattore gamma determina come -i valori 0..255 dei colori vengono convertiti in luminosit -percepita dall'occhio. Il valore standard 2,2 e dovrebbe +i valori 0..255 dei colori vengono convertiti in luminosità +percepita dall'occhio. Il valore standard è 2,2 e dovrebbe essere utilizzato normalmente durante le operazioni di editing. La funzione Verifica gamma dello schermo mostra un'immagine speciale fornita cortesemente da Norman Koren. @@ -1876,16 +1843,12 @@
        - - - -
        - -Grafico di luminosit

        +

        +Grafico di luminosità

        Questa funzione apre una piccola finestra che mostra un grafico riguardo alla distribuzione della -luminosit dell'immagine corrente. Il grafico si aggiorna +luminosità dell'immagine corrente. Il grafico si aggiorna immediatamente se si cambia immagine o si esegue qualche modifica.

        @@ -1895,55 +1858,61 @@ Esegue una nuova istanza di Fotoxx in una nuova finestra, contenente l'immagine corrente. Lo -schermo sar diviso a met fra le due istanze. Questo +schermo sarà diviso a metà fra le due istanze. Questo torna utile per comparare immagini, o per usare due foto alla volta. Entrambe le istanze possono essere usate per fare modifiche. L'istanza -copia (a sinistra) avr all'inizio una versione non modificata -dell'immagine, mentre l'istanza originale (a destra) manterr le +copia (a sinistra) avrà all'inizio una versione non modificata +dell'immagine, mentre l'istanza originale (a destra) manterrà le ultime modifiche. Se lo stesso file viene modificato nelle due istanze, -il file conterr l'immagine che verr salvata per ultima. +il file conterrà l'immagine che verrà salvata per ultima. Usare [Salva come] / Salva nuovo specificando [Creare nuova versione] se si desidera mantenere i due differenti file.


        -Slide show

        Le +Slide show
        + +Le immagini nella directory corrente, o quelle risultanti da una ricerca o una collezione, vengono mostrate una per volta. La finestra viene -allargata all'intero schermo, e men e barra dei pulsanti +allargata all'intero schermo, e menù e barra dei pulsanti vengono rimossi. Un dialogo chiede la durata per ogni immagine e il tipo di transizione per cambiarla. I modi di transizione includono i tasti freccia (transizioni manuali), rimpiazzamento istantaneo, dissolvenza in ingresso e uscita, e diversi altri metodi dinamici (la nuova immagine si espande dal centro per rimpiazzare la vecchia). Se il -modo "Manuale: tasti freccia" selezionato, la durata +modo "Manuale: tasti freccia" è selezionato, la durata è irrilevante e i tasti freccia a sinistra o destra sono usati per passare all'immagine precedente o successiva. Questi tasti possono -essere usati anche se uno degli altri modi attivo. Usare il +essere usati anche se uno degli altri modi è attivo. Usare il tasto Esc per uscire dallo slide show. Se una ricerca immagini - stata eseguita prima dello slide show, vengono mostrate queste -immagini. Prima di richiamare questa funzione possibile usare +è stata eseguita prima dello slide show, vengono mostrate queste +immagini. Prima di richiamare questa funzione è possibile usare Info->Modifica commenti o Info->Modifica titolo per mostrare il rispettivo testo di ogni immagine in una piccola finestra che si -pu spostare di lato; il testo viene aggiornato a ogni immagine -presentata. Gli altri tipi di informazione del men Info avranno +può spostare di lato; il testo viene aggiornato a ogni immagine +presentata. Gli altri tipi di informazione del menù Info avranno lo stesso comportamento. Il dialogo di avviamento della funzione permette anche di specificare un file musicale o una playlist. Se -questo campo non vuoto, la musica verr avviata insieme +questo campo non è vuoto, la musica verrà avviata insieme allo slide show.

        + -E' anche possibile avviare uno slide show con o senza musica dalla riga di comando:
        +E' anche possibile avviare uno slide show con o senza musica dalla riga +di comando:

        -   $ fotoxx -slideshow /.../imagefile1.jpg  -music /.../musicfile.ogg
        +   $ fotoxx -slideshow +/.../imagefile1.jpg  -music /.../musicfile.ogg
        +
        Lo slide show inizia con il file specificato e continua con i file -seguenti nella stessa directory. Il parametro "-music" +seguenti nella stessa directory. Il parametro "-music" è opzionale; se presente, deve specificare un file musicale (.mp3, .ogg ...) o una playlist. Il comando xdg-open(1) viene usato per aprire il -file musicale (che sar suonato con il lettore predefinito).

        +file musicale (che sarà suonato con il lettore predefinito).


        @@ -1951,12 +1920,12 @@ Esplora i colori RGB

        Quando un punto dell'immagine - cliccato con il pulsante sinistro, i valori RGB vengono +è cliccato con il pulsante sinistro, i valori RGB vengono mostrati in una finestra di dialogo. I numeri hanno il formato xxx.ddd, dove xxx sono gli 8 bit superiori del valore del colore, da 0..255, e .ddd sono gli 8 bit inferiori, da 0..999. Gli otto bit inferiori sono a zero a meno che l'immagine mostrata non sia una TIFF a 16 bit. Soltanto -le funzioni di modifica di colori e luminosit cambiano gli 8 +le funzioni di modifica di colori e luminosità cambiano gli 8 bit bassi, e questi vengono preservati solo se l'immagine viene salvata nel formato TIFF a 16 bit.
        @@ -1974,37 +1943,37 @@ controllano lo spazio in pixel fra le linee. Se le impostazioni di x-count e y-count (conteggio x e y) sono diverse da zero, allora le distanze specificate vengono ignorate e il numero richiesto di linee -verr generato. Per esempio, impostare x- e y-count a 2 per +verrà generato. Per esempio, impostare x- e y-count a 2 per dividere l'immagine in nove quadrati uguali. Le caselle di spunta x-grid e y-grid abilitano le linee orizzontali e verticali -separatamente. Il tasto G della tastiera pu essere usato per +separatamente. Il tasto G della tastiera può essere usato per invertire le linee: le caselle x-grid e y-grid vengono invertite. Se un'immagine viene stampata quando le linee sono visibili, anch'esse verranno stampate.


        - - Parametri dell'obbiettivo

        -Questo un dialogo per +Questo è un dialogo per impostare e salvare i due parametri, focale e curvatura, che devono essere impostati per ogni macchina o lente usata per i panorami. Questi valori governano il modo con cui Fotoxx "svolge" le foto panoramiche in modo che possano collimare accuratamente. Immettere un nome per la lente o macchina e i due parametri. Fino a quattro lenti o macchine -possono essere specificate. mm_focale grosso modo la lunghezza -focale della lente (equivalente a 35 mm), e curvatura un +possono essere specificate. mm_focale è grosso modo la lunghezza +focale della lente (equivalente a 35 mm), e curvatura è un fattore per compensare la bombatura ai lati. Qui si descrive come impostare i parametri, ma occorrerebbe prima leggere la sezione sulla creazione di panorami, per capire meglio le istruzioni seguenti.

        -Impostazione automatica dei parametri

        Il +Impostazione automatica dei parametri
        + +Il pulsante [Ricerca], nel dialogo di pre-allineamento nella funzione Panorama, inizia una ricerca automatica dei parametri ottimali della lente. Usare una coppia di immagini adatta: il soggetto deve trovarsi a -pi di 50 metri di distanza, le immagini devono avere poche +più di 50 metri di distanza, le immagini devono avere poche differenze nell'orizzonte e poca rotazione relativa, con molte dettagli ben contrastati nella zona di sovrapposizione. Inserire la lunghezza focale nominale; usare zero per la curvatura. Dopo aver fatto un @@ -2014,29 +1983,29 @@ successivi panorama. La funzione di ricerca scandisce un intervallo di valori per lunghezza e curvatura focale, e scostamenti dell'immagine per x, y e theta, cercando quei valori che forniscono i migliori -risultati per le immagini analizzate. Il processo lento (un -minuto o pi), ma va eseguito una volta sola per regolare le +risultati per le immagini analizzate. Il processo è lento (un +minuto o più), ma va eseguito una volta sola per regolare le caratteristiche di un determinato obbiettivo. Assicurarsi di salvare il -risultato tramite la funzione Parametri dell'obbiettivo nel men +risultato tramite la funzione Parametri dell'obbiettivo nel menù Strumenti.

        -Impostazione manuale dei parametri delle lenti
        -M Creare un panorama di un muro +Impostazione +manuale dei parametri delle lenti
        Creare un panorama di un muro di mattoni (o qualsiasi muro con molti dettagli), con due immagini che -si sovrappongano del 40%. Il muro deve distare almeno 5 metri. Durante +si sovrappongono del 40%. Il muro deve distare almeno 5 metri. Durante il pre-allineamento, regolare diametro e curvatura dell'obbiettivo fino a che le parti sovrapposte coincidano. Durante la ripresa delle due -immagini, assicurarsi di di ruotare la macchina lungo l'asse verticale +immagini, assicurarsi di ruotare la macchina lungo l'asse verticale passante per le lenti, minimizzando movimento laterale e rotazione -degli altri assi; diversamente le immagini corrisponderanno poco e i +degli altri assi, diversamente le immagini corrisponderanno poco e i parametri non saranno ottimali. Il risultato dovrebbe corrispondere all'incirca alla lunghezza focale nominale della lente (equivalente a 35 mm). Potrebbe discostarsi un poco (le mie lenti da 27 mm funzionano meglio con un'impostazione di lunghezza di 29-30 mm). Ritengo che -ci accada perch le lenti grandangolari non sono lenti -ideali. La maggior parte dei panorama saranno corretti anche se -l'impostazione della lunghezza focale impostata con un errore +ciò accada perché le lenti grandangolari non sono lenti +ideali. La maggior parte dei panorami saranno corretti anche se +l'impostazione della lunghezza focale è impostata con un errore del 10%.

        @@ -2045,55 +2014,76 @@ Questa funzione permette di scegliere una lingua (tra quelle disponibili) per l'interfaccia grafica -del programma. Se la lingua desiderata non disponibile, o ha -una traduzione imperfetta, si consideri la possibilit di creare -o correggere la traduzione: non un compito difficile (informazioni qui).
        +del programma. Se la lingua desiderata non è disponibile, o ha +una traduzione imperfetta, si consideri la possibilità di creare +o correggere la traduzione: non è un compito difficile (
        informazioni +qui).
        +
        +
        -Edit Translations (correggi traduzione / lingua del programma)
        + +Edit +Translations (correggi traduzione / lingua del programma)

        Questa procedura si usa per correggere le traduzioni interattivamente, durante l'uso di Fotoxx. Tradizionalmente i file delle traduzioni vengono modificati a parte; poi questi file vengono installati e Fotoxx viene eseguito per vedere -il risultato finale. Il vantaggio di questo metodo nuovo che -il contesto d'utilizzo del programma vissuto nello stesso +il risultato finale. Il vantaggio di questo metodo nuovo è che +il contesto d'utilizzo del programma è vissuto nello stesso momento di modifica della traduzione, e questo dovrebbe portare a una -traduzione migliore e pi agevole. Inoltre, la traduzione viene +traduzione migliore e più agevole. Inoltre, la traduzione viene usata immediatamente da Fotoxx. Per maggiori dettagli su come fare una -traduzione (incluso questo metodo interattivo), vedere il men +traduzione (incluso questo metodo interattivo), vedere il menù Aiuto -> Come tradurre il programma.


        -Crea men e lanciatore

        +Crea menù e lanciatore

        Questa funzione crea un'icona (lanciatore) sulla scrivania (desktop) e aggiunge una voce nel -men di sistema nella categoria "Grafica". Il sistema operativo +menù di sistema nella categoria "Grafica". Il sistema operativo deve essere conforme con LSB (Linux Standards Base, un insieme di regole per la standardizzazione di Linux). Il successo di tutto -ci sporadico - pu essere necessario riavviare -la sessione per vedere la nuova voce del men.
        +ciò è sporadico - può essere necessario riavviare +la sessione per vedere la nuova voce del menù.



        + Convertire file RAW
        Questa funzione converte una o -pi immagini RAW in file TIFF a 16 bit per colore, usando il +più immagini RAW in file TIFF a 16 bit per colore, usando il programma ufraw-batch. Un dialogo di scelta file si apre: selezionare -uno o pi file RAW (tenere premuto il tasto Ctrl per eseguire +uno o più file RAW (tenere premuto il tasto Ctrl per eseguire selezioni multiple). Le immagini sono convertite una per volta e mostrate nella finestra principale. Secondo il numero di file, -pu servire molto tempo (un processore da 2,67 GHz converte +può servire molto tempo (un processore da 2,67 GHz converte circa 18 file (misti) al minuto. Il programma ufraw usa in effetti core -multipli, ma la funzione di Fotoxx non usa questa possibilit.
        - -
        +multipli, ma la funzione di Fotoxx non usa questa possibilità.
        +

        +Questa funzione converte i file RAW selezionati in JPEG, PNG, TIFF-8 o +TIFF-16, usando il programma ufraw-batch. I due formati TIFF hanno +rispettivamente 8 e 16 bit per colore. I file RAW usano generalmente +10-12 bit, quindi usare TIFF-16 per mantenere la precisione disponibile +in un file RAW (tuttavia la differenza tra colore a 8 e 16 bit è +raramente precettibile).
        Un +dialogo di scelta file si apre: selezionare +uno o più file RAW (tenere premuto il tasto Ctrl per eseguire +selezioni multiple). Verrà poi chiesto di scegliere uno dei +formati elencati prima. Le immagini verranno convertite una alla volta +e mostrate nella finestra principale. Secondo il numero di file, +ciò può richiedere molto tempo (il mio veloce PC elabora +circa 24 foto al minuto usando un misto di foto RAW e uscita con +TIFF-16).
        +
        +


        Masterizza immagini su CD/DVD

        @@ -2101,20 +2091,23 @@ Questa funzione permette di scegliere file d'immagini e scriverle su un CD o DVD. Quando la procedura inizia, una galleria viene mostrata dalla quale scegliere le -immagini da incidere (dettaglio). Quando finito, la lista di immagini viene inviata al programma Brasero per eseguire la scrittura reale.
        +immagini da incidere (dettaglio). Quando finito, la lista di +immagini viene inviata al programma Brasero per eseguire la scrittura +reale.


        -Spedire immagini via e-mail
        +Spedire +immagini via e-mail
        Questa funzione permette di scegliere fino a circa 40 immagini per inviarle al programma di posta predefinito. Si apre un dialogo: cliccare [Seleziona i file] per aprire una galleria di immagini dalla quale selezionare (
        dettaglio). Finita la selezione, impostare le dimensioni massime di larghezza e -altezza. Il pulsante [Prosegui] ridurr le immagini e le -mander al programma di posta. Le nuove immagini, ridotte, sono +altezza. Il pulsante [Prosegui] ridurrà le immagini e le +manderà al programma di posta. Le nuove immagini, ridotte, sono salvate in una directory/cartella temporanea "/tmp/<nome_utente>/fotoxx/" senza intaccare quelle originali. Questa funzione usa il comando xdg-email (da LSB, Linux Standards @@ -2124,141 +2117,155 @@ allegate. Occorre poi specificare il destinatario, l'oggetto e il testo, e infine inviare il messaggio.

        - -

        -Sincronizza file
        +Sincronizza +file
        Occorre eseguire questa procedura: dopo la prima installazione di Fotoxx, quando si aggiungono immagini alla propria collezione, o dopo un'operazione di rinomina di file o cartelle. Niente viene perso quando i file vengono spostati, ma la galleria di miniature diventa lenta se un grande numero di file - stato spostato, e la funzione di ricerca immagini non -trover file nuovi o spostati altrove. La funzione Sincronizza +è stato spostato, e la funzione di ricerca immagini non +troverà file nuovi o spostati altrove. La funzione Sincronizza file crea le miniature mancanti, aggiorna quelle vecchie, e aggiorna l'indice di ricerca  usando i dati correnti delle fotografie. Se si sono usate cartelle e/o nomi di file per classificare le foto, si possono usare immediatamente questi termini nella funzione di ricerca. Se sono stati salvati titoli, etichette o punteggi dentro alle foto, anche questi dati possono essere ricercati.
        -Una finestra di dialogo chieder la directory superiore +Una finestra di dialogo chiederà la directory superiore contenente le vostre foto (es. /home/<nomeutente>/Immagini). Quella directory, e tutte quelle di ordine inferiore contenenti immagini verranno processate. Non importa se vi sono file di altro tipo mischiati con le immagini, tali file saranno ignorati. Ci sono due opzioni per eseguire la sincronizzazione: completa e incrementale. La "ricostruzione completa" azzera tutti i dati memorizzati e li -ricostruisce; pu impiegare parecchio tempo (il mio computer, +ricostruisce; può impiegare parecchio tempo (il mio computer, relativamente potente, analizza 4500 immagini in 10 minuti). Il modo -"Incrementale" salter le immagini gi conosciute (che -possiedono gi miniatura e dati per la ricerca); molto -pi rapido se solo relativamente poche immagini sono state -aggiunte (secondi invece di minuti). Lo svantaggio (non grave) +"Incrementale" salterà le immagini già conosciute (che +possiedono già miniatura e dati per la ricerca); è molto +più rapido se solo relativamente poche immagini sono state +aggiunte (secondi invece di minuti). Lo svantaggio (non grave) è che miniature e dati obsoleti vengono lasciati al loro posto invece di essere cancellati.
        -Dopo che le immagini sono state indicizzate, la loro ricerca diventa praticamente istantanea.
        +Dopo che le immagini sono state indicizzate, la loro ricerca diventa +praticamente istantanea.
        Immagini create o spostate da Fotoxx medesimo sono gestite -automaticamente. La funzione Sincronizza file necessaria solo +automaticamente. La funzione Sincronizza file è necessaria solo quando l'archivio delle immagini viene modificato dall'esterno (senza usare Fotoxx).


        +
        Menu Info

        +Menu Info

        + Nota: il programma/pacchetto exiftool -deve essere installato affinch le funzioni seguenti funzionino. +deve essere installato affinché le funzioni seguenti funzionino. Fotoxx usa tale programma per leggere e scrivere le informazioni contenute dentro a un file di immagine (metadata: EXIF, IPTC, ecc.). Se -exiftool non installato, allora la riscrittura di un file -(conseguente a una modifica) canceller questi metadati. Nelle -versioni recenti di Ubuntu, il pacchetto contenente exiftool +exiftool non è installato, allora la riscrittura di un file +(conseguente a una modifica) cancellerà questi metadati. Nelle +versioni recenti di Ubuntu, il pacchetto contenente exiftool è libimage-exiftool-perl.

        -
        Modifica commenti
        +
        + +Modifica +commenti
        -Questa una funzione +Questa è una funzione speciale per editare la chiave EXIF "User Comments". Immettere un qualsiasi testo da associare con l'immagine corrente. Linee di testo multiple di qualsiasi lunghezza possono essere immesse, fino a un limite generale di 1000 caratteri. Premere [Applica] per salvare il testo nei dati EXIF dell'immagine. La finestra di -dialogo pu essere lasciata aperta mentre si naviga su altre +dialogo può essere lasciata aperta mentre si naviga su altre immagini, e il testo corrente di ogni immagine viene mostrato, se presente. Scrivere un nuovo testo e premere [Applica] per rendere la modifica permanente. Se occorre scrivere lo stesso testo (o quasi) in -diverse immagini, si pu usare copia/incolla. Si pu +diverse immagini, si può usare copia/incolla. Si può lasciare aperta questa finestra, in un angolo dello schermo, anche nel modo Slide show. I commenti associati a un'immagine possono essere usati (ricercati) dalla funzione di Ricerca immagini.

        -
        Modifica titolo
        +
        -Funziona esattamente come "Modifica commenti", ma il testo riguarda la chiave IPTC "Caption-Abstract".
        +Modifica +titolo
        -
        +Funziona esattamente come +"Modifica commenti", ma il testo riguarda la chiave IPTC +"Caption-Abstract".
        -
        Etichette

        +
        +
        +Etichette

        I file immagine possono avere etichette di classificazione (categorie, parole chiave) associate. Queste possono essere usate per ricercare in una grande collezione quelle immagini con le etichette desiderate. Etichette tipiche sono: il soggetto principale della foto, l'evento, il luogo, le -persone, e cos via. Queste etichette risiedono nel campo +persone, e così via. Queste etichette risiedono nel campo "keywords" dei metadati IPTC. Le etichette sono solitamente composti di una sola parola, ma una breve frase contenente spazi o altri -delimitatori pu essere usata. Virgole e punti e virgola sono +delimitatori può essere usata. Virgole e punti e virgola sono riconosciuti internamente come separatori di etichette, e quindi non devono essere usati. Un'etichetta composta come "Panorama d'America" - permessa, ma sarebbe meglio usare due etichette distinte per -avere maggiore flessibilit, perch cos sarebbe +è permessa, ma sarebbe meglio usare due etichette distinte per +avere maggiore flessibilità, perché così sarebbe possibile cercare immagini aventi una sola delle due etichette o entrambe.

        -Si pu usare un albero o gerarchia di directory per organizzare +Si può usare un albero o gerarchia di directory per organizzare fisicamente le immagini, per esempio nomi di directory descriventi -l'anno, o il luogo, o altri schemi. Si pu usare il nome di file +l'anno, o il luogo, o altri schemi. Si può usare il nome di file come soggetto principale della foto. Tali schemi organizzativi sono -utili ma non indispensabili: anche possibile buttare tutte le +utili ma non indispensabili: è anche possibile buttare tutte le foto in una directory gigantesca e usare la numerazione progressiva generata dalla macchina fotografica. A prescindere dall'organizzazione fisica, le etichette permettono di organizzare le stesse immagini in viste multiple: tutte le foto di una persona attraverso tutti gli anni, tutti i luoghi, tutte le occasioni, eccetera. Tutte le immagini aventi la stessa etichetta possono essere trovate velocemente e mostrate in -una galleria di miniature, dove possibile sceglierene un -insieme pi ristretto per vederle, modificarle, cambiare loro le +una galleria di miniature, dove è possibile sceglierene un +insieme più ristretto per vederle, modificarle, cambiare loro le etichette.
        -
        + Se i nomi di file e directory -sono stati scelti accuratamente, si pu continuare a usarli in +sono stati scelti accuratamente, si può continuare a usarli in modo produttivo: si possono eseguire ricerche usando quei nomi, da soli -o in aggiunta alle etichette. Non c' bisogno di duplicare -informazioni gi presenti. Riferirsi a "Ricerca immagini" -pi sotto.
        +o in aggiunta alle etichette. Non c'è bisogno di duplicare +informazioni già presenti. Riferirsi a "Ricerca immagini" +più sotto.

        Le immagini possono avere una data (data della foto) che viene estratta dai dati EXIF o impostata manualmente. Le immagini possono avere un punteggio (a stellette) per -l'importanza del contenuto o per la loro qualit. Anche le date +l'importanza del contenuto o per la loro qualità. Anche le date e il punteggio possono essere usati come criterio di ricerca.

        -Limitazioni e consigli pratici
        + +Limitazioni e +consigli pratici
        + I seguenti sono i limiti imposti per le etichette; sono fissati durante la compilazione di Fotoxx e potrebbero essere facilmente innalzati, ma @@ -2266,57 +2273,70 @@ pratiche:

        -     o   lunghezza massima di una singola etichetta: 50 caratteri
        -     o   lunghezza massima complessiva di etichette per un file: 1000 +     +o   lunghezza massima di una singola etichetta: 50 caratteri
        +     +o   lunghezza massima complessiva di etichette per un file: +1000 caratteri
        -     o   numero massimo di etichette per una singola categoria: 50.000 +     +o   numero massimo di etichette per una singola categoria: +50.000 caratteri
        -     o   limite massimo interno per le etichette: 50.000 caratteri
        -     o   numero massimo di etichette per una ricerca: 200 caratteri
        -     o   numero massimo durante l'aggiunta in blocco di etichette: 200 +     +o   limite massimo interno per le etichette: 50.000 caratteri
        +     +o   numero massimo di etichette per una ricerca: 200 caratteri
        +     +o   numero massimo durante l'aggiunta in blocco di etichette: +200 caratteri

        + Il limite pratico per il numero -totale di etichette 200..500. Oltrepassare questo intervallo - possibile, ma porta a qualche problema pratico: la finestra -che mostra le etichette disponibili sar grande e tali etichette +totale di etichette è 200..500. Oltrepassare questo intervallo +è possibile, ma porta a qualche problema pratico: la finestra +che mostra le etichette disponibili sarà grande e tali etichette saranno difficili da individuare, anche se sono ordinate per categoria e all'interno di ogni categoria, e l'operazione di "punta e clicca" per -aggiungere etichette diventer pi impegnativa. Se le +aggiungere etichette diventerà più impegnativa. Se le etichette sono definite grossolanamente e in numero inferiore, i -risultati di una ricerca saranno pi numerosi, ma una ulteriore -raffinazione della ricerca all'interno delle miniature +risultati di una ricerca saranno più numerosi, ma una ulteriore +raffinazione della ricerca all'interno delle miniature è comunque piuttosto veloce. L'organizzazione fisica dei file viene preservata nella galleria (file che risiedono nella stessa directory appariranno affiancati nella galleria). Insomma, il mio consiglio per -il fotografo non professionista di usare poche, generiche +il fotografo non professionista è di usare poche, generiche etichette.

        - -
        Modifica etichette

        +
        +Modifica etichette


        -Per assegnare etichette all'immagine corrente, usare il men Info->Modifica etichette.
        + +Per assegnare etichette +all'immagine corrente, usare il menù Info->Modifica +etichette.
        Le etichette correnti sono mostrate in "Etichette attuali". Le etichette disponibili sono mostrate nel riquadro inferiore in "Etichette definite". Tali etichette possono essere aggiunte -all'immagine cliccandole. Un'etichetta assegnata si pu togliere +all'immagine cliccandole. Un'etichetta assegnata si può togliere cliccandola, dentro il riquadro "Etichette attuali". Le etichette aggiunte recentemente sono mostrate in "Etichette recenti"; questa - una comodit per aggiungere le stesse etichette a molte +è una comodità per aggiungere le stesse etichette a molte immagini, in previsione che molte etichette possano essere usate ripetutamente: anche queste si aggiungono cliccandole. La data dell'immagine, se disponibile, viene mostrata nel campo apposito; -pu essere immessa se mancante, o modificata. Si pu +può essere immessa se mancante, o modificata. Si può usare il formato completo AAAAMMGG (anno/mese/giorno) o le forme -pi brevi AAAAMM e AAAA. Durante una ricerca il mese e il +più brevi AAAAMM e AAAA. Durante una ricerca il mese e il giorno, se non presenti, sono assunti come 01/01 in un confronto verso il limite inferiore, e 31/12 verso il limite superiore. Il pulsante [Utilizza ultima] riempie il campo data con l'ultima data immessa o mostrata: serve a datare facilmente una serie di immagini.
        -Si pu assegnare un punteggio opzionale per la foto. Questa +Si può assegnare un punteggio opzionale per la foto. Questa finestra di dialogo rimane aperta se si passa a un'altra fotografia, e i campi vengono aggiornati con i dati della nuova foto. Il pulsante [Applica] scrive le informazioni nel file dell'immagine e nel database @@ -2325,47 +2345,49 @@
        -Gestione etichette
        +Gestione +etichette

        + Per creare etichette nuove, -usare il men Info->Gestione etichette. Si possono anche -usare categorie per organizzare le etichette e trovarle pi +usare il menù Info->Gestione etichette. Si possono anche +usare categorie per organizzare le etichette e trovarle più facilmente; le categorie sono opzionali e non hanno alcun ruolo nell'assegnamento o la ricerca: solo le etichette vengono memorizzate nell'immagine, non la categoria corrispondente. Categorie tipiche sono Persone, Luoghi, Cose, Eventi, Scenari, Palazzi, Arte e simili. Per creare un'etichetta e una categoria, immettere i rispettivi nomi e -cliccare [Crea]. La categoria pu essere omessa, e in tal caso -l'etichetta apparterr alla categoria "nocatg". Per assegnare +cliccare [Crea]. La categoria può essere omessa, e in tal caso +l'etichetta apparterrà alla categoria "nocatg". Per assegnare un'etichetta a una categoria differente, cliccare prima la categoria (le scritte in grassetto) o scriverne il nome, poi cliccare l'etichetta -e quindi premere [Crea]. l'etichetta verr spostata dalla +e quindi premere [Crea]. l'etichetta verrà spostata dalla vecchia alla nuova categoria. Per eliminare un'etichetta, cliccarla e premere [Elimina]. La finestra viene aggiornata per riflettere i -cambiamenti; se anche la finestra di modifica etichette -aperta, pure quella verr aggiornata: si possono quindi tenere +cambiamenti; se anche la finestra di modifica etichette è +aperta, pure quella verrà aggiornata: si possono quindi tenere aperte entrambe, se occorre creare o cambiare etichette in vista di un loro uso immediato. Etichette presenti nelle immagini ma non assegnate ad alcuna categoria appariranno nella sezione "nocatg".

        Nota:
        -appena creata, un'etichetta sar aggiunta al fondo della propria +appena creata, un'etichetta sarà aggiunta al fondo della propria categoria. Al riavvio successivo di Fotoxx, tutte le categorie e i loro contenuti saranno ordinati alfabeticamente, eccetto "nocatg" che - sempre ultima. Inoltre, un'etichetta scompare dalla lista se +è sempre ultima. Inoltre, un'etichetta scompare dalla lista se nessuna immagine la utilizza.

        -
        -Aggiungi etichette a pi immagini
        +Aggiungi +etichette a più immagini
        Quando si aggiungono etichette a un gran numero di immagini aventi in comune molte delle loro etichette, -usare questa procedura pu velocizzare l'operazione. Usare, +usare questa procedura può velocizzare l'operazione. Usare, nella finestra di dialogo, il pulsante [Seleziona i file] per aprire una galleria dalla quale selezionare i file (spiegazione). Dopo aver selezionato i file, specificare le etichette da aggiungere @@ -2377,7 +2399,8 @@
        -Cancellazione in blocco di etichette
        +Cancellazione +in blocco di etichette
        Questa funzione si usa per eliminare una singola etichetta dal molte immagini, o rimpiazzare @@ -2386,18 +2409,18 @@ [Seleziona i file] per aprire una galleria da cui selezionare le immagini (spiegazione). In alternativa, selezionare [cerca tutti i file] per specificare che la -cancellazione o sostituzione interesser tutti i file trovati +cancellazione o sostituzione interesserà tutti i file trovati nel database del programma, che abbiano l'etichetta specificata (similarmente alla funzione di ricerca).

        -
        Ricerca immagini


        + Esempio:selezione -di immagini del 2005 o successive, con 4 stelle o pi, con +di immagini del 2005 o successive, con 4 stelle o più, con etichetta "buildings" o "monuments" (costruzioni e monumenti), e contenenti "dresden" nel nome di file o di directory.
        @@ -2407,17 +2430,17 @@ Un apposito indice viene usato per la ricerca, che la rende molto veloce (migliaia di immagini al secondo vengono analizzate). L'indice viene generato da etichette, titoli, date e punteggi salvate -nell'immagine stessa (metadati EXIF e IPTC). Quindi si pu +nell'immagine stessa (metadati EXIF e IPTC). Quindi si può spostare file e directory senza perdere informazioni - occorre solo -rigenerare l'indice per la ricerca, che semplice e rapido. -Vedere il men Strumenti->Sincronizza file.
        +rigenerare l'indice per la ricerca, che è semplice e rapido. +Vedere il menù Strumenti->Sincronizza file.

        Usare la funzione di ricerca immagini per trovare immagini recanti le etichette desiderate, data, punteggio, commenti, titoli o nomi di file/percorsi. Le etichette definite vengono mostrate e possono essere selezionate cliccandole. Usare le caselle "all" o "any" di ogni campo per indicare se tutte (all) o una qualunque (any) delle parole -specificate deve essere presente in un'immagine affinch questa +specificate deve essere presente in un'immagine affinché questa sia selezionata. Premere poi [Prosegui] per iniziare la ricerca. Le immagini corrispondenti vengono mostrate in una galleria di miniature. Scegliere le immagini da vedere o modificare cliccando sulle miniature. @@ -2425,12 +2448,15 @@ e [Prossima]. Se un'immagine viene caricata usando la funzione File->Apri un'immagine (o il pulsante [Carica da file]), allora l'insieme corrente di immagini (la galleria) viene sostituito -dall'elenco delle immagini della directory da cui si prelevata -la nuova foto.


        +dall'elenco delle immagini della directory da cui si è prelevata +la nuova foto.

        + +
        + Un intervallo di -date pu essere usato, per restringere ulteriormente la ricerca -alle immagini all'interno del periodo richiesto. Il formato +date può essere usato, per restringere ulteriormente la ricerca +alle immagini all'interno del periodo richiesto. Il formato è AAAAMMGG (yyyymmdd). Le immagini rientrano nell'intervallo se hanno una data corrispondente o successiva alla prima data, se specificata, e uguale o precedente alla seconda data, se specificata. Se la data di @@ -2438,8 +2464,9 @@ d'inizio periodo, e 31/12 per la data di fine periodo.

        + Una coppia di punteggi -pu essere specificata per restringere la ricerca alle immagini +può essere specificata per restringere la ricerca alle immagini aventi un punteggio compreso nei due limiti specificati. Se si omette il primo limite, si assume zero; se si omette il secondo, si assume infinito.
        @@ -2450,62 +2477,63 @@ ogni parola, e possono comunque essere scritti anche nel mezzo di ognuna. Quindi, una specifica come "egitto cairo" troverebbe tutte le foto ove il nome di file o di directory contenesse una o l'altra di -queste parole, perch ogni nome di file o di cartella viene +queste parole, perché ogni nome di file o di cartella viene comparato con ognuno dei due termini (prima con "*egitto*" e poi con -"*cairo*"). Usando come specifica "egitto*cairo" il risultato -diverso, perch ogni nome di directory e file viene comparato +"*cairo*"). Usando come specifica "egitto*cairo" il risultato è +diverso, perché ogni nome di directory e file viene comparato una volta sola con la singola parola immessa, e solo le immagini che contengono entrambe le parole "egitto" e "cairo", in quell'ordine, -soddisfano il la richiesta. Il metodo di confronto semplice: +soddisfano il la richiesta. Il metodo di confronto è semplice: un asterisco ("*") corrisponde a qualsiasi sequenza di caratteri, ovunque nel nome completo di percorso del file di immagine. Il -confronto insensibile alla differenza fra maiuscole e +confronto è insensibile alla differenza fra maiuscole e minuscole. Se il termine da cercare contiene spazi, usare due virgolette intorno a esso (altrimenti verrebbe inteso come due parole -separate): per esempio una ricerca su [citt del capo] +separate): per esempio una ricerca su [città del capo] troverebbe qualsiasi file che contiene uno dei tre termini, mentre -["citt del capo"] trova solo i file che contengono esattamente +["città del capo"] trova solo i file che contengono esattamente quella scritta.
        +
        -
        La ricerca pu basarsi anche su titoli e commenti (vedere Modifica titolo e Modifica commenti). Immettere +La ricerca può basarsi +anche su titoli e commenti (vedere Modifica titolo e Modifica commenti). Immettere i termini da cercare nel campo "Ricerca testo", separati da spazi. Questi termini verranno comparati con ogni parola del titolo e del commento di ogni immagine, e le corrispondenze verranno selezionate. -Anche qui si pu usare il carattere jolly "*".
        +Anche qui si può usare il carattere jolly "*".

        Le scelte "all" (tutti) ed "any" (qualsiasi) si applicano a ogni campo di ricerca: etichette, testo, e -nomi di file. Si pu specificare, per ogni campo di ricerca, se +nomi di file. Si può specificare, per ogni campo di ricerca, se i termini all'interno devono corrispondere tutti (ALL) o almeno uno (ANY). Per esempio, se il campo etichette contiene [egitto cairo] ed -"any" selezionato, le immagini corrispondono se contengono -almeno una delle due etichette; se "all" selezionato, devono +"any" è selezionato, le immagini corrispondono se contengono +almeno una delle due etichette; se "all" è selezionato, devono contenerle entrambe.

        Si possono usare commenti, titoli e nomi di file e directory come -alternativa alle etichette. L'uso produttivo di etichette pu +alternativa alle etichette. L'uso produttivo di etichette può richiedere pianificazione, organizzazione e grande attenzione ai dettagli, e di conseguenza molto tempo. Anche la manutenzione -pu risultare difficile se si tratta di centinaia di immagini. -Commenti e nomi di file sono molto pi semplici, anche se meno +può risultare difficile se si tratta di centinaia di immagini. +Commenti e nomi di file sono molto più semplici, anche se meno precisi: basta nominare il file con il soggetto chiave, e aggiungere commenti o titolo con parole descrittive e adeguate. Non serve in questo caso avere un sistema elaborato di etichette, e le revisioni -sono pi semplici. Il sistema delle etichette ha il vantaggio -che una lista completa di quelle disponibili mantenuta +sono più semplici. Il sistema delle etichette ha il vantaggio +che una lista completa di quelle disponibili è mantenuta automaticamente e mostrata quando si esegue una ricerca, e aggiungere -etichette a una nuova immagine un'operazione semplice con il +etichette a una nuova immagine è un'operazione semplice con il clic del mouse.

        Se sono state aggiunge, rimosse o spostate immagini con metodi estranei a Fotoxx, assicurarsi di eseguire la procedura Strumenti->Sincronizza file per aggiornare l'indice di ricerca. La -procedura veloce se si usa il modo incrementale e meno di 1000 +procedura è veloce se si usa il modo incrementale e meno di 1000 immagini sono coinvolte.
        -

        @@ -2514,15 +2542,17 @@
        Queste due funzioni mostrano i metadati (dati aggiuntivi) dell'immagine corrente, se disponibili. I metadati EXIF contengono data e ora della foto, -velocit dell'otturatore, lunghezza focale, dimensione dei pixel +velocità dell'otturatore, lunghezza focale, dimensione dei pixel eccetera. Le macchine digitali memorizzano questi dati dentro l'immagine. I metadati IPTC contengono etichette (aggiunte con Fotoxx, Photoshop o altri programmi) e titoli (spesso per immagini pubblicate). Se un'immagine viene modificata e poi salvata, i metadati vengono aggiornati e salvati nella nuova immagine.
        -
        La -funzione Vedere informazioni (breve) mostra i dati pi +
        + +La +funzione Vedere informazioni (breve) mostra i dati più importanti, inclusi data e ora, esposizione, lunghezza focale (reale ed equivalente a 35 mm), etichette aggiunte dall'utente e punteggio, commenti, titolo, e una cronistoria delle manipolazioni che Fotoxx ha @@ -2530,74 +2560,70 @@ tutti i dati disponibili.

        + Fotoxx usa i seguenti metadati EXIF / IPTC:
        - - - + - - - - - - + + - - + - - + + - -
            Nome chiave (Key Name)
        -
        Uso di / con Fotoxx
        -
            Date/Time Original
        - +
           + Date/Time Original
        Modifica etichette - Data immagine
        - +
        Modifica etichette - Data +immagine
            Keywords
        - +
           + Keywords
        Modifica etichette - Etichette attuali
        - +
        Modifica etichette - +Etichette attuali
            Rating
        -
        Modifica etichette - Valutazione (punteggio)
        -
            User Comments
        - +
            User +Comments
        Modifica commenti
        -
            Caption-AbstractModifica titolo    +Caption-AbstractModifica +titolo
            Edit Status
        - +
            Edit +Status
        Cronistoria delle manipolazioni eseguite con Fotoxx
        - +
        Cronistoria delle +manipolazioni eseguite con Fotoxx
            (altro)
        -
        Modifica informazioni / Elimina informazioni
        - +
        Modifica informazioni / +Elimina informazioni
        @@ -2605,88 +2631,99 @@
        -Modifica informazioni
        +Modifica +informazioni
        Un valore specifico dei metadati -(metadata ID / key) pu essere aggiunto (se legittimo) o +(metadata ID / key) può essere aggiunto (se legittimo) o modificato. Immettere il nome del metadato (chiave / key) e cliccare [Prendi] per prelevare il valore corrente, se esiste. Immettere il -nuovo valore e cliccare [Salva] per aggiornare il dato. Si pu -immettere la chiave in minuscolo e senza spazi, cio il dato -EXIF "User Comment" pu essere scritto pi facilmente -come "usercomment". Questa finestra pu essere lasciata aperta: -il valore della chiave specificata sar aggiornato +nuovo valore e cliccare [Salva] per aggiornare il dato. Si può +immettere la chiave in minuscolo e senza spazi, cioé il dato +EXIF "User Comment" può essere scritto più facilmente +come "usercomment". Questa finestra può essere lasciata aperta: +il valore della chiave specificata sarà aggiornato automaticamente ogni volta che una nuova immagine viene caricata, e -pu essere modificato e salvato, se desiderato.
        +può essere modificato e salvato, se desiderato.


        -Elimina informazioni
        +Elimina +informazioni
        Questa funzione permette di eliminare un valore (chiave) specifico dei metadati, oppure tutti i metadati insieme. Immettere un nome di chiave in minuscolo, senza -spazi, cio "usercomment" per indicare la chiave EXIF "User +spazi, cioé "usercomment" per indicare la chiave EXIF "User Comment".

        -
        Men Seleziona
        +
        + +Menù +Seleziona

        + Introduzione
        + Le funzioni di editing si applicano di solito all'intera immagine, ma - possibile modificare solo una parte dell'immagine e lasciare -il resto invariato. Se un'area pi piccola stata +è possibile modificare solo una parte dell'immagine e lasciare +il resto invariato. Se un'area più piccola è stata selezionata, le funzioni di Ritocco e Arte riguarderanno solo -quell'area. Altre funzioni ignorano la selezione. Un'area pu +quell'area. Altre funzioni ignorano la selezione. Un'area può essere selezionata prima di cominciare una funzione di modifica, oppure -anche durante. L'area selezionata attiva immediatamente; i +anche durante. L'area selezionata è attiva immediatamente; i ritocchi precedenti sono mantenuti, e i ritocchi successivi si applicheranno solo entro l'area. Se un'altra funzione di manipolazione -viene richiamata, l'area selezionata rimane attiva, cos - possibile eseguire una serie di modifiche sull'area.
        +viene richiamata, l'area selezionata rimane attiva, così +è possibile eseguire una serie di modifiche sull'area.


        +

        Seleziona

        -
        Con -la finestra di dialogo, se c' gi un'area selezionata, -il suo contorno verr mostrato. Si pu continuare a +
        + +Con +la finestra di dialogo, se c'è già un'area selezionata, +il suo contorno verrà mostrato. Si può continuare a modificare tale area o usare [Elimina] per scartarla e iniziare una nuova area. Selezionare uno dei sei metodi (spiegati dopo) e procedere alla definizione. Togliere la spunta da "Abilita mouse" per sospendere l'operazione e rendere disponibile il mouse per ingrandire o spostare l'immagine su schermo. Rimettere la spunta per riprendere l'operazione. Il pulsante [Nascondi] rimuove il contorno (per migliorare la -visibilit dell'immagine e la dissolvenza dei margini). Usare il +visibilità dell'immagine e la dissolvenza dei margini). Usare il pulsante [Visualizza] per mostrare di nuovo il contorno. La finestra -pu essere chiusa e riaperta successivamente per riprendere a +può essere chiusa e riaperta successivamente per riprendere a modificare la stessa area o definirne una nuova.

        -Ci sono sei metodi (descritti -sotto) per racchiudere uno o pi zone che apparterranno all'area +Ci sono cinque metodi (descritti +sotto) per racchiudere uno o più zone che apparterranno all'area finale. Questi spazi chiusi saranno soggetti a modifiche future -(luminosit, colore, ecc.). Questi sei metodi possono essere +(luminosità, colore, ecc.). Questi metodi possono essere usati in qualunque ordine per definire zone da includere o eslcudere. Sceglierli con gli appositi bottoni:

        -    Rettangolo: trascinare il mouse per disegnare una zona rettangolare.
        -    Ellisse: trascinare il mouse per racchiudere una zona ellittica.
        +    Rettangolo: trascinare il mouse per disegnare una +zona rettangolare.
        +    Ellisse: trascinare il mouse per racchiudere una +zona ellittica.
            Mano libera: cliccare per disegnare linee, o trascinare per disegnare curve, in modo da racchiudere uno spazio.
            Segui bordi: cliccare lungo il bordo di un oggetto per disegnare linee che seguano un contorno, o trascinare per disegnare a mano libera.
        -    Selezione col mouse: include o esclude una zona circolare centrata sul puntatore (con raggio impostato)
        -    Selezione per colore: seleziona una piccola zona +    Selezione col mouse: seleziona una piccola zona intorno al mouse, e si espande alle aree adiacenti aventi colori simili.

        I paragrafi successivi spiegano in dettaglio ogni metodo.
        @@ -2696,38 +2733,43 @@ trascinare il mouse da un angolo a quello opposto dell'area da selezionare. Un rettangolo viene disegnato per racchiudere l'area. Cliccare col destro per cancellare e riprovare. Ripetere il processo -per selezionare pi aree rettangolari.

        +per selezionare più aree rettangolari.


        -Ellisse: identico al rettangolo, ma disegna un ellisse inscritto nel rettangolo.
        +Ellisse: è identico al rettangolo, ma +disegna un ellisse inscritto nel rettangolo.

        -Disegno a mano libera: +Disegno a +mano libera: trascinare il mouse (pulsante sinistro) per disegnare a mano libera una curva, oppure cliccare per creare una linea dall'ultimo punto a quello cliccato. Continuare intorno al bersaglio fino a circondarla di curve e linee interconnesse. Cliccare con il destro per rimuovere linee precedenti (errate) e ridisegnarle. Un clic col destro rimuove linee precedenti fino a 50 pixel; cliccare col destro ripetutamente per -rimuovere ancora di pi. Una nuova linea creata cliccando si +rimuovere ancora di più. Una nuova linea creata cliccando si connette sempre all'estremo della linea precedente. Una nuova linea creata trascinando si connette a quella precedente se iniziata vicino -all'estremo; se iniziata pi distante, una linea sconnessa -verr creata. Si pu iniziare una curva da distante, e +all'estremo; se iniziata più distante, una linea sconnessa +verrà creata. Si può iniziare una curva da distante, e dirigerla all'indietro per incontrare la vecchia linea. Se una linea creata cliccando si connette automaticamente a un punto non desiderato -(cio, non si vuole connetterla all'ultima linea), cliccare col +(cioé, non si vuole connetterla all'ultima linea), cliccare col destro e usare il trascinamento per iniziare una nuova sequenze di -linee. Un trascinamento col bottone destro pu essere usato per -cancellare piccoli segmenti: puntare col destro vicino a una linea da aggiustare, poi trascinare.
        -Alla fine dell'operazione, un'area deve essere chiusa interamente, senza crepe. Queste +linee. Un trascinamento col bottone destro può essere usato per +cancellare
        piccoli segmenti: puntare col destro vicino a +una linea da aggiustare, poi trascinare.
        +Alla fine dell'operazione, un'area deve essere chiusa interamente, +senza crepe. Queste interruzioni possono essere difficili da trovare e correggere, -perci lavorare a ingrandimento 100% e prestare attenzione. +perciò lavorare a ingrandimento 100% e prestare attenzione
        . Una serie di linee connesse automaticamente non lasceranno interruzioni, ma una deviazione da questa sequenza probabilmente -s. Per ridurre l'eventualit, usare sormonti o incroci in modo deliberato quando si connettono le linee.
        +sì. Per ridurre l'eventualità, usare +sormonti o incroci in modo deliberato quando si connettono le linee.

        Segui bordi: @@ -2735,66 +2777,62 @@ punto immesso e la posizione cliccata vengono trovati e connessi. Funziona bene su contorni puliti non troppo irregolari. Contorni frastagliati e confusi non funzionano bene e il disegno a mano libera -pu essere richiesto per avere maggiore precisione. Le regole +può essere richiesto per avere maggiore precisione. Le regole per connettere le linee sono le stesse viste prima. Il trascinamento del mouse invece dei clic funziona come il disegno a mano libera, -cos si possono usare i due metodi insieme.
        +così si possono usare i due metodi insieme.

        -
        -Selezione col mouse:
        -immettere un valore nel capo del raggio; un cerchio di raggio corrispondente apparir intorno al puntatore. Un clic o trascinamento sinistro -selezioner tutti i pixel dentro al cerchio, e un clic o -trascinamento destro deselezioner gli stessi pixel. Usare un -raggio grande per racchiudere velocemente grandi spazi, e uno piccolo -per seguire attentamente il contorno di un oggetto. Per aree -selezionate con uno dei due metodi di disegno, la deselezione non -funzioner a meno che l'area non sia stata terminata (con il -pulsante [Termina]): solo allora il mouse pu distinguere i -pixel selezionati. Semplicemente terminare l'area che si intende in -seguito espandere o riducere con questo metodo.
        +

        -Selezione per colore: -il campo "raggio" definisce un cerchio intorno al puntatore del mouse. + +Selezione col mouse:il +campo [Raggio del mouse] definisce un cerchio intorno al puntatore del +mouse. Cliccare il bottone sinistro nell'immagine per indicare un gruppo di -pixel da confrontare. La grandezza del gruppo impostata da -"raggio" e la similitudine impostata da "similarit" -(100 indica similitudine completa). Le aree adiacenti con pixel simili -a quelli entro il raggio saranno selezionati e mostrati. Un raggio -maggiore o una similarit inferiore selezioneranno pi -pixel. Se il mouse trascinato o cliccato dentro l'area -selezionata, questa verr espansa per includere i pixel +pixel come riferimento. Entro la [Distanza di ricerca] dal mouse, +qualsiasi pixel che abbia un colore simile a un pixel contenuto nel +cerchio verrà selezionato. Il valore [Distanza di ricerca] viene +moltiplicato per il [Raggio del mouse] per definire un cerchio entro il +quale cercare pixel simili. La similitudine richiesta è +impostata da [Corrispondenza colore], dove 100 indica similitudine +perfetta. Un raggio +maggiore o una similarità inferiore selezioneranno più +pixel. Se il mouse è trascinato o cliccato dentro l'area +selezionata, questa verrà espansa per includere i pixel residenti dentro il raggio. Trascinare su nuove aree da includere, o sopra isole escluse da includere. Notare che l'area si espande. Se si seleziona troppo, cliccare col destro per rimuovere l'ultima selezione; ripetere per rimuovere ulteriori selezioni. Ridurre o aumentare la -similarit per avere un controllo pi fine: la selezione -si espander pi lentamente e rimarr pi -vicina alla posizione del mouse. Il raggio della selezione +similarità per avere un controllo più fine: la selezione +si espanderà più lentamente e rimarrà più +vicina alla posizione del mouse. Il raggio della selezione è limitato a 3 volte il raggio del mouse; questo significa che un raggio -piccolo pu essere usato per inseguire un bordo e selezionare +piccolo può essere usato per inseguire un bordo e selezionare pixel vicini al bordo con buona precisione. Passare a un raggio -pi ampio per selezionare aree pi grandi dopo che il -lavoro fine stato completato. Se l'opzione "confinamento" - abilitata, allora i pixel gi selezionati agiranno come +più ampio per selezionare aree più grandi dopo che il +lavoro fine è stato completato. Se l'opzione "confinamento" +è abilitata, allora i pixel già selezionati agiranno come una barriera alla propagazione della nuova selezione. Questo talvolta - utile, per esempio se una selezione esistente -corretta e si vuole estenderla all'interno o da un'altra direzione. -Usare il trascinamento col bottone destro per deselezionare. +è utile, per esempio se una selezione esistente è +corretta e si vuole estenderla all'interno o da un'altra direzione. Il +pulsante destro del mouse funziona come quelli sinistro ma +de-seleziona, sempre basandosi sulla similarità di pixel vicini. Probabilmente serve un po' di esercizio per usare efficientemente -questa modalit.
        +questa modalità.

        Abilita mouse: se contrassegnata, questa casella impone che il mouse sia gestito dall'operazione in corso (in questo caso, operazioni di selezione). Se -la casella non contrassegnata il mouse pu essere usato +la casella non è contrassegnata il mouse può essere usato per variare l'ingrandimento o lo scorrimento dell'immagine. Lavorando -con aree pi grosse della loro porzione visibile, si pu +con aree più grosse della loro porzione visibile, si può alternare tra la selezione e la variazione della vista.

        -Larghezza di sfumatura: +Larghezza di +sfumatura: modifiche fatte entro un'area definita possono essere miscelate con la parte d'immagine all'esterno su una distanza chiamata "larghezza di sfumatura". All'esterno del bordo della selezione, l'immagine rimane @@ -2802,63 +2840,64 @@ l'immagine viene manipolata. A distanze intermedie, i pixel vengono modificati parzialmente: risultano in una miscela tra l'immagine originale e il risultato teorico della manipolazione, con una -gradazione relativa alla distanza. L'effetto una sfumatura di +gradazione relativa alla distanza. L'effetto è una sfumatura di transizione tra l'immagine originale e la parte modificata. Usare questo campo per selezionare la larghezza di questa striscia per l'operazione corrente e quelle successive. Una larghezza di zero imposta un margine assoluto per l'area di selezione. Incrementando la -larghezza si ottengono modifiche pi dolci e transizioni meno +larghezza si ottengono modifiche più dolci e transizioni meno distinguibili. Cambiare questo valore per la prima volta dopo aver impostato un'area di selezione comporta il ricalcolo della distanza per -ogni pixel entro l'area. Ci normalmente veloce (pochi -secondi), ma pu richiedere diversi minuti se l'area +ogni pixel entro l'area. Ciò è normalmente veloce (pochi +secondi), ma può richiedere diversi minuti se l'area è grande e ha una geometria complessa (un contorno molto lungo). Quando un'area viene modificata o invertita, il calcolo eseguito diventa inutile e deve essere ripetuto, se si vuole la sfumatura. Se il bordo di un'area sta entro i 4 pixel dal bordo dell'immagine, non viene -pi considerato come bordo per la sfumatura. Se un'area contiene +più considerato come bordo per la sfumatura. Se un'area contiene una porzione del bordo dell'immagine, e non si vuole sfumare lungo -questo bordo (questo il caso normale), assicurarsi che il +questo bordo (questo è il caso normale), assicurarsi che il bordo della selezione sia strettamente vicino (coincidente) con il bordo dell'immagine.

        -Visualizza / Nascondi: -usare [Nascondi] per nascondere il contorno della selezione. Ci - utile quando si usa una funzione di modifica, per vederne +Visualizza / +Nascondi: +usare [Nascondi] per nascondere il contorno della selezione. Ciò +è utile quando si usa una funzione di modifica, per vederne meglio gli effetti senza l'interferenza delle linee di selezione. Usare [Visualizza] per mostrare di nuovo il contorno della selezione e riprendere a variare l'area.

        - -Colore: alterna il colore usato per disegnare i bordi dell'area, tra rosso, verde e nero.
        +Colore: alterna il colore usato per +disegnare i bordi dell'area, tra rosso, verde e nero.

        Termina: quando si ha finito di selezionare gli spazi chiusi, usare questo -pulsante per completare il processo. Una finestrella chieder di +pulsante per completare il processo. Una finestrella chiederà di cliccare dentro ogni spazio chiuso, in sequenza. Questa azione esegue una ricerca di tutti i pixel all'interno dello spazio chiuso; tali pixel vengono riconosciuti e ricordati. Lo spazio chiuso viene temporaneamente colorato di modo che si possa vedere esattamente quali parti dell'immagine sono selezionate. La finestra di dialogo -mostrer lo stato dell'elaborazione: "successo" o "il contorno - discontinuo". Se c' un'interruzione nel contorno, +mostrerà lo stato dell'elaborazione: "successo" o "il contorno +è discontinuo". Se c'è un'interruzione nel contorno, viene fatto un tentativo per mostrare dove essa si trova: si -vedr un linea che parte dallo spazio colorato per incontrare il -lato di un rettangolo immaginario che racchiude la porzione. Pu +vedrà un linea che parte dallo spazio colorato per incontrare il +lato di un rettangolo immaginario che racchiude la porzione. Può essere possibile seguire questa linea fino all'interruzione, ma se -l'area complessa trovare la crepa pu essere difficile. -Ogni uso di [Termina] produrr un risultato differente che -pu condurre alla crepa. Ispezionare attentamente il contorno +l'area è complessa trovare la crepa può essere difficile. +Ogni uso di [Termina] produrrà un risultato differente che +può condurre alla crepa. Ispezionare attentamente il contorno dell'area, vicino al buco, e usare [Termina] di nuovo. Un'area non - funzionante fino a che non terminata con successo. -Qualsiasi area chiusa pu essere selezionata, anche se non +è funzionante fino a che non è terminata con successo. +Qualsiasi area chiusa può essere selezionata, anche se non disegnata direttamente: per esempio, selezionando un'area a forma di -ciambella con un buco al centro, sar poi possibile includere -anche il buco, fin tanto che esso delimitato da pixel inclusi +ciambella con un buco al centro, sarà poi possibile includere +anche il buco, fin tanto che esso è delimitato da pixel inclusi in una selezione.

        @@ -2867,145 +2906,159 @@ selezionata, eccetto la parte che era selezionata in precedenza. Usando la funzione due volte di file si ritorna alla selezione precedente. L'inversione dell'area comporta il ricalcolo della sfumatura, se questa - richiesta.

        +è richiesta.


        -Abilita / Disabilita: -disabilita l'area corrente senza cancellare per i suoi dati, di +Abilita / +Disabilita: +disabilita l'area corrente senza cancellare però i suoi dati, di modo che possa essere riattivata in seguito. Questo permette di alternare modifiche entro la selezione e sull'immagine intera.

        -Elimina: rimuove la selezione in modo permanente.
        +Elimina: rimuove la selezione in modo +permanente.


        -Seleziona -> Visualizza / Nascondi
        +Seleziona +-> Visualizza / Nascondi
        Mostra o nasconde il contorno -della selezione corrente. Nasconderlo utile durante il -ritocco, poich pi facile giudicare l'effetto -delle modifiche. Questa scelta di visualizza/nascondi +della selezione corrente. Nasconderlo è utile durante il +ritocco, poiché è più facile giudicare l'effetto +delle modifiche. Questa scelta di visualizza/nascondi è disponibile anche nella finestra di dialogo Seleziona.


        -Seleziona -> Abilita / Disabilita
        Abilita +Seleziona +-> Abilita / Disabilita
        + +Abilita e Disabilita l'area (selezione) corrente (mantenendo i dati per poterla riattivare in seguito). Permettono di alternare modifiche entro la selezione e sull'immagine intera. Le funzioni sono disponibili pure nella finestra di dialogo della Seleziona.

        -
        Inverti
        + +
        + +Inverti
        Inverte la selezione corrente: -l'immagine intera selezionata, tranne l'area/selezione +l'immagine intera è selezionata, tranne l'area/selezione corrente. Usando la funzione due volte di fila si torna alla situazione -di partenza. Se stata richiesta una larghezza di sfumatura, il -calcolo va ripetuto. La funzione disponibile anche nella +di partenza. Se è stata richiesta una larghezza di sfumatura, il +calcolo va ripetuto. La funzione è disponibile anche nella finestra di dialogo Sleziona.

        -
        Elimina
        -Elimina permanentemente l'area/selezione. E' disponibile anche nella finestra Seleziona.
        +Elimina permanentemente +l'area/selezione. E' disponibile anche nella finestra Seleziona.

        -
        Copia / +
        + +Copia / Incolla

        -Copia:
        la selezione corrente viene copiata (ricordata) in memoria.
        +Copia:
        la selezione +corrente viene copiata (ricordata) in memoria.

        Incolla:
        l'area salvata precedentemente (i pixel copiati con la funzione Copia) -viene incollata nell'immagine. Pu essere spostata trascinandola +viene incollata nell'immagine. Può essere spostata trascinandola con il mouse; Usare i pulsanti [Resize] e [Angolo] per variare dimensione e angolo di rotazione. Impostare il cursore [Edge blend] se si desidera una sfumatura lungo il bordo dell'oggetto incollato. Quando finito cliccare il pulsante [Fatto]. L'area appena incollata diventa la nuova selezione: le successive modifiche saranno confinate entro -quest'area, che pu essere cancellata, disabilitata o modifcata +quest'area, che può essere cancellata, disabilitata o modifcata (in particolare la Larghezza di sfumatura).

        -
        -Carica da file / Salva
        +Carica da +file / Salva
        -Se un'area di selezione -attiva o stata copiata tramite Seleziona->Copia, pu +Se un'area di selezione è +attiva o è stata copiata tramite Seleziona->Copia, può essere salvata in un file immagine usando Seleziona->Salva -(occorrer inserire un nome di file <nomefile>). Due file +(occorrerà inserire un nome di file <nomefile>). Due file sono salvati: l'immagine (i contenuti dell'area) nel file <nomefile>.tiff mentre le informazioni di trasparenza nel file <nomefile>.info. Questi file si troveranno nella directory /home/<utente>/.fotoxx/saved_areas/. Usare Seleziona->Carica da file per scegliere un'area salvata (scegliere il file TIFF), che -sar immessa nell'immagine dove potr essere spostata e +sarà immessa nell'immagine dove potrà essere spostata e variata nell stesso modo visto per Copia/Incolla.


        -
        -Immagine intera
        +Immagine +intera

        + E' talvolta utile applicare un -ritocco in modo controllato dalla luminosit, per esempio +ritocco in modo controllato dalla luminosità, per esempio applicare la riduzione del disturbo su aree scure senza toccare quelle -chiare. Per fare questo, usare il men Seleziona->Immagine -intera. Scegliere [Luminosit] o uno deicolori RGB come +chiare. Per fare questo, usare il menù Seleziona->Immagine +intera. Scegliere [Luminosità] o uno deicolori RGB come controllore. Il grafico editabile controlla come i ritocchi successivi verranno applicati all'immagine. L'asse orizzontale segue la -luminosit di un pixel da scuro a chiaro (o uno dei colori RGB) +luminosità di un pixel da scuro a chiaro (o uno dei colori RGB) da 0 a 100%. L'asse verticale governa quanto forte un ritocco viene applicato al pixel corrispondente. Un valore piccolo (curva bassa) minimizza l'effetto, e un valore grande lo massimizza. Per esempio: -applicare la mappatura di tonalit soprattutto sui pixel scuri: +applicare la mappatura di tonalità soprattutto sui pixel scuri: usare Seleziona->Immagine intera e trascinare la curva in modo che sia alta verso sinistra (pixel scuri) e bassa nel centro e a destra. -Poi, usare Ritocco->Mappa tonalit per applicare l'effetto +Poi, usare Ritocco->Mappa tonalità per applicare l'effetto alle aree scure. Si possono modificare entrambe le curve mentre si osserva il risultato.


        -
        -Seleziona e modifica
        +Seleziona e +modifica

        + Usare questa funzione in combinazione con una di ritocco. Specificare un raggio per il mouse e i fattori di potenza per il centro e il bordo distante dal centro. Poi, -richiamare una funzione di ritocco se non gi attiva. Il -puntatore sar circondato da un cerchio dal raggio specificato. +richiamare una funzione di ritocco se non già attiva. Il +puntatore sarà circondato da un cerchio dal raggio specificato. Quando il mouse (puntatore) viene trascinato sopra un'area dell'immagine, la funzione di ritocco viene applicata all'interno del -cerchio. L'intensit del ritocco regolata dai fattori +cerchio. L'intensità del ritocco è regolata dai fattori di forza (centro e bordo). Di solito si usa un valore grande al centro -e zero al bordo, indicando che l'intensit del ritocco -sar massimo al centro e sfumer gradualmente fino a zero +e zero al bordo, indicando che l'intensità del ritocco +sarà massimo al centro e sfumerà gradualmente fino a zero al bordo. Trascinando il mouse sulla stessa area ripetutamente, le modifiche vengono lentamente accumulate. Per esempio, se la funzione - Luminosit e colore, e la curva impostata a un -valore alto, l'immagine verr lentamente illuminata nella zona +è Luminosità e colore, e la curva è impostata a un +valore alto, l'immagine verrà lentamente illuminata nella zona dove il mouse viene trascinato. Questo si chiama "Dodge and burn" in altri programmi, ma in Fotoxx anche altre funzioni possono essere usate, per esempio mappatura del tono o sfocatura. Usare [Annulla] e @@ -3014,36 +3067,36 @@ produrre cambiamenti veloci (con controllo poco preciso). Trascinare il bottone destro del mouse per ridurre il ritocco o, insistendo, per cancellarlo del tutto. Quando finito con una funzione di ritocco in una -o pi zone, usare il pulsante [Fatto] per completare la +o più zone, usare il pulsante [Fatto] per completare la modifica. Usare il pulsante [Azzera area] per escludere l'area attiva -che stata lasciata fuori dal trascinamento.  Se si lascia +che è stata lasciata fuori dal trascinamento.  Se si lascia l'area attiva e s'inizia una nuova funzione di ritocco, i risultati -saranno impredicibili. Una procedura suggerita : 1 - richiamare +saranno impredicibili. Una procedura suggerita è: 1 - richiamare [Seleziona e modifica]; 2 - richiamare la funzione di ritocco con i -suoi parametri iniziare (l'effetto sull'immagine sar nullo -poich nessun trascinamento stato eseguito); 3 - +suoi parametri iniziare (l'effetto sull'immagine sarà nullo +poiché nessun trascinamento è stato eseguito); 3 - trascinare il mouse sulle zone d'interesse e osservare il risultato; 4 - regolare le impostazioni della funzione di ritocco; 5 - alternare i due passi precedenti. Questo metodo di "disegnare" un ritocco in modo -incrementale pu migliorare le aree desiderate in fretta e -facilmente. Funziona con qualsiasi ritocco che pu usare la -selezione; le pi utili sono Luminosit e colore, e Mappa -tonalit.
        +incrementale può migliorare le aree desiderate in fretta e +facilmente. Funziona con qualsiasi ritocco che può usare la +selezione; le più utili sono Luminosità e colore, e Mappa +tonalità.


        -Men Ritocco

        +Menù Ritocco


        Bilanciamento del bianco

        -Questa funzione un modo +Questa funzione è un modo facile per rimuovere una predominanza di colore, quando l'immagine ha una sfumatura generale verso il blu o il rosso. Avviata la funzione, cliccare un punto dell'immagine che non dovrebbe essere colorato: un punto bianco o grigio. Se il punto cliccato ha un colore diverso da -bianco o grigio, sar considerato come misura del falso colore -generale, e tale quantit di colore sar sottratta -dall'immagine intera. Si pu cliccare diverse aree e vedere +bianco o grigio, sarà considerato come misura del falso colore +generale, e tale quantità di colore sarà sottratta +dall'immagine intera. Si può cliccare diverse aree e vedere l'impatto istantaneamente. Cliccare [Fatto] quando soddisfatti, o [Annulla] per rinunciare.

        @@ -3051,76 +3104,85 @@
        -Trasforma in negativo
        +Trasforma in +negativo
        + +Usare questa funzione per +generare un negativo in bianco e nero o a colori, o convertire un +negativo in un positivo.
        -Usare questa funzione per generare un negativo in bianco e nero o a colori, o convertire un negativo in un positivo.
        Selezionare unodei quattro bottoni:
        -
            black/white +    +black/white positive - converte una foto a colori in una in bianco e nero
        -    - black/white negative - converte in bianco e nero e poi inverte
           + black/white negative - converte in bianco e nero e poi inverte
        +     color positive - non ha effetto: annulla le altre trasformazioni
        +    + color negative - genera il negativo a colori (rimpiazza ogni +colore RGB con il suo complementare)
        + - color negative - genera il negativo a colori (rimpiazza ogni colore RGB con il suo complementare)

        -
        Color negative: ogni colore RGB color viene rimpiazzato dal "massimo meno il valore attuale". Se i -colori RGB (in % sul massimo) sono 20/40/60, il negativo avr +colori RGB (in % sul massimo) sono 20/40/60, il negativo avrà 80/60/40. Eseguire l'operazione due volte riporta ai colori originali. L'operazione genera i colori complementari: il rosso diventa ciano, il verde magenta, e il blu giallo.

        +

        -Normalizza la luminosit

        +Normalizza la luminosità

        -Questo un metodo facile +Questo è un metodo facile e veloce per compensare una limitazione comune in fotografia: non -c' abbastanza escursione di luminosit per mostrare bene +c'è abbastanza escursione di luminosità per mostrare bene i dettagli in ogni area. Questa funzione cerca dove ci sono troppi -pixel con luminosit abbastanza simile e la distanzia, +pixel con luminosità abbastanza simile e la distanzia, compremendo i valori di altre aree per fare posto. Tecnicamente, la -distribuzione di luminosit viene fatta pi uniforme -(appiattita). Muovere il cursore osservando l'immagine, che pu +distribuzione di luminosità viene fatta più uniforme +(appiattita). Muovere il cursore osservando l'immagine, che può ritardare un momento. Alcune immagini mostreranno buoni risultati, altre forse no, o anche peggiorare. Usare questa funzione entro una -selezione spesso molto efficace; una sfumatura ([Larghezza di -sfumatura] in Seleziona) pu essere necessaria per nascondere il +selezione è spesso molto efficace; una sfumatura ([Larghezza di +sfumatura] in Seleziona) può essere necessaria per nascondere il contorno dell'area modificata.



        -Luminosit e colore
        - +Luminosità e colore

        + -Si usa per cambiare luminosit, contrasto, saturazione e bilanciamento fra i colori (relativo ai livelli RGB).
        -Si possono variare i livelli in funzione della luminosit dei -pixel dell'immagine originale; per esempio, si pu aumentare la -saturazione nelle aree pi scure lasciando intatte quelle -pi chiare.
        -Vi sono cinque curve per i cinque attributi di luminosit, +Si usa per cambiare luminosità, contrasto, saturazione e +bilanciamento fra i colori (relativo ai livelli RGB).
        +Si possono variare i livelli in funzione della luminosità dei +pixel dell'immagine originale; per esempio, si può aumentare la +saturazione nelle aree più scure lasciando intatte quelle +più chiare.
        +Vi sono cinque curve per i cinque attributi di luminosità, saturazione, e bilanciamento (livelli di rosso, verde e blu). I bottoni selezionano quale curva si vuole vedere e variare. La curva rappresenta un valore (in verticale sull'asse Y) per ogni livello di -luminosit (in orizzontale sull'asse X). La posizione verticale -centrale neutra - non modifica nessun valore, mentre una curva -spostata pi in alto amplifica l'attributo, e pi in -basso lo riduce. Inizialmente la curva piatta, e centrata -verticalmente: il risultato che l'immagine non viene alterata.
        +luminosità (in orizzontale sull'asse X). La posizione verticale +centrale è neutra - non modifica nessun valore, mentre una curva +spostata più in alto amplifica l'attributo, e più in +basso lo riduce. Inizialmente la curva è piatta, e centrata +verticalmente: il risultato è che l'immagine non viene alterata.
        Le curve possono essere trascinate con il mouse. Un punto di ancoraggio (quadratino nero) viene aggiunto alla curva quando viene tirata, e diventa un vincolo per i trascinamenti successivi: la curva -continuer a passare attraverso questo punto anche se altre zone +continuerà a passare attraverso questo punto anche se altre zone della curva si spostano. Anche i punti di ancoraggio possono essere trascinati, o cancellati con un click del pulsante destro.
        L'immagine si aggiorna immediatamente quando si ritocca la curva: @@ -3130,34 +3192,35 @@ schiarire le zone scure, sollevare la parte sinistra della curva. I pulsanti [+++], [+-] eccetera possono essere usati per traslare la curva in diversi modi.
        -La curva di luminosit modifica tutti i livelli RGB con uno +La curva di luminosità modifica tutti i livelli RGB con uno stesso fattore (proporzionale). La saturazione cambia il livello (R, G o B) dominante in una direzione, e gli altri due nella direzione -opposta, cosicch la luminosit non cambia ma la tinta -s. Le curve dei tre colori cambiano un colore per volta. Per +opposta, cosicché la luminosità non cambia ma la tinta +sì. Le curve dei tre colori cambiano un colore per volta. Per esempio, se le aree scure hanno una tendenza al rosso, abbassare la parte sinistra della curva del rosso.
        -


        -Mappatura della luce
        +Mappatura +della luce

        + Questa funzione varia la -luminosit lungo l'immagine, con direzione e ampiezza -determinabili da curve modificabili. Si pu usare ci per +luminosità lungo l'immagine, con direzione e ampiezza +determinabili da curve modificabili. Si può usare ciò per compensare illuminazioni diseguali o vignette (angoli bui).
        La finestra di dialogo mostra due curve modificabili, orizzontale e -verticale. La curva orizzontale regola la luminosit +verticale. La curva orizzontale regola la luminosità orizzontalmente, e quella verticale verticalmente. Trascinare le curve nelle direzioni segnate con "+" e "-" per aumentare o diminuire la -luminosit nelle zone corrispondenti. Per rimuovere l'effetto -vignetta dagli angoli, spostare le quattro estremit delle curve +luminosità nelle zone corrispondenti. Per rimuovere l'effetto +vignetta dagli angoli, spostare le quattro estremità delle curve verso i segni "+", o anche spostando il centro delle curve verso il "-". Per illuminare l'angolo in alto a destra, trascinare l'estremo destro della curva orizzontale verso l'alto, e l'estremo superiore @@ -3171,55 +3234,57 @@
        -Expand Brightness
        +Expand +Brightness

        + Questa funzione allarga -l'intervallo di luminosit di una foto che non utilizza tutta +l'intervallo di luminosità di una foto che non utilizza tutta l'ampiezza disponibile, eventualmente rendendola meno contrastata. Si -pu vedere questo nella finestra di distribuzione della -luminosit. Se la distribuzione mostra scarse o assenti barre +può vedere questo nella finestra di distribuzione della +luminosità. Se la distribuzione mostra scarse o assenti barre agli estremi sinistro e destro, l'immagine potrebbe beneficiare di -un'espansione della luminosit. Questo si ottiene scurendo -ancora le zone gi scure, e schiarendo quelle chiare. Spostare i -cursori per aumentare rispettivamente la quantit di scuro e di +un'espansione della luminosità. Questo si ottiene scurendo +ancora le zone già scure, e schiarendo quelle chiare. Spostare i +cursori per aumentare rispettivamente la quantità di scuro e di chiaro mentre si osserva l'immagine.

        -
        -
        -Mappa tonalit
        +Mappa +tonalità

        -La mappatura di tonalit -aumenta l'intervallo di luminosit innalzando il contrasto + +La mappatura di tonalità +aumenta l'intervallo di luminosità innalzando il contrasto locale. E' utile specialmente per migliorare immagini HDR, ma -pu essere usata anche su altri immagini. Le immagini HDR spesso -sembrano "piatte" perch il contrasto tra pixel adiacenti - stato ridotto per accomodare il contrasto generale -nell'intervallo disponibile. La mappatura di tonalit accresce +può essere usata anche su altri immagini. Le immagini HDR spesso +sembrano "piatte" perché il contrasto tra pixel adiacenti +è stato ridotto per accomodare il contrasto generale +nell'intervallo disponibile. La mappatura di tonalità accresce il contrasto locale senza aumentare quello generale; si affida alla natura della visione umana: il contrasto entro un angolo piccolo viene -percepito maggiormente del contrasto su una visuale pi ampia. +percepito maggiormente del contrasto su una visuale più ampia. Inoltre questa funzione rivela piccoli dettagli (a basso contrasto) che sarebbero altrimenti difficili da notare.

        Si possono pure usare altri -metodi: regolando la curva di luminosit pu aumentare il -contrasto per un determinato intervallo di luminosit, +metodi: regolando la curva di luminosità può aumentare il +contrasto per un determinato intervallo di luminosità, eventualmente a spesa di altri. Appiattire la distribuzione della -luminosit pu distribuire il contrasto in modo -pi omogeneo. Anche un aumento di saturazione pu +luminosità può distribuire il contrasto in modo +più omogeneo. Anche un aumento di saturazione può aumentare i dettagli. Tutti questi metodi operano globalmente: tutti i pixel di un dato colore sono processati nello stesso modo. Mappa -tonalit invece processa ogni pixel in modo diverso, in -dipendenza della luminosit dei pixel intorno, ed -pi efficace nell'aumentare i dettagli e la luminosit +tonalità invece processa ogni pixel in modo diverso, in +dipendenza della luminosità dei pixel intorno, ed è +più efficace nell'aumentare i dettagli e la luminosità percepita.

        Nella finestra di dialogo la curva determina quanto il contrasto locale @@ -3227,61 +3292,64 @@ sinistra corrisponde ai pixel aventi poco contrasto, e la parte destra a quelli con molto contrasto. Sollevare la curva a sinistra per aumentare il contrasto dei pixel attualmente poco contrastati (ma -questo aumenter anche il rumore). Il cursore di +questo aumenterà anche il rumore). Il cursore di [Amplificazione] regola il calcolo interno, da nessuna amplificazione del contrasto al massimo possibile; se spostato troppo a destra, -l'immagine pu rivelare artifatti (raggi chiari o scuri) - se -ci accade, spostare il cursore indietro fino a farli sparire.
        -La curva pu essere trascinata con il mouse, e l'effetto +l'immagine può rivelare artifatti (raggi chiari o scuri) - se +ciò accade, spostare il cursore indietro fino a farli sparire.
        +La curva può essere trascinata con il mouse, e l'effetto sull'immagine si vede in pochi secondi, in dipendenza della sua grandezza e della potenza della CPU. Anche il cursore di amplificazione -abbisogna di alcuni secondi. Se si desidera pi contrasto, +abbisogna di alcuni secondi. Se si desidera più contrasto, innalzare la curva. Se aree uniformi (come il cielo) diventano disturbate, abbassare il lato sinistro della curva per ridurre il contrasto nelle zone uniformi. In alcuni casi il metodo migliore - selezionare aree differenti e processarle separatamente, -essere cio pi moderati per il cielo, e pi +è selezionare aree differenti e processarle separatamente, +essere cioé più moderati per il cielo, e più aggressivi sui particolari come muri di pietra.
        -


        +

        + +

        Correzione occhi rossi

        Questa funzione riduce l'effetto "occhi rossi" generato dal flash. Sono disponibili due metodi. Il primo - pi rapido ma non adatto a casi difficili -(quando la pupilla rossa quanto l'intero occhio). Il secondo -metodo pi versatile per richiede pi -cura e pi tempo.
        +è più rapido ma non è adatto a casi difficili +(quando la pupilla è rossa quanto l'intero occhio). Il secondo +metodo è più versatile però richiede più +cura e più tempo.


        + Per usare il primo metodo, cliccare col sinistro sull'occhio rosso una -o pi volte fino a quando si soddisfatti. Se l'area -scurita troppo piccola o scentrata, usare un click col destro -per annullare e poi riprovare. Se un occhio rosso impossibile +o più volte fino a quando si è soddisfatti. Se l'area +scurita è troppo piccola o scentrata, usare un click col destro +per annullare e poi riprovare. Se un occhio rosso è impossibile da correggere, cliccare col destro per annullare e passare al secondo metodo.

        + Il secondo metodo funziona meglio nei casi difficili, quando la -differenza di colore tra la pupilla e l'iride troppo piccola +differenza di colore tra la pupilla e l'iride è troppo piccola per essere rilevata automaticamente dall'algoritmo. Piazzare il puntatore sul centro dell'occhio rosso; mantenere pigiato il pulsante sinistro del mouse e trascinare in basso e a destra: un ellisse -puntinato circonder l'occhio rosso. Ripetere se necessario per +puntinato circonderà l'occhio rosso. Ripetere se necessario per avere l'occhio rosso abbastanza centrato nell'ellisse. Notare che la forma dell'ellisse dipende dalla direzione del trascinamento, che -permette un pi preciso contenimento del solo occhio rosso. +permette un più preciso contenimento del solo occhio rosso. Cliccare col sinistro, ripetutamente, mentre si osserva lo scurimento -dell'occhio rosso, e smettere quando abbastanza. Se si -esagera, la pupilla pu cominciare a scurirsi: cliccare il +dell'occhio rosso, e smettere quando è abbastanza. Se si +esagera, la pupilla può cominciare a scurirsi: cliccare il pulsante destro per annullare e ripetere se necessario.


        -
        Sfocatura immagine

        @@ -3289,16 +3357,16 @@ un'immagine. Ogni pixel viene miscelato con i vicini per ridurre le differenze, facendo i contorni confusi. Immettere un valore per il raggio e cliccare [Applica] per osservare i risultati. Un valore -piccolo miscela i pixel con gl'immediati vicini, e valori pi -grandi miscelano pixel pi distanti. Il contributo di ogni pixel -decresce con la distanza, sicch i pixel pi vicini danno -il maggiore contributo. Questa funzione utile per appianare -zone ruvide (specialmente la pelle). Si pu anche usare una +piccolo miscela i pixel con gl'immediati vicini, e valori più +grandi miscelano pixel più distanti. Il contributo di ogni pixel +decresce con la distanza, sicché i pixel più vicini danno +il maggiore contributo. Questa funzione è utile per appianare +zone ruvide (specialmente la pelle). Si può anche usare una selezione per limitare l'effetto al viso o una parte di esso. Con questo metodo si possono anche ridurre effetti a bande in zone come il -cielo (questo pu succedere se altre funzioni di manipolazione -della luminosit fanno allargare troppo la distribuzione, -rendendo le transizioni di luminosit visibili).
        +cielo (questo può succedere se altre funzioni di manipolazione +della luminosità fanno allargare troppo la distribuzione, +rendendo le transizioni di luminosità visibili).


        @@ -3307,78 +3375,96 @@ Contrasta immagine


        + Questa funzione acuisce un'immagine sfuocata. Tre metodi sono implementati: riconoscimento dei bordi, maschera di contrasto, e gradiente.
        Riconoscimento dei bordi: cerca i pixel adiacenti con la maggiore -differenza di luminosit (contrasto) e aumenta la differenza. -Ci ripetuto per diversi cicli, con la soglia di -differenza di luminosit decrementata a ogni ciclo.
        -Maschera di contrasto: un metodo veloce ed efficace presente
        anche in Gimp e altri programmi. Una descrizione tecnica pu essere trovata con Google.
        +differenza di luminosità (contrasto) e aumenta la differenza. +Ciò è ripetuto per diversi cicli, con la soglia di +differenza di luminosità decrementata a ogni ciclo.
        +Maschera di contrasto: un metodo veloce ed efficace presente
        anche in Gimp e altri programmi. Una +descrizione tecnica può essere trovata con Google.
        Gradiente: i pixel sono processati da sinistra a destra e dall'alto in -basso. La differenza di luminosit (contrasto) tra ogni pixel e +basso. La differenza di luminosità (contrasto) tra ogni pixel e i suoi vicini precedenti (sinistra e sopra) viene accresciuta, e la -luminosit viene modificata per corrispondere. Questo -cambiamento di luminosit viene propagato al pixel successivo -dove il processo ripetuto.
        +luminosità viene modificata per corrispondere. Questo +cambiamento di luminosità viene propagato al pixel successivo +dove il processo è ripetuto.

        + Il metodo di riconoscimento dei -bordi genera contorni pi aspri dove il contrasto alto -e contorni pi morbidi altrove, rendendolo buono per i ritratti +bordi genera contorni più aspri dove il contrasto è alto +e contorni più morbidi altrove, rendendolo buono per i ritratti (occhi evidenti, pelle liscia). Per immagini in parte contrastate e in parte sfumate (per esempio a causa di movimenti o problemi nella lunghezza di campo), il riconoscimento dei bordi agisce principalmente -sulle aree confuse, laddove Maschera di contrasto pu generare -aloni intorno a bordi gi contrastati. Il metodo del gradiente -lavora pi o meno bene come Maschera di contrasto per immagini +sulle aree confuse, laddove Maschera di contrasto può generare +aloni intorno a bordi già contrastati. Il metodo del gradiente +lavora più o meno bene come Maschera di contrasto per immagini leggermente sfuocate. Il valore del raggio limita la distanza massima dei pixel che sono modificati intorno a un bordo. Dovrebbe essere -piccolo per immagini leggermente sfuocate e pi grande per -immagini pi povere. La soglia sopprime i cambiamenti per i -pixel a basso contrasto: un valore pi alto riduce -l'amplificazione delle irregolarit di basso livello.
        +piccolo per immagini leggermente sfuocate e più grande per +immagini più povere. La soglia sopprime i cambiamenti per i +pixel a basso contrasto: un valore più alto riduce +l'amplificazione delle irregolarità di basso livello.


        + -Per il metodo di Riconoscimento dei bordi immettere i seguenti parametri:
        +Per il metodo di Riconoscimento dei bordi immettere i seguenti +parametri:

        + -   Cicli            numero di iterazioni
        +   Cicli       +     numero di iterazioni

           Riduzione   -riduzione della soglia di luminosit per ciclo; 80 vale 0,8
        +riduzione della soglia di luminosità per ciclo; 80 vale 0,8

        -   Soglia         soglia inferiore del cambiamento di luminosit
        +   Soglia         soglia inferiore +del cambiamento di luminosità


        + Per il metodo di maschera di contrasto immettere i seguenti parametri:
        + -   Raggio        distanza massima di modifica per i pixel intorno a un bordo
        +   Raggio        distanza +massima di modifica per i pixel intorno a un bordo

        -   Quantit     quantit di correzione: 100 = normale
        +   Quantità     quantità di +correzione: 100 = normale

        -   Soglia        
        soglia inferiore del cambiamento di luminosit
        +   Soglia        
        soglia inferiore del cambiamento di +luminosità

        + -FPer il metodo Gradiente di luminosit immettere i seguenti parametri:
        +FPer il metodo Gradiente di luminosità immettere i seguenti +parametri:

        + -   Quantit     quantit di correzione: 100 = normale
        +   Quantità    
        quantità di correzione: 100 = +normale
        -   Soglia         soglia inferiore del cambiamento di luminosit
        +   Soglia        
        soglia inferiore del cambiamento di +luminosità

        + Premere il pulsante del metodo voluto e attendere alcuni secondi il risultato. I valori d'ufficio sono quelli suggeriti come punto di partenza; regolarli e ripetere il -processo fino al risultato voluto. Si pu andare avanti e +processo fino al risultato voluto. Si può andare avanti e indietro fra i metodi per vedere quale funziona meglio per una data -immagine. Si pu anche usare una selezione per operare +immagine. Si può anche usare una selezione per operare differentemente su aree diverse.


        -
        Riduci disturbi

        @@ -3397,51 +3483,60 @@

        - + - - + - + - - - +
        Appiattire livelli di colore (1)I valori maggiori e minori dei pixel entro il raggio vengono moderati leggermente.
        - +
        Appiattire +livelli di colore (1)I valori maggiori e +minori dei pixel entro il raggio vengono moderati leggermente.
        Appiattire livelli di colore (2)Appiattire livelli di +colore (2) PI valori dei pixel entro il raggio vengono comparati con i valori Media e Sigma. Quelli scostati oltre un Sigma vengono corretti verso la Media.
        -
        Imposta luminosit media per colore
        - +
        Imposta luminosità +media per colore
        I pixel vengono impostati al valore medio dei vicini entro il raggio.
        - +
        I pixel vengono impostati +al valore medio dei vicini entro il raggio.
        Filtro superiore per colore
        -
        Filtro superiore per +colore
        +
        Rileva gli eccessi mediante la comparazione con una banda di pixel a una certa distanza. La distanza viene incrementata a passi partendo da 1 pixel -fino al limite del raggio.

        +fino al limite del raggio.
        + + + + +

        -Cancellazione intelligente
        +Cancellazione +intelligente

        + -Questa funzione pu essere usata per cancellare particolari che +Questa funzione può essere usata per cancellare particolari che possono rovinare una bella foto, come elettrodotti, spazzatura per terra, cartelli e simili. L'oggetto da cancellare viene coperto con -pixel presi dall'area circostante. A volte questo molto +pixel presi dall'area circostante. A volte questo è molto efficace (effetti collaterali quasi invisibili), a volte no. Funziona -al meglio con oggetti piccoli o stretti, cio inferiori ai venti +al meglio con oggetti piccoli o stretti, cioé inferiori ai venti pixel. Il controllo [Raggio] imposta la dimensione del cerchio intorno al puntatore che definisce l'area da cancellare. Trascinare il mouse per racchiudere tutto o una parte dell'oggetto da rimuovere; col @@ -3455,51 +3550,150 @@ sulla selezione corrente. Come per tutte le funzioni di editing, i pulsanti della barra [Annulla] e [Ripeti] possono essere usati per controllare le modifiche. Probabilmente si lavora meglio con -ingrandimenti del 200% o pi. Togliere la spunta ad [Abilita +ingrandimenti del 200% o più. Togliere la spunta ad [Abilita mouse] per scorrere un'immagine ingrandita. Il controllo [Sfuoca] -aggiunge una sfumatura per i pixel di rimpiazzo; questo pu +aggiunge una sfumatura per i pixel di rimpiazzo; questo può ridurre gli effetti collaterali, dato che i nuovi pixel possono essere -pi evidenti o avere pi contrasto. Cambiare +più evidenti o avere più contrasto. Cambiare l'impostazione di [Sfuoca] e ripetere [Esegui cancellatura]. Una -sfumatura di 0,5 o 1 pixel solitamente sufficiente.
        +sfumatura di 0,5 o 1 pixel è solitamente sufficiente.



        -Rimozione polvere
        +Rimozione +polvere
        + +
        -
        Le +Le immagini ricavate da scansioni possono avere molte macchioline scure: -ombre della polvere sull'originale. Questa funzione pu essere +ombre della polvere sull'originale. Questa funzione può essere usata per rimuovere molte di esse. Spostare i tre cursori fino a che il massimo numero di macchioline sia colorato in rosso, e poi premere [Esegui cancellatura] per eliminarle. Cliccare [Rosso] per ripristinare la vista del rosso, per regolare ancora i cursori e premere [Esegui cancellatura]. Il cursore [Limite dimensione raggio] limita la -dimensione dei possibili candidati (pi a destra, -pi si possono eliminare grosse macchie). il cursore -[Luminosit max] imposta una soglia per ignorare macchie non +dimensione dei possibili candidati (più è a destra, +più si possono eliminare grosse macchie). il cursore +[Luminosità max] imposta una soglia per ignorare macchie non abbastanza scure. Il cursore [Contrasto min] ignora le macchie che non -hanno abbastanza contrasto con le loro vicinanze. Il processo +hanno abbastanza contrasto con le loro vicinanze. Il processo è usualmente un compromesso; se le impostazioni non sono ottimali, dettagli come foglie di alberi possono essere eliminati, oppure grosse macchie possono essere lasciate dove sono. Differenti parti dell'immagine possono richiedere impostazioni diverse, per esempio il -cielo pu essere trattato pi aggressivamente del muro di -una casa. Si pu semplicemente invocare la funzione pi +cielo può essere trattato più aggressivamente del muro di +una casa. Si può semplicemente invocare la funzione più volte con diversi parametri per eliminare tutte le macchie. Oppure si possono eseguire selezioni e trattarle differentemente. Se alcune macchie sono persistenti, possono essere eliminate con la cancellazione intelligente.
        +
        +

        +
        +Correggi pixel difettosi (fissi al bianco o al nero)
        +
        +I sensori delle fotocamere +possono avere difetti che mostrano singoli pixel sempre luminosi o +sempre scuri; questo può affliggere on dei colori RGB o tutti e +tre. Ho visto un caso dove un gruppo di 3x3 pixel erano sempre troppo +rossi. Questa funzione può trovare tali pixel in una foto e +ripararli sostituendoli con pixel vicini.
        +
        +Selezionare la dimensione dei difetti da cercare: blocchi di 1 pixel, 4 +pixel (2x2), o 9 pixel (3x3). I difetti rilevati vengono marcati con +piccoli cerchi dal colore selezionabile bianco, nero o rosso. +Ingrandire per ispezionare i difetti e determinare se sono veri +difetti. Usare il cursore [Contrasto] per selezionarli con precisione: +se impostato troppo basso (troppo a destra), piccole macchie con grande +contrasto possono essere selezionate erroneamente; se impostato troppo +alto, veri difetti possono essere ignorati. Usare il pulsante [Applica] +per cancellare i difetti sull'immagine; se necessario si può +eseguire la funzione molte volte con impostazioni differenti. I pixel +correntemente cerchiati possono essere salvati su un file usando +[Salva]; questo file può essere usato in seguito per correggere +i difetti in altre immagini prese dalla stessa macchina: usare il +pulsante [Apri], selezionare il file, quindi cliccare [Applica] per +eseguire la correzione. Questa procedura (correggere un'immagine +caricando le posizioni difettose da un file) funziona solo se le due +immagini non sono state ritagliate o, se invece sì, solo se sono +state ritagliate in modo identico. Se, per trovare tutti i difetti, +diverse impostazioni devono essere usate, è possibile salvare i +difetti in più file differenti, e poi combinarli manualmente con +un editore di testi. Suggerisco quanto segue, per trovare tutti i +difetti facilmente: fotografare un foglio di carta o un muro bianchi +sottoesposti, di modo che il risultato sia un grigio uniforme. La foto +risultante può essere usata come immagine campione per trovare i +pixel difettosi sia scuri che luminosi o con colori falsati.

        -
        Men trasforma
        +
        + +
        +Modifica pixel
        +
        +
        +Questa funzione ritocca puntini individuali. Ci sono tre modi di operare: Seleziona (il colore), Dipingi, e Cancella.
        +Modo [Seleziona]: cliccare in un punto per prelevarne il colore, che sarà usato per dipingere (colore corrente).
        +Modo [Dipingi]: cliccare o trascinare nella foto per dipingere usando il colore corrente (prelevato prima).
        +Modo [Cancella]: cliccare o trascinare per ripristinare il colore originale.
        +Il pulsante [Colore] permette di scegliere un colore con un selettore, +e mostra sempre il colore corrente. Il controllo Raggio del pennello +imposta in pixel la dimensione dell'area interessata dai +clic/trascinamenti. I controlli di trasparenza impostano quanto +intensamente il nuovo colore viene trasferito ai pixel, al centro e ai +bordi del mouse. La trasparenza zero applica il colore subito e +completamente; trasparenze alte (90-99) applicano poco colore e +permettono di cambiare il colore gradualmente attraverso clic o +trascinamenti ripetuti (un po' come spruzzare colore da una certa +distanza). Anche il modo Cancellazione lavora in questo modo: con +trasparenza zero si ripristinano i pixel immediatamente, con +trasparenze alte i pixel riprendono il colore originario gradualmente. +[Annulla ultimo] annulla l'effetto dell'ultimo clic o trascinamento, e +può essere usato più volte in successione per annullare +l'ultimo, il penultimo e così via. La memoria per questi +annullamenti è limitata a 200 Mib, che può essere +raggiunta se si usa un pennello grosso (ogni cambiamento di ogni pixel +viene registrato). E' utile salvare l'immagine dopo ogni modifica +soddisfacente per liberare questa memoria. La quantità di +memoria disponibile viene mostrata nella finestra di dialogo, per +vedere quando il limite si avvicina. Se un'area di selezione è +attiva, le modifiche vengono confinate in quell'area; si può +selezionare un'area "per colore" e poi cambiare tale colore senza +curarsi dei bordi. NOTA: ingrandire l'immagine al 100% o +più per usare questa funzione; se i passi del mouse sono +maggiori della dimensione dei pixel e si usa un pennello piccolo, +alcuni pixel possono essere saltati.
        +
        +

        + +Menù +trasforma
        +
        +

        Ruota immagine
        + + + +rotate.jpg
        +
        Questa funzione +mostra un dialogo per ruotare l'immagine in senso orario (+) o +antiorario (-) in passi di 0,1, 1, 10 o 90 gradi. Se l'immagine +è inclinata, usare il mouse per trascinare il lato destro su o +giù per livellarla. Usare passi di 90 gradi per convertire una +foto da verticale a orizzontale o viceversa. Non c'è perdita +d'informazioni per rotazioni di 90 gradi; per altri angoli, la perdita +è di circa 1/2 pixel. La nuova immagine risulta espansa per +accomodare quella originale, ruotata, senza ridurre le dimensioni; per +esempio: una foto 100 x 100 ruotata di 45 gradi avrà dimensioni +di 141 x 141, e le aree inutilizzate saranno nere. Usare la funzione +[Ritaglia] per rimuovere questi margini estesi.
        +

          -

        @@ -3514,33 +3708,56 @@ Quando terminato, cliccare [Fatto] per tagliare via le parti esterne al rettangolo. La finestra di dialogo mostra le dimensioni e la proporzione correnti del rettangolo di ritaglio. Se la casella [Blocca -proporzioni] marcata, muovendo un angolo del rettangolo -sposter anche quello opposto per mantenere la proporzione. Si -pu anche trascinare dal centro del rettangolo per spostarlo +proporzioni] è marcata, muovendo un angolo del rettangolo +sposterà anche quello opposto per mantenere la proporzione. Si +può anche trascinare dal centro del rettangolo per spostarlo interamente senza modificarne le dimensioni. Se [Abilita mouse] non - marcato, il mouse pu essere usato per variare +è marcato, il mouse può essere usato per variare ingrandimento e posizione dell'immagine. Quando si spunta nuovamente -[Abilita mouse], il rettangolo pu essere disegnato nuovamente +[Abilita mouse], il rettangolo può essere disegnato nuovamente nelle nuove parti visibili. Si possono usare i pulsanti di regolazione di [Larghezza] e [Altezza] per impostare la dimensione in pixel: il -rettangolo di selezione si adatter ai valori.
        +rettangolo di selezione si adatterà ai valori.

        -

        +
        + +
        + I sei pulsanti permettono di selezionare un rapporto larghezza/altezza preconfigurato. Il pulsante -[Inverti] inverte il rapporto (2:1 diventa 1:2 e cos via). Si -pu cambiare il nome del pulsante e il rapporto corrispondente -usando [Personalizza], che aprir la finestrella mostrata sopra +[Inverti] inverte il rapporto (2:1 diventa 1:2 e così via). Si +può cambiare il nome del pulsante e il rapporto corrispondente +usando [Personalizza], che aprirà la finestrella mostrata sopra a destra. Immettere i nomi desiderati nella prima riga di caselle, e il rapporto corrispondente nella linea sottostante; usare 16:9 per il formato HDTV.
        -Il pulsante [gold] usa di default il rapporto aureo (circa 1,618:1) - si pu modificare esattamente come gli altri.
        +Il pulsante [gold] usa di default il rapporto aureo (circa 1,618:1) - +si può modificare esattamente come gli altri.

        -

        +
        +
        +Ritaglia automaticamente
        +autotrim.jpg
        +
        - +
        + + +Le funzioni per creare panorami +possono lasciano margini, e altre trasformazioni possono lasciare aree +nere. Il ritaglio automatico imposta automaticamente i margini per +eliminare queste aree, e poi invoca la funzione di ritaglio (capitolo +precedente). Se i margini sono corretti, premere [Fatto]; se non sono +corretti, modificarli come descritto prima. La funzione automatica +cerca il massimo rettangolo che non attraversi i margini neri; il +risultato può essere quello desiderato oppure no, e in questo +caso essi possono essere variati.
        +
        +
        +
        +
        Ridimensiona immagine
        (riscalare)
        @@ -3551,13 +3768,13 @@ 3/4, 2/3, 1/2, 1/3, o 1/4 della dimensione originale. Usando uno di questi -pulsanti si minimizzer la perdita di risoluzione. Se la casella -[Blocca proporzioni] marcata, le proporzioni originali di -larghezza e altezza saranno preservate, cio se una dimensione -viene modificata, l'altra verr modificata di conseguenza per +pulsanti si minimizzerà la perdita di risoluzione. Se la casella +[Blocca proporzioni] è marcata, le proporzioni originali di +larghezza e altezza saranno preservate, cioé se una dimensione +viene modificata, l'altra verrà modificata di conseguenza per mantenere il rapporto. Il cambio di dimensioni viene fatto -immediatamente, ma l'immagine sembrer la stessa a meno che non -diventi pi piccola della finestra, causando un restringimento +immediatamente, ma l'immagine sembrerà la stessa a meno che non +diventi più piccola della finestra, causando un restringimento visibile. Uscire dalla finestra di dialogo con [Fatto] per mantenere le modifiche, o [Annulla] per mantenere le dimensioni immutate. La barra di stato in basso viene aggiornata solo salvando l'immagine.
        @@ -3567,29 +3784,35 @@
        -Ridimensione/esporta in blocco
        - +Ridimensiona/esporta +in blocco

        Si usa per scalare molte -immagini insieme (per caricarle su un sito web,  per guadagnare -spazio sul disco, eccetera). L'invocazione apre una finestra di dialogo +immagini insieme (per caricarle su un sito web,  o per guadagnare +spazio sul disco). L'invocazione apre una finestra di dialogo per selezionare le immagini e impostare le opzioni. Usare il pulsante [Seleziona i file] per scegliere le immagini da una galleria (dettagli). -Importante la scelta [Sostituzione originali] o [Esporta su +Selezionare larghezza e +altezza massime per i file di uscita (usare valori enormi se non si +vuole ridurre). Selezionare il [Nuovo tipo di file]: [Uguale] significa +che il tipo di file non verrà cambiato, le altre scelte +impostano invece il tipo di file che sarà usato per la nuova +copia.
        +Importante è la scelta [Sostituzione originali] o [Esporta su una posizione]; nel secondo caso, occorre specificare una directory dove le immagini scalate saranno salvate (scrivere direttamente nella casella sotto, o usare [Sfoglia]). Infine, usare [Prosegui] per -cominciare l'elaborazione; una finestrella mostrer il -progresso. Se l'opzione di sostituzione originali attiva, i +cominciare l'elaborazione; una finestrella mostrerà il +progresso. Se l'opzione di sostituzione originali è attiva, i dati EXIF verranno preservati (incluse le etichette). Se invece si - scelta l'opzione di esportazione, usare la casella [Copia +è scelta l'opzione di esportazione, usare la casella [Copia EXIF] per scegliere se tali dati devono essere esportati od omessi.
        -Le immagini riscalate saranno sempre salvate in JPEG, indifferentemente dal tipo di file in ingresso.



        -Testo sull'immagine
        +Testo +sull'immagine

        @@ -3600,54 +3823,39 @@ trascinare con il tasto sinistro del mouse per indicare la posizione del testo; usare il pulsante destro per rimuovere la scritta.
        Usare il pulsante [Font] per selezionare un diverso tipo di carattere e -una diversa dimensione; la dimensione pu essere variata anche +una diversa dimensione; la dimensione può essere variata anche con il controllo apposito senza cliccare [Font]. Il controllo [Angolo] permette di ruotare la scritta. Si possono scegliere il colore del testo (text) e dello sfondo (backing), e la trasparenza. L'esempio qui sopra mostra testo verde su sfondo blu, con trasparenza al 77%, -cio l'immagine visibile attraverso la scritta. La +cioé l'immagine è visibile attraverso la scritta. La terza casella del colore [Outline] permette di specificare il colore del contorno del testo (rosso nell'esempio). Il controllo [Spessore] imposta la larghezza del contorno. I pulsanti [Carica da file] e [Salva] richiamano una finestra di dialogo per scegliere un file, dal quale si leggono o scrivono i dati della finestra corrente (font, -colori, dimensione...), cos possibile mantenere una +colori, dimensione...), così è possibile mantenere una collezione di annotazioni usate frequentemente.


        -Per creare un watermark: -usare una trasparenza del testo del 70% o pi, e una dello +Per creare un +watermark: +usare una trasparenza del testo del 70% o più, e una dello sfondo del 100%. Il testo dovrebbe essere leggero ma leggibile. Per aggiungere un effetto di bassorilievo usare [Seleziona area] per circondare il testo e poi [Arte -> Bassorilievo] per sbalzare il -testo (se pi chiaro dell'immagine) o scavarlo (se pi +testo (se più chiaro dell'immagine) o scavarlo (se più scuro).
        -
        -
        -
        - -
        - -Ruota immagine

        - -La funzione richiama un dialogo per ruotare l'immagine in senso orario (+) o antiorario (-) a passi di 0,1, 1, 10 o 90 gradi.
        -Con un'immagine storta, usare il mouse per trascinare il lato destro in -alto o in basso fino a che l'immagine sia dritta. Usare il pulsante dei -90 gradi per convertire un'immagine da orizzontale a verticale. Con -rotazioni di 90 gradi non si perde risoluzione, mentre con altri angoli -si perde circa 1/2 pixel. L'immagine ruotata diventa pi grande -per accomodare la rotazione senza perdite: un'immagine di 100 x 100 -ruotata di 45 gradi occupa 141 x 141 pixel; le aree non usate saranno -nere. Usare [Ritaglia] per eliminare queste aree.



        -Rifletti immagine
        +Rifletti +immagine
        Scegliere [orizzontale] o [verticale]; l'immagine viene specchiata (ribaltata) di conseguenza. @@ -3656,22 +3864,23 @@ gradi.

        -

        Svolgi immagine

        -
        Fotografie +
        + +Fotografie di  soggetti vicini (solitamente edifici o interni di stanze) -possono mostrare come curve linee che in realt sono diritte. -Raddrizzare queste curve necessario per far collimare le -immagini nella creazione di un panorama (men [Combina]). Per -soggetti lontani (specialmente paesaggi) il problema non -avvertibile. Questa funzione pu essere usata per raddrizzare le +possono mostrare come curve linee che in realtà sono diritte. +Raddrizzare queste curve è necessario per far collimare le +immagini nella creazione di un panorama (menù [Combina]). Per +soggetti lontani (specialmente paesaggi) il problema non è +avvertibile. Questa funzione può essere usata per raddrizzare le linee curve e togliere l'inclinazione a quelle storte. Linee puntinate orizzontali e verticali vengono mostrate sull'immagine, come assi di -riferimento: cliccare o trascinare vicino all'estremit di una +riferimento: cliccare o trascinare vicino all'estremità di una linea per spostarla. Immettere i valori di correzione orizzontale e verticale e osservare il risultato; aumentare o diminuire i valori e ripetere. Spostare gli assi per cambiare il centro dello svolgimento. I @@ -3687,21 +3896,21 @@
        Deforma immagine (area)

        -Questa funzione si pu -usare per generare distorsioni dentro un'area. Si pu +Questa funzione si può +usare per generare distorsioni dentro un'area. Si può selezionare un'area e trascinare il mouse per deformarla rispetto al resto dell'immagine; l'immagine reagisce come se fosse fatta di gomma. -Il movimento massimo in corrispondenza del puntatore e +Il movimento è massimo in corrispondenza del puntatore e decresce a zero ai bordi della selezione. Diversi trascinamenti con lunghezze e direzioni diverse possono essere combinati per arrivare al risultato. Il pulsante [Annulla ultimo] cancella l'ultimo trascinamento -(fino agli ultimi 100). Quando finito, si pu selezionare +(fino agli ultimi 100). Quando finito, si può selezionare un'altra area e deformare ancora, o scegliere [Fatto] per terminare. Il metodo usato da Fotoxx limita la perdita di risoluzione per deformazioni ripetute: per ogni trascinamento, il movimento totale di ogni pixel viene accumulato e l'immagine originale viene usata per calcolare la disposizione finale. I pixel vengono interpolati per -ridurre spigolosit e migliorare la nitidezza.
        +ridurre spigolosità e migliorare la nitidezza.


        @@ -3709,10 +3918,10 @@
        Deforma immagine (curve)

        -Questa funzione utile +Questa funzione è utile per correggere problemi di prospettiva (vedi anche [Svolgi immagine]). Trascinare col mouse un punto qualsiasi dell'immagine: l'intera -immagine verr tirata o spinta nella direzione indicata, ma le +immagine verrà tirata o spinta nella direzione indicata, ma le zone vicino al puntatore si spostano maggiormente di quelle distanti. Si possono raddrizzare linee curve, o deformare deliberatamente l'immagine.
        @@ -3723,44 +3932,44 @@ Deforma immagine (lineare)

        TQuesta funzione lavora come la -precedente, ma su un'area pi ampia e causa una curvatura +precedente, ma su un'area più ampia e causa una curvatura minore. Per minimizzare la creazione di curvature indesiderate, trascinare gli angoli dell'immagine piuttosto che altri punti.


        -
        -Deforma immagine (speculare)
        +Deforma +immagine (speculare)
        Questa funzione deforma l'immagine in modi interessanti. Trascinare gli angoli o i lati con il -mouse; i cambiamenti sono puramente lineari cos le linee dritte -rimangono tali. Questa trasformazione chiamata "affine"; +mouse; i cambiamenti sono puramente lineari così le linee dritte +rimangono tali. Questa trasformazione è chiamata "affine"; ulteriori dettagli possono essere trovati su Internet con Google.


        -Men Arte
        +Menù +Arte


        -Profondit di colore

        +Profondità di colore

        Questa funzione cambia i normali -16 bit per colore RGB a qualsiasi quantit tra 1 e 16. Con 8 bit +16 bit per colore RGB a qualsiasi quantità tra 1 e 16. Con 8 bit per colore ci sono 16,8 milioni di combinazioni di colori; con 4 bit i -colori possibili sono solo pi 4096. Usare da 1 a 4 bit per +colori possibili sono solo più 4096. Usare da 1 a 4 bit per ottenere interessanti effetti di tipo poster.


        -
        Disegno

        @@ -3771,7 +3980,7 @@ nero. Il cursore [Soglia] converte l'immagine da scala di grigio a bianco e nero. Il cursore [Contorni] evidenzia i pixel con grande contrasto (bordi degli oggetti) e sopprime quelli poco contrastati. Il -risultato pu essere nero su bianco o bianco su nero, secondo la +risultato può essere nero su bianco o bianco su nero, secondo la selezione di [Matita] o [Gessetto]. Manipolare sia [Soglia] che [Contorni] per ottenere il miglior bilanciamento.

        @@ -3785,14 +3994,14 @@ Questa funzione trasforma una fotografia in un disegno di linee colorate corrispondenti ai contorni dei soggetti nella fotografia. I bordi (transizioni marcate di -luminosit o colore) nell'immagine vengono illuminati, e il +luminosità o colore) nell'immagine vengono illuminati, e il resto scurito. Ci sono tre cursori per controllare il processo. [Soglia del contorno] regola quanto luminoso deve essere un bordo per essere illuminato, da "nessun bordo" a "tutti" (anche quelli deboli). [Spessore contorno] regola la larghezza dell'illuminazione, da 1 pixel -a circa 5. [Luminosit immagine] regola la luminosit del +a circa 5. [Luminosità immagine] regola la luminosità del resto dell'immagine, da scuro (si vedono solo i contorni) a piena -luminosit.
        +luminosità.


        @@ -3800,18 +4009,19 @@ Bassorilievo

        Trasforma la foto in un -bassorilievo simulato. Il [Raggio] determina la grossolanit -(inverso del dettaglio). La [Profondit] quanto +bassorilievo simulato. Il [Raggio] determina la grossolanità +(inverso del dettaglio). La [Profondità] quanto è profonda l'incisione.

        +

        Mosaico

        Questa funzione trasforma una -foto in una schiera di grosse tessere monocolori. Si pu +foto in una schiera di grosse tessere monocolori. Si può impostare la grandezza delle tessere e la distanza fra esse. Questo processo viene anche chiamato "pixelaze" o "pixelate". Usare una selezione per confinare l'effetto a una parte dell'immagine, per @@ -3819,44 +4029,42 @@

        -
        Puntinismo
        Genera una schiera di puntini dalla foto, rendendola simile ai vecchi fumetti o ai quadri di Roy -Lichtenstein. L'unico parametro impostabile la dimensione dei -puntini. Prima di questa funzione, si pu provare a modificare -saturazione, profondit di colore o altri effetti per arrivare a +Lichtenstein. L'unico parametro impostabile è la dimensione dei +puntini. Prima di questa funzione, si può provare a modificare +saturazione, profondità di colore o altri effetti per arrivare a risultati interessanti.

        -

        + Pittura
        Questa funzione trasforma una foto rendendola simile a un dipinto. Riduce il numero di colori, considera i pixel vicini con colori simili, e poi li aggrega in aree -pi grandi. Quattro parametri controllano il processo: -[Profondit dei colori] imposta il numero di colori da usare +più grandi. Quattro parametri controllano il processo: +[Profondità dei colori] imposta il numero di colori da usare (numero di bit per colore): 1=8 colori, 2=64... 5=32768; [Fattore artistico] imposta un limite inferiore per aree che avranno un proprio -colore: aree pi piccole di questo numero saranno assorbite da +colore: aree più piccole di questo numero saranno assorbite da aree adiacenti simili; [Precisione colori] imposta una -similarit minima per includere una piccola area in una -adiacente: 0=qualunque (massimo raggruppamento), 100=similarit +similarità minima per includere una piccola area in una +adiacente: 0=qualunque (massimo raggruppamento), 100=similarità completa (nessun raggruppamento) ; [Contorni] determina se le aree colorate devono essere bordate con una sottile linea scura, come tessere irregolari in un mosaico. Dopo questa funzione, l'applicazione -del Bassorilievo pu aggiungere trame interessanti.
        +del Bassorilievo può aggiungere trame interessanti.

        -

        @@ -3869,13 +4077,15 @@ nell'immagine per dipingere con il colore corrente. Il modo Cancellare serve per cliccare o trascinare nell'immagine per ripristinare i pixel al loro colore originale.
        -Il pulsante [Colore] permette di scegliere un colore attraverso una finestra di selezione, e mostra sempre il colore corrente.
        -Il controllo [Raggio del pennello] imposta la grandezza dell'area ritoccata dal puntatore con ogni clic o trascinamento.
        -I controlli di trasparenza impostano l'intensit di applicazione +Il pulsante [Colore] permette di scegliere un colore attraverso una +finestra di selezione, e mostra sempre il colore corrente.
        +Il controllo [Raggio del pennello] imposta la grandezza dell'area +ritoccata dal puntatore con ogni clic o trascinamento.
        +I controlli di trasparenza impostano l'intensità di applicazione del colore al centro e ai bordi del pennello. Con trasparenza zero il nuovo colore viene impresso completamente subito, mentre una grande trasparenza (90..99) applica poco colore e permette di regolare la sua -quantit usando molti successivi clic ( analogo a +quantità usando molti successivi clic (è analogo a spruzzare il colore da una certa distanza).
        [Cancellare] funziona nello stesso modo di [Pittura]: usare zero trasparenza per per cancellare al primo clic, e alta trasparenza per @@ -3883,27 +4093,26 @@ poter ingrandire o spostare l'immagine, e rimettere la spunta per tornare a disegnare.
        Il pulsante [Annulla ultimo] annulla l'ultima operazione (un singolo -clic o trascinamento), e si pu usare pi volte per +clic o trascinamento), e si può usare più volte per annullare all'indietro molte operazioni. La memoria per le operazioni -di annullamento limitata a 200 Mib (megabyte), e pu +di annullamento è limitata a 200 Mib (megabyte), e può essere consumata se si fanno molte modifiche con un pennello grosso (ogni cambiamento a ogni pixel viene salvato). E' utile salvare l'immagine dopo ogni modifica soddisfacente per riacquistare questa -memoria. La quantit utilizzata di memoria viene mostrata, -cos si pu vedere quando si arriva vicino al limite. Se -una selezione abilitata, le operazioni vengono confinate entro -quell'area. Si pu selezionare un'area per colore e poi cambiare +memoria. La quantità utilizzata di memoria viene mostrata, +così si può vedere quando si arriva vicino al limite. Se +una selezione è abilitata, le operazioni vengono confinate entro +quell'area. Si può selezionare un'area per colore e poi cambiare il colore senza preoccuparsi dei bordi.
        -NOTA: ingrandire l'immagine al 100% o pi quando si usa -questa funzione: se i movimenti del mouse sono pi ampi dei -pixel dell'immagine e un pennello piccolo in uso, alcuni pixel +NOTA: ingrandire l'immagine al 100% o più quando si usa +questa funzione: se i movimenti del mouse sono più ampi dei +pixel dell'immagine e un pennello piccolo è in uso, alcuni pixel potrebbero venire saltati.


        -Men [Combina]
        - +Menù [Combina]

        @@ -3913,65 +4122,68 @@ Combina (sovrappone) immagini multiple con lo stesso soggetto a livelli di esposizione diversi. -L'immagine combinata pu mostrare migliori dettagli sia in parti +L'immagine combinata può mostrare migliori dettagli sia in parti chiare che scure dell'immagine prelevando pixel dall'immagine chiara per le zone scure e pixel dall'immagine scura per le zone chiare. Molte macchine digitali possono prendere scatti multipli in rapida successione con livelli d'esposizione differenti. Si possono combinare queste immagini per produrne una migliore. Se la macchina viene regolata manualmente tra gli scatti, curare di mantenerla allineata e -mirare allo stesso punto distante. Una lieve quantit di -disallineamento pu essere tollerato. Se il soggetto si muove +mirare allo stesso punto distante. Una lieve quantità di +disallineamento può essere tollerato. Se il soggetto si muove tra due scatti successivi, confusione e sdoppiamenti non possono essere evitati.


        +
        + Selezionare la funzione HDR. Una finestra di dialogo permette di selezionare fino a 9 immagini, che devono avere dimensioni molto simili in pixel. Le immagini vengono -allineate e combinate automaticamente, e questo pu richiedere -un minuto o anche pi. Finito l'allineamento, l'immagine +allineate e combinate automaticamente, e questo può richiedere +un minuto o anche più. Finito l'allineamento, l'immagine combinata viene mostrata, insieme a una finestra di dialogo per la regolazione manuale. Le contribuzioni delle immagini in ingresso sono mostrate come una serie di curve modificabili. La scala orizzontale -rappresenta la luminosit, da scuro a chiaro. Ogni curva - associata a un'immagine che contribuisce ai pixel finali; il -contributo di un'immagine a una certa luminosit -proporzionale all'altezza della sua curva a quella luminosit. -La curva inziale dell'immagine pi luminosa sar alta -verso sinistra e bassa verso destra, dando cos un gran +rappresenta la luminosità, da scuro a chiaro. Ogni curva +è associata a un'immagine che contribuisce ai pixel finali; il +contributo di un'immagine a una certa luminosità è +proporzionale all'altezza della sua curva a quella luminosità. +La curva inziale dell'immagine più luminosa sarà alta +verso sinistra e bassa verso destra, dando così un gran contributo aipixel scuri e poco contributo a quelli chiari. L'immagine -pi scura avra la curva bassa a sinistra e alta a destra, e le +più scura avra la curva bassa a sinistra e alta a destra, e le ulteriori immagini avranno curve mediane fra queste. Le curve possono essere manipolate trascinandole con il mouse. I punti d'ancoraggio (quadratini sulla curva) possono essere spostati mantenendo fissi gli altri. I contributi dell'immagine corrispondente vengono variati conformemente, e i risultati si possono vedere quasi in tempo reale. Cliccare col pulsante destro su un punto d'ancoraggio per rimuoverlo. -In genere, l'immagine pi luminosa dovrebbe contribuire -maggiormente ai pixel scuri, e quella pi scura dovrebbe +In genere, l'immagine più luminosa dovrebbe contribuire +maggiormente ai pixel scuri, e quella più scura dovrebbe contribuire maggiormente; occorre un po' di pratica per lavorare efficacemente con le curve.

        + Un sistema alternativo -pi rapido e facile pu funzionare ugualmente bene: dopo +più rapido e facile può funzionare ugualmente bene: dopo aver combinato le immagini, ignorare le curve e uscire dalla funzione e usarne invece altre per rifinire l'immagine: Normalizza/Espandi -luminosit, Luminosit e contrasto, Mappatura della luce. -Una selezione di area pu essere usata per racchiudere una zona -che ha bisogno di pi luminosit, colore o contrasto -locale, cos si possono applicare metodi e parametri diversi ad +luminosità, Luminosità e contrasto, Mappatura della luce. +Una selezione di area può essere usata per racchiudere una zona +che ha bisogno di più luminosità, colore o contrasto +locale, così si possono applicare metodi e parametri diversi ad aree differenti.

        -

        + -Combina immagini (grnade profondit - HDF)
        +Combina immagini (grnade profondità - HDF)

        Combina (sovrappone) diverse immagini dello stesso soggetto riprese con messa a fuoco differente -- @@ -3981,108 +4193,118 @@ specialmente per le riprese molto ravvicinate.

        Per prendere le foto , scegliere un punto come centro dell'immagine; -mirare all'oggetto vicino e far scattare l'otturatore a met per -impostare il fuoco sull'oggetto; mantenere l'otturatore a met, +mirare all'oggetto vicino e far scattare l'otturatore a metà per +impostare il fuoco sull'oggetto; mantenere l'otturatore a metà, mirare al centro scelto, e scattare la foto. Poi, scegliere un oggetto -pi distante e ripetere. Ripetere con distanze di fuoco -maggiori: probabilmente ogni parte della scena sar a fuoco in +più distante e ripetere. Ripetere con distanze di fuoco +maggiori: probabilmente ogni parte della scena sarà a fuoco in almeno una foto. La posizione della macchina dovrebbe essere grosso -modo sempre la stessa, che pu essere difficile se il soggetto - molto vicino. I movimenti della macchina possono causare +modo sempre la stessa, che può essere difficile se il soggetto +è molto vicino. I movimenti della macchina possono causare problemi di scalatura e parallasse (oggetti vicini spostati  a rispetto di quelli distanti); questi problemi possono essere corretti -in Fotoxx, ma ci pu richiedere parecchio tempo: - meglio cercare di evitarli.

        +in Fotoxx, ma ciò può richiedere parecchio tempo: +è meglio cercare di evitarli.



        +
        + Riprese le foto, si possono processare con Fotoxx. Invocare la funzione HDF e selezionare fino a 9 immagini; queste verranno automaticamente allineate il meglio -possibile. Questo pu richiedere un minuto o pi per +possibile. Questo può richiedere un minuto o più per immagine, in dipendenza della dimensione delle immagini e della potenza -della CPU. L'immagine risultante una miscela uniforme delle +della CPU. L'immagine risultante è una miscela uniforme delle immagini in ingresso allineate. Piccoli movimenti della macchina tra le foto vengono corretti, ma in modo limitato, e gli errori di parallasse -non vengono compensati. Quando l'allineamento completo, si -apre una finestra di dialogo. Si pu selezionare una delle +non vengono compensati. Quando l'allineamento è completo, si +apre una finestra di dialogo. Si può selezionare una delle immagini in ingresso e "pitturare" con il mouse su ogni area dell'immagine in uscita. Questo trasporta la miscela originale verso l'immagine selezionata, nella zona "pitturata". Per ogni area o oggetto -nella foto, scegliere l'immagine d'ingresso che migliore in -quell'area. Il raggio del pennello pu essere ingrandito o +nella foto, scegliere l'immagine d'ingresso che è migliore in +quell'area. Il raggio del pennello può essere ingrandito o rimpicciolito, per pitturare velocemente aree ampie o controllare piccoli dettagli quando serve. Se ci sono oggetti vicini e lontani che si sovrappongono, occorrono tempo e pazienza per rendere tutta la foto nitida. Togliere la spunta ad [Abilita mouse] per ingrandire/spostare l'immagine, e rimetterla per tornare al ritocco.
        -
        I +
        + +I disallineamenti possono essere corretti selezionando [deformazione] nella finestra di dialogo. Le immagini sottostanti possono essere trascinate e deformate con il mouse, e l'immagine composta risultante -cambia conformemente. La deformazione limitata all'area -intorno al mouse. Quando un'area gi "pitturata" viene +cambia conformemente. La deformazione è limitata all'area +intorno al mouse. Quando un'area già "pitturata" viene trascinata, l'immagine corrispondente viene selezionata e deformata, mentre aree "pitturate" con altre immagini rimangono ferme. Aree che non sono state pitturate non possono essere trascinate. Manipolare le diverse aree ed eseguire trascinamento incrementali fino a che tutte le aree siano allineate.

        - - Procedura suggerita:
        con il modo [Pittura] selezionare ogni immagine in sequenza e pitturare tutte le aree con aspetto nitido in quell'immagine. Tutti i confini che non sono allineati si mostreranno chiaramente come scostamenti nei bordi degli oggetti. Alcuni di questi possono essere ridotti selezionando un'altra immagine come sorgente per quella zona (se -pi di un'immagine abbastanza nitida in quella zona). +più di un'immagine è abbastanza nitida in quella zona). Usando il modo [deformazione] eseguire i ritocchi fini per eliminare i disallineamenti visibili.



        -Sovrapponi (interattivo con mouse)
        + +Sovrapponi +(interattivo con mouse)
        Combina (sovrappone) diverse foto dello stesso soggetto prese in tempi differenti. Serve per rimuovere turisti o automobili che vanno e vengono tra le riprese, pitturandoli via con il mouse.
        -
        Per +
        + +Per fare le foto, mirare allo stesso punto distante e riprendere diversi fotogrammi mentre gli altri oggetti (turisti, automobili...) si muovono davanti. Cercare di prendere almeno un'istantanea libera da ostacoli per ogni parte del soggetto.

        + Per processare le foto con Fotoxx, richiamare [Combina->Sovrapponi (interattivo con mouse)] e selezionare fino a nove immagini. Le immagini verranno allineate il meglio possibile, richiedendo un certo -tempo (anche un minuto o pi per ogni immagine, in dipendenza -della potenza della CPU). L'immagine in uscita una miscela +tempo (anche un minuto o più per ogni immagine, in dipendenza +della potenza della CPU). L'immagine in uscita è una miscela omogenea delle immagini in ingresso allineate. Quando l'allineamento - completo si apre un dialogo. Si pu selezionare una +è completo si apre un dialogo. Si può selezionare una delle immagini in ingresso e "pitturare" con il mouse su un'area dell'immagine risultante. Questo converte la miscela delle immagini verso l'immagine scelta, nell'area sotto pittura. Per ogni area dell'immagine, scegliere l'originale che sia libero da oggetti in movimento davanti al soggetto reale. Il raggio del pennello/mouse -pu essere variato per pitturare velocemente grandi aree o +può essere variato per pitturare velocemente grandi aree o controllare finemente piccoli dettagli. Deselezionare [Abilita mouse] per ingrandire o spostare l'immagine, e riselezionare per tornare a pitturare.


        +

        -Sovrapponi (rimozione disturbo)
        + +Sovrapponi +(rimozione disturbo)
        Questa funzione combina da 2..9 immagini dello stesso soggetto. Le foto dovrebbero essere praticamente @@ -4090,34 +4312,36 @@ libera. Se le foto sono state riprese con livelli ISO molto alti (condizioni di luce scarsa), i pixel avranno parecchio disturbo; riprendendo molte foto e facendone una media, questo disturbo -pu essere praticamente eliminato.
        +può essere praticamente eliminato.


        +
        + Per prendere le foto, scegliere un punto come centro dell'immagine. Eseguire poi diversi scatti riferiti allo stesso centro e facendo attenzione a non ruotare o -spostare troppo la macchina. Maggiori sono gli scatti, meglio ; +spostare troppo la macchina. Maggiori sono gli scatti, meglio è; fino a nove immagini possono essere usate da Fotoxx, ma se ne possono -prendere di pi per scartare quelle meno definite - un problema +prendere di più per scartare quelle meno definite - un problema ricorrente in condizione di poca luce e lunghi tempi d'esposizione. In Fotoxx richiamare [Combina->Sovrapponi (rimozione disturbo)] e selezionare fino a nove immagini. Queste vengono combinate, e infine -viene mostrato un dialogo. L'immagine risultante iniziale una +viene mostrato un dialogo. L'immagine risultante iniziale è una miscela di quelle in ingresso: i valori RGB di ogni pixel in uscita - la media matematica dei corrispondenti valori in ingresso. +è la media matematica dei corrispondenti valori in ingresso. Alcuni strumenti aggiuntivi possono essere usati per ridurre eventualmente il disturbo rimanente ancora un po'. Il bottone [use median] cambia l'algoritmo da media matematica a valore mediano (si esegue la media dei valori mediani 1-3, in dipendenza del numero di -immagini). Il risultato pu essere migliore oppure no, quindi +immagini). Il risultato può essere migliore oppure no, quindi alternare fra i due metodi per fare una comparazione (l'aggiornamento -dello schermo pu richiedere parecchi secondi).
        +dello schermo può richiedere parecchi secondi).
        Le caselle [omit low pixel] e [omit high pixel] causano l'esclusione -dei valori RGB estremi prima del calcolo della media. Questo pu +dei valori RGB estremi prima del calcolo della media. Questo può aiutare a rimuovere picchi di rumore; non ha effetto quando il metodo -[use median] selezionato.
        +[use median] è selezionato.


        @@ -4127,10 +4351,13 @@ Questa funzione affianca da 2..4 immagini insieme per formare un'immagine larga o panoramica. Le -immagini devono sovrapporsi del 15% o pi affinch Fotoxx -possa trovare i punti concidenti e combinarli.
        - +immagini devono sovrapporsi del 15% o più affinché Fotoxx +possa trovare i punti concidenti e combinarli.

        +
        + +
        + Richiamare [Combina->Crea un panorama] e selezionare da 2 a 4 file d'immagine. Le immagini vengono unite e mostrate con una piccola sovrapposizione trasparente. Un @@ -4143,80 +4370,97 @@ vicina di sinistra - funziona meglio lavorare da sinistra verso destra. Spostare l'immagine orizzontalmente e verticalmente in un allineamento approssimativo col vicino di sinistra, e poi ruotarla trascinando il -lato inferiore. L'immagine si inclina intorno al punto centrale della -sua sovrapposizione si sinistra. Il metodo pi veloce +lato inferiore a destra o sinistra. L'immagine si inclina intorno al punto centrale della +sua sovrapposizione di sinistra. Il metodo più veloce è allineare la sovrapposizione nel centro verticale, poi ruotare l'immagine, se richiesto, per portare le regioni di sovrapposizione alta e bassa all'allineamento. Non serve un'accuratezza estrema. Usare il -pulsante [Ridimensiona] per ottenere un'immagine combinata pi +pulsante [Ridimensiona] per ottenere un'immagine combinata più grande dopo averle disposte vicine.

        + Le immagini dovrebbero essere curvate correttamente e combaciare bene. Se non combaciano, occorre impostare i parametri delle lenti come descritto in [Strumenti->Parametri dell'obbiettivo] (dettagli). Si possono regolare questi parametri da dentro il dialogo di preallineamento fino a che le immagini combacino ragionevolmente bene, -e ci potrebbe essere sufficiente. Il parametro [mm focale] -(lunghezza focale, equivalente a 35 mm) ottenuto dai dati EXIF -se disponibili. Il parametro [curvatura] (barrel distortion) deve -essere regolato manualmente, ma spesso insignificante e -pu essere lasciato a zero.
        -

        +e ciò potrebbe essere sufficiente. Il parametro [mm focale] +(lunghezza focale, equivalente a 35 mm) è ottenuto dai dati EXIF +se disponibili. Il parametro [curvatura] (barrel distortion) non è disponibile nelle informazioni EXIF: deve +essere regolato manualmente, ma spesso è insignificante e +può essere lasciato a zero.
        +

        +Se una foto era stata ritagliata +di modo che la maggiore delle dimensioni (larghezza o altezza) era +stata ridotta, allora la lunghezza focale descritta in EXIF non +è più valida, e il valore iniziale prelevato da EXIF +potrebbe non funzionare bene. Una sezione (parte) di un'immagine presa +dal centro ha una lunghezza focale effettiva maggiore dell'immagine +intera. Usare il dialogo di pre-allineamento per aumentare il valore di +lunghezza focale fino a che le immagini combacino ragionevolmente bene.
        +

        -
        -
        Cliccare [Procedi] quando il -pre-allineamento terminato: il programma eseguir -l'allineamento fine e unir le immagini. Internamente, le +pre-allineamento è terminato: il programma eseguirà +l'allineamento fine e unirà le immagini. Internamente, le immagini vengono spostate e ruotate e il grado di corrispondenza viene valutato. Questo viene fatto con dimensioni d'immagine sempre maggiori, fino a che la corrispondenza migliore viene trovata entro una frazione -di pixel. Questa procedura pu richiedere da 10 secondi a un -minuto o pi per immagine, in dipendenza della dimensione delle -immagini e della velocit della CPU.
        +di pixel. Questa procedura può richiedere da 10 secondi a un +minuto o più per immagine, in dipendenza della dimensione delle +immagini e della velocità della CPU.
        +
        +

        +
        Quando l'elaborazione -dell'allineamento fine completata, l'immagine combinata viene +dell'allineamento fine è completata, l'immagine combinata viene mostrata. Una finestra di dialogo si apre per regolare in modo fine la -luminosit e la corrispondenza del colore. Pu essere -visibile un bordo spigoloso perch le immagini non hanno la -stessa luminosit e bilanciamento di colori. Il pulsante [colori -automatici] pu essere usato per eseguire una corrispondenza -automatica, che usualmente il miglior punto di partenza. Gli +luminosità e la corrispondenza del colore. Può essere +visibile un bordo spigoloso perché le immagini non hanno la +stessa luminosità e bilanciamento di colori. Il pulsante [colori +automatici] può essere usato per ricercare una corrispondenza +automatica, che è usualmente il miglior punto di partenza. Gli altri controlli permettono di fare cambi addizionali per far combaciare -meglio le immagini. Cambiare i valori per [luminosit] e i tre +meglio le immagini. Cambiare i valori per [luminosità] e i tre colori e cliccare [Applica] per vedere il risultato. Usare [colori automatici] per far convergere le altre immagini verso quella modificata. Usare [file colore] per ripristinare i valori originali dell'immagine d'ingresso. La [Larghezza di sfumatura] governa come le immagini vengono miscelate: ai bordi affiancati, il bilanciamento di -colore viene gradualmente spostato lungo la quantit di pixel +colore viene gradualmente spostato lungo la quantità di pixel specificata, per nascondere sbilanciamenti che non possono essere -corretti pienamente. Il valore iniziale 1 pixel, che rende -evidente qualsiasi differenza di colore o luminosit. Quando -terminato, si possono ancora usare [Svolgi], [Deforma], [Ruota], -[Ritaglia] e altre funzioni per le correzioni finali.
        +corretti pienamente. Il valore iniziale è 1 pixel, che rende +evidente qualsiasi differenza di colore o luminosità.
        +
        +Al termine, si possono ancora usare [Svolgi], [Deforma], [Ruota], +[Ritaglia] e altre funzioni per le correzioni finali. Usare magari la +funzione [Ritaglia automaticamente] per eliminare i bordi neri +superflui.


        -
        Panorama verticale
        +Panorama +verticale
        + Funziona esattamente come il panorama orizzontale, eccetto che le immagini sono impilate verticalmente. Per cambiare l'ordine delle immagini, trascinarle dal centro. Per ruotare un'immagine trascinarne il lato destro su o -gi. E' meglio allineare dall'alto verso il basso.
        +giù. E' meglio allineare dall'alto verso il basso.

        +Limitazioni +delle funzioni "Panorama"
        -Limitazioni delle funzioni "Panorama"
        Panorami che includono oggetti vicini possono essere complicati: quando le foto devono essere prese, fare attenzione a girare la macchina intorno all'asse della lente (non del corpo della macchina!), con il minimo spostamento laterale possibile, altrimenti le immagini si allineano malamente a causa dello -spostamento di oggetti vicini (parallasse). Questo non un -problema quando il soggetto si trova a 50 metri o pi, dato che +spostamento di oggetti vicini (parallasse). Questo non è un +problema quando il soggetto si trova a 50 metri o più, dato che un piccolo movimento laterale ha poco impatto sull'immagine.

        @@ -4227,38 +4471,43 @@
        -Men Plugins
        +Menù +Plugins

        + Altri programmi di fotoritocco -(es. Gimp) possono essere aggiunti a questo men. Essi +(es. Gimp) possono essere aggiunti a questo menù. Essi funzioneranno come qualsiasi altra funzione interna di Fotoxx. Dopo aver usato uno di questi programmi esterni per manipolare un'immagine, si potranno usare [Annulla] e [Ripeti] per controllare il risultato, eseguire ulteriori ritocchi con Fotoxx, o usare [Salva] e [Salva come] per memorizzare l'immagine modificata. L'immagine passata da Fotoxx al -programma esterno un TIFF con 16 bit per colore. Quasi tutti i +programma esterno è un TIFF con 16 bit per colore. Quasi tutti i programmi possono leggere questo formato, ma eventualmente usare solo 8 bit. Quando finito di usare l'editor esterno, prima di uscire salvare -l'immagine di nuovo su s stessa (usare "salva" invece di -cambiare nome), poi uscire. Fotoxx prelever il file manipolato -e lo user come se la modifica fosse stata effettuata da Fotoxx.
        +l'immagine di nuovo su sè stessa (usare "salva" invece di +cambiare nome), poi uscire. Fotoxx preleverà il file manipolato +e lo userà come se la modifica fosse stata effettuata da Fotoxx.

        + -Per aggiungere un nuovo plugin, usare la funzione del men -[Plugins->Gestione plug-in]. Immettere un nome per il men +Per aggiungere un nuovo plugin, usare la funzione del menù +[Plugins->Gestione plug-in]. Immettere un nome per il menù (es. "Gimp"), un comando per far partire il programma (es. "gimp") e -cliccare il pulsante [Aggiungere]. Si pu anche rimuovere un +cliccare il pulsante [Aggiungere]. Si può anche rimuovere un plugin selezionandolo dalla lista e cliccando il pulsante [Taglia].

        -Il men dei plugin non viene aggiornato fino al successivo avvio di Fotoxx.
        +Il menù dei plugin non viene aggiornato fino al successivo avvio +di Fotoxx.

        + I dati dei plugin sono salvati -nel file "/home/<utente>/.fotoxx/plugins", che pu essere +nel file "/home/<utente>/.fotoxx/plugins", che può essere manipolato con un editore di testi se desiderato. Questo metodo - la sola via per cambiare la sequenza delle voci nel -men. Attenzione a non rovinare il formato delle righe: "menu = +è la sola via per cambiare la sequenza delle voci nel +menù. Attenzione a non rovinare il formato delle righe: "menu = comando" con esattamente uno spazio prima e dopo il segno uguale.

        @@ -4266,32 +4515,39 @@

        +Menù Aiuto

        +
        +Info

        -Men Aiuto
        + +Mostra un breve messaggio sulla versione di Fotoxx, licenza, crediti e +indirizzi di contatto.
        +
        -
        Info

        - -Mostra un breve messaggio sulla versione di Fotoxx, licenza, crediti e indirizzi di contatto.
        +Guida utente
        -
        Guida utente
        La guida per l'utente (questo documento) viene aperta in un browser. -Questa guida stata scritta usando il programma KompoZer.
        +Questa guida è stata scritta usando il programma KompoZer.

        -README
        Mostra -il file README distribuito con Fotoxx, che pu contenere nuove +README
        + +Mostra +il file README distribuito con Fotoxx, che può contenere nuove informazioni sull'installazione o le dipendenze. Quando s'installa un nuovo rilascio di Fotoxx, si dovrebbe controllare il README e la -Cronistoria delle modifiche per controllare se c' qualche cosa +Cronistoria delle modifiche per controllare se c'è qualche cosa importante da sapere.

        -Cronistoria delle modifiche
        +Cronistoria +delle modifiche
        + Mostra il file "change log" distribuito con Fotoxx, contenente il dettaglio dei cambiamenti, aggiunte o correzioni apportate nel tempo al @@ -4299,7 +4555,9 @@
        -Come tradurre il programma
        +Come tradurre +il programma
        + Visualizza un breve flie di testo che spiega come fare una nuova traduzione, o correggerne una esistente. La procedura consiste nel @@ -4310,220 +4568,342 @@
        Sito WEB
        + -Carica la home page di Fotoxx da Internet. Controllare l alla +Carica la home page di Fotoxx da Internet. Controllare lì alla ricerca di aggiornamenti, nella pagina Recent changes. Questa pagina -consente di usare RSS e ci si pu sottoscrivere per ricevere +consente di usare RSS e ci si può sottoscrivere per ricevere notifiche di aggiornamenti.
        -
        - -
        +
        +
        +Organizzare una grossa quantità di immagini per la ricerca
        +
        Fotoxx può modificare e ricercare i seguenti attributi: +data, punteggio, etichette, nomi di file, parole contenute in titoli o +commenti. Tutto ciò è spiegato nella sezione Info di +questa guida. Quello che segue è un sommario delle opzioni e dei +compromessi.
        +
        +Organizzazione fisica - +usare nomi di directory e di file: questi nomi possono essere usati +come organizzazione base che permette di trovare le foto anche se +sistemi più elaborati (etichette, collezioni...) non sono usati. +L'organizzazione dovrebbe essere per date e non per eventi, luoghi o +persone. Suggerisco di usare una directory per ogni anno nominata 2005, +2006, 2007 eccetera. Questo sistema aiuta anche a impedire che una +qualsiasi directory diventi troppo grossa. I file con le foto possono +ancora essere organizzati in sequenza temporale usando MM.GG +(mese-giorno) come parte iniziale del nome; la parte restante del nome +può essere costituita dal nome dell'evento o del luogo, seguita +da un numero di sequenza.
        +
        +  Per esempio:
        /directory-principale/2011/08.20 Spitzbergen +23
        +
        +
        Questa organizzazione basilare permette a Fotoxx di trovare file +cercando nei nomi di file. Con l'esempio sopra, una ricerca per +"spitzbergen" o anche solo "spitz" produrrà tutte le immagini di +Spitzbergen. La funzione [File/Rinomina più immagini] permette +di rinominare d'un colpo un'intera partita di fotografie prese un in un +giorno in un certo luogo selezionando i file e immettendo un nome +modello com "08.20 +Spitzbergen". I numeri di sequenza sono automatici.
        +
        +Titoli: un metodo semplice +è usare titoli e commenti [Info -> Modifica titoli/commenti]. +Questi sono testi arbitrari che possono essere associati alle immagini +rapidamente: scrivere del testo, cliccare [Prossima], scrivere del +testo, cliccare [Prossima] e così via. Titoli e commenti sono +campi separati ma trattati nello stesso modo; essi sono ricercabili: le +parole in essi contenute possono essere ricercate. Si possono +aggiungere nomi di persona o altre informazioni a ogni immagine, e poi +ritrovarle velocemente. Con questo metodo si possono cercare immagini +usando una combinazione di date. nomi di file, e parole arbitrarie che +appaiono in titoli o commenti. Le date sono prelevate dai dati EXIF del +file; questo presume che l'orologio della macchina fotografica fosse +impostato correttamente al momento di prendere la foto; comunque, le +date possono essere variate usando [Info -> Modifica etichette].
        +
        +Collezioni: un altro metodo +semplice è usare le collezioni. Scegliere un nome per ogni +collezione e assegnare immagini alla stessa usando praticamente due +clic (più il tempo per trovare le immagini da aggiungere). +Questo metodo è indipendente da quelli descritti prima. +Riferirsi a [Strumenti -> Gestione collezioni]. Le collezioni si +scelgono dal nome e vengono visualizzate direttamente come gallerie di +miniature o sequenzialmente nella finestra principale.
        +
        +Etichette: lo strumento +più completo sono le etichette, ma queste sono anche quelle che +richiedono maggiore cura organizzativa. Si può scorrere le +immagini sequenzialmente e aggiungere etichette cliccando su una lista +di etichette predefinite. Nuove etichette possono essere create +all'occorrenza. Le immagini possono avere molte etichette, e possono +essere ricercate usando una combinazione AND/OR (e/oppure: tutte/almeno +una) insieme a data, punteggio, nome del file, commenti. Le etichette +sono il sistema più rapido per attraversare una grande +quantità di foto. Lo scoglio è l'organizzazione delle +etichette: occorre pianificarlo in partenza e aderire a esso, +altrimenti la situazione può diventare caotica. Se si finisce +per avere mille etichette, esse non saranno molto utili. Se le immagini +sono ordinate per data, tenderanno ad avere le stesse etichette, e +quindi l'aggiunta di etichette sarà più rapida.
        +
        +


        -Note tecniche
        +Note +tecniche

        Traduzioni

        -Vedere il men [Aiuto +Vedere il menù [Aiuto -> Come tradurre il programma]  oppure il file di testo TRANSLATIONS per informazioni su come modificare una traduzione -esistente o crearne una nuova. Questo un processo abbastanza +esistente o crearne una nuova. Questo è un processo abbastanza semplice: si tratta di editare un file che contiene messaggi in inglese seguiti dalla loro traduzione. Vederne uno esistente come esempio, magari /usr/share/fotoxx/locales/de/fotoxx.po -( la traduzione in tedesco). Una nuova traduzione per la lingua con codice ZZ dovrebbe essere salvata in /usr/share/fotoxx/locales/ZZ. -Dopo aver creato o ritoccato un simile file, esso pu essere +(è la traduzione in tedesco). Una nuova traduzione per la lingua +con codice ZZ dovrebbe essere salvata in /usr/share/fotoxx/locales/ZZ. +Dopo aver creato o ritoccato un simile file, esso può essere provato eseguendo fotoxx dalla riga di comando "fotoxx -l ZZ".
        +

        -Requisiti hardware e software
        +Requisiti +hardware e software
        + Fotoxx lavora al meglio con un computer veloce e almeno un gigabyte di memoria. I core multipli di una -CPU sono usati in funzioni intensive di calcolo (cio Contrasta, -Sfocatura, Ruota, Deforma, Panorama...). I computer pi lenti +CPU sono usati in funzioni intensive di calcolo (cioé Contrasta, +Sfocatura, Ruota, Deforma, Panorama...). I computer più lenti funzioneranno, ma saranno abbastanza lenti in alcune funzioni. Monitor -pi piccoli di 1200x800 sembreranno un po' limitati in alcune -funzioni. Lo schermo tipico di un notebook, con luminosit e +più piccoli di 1200x800 sembreranno un po' limitati in alcune +funzioni. Lo schermo tipico di un notebook, con luminosità e colore limitati, non dovrebbe essere usato per fare fotoritocco.


        -Programmi richiesti da Fotoxx
        +Programmi +richiesti da Fotoxx
        -Fotoxx richiede, al momento dell'esecuzione, i seguenti programmi o librerie:
        +Fotoxx richiede, al momento +dell'esecuzione, i seguenti programmi o librerie:

        - - + - + - + - - - + - +
           libtiff4legge e scrive file TIFF, con 8 e 16 bit per colorelegge e scrive file TIFF, +con 8 e 16 bit per colore
           xdg-utilsapre file di testo o HTML con l'applicazione preferita dall'utenteapre file di testo o HTML +con l'applicazione preferita dall'utente
           exiftool
        -
        legge e scrive i metadati in un file (EXIF: etichette, commenti ecc.)
        - +
        legge e scrive i metadati +in un file (EXIF: etichette, commenti ecc.)
           ufraw-batch 
        - +
           +ufraw-batch 
        importa e converte immagini RAW dalle macchine digitaliimporta e converte +immagini RAW dalle macchine digitali
           brasero scrive CD o DVD (per creare supporti con fotografie e immagini)scrive CD o DVD (per +creare supporti con fotografie e immagini)
        +
        -Pacchetti necessari per compilare Fotoxx dai sorgenti
        -Vedere il file README per sapere come compilare Fotoxx.
        +Pacchetti +necessari per compilare Fotoxx dai sorgenti
        + +Vedere il file README per sapere +come compilare Fotoxx.
        In aggiunta a quanto elencato prima, serve anche quanto segue:

        - + - + - - + -
           g++
        -
        Il compilatore C++ GNU
           libgtk2.0-dev 
        - +
           +libgtk2.0-dev 
        +
        librerie di sviluppo +Gnome (GTK/GDK/Pixbuf/ecc.)
        librerie di sviluppo Gnome (GTK/GDK/Pixbuf/ecc.)
        -
           libtiff4-devlibreria di sviluppo TIFF libreria di sviluppo TIFF +

        + + +
        + Nota: i nomi dei pacchetti e il loro contenuto preciso dipendono da ogni distribuzione di Linux. I pacchetti elencati prima sono validi per le distribuzioni basate su -Debian (quindi Ubuntu inclusa). Per le altre distribuzioni - possibile che servano pacchetti leggermente diversi.
        +Debian (quindi Ubuntu è inclusa). Per le altre distribuzioni +è possibile che servano pacchetti leggermente diversi.

        -Opzioni della linea di comando
        - - - - - - - - - - - - - - - - - - - +
           fotoxx -/.../imagefile.jpg
        - +Opzioni della +linea di comando
        + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + -
        directory o file iniziali da aprire
           fotoxx -l lccodice di lingua per la GUI (interfaccia utente): it, de, fr, es...
           fotoxx --vscrive il numero di versione e la data di compilazione e termina
           fotoxx -slideshow /.../image1.jpg
        -             -music /.../playlist.pls
        inizia uno slide show con image1 e seguenti, e una musica di sottofondo opzionale
        +
        -v
        +
        mostra versione e data compilazione, ed esce
        +
        /.../imagefile.jpgdirectory o file iniziali da +aprire
        -recent  (o -r)mostra una galleria di immagini recenti (il +più recente in cima)
        -prev (o -p) + apre l'ultima immagine usata
        +
        -lang lc_RCcodice di lingua per +l'interfaccia, più codice regione opzionale: it_IT, de_AT, fr, +es...
        -slideshow /.../image1.jpg
        +[-music /.../playlist.pls]
        inizia uno slide show con image1 +e seguenti, e una musica di sottofondo opzionale
        +
        -translate (o -t)
        +
        inizia subito il modo traduzione interattivo +(per tradurre i menù)

        +
        + +
        Informazioni della barra di stato

        -Esempio:  CPU 123%  1234x987x24  0.45MB  56%   edits: 3   menu locked   area active
        +Esempio:  CPU +123%  1234x987x24  0.45MB  56%   edits: 3   +menu locked   area active
        + - - - + - + - + - + - + - - + - - +
           CPU 123%
        -
        impegno di CPU del processo Fotoxxper tutte i thread
        - +
        impegno di CPU del +processo Fotoxxper tutte i thread
           1234x987x8 
        - +
           +1234x987x8 
        dimensioni immagine: larghezza x altezza x profondit (bit per colori)dimensioni immagine: +larghezza x altezza x profondità (bit per colori)
           0.45MB dimensioni del file (aggiornato al salvataggio del file)dimensioni del file +(aggiornato al salvataggio del file)
           56% quantit di zoom, in % sulle dimensioni dell'immaginequantità di zoom, +in % sulle dimensioni dell'immagine
           edits: 3
        -
        funzioni di ritocco applicate e annullabili col pulsante [Annulla]
        -
        funzioni di ritocco +applicate e annullabili col pulsante [Annulla]
        +
           menu locked  
        - +
           menu +locked  
        una funzione di modifica attiva, e le altre funzioni sono indisponibiliuna funzione di modifica +è attiva, e le altre funzioni sono indisponibili
           area active  
        - +
           area +active  
        una selezione di area attiva, e le modifiche sono confinate entro la selezioneuna selezione di area +è attiva, e le modifiche sono confinate entro la selezione
        +
        -Tipi di file supportati
        +Tipi di file +supportati
        + Fotoxx usa due librerie per leggere e scrivere i file grafici: la GDK pixbuf e libtiff. Pixbuf supporta JPEG, PNG, ICO e BMP, tutti con tre colori RGB e 8 bit per colore. Libtiff supporta file TIFF con 1 bit di colore (bianco e nero), scala di grigi con 8 e 16 bit, e colore RGB con 8 o 16 bit. Altri formati TIFF non sono supportati da Fotoxx, anche se potrebbero essere -aggiunti in caso di necessit. Immagini in bianco e nero o a +aggiunti in caso di necessità. Immagini in bianco e nero o a scala di grigi sono trattati come RGB a colori, con tutti i canali RGB allo stesso livello (toni di grigio). Fotoxx converte immagini RAW in TIFF con 16 bit per colore usando il programma ufraw-batch.

        -Testo mancante nei pulsanti della barra
        -Questo un problema di +Testo +mancante nei pulsanti della barra
        + +Questo è un problema di configurazione di Gnome. L'impostazione predefinita varia con la fase lunare. Aprire un terminale e richiamare il comando "gconf-editor". Selezionare nel dialogo "desktop > gnome > @@ -4532,142 +4912,162 @@
        -Profondit di colore
        +Profondità +di colore
        + 8 bit per colore (256 -livelli di luminosit), come supportato dai file JPEG, -la norma per i file grafici e solitamente adeguato. I monitor +livelli di luminosità), come supportato dai file JPEG, è +la norma per i file grafici e solitamente è adeguato. I monitor LCD sono limitati a 8 bit, e l'intervallo effettivo di -luminosit per la carta fotografica inferiore a 8 bit. -Un passo di luminosit (1/256esimo o 0,4% sulla gamma) +luminosità per la carta fotografica è inferiore a 8 bit. +Un passo di luminosità (1/256esimo o 0,4% sulla gamma) è modlto difficile da distinguere. 16 bit per colore possono essere utili -se un piccolo intervallo di luminosit stato molto +se un piccolo intervallo di luminosità è stato molto amplificato (usando alcune funzioni di fotoritocco). Questa -amplificazione pu portare a bande visibili o "picket +amplificazione può portare a bande visibili o "picket fence distribution". Se l'immagine era stata convertita da RAW a TIFF a -16 bit prima della modifica, questa problema pu essere ridotto, +16 bit prima della modifica, questa problema può essere ridotto, anche se l'immagine viene convertita a soli 8 bit in salvataggio (JPEG) o visualizzata su un monitor.
        -
        +

        -Algoritmo di allineamento (HDR, HDF, Stack, Panorama)
        +Algoritmo di +allineamento (HDR, HDF, +Stack, Panorama)
        + Relativamente pochi pixel "di confine" con alto contrasto vengono selezionati per controllare l'allineamento nella combinazione di immagini HDR, HDF, Stack and Panorama. I pixel scelti sono mostrati in rosso durante il processo, il -che pure divertente. Ogni immagine della sequenza -deformata variamente in piccole quantit e poi la corrispondenza -con l'immagine di riferimento viene controllata. Ci viene fatto -perch due foto fatte con piccole differenze di angolo o di +che è pure divertente. Ogni immagine della sequenza è +deformata variamente in piccole quantità e poi la corrispondenza +con l'immagine di riferimento viene controllata. Ciò viene fatto +perché due foto fatte con piccole differenze di angolo o di orizzonte non possono corrispondere perfettamente con semplici traslazioni e rotazioni. Anche la proiezione cilindrica usata per i -panorami solo un'approssimazione di quello che la lente della +panorami è solo un'approssimazione di quello che la lente della macchina fotografica fa realmente.


        -Algoritmo di Mappatura del tono
        +Algoritmo di +Mappatura del tono
        + Il metodo usato da Fotoxx - "fatto in casa", ma ispirato da Fattal e altri metodi basati -sul gradiente. Non efficace come Fattal in alcuni casi, ma si -avvicina. D'altra parte, Fotoxx semplice e rapido.
        +è "fatto in casa", ma ispirato da Fattal e altri metodi basati +sul gradiente. Non è efficace come Fattal in alcuni casi, ma si +avvicina. D'altra parte, Fotoxx è semplice e rapido.


        Canali alpa
        + Immagini che hanno canali alfa (informazioni sulla trasparenza) possono essere processate, ma il canale alfa viene perso quando l'immagine viene salvata.
        -
        -Deterioramento dell'immagine per manipolazioni ripetute
        +Deterioramento +dell'immagine per manipolazioni ripetute
        + Se si salva un'immagine modificata e il relativo file viene usato in seguito per ulteriori -modifiche, la risoluzione del pixel pu andare persa. E' meglio +modifiche, la risoluzione del pixel può andare persa. E' meglio eseguire tutte le modifiche nella prima sessione per minimizzare questo deterioramento, o usare di nuovo gli originali. Le seguenti funzioni di modifica riducono la risoluzione di circa 1/2 pixel, e l'errore -pu accumularsi se si salva e si riapre l'immagine tra una +può accumularsi se si salva e si riapre l'immagine tra una modifica e l'altra: Ruota immagine (angoli diversi da 90 gradi); HDR, HDF, Sovrapponi, Panorama, Svolgi, Deforma. Ridurre le dimensioni di un'immagine riduce naturalmente la risoluzione, ma usare le frazioni 1/2, 1/3, o 1/4 conduce ai risultati migliori. Le seguenti funzioni non riducono la risoluzione: Bilanciamento del bianco, Normalizza -luminosit, Luminosit e colore, Mappatura della luce, -Espandi luminosit, Mappa tonalit, Correzione occhi +luminosità, Luminosità e colore, Mappatura della luce, +Espandi luminosità, Mappa tonalità, Correzione occhi rossi, Contrasta immagine, Riduci disturbo, Ritaglia, Rifletti, e tutte le funzioni "artistiche".
        -
        Deterioramento dell'immagine per ripetuti salvataggi
        +
        + +Deterioramento +dell'immagine per ripetuti salvataggi
        + Aprire un JPEG compresso e risalvarlo porta a qualche deterioramento, -ma l'effetto trascurabile - per lo meno con l'algoritmo usato -da Fotoxx (libreria Pixbuf GTK) e la qualit JPEG impostata a un +ma l'effetto è trascurabile - per lo meno con l'algoritmo usato +da Fotoxx (libreria Pixbuf GTK) e la qualità JPEG impostata a un valore alto. Ho letto e salvato un JPEG 20 volte usando una -qualit di 90: una comparazione rapida con l'originale ha -mostrato una leggera riduzione della luminosit dei colori -pi brillanti, ma nessuna perdita visibile di risoluzione. I +qualità di 90: una comparazione rapida con l'originale ha +mostrato una leggera riduzione della luminosità dei colori +più brillanti, ma nessuna perdita visibile di risoluzione. I formati TIFF e PNG sono lossless (senza perdite) e quindi non hanno -deterioramento - consumano per un sacco di spazio.
        +deterioramento - consumano però un sacco di spazio.


        Errori EXIF
        + Le macchine digitali -(specialmente quelle pi vecchie) non sempre producono dati EXIF +(specialmente quelle più vecchie) non sempre producono dati EXIF strutturalmente corretti, e il programma exiftool (usato da Fotoxx per -manipolare quei dati) pu produrre messaggi di errore. Sono -riuscito a correggere quei casi salvando l'immagine sopra s -stessa, il che rimpiazza i dati EXIF con ci che exiftool era +manipolare quei dati) può produrre messaggi di errore. Sono +riuscito a correggere quei casi salvando l'immagine sopra sé +stessa, il che rimpiazza i dati EXIF con ciò che exiftool era riuscito a leggere correttamente. Se le etichette vanno perse, devono essere ripristinate a mano.


        -Caratteri di "a capo" (newline) in Commenti o Titoli
        +Caratteri di +"a capo" (newline) in Commenti o Titoli
        + Quando si introducono Commenti o -Titoli, se occorre allineare il testo in colonne, si pu usare +Titoli, se occorre allineare il testo in colonne, si può usare il tasto Invio per creare nuove linee. Questi "a capo" vengono convertiti in stringhe "\n" prima di salvarli nei dati EXIF/IPTC -perch non sono consentiti (exiftool li converte in punti). +perché non sono consentiti (exiftool li converte in punti). Quando il testo viene ricaricato, i vari "\n" vengono convertiti in "a -capo", cosicch l'allineamento originale del testo viene -ripristinato. Tutto questo non standard, quindi non ci si -pu aspettare di vedere il testo ancora allineato in altri -programmi come Photoshop. Se invece questo richiesto, non +capo", cosicchè l'allineamento originale del testo viene +ripristinato. Tutto questo non è standard, quindi non ci si +può aspettare di vedere il testo ancora allineato in altri +programmi come Photoshop. Se invece questo è richiesto, non usare il tasto Invio per generare nuove linee durante l'immissione di un lungo testo - lasciare invece che il testo sbordi da solo sulle righe seguenti.


        -Directory standard per il Cestino
        +Directory +standard per il Cestino
        -Se il men +Se il menù [File->Cestina immagine] e l'analogo pulsante della barra non spostano i file nel Cestino standard (dove possono essere recuperati -usando gli strumenti normali del desktop/scrivania), pu essere +usando gli strumenti normali del desktop/scrivania), può essere possibile rimediare al problema da soli. Se i file d'immagini non sono nel disco "/home" potrebbe, d'ufficio, non essere disponibile. Si -pu aggiungere il cestino seguendo questo esempio: se il disco -con le immagini montato come "/immagini" e il vostro UID (ID -utente) 1000, dovrebbe esserci una directory chiamata +può aggiungere il cestino seguendo questo esempio: se il disco +con le immagini è montato come "/immagini" e il vostro UID (ID +utente) è 1000, dovrebbe esserci una directory chiamata "/immagini/.Trash-1000", con proprietario UID=1000, e con pieni permessi per l'UID 1000. La funzione standard di cestinamento -metter l i file cancellati. Aggiungere questa directory +metterà là i file cancellati. Aggiungere questa directory manualmente se essa non esiste - questo potrebbe risolvere il problema.

        -
        File speciali di Fotoxx
        - -I seguenti file risiedono in "/home/<utente>/.fotoxx/". Il file search_index duplica i dati EXIF e IPTC -delle immagini; esso usato perch incrementa lettura e ricerca di tali dati di un fattore 1000.
        +
        File +speciali di Fotoxx
        + +I seguenti file risiedono in "/home/<utente>/.fotoxx/". Il file +search_index duplica i dati EXIF e IPTC +delle immagini; esso è usato perché incrementa lettura e +ricerca di tali dati di un fattore 1000.
        @@ -4675,97 +5075,86 @@ - - - + - - - + - - - - - - - @@ -4773,7 +5162,8 @@
        Codice sorgente

        -Il codice sorgente C++ + +Il codice sorgente C++ è fortemente commentato nella speranza che altre persone possano capire e usare il codice per i loro progetti. Se qualcuno ha qualche domanda tecnica su come qualche funzione lavora, o qualche suggerimento da @@ -4781,60 +5171,62 @@
        -Domande e problemi
        +Domande e +problemi
        + -Se qualcuno ha qualche domanda o incappa in un problema, pu contattare l'autore. -Se mi mandate qualsiasi immagine che d scarsi risultati, posso +Se qualcuno ha qualche domanda o incappa in un problema, può contattare l'autore. +Se mi mandate qualsiasi immagine che dà scarsi risultati, posso usarla per cercare di migliorare Fotoxx. Se si trova un listato di traceback sullo schermo, o messaggi di errore nel file -/home/<utente>/.fotoxx/fotoxx.log, si pregati d'inviare +/home/<utente>/.fotoxx/fotoxx.log, si è pregati d'inviare pure quelli. Si prega di spiegare esattamente come riprodurre l'errore, -e quale versione di Fotoxx e quale distribuzione di Linux +e quale versione di Fotoxx e quale distribuzione di Linux è stata utilizzata.

        -Come ottenere un traceback con i numeri di linea del sorgente
        +Come ottenere +un traceback con i numeri di linea del sorgente
        + Se s'incontra un crash, mi - molto pi facile cercarlo e correggerlo se posso avere -il traceback con i numeri di linea del sorgente. Questo un +è molto più facile cercarlo e correggerlo se posso avere +il traceback con i numeri di linea del sorgente. Questo è un metodo per produrre il backtrace: in un terminale, eseguire il comando -"gdb fotoxx". Fotoxx partir sotto il controllo del debugger GNU +"gdb fotoxx". Fotoxx partirà sotto il controllo del debugger GNU "gdb". In Fotoxx, eseguire l'operazione che genera il crash; il -programma gdb dir che fotoxx andato in crash. Dentro +programma gdb dirà che fotoxx è andato in crash. Dentro gdb, immettere il comando "backtrace" (senza virgolette); -dopodich, immettere "q" (quit, per terminare) e "y" (yes, +dopodiché, immettere "q" (quit, per terminare) e "y" (yes, conferma al comando). Copiare tutto il testo di gdb dalla finestra del -terminale, incollare dentro un messaggio e-mail, e inviarmelo (e-mail), insieme con la descrizione di ci che ha provocato il crash.
        +terminale, incollare dentro un messaggio e-mail, e inviarmelo (
        e-mail), insieme con la descrizione di +ciò che ha provocato il crash.
        -
        -Libro di riferimenti tecnici
        +Libro di +riferimenti tecnici
        + Raccomando il libro "Introduction to Image Processing and Analysis" di Russ and Russ, edizioni CRC Press. E' chiaro e conciso. I seguenti algoritmi sono -stati adattati da tale libro: Normalizza la luminosit, Maschera +stati adattati da tale libro: Normalizza la luminosità, Maschera di contrasto, Riduzione del disturbo (valore mediano e "top hat"), Bassorilievo. Le trasformazioni affini per la deformazione e la rotazione sono state trovate usando Google.

        Ringraziamenti
        + I programmi libtiff, ufraw, exiftool e brasero -hanno aiutato Fotoxx a evolvere molto pi velocemente di quanto +hanno aiutato Fotoxx a evolvere molto più velocemente di quanto sarebbe stato possibile senza. Naturalmente questo riguarda anche GTK, GDK, la libreria pixbuf, gli strumenti e librerie GNU, e l'intero ecosistema GNU/Linux. Grazie a coloro che hanno donato il loro tempo per le traduzioni e le prove (vedere [Aiuto->Info], e a coloro che hanno contribuito con le loro idee allo sviluppo del programma.
        - - - - - -
        + \ No newline at end of file diff -Nru fotoxx-11.11.1/f.art.cc fotoxx-12.01.2/f.art.cc --- fotoxx-11.11.1/f.art.cc 1970-01-01 00:00:00.000000000 +0000 +++ fotoxx-12.01.2/f.art.cc 2012-01-04 08:47:11.000000000 +0000 @@ -0,0 +1,1805 @@ +/************************************************************************** + + Fotoxx edit photos and manage collections + + Copyright 2007 2008 2009 2010 2011 2012 Michael Cornelison + Source URL: http://kornelix.squarespace.com/fotoxx + Contact: kornelix2@googlemail.com + + 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 http://www.gnu.org/licenses/. + +***************************************************************************/ + +#define EX extern // enable extern declarations +#include "fotoxx.h" + + +/************************************************************************** + + Fotoxx image edit - arty transformation functions + +***************************************************************************/ + + +// image color-depth reduction + +int colordep_depth = 16; // bits per RGB color + +editfunc EFcolordep; + + +void m_colordep(GtkWidget *, cchar *) +{ + int colordep_dialog_event(zdialog *zd, cchar *event); + void * colordep_thread(void *); + + cchar *colmess = ZTX("Set color depth to 1-16 bits"); + + zfuncs::F1_help_topic = "color_depth"; // v.10.8 + + EFcolordep.funcname = "color-depth"; + EFcolordep.Fprev = 1; // use preview + EFcolordep.Farea = 2; // select area usable + EFcolordep.threadfunc = colordep_thread; // thread function + if (! edit_setup(EFcolordep)) return; // setup edit + + zdialog *zd = zdialog_new(ZTX("Set Color Depth"),mWin,Bdone,Bcancel,null); + EFcolordep.zd = zd; + + zdialog_add_widget(zd,"label","lab1","dialog",colmess,"space=5"); + zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=10"); + zdialog_add_widget(zd,"spin","colors","hb1","1|16|1|16","space=5"); + + zdialog_help(zd,"color_depth"); // zdialog help topic v.11.08 + zdialog_run(zd,colordep_dialog_event,"-10/20"); // run dialog, parallel v.11.07 + + colordep_depth = 16; + return; +} + + +// dialog event and completion callback function + +int colordep_dialog_event(zdialog *zd, cchar *event) +{ + if (zd->zstat) // dialog complete + { + if (zd->zstat == 1) edit_done(EFcolordep); + else edit_cancel(EFcolordep); + return 0; + } + + if (strEqu(event,"undo")) edit_undo(); // v.10.2 + if (strEqu(event,"redo")) edit_redo(); // v.10.3 + if (strEqu(event,"blendwidth")) signal_thread(); // v.10.3 + + if (strEqu(event,"colors")) { + zdialog_fetch(zd,"colors",colordep_depth); + signal_thread(); + } + + return 0; +} + + +// image color depth thread function + +void * colordep_thread(void *) +{ + int ii, px, py, rgb, dist = 0; + uint16 m1, m2, val1, val3; + uint16 *pix1, *pix3; + double fmag, f1, f2; + + while (true) + { + thread_idle_loop(); // wait for work or exit request + + m1 = 0xFFFF << (16 - colordep_depth); // 5 > 1111100000000000 + m2 = 0x8000 >> colordep_depth; // 5 > 0000010000000000 + + fmag = 65535.0 / m1; + + for (py = 0; py < E3hh; py++) + for (px = 0; px < E3ww; px++) + { + if (Factivearea) { // select area active + ii = py * Fww + px; + dist = sa_pixmap[ii]; // distance from edge + if (! dist) continue; // outside pixel + } + + pix1 = PXMpix(E1pxm16,px,py); // input pixel + pix3 = PXMpix(E3pxm16,px,py); // output pixel + + for (rgb = 0; rgb < 3; rgb++) + { + val1 = pix1[rgb]; + if (val1 < m1) val3 = (val1 + m2) & m1; + else val3 = m1; + val3 = uint(val3 * fmag); + + if (Factivearea && dist < sa_blend) { // select area is active, + f2 = 1.0 * dist / sa_blend; // blend changes over sa_blend + f1 = 1.0 - f2; + val3 = int(f1 * val1 + f2 * val3); + } + + pix3[rgb] = val3; + } + } + + CEF->Fmod = 1; + mwpaint2(); // update window + } + + return 0; // not executed, stop g++ warning +} + + +/**************************************************************************/ + +// convert image to simulate a drawing + +int draw_contrast; +int draw_threshold; +int draw_pixcon; +int draw_reverse; +double draw_trfunc[256]; +double draw_pixcon3; +uint8 *draw_pixcon_map = 0; + +editfunc EFdraw; + + +void m_draw(GtkWidget *, cchar *) +{ + int draw_dialog_event(zdialog* zd, cchar *event); + void * draw_thread(void *); + + cchar *title = ZTX("Simulate Drawing"); + uint16 *pix1, *pix2; + int ii, px, py, qx, qy; + int red, green, blue, con, maxcon; + + zfuncs::F1_help_topic = "drawing"; // v.10.8 + + EFdraw.funcname = "drawing"; + EFdraw.Farea = 2; // select area usable + EFdraw.threadfunc = draw_thread; // thread function + if (! edit_setup(EFdraw)) return; // setup edit + + draw_pixcon_map = (uint8 *) zmalloc(E1ww*E1hh,"draw"); // set up pixel contrast map + memset(draw_pixcon_map,0,E1ww*E1hh); + + for (py = 1; py < E1hh-1; py++) // scan image pixels + for (px = 1; px < E1ww-1; px++) + { + pix1 = PXMpix(E1pxm16,px,py); // pixel at (px,py) + red = pix1[0]; // pixel RGB levels + green = pix1[1]; + blue = pix1[2]; + maxcon = 0; + + for (qy = py-1; qy < py+2; qy++) // loop 3x3 block of neighbor + for (qx = px-1; qx < px+2; qx++) // pixels around pix1 + { + pix2 = PXMpix(E1pxm16,qx,qy); // find max. contrast with + con = abs(red-pix2[0]) + abs(green-pix2[1]) + abs(blue-pix2[2]); // neighbor pixel + if (con > maxcon) maxcon = con; + } + + ii = py * E1ww + px; + draw_pixcon_map[ii] = (maxcon/3) >> 8; // contrast for (px,py) 0-255 + } + + zdialog *zd = zdialog_new(title,mWin,Bdone,Bcancel,null); + EFdraw.zd = zd; + + zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=10"); + zdialog_add_widget(zd,"vbox","vb1","hb1",0,"homog"); + zdialog_add_widget(zd,"vbox","vb2","hb1",0,"homog|expand"); + zdialog_add_widget(zd,"label","lab1","vb1",ZTX("contrast")); + zdialog_add_widget(zd,"label","lab2","vb1",Bthresh); + zdialog_add_widget(zd,"label","lab3","vb1",ZTX("outlines")); + zdialog_add_widget(zd,"hscale","contrast","vb2","0|100|1|0","expand"); + zdialog_add_widget(zd,"hscale","threshold","vb2","0|100|1|0","expand"); + zdialog_add_widget(zd,"hscale","pixcon","vb2","0|255|1|0","expand"); + zdialog_add_widget(zd,"hbox","hb4","dialog"); + zdialog_add_widget(zd,"radio","pencil","hb4",ZTX("pencil"),"space=10"); + zdialog_add_widget(zd,"radio","chalk","hb4",ZTX("chalk"),"space=10"); + + zdialog_resize(zd,300,0); + zdialog_help(zd,"drawing"); // zdialog help topic v.11.08 + zdialog_run(zd,draw_dialog_event,"-10/20"); // run dialog, parallel v.11.07 + + return; +} + + +// dialog event and completion callback function + +int draw_dialog_event(zdialog *zd, cchar *event) // draw dialog event function +{ + if (zd->zstat) // dialog complete + { + if (zd->zstat == 1) edit_done(EFdraw); + else edit_cancel(EFdraw); + zfree(draw_pixcon_map); + return 0; + } + + if (strEqu(event,"undo")) edit_undo(); // v.10.2 + if (strEqu(event,"redo")) edit_redo(); // v.10.3 + if (strEqu(event,"blendwidth")) signal_thread(); // v.10.3 + + if (strcmpv(event,"contrast","threshold","pixcon","chalk",null)) + { + zdialog_fetch(zd,"contrast",draw_contrast); // get slider values + zdialog_fetch(zd,"threshold",draw_threshold); + zdialog_fetch(zd,"pixcon",draw_pixcon); + zdialog_fetch(zd,"chalk",draw_reverse); + signal_thread(); // trigger update thread + } + + return 1; +} + + +// thread function - use multiple working threads + +void * draw_thread(void *) +{ + void * draw_wthread(void *arg); + + int ii; + double threshold, contrast, trf; + + while (true) + { + thread_idle_loop(); // wait for work or exit request + + threshold = 0.01 * draw_threshold; // range 0 to 1 + contrast = 0.01 * draw_contrast; // range 0 to 1 + + for (ii = 0; ii < 256; ii++) // brightness transfer function + { + trf = 1.0 - 0.003906 * (256 - ii) * contrast; // ramp-up from 0-1 to 1 + if (ii < 256 * threshold) trf = 0; // 0 if below threshold + draw_trfunc[ii] = trf; + } + + for (ii = 0; ii < Nwt; ii++) // start worker threads + start_wthread(draw_wthread,&wtnx[ii]); + wait_wthreads(); // wait for completion + + CEF->Fmod = 1; + mwpaint2(); // update window + } + + return 0; // not executed, stop g++ warning +} + + +void * draw_wthread(void *arg) // worker thread function +{ + void draw_1pix(int px, int py); + + int index = *((int *) (arg)); + int px, py; + double pixcon; + + pixcon = draw_pixcon / 255.0; // 0-1 linear ramp + draw_pixcon3 = 255 * pixcon * pixcon * pixcon; // 0-255 cubic ramp + + for (py = index+1; py < E1hh-1; py += Nwt) // process all pixels + for (px = 1; px < E1ww-1; px++) + draw_1pix(px,py); + + exit_wthread(); + return 0; // not executed, avoid gcc warning +} + + +void draw_1pix(int px, int py) // process one pixel +{ + uint16 *pix1, *pix3; + int ii, dist = 0; + int bright1, bright2; + int red1, green1, blue1; + int red3, green3, blue3; + double dold, dnew; + double pixcon = draw_pixcon3; + + if (Factivearea) { // select area active + ii = py * Fww + px; + dist = sa_pixmap[ii]; // distance from edge + if (! dist) return; // outside pixel + } + + pix1 = PXMpix(E1pxm16,px,py); // input pixel + pix3 = PXMpix(E3pxm16,px,py); // output pixel + + red1 = pix1[0]; + green1 = pix1[1]; + blue1 = pix1[2]; + + bright1 = ((red1 + green1 + blue1) / 3) >> 8; // old brightness 0-255 + bright2 = bright1 * draw_trfunc[bright1]; // new brightness 0-255 + + ii = py * E1ww + px; + if (draw_pixcon_map[ii] < pixcon) bright2 = 255; + + if (pixcon > 1 && bright2 > draw_threshold) bright2 = 255; // empirical !!! + + if (draw_reverse) bright2 = 255 - bright2; // negate if "chalk" + + red3 = green3 = blue3 = bright2 << 8; // gray scale, new brightness + + if (Factivearea && dist < sa_blend) { // select area is active, + dnew = 1.0 * dist / sa_blend; + dold = 1.0 - dnew; + red3 = dnew * red3 + dold * red1; + green3 = dnew * green3 + dold * green1; + blue3 = dnew * blue3 + dold * blue1; + } + + pix3[0] = red3; + pix3[1] = green3; + pix3[2] = blue3; + + return; +} + + +/**************************************************************************/ + +// make an image outline drawing from edge pixels +// superimpose outlines and image and vary brightness of each + +double outlines_olth, outlines_olww, outlines_imbr; + +editfunc EFoutlines; + + +void m_outlines(GtkWidget *, cchar *) +{ + int outlines_dialog_event(zdialog* zd, cchar *event); + void * outlines_thread(void *); + + cchar *title = ZTX("Add Image Outlines"); + + zfuncs::F1_help_topic = "outlines"; + + EFoutlines.funcname = "outlines"; + EFoutlines.Farea = 2; // select area usable + EFoutlines.threadfunc = outlines_thread; // thread function + if (! edit_setup(EFoutlines)) return; // setup edit + + zdialog *zd = zdialog_new(title,mWin,Bdone,Bcancel,null); + EFoutlines.zd = zd; + + zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=5"); + zdialog_add_widget(zd,"label","lab1","hb1",ZTX("outline threshold"),"space=5"); + zdialog_add_widget(zd,"hscale","olth","hb1","0|100|1|90","expand|space=5"); + zdialog_add_widget(zd,"hbox","hb2","dialog",0,"space=5"); + zdialog_add_widget(zd,"label","lab2","hb2",ZTX("outline width"),"space=5"); + zdialog_add_widget(zd,"hscale","olww","hb2","0|100|1|50","expand|space=5"); + zdialog_add_widget(zd,"hbox","hb3","dialog",0,"space=5"); + zdialog_add_widget(zd,"label","lab3","hb3",ZTX("image brightness"),"space=5"); + zdialog_add_widget(zd,"hscale","imbr","hb3","0|100|1|10","expand|space=5"); + + outlines_olth = 90; + outlines_olww = 50; + outlines_imbr = 10; + + zdialog_resize(zd,300,0); + zdialog_help(zd,"outlines"); // zdialog help topic v.11.08 + zdialog_run(zd,outlines_dialog_event,"-10/20"); // run dialog, parallel v.11.07 + + signal_thread(); + return; +} + + +// dialog event and completion callback function + +int outlines_dialog_event(zdialog *zd, cchar *event) // dialog event function +{ + if (zd->zstat) + { + if (zd->zstat == 1) edit_done(EFoutlines); // done + else edit_cancel(EFoutlines); // cancel or destroy + PXM_free(E8pxm16); + PXM_free(E9pxm16); + return 0; + } + + if (strEqu(event,"olth")) { + zdialog_fetch(zd,"olth",outlines_olth); // get outline threshold 0-100 + signal_thread(); + } + + if (strEqu(event,"olww")) { + zdialog_fetch(zd,"olww",outlines_olww); // get outline width 0-100 + signal_thread(); + } + + if (strEqu(event,"imbr")) { + zdialog_fetch(zd,"imbr",outlines_imbr); // get image brightness 0-100 + signal_thread(); + } + + if (strEqu(event,"undo")) edit_undo(); + if (strEqu(event,"redo")) edit_redo(); + if (strEqu(event,"blendwidth")) signal_thread(); + + return 1; +} + + +// thread function to update image + +void * outlines_thread(void *) +{ + void * outlines_wthread(void *arg); + + int px, py, ww, hh; + double olww, red3, green3, blue3; + double red3h, red3v, green3h, green3v, blue3h, blue3v; + uint16 *pix8, *pix9; + uint16 *pixa, *pixb, *pixc, *pixd, *pixe, *pixf, *pixg, *pixh; + + while (true) + { + thread_idle_loop(); // wait for work or exit request + + olww = 0.01 * outlines_olww; // outline width, 0 - 1.0 + olww = 1.0 - olww; // 1.0 - 0 + olww = 0.8 * olww + 0.2; // 1.0 - 0.2 + + ww = Fww * olww + 0.5; // create smaller outline image + hh = Fhh * olww + 0.5; + + if (! E9pxm16 || ww != E9pxm16->ww) // initial or changed outline brightness + { + PXM_free(E8pxm16); + PXM_free(E9pxm16); + + E8pxm16 = PXM_rescale(E1pxm16,ww,hh); + E9pxm16 = PXM_copy(E8pxm16); + + for (py = 1; py < hh-1; py++) + for (px = 1; px < ww-1; px++) + { + pix8 = PXMpix(E8pxm16,px,py); // input pixel + pix9 = PXMpix(E9pxm16,px,py); // output pixel + + pixa = pix8-3*ww-3; // 8 neighboring pixels are used + pixb = pix8-3*ww; // to get edge brightness using + pixc = pix8-3*ww+3; // a Sobel filter + pixd = pix8-3; + pixe = pix8+3; + pixf = pix8+3*ww-3; + pixg = pix8+3*ww; + pixh = pix8+3*ww+3; + + red3h = -pixa[0] -2 * pixb[0] -pixc[0] + pixf[0] + 2 * pixg[0] + pixh[0]; + red3v = -pixa[0] -2 * pixd[0] -pixf[0] + pixc[0] + 2 * pixe[0] + pixh[0]; + green3h = -pixa[1] -2 * pixb[1] -pixc[1] + pixf[1] + 2 * pixg[1] + pixh[1]; + green3v = -pixa[1] -2 * pixd[1] -pixf[1] + pixc[1] + 2 * pixe[1] + pixh[1]; + blue3h = -pixa[2] -2 * pixb[2] -pixc[2] + pixf[2] + 2 * pixg[2] + pixh[2]; + blue3v = -pixa[2] -2 * pixd[2] -pixf[2] + pixc[2] + 2 * pixe[2] + pixh[2]; + + red3 = (abs(red3h) + abs(red3v)) / 2; // average vertical and horizontal brightness + green3 = (abs(green3h) + abs(green3v)) / 2; + blue3 = (abs(blue3h) + abs(blue3v)) / 2; + + if (red3 > 65535) red3 = 65535; + if (green3 > 65535) green3 = 65535; + if (blue3 > 65535) blue3 = 65535; + + pix9[0] = red3; + pix9[1] = green3; + pix9[2] = blue3; + } + } + + PXM_free(E8pxm16); // scale back to full-size + E8pxm16 = PXM_rescale(E9pxm16,Fww,Fhh); + + for (int ii = 0; ii < Nwt; ii++) // start worker threads + start_wthread(outlines_wthread,&wtnx[ii]); + wait_wthreads(); // wait for completion + + CEF->Fmod = 1; + mwpaint2(); // update window + } + + return 0; // not executed, stop g++ warning +} + + +void * outlines_wthread(void *arg) // worker thread function +{ + int index = *((int *) arg); + int px, py, ii, dist = 0; + double olth, imbr, br8, dold, dnew; + double red1, green1, blue1, red3, green3, blue3; + uint16 *pix1, *pix8, *pix3; + + olth = 0.01 * outlines_olth; // outline threshold, 0 - 1.0 + olth = 1.0 - olth; // 1.0 - 0 + imbr = 0.01 * outlines_imbr; // image brightness, 0 - 1.0 + + for (py = index+1; py < Fhh-1; py += Nwt) + for (px = 1; px < Fww-1; px++) + { + if (Factivearea) { // select area active + ii = py * Fww + px; + dist = sa_pixmap[ii]; // distance from edge + if (! dist) continue; // pixel outside area + } + + pix1 = PXMpix(E1pxm16,px,py); // input image pixel + pix8 = PXMpix(E8pxm16,px,py); // input outline pixel + pix3 = PXMpix(E3pxm16,px,py); // output image pixel + + red1 = pix1[0]; // input image pixel + green1 = pix1[1]; + blue1 = pix1[2]; + + br8 = pixbright(pix8); // outline brightness + br8 = br8 / 65536.0; // scale 0 - 1.0 + + if (br8 > olth) { // > threshold, use outline pixel + red3 = pix8[0]; + green3 = pix8[1]; + blue3 = pix8[2]; + } + else { // use image pixel dimmed by user control + red3 = red1 * imbr; + green3 = green1 * imbr; + blue3 = blue1 * imbr; + } + + if (Factivearea && dist < sa_blend) { // select area is active, + dnew = 1.0 * dist / sa_blend; // blend changes over sa_blend + dold = 1.0 - dnew; + red3 = dnew * red3 + dold * red1; + green3 = dnew * green3 + dold * green1; + blue3 = dnew * blue3 + dold * blue1; + } + + pix3[0] = red3; + pix3[1] = green3; + pix3[2] = blue3; + } + + exit_wthread(); + return 0; // not executed, stop gcc warning +} + + +/**************************************************************************/ + +// convert image to simulate an embossing + +int emboss_radius, emboss_color; +double emboss_depth; +double emboss_kernel[20][20]; // support radius <= 9 + +editfunc EFemboss; + + +void m_emboss(GtkWidget *, cchar *) +{ + int emboss_dialog_event(zdialog* zd, cchar *event); + void * emboss_thread(void *); + + cchar *title = ZTX("Simulate Embossing"); + + zfuncs::F1_help_topic = "embossing"; // v.10.8 + + EFemboss.funcname = "emboss"; + EFemboss.Farea = 2; // select area usable + EFemboss.threadfunc = emboss_thread; // thread function + if (! edit_setup(EFemboss)) return; // setup edit + + zdialog *zd = zdialog_new(title,mWin,Bdone,Bcancel,null); + EFemboss.zd = zd; + + zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=10"); + zdialog_add_widget(zd,"label","lab1","hb1",Bradius,"space=5"); + zdialog_add_widget(zd,"spin","radius","hb1","0|9|1|0"); + zdialog_add_widget(zd,"label","lab2","hb1",ZTX("depth"),"space=5"); + zdialog_add_widget(zd,"spin","depth","hb1","0|99|1|0"); + zdialog_add_widget(zd,"check","color","hb1",ZTX("color"),"space=8"); + + zdialog_help(zd,"embossing"); // zdialog help topic v.11.08 + zdialog_run(zd,emboss_dialog_event,"-10/20"); // run dialog, parallel v.11.07 + return; +} + + +// dialog event and completion callback function + +int emboss_dialog_event(zdialog *zd, cchar *event) // emboss dialog event function +{ + if (zd->zstat) // dialog complete + { + if (zd->zstat == 1) edit_done(EFemboss); + else edit_cancel(EFemboss); + return 0; + } + + if (strEqu(event,"undo")) edit_undo(); // v.10.2 + if (strEqu(event,"redo")) edit_redo(); // v.10.3 + if (strEqu(event,"blendwidth")) signal_thread(); // v.10.3 + + if (strcmpv(event,"radius","depth","color",null)) + { + zdialog_fetch(zd,"radius",emboss_radius); // get user inputs + zdialog_fetch(zd,"depth",emboss_depth); + zdialog_fetch(zd,"color",emboss_color); + signal_thread(); // trigger update thread + } + + return 1; +} + + +// thread function - use multiple working threads + +void * emboss_thread(void *) +{ + void * emboss_wthread(void *arg); + + int ii, dx, dy, rad; + double depth, kern, coeff; + + while (true) + { + thread_idle_loop(); // wait for work or exit request + + rad = emboss_radius; + depth = emboss_depth; + + coeff = 0.1 * depth / (rad * rad + 1); + + for (dy = -rad; dy <= rad; dy++) // build kernel with radius and depth + for (dx = -rad; dx <= rad; dx++) + { + kern = coeff * (dx + dy); + emboss_kernel[dx+rad][dy+rad] = kern; + } + + emboss_kernel[rad][rad] = 1; // kernel center cell = 1 + + for (ii = 0; ii < Nwt; ii++) // start worker threads + start_wthread(emboss_wthread,&wtnx[ii]); + wait_wthreads(); // wait for comletion + + CEF->Fmod = 1; + mwpaint2(); // update window + } + + return 0; // not executed, stop g++ warning +} + + +void * emboss_wthread(void *arg) // worker thread function +{ + void emboss_1pix(int px, int py); + + int index = *((int *) (arg)); + int px, py; + + for (py = index; py < E1hh; py += Nwt) // process all pixels + for (px = 0; px < E1ww; px++) + emboss_1pix(px,py); + + exit_wthread(); + return 0; // not executed, avoid gcc warning +} + + +void emboss_1pix(int px, int py) // process one pixel +{ + int ii, dist = 0; + int bright1, bright3; + int rgb, dx, dy, rad; + uint16 *pix1, *pix3, *pixN; + double sumpix, kern, dold, dnew; + + if (Factivearea) { // select area active + ii = py * Fww + px; + dist = sa_pixmap[ii]; // distance from edge + if (! dist) return; // outside pixel + } + + rad = emboss_radius; + + if (px < rad || py < rad) return; + if (px > E3ww-rad-1 || py > E3hh-rad-1) return; + + pix1 = PXMpix(E1pxm16,px,py); // input pixel + pix3 = PXMpix(E3pxm16,px,py); // output pixel + + if (emboss_color) + { + for (rgb = 0; rgb < 3; rgb++) + { + sumpix = 0; + + for (dy = -rad; dy <= rad; dy++) // loop surrounding block of pixels + for (dx = -rad; dx <= rad; dx++) + { + pixN = pix1 + (dy * E1ww + dx) * 3; + kern = emboss_kernel[dx+rad][dy+rad]; + sumpix += kern * pixN[rgb]; + + bright1 = pix1[rgb]; + bright3 = sumpix; + if (bright3 < 0) bright3 = 0; + if (bright3 > 65535) bright3 = 65535; + + if (Factivearea && dist < sa_blend) { // select area is active, + dnew = 1.0 * dist / sa_blend; // blend changes over sa_blend + dold = 1.0 - dnew; + bright3 = dnew * bright3 + dold * bright1; + } + + pix3[rgb] = bright3; + } + } + } + + else // use gray scale + { + sumpix = 0; + + for (dy = -rad; dy <= rad; dy++) // loop surrounding block of pixels + for (dx = -rad; dx <= rad; dx++) + { + pixN = pix1 + (dy * E1ww + dx) * 3; + kern = emboss_kernel[dx+rad][dy+rad]; + sumpix += kern * (pixN[0] + pixN[1] + pixN[2]); + } + + bright1 = 0.3333 * (pix1[0] + pix1[1] + pix1[2]); + bright3 = 0.3333 * sumpix; + if (bright3 < 0) bright3 = 0; + if (bright3 > 65535) bright3 = 65535; + + if (Factivearea && dist < sa_blend) { // select area is active, + dnew = 1.0 * dist / sa_blend; // blend changes over sa_blend + dold = 1.0 - dnew; + bright3 = dnew * bright3 + dold * bright1; + } + + pix3[0] = pix3[1] = pix3[2] = bright3; + } + + return; +} + + +/**************************************************************************/ + +// convert image to simulate square tiles + +int tile_size, tile_gap; +uint16 *tile_pixmap = 0; + +editfunc EFtiles; + + +void m_tiles(GtkWidget *, cchar *) +{ + int tiles_dialog_event(zdialog *zd, cchar *event); + void * tiles_thread(void *); + + zfuncs::F1_help_topic = "tiles"; // v.10.8 + + EFtiles.funcname = "tiles"; + EFtiles.Farea = 2; // select area usable + EFtiles.threadfunc = tiles_thread; // thread function + if (! edit_setup(EFtiles)) return; // setup edit + + zdialog *zd = zdialog_new(ZTX("Simulate Tiles"),mWin,Bdone,Bcancel,null); + EFtiles.zd = zd; + + zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=5"); + zdialog_add_widget(zd,"label","labt","hb1",ZTX("tile size"),"space=5"); + zdialog_add_widget(zd,"spin","size","hb1","1|99|1|5","space=5"); + zdialog_add_widget(zd,"button","apply","hb1",Bapply,"space=10"); + zdialog_add_widget(zd,"hbox","hb2","dialog",0,"space=5"); + zdialog_add_widget(zd,"label","labg","hb2",ZTX("tile gap"),"space=5"); + zdialog_add_widget(zd,"spin","gap","hb2","0|9|1|1","space=5"); + + zdialog_help(zd,"tiles"); // zdialog help topic v.11.08 + zdialog_run(zd,tiles_dialog_event,"-10/20"); // run dialog, parallel v.11.07 + + tile_size = 5; + tile_gap = 1; + + tile_pixmap = (uint16 *) zmalloc(E1ww*E1hh*6,"tiles"); // set up pixel color map + memset(tile_pixmap,0,E1ww*E1hh*6); + + return; +} + + +// dialog event and completion callback function + +int tiles_dialog_event(zdialog * zd, cchar *event) +{ + if (zd->zstat) // dialog complete + { + if (zd->zstat == 1) edit_done(EFtiles); + else edit_cancel(EFtiles); + zfree(tile_pixmap); + return 0; + } + + if (strEqu(event,"undo")) edit_undo(); // v.10.2 + if (strEqu(event,"redo")) edit_redo(); // v.10.3 + if (strEqu(event,"blendwidth")) signal_thread(); // v.10.3 + + if (strNeq(event,"apply")) return 0; + + zdialog_fetch(zd,"size",tile_size); // get tile size + zdialog_fetch(zd,"gap",tile_gap); // get tile gap + + if (tile_size < 2) { + edit_reset(); // restore original image + return 0; + } + + signal_thread(); // trigger working thread + return 1; +} + + +// image tiles thread function + +void * tiles_thread(void *) +{ + int sg, gg; + int sumpix, red, green, blue; + int ii, jj, px, py, qx, qy, dist; + double dnew, dold; + uint16 *pix1, *pix3; + + while (true) + { + thread_idle_loop(); // wait for work or exit request + + sg = tile_size + tile_gap; + gg = tile_gap; + + for (py = 0; py < E1hh; py += sg) // initz. pixel color map for + for (px = 0; px < E1ww; px += sg) // given pixel size + { + sumpix = red = green = blue = 0; + + for (qy = py + gg; qy < py + sg; qy++) // get mean color for pixel block + for (qx = px + gg; qx < px + sg; qx++) + { + if (qy > E1hh-1 || qx > E1ww-1) continue; + + pix1 = PXMpix(E1pxm16,qx,qy); + red += pix1[0]; + green += pix1[1]; + blue += pix1[2]; + sumpix++; + } + + if (sumpix) { + red = (red / sumpix); + green = (green / sumpix); + blue = (blue / sumpix); + } + + for (qy = py; qy < py + sg; qy++) // set color for pixels in block + for (qx = px; qx < px + sg; qx++) + { + if (qy > E1hh-1 || qx > E1ww-1) continue; + + jj = (qy * E1ww + qx) * 3; + + if (qx-px < gg || qy-py < gg) { + tile_pixmap[jj] = tile_pixmap[jj+1] = tile_pixmap[jj+2] = 0; + continue; + } + + tile_pixmap[jj] = red; + tile_pixmap[jj+1] = green; + tile_pixmap[jj+2] = blue; + } + } + + if (Factivearea) // process selected area + { + for (ii = 0; ii < Fww * Fhh; ii++) // find pixels in select area + { // v.9.6 + if (! sa_pixmap[ii]) continue; + py = ii / Fww; + px = ii - py * Fww; + dist = sa_pixmap[ii]; // distance from edge + pix3 = PXMpix(E3pxm16,px,py); + jj = (py * E3ww + px) * 3; + + if (dist >= sa_blend) { // blend changes over sa_blend v.10.2 + pix3[0] = tile_pixmap[jj]; + pix3[1] = tile_pixmap[jj+1]; // apply block color to member pixels + pix3[2] = tile_pixmap[jj+2]; + } + else { + dnew = 1.0 * dist / sa_blend; + dold = 1.0 - dnew; + pix1 = PXMpix(E1pxm16,px,py); + pix3[0] = dnew * tile_pixmap[jj] + dold * pix1[0]; + pix3[1] = dnew * tile_pixmap[jj+1] + dold * pix1[1]; + pix3[2] = dnew * tile_pixmap[jj+2] + dold * pix1[2]; + } + } + } + + else // process entire image + { + for (py = 0; py < E3hh-1; py++) // loop all image pixels + for (px = 0; px < E3ww-1; px++) + { + pix3 = PXMpix(E3pxm16,px,py); // target pixel + jj = (py * E3ww + px) * 3; // color map for (px,py) + pix3[0] = tile_pixmap[jj]; + pix3[1] = tile_pixmap[jj+1]; + pix3[2] = tile_pixmap[jj+2]; + } + } + + CEF->Fmod = 1; + mwpaint2(); // update window + } + + return 0; // not executed, stop g++ warning +} + + +/**************************************************************************/ + +// convert image to dot grid (like Roy Lichtenstein) + +int dot_size; // tile size enclosing dots + +editfunc EFdots; + + +void m_dots(GtkWidget *, cchar *) // v.11.01 +{ + int dots_dialog_event(zdialog *zd, cchar *event); + void * dots_thread(void *); + + zfuncs::F1_help_topic = "dot_matrix"; + + EFdots.funcname = "dots"; + EFdots.Farea = 2; // select area usable + EFdots.threadfunc = dots_thread; // thread function + if (! edit_setup(EFdots)) return; // setup edit + + zdialog *zd = zdialog_new(ZTX("Convert Image to Dots"),mWin,Bdone,Bcancel,null); + EFdots.zd = zd; + + zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=5"); + zdialog_add_widget(zd,"label","labt","hb1",ZTX("dot size"),"space=5"); + zdialog_add_widget(zd,"spin","size","hb1","3|99|1|9","space=5"); + zdialog_add_widget(zd,"button","apply","hb1",Bapply,"space=10"); + zdialog_add_widget(zd,"hbox","hb2","dialog",0,"space=5"); + + zdialog_help(zd,"dot_matrix"); // zdialog help topic v.11.08 + zdialog_run(zd,dots_dialog_event,"-10/20"); // run dialog, parallel v.11.07 + + dot_size = 9; + return; +} + + +// dialog event and completion callback function + +int dots_dialog_event(zdialog * zd, cchar *event) +{ + if (zd->zstat) // dialog complete + { + if (zd->zstat == 1) edit_done(EFdots); + else edit_cancel(EFdots); + return 0; + } + + if (strEqu(event,"undo")) edit_undo(); + if (strEqu(event,"redo")) edit_redo(); + if (strEqu(event,"blendwidth")) signal_thread(); + if (strNeq(event,"apply")) return 0; // wait for [apply] + + zdialog_fetch(zd,"size",dot_size); // get dot size + signal_thread(); // trigger working thread + return 1; +} + + +// image dots thread function + +void * dots_thread(void *) +{ + int ds, sumpix, red, green, blue; + int cc, maxrgb, ii, dist, shift1, shift2; + int px, py, px1, px2, py1, py2; + int qx, qy, qx1, qx2, qy1, qy2; + uint16 *pix1, *pix3; + double relmax, radius, radius2a, radius2b, f1, f2; + double f64K = 1.0 / 65536.0; + double fpi = 1.0 / 3.14159; + double dcx, dcy, qcx, qcy, qdist2; + + while (true) + { + thread_idle_loop(); // wait for work or exit request + + mutex_lock(&Fpixmap_lock); + + ds = dot_size; // dot size and tile size + + cc = E3ww * E3hh * 6; // clear output image to black + memset(E3pxm16->bmp,0,cc); + + px1 = 0; // limits for tiles + px2 = Fww - ds; + py1 = 0; + py2 = Fhh - ds; + + if (Factivearea) { // reduce for active area + px1 = sa_minx; + px2 = sa_maxx; + py1 = sa_miny; + py2 = sa_maxy; + if (px2 > Fww - ds) px2 = Fww - ds; + if (py2 > Fhh - ds) py2 = Fhh - ds; + } + + shift1 = 0; + + for (py = py1; py < py2; py += ds) // loop all tiles in input image + { + shift1 = 1 - shift1; // offset alternate rows v.11.02 + shift2 = 0.5 * shift1 * ds; + + for (px = px1 + shift2; px < px2; px += ds) + { + sumpix = red = green = blue = 0; + + for (qy = py; qy < py + ds; qy++) // loop all pixels in tile + for (qx = px; qx < px + ds; qx++) // get mean RGB levels for tile + { + pix1 = PXMpix(E1pxm16,qx,qy); + red += pix1[0]; + green += pix1[1]; + blue += pix1[2]; + sumpix++; + } + + red = (red / sumpix); // mean RGB levels, 0 to 64K + green = (green / sumpix); + blue = (blue / sumpix); + + maxrgb = red; // max. mean RGB level, 0 to 64K + if (green > maxrgb) maxrgb = green; + if (blue > maxrgb) maxrgb = blue; + relmax = f64K * maxrgb; // max. RGB as 0 to 0.999 + + radius = ds * sqrt(fpi * relmax); // radius of dot with maximized color + radius = radius * 0.9; // deliberate reduction v.11.05 + if (radius < 0.5) continue; + + red = 65535.0 * red / maxrgb; // dot color, maximized + green = 65535.0 * green / maxrgb; + blue = 65535.0 * blue / maxrgb; + + dcx = px + 0.5 * ds; // center of dot / tile + dcy = py + 0.5 * ds; + + qx1 = dcx - radius; // pixels within dot radius of center + qx2 = dcx + radius; + qy1 = dcy - radius; + qy2 = dcy + radius; + + radius2a = (radius + 0.5) * (radius + 0.5); + radius2b = (radius - 0.5) * (radius - 0.5); + + for (qy = qy1; qy <= qy2; qy++) // loop all pixels within dot radius + for (qx = qx1; qx <= qx2; qx++) + { + qcx = qx + 0.5; // center of pixel + qcy = qy + 0.5; + qdist2 = (qcx-dcx)*(qcx-dcx) + (qcy-dcy)*(qcy-dcy); // pixel distance**2 from center of dot + if (qdist2 > radius2a) f1 = 0.0; // pixel outside dot, no color + else if (qdist2 < radius2b) f1 = 1.0; // pixel inside dot, full color + else f1 = 1.0 - sqrt(qdist2) + radius - 0.5; // pixel straddles edge, some color + pix3 = PXMpix(E3pxm16,qx,qy); + pix3[0] = f1 * red; + pix3[1] = f1 * green; + pix3[2] = f1 * blue; + } + } + } + + if (Factivearea) // select area active + { + pix1 = (uint16 *) E1pxm16->bmp; + pix3 = (uint16 *) E3pxm16->bmp; + + for (ii = 0; ii < Fww * Fhh; ii++) // loop all pixels + { + dist = sa_pixmap[ii]; + if (dist == 0) memmove(pix3,pix1,6); // pixel outside area, output pixel = input + else if (dist < sa_blend) { + f1 = 1.0 * dist / sa_blend; // pixel in blend region + f2 = 1.0 - f1; + pix3[0] = f1 * pix3[0] + f2 * pix1[0]; // output pixel is mix of input and output + pix3[1] = f1 * pix3[1] + f2 * pix1[1]; + pix3[2] = f1 * pix3[2] + f2 * pix1[2]; + } + pix1 += 3; + pix3 += 3; + } + } + + mutex_unlock(&Fpixmap_lock); + + CEF->Fmod = 1; + mwpaint2(); // update window + } + + return 0; // not executed, stop g++ warning +} + + +/**************************************************************************/ + +// convert image to simulate a painting +// processing a 10 megapixel image needs 140 MB of main memory + +namespace painting_names +{ + editfunc EFpainting; + + int color_depth; + int group_area; + double color_match; + int borders; + + typedef struct { + int16 px, py; + char direc; + } spixstack; + + int Nstack; + spixstack *pixstack; // pixel group search memory + int *pixgroup; // maps (px,py) to pixel group no. + int *groupcount; // count of pixels in each group + + int group; + char direc; + uint16 gcolor[3]; +} + + +void m_painting(GtkWidget *, cchar *) +{ + using namespace painting_names; + + int painting_dialog_event(zdialog *zd, cchar *event); + void * painting_thread(void *); + + zfuncs::F1_help_topic = "painting"; // v.10.8 + + EFpainting.funcname = "painting"; + EFpainting.Farea = 2; // select area usable + EFpainting.threadfunc = painting_thread; // thread function + if (! edit_setup(EFpainting)) return; // setup edit + + zdialog *zd = zdialog_new(ZTX("Simulate Painting"),mWin,Bdone,Bcancel,null); + EFpainting.zd = zd; + + zdialog_add_widget(zd,"hbox","hbcd","dialog",0,"space=1"); + zdialog_add_widget(zd,"label","lab1","hbcd",ZTX("color depth"),"space=5"); + zdialog_add_widget(zd,"spin","colordepth","hbcd","1|5|1|3","space=5"); + + zdialog_add_widget(zd,"hbox","hbts","dialog",0,"space=1"); + zdialog_add_widget(zd,"label","labts","hbts",ZTX("patch area goal"),"space=5"); + zdialog_add_widget(zd,"spin","grouparea","hbts","0|9999|10|1000","space=5"); + + zdialog_add_widget(zd,"hbox","hbcm","dialog",0,"space=1"); + zdialog_add_widget(zd,"label","labcm","hbcm",ZTX("req. color match"),"space=5"); + zdialog_add_widget(zd,"spin","colormatch","hbcm","0|99|1|50","space=5"); + + zdialog_add_widget(zd,"hbox","hbbd","dialog",0,"space=1"); + zdialog_add_widget(zd,"label","labbd","hbbd",ZTX("borders"),"space=5"); + zdialog_add_widget(zd,"check","borders","hbbd",0,"space=2"); + zdialog_add_widget(zd,"button","apply","hbbd",Bapply,"space=10"); + + zdialog_help(zd,"painting"); // zdialog help topic v.11.08 + zdialog_run(zd,painting_dialog_event,"-10/20"); // run dialog, parallel v.11.07 + + return; +} + + +// dialog event and completion callback function + +int painting_dialog_event(zdialog *zd, cchar *event) +{ + using namespace painting_names; + + if (zd->zstat) // dialog complete + { + if (zd->zstat == 1) edit_done(EFpainting); + else edit_cancel(EFpainting); + return 0; + } + + if (strEqu(event,"undo")) edit_undo(); // v.10.2 + if (strEqu(event,"redo")) edit_redo(); // v.10.3 + if (strEqu(event,"blendwidth")) signal_thread(); // v.10.3 + + if (strEqu(event,"apply")) { // apply user settings + zdialog_fetch(zd,"colordepth",color_depth); // color depth + zdialog_fetch(zd,"grouparea",group_area); // target group area (pixels) + zdialog_fetch(zd,"colormatch",color_match); // req. color match to combine groups + zdialog_fetch(zd,"borders",borders); // borders wanted + color_match = 0.01 * color_match; // scale 0 to 1 + + signal_thread(); // do the work + wait_thread_idle(); + } + + return 0; +} + + +// painting thread function + +void * painting_thread(void *) +{ + void painting_colordepth(); + void painting_pixgroups(); + void painting_mergegroups(); + void painting_paintborders(); + void painting_blend(); + + while (true) + { + thread_idle_loop(); // wait for work or exit request + + painting_colordepth(); // set new color depth + painting_pixgroups(); // group pixel patches of a color + painting_mergegroups(); // merge smaller into larger groups + painting_paintborders(); // add borders around groups + painting_blend(); // blend edges of selected area + + CEF->Fmod = 1; + mwpaint2(); // update window + } + + return 0; // not executed, stop g++ warning +} + + +// set the specified color depth, 1-5 bits/color + +void painting_colordepth() +{ + using namespace painting_names; + + int ii, px, py, rgb; + double fmag; + uint16 m1, m2, val1, val3; + uint16 *pix1, *pix3; + + m1 = 0xFFFF << (16 - color_depth); // 5 > 1111100000000000 + m2 = 0x8000 >> color_depth; // 5 > 0000010000000000 + + fmag = 65535.0 / m1; // full brightness range + + if (Factivearea) // process select area + { + for (ii = 0; ii < Fww * Fhh; ii++) + { // v.9.6 + if (! sa_pixmap[ii]) continue; + py = ii / Fww; + px = ii - py * Fww; + + pix1 = PXMpix(E1pxm16,px,py); // input pixel + pix3 = PXMpix(E3pxm16,px,py); // output pixel + + for (rgb = 0; rgb < 3; rgb++) + { + val1 = pix1[rgb]; + if (val1 < m1) val3 = (val1 + m2) & m1; + else val3 = m1; + val3 = uint(val3 * fmag); + pix3[rgb] = val3; + } + } + } + + else // process entire image + { + for (py = 0; py < E3hh; py++) // loop all pixels + for (px = 0; px < E3ww; px++) + { + pix1 = PXMpix(E1pxm16,px,py); // input pixel + pix3 = PXMpix(E3pxm16,px,py); // output pixel + + for (rgb = 0; rgb < 3; rgb++) + { + val1 = pix1[rgb]; + if (val1 < m1) val3 = (val1 + m2) & m1; + else val3 = m1; + val3 = uint(val3 * fmag); + pix3[rgb] = val3; + } + } + } + + return; +} + + +// find all groups of contiguous pixels with the same color + +void painting_pixgroups() +{ + using namespace painting_names; + + void painting_pushpix(int px, int py); + + int cc1, cc2; + int ii, kk, px, py; + int ppx, ppy, npx, npy; + uint16 *pix3; + + cc1 = E3ww * E3hh; + + cc2 = cc1 * sizeof(int); + pixgroup = (int *) zmalloc(cc2,"painting"); // maps pixel to assigned group + memset(pixgroup,0,cc2); + + if (Factivearea) cc1 = sa_Npixel; + + cc2 = cc1 * sizeof(spixstack); + pixstack = (spixstack *) zmalloc(cc2,"painting"); // memory stack for pixel search + memset(pixstack,0,cc2); + + cc2 = cc1 * sizeof(int); + groupcount = (int *) zmalloc(cc2,"painting"); // counts pixels per group + memset(groupcount,0,cc2); + + group = 0; + + for (py = 0; py < E3hh; py++) // loop all pixels + for (px = 0; px < E3ww; px++) + { + kk = py * E3ww + px; + if (Factivearea && ! sa_pixmap[kk]) continue; + if (pixgroup[kk]) continue; // already assigned to group + + pixgroup[kk] = ++group; // assign next group + ++groupcount[group]; + + pix3 = PXMpix(E3pxm16,px,py); + gcolor[0] = pix3[0]; + gcolor[1] = pix3[1]; + gcolor[2] = pix3[2]; + + pixstack[0].px = px; // put pixel into stack with + pixstack[0].py = py; // direction = ahead v.11.04 + pixstack[0].direc = 'a'; + Nstack = 1; + + while (Nstack) // overhauled v.11.02 + { + kk = Nstack - 1; // get last pixel in stack + px = pixstack[kk].px; + py = pixstack[kk].py; + direc = pixstack[kk].direc; + + if (direc == 'x') { + Nstack--; + continue; + } + + if (Nstack > 1) { + ii = Nstack - 2; // get prior pixel in stack + ppx = pixstack[ii].px; + ppy = pixstack[ii].py; + } + else { + ppx = px - 1; // if only one, assume prior = left + ppy = py; + } + + if (direc == 'a') { // next ahead pixel v.11.04 + npx = px + px - ppx; + npy = py + py - ppy; + pixstack[kk].direc = 'r'; // next search direction + } + + else if (direc == 'r') { // next right pixel v.11.04 + npx = px + py - ppy; + npy = py + px - ppx; + pixstack[kk].direc = 'l'; + } + + else { /* direc = 'l' */ // next left pixel v.11.04 + npx = px + ppy - py; + npy = py + ppx - px; + pixstack[kk].direc = 'x'; + } + + if (npx < 0 || npx > E3ww-1) continue; // pixel off the edge v.11.04 + if (npy < 0 || npy > E3hh-1) continue; + + kk = npy * E3ww + npx; + + if (Factivearea && ! sa_pixmap[kk]) continue; // pixel outside area + + if (pixgroup[kk]) continue; // pixel already assigned + + pix3 = PXMpix(E3pxm16,npx,npy); + if (pix3[0] != gcolor[0] || pix3[1] != gcolor[1] // not same color as group + || pix3[2] != gcolor[2]) continue; + + pixgroup[kk] = group; // assign pixel to group + ++groupcount[group]; + + kk = Nstack++; // put pixel into stack + pixstack[kk].px = npx; + pixstack[kk].py = npy; + pixstack[kk].direc = 'a'; // direction = ahead v.11.04 + } + } + + return; +} + + +// merge small pixel groups into adjacent larger groups with best color match + +void painting_mergegroups() +{ + using namespace painting_names; + + int ii, jj, kk, px, py, npx, npy; + int nccc, mcount, group2; + double ff = 1.0 / 65536.0; + double fred, fgreen, fblue, match; + int nnpx[4] = { 0, -1, +1, 0 }; + int nnpy[4] = { -1, 0, 0, +1 }; + uint16 *pix3, *pixN; + + typedef struct { + int group; + double match; + uint16 pixM[3]; + } snewgroup; + + snewgroup *newgroup; + + nccc = (group + 1) * sizeof(snewgroup); + newgroup = (snewgroup *) zmalloc(nccc,"painting"); + + if (Factivearea) // process select area + { + while (true) + { + memset(newgroup,0,nccc); + + for (ii = 0; ii < Fww * Fhh; ii++) // find pixels in select area + { // v.9.6 + if (! sa_pixmap[ii]) continue; + py = ii / Fww; + px = ii - py * Fww; + + kk = E3ww * py + px; // get assigned group + group = pixgroup[kk]; + if (groupcount[group] >= group_area) continue; // group count large enough + + pix3 = PXMpix(E3pxm16,px,py); + + for (jj = 0; jj < 4; jj++) // get 4 neighbor pixels + { + npx = px + nnpx[jj]; + npy = py + nnpy[jj]; + + if (npx < 0 || npx >= E3ww) continue; // off the edge + if (npy < 0 || npy >= E3hh) continue; + + kk = E3ww * npy + npx; + if (! sa_pixmap[kk]) continue; // pixel outside area + if (pixgroup[kk] == group) continue; // already in same group + + pixN = PXMpix(E3pxm16,npx,npy); // match color of group neighbor + fred = ff * abs(pix3[0] - pixN[0]); // to color of group + fgreen = ff * abs(pix3[1] - pixN[1]); + fblue = ff * abs(pix3[2] - pixN[2]); + match = (1.0 - fred) * (1.0 - fgreen) * (1.0 - fblue); // color match, 0 to 1.0 + if (match < color_match) continue; + + if (match > newgroup[group].match) { + newgroup[group].match = match; // remember best match + newgroup[group].group = pixgroup[kk]; // and corresp. group no. + newgroup[group].pixM[0] = pixN[0]; // and corresp. new color + newgroup[group].pixM[1] = pixN[1]; + newgroup[group].pixM[2] = pixN[2]; + } + } + } + + mcount = 0; + + for (ii = 0; ii < Fww * Fhh; ii++) // find pixels in select area + { // v.9.6 + if (! sa_pixmap[ii]) continue; + py = ii / Fww; + px = ii - py * Fww; + + kk = E3ww * py + px; + group = pixgroup[kk]; // test for new group assignment + group2 = newgroup[group].group; + if (! group2) continue; + + if (groupcount[group] > groupcount[group2]) continue; // accept only bigger new group + + pixgroup[kk] = group2; // make new group assignment + --groupcount[group]; + ++groupcount[group2]; + + pix3 = PXMpix(E3pxm16,px,py); // make new color assignment + pix3[0] = newgroup[group].pixM[0]; + pix3[1] = newgroup[group].pixM[1]; + pix3[2] = newgroup[group].pixM[2]; + + mcount++; + } + + if (mcount == 0) break; + } + } + + else // process entire image + { + while (true) + { + memset(newgroup,0,nccc); + + for (py = 0; py < E3hh; py++) // loop all pixels + for (px = 0; px < E3ww; px++) + { + kk = E3ww * py + px; // get assigned group + group = pixgroup[kk]; + if (groupcount[group] >= group_area) continue; // group count large enough + + pix3 = PXMpix(E3pxm16,px,py); + + for (jj = 0; jj < 4; jj++) // get 4 neighbor pixels + { + npx = px + nnpx[jj]; + npy = py + nnpy[jj]; + + if (npx < 0 || npx >= E3ww) continue; // off the edge + if (npy < 0 || npy >= E3hh) continue; + + kk = E3ww * npy + npx; + if (pixgroup[kk] == group) continue; // in same group + + pixN = PXMpix(E3pxm16,npx,npy); // match color of group neighbor + fred = ff * abs(pix3[0] - pixN[0]); // to color of group + fgreen = ff * abs(pix3[1] - pixN[1]); + fblue = ff * abs(pix3[2] - pixN[2]); + match = (1.0 - fred) * (1.0 - fgreen) * (1.0 - fblue); // color match, 0 to 1.0 + if (match < color_match) continue; + + if (match > newgroup[group].match) { + newgroup[group].match = match; // remember best match + newgroup[group].group = pixgroup[kk]; // and corresp. group no. + newgroup[group].pixM[0] = pixN[0]; // and corresp. new color + newgroup[group].pixM[1] = pixN[1]; + newgroup[group].pixM[2] = pixN[2]; + } + } + } + + mcount = 0; + + for (py = 0; py < E3hh; py++) // loop all pixels + for (px = 0; px < E3ww; px++) + { + kk = E3ww * py + px; + group = pixgroup[kk]; // test for new group assignment + group2 = newgroup[group].group; + if (! group2) continue; + + if (groupcount[group] > groupcount[group2]) continue; // accept only bigger new group + + pixgroup[kk] = group2; // make new group assignment + --groupcount[group]; + ++groupcount[group2]; + + pix3 = PXMpix(E3pxm16,px,py); // make new color assignment + pix3[0] = newgroup[group].pixM[0]; + pix3[1] = newgroup[group].pixM[1]; + pix3[2] = newgroup[group].pixM[2]; + + mcount++; + } + + if (mcount == 0) break; + } + } + + zfree(pixgroup); + zfree(pixstack); + zfree(groupcount); + zfree(newgroup); + + return; +} + + +// paint borders between the groups of contiguous pixels + +void painting_paintborders() +{ + using namespace painting_names; + + int ii, kk, px, py, cc; + uint16 *pix3, *pixL, *pixA; + + if (! borders) return; + + cc = E3ww * E3hh; + char * pixblack = zmalloc(cc,"painting"); + memset(pixblack,0,cc); + + if (Factivearea) + { + for (ii = 0; ii < Fww * Fhh; ii++) // find pixels in select area + { // v.9.6 + if (! sa_pixmap[ii]) continue; + py = ii / Fww; + px = ii - py * Fww; + if (px < 1 || py < 1) continue; + + pix3 = PXMpix(E3pxm16,px,py); + pixL = PXMpix(E3pxm16,px-1,py); + pixA = PXMpix(E3pxm16,px,py-1); + + if (pix3[0] != pixL[0] || pix3[1] != pixL[1] || pix3[2] != pixL[2]) + { + kk = ii - 1; + if (pixblack[kk]) continue; + kk += 1; + pixblack[kk] = 1; + continue; + } + + if (pix3[0] != pixA[0] || pix3[1] != pixA[1] || pix3[2] != pixA[2]) + { + kk = ii - E3ww; + if (pixblack[kk]) continue; + kk += E3ww; + pixblack[kk] = 1; + } + } + + for (ii = 0; ii < Fww * Fhh; ii++) // find pixels in select area + { // v.9.6 + if (! sa_pixmap[ii]) continue; + py = ii / Fww; + px = ii - py * Fww; + if (px < 1 || py < 1) continue; + + if (! pixblack[ii]) continue; + pix3 = PXMpix(E3pxm16,px,py); + pix3[0] = pix3[1] = pix3[2] = 0; + } + } + + else + { + for (py = 1; py < E3hh; py++) // loop all pixels + for (px = 1; px < E3ww; px++) // omit top and left + { + pix3 = PXMpix(E3pxm16,px,py); // output pixel + pixL = PXMpix(E3pxm16,px-1,py); // pixel to left + pixA = PXMpix(E3pxm16,px,py-1); // pixel above + + if (pix3[0] != pixL[0] || pix3[1] != pixL[1] || pix3[2] != pixL[2]) + { + kk = E3ww * py + px-1; // have horiz. transition + if (pixblack[kk]) continue; + kk += 1; + pixblack[kk] = 1; + continue; + } + + if (pix3[0] != pixA[0] || pix3[1] != pixA[1] || pix3[2] != pixA[2]) + { + kk = E3ww * (py-1) + px; // have vertical transition + if (pixblack[kk]) continue; + kk += E3ww; + pixblack[kk] = 1; + } + } + + for (py = 1; py < E3hh; py++) + for (px = 1; px < E3ww; px++) + { + kk = E3ww * py + px; + if (! pixblack[kk]) continue; + pix3 = PXMpix(E3pxm16,px,py); + pix3[0] = pix3[1] = pix3[2] = 0; + } + } + + zfree(pixblack); + return; +} + + +// blend edges of selected area + +void painting_blend() +{ + int ii, px, py, dist; + uint16 *pix1, *pix3; + double f1, f2; + + if (Factivearea && sa_blend > 0) + { + for (ii = 0; ii < Fww * Fhh; ii++) // find pixels in select area + { // v.9.6 + dist = sa_pixmap[ii]; + if (! dist || dist >= sa_blend) continue; + + py = ii / Fww; + px = ii - py * Fww; + pix1 = PXMpix(E1pxm16,px,py); // input pixel + pix3 = PXMpix(E3pxm16,px,py); // output pixel + + f2 = 1.0 * dist / sa_blend; // changes over distance sa_blend + f1 = 1.0 - f2; + + pix3[0] = int(f1 * pix1[0] + f2 * pix3[0]); + pix3[1] = int(f1 * pix1[1] + f2 * pix3[1]); + pix3[2] = int(f1 * pix1[2] + f2 * pix3[2]); + } + } + + return; +} + + + diff -Nru fotoxx-11.11.1/f.comp.cc fotoxx-12.01.2/f.comp.cc --- fotoxx-11.11.1/f.comp.cc 1970-01-01 00:00:00.000000000 +0000 +++ fotoxx-12.01.2/f.comp.cc 2012-01-04 08:47:11.000000000 +0000 @@ -0,0 +1,5885 @@ +/************************************************************************** + + Fotoxx edit photos and manage collections + + Copyright 2007 2008 2009 2010 2011 2012 Michael Cornelison + Source URL: http://kornelix.squarespace.com/fotoxx + Contact: kornelix2@googlemail.com + + 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 http://www.gnu.org/licenses/. + +***************************************************************************/ + +#define EX extern // enable extern declarations +#include "fotoxx.h" + + +/************************************************************************** + + Fotoxx image edit functions - composite functions + +***************************************************************************/ + + +// File scope variables and functions for composite images +// used by HDR, HDF, STP, STN, Panorama. + + +int cimNF; // image count, <= 10 +char *cimFile[10]; // image files +PXM *cimPXMf[10]; // original images +PXM *cimPXMs[10]; // alignment images, scaled and curved (pano) +PXM *cimPXMw[10]; // alignment images, warped + +struct cimoffs { // image alignment offsets + double xf, yf, tf; // x, y, theta offsets + double wx[4], wy[4]; // x/y corner warps, 0=NW, 1=NE, 2=SE, 3=SW +}; +cimoffs cimOffs[10]; // image alignment data in E3 output image + +double cimScale; // alignment image size relative to full image +double cimBlend; // image blend width at overlap, pixels (pano) +double cimSearchRange; // alignment search range, pixels +double cimSearchStep; // alignment search step, vpixels +double cimWarpRange; // alignment corner warp range, pixels +double cimWarpStep; // alignment corner warp step, vpixels +double cimSampSize; // pixel sample size +int cimOv1xlo, cimOv1xhi, cimOv1ylo, cimOv1yhi; // rectangle enclosing overlap area, +int cimOv2xlo, cimOv2xhi, cimOv2ylo, cimOv2yhi; // image 1 and image2 coordinates +double cimRGBmf1[3][65536]; // RGB matching factors for pixel comparisons: +double cimRGBmf2[3][65536]; // cimRGBmf1[*][pix1[*]] == cimRGBmf2[*][pix2[*]] +char *cimRedpix = 0; // maps high-contrast pixels for alignment +int cimRedImage; // which image has red pixels +int cimNsearch; // alignment search counter +int cimShowIm1, cimShowIm2; // two images for cim_show_images() +int cimShowAll; // if > 0, show all images +int cimShrink; // image shrinkage from pano image curving +int cimPano; // pano mode flag for cim_align_image() +int cimPanoV; // vertical pano flag + +int cim_load_files(); // load and check selected files +void cim_scale_image(int im, PXM **); // scale image, 1.0 to cimScale (normally < 1) +double cim_get_overlap(int im1, int im2, PXM **); // get overlap area for images (horiz or vert) +void cim_match_colors(int im1, int im2, PXM **); // match image RGB levels >> match data +void cim_adjust_colors(PXM *pxm, int fwhich); // adjust RGB levels from match data +void cim_get_redpix(int im1); // find high-contrast pixels in overlap area +void cim_curve_image(int im); // curve cimPXMs[im] using lens parameters +void cim_curve_Vimage(int im); // vertical pano version +void cim_warp_image(int im); // warp image corners: cimPXMs[im] >> cimPXMw[im] +void cim_warp_image_pano(int im, int fblend); // pano version, all / left side / blend stripe +void cim_warp_image_Vpano(int im, int fblend); // vertical pans version: bottom side corners +void cim_align_image(int im1, int im2); // align image im2 to im1, modify im2 offsets +double cim_match_images(int im1, int im2); // compute match for overlapped images +void cim_show_images(int fnew, int fblend); // combine images >> E3pxm16 >> main window +void cim_show_Vimages(int fnew, int fblend); // vertical pano version +void cim_trim(); // cut-off edges where all images do not overlap +void cim_dump_offsets(cchar *text); // diagnostic tool + + +// load image file into pixmaps cimPXMf[*] and check for errors +// returns 0 if error + +int cim_load_files() // v.10.7 +{ + PXM *pxm; + + for (int imx = 0; imx < cimNF; imx++) + { + PXM_free(cimPXMf[imx]); + pxm = f_load(cimFile[imx],16); // will diagnose errors + if (! pxm) return 0; + cimPXMf[imx] = pxm; + + PXM_fixblue(pxm); // blue=0 >> blue=2 for vpixel() v.11.07 + } + + return 1; +} + + +// scale image from full size) to cimScale (normally < 1.0) + +void cim_scale_image(int im, PXM** pxmout) // v.10.7 +{ + int ww, hh; + + ww = cimScale * cimPXMf[im]->ww; + hh = cimScale * cimPXMf[im]->hh; + + PXM_free(pxmout[im]); + pxmout[im] = PXM_rescale(cimPXMf[im],ww,hh); + + PXM_fixblue(pxmout[im]); // blue=0 >> blue=2 for vpixel() v.11.07 + + return; +} + + +// get overlap area for a pair of images im1 and im2 +// outputs are coordinates of overlap area in im1 and in im2 +// returns overlap width as fraction of image width <= 1.0 + +double cim_get_overlap(int im1, int im2, PXM **pxmx) // v.11.04 +{ + double x1, y1, t1, x2, y2, t2; + double xoff, yoff, toff, costf, sintf; + int ww1, ww2, hh1, hh2, pxM; + PXM *pxm1, *pxm2; + + x1 = cimOffs[im1].xf; // im1, im2 absolute offsets + y1 = cimOffs[im1].yf; + t1 = cimOffs[im1].tf; + x2 = cimOffs[im2].xf; + y2 = cimOffs[im2].yf; + t2 = cimOffs[im2].tf; + + xoff = (x2 - x1) * cos(t1) + (y2 - y1) * sin(t1); // offset of im2 relative to im1 + yoff = (y2 - y1) * cos(t1) - (x2 - x1) * sin(t1); + toff = t2 - t1; + + costf = cos(toff); + sintf = sin(toff); + + pxm1 = pxmx[im1]; + pxm2 = pxmx[im2]; + + ww1 = pxm1->ww; + hh1 = pxm1->hh; + ww2 = pxm2->ww; + hh2 = pxm2->hh; + + cimOv1xlo = 0; // lowest x overlap + if (xoff > 0) cimOv1xlo = xoff; + + cimOv1xhi = ww1-1; // highest x overlap + if (cimOv1xhi > xoff + ww2-1) cimOv1xhi = xoff + ww2-1; + + cimOv1ylo = 0; // lowest y overlap + if (yoff > 0) cimOv1ylo = yoff; + + cimOv1yhi = hh1-1; // highest y overlap + if (cimOv1yhi > yoff + hh2-1) cimOv1yhi = yoff + hh2-1; + + if (toff < 0) cimOv1xlo -= toff * (cimOv1yhi - cimOv1ylo); // reduce for theta offset + if (toff < 0) cimOv1yhi += toff * (cimOv1xhi - cimOv1xlo); + if (toff > 0) cimOv1xhi -= toff * (cimOv1yhi - cimOv1ylo); + if (toff > 0) cimOv1ylo += toff * (cimOv1xhi - cimOv1xlo); + + cimOv1xlo += cimShrink + 3; // account for void areas from + cimOv1xhi += - cimShrink - 3; // image shrinkage from + cimOv1ylo += cimShrink + 3; // cim_curve_image() + cimOv1yhi += - cimShrink - 3; // v.11.04 + + if (cimPanoV) { + if (cimBlend && cimBlend < (cimOv1yhi - cimOv1ylo)) { // reduce y range to cimBlend v.11.04 + pxM = (cimOv1yhi + cimOv1ylo) / 2; + cimOv1ylo = pxM - cimBlend / 2; + cimOv1yhi = pxM + cimBlend / 2; + } + } + else { + if (cimBlend && cimBlend < (cimOv1xhi - cimOv1xlo)) { // reduce x range to cimBlend + pxM = (cimOv1xhi + cimOv1xlo) / 2; + cimOv1xlo = pxM - cimBlend / 2; + cimOv1xhi = pxM + cimBlend / 2; + } + } + + cimOv2xlo = costf * (cimOv1xlo - xoff) + sintf * (cimOv1ylo - yoff); // overlap area in im2 coordinates + cimOv2xhi = costf * (cimOv1xhi - xoff) + sintf * (cimOv1yhi - yoff); + cimOv2ylo = costf * (cimOv1ylo - yoff) + sintf * (cimOv1xlo - xoff); + cimOv2yhi = costf * (cimOv1yhi - yoff) + sintf * (cimOv1xhi - xoff); + + if (cimOv1xlo < 0) cimOv1xlo = 0; // take care of limits + if (cimOv1ylo < 0) cimOv1ylo = 0; + if (cimOv2xlo < 0) cimOv2xlo = 0; + if (cimOv2ylo < 0) cimOv2ylo = 0; + if (cimOv1xhi > ww1-1) cimOv1xhi = ww1-1; + if (cimOv1yhi > hh1-1) cimOv1yhi = hh1-1; + if (cimOv2xhi > ww2-1) cimOv2xhi = ww2-1; + if (cimOv2yhi > hh2-1) cimOv2yhi = hh2-1; + + if (cimPanoV) return 1.0 * (cimOv1yhi - cimOv1ylo) / hh1; // return overlap height <= 1.0 v.11.04 + else return 1.0 * (cimOv1xhi - cimOv1xlo) / ww1; // return overlap width <= 1.0 v.11.03 +} + + +// Get the RGB brightness distribution in the overlap area for each image. +// Compute matching factors to compare pixels within the overlap area. +// compare cimRGBmf1[rgb][pix1[rgb]] to cimRGBmf2[rgb][pix2[rgb]] + +void cim_match_colors(int im1, int im2, PXM **pxmx) // v.10.7 +{ + double Bratios1[3][256]; // image2/image1 brightness ratio per color per level + double Bratios2[3][256]; // image1/image2 brightness ratio per color per level + + uint16 *pix1, vpix2[3]; + int vstat2, px1, py1; + int ii, jj, rgb; + int npix, npix1, npix2, npix3; + int brdist1[3][256], brdist2[3][256]; + double x1, y1, t1, x2, y2, t2; + double xoff, yoff, toff, costf, sintf; + double px2, py2; + double brlev1[3][256], brlev2[3][256]; + double a1, a2, b1, b2, bratio = 1; + double r256 = 1.0 / 256.0; + PXM *pxm1, *pxm2; + + pxm1 = pxmx[im1]; + pxm2 = pxmx[im2]; + + x1 = cimOffs[im1].xf; // im1, im2 absolute offsets + y1 = cimOffs[im1].yf; + t1 = cimOffs[im1].tf; + x2 = cimOffs[im2].xf; + y2 = cimOffs[im2].yf; + t2 = cimOffs[im2].tf; + + xoff = (x2 - x1) * cos(t1) + (y2 - y1) * sin(t1); // offset of im2 relative to im1 + yoff = (y2 - y1) * cos(t1) - (x2 - x1) * sin(t1); + toff = t2 - t1; + + costf = cos(toff); + sintf = sin(toff); + + for (rgb = 0; rgb < 3; rgb++) // clear distributions + for (ii = 0; ii < 256; ii++) + brdist1[rgb][ii] = brdist2[rgb][ii] = 0; + + npix = 0; + + for (py1 = cimOv1ylo; py1 < cimOv1yhi; py1++) // loop overlapped rows + for (px1 = cimOv1xlo; px1 < cimOv1xhi; px1++) // loop overlapped columns + { + pix1 = PXMpix(pxm1,px1,py1); // image1 pixel + if (! pix1[2]) continue; // ignore void pixels + + px2 = costf * (px1 - xoff) + sintf * (py1 - yoff); // corresponding image2 pixel + py2 = costf * (py1 - yoff) - sintf * (px1 - xoff); + vstat2 = vpixel(pxm2,px2,py2,vpix2); + if (! vstat2) continue; // does not exist + + ++npix; // count overlapping pixels + + for (rgb = 0; rgb < 3; rgb++) // accumulate distributions + { // by color in 256 bins + ++brdist1[rgb][int(r256*pix1[rgb])]; + ++brdist2[rgb][int(r256*vpix2[rgb])]; + } + } + + npix1 = npix / 256; // 1/256th of total pixels + + for (rgb = 0; rgb < 3; rgb++) // get brlev1[rgb][N] = mean bright + for (ii = jj = 0; jj < 256; jj++) // for Nth group of image1 pixels + { // for color rgb + brlev1[rgb][jj] = 0; + npix2 = npix1; // 1/256th of total pixels + + while (npix2 > 0 && ii < 256) // next 1/256th group from distr, + { + npix3 = brdist1[rgb][ii]; + if (npix3 == 0) { ++ii; continue; } + if (npix3 > npix2) npix3 = npix2; + brlev1[rgb][jj] += ii * npix3; // brightness * (pixels with) + brdist1[rgb][ii] -= npix3; + npix2 -= npix3; + } + + brlev1[rgb][jj] = brlev1[rgb][jj] / npix1; // mean brightness for group, 0-255 + } + + for (rgb = 0; rgb < 3; rgb++) // do same for image2 + for (ii = jj = 0; jj < 256; jj++) + { + brlev2[rgb][jj] = 0; + npix2 = npix1; + + while (npix2 > 0 && ii < 256) + { + npix3 = brdist2[rgb][ii]; + if (npix3 == 0) { ++ii; continue; } + if (npix3 > npix2) npix3 = npix2; + brlev2[rgb][jj] += ii * npix3; + brdist2[rgb][ii] -= npix3; + npix2 -= npix3; + } + + brlev2[rgb][jj] = brlev2[rgb][jj] / npix1; + } + + for (rgb = 0; rgb < 3; rgb++) // color + for (ii = jj = 0; ii < 256; ii++) // brlev1 brightness, 0 to 255 + { + if (ii == 0) bratio = 1; + while (ii > brlev2[rgb][jj] && jj < 256) ++jj; // find matching brlev2 brightness + a2 = brlev2[rgb][jj]; // next higher value + b2 = brlev1[rgb][jj]; + if (a2 > 0 && b2 > 0) { + if (jj > 0) { + a1 = brlev2[rgb][jj-1]; // next lower value + b1 = brlev1[rgb][jj-1]; + } + else a1 = b1 = 0; + if (ii == 0) bratio = b2 / a2; + else bratio = (b1 + (ii-a1)/(a2-a1) * (b2-b1)) / ii; // interpolate + } + + if (bratio < 0.2) bratio = 0.2; // contain outliers + if (bratio > 5) bratio = 5; + Bratios2[rgb][ii] = bratio; + } + + for (rgb = 0; rgb < 3; rgb++) // color + for (ii = jj = 0; ii < 256; ii++) // brlev2 brightness, 0 to 255 + { + if (ii == 0) bratio = 1; + while (ii > brlev1[rgb][jj] && jj < 256) ++jj; // find matching brlev1 brightness + a2 = brlev1[rgb][jj]; // next higher value + b2 = brlev2[rgb][jj]; + if (a2 > 0 && b2 > 0) { + if (jj > 0) { + a1 = brlev1[rgb][jj-1]; // next lower value + b1 = brlev2[rgb][jj-1]; + } + else a1 = b1 = 0; + if (ii == 0) bratio = b2 / a2; + else bratio = (b1 + (ii-a1)/(a2-a1) * (b2-b1)) / ii; // interpolate + } + + if (bratio < 0.2) bratio = 0.2; // contain outliers + if (bratio > 5) bratio = 5; + Bratios1[rgb][ii] = bratio; + } + + for (ii = 0; ii < 65536; ii++) // convert brightness ratios into + { // conversion factors + jj = ii / 256; + + for (rgb = 0; rgb < 3; rgb++) + { + cimRGBmf1[rgb][ii] = sqrt(Bratios1[rgb][jj]) * ii; // use sqrt(ratio) so that adjustment + cimRGBmf2[rgb][ii] = sqrt(Bratios2[rgb][jj]) * ii; // can be applied to both images + } + } + + return; +} + + +// Use color match data from cim_match_colors() to +// modify images so the colors match. + +void cim_adjust_colors(PXM *pxm, int fwhich) // v.10.7 +{ + int ww, hh, px, py; + int red, green, blue, max; + uint16 *pix; + double f1; + + ww = pxm->ww; + hh = pxm->hh; + + for (py = 0; py < hh; py++) + for (px = 0; px < ww; px++) + { + pix = PXMpix(pxm,px,py); + red = pix[0]; + green = pix[1]; + blue = pix[2]; + if (! blue) continue; + + if (fwhich == 1) { + red = cimRGBmf1[0][red]; + green = cimRGBmf1[1][green]; + blue = cimRGBmf1[2][blue]; + } + + if (fwhich == 2) { + red = cimRGBmf2[0][red]; + green = cimRGBmf2[1][green]; + blue = cimRGBmf2[2][blue]; + } + + if (red > 65535 || green > 65535 || blue > 65535) { + max = red; + if (green > max) max = green; + if (blue > max) max = blue; + f1 = 65535.0 / max; + red = red * f1; + green = green * f1; + blue = blue * f1; + } + + if (! blue) blue = 1; // avoid 0 v.10.7 + + pix[0] = red; + pix[1] = green; + pix[2] = blue; + } + + return; +} + + +// find pixels of greatest contrast within overlap area +// flag high-contrast pixels to use in each image compare region + +void cim_get_redpix(int im1) // v.10.7 +{ + int ww, hh, samp, xzone, yzone; + int pxL, pxH, pyL, pyH; + int px, py, ii, jj, npix; + int red1, green1, blue1, red2, green2, blue2, tcon; + int ov1xlo, ov1xhi, ov1ylo, ov1yhi; + int Hdist[256], Vdist[256], Hmin, Vmin; + double s8 = 1.0 / 770.0; + double zsamp[16] = { 4,6,6,4,6,9,9,6,6,9,9,6,4,6,6,4 }; // % sample per zone, sum = 100 + uchar *Hcon, *Vcon; + uint16 *pix1, *pix2; + PXM *pxm; + + pxm = cimPXMs[im1]; // v.11.04 + ww = pxm->ww; + hh = pxm->hh; + + if (cimRedpix) zfree(cimRedpix); // clear prior + cimRedpix = zmalloc(ww*hh,"cimRedpix"); + memset(cimRedpix,0,ww*hh); + + cimRedImage = im1; // image with red pixels + + ov1xlo = cimOv1xlo + cimSearchRange; // stay within x/y search range + ov1xhi = cimOv1xhi - cimSearchRange; // so that red pixels persist + ov1ylo = cimOv1ylo + cimSearchRange; // over offset changes + ov1yhi = cimOv1yhi - cimSearchRange; + + for (yzone = 0; yzone < 4; yzone++) // loop 16 zones v.10.8 + for (xzone = 0; xzone < 4; xzone++) + { + pxL = ov1xlo + 0.25 * xzone * (ov1xhi - ov1xlo); // px and py zone limits + pxH = ov1xlo + 0.25 * (xzone+1) * (ov1xhi - ov1xlo); + pyL = ov1ylo + 0.25 * yzone * (ov1yhi - ov1ylo); + pyH = ov1ylo + 0.25 * (yzone+1) * (ov1yhi - ov1ylo); + + npix = (pxH - pxL) * (pyH - pyL); // zone pixels + Hcon = (uchar *) zmalloc(npix,"cimRedpix"); // horizontal pixel contrast 0-255 + Vcon = (uchar *) zmalloc(npix,"cimRedpix"); // vertical pixel contrast 0-255 + + ii = 4 * yzone + xzone; + samp = cimSampSize * 0.01 * zsamp[ii]; // sample size for zone + if (samp > 0.1 * npix) samp = 0.1 * npix; // limit to 10% of zone pixels + + for (py = pyL; py < pyH; py++) // scan image pixels in zone + for (px = pxL; px < pxH; px++) + { + ii = (py-pyL) * (pxH-pxL) + (px-pxL); + Hcon[ii] = Vcon[ii] = 0; // horiz. = vert. contrast = 0 + + if (py < 8 || py > hh-9) continue; // keep away from image edges + if (px < 8 || px > ww-9) continue; + + pix1 = PXMpix(pxm,px,py-6); // verify not near void areas + if (! pix1[2]) continue; + pix1 = PXMpix(pxm,px+6,py); + if (! pix1[2]) continue; + pix1 = PXMpix(pxm,px,py+6); + if (! pix1[2]) continue; + pix1 = PXMpix(pxm,px-6,py); + if (! pix1[2]) continue; + + pix1 = PXMpix(pxm,px,py); // candidate red pixel + red1 = pix1[0]; + green1 = pix1[1]; + blue1 = pix1[2]; + + pix2 = PXMpix(pxm,px+2,py); // 2 pixels to right + red2 = pix2[0]; + green2 = pix2[1]; + blue2 = pix2[2]; + + tcon = abs(red1-red2) + abs(green1-green2) + abs(blue1-blue2); // horizontal contrast + Hcon[ii] = int(tcon * s8); // scale 0 - 255 + + pix2 = PXMpix(pxm,px,py+2); // 2 pixels below + red2 = pix2[0]; + green2 = pix2[1]; + blue2 = pix2[2]; + + tcon = abs(red1-red2) + abs(green1-green2) + abs(blue1-blue2); // vertical contrast + Vcon[ii] = int(tcon * s8); + } + + for (ii = 0; ii < 256; ii++) Hdist[ii] = Vdist[ii] = 0; // clear contrast distributions + + for (py = pyL; py < pyH; py++) // scan image pixels + for (px = pxL; px < pxH; px++) + { // build contrast distributions + ii = (py-pyL) * (pxH-pxL) + (px-pxL); + ++Hdist[Hcon[ii]]; + ++Vdist[Vcon[ii]]; + } + + for (npix = 0, ii = 255; ii > 0; ii--) // find minimum contrast needed to get + { // enough pixels for sample size + npix += Hdist[ii]; // (horizontal contrast pixels) + if (npix > samp) break; + } + Hmin = ii; + + for (npix = 0, ii = 255; ii > 0; ii--) // (verticle contrast pixels) + { + npix += Vdist[ii]; + if (npix > samp) break; + } + Vmin = ii; + + for (py = pyL; py < pyH; py++) // scan zone pixels + for (px = pxL; px < pxH; px++) + { + ii = (py-pyL) * (pxH-pxL) + (px-pxL); + jj = py * ww + px; + if (Hcon[ii] > Hmin) cimRedpix[jj] = 1; // flag pixels above min. contrast + if (Vcon[ii] > Vmin) cimRedpix[jj] = 1; + } + + zfree(Hcon); + zfree(Vcon); + + for (py = pyL; py < pyH; py++) // scan zone pixels + for (px = pxL; px < pxH; px++) + { + ii = (py-pyL) * (pxH-pxL) + (px-pxL); + jj = py * ww + px; + if (! cimRedpix[jj]) continue; + npix = cimRedpix[jj-1] + cimRedpix[jj+1]; // eliminate flagged pixels with no + npix += cimRedpix[jj-ww] + cimRedpix[jj+ww]; // neighboring flagged pixels + npix += cimRedpix[jj-ww-1] + cimRedpix[jj+ww-1]; // v.11.03 + npix += cimRedpix[jj-ww+1] + cimRedpix[jj+ww+1]; + if (npix < 2) cimRedpix[jj] = 0; + } + + for (py = pyL; py < pyH; py++) // scan zone pixels + for (px = pxL; px < pxH; px++) + { + ii = (py-pyL) * (pxH-pxL) + (px-pxL); + jj = py * ww + px; + + if (cimRedpix[jj] == 1) { // flag horizontal group of 3 + cimRedpix[jj+1] = 2; + cimRedpix[jj+2] = 2; + cimRedpix[jj+ww] = 2; // and vertical group of 3 + cimRedpix[jj+2*ww] = 2; + } + } + } + + return; +} + + +// curve image based on lens parameters (pano) +// replaces cimPXMs[im] with curved version + +void cim_curve_image(int im) // overhauled v.11.03 +{ + int px, py, ww, hh, vstat; + double ww2, hh2; + double dx, dy; + double F = lens_mm; // lens focal length, 35mm equivalent + double S = 35.0; // corresponding image width + double R1, R2, G, T, bow; + PXM *pxmin, *pxmout; + uint16 vpix[3], *pix; + + pxmin = cimPXMs[im]; // input and output image + ww = pxmin->ww; // 200 + hh = pxmin->hh; + ww2 = 0.5 * ww; // 100 + hh2 = 0.5 * hh; + + if (hh > ww) S = S * ww / hh; // vertical format + F = F / S; // 28 / 35 // scale to image dimensions + S = ww2; // 100 + F = F * ww; // 160 + R1 = F; // cylinder tangent to image plane + + bow = -lens_bow * 0.01 / hh2 / hh2; // lens bow % to fraction + if (hh > ww) + bow = -lens_bow * 0.01 / ww2 / ww2; + + pxmout = PXM_make(ww,hh,16); // temp. output PXM + + for (py = 0; py < hh; py++) // cylindrical projection v.11.03 + for (px = 0; px < ww; px++) + { + dx = px - ww2; + dy = py - hh2; + T = dx / R1; + dx = F * tan(T); + R2 = sqrt(dx * dx + F * F); + G = R1 - R2; + dy = (dy * R2) / (R2 + G); + dx += bow * dx * dy * dy; // barrel distortion + dx += ww2; + dy += hh2; + vstat = vpixel(pxmin,dx,dy,vpix); // input virtual pixel + pix = PXMpix(pxmout,px,py); // output real pixel + if (vstat) { + pix[0] = vpix[0]; + pix[1] = vpix[1]; + pix[2] = vpix[2]; + } + else pix[0] = pix[1] = pix[2] = 0; // voided pixels are (0,0,0) + } + + for (px = 1; px < ww2; px++) { // compute image shrinkage + pix = PXMpix(pxmout,px,hh/2); + if (pix[2]) break; + } + cimShrink = px-1; // = 0 if no curvature + + PXM_free(pxmin); // replace input with output PXM + cimPXMs[im] = pxmout; + + return; +} + + +// version for vertical panorama + +void cim_curve_Vimage(int im) // v.11.04 +{ + int px, py, ww, hh, vstat; + double ww2, hh2; + double dx, dy; + double F = lens_mm; // lens focal length, 35mm equivalent + double S = 35.0; // corresponding image width + double R1, R2, G, T, bow; + PXM *pxmin, *pxmout; + uint16 vpix[3], *pix; + + pxmin = cimPXMs[im]; // input and output image + ww = pxmin->ww; // 200 + hh = pxmin->hh; + ww2 = 0.5 * ww; // 100 + hh2 = 0.5 * hh; + + if (hh > ww) S = S * ww / hh; // vertical format + F = F / S; // 28 / 35 // scale to image dimensions + S = ww2; // 100 + F = F * ww; // 160 + R1 = F; // cylinder tangent to image plane + + bow = -lens_bow * 0.01 / hh2 / hh2; // lens bow % to fraction + if (hh > ww) + bow = -lens_bow * 0.01 / ww2 / ww2; + + pxmout = PXM_make(ww,hh,16); // temp. output PXM + + for (py = 0; py < hh; py++) // cylindrical projection v.11.03 + for (px = 0; px < ww; px++) + { + dx = px - ww2; + dy = py - hh2; + T = dy / R1; + dy = F * tan(T); + R2 = sqrt(dy * dy + F * F); + G = R1 - R2; + dx = (dx * R2) / (R2 + G); + dy += bow * dy * dx * dx; // barrel distortion + dx += ww2; + dy += hh2; + vstat = vpixel(pxmin,dx,dy,vpix); // input virtual pixel + pix = PXMpix(pxmout,px,py); // output real pixel + if (vstat) { + pix[0] = vpix[0]; + pix[1] = vpix[1]; + pix[2] = vpix[2]; + } + else pix[0] = pix[1] = pix[2] = 0; // voided pixels are (0,0,0) + } + + for (py = 1; py < hh2; py++) { // compute image shrinkage + pix = PXMpix(pxmout,ww/2,py); + if (pix[2]) break; + } + cimShrink = py-1; // = 0 if no curvature + + PXM_free(pxmin); // replace input with output PXM + cimPXMs[im] = pxmout; + + return; +} + + +// Warp 4 image corners according to cimOffs[im].wx[ii] and .wy[ii] +// corner = 0 = NW, 1 = NE, 2 = SE, 3 = SW +// 4 corners move by these pixel amounts and center does not move. +// input: cimPXMs[im] (flat or curved) output: cimPXMw[im] + +namespace cim_warp_image_names { + PXM *pxmin, *pxmout; + double ww, hh, wwi, hhi; + double wx0, wy0, wx1, wy1, wx2, wy2, wx3, wy3; +} + +void cim_warp_image(int im) // caller function v.10.8 +{ + using namespace cim_warp_image_names; + + void * cim_warp_image_wthread(void *arg); + + pxmin = cimPXMs[im]; // input and output pixmaps + pxmout = cimPXMw[im]; + + PXM_free(pxmout); // v.11.04 + pxmout = PXM_copy(pxmin); + cimPXMw[im] = pxmout; + + ww = pxmin->ww; + hh = pxmin->hh; + wwi = 1.0 / ww; + hhi = 1.0 / hh; + + wx0 = cimOffs[im].wx[0]; // corner warps + wy0 = cimOffs[im].wy[0]; + wx1 = cimOffs[im].wx[1]; + wy1 = cimOffs[im].wy[1]; + wx2 = cimOffs[im].wx[2]; + wy2 = cimOffs[im].wy[2]; + wx3 = cimOffs[im].wx[3]; + wy3 = cimOffs[im].wy[3]; + + for (int ii = 0; ii < Nwt; ii++) // start worker threads + start_wthread(cim_warp_image_wthread,&wtnx[ii]); + wait_wthreads(); // wait for completion + + return; +} + + +void * cim_warp_image_wthread(void *arg) // worker thread function v.10.8 +{ + using namespace cim_warp_image_names; + + int index = *((int *) arg); + int pxm, pym, vstat; + uint16 vpix[3], *pixm; + double px, py, dx, dy, coeff; + + for (pym = index; pym < hh; pym += Nwt) // loop all pixels for this thread + for (pxm = 0; pxm < ww; pxm++) + { + dx = dy = 0.0; + + coeff = (1.0 - pym * hhi - pxm * wwi); // corner 0 NW + if (coeff > 0) { + dx += coeff * wx0; + dy += coeff * wy0; + } + coeff = (1.0 - pym * hhi - (ww - pxm) * wwi); // corner 1 NE + if (coeff > 0) { + dx += coeff * wx1; + dy += coeff * wy1; + } + coeff = (1.0 - (hh - pym) * hhi - (ww - pxm) * wwi); // corner 2 SE + if (coeff > 0) { + dx += coeff * wx2; + dy += coeff * wy2; + } + coeff = (1.0 - (hh - pym) * hhi - pxm * wwi); // corner 3 SW + if (coeff > 0) { + dx += coeff * wx3; + dy += coeff * wy3; + } + + px = pxm + dx; // source pixel location + py = pym + dy; + + vstat = vpixel(pxmin,px,py,vpix); // input virtual pixel + pixm = PXMpix(pxmout,pxm,pym); // output real pixel + + if (vstat) { + pixm[0] = vpix[0]; + pixm[1] = vpix[1]; + pixm[2] = vpix[2]; + } + else pixm[0] = pixm[1] = pixm[2] = 0; + } + + exit_wthread(); + return 0; // not executed, avoid gcc warning +} + + +// warp image for pano, left side corners only, reduced warp range +// input: cimPXMs[im] (curved) +// output: cimPXMw[im] (warped) +// fblend: 0 = process entire image +// 1 = process left half only +// 2 = process blend stripe only + +void cim_warp_image_pano(int im, int fblend) // v.10.8 +{ + int ww, hh, ww2, hh2, pxL, pxH; + int pxm, pym, vstat; + uint16 vpix[3], *pixm; + double ww2i, hh2i, pxs, pys, xdisp, ydisp; + double wx0, wy0, wx3, wy3; + PXM *pxmin, *pxmout; + + pxmin = cimPXMs[im]; // input and output pixmaps + pxmout = cimPXMw[im]; + + PXM_free(pxmout); // v.11.04 + pxmout = PXM_copy(pxmin); + cimPXMw[im] = pxmout; + + ww = pxmin->ww; + hh = pxmin->hh; + + ww2 = ww / 2; + hh2 = hh / 2; + + ww2i = 1.0 / ww2; // v.10.8 + hh2i = 1.0 / hh2; + + wx0 = cimOffs[im].wx[0]; // NW corner warp + wy0 = cimOffs[im].wy[0]; + + wx3 = cimOffs[im].wx[3]; // SW corner warp + wy3 = cimOffs[im].wy[3]; + + pxL = 0; // entire image v.10.8 + pxH = ww; + + if (fblend == 1) // left half + pxH = ww2; + + if (fblend == 2) { + pxL = cimOv2xlo; // limit to overlap/blend width + pxH = cimOv2xhi; + } + + for (pym = 0; pym < hh; pym++) // loop all output pixels + for (pxm = pxL; pxm < pxH; pxm++) + { + pixm = PXMpix(pxmout,pxm,pym); // output pixel + + xdisp = (pxm - ww2) * ww2i; // -1 ... 0 ... +1 + ydisp = (pym - hh2) * hh2i; // v.11.04 + + if (xdisp > 0) { // right half, no warp + pxs = pxm; + pys = pym; + } + else if (ydisp < 0) { // use NW corner warp + pxs = pxm + wx0 * xdisp * ydisp; + pys = pym + wy0 * xdisp * ydisp; + } + else { // use SW corner warp + pxs = pxm + wx3 * xdisp * ydisp; + pys = pym + wy3 * xdisp * ydisp; + } + + vstat = vpixel(pxmin,pxs,pys,vpix); // input virtual pixel + + if (vstat) { + pixm[0] = vpix[0]; + pixm[1] = vpix[1]; + pixm[2] = vpix[2]; + } + else pixm[0] = pixm[1] = pixm[2] = 0; + } + + for (pxm = 1; pxm < ww2; pxm++) { // compute image shrinkage + pixm = PXMpix(pxmout,pxm,hh2); // used by cim_get_overlap() + if (pixm[2]) break; + } + cimShrink = pxm-1; + + return; +} + + +// vertical pano version - warp top side corners (NW, NE) + +void cim_warp_image_Vpano(int im, int fblend) // v.11.04 +{ + int ww, hh, ww2, hh2, pyL, pyH; + int pxm, pym, vstat; + uint16 vpix[3], *pixm; + double ww2i, hh2i, pxs, pys, xdisp, ydisp; + double wx0, wy0, wx1, wy1; + PXM *pxmin, *pxmout; + + pxmin = cimPXMs[im]; // input and output pixmaps + pxmout = cimPXMw[im]; + + PXM_free(pxmout); // v.11.04 + pxmout = PXM_copy(pxmin); + cimPXMw[im] = pxmout; + + ww = pxmin->ww; + hh = pxmin->hh; + + ww2 = ww / 2; + hh2 = hh / 2; + + ww2i = 1.0 / ww2; // v.10.8 + hh2i = 1.0 / hh2; + + wx0 = cimOffs[im].wx[0]; // NW corner warp + wy0 = cimOffs[im].wy[0]; + + wx1 = cimOffs[im].wx[1]; // NE corner warp + wy1 = cimOffs[im].wy[1]; + + pyL = 0; // entire image v.10.8 + pyH = hh; + + if (fblend == 1) // top half + pyH = hh2; + + if (fblend == 2) { + pyL = cimOv2ylo; // limit to overlap/blend width + pyH = cimOv2yhi; + } + + for (pym = pyL; pym < pyH; pym++) // loop all output pixels + for (pxm = 0; pxm < ww; pxm++) + { + pixm = PXMpix(pxmout,pxm,pym); // output pixel + + xdisp = (pxm - ww2) * ww2i; // -1 ... 0 ... +1 + ydisp = (pym - hh2) * hh2i; + + if (ydisp > 0) { // bottom half, no warp + pxs = pxm; + pys = pym; + } + else if (xdisp < 0) { // use NW corner warp + pxs = pxm + wx0 * xdisp * ydisp; + pys = pym + wy0 * xdisp * ydisp; + } + else { // use NE corner warp + pxs = pxm + wx1 * xdisp * ydisp; + pys = pym + wy1 * xdisp * ydisp; + } + + vstat = vpixel(pxmin,pxs,pys,vpix); // input virtual pixel + + if (vstat) { + pixm[0] = vpix[0]; + pixm[1] = vpix[1]; + pixm[2] = vpix[2]; + } + else pixm[0] = pixm[1] = pixm[2] = 0; + } + + for (pym = 1; pym < hh2; pym++) { // compute image shrinkage + pixm = PXMpix(pxmout,ww2,pym); // used by cim_get_overlap() + if (pixm[2]) break; + } + cimShrink = pym-1; + + return; +} + + +// fine-align a pair of images im1 and im2 +// cimPXMs[im2] is aligned with cimPXMs[im1] +// inputs are cimOffs[im1] and cimOffs[im2] (x/y/t and corner offsets) +// output is adjusted offsets and corner warp values for im2 only +// (im1 is used as-is without corner warps) + +void cim_align_image(int im1, int im2) // speedup v.11.03 +{ + int ii, corner1, cornerstep, cornerN, pass; + double xyrange, xystep, trange, tstep, wrange, wstep; + double xfL, xfH, yfL, yfH, tfL, tfH; + double wxL, wxH, wyL, wyH; + double match, matchB; + cimoffs offsets0, offsetsB; + + offsets0 = cimOffs[im2]; // initial offsets + offsetsB = offsets0; // = best offsets so far + matchB = cim_match_images(im1,im2); // = best image match level + + if (cimPanoV) cim_show_Vimages(0,0); // v.11.04 + else cim_show_images(0,0); // show with 50/50 blend + + for (pass = 1; pass <=2; pass++) // main pass and 2nd pass v.10.8 + { + xyrange = cimSearchRange; // x/y search range and step + xystep = cimSearchStep; + + trange = xyrange / (cimOv1yhi - cimOv1ylo); // angle range, radians + tstep = trange * xystep / xyrange; + + if (pass == 2) { + xyrange = 0.5 * xyrange; // 2nd pass, reduce range and step + xystep = 0.5 * xystep; // v.11.04 + trange = 0.5 * trange; + tstep = 0.5 * tstep; + } + + // search x/y/t range for best match + + xfL = cimOffs[im2].xf - xyrange; + xfH = cimOffs[im2].xf + xyrange + 0.5 * xystep; + yfL = cimOffs[im2].yf - xyrange; + yfH = cimOffs[im2].yf + xyrange + 0.5 * xystep; + tfL = cimOffs[im2].tf - trange; + tfH = cimOffs[im2].tf + trange + 0.5 * tstep; + + for (cimOffs[im2].xf = xfL; cimOffs[im2].xf < xfH; cimOffs[im2].xf += xystep) + for (cimOffs[im2].yf = yfL; cimOffs[im2].yf < yfH; cimOffs[im2].yf += xystep) + for (cimOffs[im2].tf = tfL; cimOffs[im2].tf < tfH; cimOffs[im2].tf += tstep) + { + match = cim_match_images(im1,im2); // get match level + + if (sigdiff(match,matchB,0.00001) > 0) { + matchB = match; // save best match + offsetsB = cimOffs[im2]; + } + + sprintf(SB_text,"align: %d match: %.5f",cimNsearch++,matchB); // update status bar + zmainloop(); // v.11.11.1 + } + + cimOffs[im2] = offsetsB; // restore best match + + if (cimPanoV) cim_show_Vimages(0,0); // v.11.04 + else cim_show_images(0,0); + + // warp corners and search for best match + + wrange = cimWarpRange; // corner warp range and step + wstep = cimWarpStep; + if (! wrange) continue; + + if (pass == 2) { // 2nd pass, 1/4 range and 1/2 step + wrange = wrange / 4; + wstep = wstep / 2; + } + + corner1 = 0; // process all 4 corners + cornerN = 3; + cornerstep = 1; + + if (cimPano) { + corner1 = 0; // left side corners 0, 3 + cornerN = 3; + cornerstep = 3; + } + + if (cimPanoV) { + corner1 = 0; // top side corners 0, 1 v.11.04 + cornerN = 1; + cornerstep = 1; + } + + matchB = cim_match_images(im1,im2); // initial image match level + + for (ii = corner1; ii <= cornerN; ii += cornerstep) // modify one corner at a time + { + wxL = cimOffs[im2].wx[ii] - wrange; + wxH = cimOffs[im2].wx[ii] + wrange + 0.5 * wstep; + wyL = cimOffs[im2].wy[ii] - wrange; + wyH = cimOffs[im2].wy[ii] + wrange + 0.5 * wstep; + + for (cimOffs[im2].wx[ii] = wxL; cimOffs[im2].wx[ii] < wxH; cimOffs[im2].wx[ii] += wstep) + for (cimOffs[im2].wy[ii] = wyL; cimOffs[im2].wy[ii] < wyH; cimOffs[im2].wy[ii] += wstep) + { + match = cim_match_images(im1,im2); // get match level + + if (sigdiff(match,matchB,0.00001) > 0) { + matchB = match; // save best match + offsetsB = cimOffs[im2]; + } + + sprintf(SB_text,"warp: %d match: %.5f",cimNsearch++,matchB); + zmainloop(); // v.11.11.1 + } + + cimOffs[im2] = offsetsB; // restore best match + } + + if (cimPano) cim_warp_image_pano(im2,1); // apply corner warps v.11.04 + else if (cimPanoV) cim_warp_image_Vpano(im2,1); + else cim_warp_image(im2); + + if (cimPanoV) cim_show_Vimages(0,0); // v.11.04 + else cim_show_images(0,0); + } + + return; +} + + +// Compare 2 pixels using precalculated brightness ratios +// 1.0 = perfect match 0 = total mismatch (black/white) + +inline double cim_match_pixels(uint16 *pix1, uint16 *pix2) // v.10.7 +{ + double red1, green1, blue1, red2, green2, blue2; + double reddiff, greendiff, bluediff, match; + double ff = 1.0 / 65536.0; + + red1 = pix1[0]; + green1 = pix1[1]; + blue1 = pix1[2]; + + red2 = pix2[0]; + green2 = pix2[1]; + blue2 = pix2[2]; + + reddiff = ff * fabs(red1-red2); // 0 = perfect match + greendiff = ff * fabs(green1-green2); // 1 = total mismatch + bluediff = ff * fabs(blue1-blue2); + + match = (1.0 - reddiff) * (1.0 - greendiff) * (1.0 - bluediff); // 1 = perfect match + return match; +} + + +// Compare two images in overlapping areas. +// Use the high-contrast pixels from cim_get_redpix() +// return: 1 = perfect match, 0 = total mismatch (black/white) +// cimPXMs[im1] is matched to cimPXMs[im2] + virtual warps + +double cim_match_images(int im1, int im2) // v.11.03 +{ + uint16 *pix1, vpix2[3]; + int ww, hh, ww2, hh2; + int px1, py1, ii, vstat; + double wwi, hhi, ww2i, hh2i, xdisp, ydisp; + double wx0, wy0, wx1, wy1, wx2, wy2, wx3, wy3; + double dx, dy, px2, py2; + double x1, y1, t1, x2, y2, t2; + double xoff, yoff, toff, costf, sintf, coeff; + double match, cmatch, maxcmatch; + PXM *pxm1, *pxm2; + + x1 = cimOffs[im1].xf; // im1, im2 absolute offsets + y1 = cimOffs[im1].yf; + t1 = cimOffs[im1].tf; + x2 = cimOffs[im2].xf; + y2 = cimOffs[im2].yf; + t2 = cimOffs[im2].tf; + + xoff = (x2 - x1) * cos(t1) + (y2 - y1) * sin(t1); // offset of im2 relative to im1 + yoff = (y2 - y1) * cos(t1) - (x2 - x1) * sin(t1); + toff = t2 - t1; + + costf = cos(toff); + sintf = sin(toff); + + wx0 = cimOffs[im2].wx[0]; // im2 corner warps + wy0 = cimOffs[im2].wy[0]; + wx1 = cimOffs[im2].wx[1]; + wy1 = cimOffs[im2].wy[1]; + wx2 = cimOffs[im2].wx[2]; + wy2 = cimOffs[im2].wy[2]; + wx3 = cimOffs[im2].wx[3]; + wy3 = cimOffs[im2].wy[3]; + + pxm1 = cimPXMs[im1]; // base image + pxm2 = cimPXMs[im2]; // comparison image (virtual warps) + + ww = pxm1->ww; + hh = pxm1->hh; + ww2 = ww / 2; + hh2 = hh / 2; + + wwi = 1.0 / ww; + hhi = 1.0 / hh; + ww2i = 1.0 / ww2; + hh2i = 1.0 / hh2; + + cmatch = 0; + maxcmatch = 1; + + if (cimPano) + { + for (py1 = cimOv1ylo; py1 < cimOv1yhi; py1++) // loop overlapping pixels + for (px1 = cimOv1xlo; px1 < cimOv1xhi; px1++) + { + ii = py1 * ww + px1; // skip low-contrast pixels + if (! cimRedpix[ii]) continue; + + pix1 = PXMpix(pxm1,px1,py1); // image1 pixel + if (! pix1[2]) continue; // ignore void pixels + + px2 = costf * (px1 - xoff) + sintf * (py1 - yoff); // corresponding image2 pixel + py2 = costf * (py1 - yoff) - sintf * (px1 - xoff); + + dx = dy = 0.0; // corner warp + + xdisp = (px2 - ww2) * ww2i; // -1 ... 0 ... +1 + ydisp = (py2 - hh2) * hh2i; // v.11.04 + + if (xdisp > 0) // right half, no warp + dx = dy = 0; + + else if (ydisp < 0) { // use NW corner warp + dx = wx0 * xdisp * ydisp; + dy = wy0 * xdisp * ydisp; + } + + else { // use SW corner warp + dx = wx3 * xdisp * ydisp; + dy = wy3 * xdisp * ydisp; + } + + px2 += dx; // source pixel location + py2 += dy; // after corner warps + + vstat = vpixel(pxm2,px2,py2,vpix2); + if (! vstat) continue; + + match = cim_match_pixels(pix1,vpix2); // compare brightness adjusted + cmatch += match; // accumulate total match + maxcmatch += 1.0; + } + } + + else if (cimPanoV) + { + for (py1 = cimOv1ylo; py1 < cimOv1yhi; py1++) // loop overlapping pixels + for (px1 = cimOv1xlo; px1 < cimOv1xhi; px1++) + { + ii = py1 * ww + px1; // skip low-contrast pixels + if (! cimRedpix[ii]) continue; + + pix1 = PXMpix(pxm1,px1,py1); // image1 pixel + if (! pix1[2]) continue; // ignore void pixels + + px2 = costf * (px1 - xoff) + sintf * (py1 - yoff); // corresponding image2 pixel + py2 = costf * (py1 - yoff) - sintf * (px1 - xoff); + + dx = dy = 0.0; // corner warp + + xdisp = (px2 - ww2) * ww2i; // -1 ... 0 ... +1 + ydisp = (py2 - hh2) * hh2i; + + if (ydisp > 0) // bottom half, no warp + dx = dy = 0; + + else if (xdisp < 0) { // use NW corner warp + dx = wx0 * xdisp * ydisp; + dy = wy0 * xdisp * ydisp; + } + + else { // use NE corner warp + dx = wx1 * xdisp * ydisp; + dy = wy1 * xdisp * ydisp; + } + + px2 += dx; // source pixel location + py2 += dy; // after corner warps + + vstat = vpixel(pxm2,px2,py2,vpix2); + if (! vstat) continue; + + match = cim_match_pixels(pix1,vpix2); // compare brightness adjusted + cmatch += match; // accumulate total match + maxcmatch += 1.0; + } + } + + else + { + for (py1 = cimOv1ylo; py1 < cimOv1yhi; py1++) // loop overlapping pixels + for (px1 = cimOv1xlo; px1 < cimOv1xhi; px1++) + { + ii = py1 * ww + px1; // skip low-contrast pixels + if (! cimRedpix[ii]) continue; + + pix1 = PXMpix(pxm1,px1,py1); // image1 pixel + if (! pix1[2]) continue; // ignore void pixels + + px2 = costf * (px1 - xoff) + sintf * (py1 - yoff); // corresponding image2 pixel + py2 = costf * (py1 - yoff) - sintf * (px1 - xoff); + + dx = dy = 0.0; // corner warp + + coeff = (1.0 - py2 * hhi - px2 * wwi); // corner 0 NW + if (coeff > 0) { + dx += coeff * wx0; + dy += coeff * wy0; + } + coeff = (1.0 - py2 * hhi - (ww - px2) * wwi); // corner 1 NE + if (coeff > 0) { + dx += coeff * wx1; + dy += coeff * wy1; + } + coeff = (1.0 - (hh - py2) * hhi - (ww - px2) * wwi); // corner 2 SE + if (coeff > 0) { + dx += coeff * wx2; + dy += coeff * wy2; + } + coeff = (1.0 - (hh - py2) * hhi - px2 * wwi); // corner 3 SW + if (coeff > 0) { + dx += coeff * wx3; + dy += coeff * wy3; + } + + px2 += dx; // source pixel location + py2 += dy; // after corner warps + + vstat = vpixel(pxm2,px2,py2,vpix2); + if (! vstat) continue; + + match = cim_match_pixels(pix1,vpix2); // compare brightness adjusted + cmatch += match; // accumulate total match + maxcmatch += 1.0; + } + } + + return cmatch / maxcmatch; +} + + +// combine and show all images +// fnew >> make new E3 output image and adjust x and y offsets +// cimPXMw[*] >> E3pxm16 >> main window +// fblend: 0 > 50/50 blend, 1 > gradual blend + +namespace cim_show_images_names { + int im1, im2, iminc, fblendd; + int wwlo[10], wwhi[10]; + int hhlo[10], hhhi[10]; + double costf[10], sintf[10]; +} + +void cim_show_images(int fnew, int fblend) // v.10.7 +{ + using namespace cim_show_images_names; + + void * cim_show_images_wthread(void *arg); + + int imx, pxr, pyr, ii, px3, py3; + int ww, hh, wwmin, wwmax, hhmin, hhmax, bmid; + double xf, yf, tf; + uint16 *pix3; + + mutex_lock(&Fpixmap_lock); // stop window updates + + fblendd = fblend; // blend 50/50 or gradual ramp + + im1 = cimShowIm1; // two images to show + im2 = cimShowIm2; + iminc = im2 - im1; // v.10.9 + + if (cimShowAll) { // show all images v.10.9 + im1 = 0; + im2 = cimNF-1; + iminc = 1; + } + + for (imx = 0; imx < cimNF; imx++) { // pre-calculate + costf[imx] = cos(cimOffs[imx].tf); + sintf[imx] = sin(cimOffs[imx].tf); + } + + if (fnew) PXM_free(E3pxm16); // force new output pixmap + + if (! E3pxm16) // allocate output pixmap + { + wwmin = hhmin = 9999; // initial values + wwmax = cimPXMw[im2]->ww; + hhmax = cimPXMw[im2]->hh; + + for (imx = im1; imx <= im2; imx += iminc) // find min and max ww and hh extents + { + xf = cimOffs[imx].xf; + yf = cimOffs[imx].yf; + tf = cimOffs[imx].tf; + ww = cimPXMw[imx]->ww; + hh = cimPXMw[imx]->hh; + if (xf < wwmin) wwmin = xf; + if (xf - tf * hh < wwmin) wwmin = xf + tf * hh; + if (xf + ww > wwmax) wwmax = xf + ww; + if (xf + ww - tf * hh > wwmax) wwmax = xf + ww - tf * hh; + if (yf < hhmin) hhmin = yf; + if (yf + tf * ww < hhmin) hhmin = yf + tf * ww; + if (yf + hh > hhmax) hhmax = yf + hh; + if (yf + hh + tf * ww > hhmax) hhmax = yf + hh + tf * ww; + } + + for (imx = im1; imx <= im2; imx += iminc) { // align to top and left edges + cimOffs[imx].xf -= wwmin; + cimOffs[imx].yf -= hhmin; + } + wwmax = wwmax - wwmin; + hhmax = hhmax - hhmin; + wwmin = hhmin = 0; + + if (cimPano) { + for (imx = im1; imx <= im2; imx += iminc) // deliberate margins v.11.03 + cimOffs[imx].yf += 10; + hhmax += 20; + } + + if (cimPanoV) { + for (imx = im1; imx <= im2; imx += iminc) // deliberate margins v.11.04 + cimOffs[imx].xf += 10; + wwmax += 20; + } + + E3pxm16 = PXM_make(wwmax,hhmax,16); // allocate output image + E3ww = wwmax; + E3hh = hhmax; + } + + for (imx = im1; imx <= im2; imx += iminc) // get ww range of each image + { + ww = cimPXMw[imx]->ww; + hh = cimPXMw[imx]->hh; + tf = cimOffs[imx].tf; + wwlo[imx] = cimOffs[imx].xf; + wwhi[imx] = wwlo[imx] + ww; + wwlo[imx] -= 0.5 * tf * hh; // use midpoint of sloping edges + wwhi[imx] -= 0.5 * tf * hh; + } + + if (cimBlend) { // blend width active + for (imx = im1; imx <= im2-1; imx += iminc) // reduce for blend width + { + if (wwhi[imx] - wwlo[imx+1] > cimBlend) { + bmid = (wwhi[imx] + wwlo[imx+1]) / 2; + wwlo[imx+1] = bmid - cimBlend / 2; + wwhi[imx] = bmid + cimBlend / 2; + } + } + } + + for (ii = 0; ii < Nwt; ii++) // start worker threads v.10.7 + start_wthread(cim_show_images_wthread,&wtnx[ii]); + wait_wthreads(); // wait for completion + + if (cimRedpix) + { + imx = cimRedImage; // paint red pixels for current image + ww = cimPXMw[imx]->ww; // being aligned + hh = cimPXMw[imx]->hh; + + for (ii = 0; ii < ww * hh; ii++) + { + if (cimRedpix[ii]) { + pyr = ii / ww; // red pixel + pxr = ii - pyr * ww; + px3 = cimOffs[imx].xf + pxr * costf[imx] - pyr * sintf[imx] + 0.5; + py3 = cimOffs[imx].yf + pyr * costf[imx] + pxr * sintf[imx] + 0.5; + pix3 = PXMpix(E3pxm16,px3,py3); + pix3[0] = 65535; pix3[1] = pix3[2] = 1; + } + } + } + + mutex_unlock(&Fpixmap_lock); + mwpaint2(); // update window + zmainloop(); // v.11.11.1 + + return; +} + + +void * cim_show_images_wthread(void *arg) // working thread v.10.7 +{ + using namespace cim_show_images_names; + + int index = *((int *) (arg)); + int imx, imy; + int px3, py3; + int vstat, vstat1, vstat2; + int red1, green1, blue1; + int red2, green2, blue2; + int red3, green3, blue3; + double f1, f2, px, py; + uint16 vpix[3], *pix3; + + red1 = green1 = blue1 = 0; + + f1 = f2 = 0.5; // to use if no fblend flag + + for (py3 = index; py3 < E3hh; py3 += Nwt) // loop E3 rows + for (px3 = 0; px3 < E3ww; px3++) // loop E3 columns + { + vstat1 = vstat2 = 0; + + for (imx = imy = im1; imx <= im2; imx += iminc) // find which images overlap this pixel + { + if (px3 < wwlo[imx] || px3 > wwhi[imx]) continue; + px = costf[imx] * (px3 - cimOffs[imx].xf) + sintf[imx] * (py3 - cimOffs[imx].yf); + py = costf[imx] * (py3 - cimOffs[imx].yf) - sintf[imx] * (px3 - cimOffs[imx].xf); + vstat = vpixel(cimPXMw[imx],px,py,vpix); + if (! vstat) continue; + + if (! vstat1) { // first overlapping image + vstat1 = 1; + imy = imx; + red1 = vpix[0]; + green1 = vpix[1]; + blue1 = vpix[2]; + } + else { // second image + vstat2 = 1; + red2 = vpix[0]; + green2 = vpix[1]; + blue2 = vpix[2]; + break; + } + } + + imx = imy; // first of 1 or 2 overlapping images + + if (vstat1) { + if (! vstat2) { + red3 = red1; // use image1 pixel + green3 = green1; + blue3 = blue1; + } + else { // use blended image1 + image2 pixels + if (fblendd) { + f1 = wwhi[imx] - px3; // gradual blend + f2 = px3 - wwlo[imx+1]; + f1 = f1 / (f1 + f2); + f2 = 1.0 - f1; + } + red3 = f1 * red1 + f2 * red2 + 0.5; + green3 = f1 * green1 + f2 * green2 + 0.5; + blue3 = f1 * blue1 + f2 * blue2 + 0.5; + } + } + + else red3 = green3 = blue3 = 0; // no overlapping image, use black pixel + + pix3 = PXMpix(E3pxm16,px3,py3); // output pixel + pix3[0] = red3; + pix3[1] = green3; + pix3[2] = blue3; + } + + exit_wthread(); + return 0; // not executed, avoid gcc warning +} + + +// version for vertical panorama + +void cim_show_Vimages(int fnew, int fblend) // v.11.04 +{ + using namespace cim_show_images_names; + + void * cim_show_Vimages_wthread(void *arg); + + int imx, pxr, pyr, ii, px3, py3; + int ww, hh, wwmin, wwmax, hhmin, hhmax, bmid; + double xf, yf, tf; + uint16 *pix3; + + mutex_lock(&Fpixmap_lock); // stop window updates + + fblendd = fblend; // blend 50/50 or gradual ramp + + im1 = 0; // show all images (pano) + im2 = cimNF-1; + + for (imx = 0; imx < cimNF; imx++) { // pre-calculate + costf[imx] = cos(cimOffs[imx].tf); + sintf[imx] = sin(cimOffs[imx].tf); + } + + if (fnew) PXM_free(E3pxm16); // force new output pixmap + + if (! E3pxm16) // allocate output pixmap + { + wwmin = hhmin = 9999; + wwmax = hhmax = 0; + + for (imx = im1; imx <= im2; imx++) // find min and max ww and hh extents + { + xf = cimOffs[imx].xf; + yf = cimOffs[imx].yf; + tf = cimOffs[imx].tf; + ww = cimPXMw[imx]->ww; + hh = cimPXMw[imx]->hh; + if (xf < wwmin) wwmin = xf; + if (xf - tf * hh < wwmin) wwmin = xf + tf * hh; + if (xf + ww > wwmax) wwmax = xf + ww; + if (xf + ww - tf * hh > wwmax) wwmax = xf + ww - tf * hh; + if (yf < hhmin) hhmin = yf; + if (yf + tf * ww < hhmin) hhmin = yf + tf * ww; + if (yf + hh > hhmax) hhmax = yf + hh; + if (yf + hh + tf * ww > hhmax) hhmax = yf + hh + tf * ww; + } + + for (imx = im1; imx <= im2; imx++) { // align to top and left edges + cimOffs[imx].xf -= wwmin; + cimOffs[imx].yf -= hhmin; + } + wwmax = wwmax - wwmin; + hhmax = hhmax - hhmin; + wwmin = hhmin = 0; + + for (imx = im1; imx <= im2; imx++) // deliberate margins + cimOffs[imx].xf += 10; + wwmax += 20; + + E3pxm16 = PXM_make(wwmax,hhmax,16); // allocate output image + E3ww = wwmax; + E3hh = hhmax; + } + + for (imx = im1; imx <= im2; imx++) // get hh range of each image + { + ww = cimPXMw[imx]->ww; + hh = cimPXMw[imx]->hh; + tf = cimOffs[imx].tf; + hhlo[imx] = cimOffs[imx].yf; + hhhi[imx] = hhlo[imx] + hh; + hhlo[imx] += 0.5 * tf * ww; // use midpoint of sloping edges + hhhi[imx] += 0.5 * tf * ww; + } + + if (cimBlend) { // blend width active + for (imx = im1; imx <= im2-1; imx++) // reduce for blend width + { + if (hhhi[imx] - hhlo[imx+1] > cimBlend) { + bmid = (hhhi[imx] + hhlo[imx+1]) / 2; + hhlo[imx+1] = bmid - cimBlend / 2; + hhhi[imx] = bmid + cimBlend / 2; + } + } + } + + for (ii = 0; ii < Nwt; ii++) // start worker threads v.10.7 + start_wthread(cim_show_Vimages_wthread,&wtnx[ii]); + wait_wthreads(); // wait for completion + + if (cimRedpix) + { + imx = cimRedImage; // paint red pixels for current image + ww = cimPXMw[imx]->ww; // being aligned + hh = cimPXMw[imx]->hh; + + for (ii = 0; ii < ww * hh; ii++) + { + if (cimRedpix[ii]) { + pyr = ii / ww; // red pixel + pxr = ii - pyr * ww; + px3 = cimOffs[imx].xf + pxr * costf[imx] - pyr * sintf[imx] + 0.5; + py3 = cimOffs[imx].yf + pyr * costf[imx] + pxr * sintf[imx] + 0.5; + pix3 = PXMpix(E3pxm16,px3,py3); + pix3[0] = 65535; pix3[1] = pix3[2] = 1; + } + } + } + + mutex_unlock(&Fpixmap_lock); + mwpaint2(); // update window + zmainloop(); // v.11.11.1 + return; +} + + +void * cim_show_Vimages_wthread(void *arg) // working thread v.11.04 +{ + using namespace cim_show_images_names; + + int index = *((int *) (arg)); + int imx, imy; + int px3, py3; + int vstat, vstat1, vstat2; + int red1, green1, blue1; + int red2, green2, blue2; + int red3, green3, blue3; + double f1, f2, px, py; + uint16 vpix[3], *pix3; + + red1 = green1 = blue1 = 0; + + f1 = f2 = 0.5; // to use if no fblend flag + + for (py3 = index; py3 < E3hh; py3 += Nwt) // loop E3 rows + for (px3 = 0; px3 < E3ww; px3++) // loop E3 columns + { + vstat1 = vstat2 = 0; + + for (imx = imy = im1; imx <= im2; imx++) // find which images overlap this pixel + { + if (py3 < hhlo[imx] || py3 > hhhi[imx]) continue; + px = costf[imx] * (px3 - cimOffs[imx].xf) + sintf[imx] * (py3 - cimOffs[imx].yf); + py = costf[imx] * (py3 - cimOffs[imx].yf) - sintf[imx] * (px3 - cimOffs[imx].xf); + vstat = vpixel(cimPXMw[imx],px,py,vpix); + if (! vstat) continue; + + if (! vstat1) { // first overlapping image + vstat1 = 1; + imy = imx; + red1 = vpix[0]; + green1 = vpix[1]; + blue1 = vpix[2]; + } + else { // second image + vstat2 = 1; + red2 = vpix[0]; + green2 = vpix[1]; + blue2 = vpix[2]; + break; + } + } + + imx = imy; // first of 1 or 2 overlapping images + + if (vstat1) { + if (! vstat2) { + red3 = red1; // use image1 pixel + green3 = green1; + blue3 = blue1; + } + else { // use blended image1 + image2 pixels + if (fblendd) { + f1 = hhhi[imx] - py3; // gradual blend + f2 = py3 - hhlo[imx+1]; + f1 = f1 / (f1 + f2); + f2 = 1.0 - f1; + } + red3 = f1 * red1 + f2 * red2 + 0.5; + green3 = f1 * green1 + f2 * green2 + 0.5; + blue3 = f1 * blue1 + f2 * blue2 + 0.5; + } + } + + else red3 = green3 = blue3 = 0; // no overlapping image, use black pixel + + pix3 = PXMpix(E3pxm16,px3,py3); // output pixel + pix3[0] = red3; + pix3[1] = green3; + pix3[2] = blue3; + } + + exit_wthread(); + return 0; // not executed, avoid gcc warning +} + + +// cut-off edges of output image where all input images do not overlap +// (HDR HDF Stack) + +void cim_trim() // v.10.9 +{ + int edgex[8] = { 0, 1, 2, 2, 2, 1, 0, 0 }; // 4 corners and 4 midpoints of rectangle + int edgey[8] = { 0, 0, 0, 1, 2, 2, 2, 1 }; // 0 and 2 mark corners, 1 marks midpoints + int edgewx[4] = { +1, -1, -1, +1 }; + int edgewy[4] = { +1, +1, -1, -1 }; + + int imx, ii, jj, ww, hh, px3, py3, px9, py9; + int wwmin, wwmax, hhmin, hhmax; + double xf, yf, tf, sintf, costf, px, py, wx, wy; + uint16 *pix3, *pix9; + + wwmin = hhmin = 0; + wwmax = E3ww; + hhmax = E3hh; + + for (imx = 0; imx < cimNF; imx++) // loop all images + { + ww = cimPXMw[imx]->ww; // image size + hh = cimPXMw[imx]->hh; + xf = cimOffs[imx].xf; // alignment offsets + yf = cimOffs[imx].yf; + tf = cimOffs[imx].tf; + sintf = sin(tf); + costf = cos(tf); + + for (ii = 0; ii < 8; ii++) // 8 points around image rectangle + { + px = ww * edgex[ii] / 2; // coordinates before warping + py = hh * edgey[ii] / 2; + + if (edgex[ii] != 1 && edgey[ii] != 1) { // if a corner + jj = ii / 2; + wx = cimOffs[imx].wx[jj]; // corner warp + wy = cimOffs[imx].wy[jj]; + if (edgewx[jj] > 0 && wx < 0) px -= wx; // if warp direction inwards, + if (edgewx[jj] < 0 && wx > 0) px -= wx; // reduce px/py by warp + if (edgewy[jj] > 0 && wy < 0) py -= wy; + if (edgewy[jj] < 0 && wy > 0) py -= wy; + } + + px3 = xf + px * costf - py * sintf; // map px/py to output image px3/py3 + py3 = yf + py * costf + px * sintf; + + if (edgex[ii] != 1) { + if (px3 < ww/2 && px3 > wwmin) wwmin = px3; // remember px3/py3 extremes + if (px3 > ww/2 && px3 < wwmax) wwmax = px3; + } + + if (edgey[ii] != 1) { + if (py3 < hh/2 && py3 > hhmin) hhmin = py3; + if (py3 > hh/2 && py3 < hhmax) hhmax = py3; + } + } + } + + wwmin += 2; // compensate rounding + wwmax -= 2; + hhmin += 2; + hhmax -= 2; + + ww = wwmax - wwmin; // new image size + hh = hhmax - hhmin; + + if (ww < 0.7 * E3ww) return; // sanity check + if (hh < 0.7 * E3hh) return; + + E9pxm16 = PXM_make(ww,hh,16); + + for (py3 = hhmin; py3 < hhmax; py3++) // E9 = trimmed E3 + for (px3 = wwmin; px3 < wwmax; px3++) + { + px9 = px3 - wwmin; + py9 = py3 - hhmin; + pix3 = PXMpix(E3pxm16,px3,py3); + pix9 = PXMpix(E9pxm16,px9,py9); + pix9[0] = pix3[0]; + pix9[1] = pix3[1]; + pix9[2] = pix3[2]; + } + + PXM_free(E3pxm16); // E3 = E9 + E3pxm16 = E9pxm16; + E9pxm16 = 0; + E3ww = ww; + E3hh = hh; + + return; +} + + +// dump offsets to stdout - diagnostic tool + +void cim_dump_offsets(cchar *text) +{ + printf("\n offsets: %s \n",text); + + for (int imx = 0; imx < cimNF; imx++) + { + printf(" imx %d x/y/t: %.1f %.1f %.4f w0: %.1f %.1f w1: %.1f %.1f w2: %.1f %.1f w3: %.1f %.1f \n", + imx, cimOffs[imx].xf, cimOffs[imx].yf, cimOffs[imx].tf, + cimOffs[imx].wx[0], cimOffs[imx].wy[0], cimOffs[imx].wx[1], cimOffs[imx].wy[1], + cimOffs[imx].wx[2], cimOffs[imx].wy[2], cimOffs[imx].wx[3], cimOffs[imx].wy[3]); + } + + return; +} + + +/************************************************************************** + + Make an HDR (high dynamic range) image from several images of the same + subject with different exposure levels. The composite image has better + visibility of detail in both the brightest and darkest areas. + +***************************************************************************/ + +int HDRstat; // 1 = OK, 0 = failed or canceled +double HDRinitAlignSize = 160; // initial align image size +double HDRimageIncrease = 1.6; // image size increase per align cycle +double HDRsampSize = 6000; // pixel sample size 11.03 + +double HDRinitSearchRange = 8.0; // initial search range, +/- pixels +double HDRinitSearchStep = 1.0; // initial search step, pixels +double HDRinitWarpRange = 3.0; // initial corner warp range, +/- pixels +double HDRinitWarpStep = 0.67; // initial corner warp step, pixels +double HDRsearchRange = 2.0; // normal search range, +/- pixels +double HDRsearchStep = 0.67; // normal search step, pixels +double HDRwarpRange = 2.0; // normal corner warp range, +/- pixels +double HDRwarpStep = 0.67; // normal corner warp step, pixels + +float *HDRbright = 0; // maps brightness per pixel +zdialog *HDRzd = 0; // tweak dialog +double HDR_respfac[10][1000]; // contribution / image / pixel brightness + +void * HDR_align_thread(void *); // align 2 images +void HDR_brightness(); // compute pixel brightness levels +void HDR_tweak(); // adjust image contribution curves +void * HDR_combine_thread(void *); // combine images per contribution curves + +editfunc EFhdr; // edit function data + + +// menu function + +void m_HDR(GtkWidget *, cchar *) // v.10.7 +{ + char **flist, *ftemp; + int imx, jj, err, px, py, ww, hh; + double diffw, diffh; + double fbright[10], btemp; + double pixsum, fnorm = 3.0 / 65536.0; + uint16 *pixel; + PXM *pxmtemp; + + zfuncs::F1_help_topic = "HDR"; // help topic + + if (mod_keep()) return; // warn unsaved changes + if (! menulock(1)) return; // test menu lock v.11.07 + menulock(0); + + for (imx = 0; imx < 10; imx++) + { // clear all file and PXM data + cimFile[imx] = 0; + cimPXMf[imx] = cimPXMs[imx] = cimPXMw[imx] = 0; + } + + cimNF = 0; + HDRbright = 0; + + flist = zgetfileN(ZTX("Select 2 to 9 files"),"openN",curr_file); // select images to combine + if (! flist) return; + + for (imx = 0; flist[imx]; imx++); // count selected files + if (imx < 2 || imx > 9) { + zmessageACK(mWin,ZTX("Select 2 to 9 files")); + goto cleanup; + } + + cimNF = imx; // file count + for (imx = 0; imx < cimNF; imx++) + cimFile[imx] = strdupz(flist[imx],0,"HDR"); // set up file list + + if (! cim_load_files()) goto cleanup; // load and check all files + + ww = cimPXMf[0]->ww; + hh = cimPXMf[0]->hh; + + for (imx = 1; imx < cimNF; imx++) // check image compatibility + { + diffw = abs(ww - cimPXMf[imx]->ww); + diffw = diffw / ww; + diffh = abs(hh - cimPXMf[imx]->hh); + diffh = diffh / hh; + + if (diffw > 0.02 || diffh > 0.02) { + zmessageACK(mWin,ZTX("Images are not all the same size")); + goto cleanup; + } + } + + free_resources(); // ready to commit + + err = f_open(cimFile[0],0); // curr_file = 1st file in list + if (err) goto cleanup; + + EFhdr.funcname = "HDR"; + if (! edit_setup(EFhdr)) goto cleanup; // setup edit (will lock) + + for (imx = 0; imx < cimNF; imx++) // compute image brightness levels + { + pixsum = 0; + for (py = 0; py < Fhh; py++) + for (px = 0; px < Fww; px++) + { + pixel = PXMpix(cimPXMf[imx],px,py); + pixsum += fnorm * (pixel[0] + pixel[1] + pixel[2]); + } + fbright[imx] = pixsum / (Fww * Fhh); + } + + for (imx = 0; imx < cimNF; imx++) // sort file and pixmap lists + for (jj = imx+1; jj < cimNF; jj++) // by decreasing brightness + { + if (fbright[jj] > fbright[imx]) { // bubble sort + btemp = fbright[jj]; + fbright[jj] = fbright[imx]; + fbright[imx] = btemp; + ftemp = cimFile[jj]; + cimFile[jj] = cimFile[imx]; + cimFile[imx] = ftemp; + pxmtemp = cimPXMf[jj]; + cimPXMf[jj] = cimPXMf[imx]; + cimPXMf[imx] = pxmtemp; + } + } + + start_thread(HDR_align_thread,0); // align each pair of images + wrapup_thread(0); // wait for completion + if (HDRstat != 1) goto cancel; + + HDR_brightness(); // compute pixel brightness levels + if (HDRstat != 1) goto cancel; + + HDR_tweak(); // combine images based on user inputs + if (HDRstat != 1) goto cancel; + + CEF->Fmod = 1; // done + edit_done(EFhdr); + goto cleanup; + +cancel: + edit_cancel(EFhdr); + +cleanup: + + if (flist) { + for (imx = 0; flist[imx]; imx++) // free file list + zfree(flist[imx]); + zfree(flist); + } + + for (imx = 0; imx < cimNF; imx++) { // free cim file and PXM data + if (cimFile[imx]) zfree(cimFile[imx]); + if (cimPXMf[imx]) PXM_free(cimPXMf[imx]); + if (cimPXMs[imx]) PXM_free(cimPXMs[imx]); + if (cimPXMw[imx]) PXM_free(cimPXMw[imx]); + } + + if (HDRbright) zfree(HDRbright); + *SB_text = 0; + + return; +} + + +// HDR align each pair of input images, output combined image to E3pxm16 +// cimPXMf[*] original image +// cimPXMs[*] scaled and color adjusted for pixel comparisons +// cimPXMw[*] warped for display + +void * HDR_align_thread(void *) // v.10.7 +{ + int imx, im1, im2, ww, hh, ii, nn; + double R, maxtf, mintf, midtf; + double xoff, yoff, toff, dxoff, dyoff; + cimoffs offsets[10]; // x/y/t offsets after alignment + + Fzoom = 0; // fit to window if big + Fblowup = 1; // scale up to window if small + Ffuncbusy++; // v.11.01 + cimShrink = 0; // no warp shrinkage (pano) + cimPano = cimPanoV = 0; // no pano mode + + for (imx = 0; imx < cimNF; imx++) // bugfix v.10.8 + memset(&offsets[imx],0,sizeof(cimoffs)); + + for (im1 = 0; im1 < cimNF-1; im1++) // loop each pair of images + { + im2 = im1 + 1; + + memset(&cimOffs[im1],0,sizeof(cimoffs)); // initial image offsets = 0 + memset(&cimOffs[im2],0,sizeof(cimoffs)); + + ww = cimPXMf[im1]->ww; // image dimensions + hh = cimPXMf[im1]->hh; + + nn = ww; // use larger of ww, hh + if (hh > ww) nn = hh; + cimScale = HDRinitAlignSize / nn; // initial align image size + if (cimScale > 1.0) cimScale = 1.0; + + cimBlend = 0; // no blend width (use all) + cim_get_overlap(im1,im2,cimPXMf); // get overlap area + cim_match_colors(im1,im2,cimPXMf); // get color matching factors + + cimSearchRange = HDRinitSearchRange; // initial align search range + cimSearchStep = HDRinitSearchStep; // initial align search step + cimWarpRange = HDRinitWarpRange; // initial align corner warp range + cimWarpStep = HDRinitWarpStep; // initial align corner warp step + cimSampSize = HDRsampSize; // pixel sample size for align/compare + cimNsearch = 0; // reset align search counter + + while (true) // loop, increasing image size + { + cim_scale_image(im1,cimPXMs); // scale images to cimScale + cim_scale_image(im2,cimPXMs); + + cim_adjust_colors(cimPXMs[im1],1); // apply color adjustments + cim_adjust_colors(cimPXMs[im2],2); + + cim_warp_image(im1); // make warped images to show + cim_warp_image(im2); + + cimShowIm1 = im1; // show two images with 50/50 blend + cimShowIm2 = im2; + cimShowAll = 0; + cim_show_images(1,0); // (x/y offsets can change) + + cim_get_overlap(im1,im2,cimPXMs); // get overlap area v.11.04 + cim_get_redpix(im1); // get high-contrast pixels + + cim_align_image(im1,im2); // align im2 to im1 + + zfree(cimRedpix); // clear red pixels + cimRedpix = 0; + + if (cimScale == 1.0) break; // done + + R = HDRimageIncrease; // next larger image size + cimScale = cimScale * R; + if (cimScale > 0.85) { // if close to end, jump to end + R = R / cimScale; + cimScale = 1.0; + } + + cimOffs[im1].xf *= R; // scale offsets for larger image + cimOffs[im1].yf *= R; + cimOffs[im2].xf *= R; + cimOffs[im2].yf *= R; + + for (ii = 0; ii < 4; ii++) { + cimOffs[im1].wx[ii] *= R; + cimOffs[im1].wy[ii] *= R; + cimOffs[im2].wx[ii] *= R; + cimOffs[im2].wy[ii] *= R; + } + + cimSearchRange = HDRsearchRange; // align search range + cimSearchStep = HDRsearchStep; // align search step size + cimWarpRange = HDRwarpRange; // align corner warp range + cimWarpStep = HDRwarpStep; // align corner warp step size + } + + offsets[im2].xf = cimOffs[im2].xf - cimOffs[im1].xf; // save im2 offsets from im1 + offsets[im2].yf = cimOffs[im2].yf - cimOffs[im1].yf; + offsets[im2].tf = cimOffs[im2].tf - cimOffs[im1].tf; + + for (ii = 0; ii < 4; ii++) { + offsets[im2].wx[ii] = cimOffs[im2].wx[ii] - cimOffs[im1].wx[ii]; + offsets[im2].wy[ii] = cimOffs[im2].wy[ii] - cimOffs[im1].wy[ii]; + } + } + + for (imx = 0; imx < cimNF; imx++) // offsets[*] >> cimOffs[*] + cimOffs[imx] = offsets[imx]; + + cimOffs[0].xf = cimOffs[0].yf = cimOffs[0].tf = 0; // image 0 at (0,0,0) + + for (im1 = 0; im1 < cimNF-1; im1++) // absolute offsets for image 1 to last + { + im2 = im1 + 1; + cimOffs[im2].xf += cimOffs[im1].xf; // x/y/t offsets are additive + cimOffs[im2].yf += cimOffs[im1].yf; + cimOffs[im2].tf += cimOffs[im1].tf; + + for (ii = 0; ii < 4; ii++) { // corner warps are additive + cimOffs[im2].wx[ii] += cimOffs[im1].wx[ii]; + cimOffs[im2].wy[ii] += cimOffs[im1].wy[ii]; + } + } + + for (imx = 1; imx < cimNF; imx++) // re-warp to absolute v.10.8 + cim_warp_image(imx); + + toff = cimOffs[0].tf; // balance +/- thetas + maxtf = mintf = toff; + for (imx = 1; imx < cimNF; imx++) { + toff = cimOffs[imx].tf; + if (toff > maxtf) maxtf = toff; + if (toff < mintf) mintf = toff; + } + midtf = 0.5 * (maxtf + mintf); + + for (imx = 0; imx < cimNF; imx++) + cimOffs[imx].tf -= midtf; + + for (im1 = 0; im1 < cimNF-1; im1++) // adjust x/y offsets for images after im1 + for (im2 = im1+1; im2 < cimNF; im2++) // due to im1 theta offset + { + toff = cimOffs[im1].tf; + xoff = cimOffs[im2].xf - cimOffs[im1].xf; + yoff = cimOffs[im2].yf - cimOffs[im1].yf; + dxoff = yoff * sin(toff); + dyoff = xoff * sin(toff); + cimOffs[im2].xf -= dxoff; + cimOffs[im2].yf += dyoff; + } + + Fzoom = Fblowup = 0; + Ffuncbusy--; + HDRstat = 1; + thread_exit(); + return 0; // not executed +} + + +// Compute mean image pixel brightness levels. +// (basis for setting image contributions per brightness level) + +void HDR_brightness() // v.10.7 +{ + int px3, py3, ww, hh, imx, kk, vstat; + double px, py, red, green, blue; + double bright, maxbright, minbright; + double xoff, yoff, sintf[10], costf[10]; + double norm, fnorm = 1.0 / 65536.0; + uint16 vpix[3], *pix3; + + cimScale = 1.0; + + for (imx = 0; imx < cimNF; imx++) // replace alignment images + { // (color adjusted for pixel matching) + PXM_free(cimPXMs[imx]); // with the original images + cimPXMs[imx] = PXM_copy(cimPXMf[imx]); + cim_warp_image(imx); // re-apply warps + } + + for (imx = 0; imx < cimNF; imx++) // pre-calculate trig functions + { + sintf[imx] = sin(cimOffs[imx].tf); + costf[imx] = cos(cimOffs[imx].tf); + } + + ww = E3pxm16->ww; + hh = E3pxm16->hh; + + HDRbright = (float *) zmalloc(ww*hh*sizeof(int),"HDR"); // get memory for brightness array + + minbright = 1.0; + maxbright = 0.0; + + for (py3 = 0; py3 < hh; py3++) // step through all output pixels + for (px3 = 0; px3 < ww; px3++) + { + red = green = blue = 0; + vstat = 0; + + for (imx = 0; imx < cimNF; imx++) // step through all input images + { + xoff = cimOffs[imx].xf; + yoff = cimOffs[imx].yf; + + px = costf[imx] * (px3 - xoff) + sintf[imx] * (py3 - yoff); // image N pixel, after offsets + py = costf[imx] * (py3 - yoff) - sintf[imx] * (px3 - xoff); + vstat = vpixel(cimPXMw[imx],px,py,vpix); + if (! vstat) break; + + red += fnorm * vpix[0]; // sum input pixels + green += fnorm * vpix[1]; + blue += fnorm * vpix[2]; + } + + if (! vstat) { // pixel outside some image + pix3 = PXMpix(E3pxm16,px3,py3); // output pixel = black + pix3[0] = pix3[1] = pix3[2] = 0; + kk = py3 * ww + px3; + HDRbright[kk] = 0; + continue; + } + + bright = (red + green + blue) / (3 * cimNF); // mean pixel brightness, 0.0 to 1.0 + kk = py3 * ww + px3; + HDRbright[kk] = bright; + + if (bright > maxbright) maxbright = bright; + if (bright < minbright) minbright = bright; + + pix3 = PXMpix(E3pxm16,px3,py3); // output pixel + pix3[0] = red * 65535.0 / cimNF; + pix3[1] = green * 65535.0 / cimNF; + pix3[2] = blue * 65535.0 / cimNF; + } + + norm = 0.999 / (maxbright - minbright); // normalize to range 0.0 to 0.999 + + for (int ii = 0; ii < ww * hh; ii++) + HDRbright[ii] = (HDRbright[ii] - minbright) * norm; + + mwpaint2(); // update window + return; +} + + +// Dialog for user to control the contributions of each input image +// while watching the output image which is updated in real time. + +void HDR_tweak() // v.10.7 +{ + int HDR_tweak_event(zdialog *zd, cchar *event); + void HDR_curvedit(int); + + int imx; + double cww = 1.0 / (cimNF-1); + + HDRzd = zdialog_new(ZTX("Adjust Image Contributions"),mWin,Bdone,Bcancel,null); + zdialog_add_widget(HDRzd,"frame","brframe","dialog",0,"expand|space=2"); + zdialog_add_widget(HDRzd,"hbox","hb1","dialog",0); + zdialog_add_widget(HDRzd,"label","lab11","hb1",ZTX("dark pixels"),"space=3"); + zdialog_add_widget(HDRzd,"label","lab12","hb1",0,"expand"); + zdialog_add_widget(HDRzd,"label","lab13","hb1",ZTX("light pixels"),"space=3"); + zdialog_add_widget(HDRzd,"hbox","hb2","dialog",0,"space=3"); + zdialog_add_widget(HDRzd,"label","labf1","hb2",ZTX("file:"),"space=3"); + zdialog_add_widget(HDRzd,"label","labf2","hb2","*"); + + zdialog_add_widget(HDRzd,"hbox","hbcf","dialog",0,"space=5"); + zdialog_add_widget(HDRzd,"label","labcf","hbcf",Bcurvefile,"space=5"); + zdialog_add_widget(HDRzd,"button","load","hbcf",Bopen,"space=5"); + zdialog_add_widget(HDRzd,"button","save","hbcf",Bsave,"space=5"); + + GtkWidget *brframe = zdialog_widget(HDRzd,"brframe"); // set up curve edit + spldat *sd = splcurve_init(brframe,HDR_curvedit); // v.11.01 + EFhdr.curves = sd; + + sd->Nspc = cimNF; // no. curves = no. files + + for (imx = 0; imx < cimNF; imx++) // set up initial response curve + { // anchor points + sd->vert[imx] = 0; + sd->nap[imx] = 2; + sd->apx[imx][0] = 0.01; // flatter curves, v.9.3 + sd->apx[imx][1] = 0.99; + sd->apy[imx][0] = 0.9 - imx * 0.8 * cww; + sd->apy[imx][1] = 0.1 + imx * 0.8 * cww; + splcurve_generate(sd,imx); + } + + start_thread(HDR_combine_thread,0); // start working thread + signal_thread(); + + zdialog_resize(HDRzd,400,360); + zdialog_run(HDRzd,HDR_tweak_event,"-10/20"); // run dialog v.11.07 + zdialog_wait(HDRzd); // wait for completion + + return; +} + + +// dialog event and completion callback function + +int HDR_tweak_event(zdialog *zd, cchar *event) +{ + spldat *sd = EFhdr.curves; + + if (strEqu(event,"load")) { // load saved curve v.11.02 + splcurve_load(sd); + zdialog_stuff(HDRzd,"labf2","*"); + signal_thread(); + return 0; + } + + if (strEqu(event,"save")) { // save curve to file v.11.02 + splcurve_save(sd); + return 0; + } + + if (zd->zstat) // dialog complete + { + wrapup_thread(8); + if (zd->zstat == 1) HDRstat = 1; + else HDRstat = 0; + zdialog_free(HDRzd); + if (HDRstat == 1) cim_trim(); // cut-off edges v.10.9 + } + + return 1; +} + + +// this function is called when a curve is edited + +void HDR_curvedit(int spc) +{ + cchar *pp; + + pp = strrchr(cimFile[spc],'/'); + zdialog_stuff(HDRzd,"labf2",pp+1); + signal_thread(); + return; +} + + +// Combine all input images >> E3pxm16 based on image response curves. + +void * HDR_combine_thread(void *) +{ + void * HDR_combine_wthread(void *arg); + + int imx, ii, kk; + double xlo, xhi, xval, yval, sumrf; + spldat *sd = EFhdr.curves; + + while (true) + { + thread_idle_loop(); // wait for work or exit request + + for (imx = 0; imx < cimNF; imx++) // loop input images + { + ii = sd->nap[imx]; // get low and high anchor points + xlo = sd->apx[imx][0]; // for image response curve + xhi = sd->apx[imx][ii-1]; + if (xlo < 0.02) xlo = 0; // snap-to scale end points + if (xhi > 0.98) xhi = 1; + + for (ii = 0; ii < 1000; ii++) // loop all brightness levels + { + HDR_respfac[imx][ii] = 0; + xval = 0.001 * ii; + if (xval < xlo || xval > xhi) continue; // no influence for brightness level + kk = 1000 * xval; // speedup v.11.06 + yval = sd->yval[imx][kk]; + HDR_respfac[imx][ii] = yval; // = contribution of this input image + } + } + + for (ii = 0; ii < 1000; ii++) // normalize the factors so that + { // they sum to 1.0 + sumrf = 0; + for (imx = 0; imx < cimNF; imx++) + sumrf += HDR_respfac[imx][ii]; + if (! sumrf) continue; + for (imx = 0; imx < cimNF; imx++) + HDR_respfac[imx][ii] = HDR_respfac[imx][ii] / sumrf; + } + + mutex_lock(&Fpixmap_lock); // stop window updates + + for (ii = 0; ii < Nwt; ii++) // start worker threads v.10.7 + start_wthread(HDR_combine_wthread,&wtnx[ii]); + wait_wthreads(); // wait for completion + + mutex_unlock(&Fpixmap_lock); + mwpaint2(); // update window + } + + return 0; // not executed +} + + +void * HDR_combine_wthread(void *arg) // working thread +{ + int index = *((int *) (arg)); + int imx, ww, hh, ii, px3, py3, vstat; + double sintf[10], costf[10], xoff, yoff; + double px, py, red, green, blue, bright, factor; + uint16 vpix[3], *pix3; + + for (imx = 0; imx < cimNF; imx++) // pre-calculate trig functions + { + sintf[imx] = sin(cimOffs[imx].tf); + costf[imx] = cos(cimOffs[imx].tf); + } + + ww = E3pxm16->ww; + hh = E3pxm16->hh; + + for (py3 = index; py3 < hh; py3 += Nwt) // step through all output pixels + for (px3 = 0; px3 < ww; px3++) + { + ii = py3 * ww + px3; + bright = HDRbright[ii]; // mean brightness, 0.0 to 1.0 + ii = 1000 * bright; + + red = green = blue = 0; + + for (imx = 0; imx < cimNF; imx++) // loop input images + { + factor = HDR_respfac[imx][ii]; // image contribution to this pixel + if (! factor) continue; // none + + xoff = cimOffs[imx].xf; + yoff = cimOffs[imx].yf; + + px = costf[imx] * (px3 - xoff) + sintf[imx] * (py3 - yoff); // input virtual pixel mapping to + py = costf[imx] * (py3 - yoff) - sintf[imx] * (px3 - xoff); // this output pixel + + vstat = vpixel(cimPXMw[imx],px,py,vpix); // get input pixel + if (! vstat) continue; + + red += factor * vpix[0]; // accumulate brightness contribution + green += factor * vpix[1]; + blue += factor * vpix[2]; + } + + pix3 = PXMpix(E3pxm16,px3,py3); // output pixel + + pix3[0] = red; // = sum of input pixel contributions + pix3[1] = green; + pix3[2] = blue; + } + + exit_wthread(); + return 0; // not executed +} + + +/************************************************************************** + + Make an HDF (high depth of field) image from several images of the same + subject with different focus settings. Combine the images and allow the + user to "paint" the output composite image using the mouse and choosing + the sharpest input image for each area of the output image. The result + is an image with a depth of field that exceeds the camera capability. + + The images are aligned at the center, but small differences in camera + position (hand-held photos) will cause parallax errors that prevent + perfect alignment of the images. Also, the images with nearer focus + will be slightly larger than those with farther focus. These problems + can be compensated by dragging and warping the images using the mouse. v.10.7 + +**************************************************************************/ + +int HDFstat; // 1 = OK, 0 = failed or canceled +double HDFinitAlignSize = 160; // initial align image size +double HDFimageIncrease = 1.6; // image size increase per align cycle +double HDFsampSize = 6000; // pixel sample size + +double HDFinitSearchRange = 8.0; // initial search range, +/- pixels +double HDFinitSearchStep = 1.0; // initial search step, pixels +double HDFinitWarpRange = 4.0; // initial corner warp range +double HDFinitWarpStep = 1.0; // initial corner warp step +double HDFsearchRange = 2.0; // normal search range +double HDFsearchStep = 1.0; // normal search step +double HDFwarpRange = 1.0; // normal corner warp range v.11.03 +double HDFwarpStep = 0.67; // normal corner warp step + +void * HDF_align_thread(void *); +void HDF_tweak(); +void HDF_mousefunc(); +void * HDF_combine_thread(void *); + +editfunc EFhdf; // edit function data + + +// menu function + +void m_HDF(GtkWidget *, cchar *) // v.10.7 +{ + char **flist; + int imx, err, ww, hh; + double diffw, diffh; + + zfuncs::F1_help_topic = "HDF"; // help topic + + if (mod_keep()) return; // warn unsaved changes + if (! menulock(1)) return; // test menu lock v.11.07 + menulock(0); + + for (imx = 0; imx < 10; imx++) + { // clear all file and PXM data + cimFile[imx] = 0; + cimPXMf[imx] = cimPXMs[imx] = cimPXMw[imx] = 0; + } + + cimNF = 0; + + flist = zgetfileN(ZTX("Select 2 to 9 files"),"openN",curr_file); // select images to combine + if (! flist) return; + + for (imx = 0; flist[imx]; imx++); // count selected files + if (imx < 2 || imx > 9) { + zmessageACK(mWin,ZTX("Select 2 to 9 files")); + goto cleanup; + } + + cimNF = imx; // file count + for (imx = 0; imx < cimNF; imx++) + cimFile[imx] = strdupz(flist[imx],0,"HDF"); // set up file list + + if (! cim_load_files()) goto cleanup; // load and check all files + + ww = cimPXMf[0]->ww; + hh = cimPXMf[0]->hh; + + for (imx = 1; imx < cimNF; imx++) // check image compatibility + { + diffw = abs(ww - cimPXMf[imx]->ww); + diffw = diffw / ww; + diffh = abs(hh - cimPXMf[imx]->hh); + diffh = diffh / hh; + + if (diffw > 0.02 || diffh > 0.02) { + zmessageACK(mWin,ZTX("Images are not all the same size")); + goto cleanup; + } + } + + free_resources(); // ready to commit + + err = f_open(cimFile[0],0); // curr_file = 1st file in list + if (err) goto cleanup; + + EFhdf.funcname = "HDF"; + if (! edit_setup(EFhdf)) goto cleanup; // setup edit (will lock) + + start_thread(HDF_align_thread,0); // align each pair of images + wrapup_thread(0); // wait for completion + if (HDFstat != 1) goto cancel; + + HDF_tweak(); // combine images based on user inputs + if (HDFstat != 1) goto cancel; + + CEF->Fmod = 1; // done + edit_done(EFhdf); + goto cleanup; + +cancel: + edit_cancel(EFhdf); + +cleanup: + + if (flist) { + for (imx = 0; flist[imx]; imx++) // free file list + zfree(flist[imx]); + zfree(flist); + } + + for (imx = 0; imx < cimNF; imx++) { // free cim file and PXM data + if (cimFile[imx]) zfree(cimFile[imx]); + if (cimPXMf[imx]) PXM_free(cimPXMf[imx]); + if (cimPXMs[imx]) PXM_free(cimPXMs[imx]); + if (cimPXMw[imx]) PXM_free(cimPXMw[imx]); + } + + *SB_text = 0; + return; +} + + +// HDF align each pair of input images, output combined image to E3pxm16 +// cimPXMf[*] original image +// cimPXMs[*] scaled and color adjusted for pixel comparisons +// cimPXMw[*] warped for display + +void * HDF_align_thread(void *) // v.10.7 +{ + int imx, im1, im2, ww, hh, ii, nn; + double R, maxtf, mintf, midtf; + double xoff, yoff, toff, dxoff, dyoff; + cimoffs offsets[10]; // x/y/t offsets after alignment + + Fzoom = 0; // fit to window if big + Fblowup = 1; // scale up to window if small + Ffuncbusy++; // v.11.01 + cimShrink = 0; // no warp shrinkage (pano) + cimPano = cimPanoV = 0; // no pano mode + + for (imx = 0; imx < cimNF; imx++) // bugfix v.10.8 + memset(&offsets[imx],0,sizeof(cimoffs)); + + for (im1 = 0; im1 < cimNF-1; im1++) // loop each pair of images + { + im2 = im1 + 1; + + memset(&cimOffs[im1],0,sizeof(cimoffs)); // initial image offsets = 0 + memset(&cimOffs[im2],0,sizeof(cimoffs)); + + ww = cimPXMf[im1]->ww; // image dimensions + hh = cimPXMf[im1]->hh; + + nn = ww; // use larger of ww, hh + if (hh > ww) nn = hh; + cimScale = HDFinitAlignSize / nn; // initial align image size + if (cimScale > 1.0) cimScale = 1.0; + + cimBlend = 0; // no blend width (use all) + cim_get_overlap(im1,im2,cimPXMf); // get overlap area + cim_match_colors(im1,im2,cimPXMf); // get color matching factors + + cimSearchRange = HDFinitSearchRange; // initial align search range + cimSearchStep = HDFinitSearchStep; // initial align search step + cimWarpRange = HDFinitWarpRange; // initial align corner warp range + cimWarpStep = HDFinitWarpStep; // initial align corner warp step + cimSampSize = HDFsampSize; // pixel sample size for align/compare + cimNsearch = 0; // reset align search counter + + while (true) // loop, increasing image size + { + cim_scale_image(im1,cimPXMs); // scale images to cimScale + cim_scale_image(im2,cimPXMs); + + cim_adjust_colors(cimPXMs[im1],1); // apply color adjustments + cim_adjust_colors(cimPXMs[im2],2); + + cim_warp_image(im1); // warp images for show + cim_warp_image(im2); + + cimShowIm1 = im1; // show these two images + cimShowIm2 = im2; // with 50/50 blend + cimShowAll = 0; + cim_show_images(1,0); // (y offset can change) + + cim_get_overlap(im1,im2,cimPXMs); // get overlap area v.11.04 + cim_get_redpix(im1); // get high-contrast pixels + + cim_align_image(im1,im2); // align im2 to im1 + + zfree(cimRedpix); // clear red pixels + cimRedpix = 0; + + if (cimScale == 1.0) break; // done + + R = HDFimageIncrease; // next larger image size + cimScale = cimScale * R; + if (cimScale > 0.85) { // if close to end, jump to end + R = R / cimScale; + cimScale = 1.0; + } + + cimOffs[im1].xf *= R; // scale offsets for larger image + cimOffs[im1].yf *= R; + cimOffs[im2].xf *= R; + cimOffs[im2].yf *= R; + + for (ii = 0; ii < 4; ii++) { + cimOffs[im1].wx[ii] *= R; + cimOffs[im1].wy[ii] *= R; + cimOffs[im2].wx[ii] *= R; + cimOffs[im2].wy[ii] *= R; + } + + cimSearchRange = HDFsearchRange; // align search range + cimSearchStep = HDFsearchStep; // align search step size + cimWarpRange = HDFwarpRange; // align corner warp range + cimWarpStep = HDFwarpStep; // align corner warp step size + } + + offsets[im2].xf = cimOffs[im2].xf - cimOffs[im1].xf; // save im2 offsets from im1 + offsets[im2].yf = cimOffs[im2].yf - cimOffs[im1].yf; + offsets[im2].tf = cimOffs[im2].tf - cimOffs[im1].tf; + + for (ii = 0; ii < 4; ii++) { + offsets[im2].wx[ii] = cimOffs[im2].wx[ii] - cimOffs[im1].wx[ii]; + offsets[im2].wy[ii] = cimOffs[im2].wy[ii] - cimOffs[im1].wy[ii]; + } + } + + for (imx = 0; imx < cimNF; imx++) // offsets[*] >> cimOffs[*] + cimOffs[imx] = offsets[imx]; + + cimOffs[0].xf = cimOffs[0].yf = cimOffs[0].tf = 0; // image 0 at (0,0,0) + + for (im1 = 0; im1 < cimNF-1; im1++) // absolute offsets for image 1 to last + { + im2 = im1 + 1; + cimOffs[im2].xf += cimOffs[im1].xf; // x/y/t offsets are additive + cimOffs[im2].yf += cimOffs[im1].yf; + cimOffs[im2].tf += cimOffs[im1].tf; + + for (ii = 0; ii < 4; ii++) { // corner warps are additive + cimOffs[im2].wx[ii] += cimOffs[im1].wx[ii]; + cimOffs[im2].wy[ii] += cimOffs[im1].wy[ii]; + } + } + + for (imx = 1; imx < cimNF; imx++) // re-warp to absolute v.10.8 + cim_warp_image(imx); + + toff = cimOffs[0].tf; // balance +/- thetas + maxtf = mintf = toff; + for (imx = 1; imx < cimNF; imx++) { + toff = cimOffs[imx].tf; + if (toff > maxtf) maxtf = toff; + if (toff < mintf) mintf = toff; + } + midtf = 0.5 * (maxtf + mintf); + + for (imx = 0; imx < cimNF; imx++) + cimOffs[imx].tf -= midtf; + + for (im1 = 0; im1 < cimNF-1; im1++) // adjust x/y offsets for images after im1 + for (im2 = im1+1; im2 < cimNF; im2++) // due to im1 theta offset + { + toff = cimOffs[im1].tf; + xoff = cimOffs[im2].xf - cimOffs[im1].xf; + yoff = cimOffs[im2].yf - cimOffs[im1].yf; + dxoff = yoff * sin(toff); + dyoff = xoff * sin(toff); + cimOffs[im2].xf -= dxoff; + cimOffs[im2].yf += dyoff; + } + + for (imx = 0; imx < cimNF; imx++) // use final warped images as basis + { // for manual align adjustments + PXM_free(cimPXMs[imx]); // bugfix v.11.04 + cimPXMs[imx] = PXM_copy(cimPXMw[imx]); + } + + Fzoom = Fblowup = 0; + Ffuncbusy--; + HDFstat = 1; + thread_exit(); + return 0; // not executed +} + + +// paint and warp output image + +zdialog *HDFzd = 0; // paint dialog +int HDFmode; // mode: paint or warp +int HDFimage; // current image (0 based) +int HDFradius; // paint mode radius +char *HDFpixmap = 0; // map input image per output pixel +float *HDFwarpx[10], *HDFwarpy[10]; // warp memory, pixel displacements + + +void HDF_tweak() // v.10.7 +{ + char imageN[8] = "imageN", labN[4] = "0"; + int cc, imx, ww, hh; + + int HDF_tweak_dialog_event(zdialog *zd, cchar *event); + + // image (o) 1 (o) 2 (o) 3 ... + // (o) paint radius [___] + // (o) warp [__] + + HDFzd = zdialog_new(ZTX("Paint and Warp Image"),mWin,Bdone,Bcancel,null); + + zdialog_add_widget(HDFzd,"hbox","hbim","dialog",0,"space=3"); + zdialog_add_widget(HDFzd,"label","labim","hbim",ZTX("image"),"space=5"); + zdialog_add_widget(HDFzd,"hbox","hbpw","dialog",0,"space=3"); + zdialog_add_widget(HDFzd,"vbox","vbpw1","hbpw",0,"homog|space=5"); + zdialog_add_widget(HDFzd,"vbox","vbpw2","hbpw",0,"homog|space=5"); + zdialog_add_widget(HDFzd,"radio","paint","vbpw1",ZTX("paint")); + zdialog_add_widget(HDFzd,"radio","warp","vbpw1",ZTX("warp")); + zdialog_add_widget(HDFzd,"hbox","hbp","vbpw2"); + zdialog_add_widget(HDFzd,"label","labpr","hbp",Bradius,"space=5"); + zdialog_add_widget(HDFzd,"spin","radius","hbp","1|400|1|100"); + zdialog_add_widget(HDFzd,"label","space","vbpw2"); + + for (imx = 0; imx < cimNF; imx++) { // add radio button for each image + imageN[5] = '1' + imx; + labN[0] = '1' + imx; + zdialog_add_widget(HDFzd,"radio",imageN,"hbim",labN); + } + + zdialog_stuff(HDFzd,"paint",1); // paint button on + zdialog_stuff(HDFzd,"warp",0); // warp button off + zdialog_stuff(HDFzd,"image1",1); // initial image = 1st + + HDFmode = 0; // start in paint mode + HDFimage = 0; // initial image + HDFradius = 100; // paint radius + + takeMouse(HDFzd,HDF_mousefunc,0); // connect mouse function v.10.12 + + cc = E3ww * E3hh; // allocate pixel map + HDFpixmap = zmalloc(cc,"HDF"); + memset(HDFpixmap,cimNF,cc); // initial state, blend all images + + for (imx = 0; imx < cimNF; imx++) { // allocate warp memory + ww = cimPXMw[imx]->ww; + hh = cimPXMw[imx]->hh; + HDFwarpx[imx] = (float *) zmalloc(ww * hh * sizeof(float),"HDF"); + HDFwarpy[imx] = (float *) zmalloc(ww * hh * sizeof(float),"HDF"); + } + + start_thread(HDF_combine_thread,0); // start working thread + signal_thread(); + + zdialog_resize(HDFzd,250,0); // stretch a bit v.11.07 + zdialog_run(HDFzd,HDF_tweak_dialog_event,"-10/20"); // run dialog, parallel v.11.07 + zdialog_wait(HDFzd); // wait for completion + + return; +} + + +// dialog event and completion callback function + +int HDF_tweak_dialog_event(zdialog *zd, cchar *event) // v.10.7 +{ + int imx, nn; + + if (zd->zstat) // dialog finish + { + freeMouse(); // disconnect mouse function v.10.12 + signal_thread(); + wrapup_thread(8); + if (zd->zstat == 1) HDFstat = 1; + else HDFstat = 0; + if (HDFstat == 1) cim_trim(); // cut-off edges v.10.9 + zdialog_free(HDFzd); + HDFmode = 0; + zfree(HDFpixmap); // free pixel map + for (imx = 0; imx < cimNF; imx++) { + zfree(HDFwarpx[imx]); // free warp memory + zfree(HDFwarpy[imx]); + } + } + + if (strEqu(event,"paint")) { // set paint mode + zdialog_fetch(zd,"paint",nn); + if (! nn) return 1; + HDFmode = 0; + gdk_window_set_cursor(drWin->window,0); // no drag cursor v.11.03 + } + + if (strEqu(event,"warp")) { // set warp mode + zdialog_fetch(zd,"warp",nn); + if (! nn) return 1; + HDFmode = 1; + paint_toparc(2); // stop brush outline + gdk_window_set_cursor(drWin->window,dragcursor); // set drag cursor v.11.03 + } + + if (strnEqu(event,"image",5)) { // image radio button + nn = event[5] - '0'; // 1 to cimNF + if (nn > 0 && nn <= cimNF) + HDFimage = nn - 1; // 0 to cimNF-1 + signal_thread(); + } + + if (strEqu(event,"radius")) // change paint radius + zdialog_fetch(zd,"radius",HDFradius); + + if (strEqu(event,"focus")) { // toggle mouse capture v.10.12 + takeMouse(zd,HDF_mousefunc,0); // connect mouse function + if (HDFmode == 1) + gdk_window_set_cursor(drWin->window,dragcursor); // warp mode, drag cursor v.11.03 + signal_thread(); + } + + return 1; +} + + +// HDF dialog mouse function +// paint: during drag, selected image >> HDFpixmap (within paint radius) >> E3 +// warp: for selected image, cimPXMs >> warp >> cimPXMw >> E3 + +void HDF_mousefunc() // v.10.7 +{ + uint16 vpix1[3], *pix2, *pix3; + int imx, radius, radius2, vstat1; + int mx, my, dx, dy, px3, py3; + char imageN[8] = "imageN"; + double px1, py1; + double xoff, yoff, sintf[10], costf[10]; + int ii, px, py, ww, hh; + double mag, dispx, dispy, d1, d2; + PXM *pxm1, *pxm2; + + if (HDFmode == 0) goto paint; + if (HDFmode == 1) goto warp; + return; + +paint: + + radius = HDFradius; // paintbrush radius + radius2 = radius * radius; + + toparcx = Mxposn - radius; // paintbrush outline circle + toparcy = Myposn - radius; + toparcw = toparch = 2 * radius; + Ftoparc = 1; + paint_toparc(3); + + if (LMclick || RMclick) { // mouse click + LMclick = RMclick = 0; + return; // ignore v.10.8 + } + + else if (Mxdrag || Mydrag) { // drag in progress + mx = Mxdrag; + my = Mydrag; + } + + else return; + + if (mx < 0 || mx > E3ww-1 || my < 0 || my > E3hh-1) // mouse outside image area + return; + + for (imx = 0; imx < cimNF; imx++) // pre-calculate trig funcs + { + sintf[imx] = sin(cimOffs[imx].tf); + costf[imx] = cos(cimOffs[imx].tf); + } + + for (dy = -radius; dy <= radius; dy++) // loop pixels around mouse + for (dx = -radius; dx <= radius; dx++) + { + if (dx*dx + dy*dy > radius2) continue; // outside radius + + px3 = mx + dx; // output pixel + py3 = my + dy; + if (px3 < 0 || px3 > E3ww-1) continue; // outside image + if (py3 < 0 || py3 > E3hh-1) continue; + + pix3 = PXMpix(E3pxm16,px3,py3); // output pixel + + imx = py3 * E3ww + px3; // update pixmap to selected image + HDFpixmap[imx] = HDFimage; + + imx = HDFimage; + xoff = cimOffs[imx].xf; + yoff = cimOffs[imx].yf; + px1 = costf[imx] * (px3 - xoff) + sintf[imx] * (py3 - yoff); // input virtual pixel + py1 = costf[imx] * (py3 - yoff) - sintf[imx] * (px3 - xoff); + vstat1 = vpixel(cimPXMw[imx],px1,py1,vpix1); + if (vstat1) { + pix3[0] = vpix1[0]; + pix3[1] = vpix1[1]; + pix3[2] = vpix1[2]; + } + else pix3[0] = pix3[1] = pix3[2] = 0; + } + + mx = mx - radius - 1; // update window v.10.12 + my = my - radius - 1; + ww = 2 * radius + 3; + paint_toparc(2); + mwpaint3(mx,my,ww,ww); + Ftoparc = 1; + paint_toparc(3); + + return; + +warp: + + if (LMclick || RMclick) { // mouse click + LMclick = RMclick = 0; // ignore v.10.8 + return; + } + + else if (Mxdrag || Mydrag) { // drag in progress + mx = Mxdrag; + my = Mydrag; + } + + else return; + + if (mx < 0 || mx > E3ww-1 || my < 0 || my > E3hh-1) // mouse outside image area + return; + + imx = my * E3ww + mx; // if pixel has been painted, + imx = HDFpixmap[imx]; // select corresp. image to warp + if (imx == cimNF) return; // else no action v.10.8 + + if (imx != HDFimage) { + HDFimage = imx; // update selected image and + imageN[5] = '1' + imx; // dialog radio button + zdialog_stuff(HDFzd,imageN,1); + } + + pxm1 = cimPXMs[imx]; // input image + pxm2 = cimPXMw[imx]; // output image + ww = pxm2->ww; + hh = pxm2->hh; + + mx = Mxdown; // drag origin, image coordinates + my = Mydown; + dx = Mxdrag - Mxdown; // drag increment + dy = Mydrag - Mydown; + Mxdown = Mxdrag; // next drag origin + Mydown = Mydrag; + + d1 = ww * ww + hh * hh; + + for (py = 0; py < hh; py++) // process all output pixels + for (px = 0; px < ww; px++) + { + d2 = (px-mx)*(px-mx) + (py-my)*(py-my); + mag = (1.0 - d2 / d1); + mag = mag * mag * mag * mag; + mag = mag * mag * mag * mag; + mag = mag * mag * mag * mag; + + dispx = -dx * mag; // displacement = drag * mag + dispy = -dy * mag; + + ii = py * ww + px; + HDFwarpx[imx][ii] += dispx; // add this drag to prior sum + HDFwarpy[imx][ii] += dispy; + + dispx = HDFwarpx[imx][ii]; + dispy = HDFwarpy[imx][ii]; + + vstat1 = vpixel(pxm1,px+dispx,py+dispy,vpix1); // input virtual pixel + pix2 = PXMpix(pxm2,px,py); // output pixel + if (vstat1) { + pix2[0] = vpix1[0]; + pix2[1] = vpix1[1]; + pix2[2] = vpix1[2]; + } + else pix2[0] = pix2[1] = pix2[2] = 0; + } + + signal_thread(); // combine images >> E3 >> main window + return; +} + + +// Combine images in E3pxm16 (not reallocated). Update main window. + +void * HDF_combine_thread(void *) // v.10.7 +{ + void * HDF_combine_wthread(void *); + + while (true) + { + thread_idle_loop(); // wait for work or exit request + + mutex_lock(&Fpixmap_lock); // stop window updates + + for (int ii = 0; ii < Nwt; ii++) // start worker threads v.10.7 + start_wthread(HDF_combine_wthread,&wtnx[ii]); + wait_wthreads(); // wait for completion + + mutex_unlock(&Fpixmap_lock); // update window + mwpaint2(); + } + + return 0; // not executed +} + + +void * HDF_combine_wthread(void *arg) // worker thread +{ + int index = *((int *) (arg)); // no more paint and warp modes v.10.8 + int px3, py3, vstat1; + int imx, red, green, blue; + double px, py; + double xoff, yoff, sintf[10], costf[10]; + uint16 vpix1[3], *pix3; + + for (imx = 0; imx < cimNF; imx++) // pre-calculate trig funcs + { + sintf[imx] = sin(cimOffs[imx].tf); + costf[imx] = cos(cimOffs[imx].tf); + } + + for (py3 = index+1; py3 < E3hh-1; py3 += Nwt) // step through output pixels + for (px3 = 1; px3 < E3ww-1; px3++) + { + pix3 = PXMpix(E3pxm16,px3,py3); + + imx = py3 * E3ww + px3; + imx = HDFpixmap[imx]; + + if (imx < cimNF) // specific image maps to pixel + { + xoff = cimOffs[imx].xf; + yoff = cimOffs[imx].yf; + px = costf[imx] * (px3 - xoff) + sintf[imx] * (py3 - yoff); + py = costf[imx] * (py3 - yoff) - sintf[imx] * (px3 - xoff); + vstat1 = vpixel(cimPXMw[imx],px,py,vpix1); // corresp. input vpixel + if (vstat1) { + pix3[0] = vpix1[0]; + pix3[1] = vpix1[1]; + pix3[2] = vpix1[2]; + } + else pix3[0] = pix3[1] = pix3[2] = 0; + } + + else // use blend of all images + { + red = green = blue = 0; + + for (imx = 0; imx < cimNF; imx++) + { + xoff = cimOffs[imx].xf; + yoff = cimOffs[imx].yf; + px = costf[imx] * (px3 - xoff) + sintf[imx] * (py3 - yoff); + py = costf[imx] * (py3 - yoff) - sintf[imx] * (px3 - xoff); + vstat1 = vpixel(cimPXMw[imx],px,py,vpix1); + if (vstat1) { + red += vpix1[0]; + green += vpix1[1]; + blue += vpix1[2]; + } + } + + pix3[0] = red / cimNF; + pix3[1] = green / cimNF; + pix3[2] = blue / cimNF; + } + } + + exit_wthread(); + return 0; // not executed, avoid gcc warning +} + + +/************************************************************************** + + Stack/Paint function + Combine multiple images of one subject taken at different times from + (almost) the same camera position. Align the images and allow the user + to choose which input image to use for each area of the output image, + by "painting" with the mouse. Use this to remove tourists and cars that + move in and out of a scene being photographed. + +**************************************************************************/ + +int STPstat; // 1 = OK, 0 = failed or canceled +double STPinitAlignSize = 160; // initial align image size +double STPimageIncrease = 1.6; // image size increase per align cycle +double STPsampSize = 10000; // pixel sample size v.11.03 + +double STPinitSearchRange = 5.0; // initial search range, +/- pixels +double STPinitSearchStep = 1.0; // initial search step, pixels +double STPinitWarpRange = 2.0; // initial corner warp range +double STPinitWarpStep = 1.0; // initial corner warp step +double STPsearchRange = 2.0; // normal search range +double STPsearchStep = 1.0; // normal search step +double STPwarpRange = 1.0; // normal corner warp range +double STPwarpStep = 0.67; // normal corner warp step + +void * STP_align_thread(void *); +void STP_tweak(); +void STP_mousefunc(); +void * STP_combine_thread(void *); + +editfunc EFstp; // edit function data + + +// menu function + +void m_STP(GtkWidget *, cchar *) // v.11.02 +{ + char **flist; + int imx, err, ww, hh; + double diffw, diffh; + + zfuncs::F1_help_topic = "stack_paint"; // help topic + + if (mod_keep()) return; // warn unsaved changes + if (! menulock(1)) return; // test menu lock v.11.07 + menulock(0); + + for (imx = 0; imx < 10; imx++) + { // clear all file and PXM data + cimFile[imx] = 0; + cimPXMf[imx] = cimPXMs[imx] = cimPXMw[imx] = 0; + } + + cimNF = 0; + + flist = zgetfileN(ZTX("Select 2 to 9 files"),"openN",curr_file); // select images to combine + if (! flist) return; + + for (imx = 0; flist[imx]; imx++); // count selected files + if (imx < 2 || imx > 9) { + zmessageACK(mWin,ZTX("Select 2 to 9 files")); + goto cleanup; + } + + cimNF = imx; // file count + for (imx = 0; imx < cimNF; imx++) + cimFile[imx] = strdupz(flist[imx],0,"STP"); // set up file list + + if (! cim_load_files()) goto cleanup; // load and check all files + + ww = cimPXMf[0]->ww; + hh = cimPXMf[0]->hh; + + for (imx = 1; imx < cimNF; imx++) // check image compatibility + { + diffw = abs(ww - cimPXMf[imx]->ww); + diffw = diffw / ww; + diffh = abs(hh - cimPXMf[imx]->hh); + diffh = diffh / hh; + + if (diffw > 0.02 || diffh > 0.02) { + zmessageACK(mWin,ZTX("Images are not all the same size")); + goto cleanup; + } + } + + free_resources(); // ready to commit + + err = f_open(cimFile[0],0); // curr_file = 1st file in list + if (err) goto cleanup; + + EFstp.funcname = "stack-paint"; + if (! edit_setup(EFstp)) goto cleanup; // setup edit (will lock) + + start_thread(STP_align_thread,0); // align each pair of images + wrapup_thread(0); // wait for completion + if (STPstat != 1) goto cancel; + + STP_tweak(); // combine images based on user inputs + if (STPstat != 1) goto cancel; + + CEF->Fmod = 1; // done + edit_done(EFstp); + goto cleanup; + +cancel: + edit_cancel(EFstp); + +cleanup: + + if (flist) { + for (imx = 0; flist[imx]; imx++) // free file list + zfree(flist[imx]); + zfree(flist); + } + + for (imx = 0; imx < cimNF; imx++) { // free cim file and PXM data + if (cimFile[imx]) zfree(cimFile[imx]); + if (cimPXMf[imx]) PXM_free(cimPXMf[imx]); + if (cimPXMs[imx]) PXM_free(cimPXMs[imx]); + if (cimPXMw[imx]) PXM_free(cimPXMw[imx]); + } + + *SB_text = 0; + return; +} + + +// align each pair of input images, output combined image to E3pxm16 +// cimPXMf[*] original image +// cimPXMs[*] scaled and color adjusted for pixel comparisons +// cimPXMw[*] warped for display + +void * STP_align_thread(void *) // v.11.02 +{ + int imx, im1, im2, ww, hh, ii, nn; + double R, maxtf, mintf, midtf; + double xoff, yoff, toff, dxoff, dyoff; + cimoffs offsets[10]; // x/y/t offsets after alignment + + Fzoom = 0; // fit to window if big + Fblowup = 1; // scale up to window if small + Ffuncbusy++; + cimShrink = 0; // no warp shrinkage (pano) + cimPano = cimPanoV = 0; // no pano mode + + for (imx = 0; imx < cimNF; imx++) + memset(&offsets[imx],0,sizeof(cimoffs)); + + for (im1 = 0; im1 < cimNF-1; im1++) // loop each pair of images + { + im2 = im1 + 1; + + memset(&cimOffs[im1],0,sizeof(cimoffs)); // initial image offsets = 0 + memset(&cimOffs[im2],0,sizeof(cimoffs)); + + ww = cimPXMf[im1]->ww; // image dimensions + hh = cimPXMf[im1]->hh; + + nn = ww; // use larger of ww, hh + if (hh > ww) nn = hh; + cimScale = STPinitAlignSize / nn; // initial align image size + if (cimScale > 1.0) cimScale = 1.0; + + cimBlend = 0; // no blend width (use all) + cim_get_overlap(im1,im2,cimPXMf); // get overlap area + cim_match_colors(im1,im2,cimPXMf); // get color matching factors + + cimSearchRange = STPinitSearchRange; // initial align search range + cimSearchStep = STPinitSearchStep; // initial align search step + cimWarpRange = STPinitWarpRange; // initial align corner warp range + cimWarpStep = STPinitWarpStep; // initial align corner warp step + cimSampSize = STPsampSize; // pixel sample size for align/compare + cimNsearch = 0; // reset align search counter + + while (true) // loop, increasing image size + { + cim_scale_image(im1,cimPXMs); // scale images to cimScale + cim_scale_image(im2,cimPXMs); + + cim_adjust_colors(cimPXMs[im1],1); // apply color adjustments + cim_adjust_colors(cimPXMs[im2],2); + + cim_warp_image(im1); // warp images for show + cim_warp_image(im2); + + cimShowIm1 = im1; // show these two images + cimShowIm2 = im2; // with 50/50 blend + cimShowAll = 0; + cim_show_images(1,0); // (y offset can change) + + cim_get_overlap(im1,im2,cimPXMs); // get overlap area v.11.04 + cim_get_redpix(im1); // get high-contrast pixels + + cim_align_image(im1,im2); // align im2 to im1 + + zfree(cimRedpix); // clear red pixels + cimRedpix = 0; + + if (cimScale == 1.0) break; // done + + R = STPimageIncrease; // next larger image size + cimScale = cimScale * R; + if (cimScale > 0.85) { // if close to end, jump to end + R = R / cimScale; + cimScale = 1.0; + } + + cimOffs[im1].xf *= R; // scale offsets for larger image + cimOffs[im1].yf *= R; + cimOffs[im2].xf *= R; + cimOffs[im2].yf *= R; + + for (ii = 0; ii < 4; ii++) { + cimOffs[im1].wx[ii] *= R; + cimOffs[im1].wy[ii] *= R; + cimOffs[im2].wx[ii] *= R; + cimOffs[im2].wy[ii] *= R; + } + + cimSearchRange = STPsearchRange; // align search range + cimSearchStep = STPsearchStep; // align search step size + cimWarpRange = STPwarpRange; // align corner warp range + cimWarpStep = STPwarpStep; // align corner warp step size + } + + offsets[im2].xf = cimOffs[im2].xf - cimOffs[im1].xf; // save im2 offsets from im1 + offsets[im2].yf = cimOffs[im2].yf - cimOffs[im1].yf; + offsets[im2].tf = cimOffs[im2].tf - cimOffs[im1].tf; + + for (ii = 0; ii < 4; ii++) { + offsets[im2].wx[ii] = cimOffs[im2].wx[ii] - cimOffs[im1].wx[ii]; + offsets[im2].wy[ii] = cimOffs[im2].wy[ii] - cimOffs[im1].wy[ii]; + } + } + + for (imx = 0; imx < cimNF; imx++) // offsets[*] >> cimOffs[*] + cimOffs[imx] = offsets[imx]; + + cimOffs[0].xf = cimOffs[0].yf = cimOffs[0].tf = 0; // image 0 at (0,0,0) + + for (im1 = 0; im1 < cimNF-1; im1++) // absolute offsets for image 1 to last + { + im2 = im1 + 1; + cimOffs[im2].xf += cimOffs[im1].xf; // x/y/t offsets are additive + cimOffs[im2].yf += cimOffs[im1].yf; + cimOffs[im2].tf += cimOffs[im1].tf; + + for (ii = 0; ii < 4; ii++) { // corner warps are additive + cimOffs[im2].wx[ii] += cimOffs[im1].wx[ii]; + cimOffs[im2].wy[ii] += cimOffs[im1].wy[ii]; + } + } + + for (imx = 1; imx < cimNF; imx++) // re-warp to absolute + cim_warp_image(imx); + + toff = cimOffs[0].tf; // balance +/- thetas + maxtf = mintf = toff; + for (imx = 1; imx < cimNF; imx++) { + toff = cimOffs[imx].tf; + if (toff > maxtf) maxtf = toff; + if (toff < mintf) mintf = toff; + } + midtf = 0.5 * (maxtf + mintf); + + for (imx = 0; imx < cimNF; imx++) + cimOffs[imx].tf -= midtf; + + for (im1 = 0; im1 < cimNF-1; im1++) // adjust x/y offsets for images after im1 + for (im2 = im1+1; im2 < cimNF; im2++) // due to im1 theta offset + { + toff = cimOffs[im1].tf; + xoff = cimOffs[im2].xf - cimOffs[im1].xf; + yoff = cimOffs[im2].yf - cimOffs[im1].yf; + dxoff = yoff * sin(toff); + dyoff = xoff * sin(toff); + cimOffs[im2].xf -= dxoff; + cimOffs[im2].yf += dyoff; + } + + Fzoom = Fblowup = 0; + Ffuncbusy--; + STPstat = 1; + thread_exit(); + return 0; // not executed +} + + +// paint output image + +zdialog *STPzd = 0; // paint dialog +int STPimage; // current image (0 based) +int STPradius; // paint mode radius +char *STPpixmap = 0; // map input image per output pixel + + +void STP_tweak() // v.11.02 +{ + char imageN[8] = "imageN", labN[4] = "0"; + int cc, imx; + + int STP_tweak_dialog_event(zdialog *zd, cchar *event); + + // image (o) 1 (o) 2 (o) 3 ... + // radius [___] + + STPzd = zdialog_new(ZTX("Select and Paint Image"),mWin,Bdone,Bcancel,null); + zdialog_add_widget(STPzd,"hbox","hbim","dialog",0,"space=3"); + zdialog_add_widget(STPzd,"label","labim","hbim",ZTX("image"),"space=5"); + zdialog_add_widget(STPzd,"hbox","hbmr","dialog",0,"space=3"); + zdialog_add_widget(STPzd,"label","labr","hbmr",Bradius,"space=5"); + zdialog_add_widget(STPzd,"spin","radius","hbmr","1|400|1|100"); + + for (imx = 0; imx < cimNF; imx++) { // add radio button for each image + imageN[5] = '1' + imx; + labN[0] = '1' + imx; + zdialog_add_widget(STPzd,"radio",imageN,"hbim",labN); + } + + zdialog_stuff(STPzd,"image1",1); // initial image = 1st + + STPimage = 0; // initial image + STPradius = 100; // paint radius + + takeMouse(STPzd,STP_mousefunc,0); // connect mouse function + + cc = E3ww * E3hh; // allocate pixel map + STPpixmap = zmalloc(cc,"STP"); + memset(STPpixmap,cimNF,cc); // initial state, blend all images + + start_thread(STP_combine_thread,0); // start working thread + signal_thread(); + + zdialog_run(STPzd,STP_tweak_dialog_event,"-10/20"); // run dialog, parallel v.11.07 + zdialog_wait(STPzd); // wait for completion + + return; +} + + +// dialog event and completion callback function + +int STP_tweak_dialog_event(zdialog *zd, cchar *event) // v.11.02 +{ + int nn; + + if (zd->zstat) // dialog finish + { + freeMouse(); // disconnect mouse function + signal_thread(); + wrapup_thread(8); + if (zd->zstat == 1) STPstat = 1; + else STPstat = 0; + if (STPstat == 1) cim_trim(); // cut-off edges + zdialog_free(STPzd); + zfree(STPpixmap); // free pixel map + } + + if (strnEqu(event,"image",5)) { // image radio button + nn = event[5] - '0'; // 1 to cimNF + if (nn > 0 && nn <= cimNF) + STPimage = nn - 1; // 0 to cimNF-1 + signal_thread(); + } + + if (strEqu(event,"radius")) // change paint radius + zdialog_fetch(zd,"radius",STPradius); + + if (strEqu(event,"focus")) { // toggle mouse capture v.12.01 + takeMouse(zd,STP_mousefunc,0); // connect mouse function + signal_thread(); + } + + return 1; +} + + +// STP dialog mouse function +// paint: during drag, selected image >> STPpixmap (within paint radius) >> E3 +// warp: for selected image, cimPXMs >> warp >> cimPXMw >> E3 + +void STP_mousefunc() // v.11.02 +{ + uint16 vpix1[3], *pix3; + int imx, radius, radius2, vstat1; + int mx, my, dx, dy, px3, py3, ww; + double px1, py1; + double xoff, yoff, sintf[10], costf[10]; + + radius = STPradius; // paintbrush radius + radius2 = radius * radius; + + toparcx = Mxposn - radius; // paintbrush outline circle + toparcy = Myposn - radius; + toparcw = toparch = 2 * radius; + Ftoparc = 1; + paint_toparc(3); + + if (LMclick || RMclick) { // mouse click + LMclick = RMclick = 0; + return; // ignore + } + + else if (Mxdrag || Mydrag) { // drag in progress + mx = Mxdrag; + my = Mydrag; + } + + else return; + + if (mx < 0 || mx > E3ww-1 || my < 0 || my > E3hh-1) // mouse outside image area + return; + + for (imx = 0; imx < cimNF; imx++) // pre-calculate trig funcs + { + sintf[imx] = sin(cimOffs[imx].tf); + costf[imx] = cos(cimOffs[imx].tf); + } + + for (dy = -radius; dy <= radius; dy++) // loop pixels around mouse + for (dx = -radius; dx <= radius; dx++) + { + if (dx*dx + dy*dy > radius2) continue; // outside radius + + px3 = mx + dx; // output pixel + py3 = my + dy; + if (px3 < 0 || px3 > E3ww-1) continue; // outside image + if (py3 < 0 || py3 > E3hh-1) continue; + + pix3 = PXMpix(E3pxm16,px3,py3); // output pixel + + imx = py3 * E3ww + px3; // update pixmap to selected image + STPpixmap[imx] = STPimage; + + imx = STPimage; + xoff = cimOffs[imx].xf; + yoff = cimOffs[imx].yf; + px1 = costf[imx] * (px3 - xoff) + sintf[imx] * (py3 - yoff); // input virtual pixel + py1 = costf[imx] * (py3 - yoff) - sintf[imx] * (px3 - xoff); + vstat1 = vpixel(cimPXMw[imx],px1,py1,vpix1); + if (vstat1) { + pix3[0] = vpix1[0]; + pix3[1] = vpix1[1]; + pix3[2] = vpix1[2]; + } + else pix3[0] = pix3[1] = pix3[2] = 0; + } + + mx = mx - radius - 1; // update window + my = my - radius - 1; + ww = 2 * radius + 3; + paint_toparc(2); + mwpaint3(mx,my,ww,ww); + Ftoparc = 1; + paint_toparc(3); + return; +} + + +// Combine images in E3pxm16 (not reallocated). Update main window. + +void * STP_combine_thread(void *) // v.11.02 +{ + void * STP_combine_wthread(void *); + + while (true) + { + thread_idle_loop(); // wait for work or exit request + + mutex_lock(&Fpixmap_lock); // stop window updates + + for (int ii = 0; ii < Nwt; ii++) // start worker threads + start_wthread(STP_combine_wthread,&wtnx[ii]); + wait_wthreads(); // wait for completion + + mutex_unlock(&Fpixmap_lock); // update window + mwpaint2(); + } + + return 0; // not executed +} + + +void * STP_combine_wthread(void *arg) // worker thread +{ + int index = *((int *) (arg)); + int px3, py3, vstat1; + int imx, red, green, blue; + double px, py; + double xoff, yoff, sintf[10], costf[10]; + uint16 vpix1[3], *pix3; + + for (imx = 0; imx < cimNF; imx++) // pre-calculate trig funcs + { + sintf[imx] = sin(cimOffs[imx].tf); + costf[imx] = cos(cimOffs[imx].tf); + } + + for (py3 = index+1; py3 < E3hh-1; py3 += Nwt) // step through output pixels + for (px3 = 1; px3 < E3ww-1; px3++) + { + pix3 = PXMpix(E3pxm16,px3,py3); + + imx = py3 * E3ww + px3; + imx = STPpixmap[imx]; + + if (imx < cimNF) // specific image maps to pixel + { + xoff = cimOffs[imx].xf; + yoff = cimOffs[imx].yf; + px = costf[imx] * (px3 - xoff) + sintf[imx] * (py3 - yoff); + py = costf[imx] * (py3 - yoff) - sintf[imx] * (px3 - xoff); + vstat1 = vpixel(cimPXMw[imx],px,py,vpix1); // corresp. input vpixel + if (vstat1) { + pix3[0] = vpix1[0]; + pix3[1] = vpix1[1]; + pix3[2] = vpix1[2]; + } + else pix3[0] = pix3[1] = pix3[2] = 0; + } + + else // use blend of all images + { + red = green = blue = 0; + + for (imx = 0; imx < cimNF; imx++) + { + xoff = cimOffs[imx].xf; + yoff = cimOffs[imx].yf; + px = costf[imx] * (px3 - xoff) + sintf[imx] * (py3 - yoff); + py = costf[imx] * (py3 - yoff) - sintf[imx] * (px3 - xoff); + vstat1 = vpixel(cimPXMw[imx],px,py,vpix1); + if (vstat1) { + red += vpix1[0]; + green += vpix1[1]; + blue += vpix1[2]; + } + } + + pix3[0] = red / cimNF; + pix3[1] = green / cimNF; + pix3[2] = blue / cimNF; + } + } + + exit_wthread(); + return 0; // not executed, avoid gcc warning +} + + +/************************************************************************** + + Stack/Noise function + Combine multiple photos of the same subject and average the + pixels for noise reduction. + +**************************************************************************/ + +double STN_initAlignSize = 160; // initial align image size +double STN_imageIncrease = 1.6; // image size increase per align cycle +double STN_sampSize = 6000; // pixel sample size + +double STN_initSearchRange = 5.0; // initial search range, +/- pixels +double STN_initSearchStep = 1.0; // initial search step, pixels +double STN_initWarpRange = 2.0; // initial corner warp range +double STN_initWarpStep = 1.0; // initial corner warp step +double STN_searchRange = 2.0; // normal search range +double STN_searchStep = 1.0; // normal search step +double STN_warpRange = 1.0; // normal corner warp range +double STN_warpStep = 0.67; // normal corner warp step + +int STN_stat; // 1 = OK, 0 = failed or canceled +int STN_average = 1, STN_median = 0; // use average/median of input pixels +int STN_exlow = 0, STN_exhigh = 0; // exclude low/high pixel + +void * STN_align_thread(void *); +void STN_tweak(); +void * STN_combine_thread(void *); + +editfunc EFstn; // edit function data + + +// menu function + +void m_STN(GtkWidget *, cchar *) // new v.10.9 +{ + char **flist; + int imx, err, ww, hh; + double diffw, diffh; + + zfuncs::F1_help_topic = "stack_noise"; // help topic + + if (mod_keep()) return; // warn unsaved changes + if (! menulock(1)) return; // test menu lock v.11.07 + menulock(0); + + for (imx = 0; imx < 10; imx++) + { // clear all file and PXM data + cimFile[imx] = 0; + cimPXMf[imx] = cimPXMs[imx] = cimPXMw[imx] = 0; + } + + cimNF = 0; + + flist = zgetfileN(ZTX("Select 2 to 9 files"),"openN",curr_file); // select images to combine + if (! flist) return; + + for (imx = 0; flist[imx]; imx++); // count selected files + if (imx < 2 || imx > 9) { + zmessageACK(mWin,ZTX("Select 2 to 9 files")); + goto cleanup; + } + + cimNF = imx; // file count + for (imx = 0; imx < cimNF; imx++) + cimFile[imx] = strdupz(flist[imx],0,"STN"); // set up file list + + if (! cim_load_files()) goto cleanup; // load and check all files + + ww = cimPXMf[0]->ww; + hh = cimPXMf[0]->hh; + + for (imx = 1; imx < cimNF; imx++) // check image compatibility + { + diffw = abs(ww - cimPXMf[imx]->ww); + diffw = diffw / ww; + diffh = abs(hh - cimPXMf[imx]->hh); + diffh = diffh / hh; + + if (diffw > 0.02 || diffh > 0.02) { + zmessageACK(mWin,ZTX("Images are not all the same size")); + goto cleanup; + } + } + + free_resources(); // ready to commit + + err = f_open(cimFile[0],0); // curr_file = 1st file in list + if (err) goto cleanup; + + EFstn.funcname = "stack-noise"; + if (! edit_setup(EFstn)) goto cleanup; // setup edit (will lock) + + start_thread(STN_align_thread,0); // align each pair of images + wrapup_thread(0); // wait for completion + if (STN_stat != 1) goto cancel; + + STN_tweak(); // combine images based on user inputs + if (STN_stat != 1) goto cancel; + + CEF->Fmod = 1; // done + edit_done(EFstn); + goto cleanup; + +cancel: + edit_cancel(EFstn); + +cleanup: + + if (flist) { + for (imx = 0; flist[imx]; imx++) // free file list + zfree(flist[imx]); + zfree(flist); + } + + for (imx = 0; imx < cimNF; imx++) { // free cim file and PXM data + if (cimFile[imx]) zfree(cimFile[imx]); + if (cimPXMf[imx]) PXM_free(cimPXMf[imx]); + if (cimPXMs[imx]) PXM_free(cimPXMs[imx]); + if (cimPXMw[imx]) PXM_free(cimPXMw[imx]); + } + + *SB_text = 0; + return; +} + + +// align each image 2nd-last to 1st image +// cimPXMf[*] original image +// cimPXMs[*] scaled and color adjusted for pixel comparisons +// cimPXMw[*] warped for display + +void * STN_align_thread(void *) // v.10.9 +{ + int imx, im1, im2, ww, hh, ii, nn; + double R, maxtf, mintf, midtf; + double xoff, yoff, toff, dxoff, dyoff; + + Fzoom = 0; // fit to window if big + Fblowup = 1; // scale up to window if small + Ffuncbusy++; // v.11.01 + cimShrink = 0; // no warp shrinkage (pano) + cimPano = cimPanoV = 0; // no pano mode + + for (imx = 1; imx < cimNF; imx++) // loop 2nd to last image + { + im1 = 0; // images to align + im2 = imx; + + memset(&cimOffs[im1],0,sizeof(cimoffs)); // initial image offsets = 0 + memset(&cimOffs[im2],0,sizeof(cimoffs)); + + ww = cimPXMf[im1]->ww; // image dimensions + hh = cimPXMf[im1]->hh; + + nn = ww; // use larger of ww, hh + if (hh > ww) nn = hh; + cimScale = STN_initAlignSize / nn; // initial align image size + if (cimScale > 1.0) cimScale = 1.0; + + cimBlend = 0; // no blend width (use all) + cim_get_overlap(im1,im2,cimPXMf); // get overlap area + cim_match_colors(im1,im2,cimPXMf); // get color matching factors + + cimSearchRange = STN_initSearchRange; // initial align search range + cimSearchStep = STN_initSearchStep; // initial align search step + cimWarpRange = STN_initWarpRange; // initial align corner warp range + cimWarpStep = STN_initWarpStep; // initial align corner warp step + cimSampSize = STN_sampSize; // pixel sample size for align/compare + cimNsearch = 0; // reset align search counter + + while (true) // loop, increasing image size + { + cim_scale_image(im1,cimPXMs); // scale images to cimScale + cim_scale_image(im2,cimPXMs); + + cim_adjust_colors(cimPXMs[im1],1); // apply color adjustments + cim_adjust_colors(cimPXMs[im2],2); + + cim_warp_image(im1); // warp images for show + cim_warp_image(im2); + + cimShowIm1 = im1; // show these two images + cimShowIm2 = im2; // with 50/50 blend + cimShowAll = 0; + cim_show_images(1,0); // (y offset can change) + + cim_get_overlap(im1,im2,cimPXMs); // get overlap area v.11.04 + cim_get_redpix(im1); // get high-contrast pixels + + cim_align_image(im1,im2); // align im2 to im1 + + zfree(cimRedpix); // clear red pixels + cimRedpix = 0; + + if (cimScale == 1.0) break; // done + + R = STN_imageIncrease; // next larger image size + cimScale = cimScale * R; + if (cimScale > 0.85) { // if close to end, jump to end + R = R / cimScale; + cimScale = 1.0; + } + + cimOffs[im1].xf *= R; // scale offsets for larger image + cimOffs[im1].yf *= R; + cimOffs[im2].xf *= R; + cimOffs[im2].yf *= R; + + for (ii = 0; ii < 4; ii++) { + cimOffs[im1].wx[ii] *= R; + cimOffs[im1].wy[ii] *= R; + cimOffs[im2].wx[ii] *= R; + cimOffs[im2].wy[ii] *= R; + } + + cimSearchRange = STN_searchRange; // align search range + cimSearchStep = STN_searchStep; // align search step size + cimWarpRange = STN_warpRange; // align corner warp range + cimWarpStep = STN_warpStep; // align corner warp step size + } + } + + toff = cimOffs[0].tf; // balance +/- thetas + maxtf = mintf = toff; + for (imx = 1; imx < cimNF; imx++) { + toff = cimOffs[imx].tf; + if (toff > maxtf) maxtf = toff; + if (toff < mintf) mintf = toff; + } + midtf = 0.5 * (maxtf + mintf); + + for (imx = 0; imx < cimNF; imx++) + cimOffs[imx].tf -= midtf; + + for (im1 = 0; im1 < cimNF-1; im1++) // adjust x/y offsets for images after im1 + for (im2 = im1+1; im2 < cimNF; im2++) // due to im1 theta offset + { + toff = cimOffs[im1].tf; + xoff = cimOffs[im2].xf - cimOffs[im1].xf; + yoff = cimOffs[im2].yf - cimOffs[im1].yf; + dxoff = yoff * sin(toff); + dyoff = xoff * sin(toff); + cimOffs[im2].xf -= dxoff; + cimOffs[im2].yf += dyoff; + } + + Fzoom = Fblowup = 0; + Ffuncbusy--; + STN_stat = 1; + thread_exit(); + return 0; // not executed +} + + +// change pixel combination according to user input + +void STN_tweak() // v.10.9 +{ + zdialog *zd; + + int STN_tweak_dialog_event(zdialog *zd, cchar *event); + + // Adjust Pixel Composition + // + // (o) use average (o) use median + // [x] omit lowest value + // [x] omit highest value + + zd = zdialog_new(ZTX("Adjust Pixel Composition"),mWin,Bdone,Bcancel,null); + zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=3"); + zdialog_add_widget(zd,"radio","average","hb1","use average","space=3"); + zdialog_add_widget(zd,"radio","median","hb1","use median","space=3"); + zdialog_add_widget(zd,"hbox","hb2","dialog",0,"space=3"); + zdialog_add_widget(zd,"check","exlow","hb2","omit low pixel","space=3"); + zdialog_add_widget(zd,"check","exhigh","hb2","omit high pixel","space=3"); + + zdialog_stuff(zd,"average",1); // default = average + zdialog_stuff(zd,"median",0); + zdialog_stuff(zd,"exlow",0); + zdialog_stuff(zd,"exhigh",0); + + STN_average = 1; + STN_median = 0; + STN_exlow = 0; + STN_exhigh = 0; + + start_thread(STN_combine_thread,0); // start working thread + signal_thread(); + + zdialog_resize(zd,250,0); + zdialog_run(zd,STN_tweak_dialog_event,"-10/20"); // run dialog, parallel v.11.07 + zdialog_wait(zd); // wait for completion + + return; +} + + +// dialog event and completion callback function + +int STN_tweak_dialog_event(zdialog *zd, cchar *event) // v.10.9 +{ + if (zd->zstat) { // dialog finish + if (zd->zstat == 1) STN_stat = 1; + else STN_stat = 0; + wrapup_thread(8); + zdialog_free(zd); + if (STN_stat == 1) cim_trim(); // trim edges v.10.9 + } + + if (strEqu(event,"average")) { + zdialog_fetch(zd,"average",STN_average); + signal_thread(); + } + + if (strEqu(event,"median")) { + zdialog_fetch(zd,"median",STN_median); + signal_thread(); + } + + if (strEqu(event,"exlow")) { + zdialog_fetch(zd,"exlow",STN_exlow); + signal_thread(); + } + + if (strEqu(event,"exhigh")) { + zdialog_fetch(zd,"exhigh",STN_exhigh); + signal_thread(); + } + + return 1; +} + + +// compute mean/median mix for each output pixel and update E3 image + +void * STN_combine_thread(void *) // v.10.9 +{ + void * STN_combine_wthread(void *arg); // worker thread + + while (true) + { + thread_idle_loop(); // wait for work or exit request + + for (int ii = 0; ii < Nwt; ii++) // start worker threads + start_wthread(STN_combine_wthread,&wtnx[ii]); + wait_wthreads(); // wait for completion + + CEF->Fmod = 1; + mwpaint2(); // update window + } + + return 0; // not executed +} + + +// worker thread + +void * STN_combine_wthread(void *arg) // v.10.9 +{ + int index = *((int *) arg); + int imx, vstat, px3, py3; + int red, green, blue; + int ii, ns, ns1, ns2; + int Rlist[10], Glist[10], Blist[10]; + double px, py; + double xoff, yoff, sintf[10], costf[10]; + uint16 *pix3, vpix[3]; + + // input layers 0 1 2 3 4 5 6 7 8 9 10 + int nsx[11][2] = { {0,0}, {0,0}, {0,1}, {1,1}, {1,2}, {2,2}, {2,3}, {2,4}, {2,5}, {3,5}, {3,6} }; + + for (imx = 0; imx < cimNF; imx++) // pre-calculate trig funcs + { + sintf[imx] = sin(cimOffs[imx].tf); + costf[imx] = cos(cimOffs[imx].tf); + } + + for (py3 = index+1; py3 < E3hh-1; py3 += Nwt) // step through output pixels + for (px3 = 1; px3 < E3ww-1; px3++) + { + for (imx = ns = 0; imx < cimNF; imx++) // get aligned input pixels + { + xoff = cimOffs[imx].xf; + yoff = cimOffs[imx].yf; + px = costf[imx] * (px3 - xoff) + sintf[imx] * (py3 - yoff); + py = costf[imx] * (py3 - yoff) - sintf[imx] * (px3 - xoff); + + vstat = vpixel(cimPXMw[imx],px,py,vpix); + if (vstat) { + Rlist[ns] = vpix[0]; // add pixel RGB values to list + Glist[ns] = vpix[1]; + Blist[ns] = vpix[2]; + ns++; + } + } + + if (! ns) continue; + + if (STN_exlow || STN_exhigh || STN_median) { // RGB values must be sorted + HeapSort(Rlist,ns); + HeapSort(Glist,ns); + HeapSort(Blist,ns); + } + + red = green = blue = 0; + + if (STN_average) // average the input pixels + { + ns1 = 0; // low and high RGB values + ns2 = ns - 1; + + if (STN_exlow) { // exclude low + ns1++; + if (ns1 > ns2) ns1--; + } + + if (STN_exhigh) { // exclude high + ns2--; + if (ns1 > ns2) ns2++; + } + + for (ii = ns1; ii <= ns2; ii++) // sum remaining RGB levels + { + red += Rlist[ii]; + green += Glist[ii]; + blue += Blist[ii]; + } + + ns = ns2 - ns1 + 1; // sample count + + red = red / ns; // output RGB = average + green = green / ns; + blue = blue / ns; + } + + if (STN_median) // use median input pixels + { + ns1 = nsx[ns][0]; // middle group of pixels + ns2 = nsx[ns][1]; + + for (ii = ns1; ii <= ns2; ii++) + { + red += Rlist[ii]; + green += Glist[ii]; + blue += Blist[ii]; + } + + ns = ns2 - ns1 + 1; // sample count + + red = red / ns; // output RGB = average + green = green / ns; + blue = blue / ns; + } + + pix3 = PXMpix(E3pxm16,px3,py3); // output pixel + pix3[0] = red; + pix3[1] = green; + pix3[2] = blue; + } + + exit_wthread(); + return 0; // not executed +} + + +/************************************************************************** + + Panorama function: join 2, 3, or 4 images. + +***************************************************************************/ + +int panStat; // 1 = OK +zdialog *panozd = 0; // pre-align dialog + +double panPreAlignSize = 1000; // pre-align image size (ww) +double panInitAlignSize = 200; // initial align image size +double panImageIncrease = 1.6; // image size increase per align cycle +double panSampSize = 10000; // pixel sample size + +double panPreAlignBlend = 0.30; // pre-align blend width * ww +double panInitBlend = 0.20; // initial blend width during auto-align +double panFinalBlend = 0.08; // final blend width * ww +double panBlendDecrease = 0.8; // blend width reduction per align cycle + +double panInitSearchRange = 5.0; // initial search range, +/- pixels +double panInitSearchStep = 0.7; // initial search step, pixels +double panInitWarpRange = 4.0; // initial corner warp range, +/- pixels +double panInitWarpStep = 1.0; // initial corner warp step, pixels +double panSearchRange = 3.0; // normal search range, +/- pixels +double panSearchStep = 1.0; // normal search step, pixels +double panWarpRange = 2.0; // normal corner warp range, +/- pixels +double panWarpStep = 1.0; // normal corner warp step, pixels + +void pano_prealign(); // manual pre-align +void pano_align(); // auto fine-align +void pano_tweak(); // user color tweak + +editfunc EFpano; // edit function data + + +// menu function + +void m_pano(GtkWidget *, cchar *) // v.10.7 +{ + int imx, err; + char **flist = 0; + + zfuncs::F1_help_topic = "panorama"; // help topic + + if (mod_keep()) return; // warn unsaved changes + if (! menulock(1)) return; // test menu lock v.11.07 + menulock(0); + + for (imx = 0; imx < 10; imx++) + { // clear all file and PXM data + cimFile[imx] = 0; + cimPXMf[imx] = cimPXMs[imx] = cimPXMw[imx] = 0; + } + cimNF = 0; + + flist = zgetfileN(ZTX("Select 2 to 4 files"),"openN",curr_file); // select images to combine + if (! flist) return; + + for (imx = 0; flist[imx]; imx++); // count selected files + if (imx < 2 || imx > 4) { + zmessageACK(mWin,ZTX("Select 2 to 4 files")); + goto cleanup; + } + + cimNF = imx; // file count + for (imx = 0; imx < cimNF; imx++) + cimFile[imx] = strdupz(flist[imx],0,"pano"); // set up file list + + if (! cim_load_files()) goto cleanup; // load and check all files + + free_resources(); // ready to commit + + err = f_open(cimFile[0],0); // curr_file = 1st file in list + if (err) goto cleanup; + + EFpano.funcname = "pano"; + if (! edit_setup(EFpano)) goto cleanup; // setup edit (will lock) + + cimShowAll = 1; // for cim_show_images(), show all v.10.9 + cimShrink = 0; // no warp shrinkage v.11.04 + cimPano = 1; // horizontal pano mode v.11.04 + cimPanoV = 0; + + pano_prealign(); // manual pre-alignment + if (panStat != 1) goto cancel; + + pano_align(); // auto full alignment + if (panStat != 1) goto cancel; + + pano_tweak(); // manual color adjustment + if (panStat != 1) goto cancel; + + CEF->Fmod = 1; // done + edit_done(EFpano); + goto cleanup; + +cancel: // failed or canceled + edit_cancel(EFpano); + +cleanup: + + if (flist) { + for (imx = 0; flist[imx]; imx++) // free file list + zfree(flist[imx]); + zfree(flist); + } + + for (imx = 0; imx < cimNF; imx++) { // free cim file and PXM data + if (cimFile[imx]) zfree(cimFile[imx]); + if (cimPXMf[imx]) PXM_free(cimPXMf[imx]); + if (cimPXMs[imx]) PXM_free(cimPXMs[imx]); + if (cimPXMw[imx]) PXM_free(cimPXMw[imx]); + } + + *SB_text = 0; + return; +} + + +// perform manual pre-align of all images +// returns alignment data in cimOffs[*] +// lens_mm and lens_bow may also be altered + +void pano_prealign() // v.10.7 +{ + int pano_prealign_event(zdialog *zd, cchar *event); // dialog event function + void * pano_prealign_thread(void *); // working thread + + int imx, ww, err = 0; + cchar *exifkey = { exif_focal_length_key }; + cchar *lensource; + char **pp = 0; + + cchar *align_mess = ZTX("Drag images into rough alignment.\n" + "To rotate, drag from lower edge."); + cchar *search_mess = ZTX("Search for lens mm and bow"); + + lens_bow = lens_settings[1]; // no EXIF for this v.12.01 + + pp = info_get(curr_file,&exifkey,1); // get lens mm from EXIF if available + if (pp && *pp) { + err = convSD(*pp, lens_mm, 20, 1000); + lensource = "(EXIF)"; // lens mm from EXIF + } + + if (! pp || ! *pp || err) { // not available + lens_mm = lens_settings[0]; // v.12.01 + lensource = "(settings)"; // lens mm from user settings + } + + for (imx = 0; imx < 10; imx++) // set all alignment offsets = 0 + memset(&cimOffs[imx],0,sizeof(cimoffs)); + + for (imx = ww = 0; imx < cimNF; imx++) // sum image widths + ww += cimPXMf[imx]->ww; + + cimScale = 1.4 * panPreAlignSize / ww; // set alignment image scale + if (cimScale > 1.0) cimScale = 1.0; // (* 0.7 after overlaps) + + for (imx = 0; imx < cimNF; imx++) // scale images > cimPXMs[*] + cim_scale_image(imx,cimPXMs); + + for (imx = 0; imx < cimNF; imx++) { // curve images, cimPXMs[*] replaced + cim_curve_image(imx); + cimPXMw[imx] = PXM_copy(cimPXMs[imx]); // copy to cimPXMw[*] for display + } + + cimOffs[0].xf = cimOffs[0].yf = 0; // first image at (0,0) + + for (imx = 1; imx < cimNF; imx++) // position images with 30% overlap + { // in horizontal row + cimOffs[imx].xf = cimOffs[imx-1].xf + 0.7 * cimPXMw[imx-1]->ww; + cimOffs[imx].yf = cimOffs[imx-1].yf; + } + + Fzoom = 0; // scale image to fit window + Fblowup = 1; // magnify small image to window size + + cimBlend = panPreAlignBlend * cimPXMw[1]->ww; // overlap in align window + cim_show_images(1,0); // combine and show images in main window + + panozd = zdialog_new(ZTX("Pre-align Images"),mWin,Bproceed,Bcancel,null); // start pre-align dialog + zdialog_add_widget(panozd,"label","lab1","dialog",align_mess,"space=5"); + zdialog_add_widget(panozd,"hbox","hb1","dialog",0,"space=2"); + zdialog_add_widget(panozd,"spin","spmm","hb1","20|999|0.1|35","space=5"); // [ 35 ] lens mm (source) + zdialog_add_widget(panozd,"label","labmm","hb1",ZTX("lens mm")); // [ 0.3 ] lens bow + zdialog_add_widget(panozd,"label","labsorc","hb1","","space=5"); // [resize] resize window + zdialog_add_widget(panozd,"hbox","hb2","dialog",0,"space=2"); // [search] search lens mm and bow + zdialog_add_widget(panozd,"spin","spbow","hb2","-9|9|0.01|0","space=5"); + zdialog_add_widget(panozd,"label","labbow","hb2",ZTX("lens bow")); + zdialog_add_widget(panozd,"hbox","hb3","dialog",0,"space=2"); + zdialog_add_widget(panozd,"button","resize","hb3",ZTX("Resize"),"space=5"); + zdialog_add_widget(panozd,"label","labsiz","hb3",ZTX("resize window"),"space=5"); + zdialog_add_widget(panozd,"hbox","hb4","dialog",0,"space=2"); + zdialog_add_widget(panozd,"button","search","hb4",Bsearch,"space=5"); + zdialog_add_widget(panozd,"label","labsearch","hb4",search_mess,"space=5"); + + zdialog_stuff(panozd,"spmm",lens_mm); // stuff lens data + zdialog_stuff(panozd,"spbow",lens_bow); + zdialog_stuff(panozd,"labsorc",lensource); // show source of lens data + + panStat = -1; // busy status + gdk_window_set_cursor(drWin->window,dragcursor); // set drag cursor v.11.03 + zdialog_run(panozd,pano_prealign_event,"-10/20"); // start dialog v.11.07 + start_thread(pano_prealign_thread,0); // start working thread + zdialog_wait(panozd); // wait for dialog completion + gdk_window_set_cursor(drWin->window,0); // restore normal cursor v.11.03 + Fzoom = Fblowup = 0; + return; +} + + +// pre-align dialog event function + +int pano_prealign_event(zdialog *zd, cchar *event) // v.10.7 +{ + int imx; + double overlap; + + if (strstr("spmm spbow",event)) { + zdialog_fetch(zd,"spmm",lens_mm); // get revised lens data + zdialog_fetch(zd,"spbow",lens_bow); + } + + if (strEqu(event,"resize")) // allocate new E3 image + cim_show_images(1,0); + + if (strEqu(event,"search")) { // search for optimal lens parms + if (cimNF != 2) + zmessageACK(mWin,ZTX("use two images only")); + else panStat = 2; // tell thread to search + return 0; + } + + if (zd->zstat) // dialog complete + { + if (zd->zstat == 1) // proceed + panStat = 1; + else // cancel or other + panStat = 0; + + zdialog_free(panozd); // kill dialog + wrapup_thread(0); // wait for thread + + if (! panStat) return 0; // canceled + + for (imx = 0; imx < cimNF-1; imx++) // check for enough overlap + { + overlap = cim_get_overlap(imx,imx+1,cimPXMs); // v.11.04 + if (overlap < panFinalBlend) { // v.11.09 + zmessageACK(mWin,ZTX("Too little overlap, cannot align")); + panStat = 0; + return 0; + } + } + } + + return 0; +} + + +// pre-align working thread +// convert mouse and KB events into image movements // overhauled v.11.02 + +void * pano_prealign_thread(void *) +{ + void pano_autolens(); + + cimoffs offstemp; + PXM *pxmtemp; + char *ftemp; + int im1, im2, imm, imx; + int mx0, my0, mx, my; // mouse drag origin, position + int xoff, yoff, lox, hix; + int sepx, minsep; + int ww, hh, rotate, midx; + double lens_mm0, lens_bow0; + double dx, dy, t1, t2, dt; + + imm = ww = hh = rotate = xoff = yoff = 0; // stop compiler warnings + + lens_mm0 = lens_mm; // to detect changes + lens_bow0 = lens_bow; + + mx0 = my0 = 0; // no drag in progress + Mcapture = KBcapture = 1; // capture mouse drag and KB keys + + cimBlend = 0; // full blend during pre-align + + while (true) // loop and align until done + { + zsleep(0.05); // logic simplified + + if (panStat == 2) { // dialog search button + panStat = -1; // back to busy status + pano_autolens(); + } + + if (panStat != -1) break; // quit signal from dialog + + if (lens_mm != lens_mm0 || lens_bow != lens_bow0) { // change in lens parameters + lens_mm0 = lens_mm; + lens_bow0 = lens_bow; + + for (imx = 0; imx < cimNF; imx++) { // re-curve images + cim_scale_image(imx,cimPXMs); + cim_curve_image(imx); + PXM_free(cimPXMw[imx]); + cimPXMw[imx] = PXM_copy(cimPXMs[imx]); + } + + cim_show_images(1,0); // combine and show images + continue; + } + + if (KBkey) { // KB input + if (KBkey == GDK_Left) cimOffs[imm].xf -= 0.5; // tweak alignment offsets + if (KBkey == GDK_Right) cimOffs[imm].xf += 0.5; + if (KBkey == GDK_Up) cimOffs[imm].yf -= 0.5; + if (KBkey == GDK_Down) cimOffs[imm].yf += 0.5; + if (KBkey == GDK_r) cimOffs[imm].tf += 0.0005; + if (KBkey == GDK_l) cimOffs[imm].tf -= 0.0005; + KBkey = 0; + + cim_show_images(0,0); // combine and show images + continue; + } + + if (! Mxdrag && ! Mydrag) // no drag underway + mx0 = my0 = 0; // reset drag origin + + if (Mxdrag || Mydrag) // mouse drag underway + { + mx = Mxdrag; // mouse position in image + my = Mydrag; + + if (! mx0 && ! my0) // new drag + { + mx0 = mx; // set drag origin + my0 = my; + minsep = 9999; + + for (imx = 0; imx < cimNF; imx++) // find image with midpoint + { // closest to mouse x + lox = cimOffs[imx].xf; + hix = lox + cimPXMw[imx]->ww; + midx = (lox + hix) / 2; + sepx = abs(midx - mx0); + if (sepx < minsep) { + minsep = sepx; + imm = imx; // image to drag or rotate + } + } + + xoff = cimOffs[imm].xf; + yoff = cimOffs[imm].yf; + ww = cimPXMw[imm]->ww; + hh = cimPXMw[imm]->hh; + + rotate = 0; // if drag at bottom edge, + if (my0 > yoff + 0.85 * hh) rotate = 1; // set rotate flag v.11.04 + } + + if (mx != mx0 || my != my0) // drag is progressing + { + dx = mx - mx0; // mouse movement + dy = my - my0; + + if (rotate && my0 > yoff && my > yoff) // rotation + { + if (imm > 0) { + lox = cimOffs[imm].xf; // if there is an image to the left, + hix = cimOffs[imm-1].xf + cimPXMw[imm-1]->ww; // midx = midpoint of overlap + midx = (lox + hix) / 2; + } + else midx = 0; // this is the leftmost image + + t1 = atan(1.0 * (mx0-xoff) / (my0-yoff)); + t2 = atan(1.0 * (mx-xoff) / (my-yoff)); + dt = t1 - t2; // angle change + dx = dt * (hh/2 + yoff); // pivot = middle of overlap on left + dy = -dt * (midx-xoff); + } + + else dt = 0; // x/y drag + + cimOffs[imm].xf += dx; // update image + cimOffs[imm].yf += dy; + cimOffs[imm].tf += dt; + xoff = cimOffs[imm].xf; // v.11.04 + yoff = cimOffs[imm].yf; + + cim_show_images(0,0); // show combined images + + mx0 = mx; // next drag origin = current mouse + my0 = my; + } + } + + for (im1 = 0; im1 < cimNF-1; im1++) // track image order changes + { + im2 = im1 + 1; + if (cimOffs[im2].xf < cimOffs[im1].xf) + { + ftemp = cimFile[im2]; // switch filespecs + cimFile[im2] = cimFile[im1]; + cimFile[im1] = ftemp; + pxmtemp = cimPXMf[im2]; // switch images + cimPXMf[im2] = cimPXMf[im1]; + cimPXMf[im1] = pxmtemp; + pxmtemp = cimPXMs[im2]; // scaled images + cimPXMs[im2] = cimPXMs[im1]; + cimPXMs[im1] = pxmtemp; + pxmtemp = cimPXMw[im2]; // warped images + cimPXMw[im2] = cimPXMw[im1]; + cimPXMw[im1] = pxmtemp; + offstemp = cimOffs[im2]; // offsets + cimOffs[im2] = cimOffs[im1]; + cimOffs[im1] = offstemp; + if (imm == im1) imm = im2; // current drag image + else if (imm == im2) imm = im1; + break; + } + } + } + + KBcapture = Mcapture = 0; + thread_exit(); + return 0; // not executed, stop g++ warning +} + + +// optimize lens parameters +// inputs and outputs: +// pre-aligned images cimPXMw[0] and [1] +// offsets in cimOffs[0] and [1] +// lens_mm, lens_bow + +void pano_autolens() // v.10.7 +{ + double mm_range, bow_range, xf_range, yf_range, tf_range; + double squeeze, xf_rfinal, rnum, matchB, matchlev; + double overlap, lens_mmB, lens_bowB; + int imx, randcount = 0; + cimoffs offsetsB; + + overlap = cim_get_overlap(0,1,cimPXMs); // v.11.04 + if (overlap < 0.1) { + threadmessage = ZTX("Too little overlap, cannot align"); + return; + } + + Ffuncbusy++; // v.11.01 + + cimSampSize = 2000; // v.11.03 + cimNsearch = 0; + + mm_range = 0.1 * lens_mm; // set initial search ranges v.11.03 + bow_range = 0.3 * lens_bow; + if (bow_range < 0.5) bow_range = 0.5; + xf_range = 7; + yf_range = 7; + tf_range = 0.01; + xf_rfinal = 0.3; // final xf range - when to quit + + cim_match_colors(0,1,cimPXMw); // adjust colors for image matching + cim_adjust_colors(cimPXMs[0],1); + cim_adjust_colors(cimPXMw[0],1); + cim_adjust_colors(cimPXMs[1],2); + cim_adjust_colors(cimPXMw[1],2); + + lens_mmB = lens_mm; // starting point + lens_bowB = lens_bow; + offsetsB = cimOffs[1]; + cimSearchRange = 7; + + matchB = 0; + + while (true) + { + srand48(time(0) + randcount++); + lens_mm = lens_mmB + mm_range * (drand48() - 0.5); // new random lens factors + lens_bow = lens_bowB + bow_range * (drand48() - 0.5); // within search range + + for (imx = 0; imx <= 1; imx++) { // re-curve images + cim_scale_image(imx,cimPXMs); + cim_curve_image(imx); + PXM_free(cimPXMw[imx]); + cimPXMw[imx] = PXM_copy(cimPXMs[imx]); + } + + cim_get_redpix(0); // get high-contrast pixels v.11.03 + cim_show_images(0,0); // combine and show images + + squeeze = 0.97; // search range reduction v.10.7 + + for (int ii = 0; ii < 1000; ii++) // loop random x/y/t alignments + { + rnum = drand48(); + if (rnum < 0.33) // random change some alignment offset + cimOffs[1].xf = offsetsB.xf + xf_range * (drand48() - 0.5); + else if (rnum < 0.67) + cimOffs[1].yf = offsetsB.yf + yf_range * (drand48() - 0.5); + else + cimOffs[1].tf = offsetsB.tf + tf_range * (drand48() - 0.5); + + matchlev = cim_match_images(0,1); // test quality of image alignment + + sprintf(SB_text,"align: %d match: %.5f lens: %.1f %.2f", // update status bar + ++cimNsearch, matchB, lens_mmB, lens_bowB); + zmainloop(); // v.11.11.1 + + if (sigdiff(matchlev,matchB,0.00001) > 0) { + matchB = matchlev; // save new best fit + lens_mmB = lens_mm; // alignment is better + lens_bowB = lens_bow; + offsetsB = cimOffs[1]; + cim_show_images(0,0); + squeeze = 1; // keep same search range as long + break; // as improvements are found + } + + if (panStat != -1) goto done; // user kill + } + + if (xf_range < xf_rfinal) goto done; // finished + + sprintf(SB_text,"align: %d match: %.5f lens: %.1f %.2f", // update status bar + cimNsearch, matchB, lens_mmB, lens_bowB); + zmainloop(); // v.11.11.1 + + mm_range = squeeze * mm_range; // reduce search range if no + if (mm_range < 0.02 * lens_mmB) mm_range = 0.02 * lens_mmB; // improvements were found + bow_range = squeeze * bow_range; + if (bow_range < 0.1 * lens_bowB) bow_range = 0.1 * lens_bowB; + if (bow_range < 0.2) bow_range = 0.2; + xf_range = squeeze * xf_range; + yf_range = squeeze * yf_range; + tf_range = squeeze * tf_range; + } + +done: + zfree(cimRedpix); + cimRedpix = 0; + + lens_mm = lens_mmB; // save best lens params found + lens_bow = lens_bowB; + if (panStat == -1 && panozd) { // unless killed + zdialog_stuff(panozd,"spmm",lens_mm); + zdialog_stuff(panozd,"spbow",lens_bow); + } + + cimSampSize = panSampSize; // restore + Ffuncbusy--; + cim_show_images(1,0); // images are left color-matched + return; +} + + +// fine-alignment +// start with very small image size +// search around offset values for best match +// increase image size and loop until full-size + +void pano_align() // v.10.7 +{ + int imx, im1, im2, ww; + double R, dx, dy, dt; + double overlap; + cimoffs offsets0; + + Fzoom = 0; // scale E3 to fit window + Fblowup = 1; // magnify small image to window size + Ffuncbusy++; // v.11.01 + + for (imx = 0; imx < cimNF; imx++) { + cimOffs[imx].xf = cimOffs[imx].xf / cimScale; // scale x/y offsets for full-size images + cimOffs[imx].yf = cimOffs[imx].yf / cimScale; + } + + cimScale = 1.0; // full-size + + for (imx = 0; imx < cimNF; imx++) { + PXM_free(cimPXMs[imx]); + cimPXMs[imx] = PXM_copy(cimPXMf[imx]); // copy full-size images + cim_curve_image(imx); // curve them + } + + cimBlend = 0.3 * cimPXMs[0]->ww; + cim_get_overlap(0,1,cimPXMs); // match images 0 & 1 in overlap area + cim_match_colors(0,1,cimPXMs); + cim_adjust_colors(cimPXMf[0],1); // image 0 << profile 1 + cim_adjust_colors(cimPXMf[1],2); // image 1 << profile 2 + + if (cimNF > 2) { + cimBlend = 0.3 * cimPXMs[1]->ww; + cim_get_overlap(1,2,cimPXMs); + cim_match_colors(1,2,cimPXMs); + cim_adjust_colors(cimPXMf[0],1); + cim_adjust_colors(cimPXMf[1],1); + cim_adjust_colors(cimPXMf[2],2); + } + + if (cimNF > 3) { + cimBlend = 0.3 * cimPXMs[2]->ww; + cim_get_overlap(2,3,cimPXMs); + cim_match_colors(2,3,cimPXMs); + cim_adjust_colors(cimPXMf[0],1); + cim_adjust_colors(cimPXMf[1],1); + cim_adjust_colors(cimPXMf[2],1); + cim_adjust_colors(cimPXMf[3],2); + } + + cimScale = panInitAlignSize / cimPXMf[1]->hh; // initial align image scale + if (cimScale > 1.0) cimScale = 1.0; + + for (imx = 0; imx < cimNF; imx++) { // scale offsets for image scale + cimOffs[imx].xf = cimOffs[imx].xf * cimScale; + cimOffs[imx].yf = cimOffs[imx].yf * cimScale; + } + + cimSearchRange = panInitSearchRange; // initial align search range + cimSearchStep = panInitSearchStep; // initial align search step + cimWarpRange = panInitWarpRange; // initial align corner warp range + cimWarpStep = panInitWarpStep; // initial align corner warp step + ww = cimPXMf[0]->ww * cimScale; // initial align image width + cimBlend = ww * panInitBlend; // initial align blend width + cimSampSize = panSampSize; // pixel sample size for align/compare + cimNsearch = 0; // reset align search counter + + while (true) // loop, increasing image size + { + for (imx = 0; imx < cimNF; imx++) { // prepare images + cim_scale_image(imx,cimPXMs); // scale to new size + cim_curve_image(imx); // curve based on lens params + cim_warp_image_pano(imx,1); // apply corner warps + } + + cim_show_images(1,0); // show with 50/50 blend in overlaps + + for (im1 = 0; im1 < cimNF-1; im1++) // fine-align each image with left neighbor + { + im2 = im1 + 1; + + offsets0 = cimOffs[im2]; // save initial alignment offsets + overlap = cim_get_overlap(im1,im2,cimPXMs); // get overlap area v.11.04 + if (overlap < panFinalBlend-2) { + zmessageACK(mWin,ZTX("Too little overlap, cannot align")); // v.11.03 + goto fail; + } + cim_get_redpix(im1); // get high-contrast pixels + + cim_align_image(im1,im2); // search for best offsets and warps + + zfree(cimRedpix); // clear red pixels + cimRedpix = 0; + + dx = cimOffs[im2].xf - offsets0.xf; // changes from initial offsets + dy = cimOffs[im2].yf - offsets0.yf; + dt = cimOffs[im2].tf - offsets0.tf; + + for (imx = im2+1; imx < cimNF; imx++) // propagate to following images + { + cimOffs[imx].xf += dx; + cimOffs[imx].yf += dy; + cimOffs[imx].tf += dt; + ww = cimOffs[imx].xf - cimOffs[im2].xf; + cimOffs[imx].yf += ww * dt; + } + } + + if (cimScale == 1.0) goto success; // done + + R = panImageIncrease; // next larger image size + cimScale = cimScale * R; + if (cimScale > 0.85) { // if close to end, jump to end + R = R / cimScale; + cimScale = 1.0; + } + + for (imx = 0; imx < cimNF; imx++) // scale offsets for new size + { + cimOffs[imx].xf *= R; + cimOffs[imx].yf *= R; + + for (int ii = 0; ii < 4; ii++) { + cimOffs[imx].wx[ii] *= R; + cimOffs[imx].wy[ii] *= R; + } + } + + cimSearchRange = panSearchRange; // align search range + cimSearchStep = panSearchStep; // align search step size + cimWarpRange = panWarpRange; // align corner warp range + cimWarpStep = panWarpStep; // align corner warp step size + + cimBlend = cimBlend * panBlendDecrease * R; // blend width, reduced + ww = cimPXMf[0]->ww * cimScale; + if (cimBlend < panFinalBlend * ww) + cimBlend = panFinalBlend * ww; // stay above minimum + } + +success: + panStat = 1; + goto align_done; +fail: + panStat = 0; +align_done: + cimBlend = 1; // tiny blend (increase in tweak if wanted) + Fzoom = Fblowup = 0; + Ffuncbusy--; + cim_show_images(0,0); + return; +} + + +// get user inputs for RGB changes and blend width, update cimPXMw[*] + +void pano_tweak() // v.10.7 +{ + int pano_tweak_event(zdialog *zd, cchar *event); // dialog event function + + cchar *tweaktitle = ZTX("Match Brightness and Color"); + char imageN[8] = "imageN"; + int imx; + + cimBlend = 1; // init. blend width + + panozd = zdialog_new(tweaktitle,mWin,Bdone,Bcancel,null); + + zdialog_add_widget(panozd,"hbox","hbim","dialog",0,"space=5"); + zdialog_add_widget(panozd,"label","labim","hbim",ZTX("image"),"space=5"); // image (o) (o) (o) (o) + zdialog_add_widget(panozd,"hbox","hbc1","dialog",0,"homog"); // + zdialog_add_widget(panozd,"label","labred","hbc1",Bred); // red green blue + zdialog_add_widget(panozd,"label","labgreen","hbc1",Bgreen); // [_____] [_____] [_____] + zdialog_add_widget(panozd,"label","labblue","hbc1",Bblue); // + zdialog_add_widget(panozd,"hbox","hbc2","dialog",0,"homog"); // brightness [___] [apply] + zdialog_add_widget(panozd,"spin","red","hbc2","50|200|0.1|100","space=5"); // + zdialog_add_widget(panozd,"spin","green","hbc2","50|200|0.1|100","space=5"); // -------------------------- + zdialog_add_widget(panozd,"spin","blue","hbc2","50|200|0.1|100","space=5"); // + zdialog_add_widget(panozd,"hbox","hbbri","dialog",0,"space=5"); // [auto color] [file color] + zdialog_add_widget(panozd,"label","labbr","hbbri",Bbrightness,"space=5"); // + zdialog_add_widget(panozd,"spin","bright","hbbri","50|200|0.1|100"); // -------------------------- + zdialog_add_widget(panozd,"button","brapp","hbbri",Bapply,"space=10"); // + zdialog_add_widget(panozd,"hsep","hsep","dialog",0,"space=5"); // blend width [___] [apply] + zdialog_add_widget(panozd,"hbox","hbc3","dialog",0,"space=5"); // + zdialog_add_widget(panozd,"button","auto","hbc3",ZTX("auto color"),"space=5"); // [done] [cancel] + zdialog_add_widget(panozd,"button","file","hbc3",ZTX("file color"),"space=5"); + zdialog_add_widget(panozd,"hsep","hsep","dialog",0,"space=5"); + zdialog_add_widget(panozd,"hbox","hbblen","dialog",0); + zdialog_add_widget(panozd,"label","labbl","hbblen",Bblendwidth,"space=5"); + zdialog_add_widget(panozd,"spin","blend","hbblen","1|300|1|1"); + zdialog_add_widget(panozd,"button","blapp","hbblen",Bapply,"space=15"); + + for (imx = 0; imx < cimNF; imx++) { // add radio button per image + imageN[5] = '0' + imx; + zdialog_add_widget(panozd,"radio",imageN,"hbim",0,"space=5"); + } + + zdialog_stuff(panozd,"image0",1); // pre-select 1st image + zdialog_resize(panozd,300,0); + + panStat = -1; // busy status + zdialog_run(panozd,pano_tweak_event,"-10/20"); // run dialog, parallel v.11.07 + zdialog_wait(panozd); // wait for dialog completion + return; +} + + +// dialog event function + +int pano_tweak_event(zdialog *zd, cchar *event) // v.10.7 +{ + char imageN[8] = "imageN"; + double red, green, blue, bright, bright2; + double red1, green1, blue1; + int nn, im0, imx, im1, im2, ww, hh, px, py; + uint16 *pixel; + + if (zd->zstat) // dialog complete + { + if (zd->zstat == 1) panStat = 1; // done + if (zd->zstat == 2) panStat = 0; // cancel + zdialog_free(panozd); // kill dialog + return 0; + } + + for (im0 = 0; im0 < cimNF; im0++) { // get which image is selected + imageN[5] = '0' + im0; // by the radio buttons + zdialog_fetch(zd,imageN,nn); + if (nn) break; + } + if (im0 == cimNF) return 1; + + zdialog_fetch(zd,"red",red); // get color adjustments + zdialog_fetch(zd,"green",green); + zdialog_fetch(zd,"blue",blue); + zdialog_fetch(zd,"bright",bright); // brightness adjustment + + bright2 = (red + green + blue) / 3; // RGB brightness + bright = bright / bright2; // bright setpoint / RGB brightness + red = red * bright; // adjust RGB brightness + green = green * bright; + blue = blue * bright; + + bright = (red + green + blue) / 3; + zdialog_stuff(zd,"red",red); // force back into consistency + zdialog_stuff(zd,"green",green); + zdialog_stuff(zd,"blue",blue); + zdialog_stuff(zd,"bright",bright); + + if (strEqu(event,"brapp")) // apply color & brightness changes + { + red = red / 100; // normalize 0.5 ... 2.0 + green = green / 100; + blue = blue / 100; + + cim_warp_image_pano(im0,0); // refresh cimPXMw from cimPXMs + + ww = cimPXMw[im0]->ww; + hh = cimPXMw[im0]->hh; + + for (py = 0; py < hh; py++) // loop all image pixels + for (px = 0; px < ww; px++) + { + pixel = PXMpix(cimPXMw[im0],px,py); + red1 = red * pixel[0]; // apply color factors + green1 = green * pixel[1]; + blue1 = blue * pixel[2]; + if (! blue1) continue; + + if (red1 > 65535 || green1 > 65535 || blue1 > 65535) { + bright = red1; // avoid overflow + if (green1 > bright) bright = green1; + if (blue1 > bright) bright = blue1; + bright = 65535.0 / bright; + red1 = red1 * bright; + green1 = green1 * bright; + blue1 = blue1 * bright; + } + + if (blue1 < 1) blue1 = 1; // avoid 0 v.10.7 + + pixel[0] = red1; + pixel[1] = green1; + pixel[2] = blue1; + } + + cimBlend = 1; + zdialog_stuff(zd,"blend",cimBlend); // v.11.04 + cim_show_images(0,0); // combine and show with 50/50 blend + } + + if (strEqu(event,"auto")) // auto match color of selected image + { + for (im1 = im0; im1 < cimNF-1; im1++) // from selected image to last image + { + im2 = im1 + 1; + cimBlend = 0.3 * cimPXMw[im2]->ww; + cim_get_overlap(im1,im2,cimPXMw); // match images in overlap area + cim_match_colors(im1,im2,cimPXMw); + cim_adjust_colors(cimPXMw[im1],1); // image im1 << profile 1 + cim_adjust_colors(cimPXMw[im2],2); // image im2 << profile 2 + for (imx = im1-1; imx >= im0; imx--) + cim_adjust_colors(cimPXMw[imx],1); + cimBlend = 1; + zdialog_stuff(zd,"blend",cimBlend); // v.11.04 + cim_show_images(0,0); + } + + for (im1 = im0-1; im1 >= 0; im1--) // from selected image to 1st image + { + im2 = im1 + 1; + cimBlend = 0.3 * cimPXMw[im2]->ww; + cim_get_overlap(im1,im2,cimPXMw); // match images in overlap area + cim_match_colors(im1,im2,cimPXMw); + cim_adjust_colors(cimPXMw[im1],1); // image im1 << profile 1 + cim_adjust_colors(cimPXMw[im2],2); // image im2 << profile 2 + for (imx = im2+1; imx < cimNF; imx++) + cim_adjust_colors(cimPXMw[imx],2); + cimBlend = 1; + zdialog_stuff(zd,"blend",cimBlend); // v.11.04 + cim_show_images(0,0); + } + } + + if (strEqu(event,"file")) // use original file colors + { + if (! cim_load_files()) return 1; + + for (imx = 0; imx < cimNF; imx++) { + PXM_free(cimPXMs[imx]); + cimPXMs[imx] = PXM_copy(cimPXMf[imx]); + cim_curve_image(imx); // curve and warp + cim_warp_image_pano(imx,0); + } + + cimBlend = 1; + zdialog_stuff(zd,"blend",cimBlend); // v.11.04 + cim_show_images(0,0); + } + + if (strEqu(event,"blapp")) // apply new blend width + { + zdialog_fetch(zd,"blend",cimBlend); // can be zero + cim_show_images(0,1); // show with gradual blend + } + + return 1; +} + + +/************************************************************************** + + Vertical Panorama function: join 2, 3, or 4 images. + +***************************************************************************/ + +void vpano_prealign(); // manual pre-align +void vpano_align(); // auto fine-align +void vpano_tweak(); // user color tweak + +editfunc EFvpano; // edit function data + + +// menu function + +void m_vpano(GtkWidget *, cchar *) // v.11.04 +{ + int imx, err; + char **flist = 0; + + zfuncs::F1_help_topic = "panorama"; // help topic + + if (mod_keep()) return; // warn unsaved changes + if (! menulock(1)) return; // test menu lock v.11.07 + menulock(0); + + for (imx = 0; imx < 10; imx++) + { // clear all file and PXM data + cimFile[imx] = 0; + cimPXMf[imx] = cimPXMs[imx] = cimPXMw[imx] = 0; + } + cimNF = 0; + + flist = zgetfileN(ZTX("Select 2 to 4 files"),"openN",curr_file); // select images to combine + if (! flist) return; + + for (imx = 0; flist[imx]; imx++); // count selected files + if (imx < 2 || imx > 4) { + zmessageACK(mWin,ZTX("Select 2 to 4 files")); + goto cleanup; + } + + cimNF = imx; // file count + for (imx = 0; imx < cimNF; imx++) + cimFile[imx] = strdupz(flist[imx],0,"pano"); // set up file list + + if (! cim_load_files()) goto cleanup; // load and check all files + + free_resources(); // ready to commit + + err = f_open(cimFile[0],0); // curr_file = 1st file in list + if (err) goto cleanup; + + EFvpano.funcname = "vpano"; + if (! edit_setup(EFvpano)) goto cleanup; // setup edit (will lock) + + cimShowAll = 1; // for cim_show_images(), show all + cimShrink = 0; // no warp shrinkage v.11.04 + cimPano = 0; // vertical pano mode v.11.04 + cimPanoV = 1; + + vpano_prealign(); // manual pre-alignment + if (panStat != 1) goto cancel; + + vpano_align(); // auto full alignment + if (panStat != 1) goto cancel; + + vpano_tweak(); // manual color adjustment + if (panStat != 1) goto cancel; + + CEF->Fmod = 1; // done + edit_done(EFvpano); + goto cleanup; + +cancel: // failed or canceled + edit_cancel(EFvpano); + +cleanup: + + if (flist) { + for (imx = 0; flist[imx]; imx++) // free file list + zfree(flist[imx]); + zfree(flist); + } + + for (imx = 0; imx < cimNF; imx++) { // free cim file and PXM data + if (cimFile[imx]) zfree(cimFile[imx]); + if (cimPXMf[imx]) PXM_free(cimPXMf[imx]); + if (cimPXMs[imx]) PXM_free(cimPXMs[imx]); + if (cimPXMw[imx]) PXM_free(cimPXMw[imx]); + } + + *SB_text = 0; + return; +} + + +// perform manual pre-align of all images +// returns alignment data in cimOffs[*] +// lens_mm and lens_bow may also be altered + +void vpano_prealign() +{ + int vpano_prealign_event(zdialog *zd, cchar *event); // dialog event function + void * vpano_prealign_thread(void *); // working thread + + int imx, hh, err = 0; + cchar *exifkey = { exif_focal_length_key }; + cchar *lensource; + char **pp = 0; + + cchar *align_mess = ZTX("Drag images into rough alignment.\n" + "To rotate, drag from right edge."); + + lens_bow = lens_settings[1]; // no EXIF for this + + pp = info_get(curr_file,&exifkey,1); // get lens mm from EXIF if available + if (pp && *pp) { + err = convSD(*pp, lens_mm, 20, 1000); + lensource = "(EXIF)"; // lens mm from EXIF + } + + if (! pp || ! *pp || err) { // not available + lens_mm = lens_settings[0]; + lensource = "(settings)"; // lens mm from user settings + } + + for (imx = 0; imx < 10; imx++) // set all alignment offsets = 0 + memset(&cimOffs[imx],0,sizeof(cimoffs)); + + for (imx = hh = 0; imx < cimNF; imx++) // sum image heights + hh += cimPXMf[imx]->hh; + + cimScale = 1.4 * panPreAlignSize / hh; // set alignment image scale + if (cimScale > 1.0) cimScale = 1.0; // (* 0.7 after overlaps) + + for (imx = 0; imx < cimNF; imx++) // scale images > cimPXMs[*] + cim_scale_image(imx,cimPXMs); + + for (imx = 0; imx < cimNF; imx++) { // curve images, cimPXMs[*] replaced + cim_curve_Vimage(imx); + cimPXMw[imx] = PXM_copy(cimPXMs[imx]); // copy to cimPXMw[*] for display + } + + cimOffs[0].xf = cimOffs[0].yf = 0; // first image at (0,0) + + for (imx = 1; imx < cimNF; imx++) // position images with 30% overlap + { // in vertical row + cimOffs[imx].yf = cimOffs[imx-1].yf + 0.7 * cimPXMw[imx-1]->hh; + cimOffs[imx].xf = cimOffs[imx-1].xf; + } + + Fzoom = 0; // scale image to fit window + Fblowup = 1; // magnify small image to window size + + cimBlend = panPreAlignBlend * cimPXMw[1]->hh; // overlap in align window + cim_show_Vimages(1,0); // combine and show images in main window + + panozd = zdialog_new(ZTX("Pre-align Images"),mWin,Bproceed,Bcancel,null); // start pre-align dialog + zdialog_add_widget(panozd,"label","lab1","dialog",align_mess,"space=5"); + zdialog_add_widget(panozd,"hbox","hb1","dialog",0,"space=2"); + zdialog_add_widget(panozd,"spin","spmm","hb1","20|999|0.1|35","space=5"); // [ 35 ] lens mm (source) + zdialog_add_widget(panozd,"label","labmm","hb1",ZTX("lens mm")); // [ 0.3 ] lens bow + zdialog_add_widget(panozd,"label","labsorc","hb1","","space=5"); // [resize] resize window + zdialog_add_widget(panozd,"hbox","hb2","dialog",0,"space=2"); + zdialog_add_widget(panozd,"spin","spbow","hb2","-9|9|0.01|0","space=5"); + zdialog_add_widget(panozd,"label","labbow","hb2",ZTX("lens bow")); + zdialog_add_widget(panozd,"hbox","hb3","dialog",0,"space=2"); + zdialog_add_widget(panozd,"button","resize","hb3",ZTX("Resize"),"space=5"); + zdialog_add_widget(panozd,"label","labsiz","hb3",ZTX("resize window"),"space=5"); + + zdialog_stuff(panozd,"spmm",lens_mm); // stuff lens data + zdialog_stuff(panozd,"spbow",lens_bow); + zdialog_stuff(panozd,"labsorc",lensource); // show source of lens data + + panStat = -1; // busy status + gdk_window_set_cursor(drWin->window,dragcursor); // set drag cursor + zdialog_run(panozd,vpano_prealign_event,"-10/20"); // start dialog v.11.07 + start_thread(vpano_prealign_thread,0); // start working thread + zdialog_wait(panozd); // wait for dialog completion + gdk_window_set_cursor(drWin->window,0); // restore normal cursor + Fzoom = Fblowup = 0; + return; +} + + +// pre-align dialog event function + +int vpano_prealign_event(zdialog *zd, cchar *event) +{ + int imx; + double overlap; + + if (strstr("spmm spbow",event)) { + zdialog_fetch(zd,"spmm",lens_mm); // get revised lens data + zdialog_fetch(zd,"spbow",lens_bow); + } + + if (strEqu(event,"resize")) // allocate new E3 image + cim_show_Vimages(1,0); + + if (zd->zstat) // dialog complete + { + if (zd->zstat == 1) // proceed + panStat = 1; + else // cancel or other + panStat = 0; + + zdialog_free(panozd); // kill dialog + wrapup_thread(0); // wait for thread + + if (! panStat) return 0; // canceled + + for (imx = 0; imx < cimNF-1; imx++) // check for enough overlap + { + overlap = cim_get_overlap(imx,imx+1,cimPXMs); // v.11.04 + if (overlap < panFinalBlend) { // v.11.09 + zmessageACK(mWin,ZTX("Too little overlap, cannot align")); + panStat = 0; + return 0; + } + } + } + + return 0; +} + + +// pre-align working thread +// convert mouse and KB events into image movements // overhauled + +void * vpano_prealign_thread(void *) +{ + cimoffs offstemp; + PXM *pxmtemp; + char *ftemp; + int im1, im2, imm, imx; + int mx0, my0, mx, my; // mouse drag origin, position + int xoff, yoff, loy, hiy; + int sepy, minsep; + int ww, hh, rotate, midy; + double lens_mm0, lens_bow0; + double dx, dy, t1, t2, dt; + + imm = ww = hh = rotate = xoff = yoff = 0; // stop compiler warnings + + lens_mm0 = lens_mm; // to detect changes + lens_bow0 = lens_bow; + + mx0 = my0 = 0; // no drag in progress + Mcapture = KBcapture = 1; // capture mouse drag and KB keys + + cimBlend = 0; // full blend during pre-align + + while (true) // loop and align until done + { + zsleep(0.05); // logic simplified + + if (panStat != -1) break; // quit signal from dialog + + if (lens_mm != lens_mm0 || lens_bow != lens_bow0) { // change in lens parameters + lens_mm0 = lens_mm; + lens_bow0 = lens_bow; + + for (imx = 0; imx < cimNF; imx++) { // re-curve images + cim_scale_image(imx,cimPXMs); + cim_curve_Vimage(imx); + PXM_free(cimPXMw[imx]); + cimPXMw[imx] = PXM_copy(cimPXMs[imx]); + } + + cim_show_Vimages(1,0); // combine and show images + continue; + } + + if (KBkey) { // KB input + if (KBkey == GDK_Left) cimOffs[imm].xf -= 0.5; // tweak alignment offsets + if (KBkey == GDK_Right) cimOffs[imm].xf += 0.5; + if (KBkey == GDK_Up) cimOffs[imm].yf -= 0.5; + if (KBkey == GDK_Down) cimOffs[imm].yf += 0.5; + if (KBkey == GDK_r) cimOffs[imm].tf += 0.0005; + if (KBkey == GDK_l) cimOffs[imm].tf -= 0.0005; + KBkey = 0; + + cim_show_Vimages(0,0); // combine and show images + continue; + } + + if (! Mxdrag && ! Mydrag) // no drag underway + mx0 = my0 = 0; // reset drag origin + + if (Mxdrag || Mydrag) // mouse drag underway + { + mx = Mxdrag; // mouse position in image + my = Mydrag; + + if (! mx0 && ! my0) // new drag + { + mx0 = mx; // set drag origin + my0 = my; + minsep = 9999; + + for (imx = 0; imx < cimNF; imx++) // find image with midpoint + { // closest to mouse y + loy = cimOffs[imx].yf; + hiy = loy + cimPXMw[imx]->hh; + midy = (loy + hiy) / 2; + sepy = abs(midy - my0); + if (sepy < minsep) { + minsep = sepy; + imm = imx; // image to drag or rotate + } + } + + xoff = cimOffs[imm].xf; + yoff = cimOffs[imm].yf; + ww = cimPXMw[imm]->ww; + hh = cimPXMw[imm]->hh; + + rotate = 0; // if drag at right edge, + if (mx0 > xoff + 0.85 * ww) rotate = 1; // set rotate flag + } + + if (mx != mx0 || my != my0) // drag is progressing + { + dx = mx - mx0; // mouse movement + dy = my - my0; + + if (rotate && my0 > yoff && my > yoff) // rotation + { + if (imm > 0) { + loy = cimOffs[imm].yf; // if there is an image above, + hiy = cimOffs[imm-1].yf + cimPXMw[imm-1]->hh; // midy = midpoint of overlap + midy = (loy + hiy) / 2; + } + else midy = 0; // this is the topmist image + + t1 = atan(1.0 * (my0-yoff) / (mx0-xoff)); + t2 = atan(1.0 * (my-yoff) / (mx-xoff)); + dt = t2 - t1; // angle change + dy = - dt * ww / 2; // pivot = middle of overlap above + dx = dt * (midy-yoff); + } + + else dt = 0; // x/y drag + + cimOffs[imm].xf += dx; // update image + cimOffs[imm].yf += dy; + cimOffs[imm].tf += dt; + xoff = cimOffs[imm].xf; // v.11.04 + yoff = cimOffs[imm].yf; + + cim_show_Vimages(0,0); // show combined images + + mx0 = mx; // next drag origin = current mouse + my0 = my; + } + } + + for (im1 = 0; im1 < cimNF-1; im1++) // track image order changes + { + im2 = im1 + 1; + if (cimOffs[im2].yf < cimOffs[im1].yf) + { + ftemp = cimFile[im2]; // switch filespecs + cimFile[im2] = cimFile[im1]; + cimFile[im1] = ftemp; + pxmtemp = cimPXMf[im2]; // switch images + cimPXMf[im2] = cimPXMf[im1]; + cimPXMf[im1] = pxmtemp; + pxmtemp = cimPXMs[im2]; // scaled images + cimPXMs[im2] = cimPXMs[im1]; + cimPXMs[im1] = pxmtemp; + pxmtemp = cimPXMw[im2]; // warped images + cimPXMw[im2] = cimPXMw[im1]; + cimPXMw[im1] = pxmtemp; + offstemp = cimOffs[im2]; // offsets + cimOffs[im2] = cimOffs[im1]; + cimOffs[im1] = offstemp; + if (imm == im1) imm = im2; // current drag image + else if (imm == im2) imm = im1; + break; + } + } + } + + KBcapture = Mcapture = 0; + thread_exit(); + return 0; // not executed, stop g++ warning +} + + +// fine-alignment +// start with very small image size +// search around offset values for best match +// increase image size and loop until full-size + +void vpano_align() +{ + int imx, im1, im2, ww, hh; + double R, dx, dy, dt; + double overlap; + cimoffs offsets0; + + Fzoom = 0; // scale E3 to fit window + Fblowup = 1; // magnify small image to window size + Ffuncbusy++; + + for (imx = 0; imx < cimNF; imx++) { + cimOffs[imx].xf = cimOffs[imx].xf / cimScale; // scale x/y offsets for full-size images + cimOffs[imx].yf = cimOffs[imx].yf / cimScale; + } + + cimScale = 1.0; // full-size + + for (imx = 0; imx < cimNF; imx++) { + PXM_free(cimPXMs[imx]); + cimPXMs[imx] = PXM_copy(cimPXMf[imx]); // copy full-size images + cim_curve_Vimage(imx); // curve them + } + + cimBlend = 0.3 * cimPXMs[0]->hh; + cim_get_overlap(0,1,cimPXMs); // match images 0 & 1 in overlap area + cim_match_colors(0,1,cimPXMs); + cim_adjust_colors(cimPXMf[0],1); // image 0 << profile 1 + cim_adjust_colors(cimPXMf[1],2); // image 1 << profile 2 + + if (cimNF > 2) { + cimBlend = 0.3 * cimPXMs[1]->hh; + cim_get_overlap(1,2,cimPXMs); + cim_match_colors(1,2,cimPXMs); + cim_adjust_colors(cimPXMf[0],1); + cim_adjust_colors(cimPXMf[1],1); + cim_adjust_colors(cimPXMf[2],2); + } + + if (cimNF > 3) { + cimBlend = 0.3 * cimPXMs[2]->hh; + cim_get_overlap(2,3,cimPXMs); + cim_match_colors(2,3,cimPXMs); + cim_adjust_colors(cimPXMf[0],1); + cim_adjust_colors(cimPXMf[1],1); + cim_adjust_colors(cimPXMf[2],1); + cim_adjust_colors(cimPXMf[3],2); + } + + cimScale = panInitAlignSize / cimPXMf[1]->hh; // initial align image scale + if (cimScale > 1.0) cimScale = 1.0; + + for (imx = 0; imx < cimNF; imx++) { // scale offsets for image scale + cimOffs[imx].xf = cimOffs[imx].xf * cimScale; + cimOffs[imx].yf = cimOffs[imx].yf * cimScale; + } + + cimSearchRange = panInitSearchRange; // initial align search range + cimSearchStep = panInitSearchStep; // initial align search step + cimWarpRange = panInitWarpRange; // initial align corner warp range + cimWarpStep = panInitWarpStep; // initial align corner warp step + hh = cimPXMf[0]->hh * cimScale; // initial align image width + cimBlend = hh * panInitBlend; // initial align blend width + cimSampSize = panSampSize; // pixel sample size for align/compare + cimNsearch = 0; // reset align search counter + + while (true) // loop, increasing image size + { + for (imx = 0; imx < cimNF; imx++) { // prepare images + cim_scale_image(imx,cimPXMs); // scale to new size + cim_curve_Vimage(imx); // curve based on lens params + cim_warp_image_Vpano(imx,1); // apply corner warps + } + + cim_show_Vimages(1,0); // show with 50/50 blend in overlaps + + for (im1 = 0; im1 < cimNF-1; im1++) // fine-align each image with top neighbor + { + im2 = im1 + 1; + + offsets0 = cimOffs[im2]; // save initial alignment offsets + overlap = cim_get_overlap(im1,im2,cimPXMs); // get overlap area v.11.04 + if (overlap < panFinalBlend-2) { + zmessageACK(mWin,ZTX("Too little overlap, cannot align")); + goto fail; + } + + cim_get_redpix(im1); // get high-contrast pixels + + cim_align_image(im1,im2); // search for best offsets and warps + + zfree(cimRedpix); // clear red pixels + cimRedpix = 0; + + dx = cimOffs[im2].xf - offsets0.xf; // changes from initial offsets + dy = cimOffs[im2].yf - offsets0.yf; + dt = cimOffs[im2].tf - offsets0.tf; + + for (imx = im2+1; imx < cimNF; imx++) // propagate to following images + { + cimOffs[imx].xf += dx; + cimOffs[imx].yf += dy; + cimOffs[imx].tf += dt; + ww = cimOffs[imx].xf - cimOffs[im2].xf; + cimOffs[imx].yf += ww * dt; + } + } + + if (cimScale == 1.0) goto success; // done + + R = panImageIncrease; // next larger image size + cimScale = cimScale * R; + if (cimScale > 0.85) { // if close to end, jump to end + R = R / cimScale; + cimScale = 1.0; + } + + for (imx = 0; imx < cimNF; imx++) // scale offsets for new size + { + cimOffs[imx].xf *= R; + cimOffs[imx].yf *= R; + + for (int ii = 0; ii < 4; ii++) { + cimOffs[imx].wx[ii] *= R; + cimOffs[imx].wy[ii] *= R; + } + } + + cimSearchRange = panSearchRange; // align search range + cimSearchStep = panSearchStep; // align search step size + cimWarpRange = panWarpRange; // align corner warp range + cimWarpStep = panWarpStep; // align corner warp step size + + cimBlend = cimBlend * panBlendDecrease * R; // blend width, reduced + hh = cimPXMf[0]->hh * cimScale; + if (cimBlend < panFinalBlend * hh) + cimBlend = panFinalBlend * hh; // stay above minimum + } + +success: + panStat = 1; + goto align_done; +fail: + panStat = 0; +align_done: + Fzoom = Fblowup = 0; + Ffuncbusy--; + cimBlend = 1; // tiny blend (increase in tweak if wanted) + cim_show_Vimages(0,0); + return; +} + + +// get user inputs for RGB changes and blend width, update cimPXMw[*] + +void vpano_tweak() +{ + int vpano_tweak_event(zdialog *zd, cchar *event); // dialog event function + + cchar *tweaktitle = ZTX("Match Brightness and Color"); + char imageN[8] = "imageN"; + int imx; + + cimBlend = 1; // init. blend width + + panozd = zdialog_new(tweaktitle,mWin,Bdone,Bcancel,null); + + zdialog_add_widget(panozd,"hbox","hbim","dialog",0,"space=5"); + zdialog_add_widget(panozd,"label","labim","hbim",ZTX("image"),"space=5"); // image (o) (o) (o) (o) + zdialog_add_widget(panozd,"hbox","hbc1","dialog",0,"homog"); // + zdialog_add_widget(panozd,"label","labred","hbc1",Bred); // red green blue + zdialog_add_widget(panozd,"label","labgreen","hbc1",Bgreen); // [_____] [_____] [_____] + zdialog_add_widget(panozd,"label","labblue","hbc1",Bblue); // + zdialog_add_widget(panozd,"hbox","hbc2","dialog",0,"homog"); // brightness [___] [apply] + zdialog_add_widget(panozd,"spin","red","hbc2","50|200|0.1|100","space=5"); // + zdialog_add_widget(panozd,"spin","green","hbc2","50|200|0.1|100","space=5"); // -------------------------- + zdialog_add_widget(panozd,"spin","blue","hbc2","50|200|0.1|100","space=5"); // + zdialog_add_widget(panozd,"hbox","hbbri","dialog",0,"space=5"); // [auto color] [file color] + zdialog_add_widget(panozd,"label","labbr","hbbri",Bbrightness,"space=5"); // + zdialog_add_widget(panozd,"spin","bright","hbbri","50|200|0.1|100"); // -------------------------- + zdialog_add_widget(panozd,"button","brapp","hbbri",Bapply,"space=10"); // + zdialog_add_widget(panozd,"hsep","hsep","dialog",0,"space=5"); // blend width [___] [apply] + zdialog_add_widget(panozd,"hbox","hbc3","dialog",0,"space=5"); // + zdialog_add_widget(panozd,"button","auto","hbc3",ZTX("auto color"),"space=5"); // [done] [cancel] + zdialog_add_widget(panozd,"button","file","hbc3",ZTX("file color"),"space=5"); + zdialog_add_widget(panozd,"hsep","hsep","dialog",0,"space=5"); + zdialog_add_widget(panozd,"hbox","hbblen","dialog",0); + zdialog_add_widget(panozd,"label","labbl","hbblen",Bblendwidth,"space=5"); + zdialog_add_widget(panozd,"spin","blend","hbblen","1|300|1|1"); + zdialog_add_widget(panozd,"button","blapp","hbblen",Bapply,"space=15"); + + for (imx = 0; imx < cimNF; imx++) { // add radio button per image + imageN[5] = '0' + imx; + zdialog_add_widget(panozd,"radio",imageN,"hbim",0,"space=5"); + } + + zdialog_stuff(panozd,"image0",1); // pre-select 1st image + zdialog_resize(panozd,300,0); + + panStat = -1; // busy status + zdialog_run(panozd,vpano_tweak_event,"-10/20"); // run dialog, parallel v.11.07 + zdialog_wait(panozd); // wait for dialog completion + return; +} + + +// dialog event function + +int vpano_tweak_event(zdialog *zd, cchar *event) +{ + char imageN[8] = "imageN"; + double red, green, blue, bright, bright2; + double red1, green1, blue1; + int nn, im0, imx, im1, im2, ww, hh, px, py; + uint16 *pixel; + + if (zd->zstat) // dialog complete + { + if (zd->zstat == 1) panStat = 1; // done + if (zd->zstat == 2) panStat = 0; // cancel + zdialog_free(panozd); // kill dialog + return 0; + } + + for (im0 = 0; im0 < cimNF; im0++) { // get which image is selected + imageN[5] = '0' + im0; // by the radio buttons + zdialog_fetch(zd,imageN,nn); + if (nn) break; + } + if (im0 == cimNF) return 1; + + zdialog_fetch(zd,"red",red); // get color adjustments + zdialog_fetch(zd,"green",green); + zdialog_fetch(zd,"blue",blue); + zdialog_fetch(zd,"bright",bright); // brightness adjustment + + bright2 = (red + green + blue) / 3; // RGB brightness + bright = bright / bright2; // bright setpoint / RGB brightness + red = red * bright; // adjust RGB brightness + green = green * bright; + blue = blue * bright; + + bright = (red + green + blue) / 3; + zdialog_stuff(zd,"red",red); // force back into consistency + zdialog_stuff(zd,"green",green); + zdialog_stuff(zd,"blue",blue); + zdialog_stuff(zd,"bright",bright); + + if (strEqu(event,"brapp")) // apply color & brightness changes + { + red = red / 100; // normalize 0.5 ... 2.0 + green = green / 100; + blue = blue / 100; + + cim_warp_image_Vpano(im0,0); // refresh cimPXMw from cimPXMs + + ww = cimPXMw[im0]->ww; + hh = cimPXMw[im0]->hh; + + for (py = 0; py < hh; py++) // loop all image pixels + for (px = 0; px < ww; px++) + { + pixel = PXMpix(cimPXMw[im0],px,py); + red1 = red * pixel[0]; // apply color factors + green1 = green * pixel[1]; + blue1 = blue * pixel[2]; + if (! blue1) continue; + + if (red1 > 65535 || green1 > 65535 || blue1 > 65535) { + bright = red1; // avoid overflow + if (green1 > bright) bright = green1; + if (blue1 > bright) bright = blue1; + bright = 65535.0 / bright; + red1 = red1 * bright; + green1 = green1 * bright; + blue1 = blue1 * bright; + } + + if (blue1 < 1) blue1 = 1; // avoid 0 + + pixel[0] = red1; + pixel[1] = green1; + pixel[2] = blue1; + } + + cimBlend = 1; + zdialog_stuff(zd,"blend",cimBlend); + cim_show_Vimages(0,0); // combine and show with 50/50 blend + } + + if (strEqu(event,"auto")) // auto match color of selected image + { + for (im1 = im0; im1 < cimNF-1; im1++) // from selected image to last image + { + im2 = im1 + 1; + cimBlend = 0.3 * cimPXMw[im2]->hh; + cim_get_overlap(im1,im2,cimPXMw); // match images in overlap area + cim_match_colors(im1,im2,cimPXMw); + cim_adjust_colors(cimPXMw[im1],1); // image im1 << profile 1 + cim_adjust_colors(cimPXMw[im2],2); // image im2 << profile 2 + for (imx = im1-1; imx >= im0; imx--) + cim_adjust_colors(cimPXMw[imx],1); + cimBlend = 1; + zdialog_stuff(zd,"blend",cimBlend); + cim_show_Vimages(0,0); + } + + for (im1 = im0-1; im1 >= 0; im1--) // from selected image to 1st image + { + im2 = im1 + 1; + cimBlend = 0.3 * cimPXMw[im2]->hh; + cim_get_overlap(im1,im2,cimPXMw); // match images in overlap area + cim_match_colors(im1,im2,cimPXMw); + cim_adjust_colors(cimPXMw[im1],1); // image im1 << profile 1 + cim_adjust_colors(cimPXMw[im2],2); // image im2 << profile 2 + for (imx = im2+1; imx < cimNF; imx++) + cim_adjust_colors(cimPXMw[imx],2); + cimBlend = 1; + zdialog_stuff(zd,"blend",cimBlend); + cim_show_Vimages(0,0); + } + } + + if (strEqu(event,"file")) // use original file colors + { + if (! cim_load_files()) return 1; + + for (imx = 0; imx < cimNF; imx++) { + PXM_free(cimPXMs[imx]); + cimPXMs[imx] = PXM_copy(cimPXMf[imx]); + cim_curve_Vimage(imx); // curve and warp + cim_warp_image_Vpano(imx,0); + } + + cimBlend = 1; + zdialog_stuff(zd,"blend",cimBlend); + cim_show_Vimages(0,0); + } + + if (strEqu(event,"blapp")) // apply new blend width + { + zdialog_fetch(zd,"blend",cimBlend); // can be zero + cim_show_Vimages(0,1); // show with gradual blend + } + + return 1; +} + + diff -Nru fotoxx-11.11.1/f.file.cc fotoxx-12.01.2/f.file.cc --- fotoxx-11.11.1/f.file.cc 1970-01-01 00:00:00.000000000 +0000 +++ fotoxx-12.01.2/f.file.cc 2012-01-04 08:47:11.000000000 +0000 @@ -0,0 +1,1768 @@ +/************************************************************************** + + Fotoxx edit photos and manage collections + + Copyright 2007 2008 2009 2010 2011 2012 Michael Cornelison + Source URL: http://kornelix.squarespace.com/fotoxx + Contact: kornelix2@googlemail.com + + 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 http://www.gnu.org/licenses/. + +***************************************************************************/ + +#define EX extern // disable extern declarations +#include "fotoxx.h" + + +/************************************************************************** + + Fotoxx image edit - file menu functions + +***************************************************************************/ + +// display image gallery (thumbnails) in a separate window + +void m_gallery(GtkWidget *, cchar *) +{ + zfuncs::F1_help_topic = "navigation"; + + if (curr_file) + image_gallery(0,"paint1",curr_file_posn,m_gallery2,mWin); // overlay main window v.10.9 + else { + char *pp = getcwd(command,ccc); // v.11.09 + if (pp) { + image_gallery(pp,"init",0,m_gallery2,mWin); // use current directory v.11.04 + image_gallery(0,"paint1"); + } + curr_file_posn = 0; // v.11.05 + } + + return; +} + + +// clicked thumbnail will call this function + +void m_gallery2(int Nth, int button) +{ + char *file; + + zfuncs::F1_help_topic = "navigation"; // v.11.08 + + if (Nth == -1) return; // gallery window closed + + file = image_gallery(0,"find",Nth); + if (! file) return; + + if (edit_coll_name && button == 3) // right-click, pass to edit collection + { // v.11.11 + edit_coll_popmenu(null,file); + zfree(file); + return; + } + + f_open(file,1,Nth); // clicked file = current file + zfree(file); + + gtk_window_present(MWIN); // bring main window to front v.10.12 + return; +} + + +/**************************************************************************/ + +// start a new parallel instance of fotoxx +// move my window to right half of desktop +// start new instance to open in left half + +void m_clone1(GtkWidget *, cchar *) +{ + GdkScreen *screen; + int ww, hh, err; + + zfuncs::F1_help_topic = "clone"; // v.10.8 + + screen = gdk_screen_get_default(); // get desktop screen size + ww = gdk_screen_get_width(screen); + hh = gdk_screen_get_height(screen); + ww = ww / 2 - 20; + hh = hh - 50; + gdk_window_move_resize(mWin->window,ww+20,10,ww,hh); // move my window to right half + + snprintf(command,ccc,"fotoxx -clone1 -lang %s",zfuncs::zlang); // start new instance + if (curr_file) strncatv(command,ccc," \"",curr_file,"\"",null); + strcat(command," &"); + err = system(command); + if (err) printf("error: %s \n",wstrerror(err)); + return; +} + + +// start a new parallel instance of fotoxx +// new window is slightly down and right from old window + +void m_clone2(GtkWidget *, cchar *) // new v.11.07 +{ + int xx, yy, ww, hh, err; + + zfuncs::F1_help_topic = "clone"; + + gtk_window_get_position(MWIN,&xx,&yy); // get window position and size + gtk_window_get_size(MWIN,&ww,&hh); + + snprintf(command,ccc,"fotoxx -clone2 %d %d %d %d -lang %s",xx,yy,ww,hh,zfuncs::zlang); + if (curr_file) strncatv(command,ccc," \"",curr_file,"\"",null); + strcat(command," &"); // start new instance and pass + err = system(command); // my window posn and size + if (err) printf("error: %s \n",wstrerror(err)); + return; +} + + +/**************************************************************************/ + +// open file menu function + +void m_open(GtkWidget *, cchar *) +{ + zfuncs::F1_help_topic = "open_image_file"; + f_open(null,1); + return; +} + + +/**************************************************************************/ + +// open drag-drop file + +void m_open_drag(int x, int y, char *file) +{ + zfuncs::F1_help_topic = "open_image_file"; + f_open(file,1); + return; +} + + +/**************************************************************************/ + +// open a new file in a new parallel instance of fotoxx +// new window is slightly down and right from old window + +void m_open_newin(GtkWidget *, cchar *) // new v.11.07 +{ + int xx, yy, ww, hh, err; + char *file; + + zfuncs::F1_help_topic = "open_image_file"; + + file = zgetfile1(ZTX("Open Image File"),"open",curr_file); // dialog to get filespec + if (! file) return; // canceled + if (image_file_type(file) != 2) return; // not a supported image file v.11.05 + + gtk_window_get_position(MWIN,&xx,&yy); // get window position and size + gtk_window_get_size(MWIN,&ww,&hh); + + snprintf(command,ccc,"fotoxx -c2 %d %d %d %d -l %s",xx,yy,ww,hh,zfuncs::zlang); + strncatv(command,ccc," \"",file,"\"",null); + strcat(command," &"); // start new instance and pass + err = system(command); // my window posn and size + if (err) printf("error: %s \n",wstrerror(err)); + return; +} + + +/**************************************************************************/ + +// open the previous file opened (not the same as toolbar [prev] button) +// repeated use will cycle back and forth between two most recent files + +void m_previous(GtkWidget *, cchar *) +{ + int ii, jj, err; + + zfuncs::F1_help_topic = "open_previous_file"; + + if (! menulock(1)) return; // v.11.11 + menulock(0); + if (mod_keep()) return; // v.11.06 + + if (curr_file) jj = 1; // 2nd most recent file v.11.08 + else jj = 0; // no current file, use most recent + + for (ii = jj; ii < Nrecentfiles; ii++) + { + if (! recentfiles[ii]) continue; // bugfix v.12.01 + err = f_open(recentfiles[ii],1); // get first one that is still there + if (! err) return; + } + + return; +} + + +/**************************************************************************/ + +// open an image file from the list of recent image files + +void m_recent(GtkWidget *, cchar *) // overhauled v.11.01 +{ + void recentfile2(int Nth, int button); + + int ii, jj, typ; + FILE *fid; + + zfuncs::F1_help_topic = "open_recent_file"; + + if (! menulock(1)) return; + menulock(0); + if (mod_keep()) return; // v.11.11 + + fid = fopen(recentfiles_file,"w"); // revalidate list of recent files + if (! fid) return; // and update disk file + + for (ii = jj = 0; ii < Nrecentfiles; ii++) + { + if (! recentfiles[ii]) continue; // improved v.11.11 + typ = image_file_type(recentfiles[ii]); + if (typ != 2) { + zfree(recentfiles[ii]); + recentfiles[ii] = 0; + continue; + } + if (jj < ii) { + recentfiles[jj] = recentfiles[ii]; + recentfiles[ii] = 0; // bugfix v.11.11.1 + } + fprintf(fid,"%s \n",recentfiles[jj]); + jj++; + } + + fclose(fid); + + if (! jj) return; // no files found + + image_gallery(recentfiles_file,"initF",0,recentfile2,mWin); // generate gallery of recent files + if (image_navi::galleryname) zfree(image_navi::galleryname); + image_navi::galleryname = strdupz("Recent Files",0,"recent files"); // v.12.01 + image_gallery(0,"paint1",0); // show new image gallery window + + return; +} + + +// clicked thumbnail will call this function + +void recentfile2(int Nth, int button) +{ + char *file; + + if (Nth == -1) { // gallery window cancelled + if (curr_file) image_gallery(curr_file,"init"); // reset gallery from current file v.11.05 + return; + } + + file = image_gallery(0,"find",Nth); + if (! file) return; + image_gallery(file,"init"); // initz. gallery from chosen file v.11.05 + image_gallery(0,"close"); // close the gallery + f_open(file,1); // open the file + zfree(file); + return; +} + + +// add a file to the list of recent files + +void add_recent_file(cchar *file) +{ + int ii; + + for (ii = 0; ii < Nrecentfiles-1 && recentfiles[ii]; ii++) // find file in recent list + if (strEqu(file,recentfiles[ii])) break; // (or find last entry in list) + if (recentfiles[ii]) zfree(recentfiles[ii]); // free this slot in list + for (; ii > 0; ii--) recentfiles[ii] = recentfiles[ii-1]; // move list UP to fill hole + recentfiles[0] = strdupz(file); // current file >> first in list + return; +} + + +/**************************************************************************/ + +// Open a file and initialize PXM bitmap. +// If flock and menu is locked, do nothing and return. +// Otherwise open the file and display in main window. +// If Nth matches the file position in current file set, curr_file_posn +// will be set to Nth, otherwise it is searched and set correctly +// (a file can be present multiple times in a collection set). +// If fkeepundo is ON, the edit undo image stack is not purged: current +// edits are kept after opening the new file (used by m_saveas()). +// Returns: 0 = OK, +N = error. + +int f_open(cchar *filespec, int flock, int Nth, int fkeepundo) +{ + PXM *temp8; + int err, cc, yn, fposn, nfiles, nimages; + char *pp, *file, *rawfile, titlebar[250]; + char fname[100], fdirk[100]; + int Gwarn = 0, Gnew = 0; + + if (flock && Fmenulock) { + zmessageACK(mWin,ZTX("prior function still active")); // v.11.06 + return 1; + } + + if (mod_keep()) return 2; // unsaved edits + + if (image_navi::gallerytype > 1) Gwarn = 1; // warn if discarding search or + pp = image_navi::galleryname; // collection type gallery + if (pp && strEqu(pp,"Recent Files")) Gwarn = 0; + + if (filespec) + file = strdupz(filespec,0,"f_open"); // use passed filespec + else { + if (Gwarn) { // warn user, gallery will be discarded + yn = zmessageYN(mWin,Bdiscard,image_navi::galleryname); + if (! yn) return 6; // do not discard v.11.09 + Gnew = 1; // flag, new gallery needed + } + pp = curr_file; + if (! pp) pp = curr_dirk; + file = zgetfile1(ZTX("Open Image File"),"open",pp); // dialog to get filespec + if (! file) return 3; // canceled + } + + if (image_file_type(file) != 2) // not a supported image file type + { + pp = strrchr(file,'.'); + if (! pp || strlen(pp) != 4 || ! strcasestr(RAWfiles,pp)) { // check if a RAW file extension + zfree(file); // v.11.09 + return 3; // no + } + + rawfile = file; // v.11.09 + file = strdupz(rawfile,5,"f_open"); // filename.raw >> filename.tiff + pp = file + (pp - rawfile); + strcpy(pp,".tiff"); + snprintf(command,ccc,"ufraw-batch --wb=camera --out-type=tiff " // convert RAW file to tiff-16 v.11.09 + "--out-depth=16 --overwrite " + "--output=\"%s\" \"%s\" ",file,rawfile); + err = system(command); + if (err) { + zmessageACK(mWin,wstrerror(err)); // failed, clean up + zfree(file); + zfree(rawfile); + return 3; + } + zfree(rawfile); // tiff file will be opened + } + + temp8 = f_load(file,8); // load image as PXM-8 pixmap + if (! temp8) { + zfree(file); // bad image + return 5; + } + // menulock() removed v.11.11 + free_resources(fkeepundo); // free resources for old image file + + if (curr_file) zfree(curr_file); // current image filespec + curr_file = strdupz(file,8,"curr_file"); + zfree(file); + + if (curr_dirk) zfree(curr_dirk); // set current directory + curr_dirk = strdupz(curr_file,0,"curr_dirk"); // for new current file + pp = strrchr(curr_dirk,'/'); + *pp = 0; + err = chdir(curr_dirk); + + Fpxm8 = temp8; // pixmap for current image + Fww = Fpxm8->ww; + Fhh = Fpxm8->hh; + + strcpy(curr_file_type,f_load_type); // set curr_file_xxx from f_load_xxx + curr_file_bpc = f_load_bpc; + curr_file_size = f_load_size; + + fposn = image_gallery_position(curr_file,Nth); // file position in gallery list + if (fposn < 0 || Gnew) { // not there or break current gallery v.11.09 + image_gallery(curr_file,"init",0,m_gallery2); // generate new gallery list v.12.01 + fposn = image_gallery_position(curr_file,0); // position and count in gallery list + image_gallery(0,"paint2",fposn); // refresh gallery window if active v.11.07 + } + + nfiles = image_navi::nfiles; // total gallery files (incl. directories) + nimages = image_navi::nimages; // total image files v.11.05 + + curr_file_posn = fposn; // keep track of file position + curr_file_count = image_navi::nimages; // and image gallery count + + add_recent_file(curr_file); // first in recent files list + + Fzoom = 0; // zoom level = fit window + zoomx = zoomy = 0; // no zoom center + + pp = (char *) strrchr(curr_file,'/'); + strncpy0(fname,pp+1,99); // file name + cc = pp - curr_file; + if (cc < 99) strncpy0(fdirk,curr_file,cc+2); // get dirk/path/ if short enough + else { + strncpy(fdirk,curr_file,96); // or use /dirk/path... + strcpy(fdirk+95,"..."); + } + + fposn = fposn + 1 - nfiles + nimages; // position among images, 1-based + snprintf(titlebar,250,"%s %d/%d %s %s", // window title bar + fversion,fposn,curr_file_count,fname,fdirk); + gtk_window_set_title(MWIN,titlebar); + + mwpaint1(); // immediate paint v.11.11 + gtk_window_present(MWIN); // bring main window to front v.11.04 + zmainloop(); + + if (zdrename) m_rename(0,0); // update active rename dialog + if (zdexifview) info_view(0); // " EXIF/IPTC view window v.10.2 + if (zdexifedit) m_info_edit(0,0); // " EXIF/IPTC edit window v.10.11 + if (zdedittags) m_edit_tags(0,0); // " edit tags dialog + if (zdeditcctext) m_edit_cctext(0,0); // " edit comments dialog v.10.10 + + curr_image_time = get_seconds(); // mark time of file load v.11.07 + + return 0; +} + + +/**************************************************************************/ + +// open previous or next file in current gallery list + +void m_prev(GtkWidget *, cchar *menu) +{ + int err, Nth; + + if (menu) zfuncs::F1_help_topic = "open_image_file"; + + if (Fmenulock) return; + if (mod_keep()) return; + if (! curr_file) return; + + for (Nth = curr_file_posn-1; Nth >= 0; Nth--) // v.11.05 + { + char *pp = image_gallery(0,"find",Nth); + if (! pp) continue; + err = f_open(pp,1,Nth); + zfree(pp); + if (! err) break; + } + + return; +} + +void m_next(GtkWidget *, cchar *menu) +{ + int err, Nth; + int nfiles = image_navi::nfiles; + + if (menu) zfuncs::F1_help_topic = "open_image_file"; + + if (Fmenulock) return; + if (mod_keep()) return; + if (! curr_file) return; + + for (Nth = curr_file_posn+1; Nth < nfiles; Nth++) // v.11.05 + { + char *pp = image_gallery(0,"find",Nth); + if (! pp) continue; + err = f_open(pp,1,Nth); + zfree(pp); + if (! err) break; + } + + return; +} + + +/**************************************************************************/ + +// save (modified) image to same file + +void m_save(GtkWidget *, cchar *menu) +{ + int Fwarn = 1, zstat, suppress; + char *pp; + zdialog *zd; + cchar *warn_message = ZTX("Overwrite original file?"); + cchar *suppress_message = ZTX("Do not warn again"); + + if (! curr_file) return; + if (is_syncbusy()) return; // v.11.11 + + if (menu && strNeq(menu,"nowarn")) // don't change help topic v.11.11 + zfuncs::F1_help_topic = "save_file"; + + if (Fwarnoverwrite) { // warn if overwrite original v.11.10 + pp = strrchr(curr_file,'/'); + if (! pp) return; + pp = strstr(pp,".v"); // look for version notation .vNN + if (pp && pp[2] >= '0' && pp[2] <= '9' + && pp[3] >= '0' && pp[3] <= '9') Fwarn = 0; // found, file not original + + if (Fwarn && ! (menu && strEqu(menu,"nowarn"))) { // no warn if KB rotate save v.11.11 + zd = zdialog_new(ZTX("Warning"),mWin,Bproceed,Bcancel,null); + zdialog_add_widget(zd,"label","lab1","dialog",warn_message,"space=5"); + zdialog_add_widget(zd,"check","suppress","dialog",suppress_message,"space=5"); + zdialog_run(zd); + zstat = zdialog_wait(zd); + zdialog_fetch(zd,"suppress",suppress); + zdialog_free(zd); + if (suppress) { + Fwarnoverwrite = 0; + save_params(); + } + if (zstat != 1) return; + } + } + + strcpy(jpeg_quality,def_jpeg_quality); // default jpeg save quality + + if (strEqu(curr_file_type,"other")) // if gif, bmp, etc. use jpg v.11.03 + strcpy(curr_file_type,"jpg"); + + f_save(curr_file,curr_file_type,curr_file_bpc); // save file + + strcpy(curr_file_type,f_save_type); // update curr_file_xxx from f_save_xxx + curr_file_size = f_save_size; + + return; +} + + +/**************************************************************************/ + +// save (modified) image to new version of same file +// - no confirmation of overwrite. + +void m_savevers(GtkWidget *, cchar *) // new v.11.07 +{ + char *outfile, *pext, *pvers; + cchar *delim; + int ii, err, nvers; + struct stat fstat; + + if (! curr_file) return; + if (is_syncbusy()) return; // v.11.11 + + zfuncs::F1_help_topic = "save_file"; + + strcpy(jpeg_quality,def_jpeg_quality); // default jpeg save quality + + outfile = strdupz(curr_file,12,"curr_file"); // output file name TBD + + pext = strrchr(outfile,'/'); // find file .ext + if (pext) pext = strrchr(pext,'.'); + if (pext && strlen(pext) > 5) pext = 0; + if (! pext) pext = outfile + strlen(outfile); // unknown, none + + pvers = pext - 4; // find curr. version: filename.vNN.ext + if (! strnEqu(pvers,".v",2)) nvers = 0; + else { + err = convSI(pvers+2,nvers,1,98,&delim); // convert NN to number 1-98 + if (err > 1) nvers = 0; // conversion error + if (delim != pext) nvers = 0; // check format is .vNN + } + if (nvers == 0) { // no version in file name + pvers = pext; + pext += 4; + memmove(pext,pvers,6); // make space for .vNN before .ext + strncpy(pvers,".vNN",4); + } + + for (ii = 98; ii > nvers; ii--) // look for higher file versions + { + pvers[2] = ii/10 + '0'; // build filename.vNN.ext + pvers[3] = ii - 10 * (ii/10) + '0'; + err = stat(outfile,&fstat); + if (! err) break; + } + + ii++; // use next version 1-99 + nvers = ii; + pvers[2] = ii/10 + '0'; // build filename.vNN.ext + pvers[3] = ii - 10 * (ii/10) + '0'; + + f_save(outfile,curr_file_type,curr_file_bpc); // save file (fails at 99 versions) + + load_fileinfo(outfile); // update search index file + update_search_index(outfile); + + image_gallery(outfile,"init"); // update gallery + image_gallery(outfile,"paint2",-1); // refresh gallery window if active + + f_open(outfile,1,0,1); // new version = current file v.11.11.1 + + zfree(outfile); + return; +} + + +/**************************************************************************/ + +// save (modified) image to new file +// confirm if overwrite existing file + +GtkWidget *saveas_fchooser; + +void m_saveas(GtkWidget *, cchar *menu) +{ + void saveas_radiobutt(void *, int button); + void saveas_kbkey(void *, GdkEventKey *event); + + GtkWidget *fdialog, *hbox; + GtkWidget *tiff8, *tiff16, *jpeg, *png, *jqlab, *jqval; + GtkWidget *makecurrent; + char *outfile = 0, *outfile2 = 0, *pext; + int ii, err, yn, bpc, status, mkcurr = 0; + struct stat fstat; + cchar *type; + cchar *exts = ".jpg.JPG.jpeg.JPEG.tif.TIF.tiff.TIFF.png.PNG"; + + if (! curr_file) return; + if (is_syncbusy()) return; // v.11.11 + + if (menu) zfuncs::F1_help_topic = "save_file"; + + fdialog = gtk_dialog_new_with_buttons(ZTX("Save File"), // build file save dialog + MWIN, GTK_DIALOG_MODAL, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, null); + gtk_window_set_default_size(GTK_WINDOW(fdialog),600,500); + + saveas_fchooser = gtk_file_chooser_widget_new(GTK_FILE_CHOOSER_ACTION_SAVE); + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(fdialog)->vbox),saveas_fchooser); + + // set_filename() should select the file but does nothing GTK bug ? v.10.9.1 ///// + // set_current_name() puts file name in input box, but does not select the file + gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(saveas_fchooser),curr_file); + char *fname = strrchr(curr_file,'/') + 1; + gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(saveas_fchooser),fname); + + hbox = gtk_hbox_new(0,0); + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(fdialog)->vbox),hbox); + gtk_box_set_child_packing(GTK_BOX(GTK_DIALOG(fdialog)->vbox),hbox,0,0,10,GTK_PACK_END); + + tiff8 = gtk_radio_button_new_with_label(null,"tiff-8"); + tiff16 = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(tiff8),"tiff-16"); + png = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(tiff8),"png"); + jpeg = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(tiff8),"jpeg"); + jqlab = gtk_label_new(ZTX("quality")); + jqval = gtk_entry_new(); + makecurrent = gtk_check_button_new_with_label(ZTX("make current")); + + gtk_entry_set_width_chars(GTK_ENTRY(jqval),2); + gtk_box_pack_start(GTK_BOX(hbox),tiff8,0,0,5); // (o) tiff8 (o) tiff16 (o) png + gtk_box_pack_start(GTK_BOX(hbox),tiff16,0,0,5); + gtk_box_pack_start(GTK_BOX(hbox),png,0,0,5); + gtk_box_pack_start(GTK_BOX(hbox),jpeg,0,0,5); // (o) jpeg jpeg quality [__] + gtk_box_pack_start(GTK_BOX(hbox),jqlab,0,0,0); + gtk_box_pack_start(GTK_BOX(hbox),jqval,0,0,3); + gtk_box_pack_end(GTK_BOX(hbox),makecurrent,0,0,3); // [x] make current + + G_SIGNAL(tiff8,"pressed",saveas_radiobutt,0); // connect file type radio buttons + G_SIGNAL(tiff16,"pressed",saveas_radiobutt,1); // to handler function + G_SIGNAL(png,"pressed",saveas_radiobutt,2); + G_SIGNAL(jpeg,"pressed",saveas_radiobutt,3); + G_SIGNAL(fdialog,"key-release-event",saveas_kbkey,0); + + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(jpeg),1); // set default file type = jpeg + gtk_entry_set_text(GTK_ENTRY(jqval),def_jpeg_quality); // default jpeg save quality + + if (strEqu(curr_file_type,"png")) // default matches file type + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(png),1); // if png or tiff + if (strEqu(curr_file_type,"tiff")) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tiff8),1); + if (curr_file_bpc == 16) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tiff16),1); + +dialog_run: + + gtk_widget_show_all(fdialog); // run dialog + + status = gtk_dialog_run(GTK_DIALOG(fdialog)); + if (status != GTK_RESPONSE_ACCEPT) { // user cancelled + gtk_widget_destroy(fdialog); + return; + } + + outfile2 = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(saveas_fchooser)); + if (! outfile2) goto dialog_run; + outfile = strdupz(outfile2,12,"curr_file"); // add space for possible .vNN and .ext + g_free(outfile2); + + type = "jpg"; // default output type + bpc = 8; + + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(png))) + type = "png"; + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(tiff8))) + type = "tif"; + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(tiff16))) { + type = "tif"; + bpc = 16; + } + + if (strEqu(type,"jpg")) { // set jpeg save quality + ii = atoi(gtk_entry_get_text(GTK_ENTRY(jqval))); + if (ii < 1 || ii > 100) { + zmessageACK(mWin,ZTX("jpeg quality must be 1-100")); + goto dialog_run; + } + sprintf(jpeg_quality,"%d",ii); + } + + pext = strrchr(outfile,'/'); // locate file .ext + if (pext) pext = strrchr(pext,'.'); + if (pext && ! strstr(exts,pext)) pext = 0; // keep .ext and append new v.10.12.1 + if (! pext) { + pext = outfile + strlen(outfile); // missing, add one + strcpy(pext,"."); + strcpy(pext+1,type); + } + + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(makecurrent))) // make saved file the current file? + mkcurr = 1; + + gtk_widget_destroy(fdialog); // kill dialog /// gtk bug, can crash + + err = stat(outfile,&fstat); // check if file exists + if (! err) { + yn = zmessageYN(mWin,ZTX("Overwrite file? \n %s"),outfile); // confirm overwrite + if (! yn) { + zfree(outfile); + return; + } + } + + f_save(outfile,type,bpc); // save the file + + load_fileinfo(outfile); // update search index file v.11.07 + update_search_index(outfile); + + if (mkcurr) // use the saved file as new current file + f_open(outfile,1,0,1); // and retain edit history v.11.07 + else if (samedirk(outfile,curr_file)) { // if same directory, update gallery + image_gallery(outfile,"init"); // add new file to gallery + image_gallery(0,"paint2",curr_file_posn); // refresh if active, keep position + } + + zfree(outfile); + return; +} + + +// set dialog file type from user selection of file type radio button + +void saveas_radiobutt(void *, int button) // v.9.4 +{ + cchar *filetypes[4] = { ".tif", ".tif", ".png", ".jpg" }; // v.10.9 + char *filespec; + char *filename, *pp; + + filespec = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(saveas_fchooser)); + if (! filespec) return; + filename = strrchr(filespec,'/'); + if (! filename) return; + filename = strdupz(filename+1,6,"saveas"); + pp = strrchr(filename,'.'); + if (! pp || strlen(pp) > 5) pp = filename + strlen(filename); // bugfix v.10.9.1 + strcpy(pp,filetypes[button]); + gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(saveas_fchooser),filename); + gtk_widget_show_all(saveas_fchooser); + zfree(filename); + g_free(filespec); // bugfix, leak v.10.9.1 + return; +} + + +// response function for KB key release + +void saveas_kbkey(void *, GdkEventKey *event) // v.10.5 +{ + if (event->keyval == GDK_F1) + showz_userguide(zfuncs::F1_help_topic); + return; +} + + +/**************************************************************************/ + +// set new image zoom level or magnification +// zoom: "in" zoom in in steps +// "out" zoom out in steps +// "fit" zoom out to fit window +// "100" toggle 100% and fit window + +void m_zoom(GtkWidget *, cchar *zoom) +{ + int iww, ihh, Dww, Dhh; + double scalew, scaleh, fitscale, fzoom2; + static double ratio = 0; + + if (! ratio) { + if (! zoomratio || strEqu(zoomratio,"undefined")) // bugfix 12.01.1 + zoomratio = strdupz("1.4142136"); + convSD(zoomratio,ratio); + if (ratio < 1.1 || ratio > 2.0) ratio = 1.4142136; + } + + Dww = drWin->allocation.width; // drawing window size + Dhh = drWin->allocation.height; + + if (E3pxm16) { // bugfix + iww = E3ww; + ihh = E3hh; + } + else { + iww = Fww; + ihh = Fhh; + } + + if (iww > Dww || ihh > Dhh) { // get window fit scale + scalew = 1.0 * Dww / iww; + scaleh = 1.0 * Dhh / ihh; + if (scalew < scaleh) fitscale = scalew; + else fitscale = scaleh; // window/image, < 1.0 + } + else fitscale = 1.0; // if image < window use 100% + + if (strEqu(zoom,"Zoom+")) zoom = "in"; // toolbar button, + = zoom in + if (strEqu(zoom,"Zoom-")) zoom = "fit"; // - = fit window + + if (strstr("in out",zoom)) // zoom in or out + { + convSD(zoomratio,ratio); // zoom ratio, string to double + if (! Fzoom) Fzoom = fitscale; // current zoom scale + for (fzoom2 = 0.125; fzoom2 < 4.0; fzoom2 *= ratio) // find nearest natural ratio + if (Fzoom < fzoom2 * sqrt(ratio)) break; + if (strEqu(zoom,"out")) ratio = 1.0 / ratio; // zoom out, make image smaller + Fzoom = fzoom2 * ratio; + if (Fzoom > 0.124 && Fzoom < 0.126) Fzoom = 0.125; + if (Fzoom > 0.24 && Fzoom < 0.26) Fzoom = 0.25; + if (Fzoom > 0.49 && Fzoom < 0.51) Fzoom = 0.50; + if (Fzoom > 0.99 && Fzoom < 1.01) Fzoom = 1.00; + if (Fzoom > 1.99 && Fzoom < 2.01) Fzoom = 2.00; + if (Fzoom > 3.99) Fzoom = 4.0; + if (Fzoom < fitscale) Fzoom = 0; // image < window + } + + if (strEqu(zoom,"fit")) Fzoom = 0; // zoom to fit window + + if (strEqu(zoom,"100")) { + if (Fzoom != 0) Fzoom = 0; // toggle 100% and fit window + else Fzoom = 1; + } + + if (! Fzoom) zoomx = zoomy = 0; // no req. zoom center + + mwpaint2(); // refresh window + curr_image_time = get_seconds(); // mark time of image change v.11.07 + return; +} + + +/**************************************************************************/ + +// create a new blank image with desired background color + +void m_create(GtkWidget *, cchar *) // v.11.01 +{ + int create_dialog_event(zdialog *zd, cchar *event); + + zdialog *zd; + int zstat; + char *prev_file = 0; + + zfuncs::F1_help_topic = "create"; + + if (is_syncbusy()) return; // v.11.11 + if (mod_keep()) return; // unsaved edits + if (! menulock(1)) return; // lock menus + + if (curr_file) prev_file = strdupz(curr_file); + +// file name [___________________________] .jpg // v.11.05 +// width [____] height [____] (pixels) +// color [____] + + zd = zdialog_new(ZTX("Create Blank Image"),mWin,Bdone,Bcancel,null); + zdialog_add_widget(zd,"hbox","hbf","dialog",0,"space=5"); + zdialog_add_widget(zd,"label","labf","hbf",ZTX("file name"),"space=3"); + zdialog_add_widget(zd,"entry","file","hbf","no-name","space=3|expand"); + zdialog_add_widget(zd,"label","ftype","hbf",".jpg "); + zdialog_add_widget(zd,"hbox","hbz","dialog",0,"space=5"); + zdialog_add_widget(zd,"label","space","hbz",0,"space=3"); + zdialog_add_widget(zd,"label","labw","hbz",ZTX("width")); + zdialog_add_widget(zd,"spin","width","hbz","100|9999|1|1600"); + zdialog_add_widget(zd,"label","space","hbz",0,"space=5"); + zdialog_add_widget(zd,"label","labh","hbz",ZTX("height")); + zdialog_add_widget(zd,"spin","height","hbz","100|9999|1|1000"); + zdialog_add_widget(zd,"label","space","hbz",0,"space=3"); + zdialog_add_widget(zd,"label","labp","hbz","(pixels) "); + zdialog_add_widget(zd,"hbox","hbc","dialog",0,"space=5"); + zdialog_add_widget(zd,"label","space","hbc",0,"space=3"); + zdialog_add_widget(zd,"label","labc","hbc",ZTX("color")); + zdialog_add_widget(zd,"colorbutt","color","hbc","200|200|200"); + + create_dialog_event(zd,"init"); + + zdialog_help(zd,"create"); // zdialog help topic v.11.08 + zdialog_run(zd,create_dialog_event); + zstat = zdialog_wait(zd); + zdialog_free(zd); + + if (zstat != 1) { // cancel + if (prev_file) { + f_open(prev_file,0); // back to previous file + zfree(prev_file); + mwpaint2(); + } + } + + menulock(0); + return; +} + + +// dialog event and completion function + +int create_dialog_event(zdialog *zd, cchar *event) // overhauled v.11.05 +{ + char color[20], fname[100], *filespec; + cchar *pp; + int fncc, ww, hh, err; + static int red, green, blue; + uint8 *pixel; + struct stat statb; + + if (zd->zstat != 1) return 0; // [done] + + zdialog_fetch(zd,"file",fname,100); // get new file name + strTrim2(fname); + if (*fname <= ' ') strcpy(fname,"no-name"); + fncc = strlen(fname); + + filespec = strdupz(curr_dirk,fncc+8,"create"); // make full filespec + strcat(filespec,"/"); + strcat(filespec,fname); + strcat(filespec,".jpg"); + + err = stat(filespec,&statb); // make sure it does not exist + if (! err) { + zmessageACK(mWin,"file already exists"); + zfree(filespec); + zd->zstat = 0; // keep dialog alive + return 0; + } + + if (curr_file) zfree(curr_file); // stop copy of metadata from old file + curr_file = 0; // bugfix v.11.08 + + zdialog_fetch(zd,"width",ww); // get image dimensions + zdialog_fetch(zd,"height",hh); + + zdialog_fetch(zd,"color",color,19); // get image color + pp = strField(color,"|",1); + if (pp) red = atoi(pp); + pp = strField(color,"|",2); + if (pp) green = atoi(pp); + pp = strField(color,"|",3); + if (pp) blue = atoi(pp); + + mutex_lock(&Fpixmap_lock); // lock pixmaps + + PXM_free(Fpxm8); // create new PXM image + Fpxm8 = PXM_make(ww,hh,8); + Fww = Fpxm8->ww; + Fhh = Fpxm8->hh; + pixel = (uint8 *) Fpxm8->bmp; + + for (int ii = 0; ii < ww * hh * 3; ii += 3) { + pixel[ii] = red; + pixel[ii+1] = green; + pixel[ii+2] = blue; + } + + mutex_unlock(&Fpixmap_lock); + + strcpy(jpeg_quality,def_jpeg_quality); + + err = f_save(filespec,"jpg",8); // save to disk + if (err) { + zmessageACK(mWin,"cannot save file"); + zfree(filespec); + return 0; + } + + f_open(filespec,0); // make it the current file + zfree(filespec); + + return 0; +} + + +/**************************************************************************/ + +// Delete image file - move curr_file to trash. +// Use new Linux standard trash function. // v.10.8 +// If not available, revert to Desktop folder for fotoxx trash. + +void m_trash(GtkWidget *, cchar *) +{ + int err, yn; + char *pp, trashdir[200]; + struct stat trstat; + static int gstat, trashworks = 1; // assume it works until otherwise + GError *gerror = 0; + GFile *gfile = 0; + cchar *gerrmess = ZTX("Linux standard trash is not supported. \n" + "Desktop trash folder will be created."); + + zfuncs::F1_help_topic = "trash"; // v.10.8 + + if (! curr_file) return; // nothing to trash + + if (is_syncbusy()) return; // v.11.11 + if (! menulock(1)) return; // check lock but leave unlocked + menulock(0); + + err = stat(curr_file,&trstat); // get file status + if (err) { + zmessLogACK(mWin,strerror(errno)); + return; + } + + if (! (trstat.st_mode & S_IWUSR)) { // check permission + yn = zmessageYN(mWin,ZTX("Move read-only file to trash?")); + if (! yn) return; + trstat.st_mode |= S_IWUSR; + chmod(curr_file,trstat.st_mode); + } + + if (trashworks) // try Linux standard trash + { + gfile = g_file_new_for_path(curr_file); + gstat = g_file_trash(gfile,0,&gerror); + if (! gstat) { + printf("no standard trash: %s \n",gerror->message); + zmessageACK(mWin,gerrmess); + trashworks = 0; // did not work + } + } + + if (! trashworks) + { + snprintf(trashdir,199,"%s/%s",getenv("HOME"),ftrash); // use fotoxx trash filespec + + trstat.st_mode = 0; + err = stat(trashdir,&trstat); + if (! S_ISDIR(trstat.st_mode)) { + err = mkdir(trashdir,0750); // v.11.03 + if (err) { + zmessLogACK(mWin,ZTX("Cannot create trash folder: %s"),wstrerror(errno)); + return; + } + } + + snprintf(command,ccc,"cp \"%s\" \"%s\" ",curr_file,trashdir); // copy image file to trash + err = system(command); + if (err) { + zmessLogACK(mWin,ZTX("error: %s"),wstrerror(err)); + return; + } + + err = remove(curr_file); // remove original file v.11.03 + if (err) { + zmessLogACK(mWin,ZTX("error: %s"),wstrerror(errno)); + return; + } + } + + delete_search_index(curr_file); // delete in search index file + image_gallery(0,"delete",curr_file_posn); // delete in gallery list + pp = image_gallery(0,"find",curr_file_posn); // open next file (now current position) + if (! pp) pp = image_gallery(0,"find",curr_file_posn-1); // no next, get prev. if poss. v.11.12 + if (! pp) { + free_resources(0); // leave screen blank v.11.12 + mwpaint2(); + } + else { + f_open(pp,1); // open next/prev file + zfree(pp); + image_gallery(0,"paint2",curr_file_posn); // refresh gallery window if active v.11.07 + } + + return; +} + + +/**************************************************************************/ + +// rename menu function +// activate rename dialog, stuff data from current file +// dialog remains active when new file is opened + +char rename_old[100] = ""; +char rename_new[100] = ""; + +void m_rename(GtkWidget *, cchar *menu) +{ + int rename_dialog_event(zdialog *zd, cchar *event); + + char *pdir, *pfile, *pext; + + if (menu) zfuncs::F1_help_topic = "rename"; + + if (! curr_file) return; + if (is_syncbusy()) return; // v.11.11 + + if (! zdrename) // restart dialog + { + zdrename = zdialog_new(ZTX("Rename Image File"),mWin,Bcancel,null); + zdialog_add_widget(zdrename,"hbox","hb1","dialog",0,"space=10"); + zdialog_add_widget(zdrename,"vbox","vb1","hb1",0,"homog|space=5"); + zdialog_add_widget(zdrename,"vbox","vb2","hb1",0,"homog|expand"); + + zdialog_add_widget(zdrename,"button","Bold","vb1",ZTX("old name")); + zdialog_add_widget(zdrename,"button","Bnew","vb1",ZTX("rename to")); + zdialog_add_widget(zdrename,"button","Bprev","vb1",ZTX("previous")); + + zdialog_add_widget(zdrename,"hbox","hb21","vb2",0); // [ old name ] [ oldname ] + zdialog_add_widget(zdrename,"hbox","hb22","vb2",0); // [ new name ] [ newname ] [+1] + zdialog_add_widget(zdrename,"hbox","hb23","vb2",0); // [ previous ] [ prevname ] + + zdialog_add_widget(zdrename,"label","Lold","hb21"); + zdialog_add_widget(zdrename,"entry","Enew","hb22",0,"expand|scc=30"); + zdialog_add_widget(zdrename,"button","B+1","hb22"," +1 ","space=5"); + zdialog_add_widget(zdrename,"label","Lprev","hb23"); + + zdialog_help(zdrename,"rename"); // zdialog help topic v.11.08 + zdialog_run(zdrename,rename_dialog_event); // run dialog + } + + parsefile(curr_file,&pdir,&pfile,&pext); + strncpy0(rename_old,pfile,99); + strncpy0(rename_new,pfile,99); + zdialog_stuff(zdrename,"Lold",rename_old); // current file name + zdialog_stuff(zdrename,"Enew",rename_new); // entered file name + + return; +} + + +// dialog event and completion callback function + +int rename_dialog_event(zdialog *zd, cchar *event) +{ + char *pp, *pdir, *pfile, *pext, *pnew, *pold; + int nseq, digits, ccp, ccn, ccx, err; + struct stat statb; + + if (zd->zstat) { // complete + zdialog_free(zdrename); // kill dialog + return 0; + } + + if (strEqu(event,"Bold")) // reset to current file name + zdialog_stuff(zd,"Enew",rename_old); + + if (strEqu(event,"Bprev")) { // previous name >> new name + zdialog_fetch(zd,"Lprev",rename_new,99); + zdialog_stuff(zd,"Enew",rename_new); + } + + if (strEqu(event,"B+1")) // increment sequence number + { + zdialog_fetch(zd,"Enew",rename_new,94); // get entered filename + pp = rename_new + strlen(rename_new); + digits = 0; + while (pp[-1] >= '0' && pp[-1] <= '9') { + pp--; // look for NNN in filenameNNN + digits++; + } + nseq = 1 + atoi(pp); // NNN + 1 + if (nseq > 9999) nseq = 0; + if (digits < 2) digits = 2; // keep digit count if enough + if (nseq > 99 && digits < 3) digits = 3; // use leading zeros + if (nseq > 999 && digits < 4) digits = 4; + snprintf(pp,digits+1,"%0*d",digits,nseq); + zdialog_stuff(zd,"Enew",rename_new); + } + + if (strEqu(event,"Bnew")) // [rename to] button + { + if (is_syncbusy()) return 0; // v.11.11 + if (! menulock(1)) return 0; // check lock but leave unlocked + menulock(0); + + parsefile(curr_file,&pdir,&pfile,&pext); // existing /directories/file.ext + + zdialog_fetch(zd,"Enew",rename_new,94); // new file name from user + + ccp = strlen(pdir); // length of /directories/ + ccn = strlen(rename_new); // length of file + if (pext) ccx = strlen(pext); // length of .ext + else ccx = 0; + + pnew = zmalloc(ccp + ccn + ccx + 1,"rename"); // put it all together + strncpy(pnew,curr_file,ccp); // /directories/file.ext + strcpy(pnew+ccp,rename_new); + if (ccx) strcpy(pnew+ccp+ccn,pext); + + err = stat(pnew,&statb); // check if new name exists + if (! err) { + zmessageACK(mWin,ZTX("The target file already exists")); + zfree(pnew); + return 0; + } + + snprintf(command,ccc,"cp -p \"%s\" \"%s\"",curr_file,pnew); // copy to new file -p v.10.3 + err = system(command); + if (err) { + zmessageACK(mWin,ZTX("Rename failed: \n %s"),wstrerror(err)); + printf("command: %s \n",command); + zfree(pnew); + return 0; + } + + zdialog_stuff(zd,"Lprev",rename_new); // set previous name in dialog + + load_fileinfo(pnew); // update search index file + update_search_index(pnew); + + pold = strdupz(curr_file,0,"curr_file"); // save file name to be deleted + delete_search_index(pold); // delete in search index v.9.7 + err = remove(pold); // delete file v.11.03 + + err = f_open(pnew,1); // no automatic "next" v.11.08 + image_gallery(curr_file,"init"); // update gallery v.11.05 + image_gallery(0,"paint2",curr_file_posn); // refresh gallery window if active + + zfree(pnew); + zfree(pold); + } + + return 0; +} + + +/**************************************************************************/ + +// menu function - batch rename files + +char **batchrename_filelist = 0; +int batchrename_filecount = 0; + +void m_batchrename(GtkWidget *, cchar *) // new v.9.7 +{ + int batchrename_dialog_event(zdialog *zd, cchar *event); + + zdialog *zd; + + if (zdrename) return; // interactive rename is active + + if (is_syncbusy()) return; // v.11.11 + if (mod_keep()) return; // unsaved edits + if (! menulock(1)) return; // lock menus v.10.8 + + zfuncs::F1_help_topic = "batch_rename"; // v.10.8 + + zd = zdialog_new(ZTX("Batch Rename"),mWin,Bproceed,Bcancel,null); + zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=5"); + zdialog_add_widget(zd,"button","files","hb1",Bselectfiles,"space=10"); + zdialog_add_widget(zd,"label","labcount","hb1",ZTX("%d files selected"),"space=10"); + zdialog_add_widget(zd,"hbox","hb2","dialog","space=5"); + zdialog_add_widget(zd,"label","lab2","hb2",ZTX("new base name"),"space=10"); + zdialog_add_widget(zd,"entry","basename","hb2"); + zdialog_add_widget(zd,"hbox","hb3","dialog",0,"space=5"); + zdialog_add_widget(zd,"label","lab31","hb3",ZTX("starting sequence"),"space=10"); + zdialog_add_widget(zd,"entry","sequence","hb3","100","scc=5"); + zdialog_add_widget(zd,"label","lab32","hb3",ZTX("increment"),"space=10"); + zdialog_add_widget(zd,"entry","increment","hb3","01","scc=3"); + + batchrename_filelist = 0; + batchrename_filecount = 0; + + zdialog_help(zd,"batch_rename"); // zdialog help topic v.11.08 + zdialog_run(zd,batchrename_dialog_event); // run dialog + zdialog_wait(zd); // wait for completion + + zdialog_free(zd); + menulock(0); + return; +} + + +// dialog event and completion callback function + +int batchrename_dialog_event(zdialog *zd, cchar *event) +{ + char **flist = batchrename_filelist, countmess[50]; + cchar *selectmess = ZTX("select files to rename"); + int ii, err, cc, ccp, ccn, ccx; + int sequence, increment, adder; + char basename[100], filename[120], *oldfile, *newfile; + char *pdir, *pfile, *pext; + cchar *errmess = ZTX("base name / sequence / increment not reasonable"); + struct stat statb; + + if (strEqu(event,"files")) // select images to rename + { + if (flist) { // free prior list + for (ii = 0; flist[ii]; ii++) + zfree(flist[ii]); + zfree(flist); + } + + flist = zgetfileN(selectmess,"openN",curr_file); // get file list from user + batchrename_filelist = flist; + + if (flist) // count files in list + for (ii = 0; flist[ii]; ii++); + else ii = 0; + batchrename_filecount = ii; + + snprintf(countmess,50,ZTX("%d files selected"),batchrename_filecount); + zdialog_stuff(zd,"labcount",countmess); + } + + if (! zd->zstat) return 0; // dialog active + + if (zd->zstat != 1) goto cleanup; // dialog canceled + if (! batchrename_filecount) goto cleanup; // no files selected + + zdialog_fetch(zd,"basename",basename,99); + zdialog_fetch(zd,"sequence",sequence); + zdialog_fetch(zd,"increment",increment); + + if (strlen(basename) < 1 || sequence < 1 || increment < 1) { + zd->zstat = 0; // keep dialog alive bugfix v.10.7 + zmessageACK(mWin,errmess); + return 0; + } + + write_popup_text("open","Renaming files",500,200,mWin); // status monitor popup window v.10.3 + + for (ii = 0; flist[ii]; ii++) + { + oldfile = flist[ii]; + parsefile(oldfile,&pdir,&pfile,&pext); + ccp = strlen(pdir); + if (pext) ccx = strlen(pext); + else ccx = 0; + + adder = sequence + ii * increment; + snprintf(filename,119,"%s%d",basename,adder); // removed "-" between v.10.7 + ccn = strlen(filename); + + newfile = zmalloc(ccp + ccn + ccx + 1,"rename"); // construct /path/filename.ext + strcpy(newfile,pdir); + strcpy(newfile+ccp,filename); + if (ccx) strcpy(newfile+ccp+ccn,pext); + + err = stat(newfile,&statb); + if (! err) { + snprintf(command,ccc,"%s %s",ZTX("new file already exists:"),newfile); + write_popup_text("write",command); + zfree(newfile); + break; + } + + cc = snprintf(command,ccc,"cp -p \"%s\" \"%s\"",oldfile,newfile); // copy to new file -p v.10.3 + if (cc >= maxfcc*2) { + snprintf(command,ccc,"%s %s",ZTX("filespec too long:"),oldfile); + write_popup_text("write",command); + zfree(newfile); + break; + } + + write_popup_text("write",command); // report progress + zmainloop(); + + err = system(command); + if (err) { + snprintf(command,ccc,"%s %s",ZTX("Rename failed:"),wstrerror(err)); + write_popup_text("write",command); + zfree(newfile); + break; + } + + load_fileinfo(newfile); // update search index file + update_search_index(newfile); + zfree(newfile); + + err = remove(oldfile); // delete old file v.11.03 + delete_search_index(oldfile); // remove from search index + zmainloop(); + } + + write_popup_text("write","COMPLETED"); + write_popup_text("close",0); + + image_gallery(curr_file,"init"); // update gallery file list + image_gallery(0,"paint2",curr_file_posn); // refresh gallery window if active + +cleanup: + + if (batchrename_filecount) { + for (ii = 0; flist[ii]; ii++) + zfree(flist[ii]); + zfree(flist); + batchrename_filecount = 0; // bugfix v.12.01 + } + + return 0; +} + + +/**************************************************************************/ + +// print current image file + +double print_size[2] = { 29.7, 21.0 }; // default A4 landscape +double print_margins[4] = { 0.5, 0.5, 0.5, 0.5 }; // top, bottom, left, right + +void m_print(GtkWidget *, cchar *) // use GTK print v.9.4 +{ + PXM * print_addgrid(PXM *printimage); // v.11.01 + + int err; + char *printfile; + PXM *printimage, *pxmtemp; + + zfuncs::F1_help_topic = "print"; + + if (! curr_file) return; // no image file + + printfile = strdupz(get_zuserdir(),20,"printfile"); // make temp print file: + strcat(printfile,"/printfile.tif"); // ~/.fotoxx/printfile.tif v.11.03 + + if (Fpxm16) printimage = PXM_convbpc(Fpxm16); + else printimage = PXM_copy(Fpxm8); + + pxmtemp = print_addgrid(printimage); // add grid lines if wanted v.11.01 + if (pxmtemp) { + PXM_free(printimage); + printimage = pxmtemp; + } + + err = PXBwrite(printimage,printfile); + PXM_free(printimage); + + if (err) { + zfree(printfile); // v.10.3 + return; + } + + print_image_paper_setup(mWin); // new v.11.10 + print_image_margins_setup(mWin); + print_image_file(printfile); + + zfree(printfile); + return; +} + + +// add grid lines to print image if wanted + +PXM * print_addgrid(PXM *printimage) // v.11.01 +{ + PXM *temp8; + uint8 *pixel; + int px, py, ww, hh, row; + int startx, starty, stepx, stepy; + + if (! Fgrid) return 0; // grid lines off + + temp8 = f_load(curr_file,8); + if (! temp8) return 0; + + ww = temp8->ww; + hh = temp8->hh; + row = ww * 3; + + stepx = gridspace[0]; // space between grid lines + stepy = gridspace[1]; + + stepx = stepx / Mscale; // window scale to image scale + stepy = stepy / Mscale; + + if (gridcount[0]) stepx = ww / (1 + gridcount[0]); // if line counts specified, + if (gridcount[1]) stepy = hh / ( 1 + gridcount[1]); // set spacing accordingly + + startx = stepx * gridoffset[0] / 100; // variable offsets v.11.11 + if (startx < 0) startx += stepx; + + starty = stepy * gridoffset[1] / 100; + if (starty < 0) starty += stepy; + + if (gridon[0]) { + for (px = startx; px < ww-1; px += stepx) + for (py = 0; py < hh; py++) + { + pixel = PXMpix8(temp8,px,py); // adjoining white and black lines + pixel[0] = pixel[1] = pixel[2] = 255; + pixel[3] = pixel[4] = pixel[5] = 0; + } + } + + if (gridon[1]) { + for (py = starty; py < hh-1; py += stepy) + for (px = 0; px < ww; px++) + { + pixel = PXMpix8(temp8,px,py); + pixel[0] = pixel[1] = pixel[2] = 255; + pixel[row] = pixel[row+1] = pixel[row+2] = 0; + } + } + + return temp8; +} + + +/**************************************************************************/ + +// normal quit menu function + +void m_quit(GtkWidget *, cchar *) +{ + if (mod_keep()) return; // unsaved edits + printf("quit \n"); + Fshutdown++; // bugfix v.10.11 + + for (int ii = 0; ii < 100; ii++) // wait if something running + if (Ffuncbusy) { // v.11.01 + zmainloop(); + zsleep(0.01); + } + + if (Ffuncbusy) printf("busy function killed"); // v.11.05 + + gtk_window_get_position(MWIN,&mwgeom[0],&mwgeom[1]); // get last window position v.11.07 + gtk_window_get_size(MWIN,&mwgeom[2],&mwgeom[3]); // and size for next session + save_params(); // save state for next session + zdialog_positions("save"); // save dialog positions too v.11.07 + free_resources(); // delete temp files + if (KBzmalloclog) zmalloc_report(); // report memory v.10.8 + fflush(null); // flush stdout, stderr v.11.05 + gtk_main_quit(); // gone forever + return; +} + + +/************************************************************************** + plugin menu functions +**************************************************************************/ + +// process plugin menu selection +// execute correspinding command using current image file + +editfunc EFplugin; + +void m_run_plugin(GtkWidget *, cchar *menu) // v.11.03 +{ + int ii, jj, err; + char *pp = 0, pluginfile[200]; + PXM *pxmtemp; + + zfuncs::F1_help_topic = "plugins"; + + for (ii = 0; ii < Nplugins; ii++) // search plugins for menu name + { + pp = strstr(plugins[ii]," = "); + if (! pp) continue; + *pp = 0; + jj = strEqu(plugins[ii],menu); + *pp = ' '; + if (jj) break; + } + + if (ii == Nplugins) { + zmessageACK(mWin,"plugin menu not found %s",menu); + return; + } + + pp += 3; + if (strlen(pp) < 3) { + zmessageACK(mWin,"no plugin command"); + return; + } + + strncpy0(command,pp,ccc); // corresp. command + strTrim2(command); + + EFplugin.funcname = menu; + if (! edit_setup(EFplugin)) return; // setup edit + + snprintf(pluginfile,199,"%s/plugfile.tif",get_zuserdir()); // /home/user/.fotoxx/plugfile.tif + + TIFFwrite(E1pxm16,pluginfile); // E1 >> plugin_file + + strcat(command," "); // construct: command /.../plugin_file & + strcat(command,pluginfile); + printf("plugin: %s \n",command); + + err = system(command); // execute plugin command + if (err) { + zmessageACK(mWin,"plugin command error"); + edit_cancel(EFplugin); + return; + } + + pxmtemp = TIFFread(pluginfile); // read command output file + if (! pxmtemp) { + zmessageACK(mWin,"plugin failed"); + edit_cancel(EFplugin); + return; + } + + PXM_free(E3pxm16); // plugin_file >> E3 + if (pxmtemp->bpc == 16) E3pxm16 = pxmtemp; + else { + E3pxm16 = PXM_convbpc(pxmtemp); + PXM_free(pxmtemp); + } + + EFplugin.Fmod = 1; // assume image was modified + edit_done(EFplugin); + + return; +} + + +// edit plugins menu + +void m_edit_plugins(GtkWidget *, cchar *) // v.11.03 +{ + int edit_plugins_event(zdialog *zd, cchar *event); + + int ii; + char *pp; + zdialog *zd; + + zfuncs::F1_help_topic = "plugins"; + + zd = zdialog_new("Edit Plugins",mWin,ZTX("Add"),ZTX("Remove"),Bdone,null); + zdialog_add_widget(zd,"hbox","hbm","dialog",0,"space=5"); + zdialog_add_widget(zd,"label","labm","hbm",ZTX("menu name"),"space=5"); + zdialog_add_widget(zd,"comboE","menu","hbm",0,"space=5"); + zdialog_add_widget(zd,"hbox","hbc","dialog",0,"space=5"); + zdialog_add_widget(zd,"label","labc","hbc","command","space=5"); + zdialog_add_widget(zd,"entry","command","hbc",0,"space=5|expand"); + + for (ii = 0; ii < Nplugins; ii++) // stuff combo box with available + { // plugin menu names + pp = strstr(plugins[ii]," = "); + if (! pp) continue; + *pp = 0; + zdialog_cb_app(zd,"menu",plugins[ii]); + *pp = ' '; + } + + zdialog_help(zd,"plugins"); // zdialog help topic v.11.08 + zdialog_run(zd,edit_plugins_event); + return; +} + + +// dialog event function + +int edit_plugins_event(zdialog *zd, cchar *event) +{ + int ii, jj, cc, zstat; + char menu[40], *pp = 0; + + zdialog_fetch(zd,"menu",menu,40); // selected menu + zdialog_fetch(zd,"command",command,ccc); + + if (strEqu(event,"menu")) + { + for (ii = 0; ii < Nplugins; ii++) + { + pp = strstr(plugins[ii]," = "); // find corresp. plugin record + if (! pp) continue; + *pp = 0; + jj = strEqu(plugins[ii],menu); + *pp = ' '; + if (jj) break; + } + + if (ii == Nplugins) return 0; + + pp += 3; + if (strlen(pp) < 3) return 0; + strncpy0(command,pp,ccc); + zdialog_stuff(zd,"command",command); // stuff corresp. command in dialog + + return 0; + } + + zstat = zd->zstat; + if (! zstat) return 0; + + if (zstat == 1) // add new plugin + { + if (strlen(menu) < 3 || strlen(command) < 3) return 0; + if (Nplugins == maxplugins) { + zmessageACK(mWin,"too many plugins"); + return 0; + } + ii = Nplugins; // add plugin record + cc = strlen(menu) + strlen(command) + 5; + plugins[ii] = zmalloc(cc,"plugins"); // format: menu = command + strcpy(plugins[ii],menu); + strcat(plugins[ii]," = "); + strcat(plugins[ii],command); + Nplugins++; + + zmessageACK(mWin,ZTX("Restart Fotoxx to update plugin menu")); + } + + if (zstat == 2) // remove current plugin + { + for (ii = 0; ii < Nplugins; ii++) + { + pp = strstr(plugins[ii]," = "); // find corresp. plugin record + if (! pp) continue; + *pp = 0; + jj = strEqu(plugins[ii],menu); + *pp = ' '; + if (jj) break; + } + + if (ii == Nplugins) return 0; + + Nplugins--; // remove plugin record + for (jj = ii; jj < Nplugins; jj++) + plugins[jj] = plugins[jj+1]; + + zmessageACK(mWin,ZTX("Restart Fotoxx to update plugin menu")); + } + + if (zstat == 3) { // done + zdialog_free(zd); + return 0; + } + + return 0; +} + + + diff -Nru fotoxx-11.11.1/f.info.cc fotoxx-12.01.2/f.info.cc --- fotoxx-11.11.1/f.info.cc 1970-01-01 00:00:00.000000000 +0000 +++ fotoxx-12.01.2/f.info.cc 2012-01-04 08:47:11.000000000 +0000 @@ -0,0 +1,3138 @@ +/************************************************************************** + + Fotoxx edit photos and manage collections + + Copyright 2007 2008 2009 2010 2011 2012 Michael Cornelison + Source URL: http://kornelix.squarespace.com/fotoxx + Contact: kornelix2@googlemail.com + + 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 http://www.gnu.org/licenses/. + +***************************************************************************/ + +#define EX extern // enable extern declarations +#include "fotoxx.h" + + +/************************************************************************** + + Fotoxx image editor - image metadata functions, EXIF/IPTC etc. + +***************************************************************************/ + +int get_mouse_tag(GtkTextView *, int px, int py, cchar *); // get tag selected by mouse +int add_tag(char *tag, char *taglist, int maxcc); // add tag if unique and enough space +int del_tag(char *tag, char *taglist); // remove tag from tag list +int add_recentag(char *tag); // add tag to recent tags, keep most recent +void load_deftags(); // tags_defined file >> tags_deftags[] +void save_deftags(); // tags_deftags[] >> defined_tags file +int find_deftag(char *tag); // find tag in tags_deftags[] +int add_deftag(char *catg, char *tag); // add tag to tags_deftags[] +int del_deftag(char *tag); // remove tag from tags_deftags[] +void deftags_stuff(zdialog *zd); // tags_deftags[] >> dialog widget "deftags" + +char tags_date[12] = ""; // image date, yyyymmdd +char tags_prdate[12] = ""; // previous image date read or set +char tags_stars = '0'; // image rating in stars, '0' to '5' +char tags_cliktag[tagcc] = ""; // tag clicked by mouse +char tags_clikcatg[tagcc] = ""; // category clicked by mouse +char *tags_deftags[maxtagcats]; // defined tags: catg: tag1, tag2, ... tagN, +char tags_deftext[tagTcc] = ""; // defined tags as flat text buffer +char tags_filetags[tagFcc] = ""; // tags for current image file +char tags_recentags[tagRcc] = ""; // recently added tags list +char tags_batchAddTags[tagMcc] = ""; // batch add tags list +char tags_searchtags[tagScc] = ""; // search tags list +char tags_searchtext[tagScc] = ""; // search comments & captions word list +char tags_searchfiles[tagScc] = ""; // search files list +char tags_comments[tagFcc]; // image comments +char tags_caption[tagFcc]; // image caption + + +/**************************************************************************/ + +// View and edit IPTC Caption and EXIF UserComment data + +void m_edit_cctext(GtkWidget *, cchar *menu) // 2 functions combined v.11.09 +{ + int edit_cctext_dialog_event(zdialog *zd, cchar *event); + char text[tagFcc]; + cchar *title = ZTX("Edit Caption and Comments"); + + if (menu) zfuncs::F1_help_topic = "edit_cctext"; + + if (! curr_file) return; + + if (! Fexiftool) { // exiftool is required + zmessageACK(mWin,Bexiftoolmissing); + return; + } + + if (! zdeditcctext) // popup dialog if not already + { + zdeditcctext = zdialog_new(title,mWin,Bapply,Bcancel,null); + zdialog *zd = zdeditcctext; + zdialog_add_widget(zd,"hbox","hbcap","dialog"); + zdialog_add_widget(zd,"label","labcap","hbcap","Caption","space=5"); + zdialog_add_widget(zd,"frame","framecap","hbcap",0,"expand"); + zdialog_add_widget(zd,"edit","textcap","framecap",0,"space=5|wrap"); + zdialog_add_widget(zd,"hbox","hbcom","dialog"); + zdialog_add_widget(zd,"label","labcom","hbcom","Comments","space=5"); + zdialog_add_widget(zd,"frame","framecom","hbcom",0,"expand"); + zdialog_add_widget(zd,"edit","textcom","framecom",0,"space=5|wrap"); + zdialog_resize(zd,300,0); + zdialog_help(zd,"edit_cctext"); // zdialog help topic v.11.08 + zdialog_run(zd,edit_cctext_dialog_event); + } + + load_fileinfo(curr_file); // get current caption and comments + repl_1str(tags_caption,text,"\\n","\n"); // replace "\n" with real newlines + zdialog_stuff(zdeditcctext,"textcap",text); // stuff into dialog + repl_1str(tags_comments,text,"\\n","\n"); // replace "\n" with real newlines + zdialog_stuff(zdeditcctext,"textcom",text); // stuff into dialog + + return; +} + + +// dialog event and completion callback function + +int edit_cctext_dialog_event(zdialog *zd, cchar *event) +{ + char text[tagFcc]; + + if (! zd->zstat) return 0; + + else if (zd->zstat == 1) // apply, save text + { + zd->zstat = 0; // keep dialog active + if (is_syncbusy()) return 0; // must wait for file sync v.11.11 + zdialog_fetch(zd,"textcap",text,tagFcc); // get new cctext + repl_1str(text,tags_caption,"\n","\\n"); // replace newlines with "\n" + zdialog_fetch(zd,"textcom",text,tagFcc); // get new cctext + repl_1str(text,tags_comments,"\n","\\n"); // replace newlines with "\n" + Ftagschanged = 1; + save_fileinfo(curr_file); // save in image file + } + + else zdialog_free(zdeditcctext); // cancel + + return 1; +} + + +/**************************************************************************/ + +// edit tags menu function + +void m_edit_tags(GtkWidget *, cchar *menu) +{ + void edittags_fixwidget(zdialog *, cchar * widgetname); // fix tags widget for selecting with mouse + int edittags_dialog_event(zdialog *zd, cchar *event); + + char *ppv, starsN[12]; + + if (menu) zfuncs::F1_help_topic = "edit_tags"; + + if (! Fexiftool) { // exiftool is required + zmessageACK(mWin,Bexiftoolmissing); + return; + } + + if (! curr_file) return; + + if (! zdedittags) // (re) start tag edit dialog + { + zdedittags = zdialog_new(ZTX("Edit Tags"),mWin,Bapply,Bcancel,null); + + zdialog_add_widget(zdedittags,"hbox","hb1","dialog",0,"space=5"); + zdialog_add_widget(zdedittags,"label","labfile","hb1",ZTX("file:"),"space=5"); + zdialog_add_widget(zdedittags,"label","file","hb1"); + + zdialog_add_widget(zdedittags,"hbox","hb2","dialog",0,"space=5"); + zdialog_add_widget(zdedittags,"label","lab21","hb2",ZTX("image date (yyyymmdd)"),"space=5"); + zdialog_add_widget(zdedittags,"entry","date","hb2",0,"scc=12"); + zdialog_add_widget(zdedittags,"button","prdate","hb2",ZTX("use last"),"space=5"); + + zdialog_add_widget(zdedittags,"hbox","hb3","dialog",0,"space=5"); + zdialog_add_widget(zdedittags,"label","labstars","hb3",ZTX("image stars"),"space=5"); + zdialog_add_widget(zdedittags,"vbox","vb3","hb3"); + zdialog_add_widget(zdedittags,"hbox","hb31","vb3",0,"homog"); + zdialog_add_widget(zdedittags,"hbox","hb32","vb3",0,"homog"); + zdialog_add_widget(zdedittags,"label","lab30","hb31","0"); + zdialog_add_widget(zdedittags,"label","lab31","hb31","1"); + zdialog_add_widget(zdedittags,"label","lab32","hb31","2"); + zdialog_add_widget(zdedittags,"label","lab33","hb31","3"); + zdialog_add_widget(zdedittags,"label","lab34","hb31","4"); + zdialog_add_widget(zdedittags,"label","lab35","hb31","5"); + zdialog_add_widget(zdedittags,"radio","stars0","hb32",0); + zdialog_add_widget(zdedittags,"radio","stars1","hb32",0); + zdialog_add_widget(zdedittags,"radio","stars2","hb32",0); + zdialog_add_widget(zdedittags,"radio","stars3","hb32",0); + zdialog_add_widget(zdedittags,"radio","stars4","hb32",0); + zdialog_add_widget(zdedittags,"radio","stars5","hb32",0); + + zdialog_add_widget(zdedittags,"hbox","hb4","dialog",0,"space=5"); + zdialog_add_widget(zdedittags,"label","lab4","hb4",ZTX("current tags"),"space=5"); + zdialog_add_widget(zdedittags,"frame","frame4","hb4",0,"expand"); + zdialog_add_widget(zdedittags,"edit","filetags","frame4",0,"expand|wrap"); // v.11.06 + + zdialog_add_widget(zdedittags,"hbox","hb5","dialog",0,"space=5"); + zdialog_add_widget(zdedittags,"label","recent","hb5",ZTX("recent tags"),"space=5"); + zdialog_add_widget(zdedittags,"frame","frame5","hb5",0,"expand"); + zdialog_add_widget(zdedittags,"edit","recentags","frame5",0,"expand|wrap"); // v.11.06 + + zdialog_add_widget(zdedittags,"hbox","hb8","dialog"); + zdialog_add_widget(zdedittags,"label","labdeftags","hb8",ZTX("defined tags"),"space=5"); + zdialog_add_widget(zdedittags,"hbox","hb9","dialog",0,"expand"); + zdialog_add_widget(zdedittags,"frame","frame8","hb9",0,"space=5|expand"); + zdialog_add_widget(zdedittags,"scrwin","scrwin8","frame8",0,"expand"); + zdialog_add_widget(zdedittags,"edit","deftags","scrwin8",0,"expand|wrap"); // v.11.06 + + zdialog_resize(zdedittags,500,500); // run dialog + zdialog_help(zdedittags,"edit_tags"); // zdialog help topic v.11.08 + zdialog_run(zdedittags,edittags_dialog_event); + + edittags_fixwidget(zdedittags,"filetags"); // setup for mouse tag selection + edittags_fixwidget(zdedittags,"recentags"); + edittags_fixwidget(zdedittags,"deftags"); + + load_deftags(); // stuff defined tags into dialog + deftags_stuff(zdedittags); + } + + load_fileinfo(curr_file); // get EXIF/IPTC data + + ppv = (char *) strrchr(curr_file,'/'); + zdialog_stuff(zdedittags,"file",ppv+1); // stuff dialog file name + + zdialog_stuff(zdedittags,"date",tags_date); // stuff dialog data + sprintf(starsN,"stars%c",tags_stars); + zdialog_stuff(zdedittags,starsN,1); + zdialog_stuff(zdedittags,"filetags",tags_filetags); + zdialog_stuff(zdedittags,"recentags",tags_recentags); + + return; +} + + +// setup tag display widget for tag selection using mouse clicks + +void edittags_fixwidget(zdialog *zd, cchar * widgetname) +{ + void edittags_mouse(GtkTextView *, GdkEventButton *, cchar *); // select tag via mouse click + + GtkWidget *widget; + GdkWindow *gdkwin; + + widget = zdialog_widget(zd,widgetname); // make widget wrap text + gtk_text_view_set_editable(GTK_TEXT_VIEW(widget),0); // disable widget editing + + gdkwin = gtk_text_view_get_window(GTK_TEXT_VIEW(widget),TEXTWIN); // cursor for tag selection + gdk_window_set_cursor(gdkwin,arrowcursor); + + gtk_widget_add_events(widget,GDK_BUTTON_PRESS_MASK); // connect mouse-click event + G_SIGNAL(widget,"button-press-event",edittags_mouse,widgetname); +} + + +// edit tags mouse-click event function +// get clicked tag and add to or remove from file tags and recent tags + +void edittags_mouse(GtkTextView *widget, GdkEventButton *event, cchar *widgetname) +{ + int mpx, mpy; + + if (event->type != GDK_BUTTON_PRESS) return; + mpx = int(event->x); // mouse click position + mpy = int(event->y); + + get_mouse_tag(widget,mpx,mpy,widgetname); // tags_cliktag = clicked tag in list + if (! *tags_cliktag) return; + + if (strEqu(widgetname,"filetags")) { // remove tag from file tags + del_tag(tags_cliktag,tags_filetags); + zdialog_stuff(zdedittags,"filetags",tags_filetags); // update dialog widgets + } + + if (strEqu(widgetname,"recentags")) { // add recent tag to file tags + add_tag(tags_cliktag,tags_filetags,tagFcc); + zdialog_stuff(zdedittags,"filetags",tags_filetags); + } + + if (strEqu(widgetname,"deftags")) { // add defined tag to file tags + add_tag(tags_cliktag,tags_filetags,tagFcc); + zdialog_stuff(zdedittags,"filetags",tags_filetags); + add_recentag(tags_cliktag); // and to recent tags + zdialog_stuff(zdedittags,"recentags",tags_recentags); + } + + *tags_cliktag = 0; + return; +} + + +// dialog event and completion callback function + +int edittags_dialog_event(zdialog *zd, cchar *event) +{ + int err; + + if (zd->zstat) { + if (zd->zstat == 1) { // [apply] + zd->zstat = 0; // keep dialog active + if (is_syncbusy()) return 0; // must wait for file sync v.11.11 + save_fileinfo(curr_file); // save tag changes + return 0; + } + + zdialog_free(zdedittags); // cancel - kill dialog + return 0; + } + + if (strEqu(event,"date")) { // image date revised + err = zdialog_fetch(zd,"date",tags_date,11); + if (err) return 1; + if (strlen(tags_date) == 4) strcat(tags_date,"0101"); // yyyy >> yyyy0101 + if (strlen(tags_date) == 6) strcat(tags_date,"01"); // yyyymm >> yyyymm01 + Ftagschanged++; + } + + if (strEqu(event,"prdate")) { // repeat last date used + if (*tags_prdate) { + zdialog_stuff(zd,"date",tags_prdate); + strcpy(tags_date,tags_prdate); + Ftagschanged++; + } + } + + if (strnEqu(event,"stars",5)) { // event = stars0 to stars5 + tags_stars = event[5]; // '0' to '5' + Ftagschanged++; + } + + if (strEqu(event,"tags-changed")) // get new defined tags data + deftags_stuff(zdedittags); // v.11.02 + + return 0; +} + + +/**************************************************************************/ + +// manage tags menu function + +zdialog *zdmanagetags = 0; + +void m_manage_tags(GtkWidget *, cchar *) // v.11.02 - separate edit and manage tags +{ + void managetags_fixwidget(zdialog *, cchar * widgetname); // fix tags widget for selecting with mouse + int managetags_dialog_event(zdialog *zd, cchar *event); + + zfuncs::F1_help_topic = "manage_tags"; + + if (zdmanagetags) return; + zdmanagetags = zdialog_new(ZTX("Manage Tags"),mWin,Bcancel,null); + + zdialog_add_widget(zdmanagetags,"hbox","hb7","dialog",0,"space=5"); + zdialog_add_widget(zdmanagetags,"label","labcatg","hb7",ZTX("category"),"space=5"); + zdialog_add_widget(zdmanagetags,"entry","catg","hb7",0,"scc=12"); + zdialog_add_widget(zdmanagetags,"label","space","hb7",0,"space=5"); + zdialog_add_widget(zdmanagetags,"label","labtag","hb7",ZTX("tag"),"space=5"); + zdialog_add_widget(zdmanagetags,"entry","tag","hb7",0,"scc=20|expand"); + zdialog_add_widget(zdmanagetags,"label","space","hb7",0,"space=5"); + zdialog_add_widget(zdmanagetags,"button","create","hb7",ZTX("create")); + zdialog_add_widget(zdmanagetags,"button","delete","hb7",ZTX("delete")); + + zdialog_add_widget(zdmanagetags,"hbox","hb8","dialog"); + zdialog_add_widget(zdmanagetags,"label","labdeftags","hb8",ZTX("defined tags"),"space=5"); + zdialog_add_widget(zdmanagetags,"hbox","hb9","dialog",0,"expand"); + zdialog_add_widget(zdmanagetags,"frame","frame8","hb9",0,"space=5|expand"); + zdialog_add_widget(zdmanagetags,"scrwin","scrwin8","frame8",0,"expand"); + zdialog_add_widget(zdmanagetags,"edit","deftags","scrwin8",0,"expand|wrap"); // v.11.06 + + zdialog_resize(zdmanagetags,0,400); // run dialog + zdialog_help(zdmanagetags,"manage_tags"); // zdialog help topic v.11.08 + zdialog_run(zdmanagetags,managetags_dialog_event); + + managetags_fixwidget(zdmanagetags,"deftags"); // setup for mouse tag selection + + load_deftags(); // stuff defined tags into dialog + deftags_stuff(zdmanagetags); + + return; +} + + +// setup tag display widget for tag selection using mouse clicks + +void managetags_fixwidget(zdialog *zd, cchar * widgetname) +{ + void managetags_mouse(GtkTextView *, GdkEventButton *, cchar *); // select tag via mouse click + + GtkWidget *widget; + GdkWindow *gdkwin; + + widget = zdialog_widget(zd,widgetname); // make widget wrap text + gtk_text_view_set_editable(GTK_TEXT_VIEW(widget),0); // disable widget editing + + gdkwin = gtk_text_view_get_window(GTK_TEXT_VIEW(widget),TEXTWIN); // cursor for tag selection + gdk_window_set_cursor(gdkwin,arrowcursor); + + gtk_widget_add_events(widget,GDK_BUTTON_PRESS_MASK); // connect mouse-click event + G_SIGNAL(widget,"button-press-event",managetags_mouse,widgetname); +} + + +// manage tags mouse-click event function +// get clicked tag category or tag name + +void managetags_mouse(GtkTextView *widget, GdkEventButton *event, cchar *widgetname) +{ + int mpx, mpy, cc; + + if (event->type != GDK_BUTTON_PRESS) return; + mpx = int(event->x); // mouse click position + mpy = int(event->y); + + cc = get_mouse_tag(widget,mpx,mpy,widgetname); // tags_cliktag = clicked tag in list + + if (! cc) { + if (*tags_clikcatg) // selected category >> dialog widget + zdialog_stuff(zdmanagetags,"catg",tags_clikcatg); + return; + } + + zdialog_stuff(zdmanagetags,"tag",tags_cliktag); // selected tag >> dialog widget + return; +} + + +// dialog event and completion callback function + +int managetags_dialog_event(zdialog *zd, cchar *event) +{ + char tag[tagcc], catg[tagcc]; + int changed = 0; + + if (zd->zstat) { + zdialog_free(zdmanagetags); + return 0; + } + + if (strEqu(event,"create")) { // add new tag to defined tags + zdialog_fetch(zd,"catg",catg,tagcc); + zdialog_fetch(zd,"tag",tag,tagcc); + add_deftag(catg,tag); + changed++; + } + + if (strEqu(event,"delete")) { // remove tag from defined tags + zdialog_fetch(zd,"tag",tag,tagcc); + del_deftag(tag); + changed++; + } + + if (changed) { + save_deftags(); // save tag updates to file + deftags_stuff(zdmanagetags); // update dialog "deftags" window + if (zdedittags) // and edit tags window if active + zdialog_send_event(zdedittags,"tags-changed"); + } + + return 0; +} + + +/**************************************************************************/ + +// Convert mouse click position in a tag list into the selected tag. +// cc of selected tag is returned, or zero if no tag clicked. +// Selected tag is returned in tags_cliktag, or null if no tag clicked. +// If a category is clicked, it is returned in tags_clikcatg and zero is returned. + +int get_mouse_tag(GtkTextView *widget, int mpx, int mpy, cchar *widgetname) +{ + GtkTextIter iter; + int tbx, tby, offset, cc; + char *ptext, *pp1, *pp2; + + *tags_cliktag = *tags_clikcatg = 0; // start with no tag or category v.11.05 + + gtk_text_view_window_to_buffer_coords(widget,GTK_TEXT_WINDOW_TEXT,mpx,mpy,&tbx,&tby); + gtk_text_view_get_iter_at_location(widget,&iter,tbx,tby); + offset = gtk_text_iter_get_offset(&iter); // graphic position in widget text + + ptext = 0; + if (strEqu(widgetname,"filetags")) ptext = tags_filetags; // get corresponding text + if (strEqu(widgetname,"recentags")) ptext = tags_recentags; + if (strEqu(widgetname,"batchAddTags")) ptext = tags_batchAddTags; + if (strEqu(widgetname,"searchtags")) ptext = tags_searchtags; + if (strEqu(widgetname,"deftags")) ptext = tags_deftext; + if (! ptext) return 0; + + pp1 = ptext + utf8_position(ptext,offset); // graphic position to byte position + + if (! *pp1 || strchr(tagdelims":\n",*pp1)) return 0; // reject edge position or delimiter + while (pp1 > ptext && ! strchr(tagdelims":\n",pp1[-1])) pp1--; // find start of tag + pp2 = pp1; + while (pp2[1] && ! strchr(tagdelims":\n",pp2[1])) pp2++; // find following delimiter including ":" + while (*pp1 == ' ') pp1++; // no leading or trailing blanks + while (*pp2 == ' ') pp2--; + cc = pp2 - pp1 + 1; + if (cc <= 1) return 0; // reject tag < 2 chars. + if (cc >= tagcc) return 0; // reject tag too big + if (pp2[1] == ':') { + strncpy0(tags_clikcatg,pp1,cc+1); // tags_clikcatg = selected category + return 0; // return 0 + } + strncpy0(tags_cliktag,pp1,cc+1); // tags_cliktag = selected tag + return cc; // return cc +} + + +/**************************************************************************/ + +// add input tag to output tag list if not already there and enough room +// returns: 0 = added OK 1 = not unique (case ignored) +// 2 = overflow 3 = bad utf8 characters 4 = null tag + +int add_tag(char *tag, char *taglist, int maxcc) +{ + char *pp1, *pp2, tag1[tagcc], tag2[tagcc]; + int cc, cc1, cc2; + + strncpy0(tag1,tag,tagcc); // remove leading and trailing blanks + cc = strTrim2(tag2,tag1); + if (! cc) return 4; + + if (utf8_check(tag2)) { // check for valid utf8 encoding + printf("bad utf8 characters: %s \n",tag2); + return 3; + } + + while ((pp1 = strpbrk(tag2,tagdelims":"))) *pp1 = '-'; // replace problem characters + + strcpy(tag,tag2); // replace tag with sanitized version + + pp1 = taglist; + cc1 = strlen(tag); + + while (true) // check if already in tag list + { + while (*pp1 == ' ' || *pp1 == tagdelim1) pp1++; + if (! *pp1) break; + pp2 = pp1 + 1; + while (*pp2 && *pp2 != tagdelim1) pp2++; + cc2 = pp2 - pp1; + if (cc2 == cc1 && strncaseEqu(tag,pp1,cc1)) return 1; + pp1 = pp2; + } + + cc2 = strlen(taglist); // append to tag list if space enough + if (cc1 + cc2 + 3 > maxcc) return 2; + strcpy(taglist + cc2,tag); + strcpy(taglist + cc2 + cc1, tagdelim2); // add delimiter + space + + if (taglist == tags_filetags) // image tags were changed + Ftagschanged++; + return 0; +} + + +// remove tag from taglist, if present +// returns: 0 if found and deleted, otherwise 1 + +int del_tag(char *tag, char *taglist) +{ + int ii, ftcc, atcc, found; + char *temptags; + cchar *pp; + + temptags = strdupz(taglist,0,"del_tag"); + + *taglist = 0; + ftcc = found = 0; + + for (ii = 1; ; ii++) + { + pp = strField(temptags,tagdelims,ii); // next tag + if (! pp) { + zfree(temptags); + if (found && taglist == tags_filetags) // image tags were changed + Ftagschanged++; + return 1-found; + } + if (*pp == ' ') continue; + + if (strcaseEqu(pp,tag)) { // skip matching tag + found = 1; + continue; + } + + atcc = strlen(pp); // copy non-matching tag + strcpy(taglist + ftcc, pp); + ftcc += atcc; + strcpy(taglist + ftcc, tagdelim2); // + delim + blank + ftcc += 2; + } +} + + +// add new tag to recent tags, if not already. +// remove oldest to make space if needed. + +int add_recentag(char *tag) +{ + int err; + char *pp, temptags[tagRcc]; + + err = add_tag(tag,tags_recentags,tagRcc); // add tag to recent tags + + while (err == 2) // overflow + { + strncpy0(temptags,tags_recentags,tagRcc); // remove oldest to make room + pp = strpbrk(temptags,tagdelims); + if (! pp) return 0; + strcpy(tags_recentags,pp+2); // delimiter + blank before tag + err = add_tag(tag,tags_recentags,tagRcc); + } + + return 0; +} + + +/**************************************************************************/ + +// Load tags_defined file into tags_deftags[ii] => category: tag1, tag2, ... +// Read search_index file and add unmatched tags: => nocatg: tag1, tag2, ... + +void load_deftags() +{ + int tags_Ucomp(cchar *tag1, cchar *tag2); + + static int Floaded = 0; + FILE *fid; + int ii, jj, ntags, err, cc, tcc; + int ncats, catoverflow; + int nocat, nocatcc; + char tag[tagcc], catg[tagcc]; + char tagsbuff[tagGcc]; + char *pp1, *pp2; + char ptags[tagntc][tagcc]; + + if (Floaded) return; // use memory tags if already there v.11.02 + Floaded++; + + for (ii = 0; ii < maxtagcats; ii++) // clean memory + tags_deftags[ii] = 0; + + ncats = catoverflow = 0; + + fid = fopen(tags_defined_file,"r"); // read tags_defined file + if (fid) { + while (true) { + pp1 = fgets_trim(tagsbuff,tagGcc,fid); + if (! pp1) break; + if (ncats == maxtagcats-1) goto toomanycats; + pp2 = strchr(pp1,':'); // isolate "category:" + if (! pp2) continue; // reject bad data + cc = pp2 - pp1 + 1; + if (cc > tagcc-1) continue; + strncpy0(catg,pp1,cc); // (for error message) + if (strlen(pp1) > tagGcc-2) goto cattoobig; + pp2++; + while (*pp2 == ' ') pp2++; + if (strlen(pp2) < 3) continue; + while ((pp2 = strpbrk(pp2,tagdelims))) *pp2++ = tagdelim1; // force comma delimiter v.11.02 + tags_deftags[ncats] = strdupz(pp1,0,"def_tags"); // tags_deftags[ii] + ncats++; // = category: tag1, tag2, ... tagN, + } + err = fclose(fid); + if (err) goto deftagserr; + } + + nocat = ncats; // make last category "nocatg" for + ncats++; // unmatched tags in search_index file + tags_deftags[nocat] = zmalloc(tagGcc,"deftags"); + strcpy(tags_deftags[nocat],"nocatg: "); + nocatcc = 8; + + fid = fopen(search_index_file,"r"); // read search_index file + if (! fid) return; + + while (true) + { + pp1 = fgets_trim(tagsbuff,tagGcc,fid); // next image file tags record + if (! pp1) break; + if (strnNeq(tagsbuff,"tags: ",6)) continue; + pp1 = pp1 + 6; + + while (true) + { + while (*pp1 && strchr(tagdelims" ",*pp1)) pp1++; // next image tag start + if (! *pp1) break; + pp2 = strpbrk(pp1,tagdelims); // end + if (! pp2) pp2 = pp1 + strlen(pp1); + cc = pp2 - pp1; + if (cc > tagcc-1) { + pp1 = pp2; // bugfix v.10.9 + continue; // ignore huge tag + } + + strncpy0(tag,pp1,cc+1); // look for tag in defined tags + err = find_deftag(tag); + if (! err) { // found + pp1 = pp2; + continue; + } + + if (nocatcc + cc + 2 > tagGcc-2) { + catoverflow = 1; // nocatg: length limit reached + break; + } + else { + strcpy(tags_deftags[nocat] + nocatcc, tag); // append tag to list + nocatcc += cc; + strcpy(tags_deftags[nocat] + nocatcc, tagdelim2); // + delim + blank + nocatcc += 2; + } + + pp1 = pp2; + } + } + + err = fclose(fid); + if (err) goto filetagserr; + if (catoverflow) goto cattoobig; + +// parse all the tags in each category and sort in ascending order + + for (ii = 0; ii < ncats; ii++) + { + pp1 = tags_deftags[ii]; + pp2 = strchr(pp1,':'); + cc = pp2 - pp1 + 1; + strncpy0(catg,pp1,cc); + pp1 = pp2 + 1; + while (*pp1 == ' ') pp1++; + tcc = 0; + + for (jj = 0; jj < tagntc; jj++) + { + if (! *pp1) break; + pp2 = strchr(pp1,tagdelim1); + if (pp2) cc = pp2 - pp1; + else cc = strlen(pp1); + if (cc > tagcc-1) cc = tagcc-1; + strncpy0(ptags[jj],pp1,cc+1); + pp1 += cc + 1; + tcc += cc; + while (*pp1 == ' ') pp1++; + } + + ntags = jj; + if (ntags == tagntc) goto cattoobig; + HeapSort((char *) ptags,tagcc,ntags,tags_Ucomp); + + pp1 = tags_deftags[ii]; + tcc += strlen(catg) + 2 + 2 * ntags + 2; // category, all tags, delimiters + pp2 = zmalloc(tcc,"deftags"); + + tags_deftags[ii] = pp2; // swap memory + zfree(pp1); + + strcpy(pp2,catg); + pp2 += strlen(catg); + strcpy(pp2,": "); // pp2 = "category: " + pp2 += 2; + + for (jj = 0; jj < ntags; jj++) // add the sorted tags + { + strcpy(pp2,ptags[jj]); // append tag + delim + blank + pp2 += strlen(pp2); + strcpy(pp2,tagdelim2); + pp2 += 2; + } + + *pp2 = 0; + } + +// sort the categories in ascending order +// leave "nocatg" at the end + + for (ii = 0; ii < ncats-1; ii++) + for (jj = ii+1; jj < ncats-1; jj++) // v.11.02 + { + pp1 = tags_deftags[ii]; + pp2 = tags_deftags[jj]; + if (strcasecmp(pp1,pp2) > 0) { + tags_deftags[ii] = pp2; + tags_deftags[jj] = pp1; + } + } + + return; + +toomanycats: + zmessLogACK(mWin,"more than %d categories",maxtagcats); + fclose(fid); + return; + +cattoobig: + zmessLogACK(mWin,"category %s is too big",catg); + fclose(fid); + return; + +deftagserr: + zmessLogACK(mWin,"tags_defined file error: %s",strerror(errno)); + return; + +filetagserr: + zmessLogACK(mWin,"search_index file error: %s",strerror(errno)); + return; +} + + +// compare function for tag sorting +// wcscasecmp does not work for plain ascii +// so what happens to Chinese, etc? + +int tags_Ucomp(cchar *tag1, cchar *tag2) +{ + return strcasecmp(tag1,tag2); +} + + +// write tags_deftags[] memory data to the defined tags file if any changes were made + +void save_deftags() +{ + int ii, err; + FILE *fid; + + fid = fopen(tags_defined_file,"w"); // write tags_defined file + if (! fid) goto deftagserr; + + for (ii = 0; ii < maxtagcats; ii++) + { + if (! tags_deftags[ii+1]) break; // omit last category, "nocatg" + err = fprintf(fid,"%s\n",tags_deftags[ii]); // each record: + if (err < 0) goto deftagserr; // category: tag1, tag2, ... tagN, + } + + err = fclose(fid); + if (err) goto deftagserr; + return; + +deftagserr: + zmessLogACK(mWin,"tags_defined file error: %s",strerror(errno)); + return; +} + + +// find a given tag in tags_deftags[] +// return: 0 = found, 1 = not found + +int find_deftag(char *tag) +{ + int ii, cc; + char tag2[tagcc+4]; + char *pp; + + if (! tag || *tag <= ' ') return 0; // bad tag + + strncpy0(tag2,tag,tagcc); // construct tag + delim + blank + cc = strlen(tag2); + strcpy(tag2+cc,tagdelim2); + cc += 2; + + for (ii = 0; ii < maxtagcats; ii++) + { + pp = tags_deftags[ii]; // category: tag1, tag2, ... tagN, + if (! pp) return 1; // not found + + while (pp) + { + pp = strcasestr(pp,tag2); // look for delim + blank + tag + delim + if (! pp) break; + if (strchr(tagdelims":", pp[-2])) return 0; + pp += cc; + } + } + + return 1; +} + + +// add new tag to tags_deftags[] >> category: tag1, tag2, ... newtag, +// returns: 0 = added OK 1 = not unique (case ignored) +// 2 = overflow 3 = bad utf8 characters 4 = null tag +// if tag present under another category, it is moved to new category + +int add_deftag(char *catg, char *tag) +{ + int ii, cc, cc1, cc2; + char tag1[tagcc], tag2[tagcc]; + char *pp1, *pp2; + + strncpy0(tag1,tag,tagcc); // remove leading and trailing blanks + cc = strTrim2(tag2,tag1); + if (! cc) return 4; + + if (utf8_check(tag2)) { // check for valid utf8 encoding + printf("bad utf8 characters: %s \n",tag2); + return 3; + } + + while ((pp1 = strpbrk(tag2,tagdelims":"))) *pp1 = '-'; // replace problem characters + + strcpy(tag,tag2); // replace tag with sanitized version + + del_deftag(tag); // delete if already there + + if (! catg || *catg <= ' ') catg = (char *) "nocatg"; + + cc1 = strlen(catg); + + for (ii = 0; ii < maxtagcats; ii++) // look for given category + { + pp1 = tags_deftags[ii]; + if (! pp1) goto newcatg; + if (! strnEqu(catg,pp1,cc1)) continue; + if (pp1[cc1] == ':') goto oldcatg; + } + +newcatg: + if (ii == maxtagcats) goto toomanycats; + cc1 = strlen(catg) + strlen(tag) + 6; + pp1 = zmalloc(cc1,"deftags"); + *pp1 = 0; + strncatv(pp1,cc1,catg,": ",tag,tagdelim2,null); // category: + tag + delim + blank + tags_deftags[ii] = tags_deftags[ii-1]; // move "nocatg" record to next slot + tags_deftags[ii-1] = pp1; // insert new record before + return 0; + +oldcatg: + cc1 = strlen(tag); + pp2 = pp1 + 2; + while (true) { + pp2 = strcasestr(pp2,tag); // look for delim + blank + tag + delim + if (! pp2) break; // or colon + blank + tag + delim + if (strchr(tagdelims,pp2[cc]) && strchr(tagdelims":", pp2[-2])) + return 1; // tag not unique + pp2 += cc1; + } + cc2 = strlen(pp1); // add new tag to old record + if (cc1 + cc2 + 4 > tagGcc) goto cattoobig; + pp2 = strdupz(pp1,cc2+4,"def_tags"); // expand string + zfree(pp1); + tags_deftags[ii] = pp2; + strcpy(pp2+cc2,tag); // old record + tag + delim + blank + strcpy(pp2+cc2+cc1,tagdelim2); + return 0; + +toomanycats: + zmessLogACK(mWin,"more than %d categories",maxtagcats); + return 2; + +cattoobig: + zmessLogACK(mWin,"category is too big"); + return 2; +} + + +// delete tag from defined tags list, tags_deftags[] +// return: 0 = found and deleted, 1 = not found + +int del_deftag(char *tag) +{ + int ii, cc; + char tag2[tagcc+4]; + char *pp, *pp1, *pp2; + + if (! tag || *tag <= ' ') return 1; // bad tag + + strncpy0(tag2,tag,tagcc); // construct tag + delim + blank + cc = strlen(tag2); + strcpy(tag2+cc,tagdelim2); + cc += 2; + + for (ii = 0; ii < maxtagcats; ii++) + { + pp = tags_deftags[ii]; + if (! pp) return 1; // not found + + while (pp) + { + pp = strcasestr(pp,tag2); // look for prior delim or colon + if (! pp) break; + if (strchr(tagdelims":", pp[-2])) goto found; + pp += cc; + } + } + +found: + for (pp1 = pp, pp2 = pp+cc; *pp2; pp1++, pp2++) // eliminate tag, delim, blank + *pp1 = *pp2; + *pp1 = 0; + + return 0; +} + + +// stuff tags_deftags[] into given text widget and format by category +// create tags_deftext with flat list of tags for mouse clicking + +void deftags_stuff(zdialog *zd) +{ + GtkWidget *widget; + GtkTextBuffer *textbuff; + GtkTextIter iter1, iter2; + int ii, cc; + char catgname[tagcc+3]; + char *pp1, *pp2; + + widget = zdialog_widget(zd,"deftags"); + wclear(widget); + + for (ii = 0; ii < maxtagcats; ii++) + { + pp1 = tags_deftags[ii]; + if (! pp1) break; + pp2 = strchr(pp1,':'); + if (! pp2) continue; + if (pp2 > pp1 + tagcc-3) continue; + pp2 += 2; + cc = pp2 - pp1 + 1; + strncpy0(catgname,pp1,cc); + wprintx(widget,0,catgname,"monospace bold 9"); + if (*pp2) wprintx(widget,0,pp2,"monospace 9"); + wprintx(widget,0,"\n"); + } + + textbuff = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget)); + gtk_text_buffer_get_bounds(textbuff,&iter1,&iter2); + pp1 = gtk_text_buffer_get_text(textbuff,&iter1,&iter2,0); + strncpy0(tags_deftext,pp1,tagTcc); + + return; +} + + +/**************************************************************************/ + +// image file EXIF/IPTC data >> tags_date, tags_stars, tags_filetags, +// tags_comments, tags_caption in memory + +void load_fileinfo(cchar *file) +{ + void exif_tagdate(cchar *exifdate, char *tagdate); + + int ii, jj, cc; + char *pp; + cchar *exifkeys[5] = { exif_date_key, iptc_tags_key, iptc_rating_key, + exif_comment_key, iptc_caption_key }; + char **ppv, *imagedate, *imagetags, *imagestars, *imagecomms, *imagecapt; + + *tags_filetags = *tags_date = *tags_comments = *tags_caption = 0; + tags_stars = '0'; + + ppv = info_get(file,exifkeys,5); // stars rating added v.10.0 + imagedate = ppv[0]; + imagetags = ppv[1]; + imagestars = ppv[2]; + imagecomms = ppv[3]; + imagecapt = ppv[4]; + + if (imagedate) { + exif_tagdate(imagedate,tags_date); // EXIF date/time >> yyyymmdd + strcpy(tags_prdate,tags_date); + zfree(imagedate); + } + + if (imagetags) + { + for (ii = 1; ; ii++) + { + pp = (char *) strField(imagetags,tagdelims,ii); + if (! pp) break; + if (*pp == ' ') continue; + cc = strlen(pp); + if (cc >= tagcc) continue; // reject tags too big + for (jj = 0; jj < cc; jj++) + if (pp[jj] > 0 && pp[jj] < ' ') break; // reject tags with control characters + if (jj < cc) continue; + add_tag(pp,tags_filetags,tagFcc); // add to file tags if unique + } + + zfree(imagetags); + } + + if (imagestars) { // v.10.0 + tags_stars = *imagestars; + if (tags_stars < '0' || tags_stars > '5') tags_stars = '0'; + zfree(imagestars); + } + + if (imagecomms) { // v.10.11 + strncpy0(tags_comments,imagecomms,tagFcc); + zfree(imagecomms); + } + + if (imagecapt) { // v.10.12 + strncpy0(tags_caption,imagecapt,tagFcc); + zfree(imagecapt); + } + + Ftagschanged = 0; + return; +} + + +// tags_date, tags_stars, tags_filetags in memory >> image file EXIF/IPTC data +// update defined tags file if any changes + +void save_fileinfo(cchar *file) +{ + void tag_exifdate(cchar *tagdate, char *exifdate); + + cchar *exifkeys[5] = { exif_date_key, iptc_tags_key, iptc_rating_key, + exif_comment_key, iptc_caption_key }; + cchar *exifdata[5]; + char imagedate[24], sstars[4]; + + if (! Ftagschanged) return; // no changes to tags etc. + Ftagschanged = 0; + + *imagedate = 0; + if (*tags_date) { + tag_exifdate(tags_date,imagedate); // yyyymmdd >> EXIF date/time + strcpy(tags_prdate,tags_date); + } + + sstars[0] = tags_stars; // string for stars rating + sstars[1] = 0; + + exifdata[0] = imagedate; // update file EXIF/IPTC data + exifdata[1] = tags_filetags; + exifdata[2] = sstars; + exifdata[3] = tags_comments; // v.10.11 + exifdata[4] = tags_caption; // v.10.12 + info_put(file,exifkeys,exifdata,5); + + update_search_index(file); // update search index file + + if (zdexifview) info_view(0); // live EXIF/IPTC update v.10.2 + return; +} + + +// update search index file (replace updated file data) // overhauled v.12.01 + +void update_search_index(cchar *file) +{ + char *ppv, temp_search_index_file[200]; + char imagedate[12], filedate[16]; + char buff[tagrecl]; + int err, eof = 0, fcopy = 0, comp = 0, finserted = 0; + FILE *fidr, *fidw; + struct stat statb; + struct tm bdt; + + if (is_syncbusy()) return; // must wait for file sync v.11.11 + + strcpy(temp_search_index_file,search_index_file); // temp tag file + strcat(temp_search_index_file,"_temp"); + + fidw = fopen(temp_search_index_file,"w"); // write temp tag file (new) + if (! fidw) goto tagserror; + + fidr = fopen(search_index_file,"r"); // read tag file (old) + + if (fidr) + { + while (true) // copy search index file to temp + { // file, inserting or replacing + ppv = fgets_trim(buff,tagrecl,fidr); // records for caller's file + if (! ppv) eof = 1; + + if (strnEqu(buff,"file: ",6)) // start of next file entry + { + comp = strcmp(file,buff+6); + if (comp > 0) fcopy = 1; // new entry is after this one + if (comp == 0) fcopy = 0; // new entry replaces this one + if (comp < 0) fcopy = 1; // new entry is before this one + } + + if (comp <= 0 && ! finserted) // new entry inserts here v.12.01 + { + err = fprintf(fidw,"file: %s\n",file); // output filespec + if (err <= 0) goto tagserror; + + if (*tags_date) { // image date + strncpy(imagedate,tags_date,4); + strncpy(imagedate+5,tags_date+4,2); // yyyymmdd >> yyyy:mm:dd + strncpy(imagedate+8,tags_date+6,2); + imagedate[4] = imagedate[7] = ':'; + imagedate[10] = 0; + } + else strcpy(imagedate,"null"); // missing image date + + err = stat(file,&statb); + gmtime_r(&statb.st_mtime,&bdt); + sprintf(filedate,"%04d%02d%02d%02d%02d%02d", // file date = yyyymmddhhmmss + bdt.tm_year + 1900, bdt.tm_mon + 1, bdt.tm_mday, + bdt.tm_hour, bdt.tm_min, bdt.tm_sec); + + err = fprintf(fidw,"date: %s %s\n",imagedate,filedate); // output image and file date + + if (*tags_filetags) // output filetags + err = fprintf(fidw,"tags: %s\n",tags_filetags); + else err = fprintf(fidw,"tags: null" tagdelim2 "\n"); // "null" tag if none v.11.02 + + err = fprintf(fidw,"stars: %c\n",tags_stars); // output stars rating + + if (*tags_comments) // output user comments + err = fprintf(fidw,"comms: %s\n",tags_comments); + else err = fprintf(fidw,"comms: null \n"); // "null" if none + + if (*tags_caption) // output user caption v.10.12 + err = fprintf(fidw,"capt: %s\n",tags_caption); + else err = fprintf(fidw,"capt: null \n"); // "null" if none + + err = fprintf(fidw,"\n"); // EOL + + finserted = 1; + } + + if (eof) break; + if (fcopy) fprintf(fidw,"%s\n",buff); // copy this entry + } + + err = fclose(fidr); + if (err) goto tagserror; + } + + err = fclose(fidw); // close temp file + if (err) goto tagserror; + + err = rename(temp_search_index_file,search_index_file); // replace tags file with temp file + if (err) goto tagserror; + return; + +tagserror: + zmessLogACK(mWin,ZTX("search index file error: %s"),strerror(errno)); + return; +} + + +// file is deleted from search index file + +void delete_search_index(cchar *file) // overhauled v.10.11.2 +{ + char *ppv, temp_search_index_file[200]; + char indexbuff[tagrecl]; + char filebuff[tagrecl], datebuff[tagrecl]; + char tagsbuff[tagrecl], starsbuff[tagrecl]; + char commsbuff[tagrecl], captbuff[tagrecl]; + int err, ftf = 1; + FILE *fidr, *fidw; + + if (is_syncbusy()) return; // must wait for file sync v.11.11 + + strcpy(temp_search_index_file,search_index_file); // temp tag file + strcat(temp_search_index_file,"_temp"); + + fidr = fopen(search_index_file,"r"); // read tag file + if (! fidr) return; + + fidw = fopen(temp_search_index_file,"w"); // write temp tag file + if (! fidw) goto tagserror; + + while (true) // copy search index file to temp + { // file, omitting this image file + ppv = fgets_trim(indexbuff,tagrecl,fidr); + + if (! ppv || strnEqu(indexbuff,"file: ",6)) // EOF or start of next file + { + if (! ftf && strNeq(filebuff+6,file)) // not 1st time and not file to omit + { + fprintf(fidw,"%s\n",filebuff); // output completed data for previous file + fprintf(fidw,"%s\n",datebuff); + fprintf(fidw,"%s\n",tagsbuff); + fprintf(fidw,"%s\n",starsbuff); + fprintf(fidw,"%s\n",commsbuff); + fprintf(fidw,"%s\n",captbuff); + fprintf(fidw,"\n"); + } + + if (! ppv) break; // EOF + + ftf = 0; + strncpy0(filebuff,indexbuff,tagrecl); // next file: filespec record + strcpy(datebuff,"date: null "); // initz. remaining data = empty + strcpy(tagsbuff,"tags: null"tagdelim2); // v.11.02 + strcpy(starsbuff,"stars: 0 "); + strcpy(commsbuff,"comms: null "); + strcpy(captbuff,"capt: null "); + } + + if (strnEqu(indexbuff,"date: ",6)) // copy whatever is found + strncpy0(datebuff,indexbuff,tagrecl); + + if (strnEqu(indexbuff,"tags: ",6)) + strncpy0(tagsbuff,indexbuff,tagrecl); + + if (strnEqu(indexbuff,"stars: ",7)) + strncpy0(starsbuff,indexbuff,tagrecl); + + if (strnEqu(indexbuff,"comms: ",7)) + strncpy0(commsbuff,indexbuff,tagrecl); + + if (strnEqu(indexbuff,"capt: ",6)) + strncpy0(captbuff,indexbuff,tagrecl); + } + + err = fclose(fidr); + if (err) goto tagserror; + + err = fclose(fidw); + if (err) goto tagserror; + + err = rename(temp_search_index_file,search_index_file); // replace tags file with temp file + if (err) goto tagserror; + + return; + +tagserror: + zmessLogACK(mWin,ZTX("search index file error: %s"),strerror(errno)); + return; +} + + +/**************************************************************************/ + +// menu function - add tags to many files at once + +char **batchAddTags_filelist = 0; +int batchAddTags_filecount = 0; +zdialog *zdbatchAddTags = null; // batch add tags dialog + +void m_batchAddTags(GtkWidget *, cchar *) // new v.9.7 +{ + void batchAddTags_fixwidget(zdialog *zd, cchar * widgetname); + int batchAddTags_dialog_event(zdialog *zd, cchar *event); + + char *ptag, **flist, *file; + int ii, jj, err; + + zfuncs::F1_help_topic = "batch_add_tags"; // v.10.8 + + if (! Fexiftool) { // exiftool is required + zmessageACK(mWin,Bexiftoolmissing); + return; + } + + if (is_syncbusy()) return; // must wait for file sync v.11.11 + if (mod_keep()) return; // unsaved edits + if (! menulock(1)) return; // v.10.5 + + zdbatchAddTags = zdialog_new(ZTX("Batch Add Tags"),mWin,Bproceed,Bcancel,null); + + zdialog_add_widget(zdbatchAddTags,"hbox","hb1","dialog",0,"space=5"); + zdialog_add_widget(zdbatchAddTags,"label","lab1","hb1",ZTX("tags to add"),"space=10"); + zdialog_add_widget(zdbatchAddTags,"frame","frame1","hb1",0,"expand"); + zdialog_add_widget(zdbatchAddTags,"edit","batchAddTags","frame1",0,"expand|wrap"); // v.11.06 + + zdialog_add_widget(zdbatchAddTags,"hbox","hb2","dialog",0,"space=5"); + zdialog_add_widget(zdbatchAddTags,"button","createtag","hb2",ZTX("create tag"),"space=10"); + zdialog_add_widget(zdbatchAddTags,"entry","ctag","hb2",0); + + zdialog_add_widget(zdbatchAddTags,"hbox","hb3","dialog",0,"space=5"); + zdialog_add_widget(zdbatchAddTags,"button","files","hb3",Bselectfiles,"space=10"); + zdialog_add_widget(zdbatchAddTags,"label","labcount","hb3","0 files selected","space=10"); + + zdialog_add_widget(zdbatchAddTags,"hbox","space","dialog",0,"space=3"); + zdialog_add_widget(zdbatchAddTags,"hbox","hb5","dialog"); + zdialog_add_widget(zdbatchAddTags,"label","labdeftags","hb5",ZTX("defined tags")); + zdialog_add_widget(zdbatchAddTags,"frame","frame5","dialog",0,"space=5|expand"); + zdialog_add_widget(zdbatchAddTags,"scrwin","scrwin5","frame5",0,"expand"); + zdialog_add_widget(zdbatchAddTags,"edit","deftags","scrwin5",0,"expand|wrap"); // v.11.06 + + load_deftags(); // stuff defined tags into dialog + deftags_stuff(zdbatchAddTags); + + batchAddTags_filelist = 0; + batchAddTags_filecount = 0; + *tags_batchAddTags = 0; + + zdialog_resize(zdbatchAddTags,400,400); // run dialog + zdialog_help(zdbatchAddTags,"batch_add_tags"); // zdialog help topic v.11.08 + zdialog_run(zdbatchAddTags,batchAddTags_dialog_event); + + batchAddTags_fixwidget(zdbatchAddTags,"batchAddTags"); // setup for mouse tag selection + batchAddTags_fixwidget(zdbatchAddTags,"deftags"); + + zdialog_wait(zdbatchAddTags); // wait for dialog completion + + flist = batchAddTags_filelist; + + if (zdbatchAddTags->zstat != 1) goto cleanup; + if (! batchAddTags_filecount) goto cleanup; + if (*tags_batchAddTags <= ' ') goto cleanup; // v.10.5 + + write_popup_text("open","Adding Tags",500,200,mWin); // status monitor popup window v.11.01 + + for (ii = 0; flist[ii]; ii++) // loop all selected files + { + file = flist[ii]; // display image + err = f_open(file,0); + if (err) continue; + + write_popup_text("write",file); // report progress + zmainloop(); + + load_fileinfo(file); // load current file tags + + for (jj = 1; ; jj++) // add new tags unless already + { + ptag = (char *) strField(tags_batchAddTags,tagdelims,jj); + if (! ptag) break; + if (*ptag == ' ') continue; + err = add_tag(ptag,tags_filetags,tagFcc); + if (err == 2) + zmessageACK(mWin,ZTX("%s \n too many tags"),file); + } + + save_fileinfo(file); // save tag changes + } + + write_popup_text("write","COMPLETED"); + write_popup_text("close",0); + +cleanup: + + zdialog_free(zdbatchAddTags); + + if (batchAddTags_filecount) { + for (ii = 0; flist[ii]; ii++) + zfree(flist[ii]); + zfree(flist); + } + + menulock(0); + return; +} + + +// setup tag display widget for tag selection using mouse clicks + +void batchAddTags_fixwidget(zdialog *zd, cchar * widgetname) +{ + void batchAddTags_mouse(GtkTextView *widget, GdkEventButton *event, cchar *widgetname); + + GtkWidget *widget; + GdkWindow *gdkwin; + + widget = zdialog_widget(zd,widgetname); // make widget wrap text + gtk_text_view_set_editable(GTK_TEXT_VIEW(widget),0); // disable widget editing + + gdkwin = gtk_text_view_get_window(GTK_TEXT_VIEW(widget),TEXTWIN); // cursor for tag selection + gdk_window_set_cursor(gdkwin,arrowcursor); + + gtk_widget_add_events(widget,GDK_BUTTON_PRESS_MASK); // connect mouse-click event + G_SIGNAL(widget,"button-press-event",batchAddTags_mouse,widgetname); +} + + +// batchAddTags mouse-click event function +// get clicked tag and add to or remove from tags_batchAddTags + +void batchAddTags_mouse(GtkTextView *widget, GdkEventButton *event, cchar *widgetname) +{ + int mpx, mpy, cc; + + if (event->type != GDK_BUTTON_PRESS) return; + mpx = int(event->x); // mouse click position + mpy = int(event->y); + + cc = get_mouse_tag(widget,mpx,mpy,widgetname); // tags_cliktag = clicked tag in list + if (! cc) return; + + if (strEqu(widgetname,"batchAddTags")) { + del_tag(tags_cliktag,tags_batchAddTags); // remove tag from tags_batchAddTags + zdialog_stuff(zdbatchAddTags,"batchAddTags",tags_batchAddTags); // update dialog widgets + } + + if (strEqu(widgetname,"deftags")) { + add_tag(tags_cliktag,tags_batchAddTags,tagMcc); // add defined tag to tags_batchAddTags + zdialog_stuff(zdbatchAddTags,"batchAddTags",tags_batchAddTags); + } + + return; +} + + +// batchAddTags dialog event function + +int batchAddTags_dialog_event(zdialog *zd, cchar *event) +{ + int ii, err; + char tag[tagcc]; + char **flist = batchAddTags_filelist, countmess[50]; + + if (strEqu(event,"createtag")) { + err = zdialog_fetch(zd,"ctag",tag,tagcc); // add new tag to list + if (err) return 0; // reject too big tag + add_tag(tag,tags_batchAddTags,tagMcc); // add tag to tags_batchAddTags + zdialog_stuff(zd,"batchAddTags",tags_batchAddTags); // update dialog widgets + zdialog_stuff(zd,"ctag",""); + } + + if (strEqu(event,"files")) // select images to add tags + { + if (flist) { // free prior list + for (ii = 0; flist[ii]; ii++) + zfree(flist[ii]); + zfree(flist); + } + + flist = image_gallery_getfiles(0,mWin); // get file list from user + batchAddTags_filelist = flist; + + if (flist) // count files in list + for (ii = 0; flist[ii]; ii++); + else ii = 0; + batchAddTags_filecount = ii; + + snprintf(countmess,50,ZTX("%d files selected"),batchAddTags_filecount); + zdialog_stuff(zd,"labcount",countmess); + } + + return 0; +} + + +/**************************************************************************/ + +// menu function - delete or replace a tag for many files at once + +char **batchDelTag_filelist = 0; + +void m_batchDelTag(GtkWidget *, cchar *) // new v.10.9 +{ + int batchDelTag_dialog_event(zdialog *zd, cchar *event); + + char **flist, *file; + char deltag[tagcc], reptag[tagcc]; + int ii, err; + zdialog *zd; + + zfuncs::F1_help_topic = "batch_delete_tag"; + + if (! Fexiftool) { // exiftool is required + zmessageACK(mWin,Bexiftoolmissing); + return; + } + + if (is_syncbusy()) return; // must wait for file sync v.11.11 + if (mod_keep()) return; // unsaved edits + if (! menulock(1)) return; // v.10.5 + + zd = zdialog_new(ZTX("Batch Delete Tag"),mWin,Bproceed,Bcancel,null); + + zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=5"); + zdialog_add_widget(zd,"label","lab1","hb1",ZTX("tag to remove"),"space=10"); + zdialog_add_widget(zd,"entry","deltag","hb1",0,"scc=20"); + + zdialog_add_widget(zd,"hbox","hb2","dialog",0,"space=5"); + zdialog_add_widget(zd,"label","lab2","hb2",ZTX("optional replacement"),"space=10"); + zdialog_add_widget(zd,"entry","reptag","hb2",0,"scc=20"); + + zdialog_add_widget(zd,"hbox","hb3","dialog",0,"space=5"); + zdialog_add_widget(zd,"button","files","hb3",Bselectfiles,"space=10"); + zdialog_add_widget(zd,"label","labcount","hb3",ZTX("0 files selected"),"space=10"); + + zdialog_add_widget(zd,"hbox","hb4","dialog",0,"space=5"); + zdialog_add_widget(zd,"check","allfiles","hb4",ZTX("search all files"),"space=10"); + + batchDelTag_filelist = flist = 0; + + zdialog_help(zd,"batch_delete_tag"); // zdialog help topic v.11.08 + zdialog_run(zd,batchDelTag_dialog_event); // run dialog + zdialog_wait(zd); // wait for completion + + if (zd->zstat != 1) goto cleanup; // canceled + + flist = batchDelTag_filelist; // get selected files + if (! flist) goto cleanup; + + zdialog_fetch(zd,"deltag",deltag,tagcc); // get tag to delete + strTrim2(deltag); // remove leading and trailing blanks + strToLower(deltag); // use lower case for matching + if (! *deltag) goto cleanup; + + zdialog_fetch(zd,"reptag",reptag,tagcc); // optional replacement tag + strTrim2(reptag); + + write_popup_text("open","Deleting Tags",500,200,mWin); // status monitor popup window v.11.01 + + for (ii = 0; flist[ii]; ii++) // loop all selected files + { + file = flist[ii]; + err = f_open(file,0); // display image + if (err) continue; + + write_popup_text("write",file); // report progress + zmainloop(); + + load_fileinfo(file); // load current file tags + + err = del_tag(deltag,tags_filetags); // remove tag, if present + if (err) continue; // not present + + if (*reptag) { // add replacement tag, if defined + err = add_tag(reptag,tags_filetags,tagFcc); + if (err == 2) + zmessageACK(mWin,ZTX("%s \n too many tags"),file); + } + + save_fileinfo(file); // save tag changes + } + + write_popup_text("write","COMPLETED"); + write_popup_text("close",0); + +cleanup: + + zdialog_free(zd); + + if (flist) { + for (ii = 0; flist[ii]; ii++) + zfree(flist[ii]); + zfree(flist); + } + + menulock(0); + return; +} + + +// batchDelTag dialog event function + +int batchDelTag_dialog_event(zdialog *zd, cchar *event) +{ + FILE *fidr; + struct stat statbuf; + char deltag[tagcc]; + char **flist = batchDelTag_filelist; + int err, nfiles, ii, allfiles; + char filebuff[tagrecl], tagsbuff[tagrecl]; + char *ppv, *file, *tags, countmess[50]; + cchar *ppf; + int maxfiles = 100000; // max. files with tag to delete v.11.04 + + zdialog_fetch(zd,"deltag",deltag,tagcc); // get tag to delete + strTrim2(deltag); // remove leading and trailing blanks + strToLower(deltag); // use lower case for matching + + if (zd->zstat == 1) // [proceed] + { + if (! flist) { + zmessageACK(mWin,ZTX("no files selected")); // v.11.01 + zd->zstat = 0; // keep dialog active + goto finish; + } + + if (! *deltag) { + zmessageACK(mWin,ZTX("no tag specified")); // v.11.01 + zd->zstat = 0; + goto finish; + } + + return 0; + } + + if (strEqu(event,"deltag")) // tag changed + { + if (flist) { // clear file list v.11.01 + for (ii = 0; flist[ii]; ii++) + zfree(flist[ii]); + zfree(flist); + flist = 0; + } + + zdialog_stuff(zd,"allfiles",0); // reset "all files" checkbox v.11.01 + goto finish; + } + + if (strEqu(event,"files")) // select images to delete tags + { + if (! *deltag) { + zmessageACK(mWin,ZTX("specify tag")); // v.11.01 + goto finish; + } + + if (flist) { // free prior list + for (ii = 0; flist[ii]; ii++) + zfree(flist[ii]); + zfree(flist); + flist = 0; + } + + flist = image_gallery_getfiles(0,mWin); // get file list from user + zdialog_stuff(zd,"allfiles",0); // reset "all files" checkbox v.11.01 + goto finish; + } + + if (strEqu(event,"allfiles")) + { + if (flist) { // clear file list + for (ii = 0; flist[ii]; ii++) + zfree(flist[ii]); + zfree(flist); + flist = 0; + } + + zdialog_fetch(zd,"allfiles",allfiles); // get checkbox "all files" + if (! allfiles) goto finish; // was unselected + + if (! *deltag) { + zmessageACK(mWin,ZTX("specify tag")); // v.11.01 + goto finish; + } + + fidr = fopen(search_index_file,"r"); // read search index file + if (! fidr) goto finish; // no file + + flist = (char **) zmalloc(maxfiles*sizeof(char *),"DeleteTag"); // list for files found + nfiles = 0; // count files found + flist[0] = 0; + + while (true) + { + ppv = fgets_trim(filebuff,tagrecl,fidr,1); // next record + if (! ppv) break; // EOF + + if (! strnEqu(ppv,"file: ",6)) continue; // file: /dir.../filename.jpg + + file = ppv+6; + err=stat(file,&statbuf); // check file exists + if (err) continue; + if (! S_ISREG(statbuf.st_mode)) continue; + + ppv = fgets_trim(tagsbuff,tagrecl,fidr); // next record + if (! ppv) break; + if (! strnEqu(ppv,"date: ",6)) continue; // date: yyyy:mm:dd + + ppv = fgets_trim(tagsbuff,tagrecl,fidr); // next record + if (! ppv) break; + if (! strnEqu(ppv,"tags: ",6)) continue; // tags: xxxx, xxxxx, ... + + tags = ppv + 6; + strToLower(tags); // use lower case for matching + + for (ii = 1; ; ii++) // step thru file tags + { + ppf = strField(tags,tagdelims,ii); + if (! ppf) break; + if (*ppf == ' ') continue; + if (strEqu(ppf,deltag)) break; // look for my tag + } + + if (! ppf) continue; // tag not found + + flist[nfiles] = strdupz(file,0,"batch_del_tag"); + nfiles++; + if (nfiles == maxfiles-1) break; + } + + fclose(fidr); // close search index file + flist[nfiles] = 0; // EOL marker + } + +finish: + + batchDelTag_filelist = flist; // file list to process + + if (flist) // count files in list + for (ii = 0; flist[ii]; ii++); + else ii = 0; + + snprintf(countmess,50,ZTX("%d files selected"),ii); // stuff file count into dialog + zdialog_stuff(zd,"labcount",countmess); + + return 0; +} + + +/************************************************************************** + functions to view and edit metadata: EXIF, IPTC, etc. +***************************************************************************/ + +// menu function and popup dialog to show EXIF/IPTC data +// window is updated when navigating to another image + +void m_info_view_short(GtkWidget *, cchar *menu) // v.10.12 +{ + zfuncs::F1_help_topic = "view_info"; + info_view(1); + return; +} + +void m_info_view_long(GtkWidget *, cchar *menu) // v.10.12 +{ + zfuncs::F1_help_topic = "view_info"; + info_view(2); + return; +} + +void info_view(int arg) +{ + int info_view_dialog_event(zdialog *zd, cchar *event); + + static int length = 1; + char *buff; + int contx = 0; + GtkWidget *widget; + + if (! Fexiftool) { // exiftool is required + zmessageACK(mWin,Bexiftoolmissing); + return; + } + + if (! curr_file) return; + + if (arg > 0) length = arg; // change short/long report mode + + if (! zdexifview) // popup dialog if not already + { + zdexifview = zdialog_new(ZTX("View Info"),mWin,Bcancel,null); + zdialog_add_widget(zdexifview,"scrwin","scroll","dialog",0,"expand"); + zdialog_add_widget(zdexifview,"edit","exifdata","scroll",0,"expand|wrap"); + zdialog_resize(zdexifview,500,400); + zdialog_help(zdexifview,"view_info"); // zdialog help topic v.11.08 + zdialog_run(zdexifview,info_view_dialog_event); + } + + widget = zdialog_widget(zdexifview,"exifdata"); // v.10.12 + gtk_text_view_set_editable(GTK_TEXT_VIEW(widget),0); // disable widget editing + gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(widget),GTK_WRAP_NONE); // disable text wrap + + if (length == 1) // short report + { + snprintf(command,ccc,"exiftool -common -%s -%s -%s -%s -%s -%s \"%s\" ", + iptc_tags_key, iptc_rating_key, iptc_editlog_key, exif_comment_key, + iptc_caption_key, exif_focal_length_key, curr_file); + } + else + snprintf(command,ccc,"exiftool -e \"%s\" ",curr_file); // long, output everything + + widget = zdialog_widget(zdexifview,"exifdata"); // widget for output + wclear(widget); + + while ((buff = command_output(contx,command))) { // run command, output into window + wprintf(widget,"%s\n",buff); + zfree(buff); // memory leak v.11.03 + } + + command_status(contx); // free resources + + return; +} + + +// dialog event and completion callback function + +int info_view_dialog_event(zdialog *zd, cchar *event) // kill dialog +{ + if (! zd->zstat) return 0; + zdialog_free(zdexifview); + return 0; +} + + +/**************************************************************************/ + +// edit EXIF/IPTC data - add or change specified EXIF/IPTC/etc. key + +void m_info_edit(GtkWidget *, cchar *menu) // new v.10.2 +{ + char keyname[40], keydata[1000]; + cchar *pp1[1]; + char **pp2; + + int info_edit_dialog_event(zdialog *zd, cchar *event); + + if (menu) zfuncs::F1_help_topic = "edit_info"; + + if (! Fexiftool) { // exiftool is required + zmessageACK(mWin,Bexiftoolmissing); + return; + } + + if (! curr_file) return; + + if (! zdexifedit) // popup dialog if not already v.10.8 + { + zdexifedit = zdialog_new(ZTX("Edit Info"),mWin,Bfetch,Bsave,Bcancel,null); + zdialog_add_widget(zdexifedit,"vbox","hb1","dialog"); + zdialog_add_widget(zdexifedit,"hbox","hbkey","dialog",0,"space=5"); + zdialog_add_widget(zdexifedit,"hbox","hbdata","dialog",0,"space=5"); + zdialog_add_widget(zdexifedit,"label","labkey","hbkey","key name"); + zdialog_add_widget(zdexifedit,"entry","keyname","hbkey",0,"scc=20"); + zdialog_add_widget(zdexifedit,"label","labdata","hbdata","key value"); + zdialog_add_widget(zdexifedit,"entry","keydata","hbdata",0,"expand"); + zdialog_help(zdexifedit,"edit_info"); // zdialog help topic v.11.08 + zdialog_run(zdexifedit,info_edit_dialog_event); + } + + zdialog_fetch(zdexifedit,"keyname",keyname,40); // get key name from dialog + strCompress(keyname); // v.10.8 + + if (*keyname) // update live dialog v.10.8 + { + pp1[0] = keyname; // look for key data + pp2 = info_get(curr_file,pp1,1); + if (pp2[0]) { + strncpy0(keydata,pp2[0],999); + zfree(pp2[0]); + } + else *keydata = 0; + zdialog_stuff(zdexifedit,"keydata",keydata); // stuff into dialog + } + + return; +} + + +// dialog event and completion callback function + +int info_edit_dialog_event(zdialog *zd, cchar *event) +{ + char keyname[40], keydata[1000]; // v.11.02 (was 100) + cchar *pp1[1], *pp2[1]; + char **pp3; + int err; + + if (! zd->zstat) return 0; + + zdialog_fetch(zd,"keyname",keyname,40); + zdialog_fetch(zd,"keydata",keydata,1000); + strCompress(keyname); // remove blanks v.10.8 + + if (zd->zstat == 1) // fetch + { + zd->zstat = 0; + if (! *keyname) return 0; // bugfix v.11.02 + pp1[0] = keyname; + pp3 = info_get(curr_file,pp1,1); + if (pp3[0]) { + strncpy0(keydata,pp3[0],99); + zfree(pp3[0]); + } + else *keydata = 0; + zdialog_stuff(zd,"keydata",keydata); + } + + else if (zd->zstat == 2) // save + { + zd->zstat = 0; // keep dialog active + if (! *keyname) return 0; // bugfix v.11.02 + if (is_syncbusy()) return 0; // must wait for file sync v.11.11 + pp1[0] = keyname; + pp2[0] = keydata; + err = info_put(curr_file,pp1,pp2,1); + if (err) zmessageACK(mWin,"error: %s",strerror(err)); + if (zdexifview) info_view(0); // update exif view if active + } + + else zdialog_free(zdexifedit); // other + + return 1; +} + + +/**************************************************************************/ + +// delete EXIF/IPTC data, specific key or all data + +void m_info_delete(GtkWidget *, cchar *menu) // new v.10.2 +{ + int info_delete_dialog_event(zdialog *zd, cchar *event); + + zdialog *zd; + + zfuncs::F1_help_topic = "delete_info"; // v.10.8 + + if (! Fexiftool) { // exiftool is required + zmessageACK(mWin,Bexiftoolmissing); + return; + } + + if (! curr_file) return; + if (is_syncbusy()) return; // must wait for file sync v.11.11 + + zd = zdialog_new(ZTX("Delete Info"),mWin,Bapply,Bcancel,null); + zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=5"); + zdialog_add_widget(zd,"radio","kall","hb1",ZTX("All"),"space=5"); + zdialog_add_widget(zd,"radio","key1","hb1",ZTX("One Key:")); + zdialog_add_widget(zd,"entry","keyname","hb1",0,"scc=20"); + zdialog_stuff(zd,"key1",1); + + zdialog_help(zd,"delete_info"); // zdialog help topic v.11.08 + zdialog_run(zd,info_delete_dialog_event); + return; +} + + +// dialog event and completion callback function + +int info_delete_dialog_event(zdialog *zd, cchar *event) +{ + int kall, key1, err; + char keyname[40]; + + if (! zd->zstat) return 0; + + if (zd->zstat != 1) { // canceled + zdialog_free(zd); + return 1; + } + + zd->zstat = 0; // dialog remains active + + zdialog_fetch(zd,"kall",kall); + zdialog_fetch(zd,"key1",key1); + zdialog_fetch(zd,"keyname",keyname,40); + strCompress(keyname); // v.10.8 + // bugfix - quotes around file v.10.3 + if (kall) + snprintf(command,ccc,"exiftool -m -q -overwrite_original -all= \"%s\"",curr_file); + else if (key1) + snprintf(command,ccc,"exiftool -m -q -overwrite_original -%s= \"%s\"",keyname,curr_file); + else return 1; + + err = system(command); + if (err) zmessageACK(mWin,"%s",wstrerror(err)); + + if (zdexifview) info_view(0); // update exif view if active + + return 1; +} + + +/**************************************************************************/ + +// get EXIF/IPTC metadata for given image file and EXIF/IPTC key(s) +// returns array of pointers to corresponding key values +// if a key is missing, corresponding pointer is null +// returned strings belong to caller, are subject for zfree() +// up to 9 keynames may be requested per call +// command: +// exiftool -keyname1 -keyname2 ... "file" +// command output: +// keyname1: keyvalue1 +// keyname2: keyvalue2 +// ... +// The CPU time for this call is about 0.1 seconds (BIG). + +char ** info_get(cchar *file, cchar **keys, int nkeys) +{ + char *pp; + static char *keyvals[10]; + int contx = 0, err, ii; + uint cc; + + if (nkeys < 1 || nkeys > 9) zappcrash("info_get nkeys: %d",nkeys); + + cc = 10 * sizeof(char *); // v.12.01 + memset(keyvals,0,cc); + + strcpy(command,"exiftool -m -q -S -fast"); + + for (ii = 0; ii < nkeys; ii++) // build command line + strncatv(command,ccc," -",keys[ii],null); + + strncatv(command,ccc," \"",file,"\"",null); + + while (true) + { + pp = command_output(contx,command); + if (! pp) break; + + for (ii = 0; ii < nkeys; ii++) + { + cc = strlen(keys[ii]); + if (strncasecmp(pp,keys[ii],cc) == 0) // ignore case + if (strlen(pp) > cc+2) + keyvals[ii] = strdupz(pp+cc+2,0,"info_get"); // check not empty + } + + zfree(pp); + } + + err = command_status(contx); + if (err) printf(" exiftool: %s \n",wstrerror(err)); + + return keyvals; +} + + +/**************************************************************************/ + +// Get metadata for a list of image files and a list of EXIF/IPTC keys. +// +// Returns an array of pointers to corresponding key values. +// If a key is missing, corresponding pointer is null. +// Returned strings belong to caller, are subject for zfree(). +// +// shell command: +// exiftool -keyname1 -keyname2 ... "file1" "file2" ... +// +// shell command output: +// ======== file1 +// keyname1: keyvalue1 +// keyname2: keyvalue2 +// ... +// ======== file2 +// keyname1: keyvalue3 +// keyname2: keyvalue4 +// ... +// +// Returned list of strings (char **): +// keyvalue1, keyvalue2, ... keyvalue3, keyvalue4, ... null +// +// The CPU time for this call is about 0.1 + 0.01 seconds per file +// (based on 3.3 GHz Intel Core i5 cpu). + +char ** info_getN(cchar **files, int NF, cchar **keys, int NK) // v.12.01 +{ + char *ppk, *ppv, **keyvals; + int contx = 0, cc, ii, ff, kk; + char command[10000]; + + cc = (1 + NF * NK) * sizeof(char *); + keyvals = (char **) zmalloc(cc,"info_getN"); + memset(keyvals,0,cc); + + strcpy(command,"exiftool -m -s2 -fast2"); // build command line + + for (kk = 0; kk < NK; kk++) + strncatv(command,9999," -",keys[kk],null); + + for (ff = 0; ff < NF; ff++) + strncatv(command,9999," \"",files[ff],"\"",null); + + ff = NF; // flag: no current file + + while ((ppk = command_output(contx,command))) + { + if (NF > 1) // multiple files + { + if (strnEqu(ppk,"========",8)) // look for start of next file + { + for (ff = 0; ff < NF; ff++) + if (strstr(ppk+8,files[ff])) break; // locate file in my list + zfree(ppk); + continue; + } + + if (ff == NF) continue; // no matching file + } + + else ff = 0; // if 1 file, no "========" lines + + for (kk = 0; kk < NK; kk++) + { // look for key name + cc = strlen(keys[kk]); + if (strncasecmp(ppk,keys[kk],cc)) continue; + ppv = ppk + cc; // name matches + while (*ppv && *ppv == ' ') ppv++; // followed by blanks + if (strncmp(ppv,": ",2)) continue; // followed by ": " + ppv += 2; + if (strlen(ppv) < 1) continue; // followed by key value + if (strlen(ppv) > 999) ppv[999] = 0; // limit length to 999 + ii = NK * ff + kk; // index for file and key + keyvals[ii] = strdupz(ppv,0,"info_getN"); + break; + } + + zfree(ppk); + } + + return keyvals; +} + + +/**************************************************************************/ + +// create or change EXIF/IPTC metadata for given image file and key(s) +// up to 9 keys may be processed +// command: +// exiftool -overwrite_original -keyname="keyvalue" ... "file" +// +// NOTE: exiftool replaces \n (newline) in "keyvalue" with "." (period) + +int info_put(cchar *file, cchar **keys, cchar **text, int nkeys) +{ + int ii, err; + char *ptext[10]; + + if (nkeys < 1 || nkeys > 9) zappcrash("info_put nkeys: %d",nkeys); + + for (ii = 0; ii < nkeys; ii++) + { + if (! text[ii]) text[ii] = ""; // if null pointer use empty string + ptext[ii] = strdupz(text[ii],20,"info_put"); + if (strchr(text[ii],'"')) // replace imbedded " with \" + repl_1str(text[ii],ptext[ii],"\"","\\\""); // else exiftool command fails + } + + strcpy(command,"exiftool -m -q -overwrite_original"); + + for (ii = 0; ii < nkeys; ii++) // build command line + strncatv(command,ccc," -",keys[ii],"=\"",ptext[ii],"\"",null); + strncatv(command,ccc," \"",file,"\"",null); + + for (ii = 0; ii < nkeys; ii++) // plug small leak v.12.01 + zfree((char *) ptext[ii]); + + err = system(command); + if (err) printf(" info_put: %s \n",wstrerror(err)); + return err; +} + + +/**************************************************************************/ + +// copy EXIF/IPTC data from original image file to new (edited) image file +// if nkeys > 0, up to 9 keys may be replaced with new values +// exiftool command revised: parameter sequence and -icc_profile + +int info_copy(cchar *file1, cchar *file2, cchar **keys, cchar **text, int nkeys) +{ + int ii, err; + + strcpy(command,"exiftool -m -q -tagsfromfile"); // exiftool -m -q -tagsfromfile "file1" + strncatv(command,ccc," \"",file1,"\"",null); + + strncatv(command,ccc," -all -icc_profile",null); // -all -icc_profile + + for (ii = 0; ii < nkeys; ii++) // -keyname="keyvalue" ... (options) + if (text[ii]) + strncatv(command,ccc," -",keys[ii],"=\"",text[ii],"\"",null); + + strncatv(command,ccc," \"",file2,"\""," -overwrite_original",null); // "file2" -overwrite_original + + err = system(command); + if (err) printf(" exiftool: %s \n",wstrerror(err)); + return err; +} + + +/**************************************************************************/ + +// convert between EXIF and fotoxx tag date formats +// EXIF date: yyyy:mm:dd hh:mm:ss[.ss] +// tag date: yyyymmdd +// + +void exif_tagdate(cchar *exifdate, char *tagdate) +{ + time_t tnow; + struct tm *snow; + + if (! exifdate || strlen(exifdate) < 10) { // bad EXIF date, use current date + tnow = time(0); + snow = localtime(&tnow); + snprintf(tagdate,8,"%4d%02d%02d", + snow->tm_year+1900, snow->tm_mon+1, snow->tm_mday); + tagdate[8] = 0; + return; + } + + strncpy(tagdate,exifdate,4); // convert + strncpy(tagdate+4,exifdate+5,2); + strncpy(tagdate+6,exifdate+8,2); + tagdate[8] = 0; + return; +} + +void tag_exifdate(cchar *tagdate, char *exifdate) +{ + int cc; + time_t tnow; + struct tm *snow; + + if (! tagdate || strlen(tagdate) < 4) { + tnow = time(0); + snow = localtime(&tnow); + snprintf(exifdate,20,"%4d:%02d:%02d %02d:%02d:%02d", + snow->tm_year+1900, snow->tm_mon+1, snow->tm_mday, + snow->tm_hour, snow->tm_min, snow->tm_sec); + exifdate[19] = 0; + return; + } + + strncpy(exifdate,tagdate,4); + strcpy(exifdate+4,":01:01 00:00:00"); + cc = strlen(tagdate); + if (cc >= 6) strncpy(exifdate+5,tagdate+4,2); + if (cc >= 8) strncpy(exifdate+8,tagdate+6,2); + exifdate[19] = 0; + return; +} + + +/**************************************************************************/ + +// search image tags, dates, stars, comments, captions for matching images + +char searchDateFrom[12] = ""; // image search date range +char searchDateTo[12] = ""; +char searchStarsFrom[4] = ""; // image search stars range +char searchStarsTo[4] = ""; + +zdialog *zdsearchinfo = 0; // search tags dialog + + +void m_search_images(GtkWidget *, cchar *) +{ + void searchinfo_fixwidget(zdialog *zd, cchar * widgetname); + int searchinfo_dialog_event(zdialog*, cchar *event); + + zdialog *zd; + + if (is_syncbusy()) return; // must wait for file sync v.11.11 + if (mod_keep()) return; // unsaved edits + if (! menulock(1)) return; + menulock(0); + + zfuncs::F1_help_topic = "search_images"; // v.10.8 + +/*** + date range [_______] [_______] (yyyymmdd) + stars range [__] [__] all any + search tags [________________________] (o) (o) + search text [________________________] (o) (o) + file names [________________________] (o) (o) + + defined tags + ---------------------------------------------- + | | + | | + | | + | | + | | + ---------------------------------------------- + [proceed] [cancel] +***/ + + zd = zdialog_new(ZTX("Search Tags, Comments, File Names"),mWin,Bproceed,Bcancel,null); + zdsearchinfo = zd; + + zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=5"); + zdialog_add_widget(zd,"vbox","vb1","hb1",0,"homog|space=3"); + zdialog_add_widget(zd,"vbox","vb2","hb1",0,"homog|space=3|expand"); + + zdialog_add_widget(zd,"label","labD","vb1",ZTX("date range")); + zdialog_add_widget(zd,"label","labS","vb1",ZTX("stars range")); + zdialog_add_widget(zd,"label","labT","vb1",ZTX("search tags")); + zdialog_add_widget(zd,"label","labT","vb1",ZTX("search text")); + zdialog_add_widget(zd,"label","labF","vb1",ZTX("file names")); + + zdialog_add_widget(zd,"hbox","hbD","vb2",0,"space=1"); + zdialog_add_widget(zd,"entry","datefrom","hbD",0,"scc=10"); + zdialog_add_widget(zd,"entry","dateto","hbD",0,"scc=10"); + zdialog_add_widget(zd,"label","labD","hbD",ZTX("(yyyymmdd)"),"space=5"); + + zdialog_add_widget(zd,"hbox","hbS","vb2",0,"space=1"); + zdialog_add_widget(zd,"entry","starsfrom","hbS",0,"scc=2"); + zdialog_add_widget(zd,"entry","starsto","hbS",0,"scc=2"); + zdialog_add_widget(zd,"label","space","hbS",0,"expand"); + zdialog_add_widget(zd,"label","all-any","hbS",ZTX("all/any")); + + zdialog_add_widget(zd,"hbox","hbT","vb2",0,"space=1"); + zdialog_add_widget(zd,"frame","frameT","hbT",0,"expand"); + zdialog_add_widget(zd,"edit","searchtags","frameT",0,"expand|wrap"); + zdialog_add_widget(zd,"radio","alltags","hbT",0); + zdialog_add_widget(zd,"radio","anytags","hbT",0); + + zdialog_add_widget(zd,"hbox","hbC","vb2",0,"space=1|expand"); + zdialog_add_widget(zd,"entry","searchtext","hbC",0,"expand"); + zdialog_add_widget(zd,"radio","alltext","hbC",0); + zdialog_add_widget(zd,"radio","anytext","hbC",0); + + zdialog_add_widget(zd,"hbox","hbF","vb2",0,"space=1|expand"); + zdialog_add_widget(zd,"entry","searchfiles","hbF",0,"expand"); + zdialog_add_widget(zd,"radio","allfiles","hbF",0); + zdialog_add_widget(zd,"radio","anyfiles","hbF",0); + + zdialog_add_widget(zd,"hbox","hbA1","dialog",0,"space=3"); + zdialog_add_widget(zd,"label","labdeftags","hbA1",ZTX("defined tags"),"space=5"); + zdialog_add_widget(zd,"hbox","hbA2","dialog",0,"expand"); + zdialog_add_widget(zd,"frame","frameA","hbA2",0,"space=5|expand"); + zdialog_add_widget(zd,"scrwin","scrwinA","frameA",0,"expand"); + zdialog_add_widget(zd,"edit","deftags","scrwinA",0,"expand|wrap"); + + zdialog_resize(zd,400,500); // start dialog + zdialog_help(zd,"search_images"); // zdialog help topic v.11.08 + zdialog_run(zd,searchinfo_dialog_event); + + searchinfo_fixwidget(zd,"deftags"); // setup tag selection via mouse + searchinfo_fixwidget(zd,"searchtags"); + + zdialog_stuff(zd,"datefrom",searchDateFrom); // stuff previous date range + zdialog_stuff(zd,"dateto",searchDateTo); + zdialog_stuff(zd,"starsfrom",searchStarsFrom); + zdialog_stuff(zd,"starsto",searchStarsTo); + zdialog_stuff(zd,"searchtags",tags_searchtags); // stuff previous search tags + zdialog_stuff(zd,"searchtext",tags_searchtext); // stuff previous search text + zdialog_stuff(zd,"searchfiles",tags_searchfiles); // stuff previous search files + + zdialog_stuff(zd,"alltags",0); // default any tags, text, files + zdialog_stuff(zd,"anytags",1); + zdialog_stuff(zd,"alltext",0); + zdialog_stuff(zd,"anytext",1); + zdialog_stuff(zd,"allfiles",0); + zdialog_stuff(zd,"anyfiles",1); + + load_deftags(); // stuff defined tags into dialog + deftags_stuff(zd); + + return; +} + + +// setup tag display widget for tag selection using mouse clicks + +void searchinfo_fixwidget(zdialog *zd, cchar * widgetname) +{ + void searchinfo_mouse(GtkTextView *widget, GdkEventButton *event, cchar *widgetname); + + GtkWidget *widget; + GdkWindow *gdkwin; + + widget = zdialog_widget(zd,widgetname); // make widget wrap text + gtk_text_view_set_editable(GTK_TEXT_VIEW(widget),0); // disable widget editing + + gdkwin = gtk_text_view_get_window(GTK_TEXT_VIEW(widget),TEXTWIN); // cursor for tag selection + gdk_window_set_cursor(gdkwin,arrowcursor); + + gtk_widget_add_events(widget,GDK_BUTTON_PRESS_MASK); // connect mouse-click event + G_SIGNAL(widget,"button-press-event",searchinfo_mouse,widgetname); +} + + +// search tags mouse-click event function +// get clicked tag and add to or remove from tags_searchtags + +void searchinfo_mouse(GtkTextView *widget, GdkEventButton *event, cchar *widgetname) +{ + int mpx, mpy, cc; + + if (event->type != GDK_BUTTON_PRESS) return; + mpx = int(event->x); // mouse click position + mpy = int(event->y); + + cc = get_mouse_tag(widget,mpx,mpy,widgetname); // tags_cliktag = clicked tag in list + if (! cc) return; + + if (strEqu(widgetname,"deftags")) { + add_tag(tags_cliktag,tags_searchtags,tagScc); // add defined tag to search tags + zdialog_stuff(zdsearchinfo,"searchtags",tags_searchtags); + } + + if (strEqu(widgetname,"searchtags")) { // v.10.6 + del_tag(tags_cliktag,tags_searchtags); // remove tag from searchtags + zdialog_stuff(zdsearchinfo,"searchtags",tags_searchtags); // update dialog widgets + } + + return; +} + + +// dialog event and completion callback function + +int searchinfo_dialog_event(zdialog *zd, cchar *event) +{ + int searchinfo_text(char *text, int Fmall); + + char indexbuff[tagrecl], resultsfile[200]; + char temp[tagrecl], date1[12], date2[12]; + cchar *pp, *pps, *ppf; + int err, iix, iis, iif, cc; + int Nxrec, nmatch, nfail; + int Fdates, Ftext, Ffiles, Ftags, Fstars; + int Falltags, Falltext, Fallfiles; + FILE *fid; + struct stat statbuf; + + struct xrec_t { // image metadata record + char *file; // image filespec + char *tags; // image tags + char *comms; // image comments + char *capt; // image caption + char date[12]; // image date + char stars; // image star rating, '0' to '5' + }; + + if (! zd->zstat) return 0; // wait for completion + + if (zd->zstat != 1) { + zdialog_free(zd); // cancel + return 0; + } + + zdialog_fetch(zd,"datefrom",searchDateFrom,10); // get search date range + zdialog_fetch(zd,"dateto",searchDateTo,10); + zdialog_fetch(zd,"starsfrom",searchStarsFrom,2); // get search stars range + zdialog_fetch(zd,"starsto",searchStarsTo,2); + zdialog_fetch(zd,"searchtags",tags_searchtags,tagScc); // get search tags + zdialog_fetch(zd,"searchtext",tags_searchtext,tagScc); // get search text* + zdialog_fetch(zd,"searchfiles",tags_searchfiles,tagScc); // get search /path*/file* + + zdialog_fetch(zd,"alltags",Falltags); // get match all/any options + zdialog_fetch(zd,"alltext",Falltext); + zdialog_fetch(zd,"allfiles",Fallfiles); + + zdialog_free(zd); // cancel dialog + + strcpy(date1,"0000:01:01"); // defaults for missing dates + strcpy(date2,"9999:12:31"); // v.10.12 + + Fdates = 0; + if (*searchDateFrom) { // date from was given + Fdates++; + strncpy(date1,searchDateFrom,4); // convert format + if (searchDateFrom[4] >= '0') // yyyymmdd >> yyyy:mm:dd + strncpy(date1+5,searchDateFrom+4,2); + if (searchDateFrom[6] >= '0') + strncpy(date1+8,searchDateFrom+6,2); + } + if (*searchDateTo) { // date to was given + Fdates++; + strncpy(date2,searchDateTo,4); + if (searchDateTo[4] >= '0') + strncpy(date2+5,searchDateTo+4,2); + if (searchDateTo[6] >= '0') + strncpy(date2+8,searchDateTo+6,2); + } + + Fstars = 0; + if (*searchStarsFrom || *searchStarsTo) Fstars = 1; // stars was given + + Ffiles = 0; + if (! blank_null(tags_searchfiles)) Ffiles = 1; // search path / file (fragment) was given + + Ftext = 0; + if (! blank_null(tags_searchtext)) Ftext = 1; // search text was given + + Ftags = 0; + if (! blank_null(tags_searchtags)) Ftags = 1; // search tags was given + + if (Ffiles) strToLower(tags_searchfiles); // all comparisons in lower case + if (Ftags) strToLower(tags_searchtags); + if (Ftext) strToLower(tags_searchtext); + + cc = MAXIMAGES * sizeof(xrec_t); + xrec_t *xrec = (xrec_t *) zmalloc(cc,"search"); + memset(xrec,0,cc); + + Nxrec = 0; + fid = fopen(search_index_file,"r"); + if (! fid) goto noindexfile; + *indexbuff = 0; + + while (true) // read index file + { + if (! strnEqu(indexbuff,"file: ",6)) { // skip to next "file" record + pp = fgets_trim(indexbuff,tagrecl,fid); + if (! pp) break; // EOF + continue; + } + + *indexbuff = 0; // prevent possible looping + + iix = Nxrec; + if (xrec[iix].file) zfree(xrec[iix].file); // xrecs are re-used + if (xrec[iix].tags) zfree(xrec[iix].tags); + if (xrec[iix].comms) zfree(xrec[iix].comms); + if (xrec[iix].capt) zfree(xrec[iix].capt); + + memset(&xrec[iix],0,sizeof(xrec)); + pp = indexbuff + 6; // filespec + xrec[iix].file = strdupz(pp,0,"search"); // setup new xrec member + xrec[iix].stars = '0'; + + while (true) + { + pp = fgets_trim(indexbuff,tagrecl,fid); // get recs following "file" + if (! pp) break; + + if (strnEqu(pp,"date: ",6)) + { + pp = strField(pp,' ',2); + if (pp) strncpy0(xrec[iix].date,pp,12); + } + + else if (strnEqu(pp,"tags: ",6)) + xrec[iix].tags = strdupz(pp+6,0,"search"); + + else if (strnEqu(pp,"stars: ",7)) + xrec[iix].stars = *(pp+7); + + else if (strnEqu(pp,"comms: ",7)) + xrec[iix].comms = strdupz(pp+7,0,"search"); + + else if (strnEqu(pp,"capt: ",6)) + xrec[iix].capt = strdupz(pp+6,0,"search"); + + else break; + } + + err=stat(xrec[iix].file,&statbuf); // check file exists + if (err) continue; + if (! S_ISREG(statbuf.st_mode)) continue; + + if (Ffiles) // file name match is wanted + { + nmatch = nfail = 0; + + for (iis = 1; ; iis++) + { + pps = strField(tags_searchfiles,' ',iis); // step thru search file names + if (! pps) break; + if (strcasestr(xrec[iix].file,pps)) nmatch++; + else nfail++; + } + + if (nmatch == 0) continue; // no match to any file + if (Fallfiles && nfail) continue; // no match to all files + } + + if (Fdates) // date match is wanted + { + if (strcmp(xrec[iix].date,date1) < 0) continue; + if (strcmp(xrec[iix].date,date2) > 0) continue; + } + + if (Ftags) // tags match is wanted + { + strToLower(temp,xrec[iix].tags); + nmatch = nfail = 0; + + for (iis = 1; ; iis++) // step thru search tags + { + pps = strField(tags_searchtags,tagdelims,iis); // (delimited, wildcards) + if (! pps) break; + if (*pps == ' ') continue; + + for (iif = 1; ; iif++) // step thru file tags (delimited) + { + ppf = strField(temp,tagdelims,iif); + if (! ppf) { nfail++; break; } // count matches and fails + if (*ppf == ' ') continue; + if (MatchWild(pps,ppf) == 0) { nmatch++; break; } // wildcard match + } + } + + if (nmatch == 0) continue; // no match to any tag + if (Falltags && nfail) continue; // no match to all tags + } + + if (Fstars) // stars match is wanted + { + if (*searchStarsFrom && xrec[iix].stars < *searchStarsFrom) continue; + if (*searchStarsTo && xrec[iix].stars > *searchStarsTo) continue; + } + + if (Ftext) // text match is wanted + { + nmatch = nfail = 0; + + for (iis = 1; ; iis++) // step through search words + { + pps = strField(tags_searchtext,' ',iis); + if (! pps) break; + if (*pps == ' ') continue; + if (strcasestr(xrec[iix].capt,pps)) nmatch++; // search captions for word + else if (strcasestr(xrec[iix].comms,pps)) nmatch++; // search comments for word + else nfail++; + } + + if (nmatch == 0) continue; // no match to any word + if (Falltext && nfail) continue; // no match to all words + } + + if (++Nxrec == MAXIMAGES) goto toomanyfiles; // keep this record + } + + fclose(fid); + + if (! Nxrec) goto nomatches; + + snprintf(resultsfile,199,"%s/search_results",get_zuserdir()); + fid = fopen(resultsfile,"w"); // search results output file + if (! fid) goto writerror; + + for (iix = 0; iix < Nxrec; iix++) // write matching filespecs + fprintf(fid,"%s\n",xrec[iix].file); + + fclose(fid); + + image_gallery(resultsfile,"initF",0,m_gallery2,mWin); // generate gallery of matching files + // sort removed v.12.01 + image_gallery(0,"paint1"); // show new image gallery window + goto freememory; + +nomatches: + zmessageACK(mWin,ZTX("No matching images found")); + goto freememory; + +noindexfile: + zmessageACK(mWin,ZTX("No search index file present")); + goto freememory; + +writerror: + zmessLogACK(mWin,"output file error: %s",strerror(errno)); + goto freememory; + +toomanyfiles: + zmessLogACK(mWin,"too many image files"); + goto freememory; + +freememory: + for (iix = 0; iix < Nxrec; iix++) { // free allocated memory + if (xrec[iix].file) zfree(xrec[iix].file); + if (xrec[iix].tags) zfree(xrec[iix].tags); + if (xrec[iix].comms) zfree(xrec[iix].comms); + if (xrec[iix].capt) zfree(xrec[iix].capt); + } + zfree(xrec); + return 0; +} + + +/**************************************************************************/ + +// report metadata for the current set of image files +// (from a directory, a collection, or a search) + +namespace search_metadata +{ + char *keys[5]; // search keys and match data + char *match[5]; + char keyx[8], matchx[8]; +} + +void m_search_metadata(GtkWidget *, cchar *) // new v.12.01 +{ + using namespace search_metadata; + + int search_metadata_dialog_event(zdialog*, cchar *event); + + cchar *infomess = "These items are always reported: \n" + "date, stars, tags, caption, comment"; + zdialog *zd; + + if (mod_keep()) return; // unsaved edits + if (! menulock(1)) return; + menulock(0); + + zfuncs::F1_help_topic = "search_metadata"; + +/*** + Search Metadata (EXIF/IPTC etc.) + + These items from the current + image set are reported: date, + stars, tags, caption, comment + + Additional Items for Report + Keyword Match + [__________] [_________________] + [__________] [_________________] + [__________] [_________________] + [__________] [_________________] + [__________] [_________________] + + [proceed] [cancel] +***/ + + zd = zdialog_new("Search Metadata (EXIF/IPTC etc.)",mWin,Bproceed,Bcancel,null); + zdialog_add_widget(zd,"label","labinfo","dialog",infomess,"space=5"); + zdialog_add_widget(zd,"label","labopts","dialog",ZTX("Additional Items for Report")); + + zdialog_add_widget(zd,"hbox","hb1","dialog"); + zdialog_add_widget(zd,"vbox","vb1","hb1",0,"space=5"); + zdialog_add_widget(zd,"vbox","vb2","hb1",0,"space=5|expand"); + + zdialog_add_widget(zd,"label","lab1","vb1","Keyword"); + zdialog_add_widget(zd,"entry","key0","vb1"); + zdialog_add_widget(zd,"entry","key1","vb1"); + zdialog_add_widget(zd,"entry","key2","vb1"); + zdialog_add_widget(zd,"entry","key3","vb1"); + zdialog_add_widget(zd,"entry","key4","vb1"); + + zdialog_add_widget(zd,"label","lab2","vb2","Match"); + zdialog_add_widget(zd,"entry","match0","vb2",0,"expand"); + zdialog_add_widget(zd,"entry","match1","vb2",0,"expand"); + zdialog_add_widget(zd,"entry","match2","vb2",0,"expand"); + zdialog_add_widget(zd,"entry","match3","vb2",0,"expand"); + zdialog_add_widget(zd,"entry","match4","vb2",0,"expand"); + + strcpy(keyx,"keyx"); + strcpy(matchx,"matchx"); + + for (int ii = 0; ii < 5; ii++) // preload prior data if any + { + keyx[3] = '0' + ii; + if (keys[ii]) zdialog_stuff(zd,keyx,keys[ii]); + matchx[5] = '0' + ii; + if (match[ii]) zdialog_stuff(zd,matchx,match[ii]); + } + + zdialog_help(zd,"search_metadata"); + zdialog_resize(zd,400,300); + zdialog_run(zd,search_metadata_dialog_event); + return; +} + + +// dialog event and completion callback function + +struct xrec_t { // image metadata record + char *file; // image filespec + char *tags; // image tags + char *comms; // image comments + char *capt; // image caption + char date[12]; // image date + char stars; // image star rating, '0' to '5' +}; + + +int search_metadata_dialog_event(zdialog *zd, cchar *event) +{ + using namespace search_metadata; + using namespace image_navi; + + int metadata_xrec_compare(cchar *rec1, cchar *rec2); + int metadata_xrec_search(char *file, xrec_t *xrecs, int nrecs); + + char indexbuff[tagrecl], *file, **kvals; + char mdtext1[2*tagrecl], mdtext2[5][200]; + int err, ii, jj, iif, iix, nth, cc; + int Nxrec, Nkeys, Ncache, pcache, Fmeta; + char **ppcache = 0, *file2; + cchar *pp, *Fcache[50]; + FILE *fid; + struct stat statbuf; + + if (! zd->zstat) return 0; // wait for completion + + if (zd->zstat != 1) { + zdialog_free(zd); // cancel + return 0; + } + + if (! keys[0]) // first call initialization + { + for (ii = 0; ii < 5; ii++) { + keys[ii] = zmalloc(40,"search_metadata"); + match[ii] = zmalloc(100,"search_metadata"); + *keys[ii] = *match[ii] = 0; + } + } + + Nkeys = 0; + + for (ii = jj = 0; ii < 5; ii++) // get optional metadata keys + { + keyx[3] = '0' + ii; + zdialog_fetch(zd,keyx,keys[ii],40); + strCompress(keys[ii]); // remove all blanks from key names + if (*keys[ii] <= ' ') continue; + memmove(keys[jj],keys[ii],40); // repack blank keys + matchx[5] = '0' + ii; + zdialog_fetch(zd,matchx,match[ii],100); // get corresp. match value if any + strTrim2(match[jj],match[ii]); // trim leading and trailing blanks + if (ii > jj) *keys[ii] = *match[ii] = 0; + jj++; + } + + Nkeys = jj; // keys found, no blanks + + zdialog_free(zd); // cancel dialog + + cc = MAXIMAGES * sizeof(xrec_t); // allocate memory for index recs. + xrec_t *xrec = (xrec_t *) zmalloc(cc,"search_metadata"); + memset(xrec,0,cc); + + Nxrec = 0; + fid = fopen(search_index_file,"r"); + if (! fid) goto noindexfile; + *indexbuff = 0; + + while (true) // read index file + { + if (! strnEqu(indexbuff,"file: ",6)) { // skip to next "file" record + pp = fgets_trim(indexbuff,tagrecl,fid); + if (! pp) break; // EOF + continue; + } + + *indexbuff = 0; // prevent looping + + file = indexbuff + 6; + err=stat(file,&statbuf); // check file exists + if (err) continue; + + iix = Nxrec; + memset(&xrec[iix],0,sizeof(xrec)); + + xrec[iix].file = strdupz(file,0,"search_metadata"); // setup new xrec member + xrec[iix].stars = '0'; + + while (true) + { + pp = fgets_trim(indexbuff,tagrecl,fid); // get recs following "file" + if (! pp) break; + + if (strnEqu(pp,"date: ",6)) { + pp = strField(pp,' ',2); + if (pp) strncpy0(xrec[iix].date,pp,12); + } + + else if (strnEqu(pp,"tags: ",6)) + xrec[iix].tags = strdupz(pp+6,0,"search_metadata"); + + else if (strnEqu(pp,"stars: ",7)) + xrec[iix].stars = *(pp+7); + + else if (strnEqu(pp,"comms: ",7)) + xrec[iix].comms = strdupz(pp+7,0,"search_metadata"); + + else if (strnEqu(pp,"capt: ",6)) + xrec[iix].capt = strdupz(pp+6,0,"search_metadata"); + + else break; + } + + if (++Nxrec == MAXIMAGES) goto toomanyfiles; + } + + fclose(fid); + + if (! Nxrec) goto noindexfile; + + if (Nxrec > 1) // sort index records + HeapSort((char *) xrec, sizeof(xrec_t), Nxrec, metadata_xrec_compare); + + if (! mdlist) { + cc = nfiles * sizeof(char *); // allocate metadata list + mdlist = (char **) zmalloc(cc,"search_metadata"); + memset(mdlist,0,cc); + } + + Ncache = 0; // cache empty + pcache = 0; + + if (gallerytype == 3) gallerytype = 2; // make gallery deletes work + + for (iif = 0; iif < nfiles; iif++) // loop image gallery files + { + if (mdlist[iif]) zfree(mdlist[iif]); // clear prior metadata + mdlist[iif] = 0; + + file = image_gallery(0,"find",iif); // file gone? + if (! file) continue; + + if (image_file_type(file) != 2) { // remove directory from gallery list + nth = image_gallery_position(file,iif); + image_gallery(0,"delete",nth); + zfree(file); + iif--; + continue; + } + + iix = metadata_xrec_search(file,xrec,Nxrec); // get corresp. index record + + if (iix >= 0) // get metadata from index rec. + { + cc = 2 * tagrecl; + snprintf(mdtext1, cc," date: %s stars: %c\n caption: %s\n comments: %s\n tags: %s", + xrec[iix].date, xrec[iix].stars, xrec[iix].capt, xrec[iix].comms, xrec[iix].tags); + } + else *mdtext1 = 0; // none avail. + + if (Nkeys) // optional metadata requested + { + if (! Ncache) // cache is empty + { + for (jj = iif; Ncache < 50 && jj < nfiles; jj++) + { + file2 = image_gallery(0,"find",jj); + if (! file2) continue; + if (image_file_type(file2) == 2) { // put next 50 files into cache + Fcache[Ncache] = file2; + Ncache++; + } + else zfree(file2); + } + + if (Ncache) { + if (ppcache) zfree(ppcache); // get metadata for cached files + ppcache = info_getN(Fcache,Ncache,(cchar**) keys,Nkeys); + } + + pcache = 0; // first cache position + } + + file2 = (char *) Fcache[pcache]; // next cached file + kvals = ppcache + Nkeys * pcache; // key values for cached file + + if (Ncache && strEqu(file,file2)) { // cached metadata is for this file + Fmeta = 1; + Ncache--; // index cache to next + pcache++; + } + else Fmeta = 0; // no metadata for this file + + for (jj = 0; jj < Nkeys; jj++) { // check key values for match + if (*match[jj] > ' ') { // match value(s) are present + if (! Fmeta) break; // metadata not available + if (! kvals[jj]) break; // key not present in metadata + for (nth = 1; ; nth++) { + pp = strField(match[jj],' ',nth); // get each match value + if (! pp) break; // no more, no match found + if (strcasestr(kvals[jj],pp)) break; // found match + } + if (! pp) break; // no match found + } + } + + if (jj < Nkeys) { // at least one match fail + nth = image_gallery_position(file,iif); // remove file from gallery list + image_gallery(0,"delete",nth); + iif--; + zfree(file2); // free memory + for (jj = 0; jj < Nkeys; jj++) + if (kvals[jj]) zfree(kvals[jj]); + continue; // skip this file + } + else { // all metadata matched + for (jj = 0; jj < 5; jj++) + mdtext2[jj][0] = 0; + for (jj = 0; jj < Nkeys; jj++) // add metadata to report + snprintf(mdtext2[jj], 200, "\n key: %s value: %s", keys[jj], kvals[jj]); + strncatv(mdtext1, cc, mdtext2[0], mdtext2[1], mdtext2[2], mdtext2[3], mdtext2[4], null); + zfree(file2); // free memory + for (jj = 0; jj < Nkeys; jj++) + if (kvals[jj]) zfree(kvals[jj]); + } // keep this file + } + + mdlist[iif] = strdupz(mdtext1,0,"metadata report"); // attach metadata for gallery paint + zfree(file); + } + + if (galleryname) zfree(galleryname); + galleryname = strdupz("metadata report"); + gallerytype = 3; // outlaw gallery adds/deletes + image_gallery(0,"paint1"); // show new image gallery window + goto freememory; + +noindexfile: + zmessageACK(mWin,ZTX("No search index file present")); + goto freememory; + +toomanyfiles: + zmessLogACK(mWin,"too many image files"); + goto freememory; + +freememory: + if (ppcache) zfree(ppcache); + for (iix = 0; iix < Nxrec; iix++) { // free allocated memory + if (xrec[iix].file) zfree(xrec[iix].file); + if (xrec[iix].tags) zfree(xrec[iix].tags); + if (xrec[iix].comms) zfree(xrec[iix].comms); + if (xrec[iix].capt) zfree(xrec[iix].capt); + } + zfree(xrec); + + return 0; +} + + +// sort compare function - compare xrec files and return +// returns <0 0 >0 for file1 < = > file2 + +int metadata_xrec_compare(cchar *rec1, cchar *rec2) +{ + char * file1 = ((xrec_t *) rec1)->file; + char * file2 = ((xrec_t *) rec2)->file; + return strcmp(file1,file2); +} + + +// perform a binary search for a file within sorted xrecs in memory +// return matching record number (0 based) or -1 if not found +// execution time < 1 microsec. + +int metadata_xrec_search(char *file, xrec_t *xrecs, int nrecs) +{ + int ii, jj, kk, rkk; + + ii = nrecs / 2; // next element to search + jj = (ii + 1) / 2; // next increment + nrecs--; // last element + rkk = 0; + + while (true) + { + kk = strcmp(xrecs[ii].file,file); // compare member rec to seek rec + + if (kk > 0) + { + ii -= jj; // too high, go down in set + if (ii < 0) return -1; + } + + else if (kk < 0) + { + ii += jj; // too low, go up in set + if (ii > nrecs) return -1; + } + + else if (kk == 0) return ii; // matched + + jj = jj / 2; // reduce increment + + if (jj == 0) + { + jj = 1; // step by 1 element + if (! rkk) rkk = kk; // save direction + else + { + if (rkk > 0) { if (kk < 0) return -1; } // if change direction, fail + else if (kk > 0) return -1; + } + } + } +} + + + diff -Nru fotoxx-11.11.1/f.navi.cc fotoxx-12.01.2/f.navi.cc --- fotoxx-11.11.1/f.navi.cc 1970-01-01 00:00:00.000000000 +0000 +++ fotoxx-12.01.2/f.navi.cc 2012-01-04 08:47:11.000000000 +0000 @@ -0,0 +1,1662 @@ +/************************************************************************** + + Fotoxx edit photos and manage collections + + Copyright 2007 2008 2009 2010 2011 2012 Michael Cornelison + Source URL: http://kornelix.squarespace.com/fotoxx + Contact: kornelix2@googlemail.com + + 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 http://www.gnu.org/licenses/. + +***************************************************************************/ + +#define EX extern // enable extern declarations +#include "fotoxx.h" + + +/************************************************************************** + + Fotoxx image edit - functions for navigation of image files + +**************************************************************************/ + + + GtkWidget *wing = 0, *vboxx, *scrwing, *layout; // image gallery and drawing windows + GtkWidget *pwing = 0; // parent window + GtkAdjustment *scrollbar; + GdkGC *gdkgc2 = 0; // graphics context + +namespace image_navi +{ + #define thumbnail_cachesize 10000 // max thumbnails cached in memory + #define imagetypes ".jpeg .jpg .png .tif .tiff .bmp .gif .svg .xpm" // supported image file types + + #define TEXTWIN GTK_TEXT_WINDOW_TEXT // GDK window of GTK text view + #define NODITHER GDK_RGB_DITHER_NONE + #define SCROLLWIN GTK_SCROLLED_WINDOW + #define NEVER GTK_POLICY_NEVER + #define ALWAYS GTK_POLICY_ALWAYS + #define interp GDK_INTERP_BILINEAR + #define colorspace GDK_COLORSPACE_RGB + + int thumbfilesize = 256; // default thumbnail image size + #define thumbxx 6 // thumbx array size + int thumbx[6] = { 512, 360, 256, 180, 128, 90 }; // thumbnail image step sizes + + char *galleryname = 0; // image directory or file list name + int gallerytype = 0; // 1/2/3 = directory/file-list/metadata + int nfiles = 0; // total file count (incl. subdirks) + int nimages = 0; // image file count + char **flist = 0; // image file list + char **mdlist = 0; // corresp. metadata + + typedef void ufunc(int Nth, int button); // callback function for clicked image + ufunc *userfunc; + + int xwinW = 1000, xwinH = 700; // gallery window initial size + int xwinX, xwinY; // gallery window initial position + int thumbsize = thumbfilesize; // thumbnail image <= thumbnail file + int thumbW, thumbH; // gallery window thumbnail cell size + int xrows, xcols; // gallery window thumbnail rows, cols + int margin = 5; // cell margin from left and top edge + int genthumbs = 0; // count newly generated thumbnails + int scrollposn; // gallery window scroll position + int maxscroll; // max. scroll position + int fpresent = 0; // force gallery window to z-top + int targposn = 0; // scroll-to file position (Nth) + + // private functions + int gallery_paint(GtkWidget *, GdkEventExpose *); // gallery window paint function + int gallery_paint_metadata(GdkEventExpose *expose); // "" for metadata report + void draw_text(GtkWidget *win, char *text, int x, int y, int ww); // draw text in gallery window + void gallery_destroy(); // gallery window destroy event function + void menufuncx(GtkWidget *win, cchar *menu); // function for gallery window buttons + void mouse_xevent(GtkWidget *, GdkEventButton *, void *); // gallery window mouse event function + int KBxpress(GtkWidget *, GdkEventKey *, void *); // gallery window key press event func. + int KBxrelease(GtkWidget *, GdkEventKey *, void *); // gallery window key release event + char * image_navigate(cchar *filez, cchar *action, int Nth = 0); // image file list setup and navigate + int image_fcomp(cchar *file1, cchar *file2); // file name compare (special sort) +} + + +/************************************************************************** + + public function to create/update image gallery (thumbnail window) // overhauled + + Make window scrolling window of thumbnails for a list of files + Handle window buttons (up row, down page, open file, etc.) + Call ufunc() when thumbnail image is clicked + + char * image_gallery(cchar *filez, cchar *action, int Nth, + void ufunc(int Nth, int button), GtkWidget *parent) + + filez: image file or directory of image files or file with list of image files + + action: init: filez = initial file or directory + initF: filez = file with list of image files to use + sort: sort the file list, directories first, ignore case + insert: insert filez into file list at position Nth (0 to last+1) + delete: delete Nth file in list + find: return Nth file (0 base) or null if Nth > last + paint1: create or refresh gallery window, anchor = Nth file + paint2: refresh gallery window if present, anchor = Nth file + close close gallery window + + Nth: file to return (action = find) or file to scroll-to (action = paint) + + void ufunc(int Nth, int button): + - returns Nth of clicked thumbnail (0 to last) + - returns -1 if gallery window is closed + - returns -2 if key F1 is pressed (for context help) + - button is mouse button used on clicked thumbnail + + parent: optional parent window + if present, gallery window will overlay the parent window + (window placement can be undone by the user) + + Returned values: + Nth: filespec, others: null + The returned file belongs to caller and is subject for zfree(). + +***************************************************************************/ + +char * image_gallery(cchar *filez, cchar *action, int Nth, + void ufunc(int Nth, int button), GtkWidget *parent) +{ + using namespace image_navi; + + GtkWidget *tbarx; + + zthreadcrash(); // thread usage not allowed + + if (ufunc) userfunc = ufunc; // save callback function + if (parent) pwing = parent; // save parent window + + if (strstr("init initF sort insert delete find",action)) + return image_navigate(filez,action,Nth); // create or navigate image file list + + if (strEqu(action,"close")) { + if (wing) gtk_widget_destroy(wing); + return 0; + } + + if (! strnEqu(action,"paint",5)) // must be paint1 or paint2 + zappcrash("image_gallery action: %s",action); + + if (strEqu(action,"paint2") && ! wing) return 0; // refresh but window not active + if (strEqu(action,"paint1")) fpresent++; // bring window to z-top + + if (Nth >= 0) targposn = Nth; // scroll-to file position + else if (filez) targposn = image_gallery_position(filez,0); // or use filez if present + if (targposn > nfiles-1) targposn = nfiles-1; // (-1 for no change) + + if (wing) { // repaint existing gallery window + gallery_paint(0,0); + return 0; + } + + wing = gtk_window_new(GTK_WINDOW_TOPLEVEL); // create new gallery window + + if (pwing) { + gtk_window_get_size(GTK_WINDOW(pwing),&xwinW,&xwinH); // overlay parent window + gtk_window_get_position(GTK_WINDOW(pwing),&xwinX,&xwinY); + gtk_window_set_default_size(GTK_WINDOW(wing),xwinW,xwinH); + gtk_window_move(GTK_WINDOW(wing),xwinX,xwinY); + } + else { + gtk_window_set_default_size(GTK_WINDOW(wing),xwinW,xwinH+56); // + toolbar size to stop shrinkage + gtk_window_set_position(GTK_WINDOW(wing),GTK_WIN_POS_MOUSE); + } + + vboxx = gtk_vbox_new(0,0); // vertical packing box + gtk_container_add(GTK_CONTAINER(wing),vboxx); // add to main window + + tbarx = create_toolbar(vboxx,24); // add toolbar and buttons + gtk_toolbar_set_style(GTK_TOOLBAR(tbarx),GTK_TOOLBAR_BOTH); + + add_toolbar_button(tbarx, ZTX("bigger"), ZTX("increase thumbnail size"), "gtk-zoom-in", menufuncx); + add_toolbar_button(tbarx, ZTX("smaller"), ZTX("reduce thumbnail size"), "gtk-zoom-out", menufuncx); + add_toolbar_button(tbarx, ZTX("parent"), ZTX("parent directory"), "folder.png", menufuncx); + add_toolbar_button(tbarx, ZTX("first page"), ZTX("jump to first file"), "first-page.png", menufuncx); + add_toolbar_button(tbarx, ZTX("prev page"), ZTX("previous page"), "prev-page.png", menufuncx); + add_toolbar_button(tbarx, ZTX("prev row"), ZTX("previous row"), "prev-row.png", menufuncx); + add_toolbar_button(tbarx, ZTX("next row"), ZTX("next row"), "next-row.png", menufuncx); + add_toolbar_button(tbarx, ZTX("next page"), ZTX("ttip::next page"), "next-page.png", menufuncx); + add_toolbar_button(tbarx, ZTX("last page"), ZTX("jump to last file"), "last-page.png", menufuncx); + add_toolbar_button(tbarx, ZTX("close"), ZTX("close image gallery"), "gtk-close", menufuncx); + + gtk_toolbar_set_style(GTK_TOOLBAR(tbarx),GTK_TOOLBAR_BOTH); // set toolbar style v.12.01 + if (strEqu(tbar_style,"icons")) + gtk_toolbar_set_style(GTK_TOOLBAR(tbarx),GTK_TOOLBAR_ICONS); + if (strEqu(tbar_style,"text")) + gtk_toolbar_set_style(GTK_TOOLBAR(tbarx),GTK_TOOLBAR_TEXT); + + scrwing = gtk_scrolled_window_new(0,0); // create scrolled window + gtk_container_add(GTK_CONTAINER(vboxx),scrwing); // add to main window + layout = gtk_layout_new(0,0); // create drawing window + gtk_layout_set_size(GTK_LAYOUT(layout),xwinW,xwinH); // initial size v.12.01 + gtk_container_add(GTK_CONTAINER(scrwing),layout); // add to scrolled window + gtk_scrolled_window_set_policy(SCROLLWIN(scrwing),NEVER,ALWAYS); // vertical scroll bar + scrollbar = gtk_layout_get_vadjustment(GTK_LAYOUT(layout)); + + G_SIGNAL(wing,"destroy",gallery_destroy,0); // connect window events + G_SIGNAL(layout,"expose-event",gallery_paint,0); + gtk_widget_add_events(layout,GDK_BUTTON_PRESS_MASK); // connect mouse events + G_SIGNAL(layout,"button-press-event",mouse_xevent,0); + G_SIGNAL(wing,"key-press-event",KBxpress,0); // connect KB events + G_SIGNAL(wing,"key-release-event",KBxrelease,0); + + gtk_widget_show_all(wing); // show all widgets + gdkgc2 = gdk_gc_new(layout->window); // initz. graphics context + gallery_paint(0,0); // repaint + gtk_window_present(GTK_WINDOW(wing)); // bring gallery window to top + zmainloop(); + + return 0; +} + + +// expose event private function +// paint gallery window - draw all thumbnail images that can fit + +int image_navi::gallery_paint(GtkWidget *, GdkEventExpose *expose) +{ + using namespace image_navi; + + GdkPixbuf *pxbT; + GdkRectangle rect; + int ii, nrows, row1, row2; + int currscrollposn; + int layoutW, layoutH; + int expy1, expy2, row, col; + int thumx, thumy, orgx, orgy, ww, hh; + int stat, popup = 0; + char *pp, *fname; + char wintitle[200]; + char filep0; + + if (gallerytype == 3) { + stat = gallery_paint_metadata(expose); // v.12.01 + return stat; + } + + xwinW = layout->allocation.width; // curr. gallery window size + xwinH = layout->allocation.height; + + thumbW = thumbsize + 10; // thumbnail cell size + thumbH = thumbsize + 30; + + if (! thumbsize) { + thumbW = 400; // zero, list view + thumbH = 20; + } + + xrows = int(0.2 + 1.0 * xwinH / thumbH); // get thumbnail rows and cols that + xcols = int(0.3 + 1.0 * xwinW / thumbW); // (almost) fit in window + if (xrows < 1) xrows = 1; + if (xcols < 1) xcols = 1; + nrows = (nfiles+xcols-1) / xcols; // thumbnail rows, 1 or more + if (nrows < 1) nrows = 1; // bugfix + + layoutW = xcols * thumbW + margin + 10; // layout size for entire file list + layoutH = (nrows+1) * thumbH + margin; // last row + 1 + if (layoutH < xwinH) layoutH = xwinH; // bugfix + gtk_layout_set_size(GTK_LAYOUT(layout),layoutW,layoutH); + + maxscroll = layoutH - xwinH; // scroll to end of layout + if (maxscroll < 0) maxscroll = 0; + + gtk_adjustment_set_step_increment(scrollbar,thumbH); // scrollbar works in row steps + gtk_adjustment_set_page_increment(scrollbar,thumbH * xrows); // and in page steps + + currscrollposn = gtk_adjustment_get_value(scrollbar); // current scroll position + scrollposn = currscrollposn; + + if (targposn >= 0) { + scrollposn = targposn / xcols * thumbH; // set initial scroll position from + if (scrollposn > maxscroll) scrollposn = maxscroll; // target file position if defined, + scrollposn = scrollposn / thumbH * thumbH; // then disable it for local control + } // of scrolling from gallery window + targposn = -1; + + if (scrollposn > maxscroll) scrollposn = maxscroll; // bugfix + + if (scrollposn != currscrollposn) + gtk_adjustment_set_value(scrollbar,scrollposn); // will cause re-entrance + + if (! expose) // initial window or navigation button + { + snprintf(wintitle,199,"%s %d files",galleryname,nfiles); // window title: gallery name and file count + gtk_window_set_title(GTK_WINDOW(wing),wintitle); + gdk_window_invalidate_rect(wing->window,0,1); // will cause re-entrance + if (fpresent) gtk_window_present(GTK_WINDOW(wing)); // bring window to top + zmainloop(); + fpresent = 0; + return 0; + } + + rect = expose->area; // exposed area to refresh + expy1 = rect.y; + expy2 = expy1 + rect.height; + row1 = expy1 / thumbH; + row2 = expy2 / thumbH; + + ii = row1 * xcols; // 1st image file in top row + if (ii >= nfiles) return 1; + + for (row = row1; row <= row2; row++) // draw file thumbnails + for (col = 0; col < xcols; col++) + { + if (genthumbs == 1 && ! popup) { // inform user of delay + write_popup_text("open","please wait",200,10,wing); + write_popup_text("write","\n generating thumbnails"); // 1st pass gtk bug, no text //// + genthumbs = 2; + popup = 1; + } + if (genthumbs < 5) zmainloop(); // mysterious, necessary //// + + thumx = col * thumbW + margin; // upper left corner in window space + thumy = row * thumbH + margin; + + filep0 = *flist[ii]; + *flist[ii] = '/'; // get filespec, replace ! with / + + if (thumy < expy2 && thumy+14 > expy1) { // if in exposed area, + pp = (char *) strrchr(flist[ii],'/'); // draw file name + if (pp) fname = pp + 1; + else fname = flist[ii]; + draw_text(layout,fname,thumx,thumy,thumbW-5); + } + + if (thumbsize) // zero >> list view + pxbT = image_thumbnail(flist[ii],thumbsize); // get thumbnail + else pxbT = 0; + + *flist[ii] = filep0; // restore posn. 0 bugfix v.12.01 + + if (pxbT) { + thumy = thumy + 16; // thumbnail 16 pixels down from text + orgx = 0; + orgy = 0; + ww = gdk_pixbuf_get_width(pxbT); + hh = gdk_pixbuf_get_height(pxbT); + + if (thumy < expy1) { + orgy = orgy + (expy1 - thumy); + hh = hh - (expy1 - thumy); + } + if (thumy + orgy + hh > expy2) + hh = hh - (thumy + orgy + hh - expy2); + + if (orgy >= 0 && hh > 0) + gdk_draw_pixbuf(GTK_LAYOUT(layout)->bin_window,0,pxbT, + orgx,orgy,thumx+orgx,thumy+orgy,ww,hh,NODITHER,0,0); + g_object_unref(pxbT); + } + + if (++ii == nfiles) goto thumbsdone; // EOL + } + +thumbsdone: + + if (popup) { + write_popup_text("close"); + genthumbs = 0; + } + + return 1; +} + + +// expose event private function for metadata gallery report +// paint gallery window - draw all thumbnail images that can fit + +int image_navi::gallery_paint_metadata(GdkEventExpose *expose) // v.12.01 +{ + using namespace image_navi; + + GdkPixbuf *pxbT; + GdkRectangle rect; + int ii, nrows, row1, row2; + int currscrollposn; + int layoutW, layoutH; + int expy1, expy2, row, col; + int thumx, thumy, orgx, orgy, ww, hh; + int popup = 0, textww; + char wintitle[200]; + + xwinW = layout->allocation.width; // curr. gallery window size + xwinH = layout->allocation.height; + + if (thumbsize < 64) thumbsize = 64; + thumbW = thumbsize + 10; // thumbnail layout size + thumbH = thumbsize + 20; + + xrows = int(0.2 + 1.0 * xwinH / thumbH); // get thumbnail rows fitting in window + if (xrows < 1) xrows = 1; + xcols = 1; // force cols = 1 + nrows = nfiles; // thumbnail rows + + layoutW = xwinW; // layout size for entire file list + if (layoutW < 800) layoutW = 800; + layoutH = (nrows+1) * thumbH + margin; // last row + 1 + if (layoutH < xwinH) layoutH = xwinH; + gtk_layout_set_size(GTK_LAYOUT(layout),layoutW,layoutH); + + textww = layoutW - thumbW - 2 * margin; // space for text right of thumbnail + + maxscroll = layoutH - xwinH; // scroll to end of layout + if (maxscroll < 0) maxscroll = 0; + + gtk_adjustment_set_step_increment(scrollbar,thumbH); // scrollbar works in row steps + gtk_adjustment_set_page_increment(scrollbar,thumbH * xrows); // and in page steps + + currscrollposn = gtk_adjustment_get_value(scrollbar); // current scroll position + scrollposn = currscrollposn; + + if (targposn >= 0) { + scrollposn = targposn / xcols * thumbH; // set initial scroll position from + if (scrollposn > maxscroll) scrollposn = maxscroll; // target file position if defined, + scrollposn = scrollposn / thumbH * thumbH; // then disable it for local control + } // of scrolling from gallery window + targposn = -1; + + if (scrollposn > maxscroll) scrollposn = maxscroll; + + if (scrollposn != currscrollposn) + gtk_adjustment_set_value(scrollbar,scrollposn); // will cause re-entrance + + if (! expose) // initial window or navigation button + { + snprintf(wintitle,199,"%s %d files",galleryname,nfiles); // window title: gallery name and file count + gtk_window_set_title(GTK_WINDOW(wing),wintitle); + gdk_window_invalidate_rect(wing->window,0,1); // will cause re-entrance + if (fpresent) gtk_window_present(GTK_WINDOW(wing)); // bring window to top + zmainloop(); + fpresent = 0; + return 0; + } + + rect = expose->area; // exposed area to refresh + expy1 = rect.y; + expy2 = expy1 + rect.height; + row1 = expy1 / thumbH; + row2 = expy2 / thumbH; + + ii = row1 * xcols; // 1st image file in top row + if (ii >= nfiles) return 1; + + for (row = row1; row <= row2; row++) // draw file thumbnails + for (col = 0; col < xcols; col++) + { + if (genthumbs == 1 && ! popup) { // inform user of delay + write_popup_text("open","please wait",200,10,wing); + write_popup_text("write","\n generating thumbnails"); // 1st pass gtk bug, no text //// + genthumbs = 2; + popup = 1; + } + if (genthumbs < 5) zmainloop(); // mysterious, necessary //// + + thumx = col * thumbW + margin; // upper left corner in window space + thumy = row * thumbH + margin; + + pxbT = image_thumbnail(flist[ii],thumbsize); // get thumbnail + + if (pxbT) { + orgx = 0; + orgy = 0; + ww = gdk_pixbuf_get_width(pxbT); + hh = gdk_pixbuf_get_height(pxbT); + + if (thumy < expy1) { // position in layout + orgy = orgy + (expy1 - thumy); + hh = hh - (expy1 - thumy); + } + if (thumy + orgy + hh > expy2) + hh = hh - (thumy + orgy + hh - expy2); + + if (orgy >= 0 && hh > 0) // write in layout + gdk_draw_pixbuf(GTK_LAYOUT(layout)->bin_window,0,pxbT, + orgx,orgy,thumx+orgx,thumy+orgy,ww,hh,NODITHER,0,0); + g_object_unref(pxbT); + } + + draw_text(layout,flist[ii],thumbW+margin,thumy,textww); // write filespec to right of thumbnail + + if (mdlist && mdlist[ii]) // write metadata if present + draw_text(layout,mdlist[ii],thumbW+margin,thumy+20,textww); + + if (++ii == nfiles) goto thumbsdone; // EOL + } + +thumbsdone: + + if (popup) { + write_popup_text("close"); + genthumbs = 0; + } + + return 1; +} + + +// private function +// write text for thumbnail limited by width of thumbnail + +void image_navi::draw_text(GtkWidget *win, char *text, int x, int y, int ww) +{ + using namespace image_navi; + + static PangoFontDescription *pfont = 0; + static PangoLayout *playout = 0; + + int nn; + static int thumbsize2 = 0; + static char thumbfont[12] = ""; + + if (thumbsize != thumbsize2) { // scale file name font to thumbnail size + thumbsize2 = thumbsize; + nn = 7 + thumbsize / 128; // font size from 7 to 10 + if (thumbsize == 0) nn = 9; // list view, use 9 + sprintf(thumbfont,"sans %d",nn); + pfont = pango_font_description_from_string(thumbfont); + playout = gtk_widget_create_pango_layout(win,0); + pango_layout_set_font_description(playout,pfont); + } + + pango_layout_set_width(playout,ww*PANGO_SCALE); // limit width to avail. space v.12.01 + pango_layout_set_ellipsize(playout,PANGO_ELLIPSIZE_END); + pango_layout_set_text(playout,text,-1); + + gdk_draw_layout(GTK_LAYOUT(win)->bin_window,gdkgc2,x,y,playout); + return; +} + + +// private function +// gallery window destroy event - mark window not active. + +void image_navi::gallery_destroy() +{ + using namespace image_navi; + + wing = 0; // no window + if (userfunc) userfunc(-1,0); // tell caller + return; +} + + +// private function - menu function for gallery window +// - scroll window as requested +// - jump to new file or folder as requested + +void image_navi::menufuncx(GtkWidget *win, cchar *menu) +{ + using namespace image_navi; + + int ii, yn, Gwarn, scrollp; + char *filez, *pp; + + if (strEqu(menu,ZTX("close"))) { // close image gallery window + gtk_widget_destroy(wing); // destroy event function calls userfunc(-1) + return; + } + + if (strEqu(menu,ZTX("bigger"))) { // next bigger thumbnail size + for (ii = 0; ii < thumbxx; ii++) + if (thumbsize == thumbx[ii]) break; + if (ii == 0) return; + thumbsize = thumbx[ii-1]; + targposn = scrollposn / thumbH * xcols; // keep top row position + gallery_paint(0,0); + return; + } + + if (strEqu(menu,ZTX("smaller"))) { // next smaller + for (ii = 0; ii < thumbxx; ii++) + if (thumbsize == thumbx[ii]) break; + if (ii >= thumbxx-1) thumbsize = 0; // no thumbs, list view + else thumbsize = thumbx[ii+1]; + if (thumbsize <= 128 && gallerytype == 3) // min. size for metadata report v.12.01 + thumbsize = 128; + targposn = scrollposn / thumbH * xcols; // keep top row position + gallery_paint(0,0); + return; + } + + scrollp = scrollposn; + + if (strEqu(menu,ZTX("parent"))) { + Gwarn = 0; + if (image_navi::gallerytype > 1) Gwarn = 1; // warn if discarding search or + pp = image_navi::galleryname; // collection type gallery + if (pp && strEqu(pp,"Recent Files")) Gwarn = 0; // v.12.01 + if (Gwarn) { // if gallery not from a directory, + yn = zmessageYN(wing,Bdiscard,image_navi::galleryname); // warn user, gallery will be discarded + if (! yn) return; // do not discard + } + if (galleryname && gallerytype == 1) + filez = strdupz(galleryname,0,"image_navi"); + else filez = strdupz(curr_dirk,0,"image_navi"); // v.12.01 + pp = strrchr(filez,'/'); // go up to '/' and stop + if (pp && pp > filez) *pp = 0; + else filez = strdupz("/",0,"image_navi"); // v.12.01 + image_navigate(filez,"init"); // get new file list + gallery_paint(0,0); + zfree(filez); + scrollp = 0; + } + + if (strEqu(menu,ZTX("prev row"))) scrollp -= thumbH; + if (strEqu(menu,ZTX("next row"))) scrollp += thumbH; + if (strEqu(menu,ZTX("prev page"))) scrollp -= thumbH * xrows; + if (strEqu(menu,ZTX("next page"))) scrollp += thumbH * xrows; + if (strEqu(menu,ZTX("first page"))) scrollp = 0; + if (strEqu(menu,ZTX("last page"))) scrollp = maxscroll; + + if (scrollp < 0) scrollp = 0; // enforce limits + if (scrollp > maxscroll) scrollp = maxscroll; + scrollp = scrollp / thumbH * thumbH; // align top row + + if (scrollp != scrollposn) + gtk_adjustment_set_value(scrollbar,scrollp); + + return; +} + + +// private function +// mouse event function for gallery window - get selected thumbnail and file +// user function receives clicked file, which is subject for zfree() + +void image_navi::mouse_xevent(GtkWidget *, GdkEventButton *event, void *) +{ + using namespace image_navi; + + int mousex, mousey, mousebutt; + int row, col, nrows, ii, err; + char *filez; + struct stat statb; + + if (! nfiles) return; // empty window + + mousex = int(event->x); + mousey = int(event->y); + mousebutt = event->button; + + row = (mousey - margin) / thumbH; // find selected row, col + col = (mousex - margin) / thumbW; + + nrows = 1 + (nfiles-1) / xcols; // total thumbnail rows, 1 or more + if (col < 0 || col >= xcols) return; + if (row < 0 || row >= nrows) return; + + ii = xcols * row + col; + if (ii >= nfiles) return; + + filez = strdupz(flist[ii],0,"image_navi"); // selected file + *filez = '/'; + + err = stat(filez,&statb); + if (err) { // file is gone? + zfree(filez); + return; + } + + if (S_ISDIR(statb.st_mode)) { // if directory, go there + image_navigate(filez,"init"); + gallery_paint(0,0); + zfree(filez); + return; + } + + if (userfunc) userfunc(ii,mousebutt); // clicked file position to user + return; +} + + +// private function +// KB event function - respond to keyboard navigation keys +// key definitions: /usr/include/gtk-2.0/gdk/gdkkeysyms.h + +int image_navi::KBxpress(GtkWidget *win, GdkEventKey *event, void *) // prevent propagation of key-press +{ // events to toolbar buttons + return 1; +} + +int image_navi::KBxrelease(GtkWidget *win, GdkEventKey *event, void *) +{ + using namespace image_navi; + + int KBkey; + + KBkey = event->keyval; + + if (KBkey == GDK_plus) menufuncx(win,ZTX("bigger")); // +/- = bigger/smaller thumbnails + if (KBkey == GDK_equal) menufuncx(win,ZTX("bigger")); + if (KBkey == GDK_minus) menufuncx(win,ZTX("smaller")); + if (KBkey == GDK_KP_Add) menufuncx(win,ZTX("bigger")); // keypad +/- also + if (KBkey == GDK_KP_Subtract) menufuncx(win,ZTX("smaller")); + + if (KBkey == GDK_Left) menufuncx(win,ZTX("prev page")); // left arrow = previous page + if (KBkey == GDK_Right) menufuncx(win,ZTX("next page")); // right arrow = next page + if (KBkey == GDK_Up) menufuncx(win,ZTX("prev row")); // up arrow = previous row + if (KBkey == GDK_Down) menufuncx(win,ZTX("next row")); // down arrow = next row + + if (KBkey == GDK_Home) menufuncx(win,ZTX("first page")); // keys added + if (KBkey == GDK_End) menufuncx(win,ZTX("last page")); + if (KBkey == GDK_Page_Up) menufuncx(win,ZTX("prev page")); + if (KBkey == GDK_Page_Down) menufuncx(win,ZTX("next page")); + + if (KBkey == GDK_Escape) gtk_widget_destroy(win); // Escape = cancel gallery window + + if (KBkey == GDK_F1) + showz_userguide(zfuncs::F1_help_topic); + + return 1; +} + + +// Public function - get file position in file list. +// If Nth position matches file, this is returned. +// Otherwise the file is searched from position 0. +// Position 0-last is returned if found, or -1 if not. + +int image_gallery_position(cchar *file, int Nth) +{ + using namespace image_navi; + + int ii; + + if (! nfiles) return -1; + + if (Nth >= 0 && Nth < nfiles) ii = Nth; + else ii = 0; + + if (strEqu(file+1,flist[ii]+1)) return ii; // 1st flist[ii] char. may be ! + + for (ii = 0; ii < nfiles; ii++) + if (strEqu(file+1,flist[ii]+1)) break; + + if (ii < nfiles) return ii; + return -1; +} + + +// public function +// determine if a file is a directory or a supported image file type +// return: 0 = error, 1 = directory, 2 = image file, 3 = other + +int image_file_type(cchar *file) +{ + using namespace image_navi; + + int err, cc; + cchar *pp; + struct stat statbuf; + + if (! file) return 0; + err = stat(file,&statbuf); + if (err) return 0; + + if (S_ISDIR(statbuf.st_mode)) { // directory + cc = strlen(file); + if (cc > 12) { + pp = file + cc - 12; + if (strEqu(pp,"/.thumbnails")) return 3; // .thumbnails + } + return 1; + } + + if (S_ISREG(statbuf.st_mode)) { // reg. file + pp = strrchr(file,'.'); + if (! pp) return 3; + pp = strcasestr(imagetypes,pp); // supported image type + if (pp) return 2; + } + + return 3; +} + + +// Public function +// Get thumbnail filespec for the given image file. +// If missing or stale, add or update in /.thumbnails directory. +// Returned filespec is subject for zfree(). +// Use 4 threads to build missing thumbnails asynchrounously +// (and hopefully ahead of need). + +namespace image_thumbs +{ + char * image_thumbfile_1x(char *imagefile); + void * image_thumbfile_thread(void *arg); + int image_thumbfile_lock(char *imagefile, int lock); + char *imagefilex; + char *thumbfilex; + char *directoryx; + char **filelistx; + int Nfilesx; + int indexx; + int busythreads; + int stopthreads; + char *lockfiles[5]; + mutex filelock = PTHREAD_MUTEX_INITIALIZER; + mutex thumblock = PTHREAD_MUTEX_INITIALIZER; +} + + +char * image_thumbfile(char *imagefile) +{ + using namespace image_thumbs; + + char *thumbfile, *directory; + char *pfile, *bfile, *buff; + cchar *findcommand = "find \"%s\" -maxdepth 1"; + struct stat statf, statb; + int err, ftyp, contx = 0; + + zthreadcrash(); // thread usage not allowed + + err = stat(imagefile,&statf); + if (err) return 0; + if (! S_ISREG(statf.st_mode)) return 0; // not a regular file + if (image_file_type(imagefile) != 2) return 0; // unsupported image type + + pfile = strrchr(imagefile,'/'); // get .../filename.xxx + if (! pfile) return 0; + if (pfile > imagefile+12 && strnEqu(pfile-12,"/.thumbnails/",13)) { // .../.thumbnails/filename.xxx ?? + thumbfile = strdupz(imagefile,0,"image_thumbfile"); // yes, a thumbnail file + return thumbfile; // return same file + } + + thumbfile = strdupz(imagefile,20,"image_thumbfile"); // construct thumbnail file + bfile = thumbfile + (pfile - imagefile); // .../.thumbnails/filename.xxx.png + strcpy(bfile,"/.thumbnails"); + bfile += 12; + strcpy(bfile,pfile); + strcat(bfile,".png"); + + err = stat(thumbfile,&statb); // thumbnail file exists ?? + if (! err) { // yes + if (statb.st_mtime >= statf.st_mtime) return thumbfile; // up to date, return it + zfree(thumbfile); + thumbfile = image_thumbfile_1x(imagefile); // refresh stale thumbnail + return thumbfile; // return it + } + + zfree(thumbfile); + + directory = strdupz(imagefile,0,"image_thumbfile"); // thumbnail does not exist + pfile = strrchr(directory,'/'); + pfile[1] = 0; // image directory/ + + if (! directoryx) directoryx = directory; // first use + else if (strNeq(directoryx,directory)) { // new directory to search + stopthreads = 1; + while (busythreads) zsleep(0.001); // stop prior search if any + zfree(directoryx); + directoryx = directory; // directory for new search + } + else zfree(directory); // no change + + imagefilex = imagefile; // target thumbnail to get + + while (busythreads) { // if ongoing search, request thumbnail + if (! imagefilex) return thumbfilex; // from existing search threads + zsleep(0.001); // (this can fail rarely) + } + + if (filelistx) // set up empty file list + for (int ii = 0; ii < Nfilesx; ii++) zfree(filelistx[ii]); + else + filelistx = (char **) zmalloc(MAXIMAGES * sizeof(char *),"image_thumbfile"); + Nfilesx = 0; + + while ((buff = command_output(contx,findcommand,directoryx))) // search image file directory + { + if (Nfilesx == MAXIMAGES) { // no room + zmessageACK(0,Btoomanyfiles,MAXIMAGES); + break; + } + + ftyp = image_file_type(buff); + if (ftyp == 2) { // supported image file type + filelistx[Nfilesx] = buff; // add to file list + Nfilesx++; + } + else zfree(buff); + } + + busythreads = 4; // start search threads for this directory + stopthreads = 0; + indexx = -1; + + for (int ii = 0; ii < 4; ii++) + start_detached_thread(image_thumbfile_thread,0); + + while (busythreads) { // return as soon as target thumbnail + if (! imagefilex) return thumbfilex; // has been generated + zsleep(0.001); + } + + if (! imagefilex) return thumbfilex; + printf("image_thumbfile failed %s \n",imagefile); // failure + return 0; +} + + +// private function +// four threads each processing 1/4 of the entries in filelistx + +void * image_thumbs::image_thumbfile_thread(void *arg) +{ + using namespace image_thumbs; + + int ii; + char *thumbfile; + + while (indexx < Nfilesx) + { + if (imagefilex) { // if thumbnail request is waiting + mutex_lock(&thumblock); // take care of it first + if (imagefilex) + thumbfilex = image_thumbfile_1x(imagefilex); + imagefilex = 0; + mutex_unlock(&thumblock); + } + + if (stopthreads) break; // stop before done + + ii = zadd_locked(indexx,+1); // get next file from list + if (ii >= Nfilesx) break; + + thumbfile = image_thumbfile_1x(filelistx[ii]); // make thumbnail file if needed + if (thumbfile) zfree(thumbfile); + } + + zadd_locked(busythreads,-1); // decrement busy count + pthread_exit(0); // "return" cannot be used here +} + + +// Private function to create a single thumbnail file. +// Get thumbnail file for the given image file. +// If missing or stale, add or update in /.thumbnails directory. +// Returned filespec is subject for zfree(). + +char * image_thumbs::image_thumbfile_1x(char *imagefile) +{ + using namespace image_thumbs; + + GdkPixbuf *thumbpxb; + GError *gerror = 0; + char *pfile, *bfile, *thumbfile; + int err, sizew, sizeh; + struct stat statf, statb; + + err = stat(imagefile,&statf); + if (err) return 0; + if (! S_ISREG(statf.st_mode)) return 0; // not a regular file + if (image_file_type(imagefile) != 2) return 0; // unsupported image type + + pfile = strrchr(imagefile,'/'); // get .../filename.xxx + if (! pfile) return 0; + if (pfile > imagefile+12 && strnEqu(pfile-12,"/.thumbnails/",13)) { // .../.thumbnails/filename.xxx ?? + thumbfile = strdupz(imagefile,0,"image_thumbfile"); // yes, a thumbnail file + return thumbfile; // return same file + } + + thumbfile = strdupz(imagefile,20,"image_thumbfile"); // construct thumbnail file + bfile = thumbfile + (pfile - imagefile); // .../.thumbnails/filename.xxx.png + strcpy(bfile,"/.thumbnails"); + bfile += 12; + strcpy(bfile,pfile); + strcat(bfile,".png"); + + while (! image_thumbfile_lock(imagefile,1)) zsleep(0.001); // lock file for me + + err = stat(thumbfile,&statb); // thumbnail file exists ?? + if (err || (statb.st_mtime < statf.st_mtime)) + { // does not exist or stale + *bfile = 0; + err = stat(thumbfile,&statb); + if (err) err = mkdir(thumbfile,0751); // create .thumbnails directory + if (err) { + image_thumbfile_lock(imagefile,0); + return 0; + } + *bfile = *pfile; + sizew = sizeh = image_navi::thumbfilesize; // create thumbnail pixbuf + thumbpxb = gdk_pixbuf_new_from_file_at_size(imagefile,sizew,sizeh,&gerror); + if (! thumbpxb) { + printf("gdk_pixbuf_new error: %s \n",gerror->message); // diagnose error + image_thumbfile_lock(imagefile,0); + return 0; + } + gdk_pixbuf_save(thumbpxb,thumbfile,"png",&gerror,null); // save in /.thumbnails/ directory + g_object_unref(thumbpxb); + image_navi::genthumbs++; // count generated thumbnails + } + + image_thumbfile_lock(imagefile,0); // return thumbfile + return thumbfile; +} + + +// prevent interference from multiple threads working on the same image file + +int image_thumbs::image_thumbfile_lock(char *imagefile, int lock) +{ + using namespace image_thumbs; + + int ii, jj = -1; + + mutex_lock(&filelock); + + if (lock) // lock file if possible + { + for (ii = 0; ii < 5; ii++) { + if (! lockfiles[ii]) jj = ii; // remember 1st empty slot + else if (strEqu(lockfiles[ii],imagefile)) { + mutex_unlock(&filelock); // file is already locked + return 0; + } + } + + if (jj < 0) zappcrash("image_thumbfile_lock > 5"); + lockfiles[jj] = imagefile; // lock the file + mutex_unlock(&filelock); + return 1; + } + + else // unlock file + { + for (ii = 0; ii < 5; ii++) { + if (! lockfiles[ii]) continue; + if (strEqu(lockfiles[ii],imagefile)) { + lockfiles[ii] = 0; + mutex_unlock(&filelock); + return 1; + } + } + zappcrash("image_thumbfile_lock gone"); + return 0; + } +} + + +// Public function +// Get thumbnail image for given image file, from .thumbnails directory. +// Add thumbnail file if missing, or update it if older than image file. +// Returned thumbnail belongs to caller: g_object_unref() is necessary. + +GdkPixbuf * image_thumbnail(char *fpath, int size) +{ + using namespace zfuncs; + using namespace image_navi; + + GdkPixbuf *thumbpxb; + GError *gerror = 0; + int ii, err; + char *bpath; + time_t mtime; + struct stat statf; + const int cachesize = thumbnail_cachesize; // shorthand + + static int nextcache, ftf = 1; + static int sizecache[cachesize]; + static time_t mtimecache[cachesize]; + static char *fpathcache[cachesize]; + static GdkPixbuf *pixbufcache[cachesize]; + + zthreadcrash(); // thread usage not allowed + + if (ftf) { // first call + for (ii = 0; ii < cachesize; ii++) + fpathcache[ii] = 0; // clear cache + ftf = 0; + } + + err = stat(fpath,&statf); // fpath status info + if (err) return 0; + + if (S_ISDIR(statf.st_mode)) { // if directory, return folder image + bpath = zmalloc(500); + strncatv(bpath,499,zicondir,"/folder256.png",null); + thumbpxb = gdk_pixbuf_new_from_file_at_size(bpath,size,size,&gerror); + zfree(bpath); + return thumbpxb; + } + + mtime = statf.st_mtime; // last modification time + + if (! size) size = thumbfilesize; // default thumb size + + for (ii = nextcache; ii >= 0; ii--) // get cached pixbuf if found + if (fpathcache[ii] && strEqu(fpath,fpathcache[ii]) && + sizecache[ii] == size && mtime == mtimecache[ii]) break; // check mtime (bugfix) + if (ii >= 0) { + thumbpxb = gdk_pixbuf_copy(pixbufcache[ii]); + return thumbpxb; + } + for (ii = cachesize-1; ii > nextcache; ii--) // continue search + if (fpathcache[ii] && strEqu(fpath,fpathcache[ii]) && + sizecache[ii] == size && mtime == mtimecache[ii]) break; + if (ii > nextcache) { + thumbpxb = gdk_pixbuf_copy(pixbufcache[ii]); + return thumbpxb; + } + + if (size > thumbfilesize) { // support huge thumbnails + thumbpxb = gdk_pixbuf_new_from_file_at_size(fpath,size,size,&gerror); + goto addcache; + } + + bpath = image_thumbfile(fpath); // get thumbnail file + if (! bpath) return 0; + thumbpxb = gdk_pixbuf_new_from_file_at_size(bpath,size,size,&gerror); // get thumbnail + zfree(bpath); + goto addcache; + +addcache: + nextcache++; // next cache slot (oldest) + if (nextcache == cachesize) nextcache = 0; + ii = nextcache; + if (fpathcache[ii]) { // free prior occupant + zfree(fpathcache[ii]); + g_object_unref(pixbufcache[ii]); + } + fpathcache[ii] = strdupz(fpath,0,"thumbnail_cache"); // add new occupant + pixbufcache[ii] = gdk_pixbuf_copy(thumbpxb); // this memory is not tracked + sizecache[ii] = size; + mtimecache[ii] = mtime; + + return thumbpxb; // return pixbuf to caller +} + + +/************************************************************************** + + private function - manage list of image files within a directory + + get an image file in the same directory as given file or directory + + char * image_navi::image_navigate(cchar *filez, cchar *action, int Nth) + + action: init: file list = directories and image files in directory filez + initF: file list = filez = list of image files to use (cchar **) + sort: sort the file list, directories first, ignore case + insert: insert filez into file list at position Nth (0 to last+1) + delete: delete Nth file in list + find: returns Nth file (0 base) or null if Nth > last + + Nth: file to return for action = find + + Returned values: + find: filespec, else null + The returned file belongs to caller and is subject for zfree(). + +***************************************************************************/ + +char * image_navi::image_navigate(cchar *filez, cchar *action, int Nth) +{ + using namespace image_navi; + + char *buff; + cchar *findcommand = "find \"%s\" -maxdepth 1"; + char *pp, *file2; + int err, ii, cc, ftyp, contx = 0, fposn; + FILE *fid; + struct stat statbuf; + + if (! strstr("init initF sort insert delete find",action)) + zappcrash("image_navigate %s",action); + + if (strnEqu(action,"init",4)) // init or initF + { + if (flist) { + for (ii = 0; ii < nfiles; ii++) zfree(flist[ii]); // free prior file list + zfree(flist); + } + + if (mdlist) { // clear prior metadata if any + for (ii = 0; ii < nfiles; ii++) + if (mdlist[ii]) zfree(mdlist[ii]); + zfree(mdlist); + mdlist = 0; + } + + cc = MAXIMAGES * sizeof(char *); + flist = (char **) zmalloc(cc,"image_navi"); // list of file pointers + + nfiles = nimages = 0; // no files + fposn = 0; + gallerytype = 0; // v.12.01 + } + + if (strEqu(action,"init")) // initialize from given directory + { + if (! filez) return 0; // should not happen + + if (galleryname) zfree(galleryname); + galleryname = strdupz(filez,0,"image_navi"); + gallerytype = 1; // gallery type = directory + + err = stat(galleryname,&statbuf); + if (err) { + pp = (char *) strrchr(galleryname,'/'); // bad file, check directory part + if (! pp) return 0; + pp[1] = 0; + err = stat(galleryname,&statbuf); + if (err) return 0; // give up, empty file list + } + + if (S_ISREG(statbuf.st_mode)) { // if a file, get directory part + pp = (char *) strrchr(galleryname,'/'); + if (! pp) return 0; + pp[1] = 0; + } + + while ((buff = command_output(contx,findcommand,galleryname))) // find all files + { + if (strEqu(buff,galleryname)) { // skip self directory + zfree(buff); + continue; + } + + if (nfiles == MAXIMAGES) { // message, not crash + zmessageACK(0,Btoomanyfiles,MAXIMAGES); + break; + } + + ftyp = image_file_type(buff); + + if (ftyp == 1) { // subdirectory + flist[nfiles] = buff; // add to file list + flist[nfiles][0] = '!'; // if directory, make it sort first + nfiles++; + } + + else if (ftyp == 2) { // supported image file type + flist[nfiles] = buff; // add to file list + nfiles++; + nimages++; + } + + else { + zfree(buff); // (.thumbnails not ftyp 1) + continue; + } + } + + if (nfiles > 1) + HeapSort(flist,nfiles,image_fcomp); // Heap Sort - pointers to strings + + return 0; + } + + if (strEqu(action,"initF")) // initialize from given list + { + if (galleryname) zfree(galleryname); + galleryname = strdupz(filez,0,"image_navi"); + gallerytype = 2; // gallery type = file list + + fid = fopen(galleryname,"r"); // open file + if (! fid) return 0; + + buff = zmalloc(maxfcc); + + while (true) // read list of files + { + if (nfiles == MAXIMAGES) { + zmessageACK(0,Btoomanyfiles,MAXIMAGES); + break; + } + pp = fgets_trim(buff,maxfcc-1,fid,1); + if (! pp) break; + err = stat(pp,&statbuf); // check file exists + if (err) continue; + flist[nfiles] = strdupz(buff,0,"image_navi"); // add files to memory list + nfiles++; + nimages++; + } + + fclose(fid); + zfree(buff); // sort removed + return 0; + } + + if (strEqu(action,"sort")) // sort the list from initF + { + if (gallerytype == 3) return 0; // v.12.01 + if (nfiles < 2) return 0; + HeapSort(flist,nfiles,image_fcomp); // Heap Sort - pointers to strings + return 0; + } + + if (strEqu(action,"insert")) // insert new file into list + { + if (gallerytype == 3) return 0; // metadata report v.12.01 + fposn = Nth; // file position from caller + if (fposn < 0) fposn = 0; // limit to allowed range + if (fposn > nfiles) fposn = nfiles; + + if (nfiles == MAXIMAGES-1) { // no room + zmessageACK(0,Btoomanyfiles,MAXIMAGES); + return 0; + } + + for (ii = nfiles; ii > fposn; ii--) // create hole is list + flist[ii] = flist[ii-1]; + + flist[fposn] = strdupz(filez,0,"image_navi"); // put new file in hole + nfiles++; + nimages++; // bugfix + } + + if (strEqu(action,"delete")) // delete file from list + { + if (gallerytype == 3) return 0; // metadata report v.12.01 + fposn = Nth; // file position from caller must be OK + if (fposn < 0 || fposn > nfiles-1) return 0; + nfiles--; + if (*flist[fposn] != '!') nimages--; // not a directory v.12.01 + zfree(flist[fposn]); // remove file from list + for (ii = fposn; ii < nfiles; ii++) { // close the hole + if (nfiles < 0) printf("meaningless reference %d",ii); // stop g++ optimization bug //// + flist[ii] = flist[ii+1]; + } + } + + if (strEqu(action,"find")) + { + fposn = Nth; // file position from caller must be OK + if (fposn < 0 || fposn > nfiles-1) return 0; + file2 = strdupz(flist[fposn],0,"image_navi"); // get Nth file + file2[0] = '/'; // restore initial '/' + err = stat(file2,&statbuf); + if (! err) return file2; + zfree(file2); + } + + return 0; +} + + +// private function for special file name compare +// directories sort first and upper/lower case is ignored + +int image_navi::image_fcomp(cchar *file1, cchar *file2) +{ + int nn; + nn = strcasecmp(file1,file2); // compare ignoring case + if (nn != 0) return nn; + nn = strcmp(file1,file2); // if equal, do normal compare + return nn; +} + + +/**************************************************************************/ + +// Select files from the image gallery window, return list of files selected. +// The dialog shows the list of files selected and can be edited. +// The returned file list belongs to caller and is subject for zfree(). +// The file list EOL is marked with null. +// The image_gallery() callback function is changed and must be restored by caller. + +int imgl_showthumb(); +void imgl_insert_file(cchar *imagefile); +void imgl_gallery_file(int Nth, int button); + +GtkWidget *imgl_drawarea = 0; +GtkWidget *imgl_files = 0; +cchar *imgl_font = "Monospace 8"; +zdialog *imgl_zd = 0; +int imgl_fontheight = 14; +int imgl_cursorpos = 0; + + +char ** image_gallery_getfiles(char *startdir, GtkWidget *parent) +{ + int imgl_dialog_event(zdialog *zd, cchar *event); + int imgl_mouseclick(GtkWidget *, GdkEventButton *event, void *); + + PangoLanguage *plang; + PangoFontDescription *pfontdesc; + PangoContext *pcontext; + PangoFont *pfont; + PangoFontMetrics *pmetrics; + GdkCursor *cursor; + GdkWindow *gdkwin; + GtkTextBuffer *textBuff; + GtkTextIter iter1, iter2; + + int fontascent, fontdescent; + int line, nlines, ii; + char *imagefile, **filelist; + + zthreadcrash(); // thread usage not allowed + + image_gallery(startdir,"paint1",0,imgl_gallery_file,parent); // activate image gallery window + + imgl_zd = zdialog_new(ZTX("Select Files"),wing,ZTX("done"),ZTX("cancel"),null); + zdialog_add_widget(imgl_zd,"hbox","hb1","dialog",0,"expand|space=5"); + zdialog_add_widget(imgl_zd,"frame","fr11","hb1",0,"expand"); + zdialog_add_widget(imgl_zd,"scrwin","scrwin","fr11",0,"expand"); + zdialog_add_widget(imgl_zd,"edit","files","scrwin"); + zdialog_add_widget(imgl_zd,"vbox","vb12","hb1"); + zdialog_add_widget(imgl_zd,"frame","fr12","vb12"); + zdialog_add_widget(imgl_zd,"hbox","hb2","dialog",0,"space=5"); + zdialog_add_widget(imgl_zd,"button","delete","hb2",ZTX("delete"),"space=8"); + zdialog_add_widget(imgl_zd,"button","insert","hb2",ZTX("insert"),"space=8"); + zdialog_add_widget(imgl_zd,"button","addall","hb2",ZTX("add all"),"space=30"); + + GtkWidget *textbox = zdialog_widget(imgl_zd,"files"); // disable text wrap + gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(textbox),GTK_WRAP_NONE); + + GtkWidget *frame = zdialog_widget(imgl_zd,"fr12"); // drawing area for thumbnail image + imgl_drawarea = gtk_drawing_area_new(); + gtk_widget_set_size_request(imgl_drawarea,256,258); // increased + gtk_container_add(GTK_CONTAINER(frame),imgl_drawarea); + + imgl_files = zdialog_widget(imgl_zd,"files"); // activate mouse-clicks for + gtk_widget_add_events(imgl_files,GDK_BUTTON_PRESS_MASK); // file list widget + G_SIGNAL(imgl_files,"button-press-event",imgl_mouseclick,0); + + pfontdesc = pango_font_description_from_string(imgl_font); // set default font for files window + gtk_widget_modify_font(imgl_files,pfontdesc); + + plang = pango_language_get_default(); // get font metrics (what a mess) + pcontext = gtk_widget_get_pango_context(imgl_files); + pfont = pango_context_load_font(pcontext,pfontdesc); + pmetrics = pango_font_get_metrics(pfont,plang); + fontascent = pango_font_metrics_get_ascent(pmetrics) / PANGO_SCALE; + fontdescent = pango_font_metrics_get_descent(pmetrics) / PANGO_SCALE; + imgl_fontheight = fontascent + fontdescent; // effective line height + + zdialog_resize(imgl_zd,600,0); // start dialog + zdialog_run(imgl_zd,imgl_dialog_event); + + cursor = gdk_cursor_new(GDK_TOP_LEFT_ARROW); // arrow cursor for file list widget + gdkwin = gtk_text_view_get_window(GTK_TEXT_VIEW(imgl_files),TEXTWIN); // (must be done after window realized) + gdk_window_set_cursor(gdkwin,cursor); + imgl_cursorpos = 0; + + zdialog_wait(imgl_zd); // wait for completion + + if (imgl_zd->zstat != 1) { // cancelled + zdialog_free(imgl_zd); // kill dialog + image_gallery(0,"close"); // close image gallery window + return 0; + } + + textBuff = gtk_text_view_get_buffer(GTK_TEXT_VIEW(imgl_files)); + nlines = gtk_text_buffer_get_line_count(textBuff); + + filelist = (char **) zmalloc((nlines+1) * sizeof(char *),"imgl.getfiles"); + + for (ii = line = 0; line < nlines; line++) // get list of files from dialog + { + gtk_text_buffer_get_iter_at_line(textBuff,&iter1,line); // iter at line start + iter2 = iter1; + gtk_text_iter_forward_to_line_end(&iter2); + imagefile = gtk_text_buffer_get_text(textBuff,&iter1,&iter2,0); // get line of text + if (imagefile && *imagefile == '/') { + filelist[ii] = strdupz(imagefile,0,"imgl.getfiles"); // >> next file in list + free(imagefile); + ii++; + } + } + filelist[ii] = 0; // mark EOL + + zdialog_free(imgl_zd); // kill dialog + image_gallery(0,"close"); // close image gallery window + + if (! ii) { + zfree(filelist); // file list is empty + return 0; + } + + return filelist; // return file list +} + + +// imgl dialog event function + +int imgl_dialog_event(zdialog *zd, cchar *event) +{ + GtkTextBuffer *textBuff; + GtkTextIter iter1, iter2; + char *ftemp; + static char *imagefile = 0; + int line, posn; + + if (strEqu(event,"delete")) // delete file at cursor position + { + if (imagefile) zfree(imagefile); + imagefile = 0; + + textBuff = gtk_text_view_get_buffer(GTK_TEXT_VIEW(imgl_files)); + line = imgl_cursorpos; + gtk_text_buffer_get_iter_at_line(textBuff,&iter1,line); // iter at line start + iter2 = iter1; + gtk_text_iter_forward_to_line_end(&iter2); // iter at line end + + ftemp = gtk_text_buffer_get_text(textBuff,&iter1,&iter2,0); // get selected file + if (! ftemp || *ftemp != '/') { + if (ftemp) free(ftemp); + return 0; + } + + imagefile = strdupz(ftemp,0,"imgl.getfiles"); // save deleted file for poss. insert + free(ftemp); + + gtk_text_buffer_delete(textBuff,&iter1,&iter2); // delete file text + gtk_text_buffer_get_iter_at_line(textBuff,&iter2,line+1); + gtk_text_buffer_delete(textBuff,&iter1,&iter2); // delete empty line (\n) + + imgl_showthumb(); // thumbnail = next file + } + + if (strEqu(event,"insert")) // insert last deleted file + { // at current cursor position + if (! imagefile) return 0; + imgl_insert_file(imagefile); + zfree(imagefile); + imagefile = 0; + } + + if (strEqu(event,"addall")) // insert all files in image gallery + { + textBuff = gtk_text_view_get_buffer(GTK_TEXT_VIEW(imgl_files)); + posn = 0; + + while (true) + { + imagefile = image_gallery(0,"find",posn); // get first or next file + if (! imagefile) break; + posn++; + gtk_text_buffer_get_iter_at_line(textBuff,&iter1,imgl_cursorpos); + gtk_text_buffer_insert(textBuff,&iter1,"\n",1); // insert new blank line + gtk_text_buffer_get_iter_at_line(textBuff,&iter1,imgl_cursorpos); + gtk_text_buffer_insert(textBuff,&iter1,imagefile,-1); // insert image file + zfree(imagefile); + imgl_cursorpos++; // advance cursor position + } + } + + return 0; +} + + +// add image file to list at current cursor position, set thumbnail = file + +void imgl_insert_file(cchar *imagefile) +{ + GtkTextIter iter; + GtkTextBuffer *textBuff; + + textBuff = gtk_text_view_get_buffer(GTK_TEXT_VIEW(imgl_files)); + gtk_text_buffer_get_iter_at_line(textBuff,&iter,imgl_cursorpos); + gtk_text_buffer_insert(textBuff,&iter,"\n",1); // insert new blank line + gtk_text_buffer_get_iter_at_line(textBuff,&iter,imgl_cursorpos); + gtk_text_buffer_insert(textBuff,&iter,imagefile,-1); // insert image file + + imgl_showthumb(); // update thumbnail + imgl_cursorpos++; // advance cursor position + + return; +} + + +// called from image gallery window when a thumbnail is clicked +// add image file to list at current cursor position, set thumbnail = file + +void imgl_gallery_file(int Nth, int button) +{ + int ftyp; + char *imagefile; + + if (Nth == -2) { + showz_userguide(zfuncs::F1_help_topic); // F1 context help + return; + } + + imagefile = image_gallery(0,"find",Nth); // get file at clicked position + if (! imagefile) return; + + ftyp = image_file_type(imagefile); // ignore directories + if (ftyp == 2) imgl_insert_file(imagefile); // insert file at current position + zfree(imagefile); + + return; +} + + +// process mouse click in files window: +// set new cursor position and set thumbnail = clicked file + +int imgl_mouseclick(GtkWidget *, GdkEventButton *event, void *) +{ + int mpy; + GtkWidget *scrollwin; + GtkAdjustment *scrolladj; + double scrollpos; + + if (event->type != GDK_BUTTON_PRESS) return 0; + mpy = int(event->y); + scrollwin = zdialog_widget(imgl_zd,"scrwin"); // window scroll position + scrolladj = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(scrollwin)); + scrollpos = gtk_adjustment_get_value(scrolladj); + imgl_cursorpos = (mpy + scrollpos) / imgl_fontheight; // line selected + imgl_showthumb(); // show thumbnail image + return 0; +} + + +// show thumbnail for file at current cursor position + +int imgl_showthumb() +{ + int line; + char *imagefile; + GtkTextBuffer *textBuff; + GtkTextIter iter1, iter2; + GdkPixbuf *thumbnail = 0; + + gdk_window_clear(imgl_drawarea->window); + + line = imgl_cursorpos; + textBuff = gtk_text_view_get_buffer(GTK_TEXT_VIEW(imgl_files)); + gtk_text_buffer_get_iter_at_line(textBuff,&iter1,line); // iter at line start + iter2 = iter1; + gtk_text_iter_forward_to_line_end(&iter2); // iter at line end + + imagefile = gtk_text_buffer_get_text(textBuff,&iter1,&iter2,0); // get selected file + if (*imagefile != '/') { + free(imagefile); + return 0; + } + + thumbnail = image_thumbnail(imagefile,256); // get thumbnail + free(imagefile); + + if (thumbnail) { + gdk_draw_pixbuf(imgl_drawarea->window,0,thumbnail,0,0,0,0,-1,-1,NODITHER,0,0); + g_object_unref(thumbnail); + } + return 0; +} + + diff -Nru fotoxx-11.11.1/fotoxx-11.11.1.cc fotoxx-12.01.2/fotoxx-11.11.1.cc --- fotoxx-11.11.1/fotoxx-11.11.1.cc 2011-11-05 05:30:36.000000000 +0000 +++ fotoxx-12.01.2/fotoxx-11.11.1.cc 1970-01-01 00:00:00.000000000 +0000 @@ -1,6780 +0,0 @@ -/************************************************************************** - - Fotoxx edit photos and manage collections - - Copyright 2007 2008 2009 2010 2011 Michael Cornelison - Source URL: http://kornelix.squarespace.com/fotoxx - Contact: kornelix2@googlemail.com - - 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 http://www.gnu.org/licenses/. - -***************************************************************************/ - -#define EX // disable extern declarations -#include "fotoxx.h" - -#define fversion "Fotoxx v.11.11.1" // this fotoxx version -#define flicense "Free software - GNU General Public License v.3" -#define fhomepage "http://kornelix.squarespace.com/fotoxx" -#define ftranslators \ - "Translators: Jie Luo, Eugenio Baldi, Justa, Peter Landgren, \n" \ - "Alexander Krasnopolsky, Arthur Kalverboer, André Campos Rodovalho, \n" \ - "Stanislas Zeller, Doriano Blengino" -#define fcredits "Software used: GTK, libtiff, ufraw-batch, exiftool" -#define fcontact "Bug reports: kornelix2@googlemail.com" - - -char *initial_file = 0; // initial file on command line - - -// fotoxx main program - -int main(int argc, char *argv[]) -{ - using namespace zfuncs; - - char lang[8] = "", *pp; - int err; - struct stat statb; - int Fclone=0, cloxx=0, cloyy=0, cloww=0, clohh=0; - GdkScreen *screen; - int Fsyncfiles = 0; - - printf(fversion "\n"); // print fotoxx version - if (argc > 1 && strEqu(argv[1],"-v")) return 0; // no more is wanted - - // initialize externals - - maxcolor = 0xffff; - for (int ii = 0; ii < 8; ii++) wtnx[ii] = ii; - strcpy(jpeg_quality,def_jpeg_quality); - mwgeom[0] = mwgeom[1] = 100; // default main window geometry v.11.07 - mwgeom[2] = 700; mwgeom[3] = 500; - Mscale = 1.0; - trimsize[0] = 1600; - trimsize[1] = 1000; - editresize[0] = 1600; - editresize[1] = 1200; - batchresize[0] = 1600; - batchresize[1] = 1200; - emailsize[0] = 1000; - emailsize[1] = 800; - gridcount[0] = gridcount[1] = 5; // set default grid line counts - sa_pixRGB = &green; - ss_funcs[0] = 1; - tbar_style = "both"; // default toolbar style - Ffirsttime = 1; // first time startup v.11.11 - fsync_lock = "fotoxx_syncfiles"; - - // command line args - - gtk_init(&argc,&argv); // initz. GTK & strip GTK command line params - - for (int ii = 1; ii < argc; ii++) // command line parameters - { - pp = argv[ii]; - if (strcmpv(pp,"-debug","-d",null)) // -debug - Fdebug = 1; - else if (strcmpv(pp,"-lang","-l",null) && argc > ii+1) // -lang lc_RC (language/region code) - strncpy0(lang,argv[++ii],7); - else if (strcmpv(pp,"-clone1","-c1",null)) // -clone1 (clone1/2 not user options) - Fclone = 1; - else if (strcmpv(pp,"-clone2","-c2",null)) { // -clone2 xpos ypos v.11.07 - Fclone = 2; - cloxx = atoi(argv[ii+1]); // window position and size - cloyy = atoi(argv[ii+2]); // passed from parent instance - cloww = atoi(argv[ii+3]); - clohh = atoi(argv[ii+4]); - ii += 4; - } - else if (strcmpv(pp,"-slideshow","-ss",null) && argc > ii+1) // -slideshow /image/file.jpg v.11.04 - SS_imagefile = strdupz(argv[++ii]); - else if (strcmpv(pp,"-music","-m",null) && argc > ii+1) // -music /music/file.ogg v.11.04 - SS_musicfile = strdupz(argv[++ii]); - else if (strcmpv(pp,"-recent","-r",null)) // recent files gallery v.11.07 - Frecent = 1; - else if (strcmpv(pp,"-previous","-prev","-p",null)) // open previous file v.11.07 - Fprev = 1; - else if (strcmpv(pp,"-syncfiles",null)) { // spawned sync files process v.11.11 - Fsyncfiles = 1; - pp = argv[++ii]; - if (strEqu(pp,"auto")) Fautosync = 1; // set auto or manual sync - if (strEqu(pp,"manual")) Fmansync = 1; - } - else initial_file = strdupz(pp); // must be initial file or directory - } - - zinitapp("fotoxx",null); // get app directories - - ZTXinit(lang); // setup locale and translations - - *topdirk_file = 0; - strncatv(topdirk_file,199,get_zuserdir(),"/top_directory",null); // /home/user/.fotoxx/top_directory - - *search_index_file = 0; - strncatv(search_index_file,199,get_zuserdir(),"/search_index",null); // /home/user/.fotoxx/search_index - - *tags_defined_file = 0; - strncatv(tags_defined_file,199,get_zuserdir(),"/tags_defined",null); // /home/user/.fotoxx/tags_defined - - *recentfiles_file = 0; - strncatv(recentfiles_file,199,get_zuserdir(),"/recent_files",null); // /home/user/.fotoxx/recent_files - - *saved_areas_dirk = 0; - strncatv(saved_areas_dirk,199,get_zuserdir(),"/saved_areas/",null); // /home/user/.fotoxx/saved_areas/ - err = stat(saved_areas_dirk,&statb); - if (err) mkdir(saved_areas_dirk,0750); - - *collections_dirk = 0; - strncatv(collections_dirk,199,get_zuserdir(),"/collections/",null); // /home/user/.fotoxx/collections/ - err = stat(collections_dirk,&statb); - if (err) mkdir(collections_dirk,0750); - - *saved_curves_dirk = 0; - strncatv(saved_curves_dirk,199,get_zuserdir(),"/saved_curves/",null); // /home/user/.fotoxx/saved_curves/ - err = stat(saved_curves_dirk,&statb); - if (err) mkdir(saved_curves_dirk,0750); - - *annotations_dirk = 0; - strncatv(annotations_dirk,199,get_zuserdir(),"/annotations/",null); // /home/user/.fotoxx/annotations/ - err = stat(annotations_dirk,&statb); - if (err) mkdir(annotations_dirk,0750); - - load_params(); // restore parameters from last session - - if (Fsyncfiles) { // this is spawned sync process v.11.11 - gtk_init_add((GtkFunction) syncfiles_func,0); // do the sync function only - gtk_main(); - return 0; - } - - if (! Fsyncfiles && ! Fclone) { // this is the user GUI process - printf("spawn sync files subprocess \n"); - err = system("fotoxx -syncfiles auto &"); // spawn process for sync files - if (err) { - printf("error: %s \n",wstrerror(err)); // quit if failed - return 1; - } - } - - mWin = gtk_window_new(GTK_WINDOW_TOPLEVEL); // create main window - gtk_window_set_title(MWIN,fversion); - - mVbox = gtk_vbox_new(0,0); // add vert. packing box - gtk_container_add(GTK_CONTAINER(mWin),mVbox); - - mMbar = create_menubar(mVbox); // add menus / sub-menus - - GtkWidget *mFile = add_menubar_item(mMbar,ZTX("File"),topmenufunc); - add_submenu_item(mFile, ZTX("Image Gallery"), m_gallery); - add_submenu_item(mFile, ZTX("Clone 50/50"), m_clone1); - add_submenu_item(mFile, ZTX("Clone Overlay"), m_clone2); - add_submenu_item(mFile, ZTX("Open Image File"), m_open); - add_submenu_item(mFile, ZTX("Open in New Window"), m_open_newin); - add_submenu_item(mFile, ZTX("Open Previous File"), m_previous); - add_submenu_item(mFile, ZTX("Open Recent File"), m_recent); - add_submenu_item(mFile, ZTX("Save to Same File"), m_save); - add_submenu_item(mFile, ZTX("Save to New Version"), m_savevers); - add_submenu_item(mFile, ZTX("Save to New File"), m_saveas); - add_submenu_item(mFile, ZTX("Create Blank Image"), m_create); - add_submenu_item(mFile, ZTX("Trash Image File"), m_trash); - add_submenu_item(mFile, ZTX("Rename Image File"), m_rename); - add_submenu_item(mFile, ZTX("Batch Rename Files"), m_batchrename); - add_submenu_item(mFile, ZTX("Print Image File"), m_print); - add_submenu_item(mFile, ZTX("Quit fotoxx"), m_quit); - - GtkWidget *mTools = add_menubar_item(mMbar,ZTX("Tools"),topmenufunc); - add_submenu_item(mTools, ZTX("Manage Collections"), m_manage_collections); - add_submenu_item(mTools, ZTX("Move Collections"), m_move_collections); - add_submenu_item(mTools, ZTX("Check Monitor"), m_moncheck); - add_submenu_item(mTools, ZTX("Monitor Gamma"), m_mongamma); - add_submenu_item(mTools, ZTX("Brightness Graph"), m_histogram); - add_submenu_item(mTools, ZTX("Slide Show"), m_slideshow); - add_submenu_item(mTools, ZTX("Show RGB"), m_show_RGB); - add_submenu_item(mTools, ZTX("Grid Lines"), m_gridlines); - add_submenu_item(mTools, ZTX("Lens Parameters"), m_lensparms); - add_submenu_item(mTools, ZTX("Change Language"), m_lang); - add_submenu_item(mTools, "Edit Translations", m_translate); - add_submenu_item(mTools, ZTX("Add Menu and Launcher"), m_menu_launcher); - add_submenu_item(mTools, ZTX("Convert RAW files"), m_conv_raw); - add_submenu_item(mTools, ZTX("Burn Images to CD/DVD"), m_burn); - add_submenu_item(mTools, ZTX("E-mail Images"), m_email); - add_submenu_item(mTools, ZTX("Synchronize Files"), m_syncfiles); - add_submenu_item(mTools, ZTX("Toolbar Style"), m_tbar_style); - add_submenu_item(mTools, ZTX("Memory Usage"), m_memory_usage); - - GtkWidget *mInfo = add_menubar_item(mMbar,"Info",topmenufunc); - add_submenu_item(mInfo, ZTX("Edit Caption/Comments"), m_edit_cctext); - add_submenu_item(mInfo, ZTX("Edit Tags"), m_edit_tags); - add_submenu_item(mInfo, ZTX("Manage Tags"), m_manage_tags); - add_submenu_item(mInfo, ZTX("Batch Add Tags"), m_batchAddTags); - add_submenu_item(mInfo, ZTX("Batch Delete Tag"), m_batchDelTag); - add_submenu_item(mInfo, ZTX("View Info (short)"), m_info_view_short); - add_submenu_item(mInfo, ZTX("View Info (long)"), m_info_view_long); - add_submenu_item(mInfo, ZTX("Edit Info"), m_info_edit); - add_submenu_item(mInfo, ZTX("Delete Info"), m_info_delete); - add_submenu_item(mInfo, ZTX("Search Images"), m_search_images); - - GtkWidget *mSelect = add_menubar_item(mMbar,ZTX("Select"),topmenufunc); - add_submenu_item(mSelect, ZTX("Select"), m_select); - add_submenu_item(mSelect, ZTX("Show"), m_select_show); - add_submenu_item(mSelect, ZTX("Hide"), m_select_hide); - add_submenu_item(mSelect, ZTX("Enable"), m_select_enable); - add_submenu_item(mSelect, ZTX("Disable"), m_select_disable); - add_submenu_item(mSelect, ZTX("Invert"), m_select_invert); - add_submenu_item(mSelect, ZTX("Unselect"), m_select_unselect); - add_submenu_item(mSelect, ZTX("Copy"), m_select_copy); - add_submenu_item(mSelect, ZTX("Paste"), m_select_paste); - add_submenu_item(mSelect, ZTX("Open"), m_select_open); - add_submenu_item(mSelect, ZTX("Save"), m_select_save); - add_submenu_item(mSelect, ZTX("Select Whole Image"), m_select_whole_image); - add_submenu_item(mSelect, ZTX("Select and Edit"), m_select_edit); - - GtkWidget *mTransf = add_menubar_item(mMbar,ZTX("Transform"),topmenufunc); - add_submenu_item(mTransf, ZTX("Rotate Image"), m_rotate); - add_submenu_item(mTransf, ZTX("Trim Image"), m_trim); - add_submenu_item(mTransf, ZTX("Resize Image"), m_resize); - add_submenu_item(mTransf, ZTX("Batch Resize/Export"), m_batchresize); - add_submenu_item(mTransf, ZTX("Annotate Image"), m_annotate); - add_submenu_item(mTransf, ZTX("Flip Image"), m_flip); - add_submenu_item(mTransf, ZTX("Make Negative"), m_negate); - add_submenu_item(mTransf, ZTX("Unbend Image"), m_unbend); - add_submenu_item(mTransf, ZTX("Keystone Correction"), m_keystone); - add_submenu_item(mTransf, ZTX("Warp Image (area)"), m_warp_area); - add_submenu_item(mTransf, ZTX("Warp Image (curved)"), m_warp_curved); - add_submenu_item(mTransf, ZTX("Warp Image (linear)"), m_warp_linear); - add_submenu_item(mTransf, ZTX("Warp Image (affine)"), m_warp_affine); - - GtkWidget *mRetouch = add_menubar_item(mMbar,ZTX("Retouch"),topmenufunc); - add_submenu_item(mRetouch, ZTX("Brightness/Color"), m_tune); - add_submenu_item(mRetouch, ZTX("Gamma Curves"), m_gamma); - add_submenu_item(mRetouch, ZTX("Expand Brightness"), m_xbrange); - add_submenu_item(mRetouch, ZTX("Flatten Brightness"), m_flatten); - add_submenu_item(mRetouch, ZTX("Brightness Ramp"), m_brightramp); - add_submenu_item(mRetouch, ZTX("Tone Mapping"), m_tonemap); - add_submenu_item(mRetouch, ZTX("White Balance"), m_whitebal); - add_submenu_item(mRetouch, ZTX("Match Colors"), m_match_color); - add_submenu_item(mRetouch, "DRGB", m_DRGB); - add_submenu_item(mRetouch, ZTX("Revise RGB"), m_revise_RGB); - add_submenu_item(mRetouch, ZTX("Red Eyes"), m_redeye); - add_submenu_item(mRetouch, ZTX("Blur Image"), m_blur); - add_submenu_item(mRetouch, ZTX("Sharpen Image"), m_sharpen); - add_submenu_item(mRetouch, ZTX("Reduce Noise"), m_denoise); - add_submenu_item(mRetouch, ZTX("Smart Erase"), m_smart_erase); - add_submenu_item(mRetouch, ZTX("Remove Dust"), m_dust); - add_submenu_item(mRetouch, ZTX("Edit Pixels"), m_pixedit); - - GtkWidget *mArt = add_menubar_item(mMbar,ZTX("Art"),topmenufunc); - add_submenu_item(mArt, ZTX("Color Depth"), m_colordep); - add_submenu_item(mArt, ZTX("Drawing"), m_draw); - add_submenu_item(mArt, ZTX("Outlines"), m_outlines); - add_submenu_item(mArt, ZTX("Embossing"), m_emboss); - add_submenu_item(mArt, ZTX("Tiles"), m_tiles); - add_submenu_item(mArt, ZTX("Dots"), m_dots); - add_submenu_item(mArt, ZTX("Painting"), m_painting); - - GtkWidget *mComb = add_menubar_item(mMbar,ZTX("Combine"),topmenufunc); - add_submenu_item(mComb, ZTX("High Dynamic Range"), m_HDR); - add_submenu_item(mComb, ZTX("High Depth of Field"), m_HDF); - add_submenu_item(mComb, ZTX("Stack / Paint"), m_STP); - add_submenu_item(mComb, ZTX("Stack / Noise"), m_STN); - add_submenu_item(mComb, ZTX("Panorama"), m_pano); - add_submenu_item(mComb, ZTX("Vertical Panorama"), m_vpano); - - GtkWidget *mPlugins = add_menubar_item(mMbar,"Plugins",topmenufunc); // build plugin menu v.11.03 - add_submenu_item(mPlugins,ZTX("Edit Plugins"),m_edit_plugins); - for (int ii = 0; ii < Nplugins; ii++) { - pp = strstr(plugins[ii]," = "); - if (! pp) continue; - *pp = 0; - add_submenu_item(mPlugins,plugins[ii],m_run_plugin); - *pp = ' '; - } - - GtkWidget *mHelp = add_menubar_item(mMbar,ZTX("Help"),topmenufunc); - add_submenu_item(mHelp, ZTX("About"), m_help); - add_submenu_item(mHelp, ZTX("User Guide"), m_help); - add_submenu_item(mHelp, ZTX("User Guide Changes"), m_help); - add_submenu_item(mHelp, ZTX("Edit Functions Summary"), m_help); - add_submenu_item(mHelp, ZTX("Change Log"), m_help); - add_submenu_item(mHelp, ZTX("Translations"), m_help); - add_submenu_item(mHelp, ZTX("Home Page"), m_help); - add_submenu_item(mHelp, "README", m_help); - - mTbar = create_toolbar(mVbox); // toolbar buttons - add_toolbar_button(mTbar, ZTX("Gallery"), ZTX("Image Gallery"), "gallery.png", m_gallery); - add_toolbar_button(mTbar, ZTX("Open"), ZTX("Open Image File"), "open.png", m_open); - add_toolbar_button(mTbar, ZTX("Prev"), ZTX("Open Previous File"), "prev.png", m_prev); - add_toolbar_button(mTbar, ZTX("Next"), ZTX("Open Next File"), "next.png", m_next); - add_toolbar_button(mTbar, "Zoom+", ZTX("Zoom-in (bigger)"), "zoom+.png", m_zoom); - add_toolbar_button(mTbar, "Zoom-", ZTX("Zoom-out (smaller)"), "zoom-.png", m_zoom); - add_toolbar_button(mTbar, ZTX("Undo"), ZTX("Undo One Edit"), "undo.png", m_undo); - add_toolbar_button(mTbar, ZTX("Redo"), ZTX("Redo One Edit"), "redo.png", m_redo); - add_toolbar_button(mTbar, "separator", null, null, null); - add_toolbar_button(mTbar, "separator", null, null, null); - add_toolbar_button(mTbar, ZTX("Save"), ZTX("Save to Same File"), "save.png", m_save); - add_toolbar_button(mTbar, ZTX("Save+V"), ZTX("Save to New Version"), "save+V.png", m_savevers); - add_toolbar_button(mTbar, ZTX("Save+F"), ZTX("Save to New File"), "save+F.png", m_saveas); - add_toolbar_button(mTbar, ZTX("Trash"), ZTX("Move Image to Trash"), "trash.png", m_trash); - add_toolbar_button(mTbar, "separator", null, null, null); - add_toolbar_button(mTbar, "separator", null, null, null); - add_toolbar_button(mTbar, ZTX("Quit"), ZTX("Quit fotoxx"), "quit.png", m_quit); - add_toolbar_button(mTbar, ZTX("Help"), ZTX("Fotoxx Essentials"), "help.png", m_help); - - tbar_style_set(null); // recall last toolbar style v.11.06 - - drWin = gtk_drawing_area_new(); // add drawing window - gtk_box_pack_start(GTK_BOX(mVbox),drWin,1,1,0); - - STbar = create_stbar(mVbox); // add status bar - - G_SIGNAL(mWin,"delete_event",delete_event,0) // connect signals - G_SIGNAL(mWin,"destroy",destroy_event,0) - G_SIGNAL(drWin,"expose-event",mwpaint1,0) - - gtk_widget_add_events(drWin,GDK_BUTTON_PRESS_MASK); // connect mouse events - gtk_widget_add_events(drWin,GDK_BUTTON_RELEASE_MASK); - gtk_widget_add_events(drWin,GDK_BUTTON_MOTION_MASK); // motion with button pressed - gtk_widget_add_events(drWin,GDK_POINTER_MOTION_MASK); // pointer motion - G_SIGNAL(drWin,"button-press-event",mouse_event,0) - G_SIGNAL(drWin,"button-release-event",mouse_event,0) - G_SIGNAL(drWin,"motion-notify-event",mouse_event,0) - - G_SIGNAL(mWin,"key-press-event",KBpress,0) // connect KB events - G_SIGNAL(mWin,"key-release-event",KBrelease,0) - - drag_drop_connect(drWin,m_open_drag); // connect drag-drop event - - gtk_window_move(MWIN,mwgeom[0],mwgeom[1]); // main window geometry - gtk_window_set_default_size(MWIN,mwgeom[2],mwgeom[3]); // (defaults or last session params) - gtk_widget_show_all(mWin); // show all widgets - - if (Fclone == 1) { // clone1: left half of desktop v.10.12 - screen = gdk_screen_get_default(); - cloww = gdk_screen_get_width(screen); - clohh = gdk_screen_get_height(screen); - cloww = cloww / 2 - 20; - clohh = clohh - 50; - gtk_window_move(MWIN,10,10); // v.11.07 - gtk_window_resize(MWIN,cloww,clohh); - } - - if (Fclone == 2) { // clone2: open new window v.11.07 - gtk_window_move(MWIN,cloxx+20,cloyy+30); // slightly offset from old window - gtk_window_resize(MWIN,cloww,clohh); - } - - gdkgc = gdk_gc_new(drWin->window); // initz. graphics context - - black.red = black.green = black.blue = 0; // set up colors - white.red = white.green = white.blue = maxcolor; - lgray.red = lgray.green = lgray.blue = 0.9 * maxcolor; - dgray.red = dgray.green = dgray.blue = 0.5 * maxcolor; - red.red = maxcolor; red.green = red.blue = 0; - green.green = maxcolor; green.red = green.blue = 0; - - colormap = gtk_widget_get_colormap(drWin); - gdk_rgb_find_color(colormap,&black); - gdk_rgb_find_color(colormap,&white); - gdk_rgb_find_color(colormap,&lgray); - gdk_rgb_find_color(colormap,&dgray); - gdk_rgb_find_color(colormap,&red); - gdk_rgb_find_color(colormap,&green); - - gdk_gc_set_foreground(gdkgc,&black); - gdk_gc_set_background(gdkgc,&lgray); - gdk_window_set_background(drWin->window,&lgray); // v.11.01 - fg_color = black; - - gdk_gc_set_line_attributes(gdkgc,1,LINEATTRIBUTES); - - arrowcursor = gdk_cursor_new(GDK_TOP_LEFT_ARROW); // cursor for selection - dragcursor = gdk_cursor_new(GDK_CROSSHAIR); // cursor for dragging - drawcursor = gdk_cursor_new(GDK_PENCIL); // cursor for drawing lines - - gtk_init_add((GtkFunction) gtkinitfunc,0); // set initz. call from gtk_main() - gtk_main(); // start processing window events - return 0; -} - - -/**************************************************************************/ - -// initial function called from gtk_main() at startup - -int gtkinitfunc(void *data) -{ - int err, flag, npid; - int ftype, fdirk = 0; - char procfile[20], *ppv; - cchar *pp, *pp2; - struct stat statb; - - menulock(1); // block menus until initz. done v.11.04 - - printf("install location: %s \n",get_zinstalloc()); // install location v.11.05 - - if (Ffirsttime) { // first time startup v.11.11 - printf("%s \n",ZTX("first time startup")); - zmessageACK(mWin,"User Guide is available in Help menu"); // inform user of user guide - Ffirsttime = 0; - save_params(); - } - - Nwt = sysconf(_SC_NPROCESSORS_ONLN); // get SMP CPU count - if (Nwt <= 0) Nwt = 1; - if (Nwt > max_threads) Nwt = max_threads; // compile time limit - printf("using %d threads \n",Nwt); - - err = system("which exiftool"); // check for exiftool v.11.05 - if (! err) Fexiftool = 1; - err = system("which xdg-open"); // check for xdg-open - if (! err) Fxdgopen = 1; - err = system("which ufraw-batch"); // check for ufraw-batch - if (! err) Fufraw = 1; - - undo_files = zmalloc(200); - *undo_files = 0; // look for orphaned undo files - strncatv(undo_files,199,get_zuserdir(),"/*_undo_*",null); // /home/user/.fotoxx/*_undo_* - flag = 1; - while ((pp = SearchWild(undo_files,flag))) - { - pp2 = strstr(pp,".fotoxx/"); - if (! pp2) continue; - npid = atoi(pp2+8); // pid of file owner - snprintf(procfile,19,"/proc/%d",npid); - err = stat(procfile,&statb); - if (! err) continue; // pid is active, keep file - printf("orphaned undo file deleted: %s \n",pp); - err = remove(pp); // delete file v.11.03 - } - - *undo_files = 0; // setup undo filespec template - strncatv(undo_files,199,get_zuserdir(),"/",PIDstring,"_undo_nn",null); // /home/user/.fotoxx/pppppp_undo_nn - - editlog = pvlist_create(maxedits); // history log of image edits done - for (int ii = 0; ii < maxedits; ii++) // pre-load all pvlist entries v.10.2 - pvlist_append(editlog,"nothing"); - - mutex_init(&Fpixmap_lock,0); // setup lock for edit pixmaps - TIFFSetWarningHandler(tiffwarninghandler); // intercept TIFF warning messages - zdialog_positions("load"); // load saved dialog positions v.11.07 - -// set up current file and directory from saved parameters or command line - - if (topdirk) curr_dirk = strdupz(topdirk); // use top directory if defined v.11.07 - else { - ppv = getcwd(command,ccc); // or use current directory v.11.09 - if (ppv) curr_dirk = strdupz(ppv); - } - - if (initial_file) { // from command line or previous session - ppv = realpath(initial_file,0); // prepend directory if needed - if (ppv) { - zfree(initial_file); - initial_file = strdupz(ppv); - free(ppv); - } - else { - printf("invalid file: %s \n",initial_file); // invalid file path - zfree(initial_file); - initial_file = 0; - } - } - - if (initial_file) { - ftype = image_file_type(initial_file); - if (ftype == 0) { // non-existent file - printf("invalid file: %s \n",initial_file); - zfree(initial_file); - initial_file = 0; - } - else if (ftype == 1) { // is a directory - if (curr_dirk) zfree(curr_dirk); - curr_dirk = initial_file; - initial_file = 0; - fdirk = 1; - } - else if (ftype == 2) { // supported image file type - if (curr_dirk) zfree(curr_dirk); - curr_dirk = strdupz(initial_file); // set current directory from file - ppv = strrchr(curr_dirk,'/'); - if (ppv) *ppv = 0; - } - else { - printf("unsupported file type: %s \n",initial_file); // unsupported file type - zfree(initial_file); - initial_file = 0; - } - } - - if (curr_dirk) err = chdir(curr_dirk); // set current directory - - menulock(0); // enable menus v.11.04 - - g_timeout_add(200,gtimefunc,0); // start periodic function (200 ms) v.11.06 - - if (SS_imagefile) { // start slide show if wanted v.11.04 - f_open(SS_imagefile,1); - if (SS_musicfile) { - sprintf(command,"xdg-open \"%s\" ",SS_musicfile); // start music if wanted - printf("command: %s \n",command); - err = system(command); - } - m_slideshow(0,0); - return 0; - } - - if (initial_file) // open initial file - f_open(initial_file,1); - - else if (fdirk) { // open gallery for initial directory - image_navi::thumbsize = 128; - m_gallery(0,0); // v.11.08 - } - - else if (Fprev) // start with previous file v.11.08 - m_previous(0,0); - - else if (Frecent) { - image_navi::thumbsize = 180; // start with gallery of recent files - m_recent(0,0); // v.11.07 - } - - return 0; // start with blank window -} - - -/**************************************************************************/ - -// Periodic function -// Avoid any thread usage of gtk/gdk functions. - -int gtimefunc(void *arg) -{ - static zdialog *zdmessage = 0; - int syncfd; - - if (Wrepaint) { // window update needed - Wrepaint = 0; - mwpaint1(); - } - - update_statusbar(); // update every cycle v.11.03 - - if (Fslideshow) slideshow_next("timer"); // show next image if time is up - - if (Ffuncbusy) - paint_text(Dww/2-50,Dhh-20,"BUSY","monospace 10"); // write BUSY on window v.11.07 - - if (threadmessage && ! zdmessage) // display message for thread process - zdmessage = zmessage_post(mWin,0,threadmessage); // (avoid use of GTK in threads) v.11.03 - - if (zdmessage && ! threadmessage) // message terminated by thread - zdialog_free(zdmessage); - - if (zdmessage && zdmessage->sentinel != zdsentinel) { // popup window closed by user - zdmessage = 0; - threadmessage = 0; - } - - syncfd = global_lock(fsync_lock); // check for sync files process - if (syncfd >= 0) { // not busy - global_unlock(syncfd); - if (Fsyncbusy) threadmessage = 0; // it was busy, now done v.11.11 - Fsyncbusy = 0; - } - else Fsyncbusy = 1; // sync files still busy - - return 1; -} - - -/**************************************************************************/ - -// update status bar with image data and status -// called from timer function - -void update_statusbar() -{ - static double time1 = 0, time2, cpu1 = 0, cpu2, cpuload; - char text1[300], text2[100]; - int ww, hh, scale, bpc, done; - double file_MB = 1.0 / mega * curr_file_size; - - *text1 = *text2 = 0; - - time2 = get_seconds(); // compute process cpu load - if (time2 - time1 > 1.0) { // at 1 second intervals - cpu2 = jobtime(); // v.11.09 - cpuload = 100.0 * (cpu2 - cpu1) / (time2 - time1); - time1 = time2; - cpu1 = cpu2; - } - - sprintf(text1,"CPU %03.0f%c",cpuload,'%'); // CPU 023% - - if (curr_file) // v.11.04 - { - if (E3pxm16) { - ww = E3ww; - hh = E3hh; - bpc = 16; - } - else if (Fpxm16) { - ww = Fww; - hh = Fhh; - bpc = 16; - } - else { - ww = Fww; - hh = Fhh; - bpc = curr_file_bpc; - } - - snprintf(text2,99," %dx%dx%d",ww,hh,bpc); // 2345x1234x16 (preview) 1.56MB 45% - strcat(text1,text2); - if (Fpreview) strcat(text1," (preview)"); - sprintf(text2," %.2fMB",file_MB); - strcat(text1,text2); - scale = Mscale * 100 + 0.5; - sprintf(text2," %d%c",scale,'%'); - strcat(text1,text2); - - if (Pundo) { // edit undo stack depth - snprintf(text2,99," edits: %d",Pundo); - strcat(text1,text2); - } - } - - if (Fmenulock) strcat(text1," menu locked"); - if (Fsyncbusy) strcat(text1," file sync busy"); // v.11.11 - if (Factivearea) strcat(text1," area active"); // v.11.01 - if (zfuncs::zdialog_busy) strcat(text1," dialog open"); // v.11.11 - - if (SB_goal) { // progress monitor v.9.6 - done = 100.0 * SB_done / SB_goal; // v.11.06 - snprintf(text2,99," progress %d%c",done,'%'); - strcat(text1,text2); - } - - if (*SB_text) { // application text v.10.7 - strcat(text1," "); - strcat(text1,SB_text); - } - - stbar_message(STbar,text1); // write to status bar - - return; -} - - -/**************************************************************************/ - -// functions for main window event signals - -int delete_event() // main window closed -{ - printf("main window delete event \n"); - if (mod_keep()) return 1; // allow user bailout - Fshutdown++; // shutdown in progress - save_params(); // save parameters for next session - zdialog_positions("save"); // save dialog positions too v.11.07 - free_resources(); // delete undo files - return 0; -} - -void destroy_event() // main window destroyed -{ - printf("main window destroy event \n"); - exit(1); // instead of gtk_main_quit(); - return; -} - - -// process top-level menu entry - -void topmenufunc(GtkWidget *, cchar *menu) -{ - topmenu = (char *) menu; // remember top-level menu in case - return; // this is needed somewhere -} - - -/**************************************************************************/ - -// Paint window when created, exposed, resized, or modified (edited). -// This is a full window update. May NOT be called from threads. - -int mwpaint1() -{ - GdkRectangle wrect; - int incrx, incry; // mouse drag - static int pincrx = 0, pincry = 0; // prior mouse drag - static int pdww = 0, pdhh = 0; // prior window size - static int piorgx = 0, piorgy = 0; // prior image origin in window - static double pscale = 1; // prior scale - double wscale, hscale; - int refresh = 0; // flag, image refesh needed - PXM *pxmtemp; - - if (Fshutdown) return 1; // shutdown underway - if (! Fpxm8) return 1; // no image - - Dww = drWin->allocation.width; // (new) drawing window size - Dhh = drWin->allocation.height; - if (Dww < 20 || Dhh < 20) return 1; // too small - - if (mutex_trylock(&Fpixmap_lock) != 0) { // lock pixmaps - Wrepaint++; // cannot, come back later - return 1; - } - - if (Frefresh) { // image was updated - refresh++; - Frefresh = 0; - } - - if (Dww != pdww || Dhh != pdhh) { // window size changed - refresh++; // image refresh needed - pdww = Dww; - pdhh = Dhh; - } - - if (E3pxm16) { // get image size - Iww = E3ww; - Ihh = E3hh; // edit in progress - } - else { - Iww = Fww; // no edit - Ihh = Fhh; - } - - if (Fzoom == 0) { // scale to fit window - wscale = 1.0 * Dww / Iww; - hscale = 1.0 * Dhh / Ihh; - if (wscale < hscale) Mscale = wscale; // use greatest ww/hh ratio - else Mscale = hscale; - if (Iww < Dww && Ihh < Dhh && ! Fblowup) Mscale = 1.0; // small image 1x unless Fblowup - zoomx = zoomy = 0; - } - else Mscale = Fzoom; // scale to Fzoom level - - if (Mscale != pscale) refresh++; // scale changed, image refresh needed - - if (Mscale > pscale) { // zoom increased - Iorgx += iww * 0.5 * (1.0 - pscale / Mscale); // keep current image center - Iorgy += ihh * 0.5 * (1.0 - pscale / Mscale); - } - pscale = Mscale; - - iww = Dww / Mscale; // image space fitting in window - if (iww > Iww) iww = Iww; - ihh = Dhh / Mscale; - if (ihh > Ihh) ihh = Ihh; - - if (zoomx || zoomy) { // req. zoom center - Iorgx = zoomx - 0.5 * iww; // corresp. image origin - Iorgy = zoomy - 0.5 * ihh; - zoomx = zoomy = 0; - } - - if ((Mxdrag || Mydrag) && ! Mcapture) { // scroll via mouse drag - incrx = (Mxdrag - Mxdown) * 1.3 * Iww / iww; // scale - incry = (Mydrag - Mydown) * 1.3 * Ihh / ihh; - if (pincrx > 0 && incrx < 0) incrx = 0; // stop bounce at extremes - if (pincrx < 0 && incrx > 0) incrx = 0; - pincrx = incrx; - if (pincry > 0 && incry < 0) incry = 0; - if (pincry < 0 && incry > 0) incry = 0; - pincry = incry; - Iorgx += incrx; // new image origin after scroll - Iorgy += incry; - Mxdown = Mxdrag + incrx; // new drag origin - Mydown = Mydrag + incry; - Mxdrag = Mydrag = 0; - } - - if (iww == Iww) { // scaled image <= window width - Iorgx = 0; // center image in window - Dorgx = 0.5 * (Dww - Iww * Mscale); - } - else Dorgx = 0; // image > window, use entire window - - if (ihh == Ihh) { // same for image height - Iorgy = 0; - Dorgy = 0.5 * (Dhh - Ihh * Mscale); - } - else Dorgy = 0; - - if (Iorgx + iww > Iww) Iorgx = Iww - iww; // set limits - if (Iorgy + ihh > Ihh) Iorgy = Ihh - ihh; - if (Iorgx < 0) Iorgx = 0; - if (Iorgy < 0) Iorgy = 0; - - if (Iorgx != piorgx || Iorgy != piorgy) { // image origin changed - refresh++; // image refresh needed - piorgx = Iorgx; - piorgy = Iorgy; - } - - if (refresh) // image refresh is needed - { - if (E3pxm16) { // edit in progress - PXM_free(Dpxm16); - Dpxm16 = PXM_copy_area(E3pxm16,Iorgx,Iorgy,iww,ihh); // copy E3 image area, PXM-16 - pxmtemp = PXM_convbpc(Dpxm16); // convert to PXM-8 - } - else pxmtemp = PXM_copy_area(Fpxm8,Iorgx,Iorgy,iww,ihh); // no edit, copy PXM-8 image area - - dww = iww * Mscale; // scale to window - dhh = ihh * Mscale; - PXM_free(Dpxm8); - Dpxm8 = PXM_rescale(pxmtemp,dww,dhh); - PXM_free(pxmtemp); - } - - wrect.x = wrect.y = 0; // stop flicker - wrect.width = Dww; - wrect.height = Dhh; - gdk_window_begin_paint_rect(drWin->window,&wrect); - - gdk_draw_rgb_image(drWin->window, gdkgc, Dorgx, Dorgy, dww, dhh, // draw scaled image to window - NODITHER, (uint8 *) Dpxm8->bmp, dww*3); - - if (Ntoplines) paint_toplines(1); // draw line overlays - if (Ftoparc) paint_toparc(1); // draw arc overlay - if (Fgrid) paint_gridlines(); // draw grid lines - if (Ntoptext) paint_toptext(); // draw text strings v.11.07 - if (Fshowarea && ! Fpreview) sa_show(1); // draw select area outline - - gdk_window_end_paint(drWin->window); // release all window updates - - mutex_unlock(&Fpixmap_lock); // unlock pixmaps - Wpainted++; // notify edit function of repaint - histogram_paint(); // update brightness histogram if exists - return 1; -} - - -/**************************************************************************/ - -// Cause (modified) output image to get repainted soon. -// The entire image is repainted (that part within the window). -// MAY be called from threads. - -void mwpaint2() -{ - Frefresh++; - Wrepaint++; // req. repaint by periodic function - return; -} - - -// Repaint a rectangular part of the image being edited. -// px3, py3, ww3, hh3: modified area within E3pxm16 to be repainted -// Dpxm16: 1x copy of E3pxm16 area currently visible in main window -// px2, py2, ww2, hh2: E3pxm16 area copied into Dpxm16 -// Dpxm8: window image, Dpxm16 scaled to window, converted to 8 bits -// May NOT be called from threads. - -void mwpaint3(int px3, int py3, int ww3, int hh3) // overhauled v.10.11 -{ - int px2, py2, ww2, hh2, dx, dy; - uint16 *pix2, *pix3; - uint8 *pxm8area; - - if (! Dpxm16) zappcrash("mwpaint3() no Dpxm16"); // v.10.12 - - px2 = px3 - Iorgx; // map modified area into Dpxm16 - py2 = py3 - Iorgy; - ww2 = ww3; - hh2 = hh3; - - if (px2 < 0) { // if beyond Dpxm16 edge, reduce - px3 -= px2; - ww2 += px2; - px2 = 0; - } - if (px2 + ww2 > iww) ww2 = iww - px2; - - if (py2 < 0) { - py3 -= py2; - hh2 += py2; - py2 = 0; - } - if (py2 + hh2 > ihh) hh2 = ihh - py2; - - if (ww2 <= 0 || hh2 <= 0) return; // completely off Dpxm16 image - - for (dy = 0; dy < hh2; dy++) // copy pixels from E3pxm16 to Dpxm16 - for (dx = 0; dx < ww2; dx++) - { - pix3 = PXMpix(E3pxm16,px3+dx,py3+dy); - pix2 = PXMpix(Dpxm16,px2+dx,py2+dy); - pix2[0] = pix3[0]; - pix2[1] = pix3[1]; - pix2[2] = pix3[2]; - } - - PXM_update(Dpxm16,Dpxm8,px2,py2,ww2,hh2); // copy/rescale Dpxm16 area into Dpxm8 area - - px2 = px2 * Mscale - 1; // Dpxm8 area impacted v.10.12 - py2 = py2 * Mscale - 1; - ww2 = ww2 * Mscale + 1 / Mscale + 2; - hh2 = hh2 * Mscale + 1 / Mscale + 2; - - if (px2 < 0) px2 = 0; // stay within image edge - if (py2 < 0) py2 = 0; - if (px2 + ww2 > dww) ww2 = dww - px2; - if (py2 + hh2 > dhh) hh2 = dhh - py2; - if (ww2 <= 0 || hh2 <= 0) return; // completely off Dpxm8 image - - pxm8area = (uint8 *) Dpxm8->bmp + 3 * (dww * py2 + px2); // origin of area to copy - - gdk_draw_rgb_image(drWin->window, gdkgc, px2 + Dorgx, py2 + Dorgy, // copy into window - ww2, hh2, NODITHER, pxm8area, dww*3); - return; -} - - -/**************************************************************************/ - -// mouse event function - capture buttons and drag movements - -void mouse_event(GtkWidget *, GdkEventButton *event, void *) -{ - void mouse_convert(int &xpos, int &ypos); - - static int bdtime = 0, butime = 0, mbusy = 0; - int button, time, type; - - type = event->type; - button = event->button; // button, 1/3 = left/right - time = event->time; - Mxposn = event->x; // mouse position in window - Myposn = event->y; - - mouse_convert(Mxposn,Myposn); // convert to image space - - if (type == GDK_MOTION_NOTIFY) { - if (mbusy) return; // discard excess motion events - mbusy++; - zmainloop(); - mbusy = 0; - } - - if (type == GDK_BUTTON_PRESS) { // button down - bdtime = time; // time of button down - Mxdown = Mxposn; // position at button down time - Mydown = Myposn; - if (button) { - Mdrag++; // possible drag start - Mbutton = button; - } - Mxdrag = Mydrag = 0; - } - - if (type == GDK_BUTTON_RELEASE) { // button up - Mxclick = Myclick = 0; // reset click status - butime = time; // time of button up - if (butime - bdtime < 400) // less than 0.4 secs down - if (Mxposn == Mxdown && Myposn == Mydown) { // and not moving - if (Mbutton == 1) LMclick++; // left mouse click - if (Mbutton == 3) RMclick++; // right mouse click - Mxclick = Mxdown; // click = button down position - Myclick = Mydown; - } - Mxdown = Mydown = Mxdrag = Mydrag = Mdrag = Mbutton = 0; // forget buttons and drag - } - - if (type == GDK_MOTION_NOTIFY && Mdrag) { // drag underway - Mxdrag = Mxposn; - Mydrag = Myposn; - } - - if (mouseCBfunc) { // pass to handler function - if (mbusy) return; - mbusy++; // stop re-entrance v.10.8 - (* mouseCBfunc)(); - mbusy = 0; - return; - } - - if (LMclick && ! Mcapture) { // left click = zoom request - LMclick = 0; - zoomx = Mxclick; // zoom center = mouse - zoomy = Myclick; - m_zoom(null, (char *) "+"); - } - - if (RMclick && ! Mcapture) { // right click - RMclick = 0; - if (Fzoom) { - zoomx = zoomy = 0; // reset zoomed image - m_zoom(null, (char *) "-"); - } - else if (edit_coll_name && curr_file) // pass file to edit collection - edit_coll_popmenu(null,curr_file); // v.11.11 - } - - if ((Mxdrag || Mydrag) && ! Mcapture) mwpaint1(); // drag = scroll - return; -} - - -// convert mouse position from window space to image space - -void mouse_convert(int &xpos, int &ypos) -{ - xpos = (xpos - Dorgx) / Mscale + Iorgx + 0.5; - ypos = (ypos - Dorgy) / Mscale + Iorgy + 0.5; - - if (xpos < 0) xpos = 0; // if outside image put at edge - if (ypos < 0) ypos = 0; - - if (E3pxm16) { - if (xpos >= E3ww) xpos = E3ww-1; - if (ypos >= E3hh) ypos = E3hh-1; - } - else { - if (xpos >= Fww) xpos = Fww-1; - if (ypos >= Fhh) ypos = Fhh-1; - } - - return; -} - - -/**************************************************************************/ - -// keyboard event function - some toolbar buttons have KB equivalents -// GDK key symbols: /usr/include/gtk-2.0/gdk/gdkkeysyms.h - -int KBzmalloclog = 0; -int KBcontrolkey; -int KBshiftkey; -int KB_A_key; - -int KBpress(GtkWidget *win, GdkEventKey *event, void *) // prevent propagation of key-press -{ // events to toolbar buttons - KBkey = event->keyval; - - if (KBkey == GDK_Control_L || // Ctrl key is pressed v.11.07 - KBkey == GDK_Control_R) KBcontrolkey = 1; - - if (KBkey == GDK_Shift_L || // Shift key is pressed v.11.07 - KBkey == GDK_Shift_R) KBshiftkey = 1; - - if (KBkey == GDK_a || // 'A' key is pressed v.11.11 - KBkey == GDK_A) KB_A_key = 1; // (undo/redo --> undo/redo ALL) - - return 1; -} - -int KBrelease(GtkWidget *win, GdkEventKey *event, void *) -{ - int angle = 0; - PXM *pxm; - - KBkey = event->keyval; - - if (KBcapture) return 1; // let function handle it - - if (KBkey == GDK_Control_L || // Ctrl key released v.11.07 - KBkey == GDK_Control_R) KBcontrolkey = 0; - - if (KBkey == GDK_Shift_L || // Shift key released v.11.07 - KBkey == GDK_Shift_R) KBshiftkey = 0; - - if (KBkey == GDK_a || // 'A' key is released v.11.11 - KBkey == GDK_A) KB_A_key = 0; - - if (KBcontrolkey) { - if (KBkey == GDK_s) m_save(0,0); // Ctrl-* shortcuts - if (KBkey == GDK_S) m_saveas(0,0); - if (KBkey == GDK_v) m_savevers(0,0); - if (KBkey == GDK_V) m_savevers(0,0); - if (KBkey == GDK_q) m_quit(0,0); - if (KBkey == GDK_Q) m_quit(0,0); - } - - if (KBkey == GDK_G || KBkey == GDK_g) // toggle grid lines v.11.11 - toggle_grid(2); - - if (Fslideshow) { // v.11.10 - if (KBkey == GDK_Left) slideshow_next("prev"); // arrow keys = prev/next image - if (KBkey == GDK_Right) slideshow_next("next"); - if (KBkey == GDK_space) slideshow_next("pause"); // spacebar = pause/resume - if (KBkey == GDK_Escape) m_slideshow(0,0); // escape = exit slideshow - } - else { - if (KBkey == GDK_Left) m_prev(0,0); // arrow keys = prev/next image - if (KBkey == GDK_Right) m_next(0,0); - } - - if (KBkey == GDK_plus) m_zoom(null, (char *) "+"); // +/- keys >> zoom in/out - if (KBkey == GDK_equal) m_zoom(null, (char *) "+"); // = key: same as + - if (KBkey == GDK_minus) m_zoom(null, (char *) "-"); - if (KBkey == GDK_KP_Add) m_zoom(null, (char *) "+"); // keypad + - if (KBkey == GDK_KP_Subtract) m_zoom(null, (char *) "-"); // keypad - - - if (KBkey == GDK_Delete) m_trash(0,0); // delete >> trash - - if (KBkey == GDK_F1) // F1 >> user guide - showz_userguide(zfuncs::F1_help_topic); // show topic if there, or page 1 - - if (! E1pxm16) { // if no edit in progress, - if (KBkey == GDK_R || KBkey == GDK_r) angle = 90; // allow manual rotations - if (KBkey == GDK_L || KBkey == GDK_l) angle = -90; - if (angle) { - mutex_lock(&Fpixmap_lock); // v.10.5 - pxm = PXM_rotate(Fpxm8,angle); - PXM_free(Fpxm8); - Fpxm8 = pxm; - Fww = pxm->ww; - Fhh = pxm->hh; - mutex_unlock(&Fpixmap_lock); - mwpaint2(); - m_save(0,"nowarn"); // auto save uprighted image v.10.12 - } - } - - if (KBcontrolkey && KBkey == GDK_m) { // zmalloc() activity log - KBzmalloclog = 1 - KBzmalloclog; // Ctrl+M = toggle on/off - if (KBzmalloclog) zmalloc_log(999999); - else zmalloc_log(0); - zmalloc_report(); // v.10.8 - } - - if (KBkey == GDK_T || KBkey == GDK_t) m_trim(0,0); // Key T = Trim function v.10.3.1 - if (KBkey == GDK_B || KBkey == GDK_b) m_tune(0,0); // Key B = brightness/color v.10.3.1 - if (KBkey == GDK_N || KBkey == GDK_n) m_rename(0,0); // Key N = rename file v.11.11 - - if (KBkey == GDK_z || KBkey == GDK_Z) { // Z key - if (! KBcontrolkey) m_zoom(null, (char *) "Z"); // if no control key, toggle zoom 1x - else { // if control key, v.11.11 - if (KBshiftkey) m_redo(0,0); // with shift: redo edit - else m_undo(0,0); // without shift: undo edit - } - } - - KBkey = 0; - return 1; -} - - -/**************************************************************************/ - -// paint a grid of horizontal and vertical lines - -void paint_gridlines() // revised v.10.10.2 -{ - int px, py, stepx, stepy, startx, starty; - - if (! Fpxm8) return; // no image - if (! Fgrid) return; // grid lines off v.11.11 - - stepx = gridspace[0]; // space between grid lines - stepy = gridspace[1]; - - if (gridcount[0]) stepx = dww / (1 + gridcount[0]); // if line counts specified, v.10.11 - if (gridcount[1]) stepy = dhh / ( 1 + gridcount[1]); // set spacing accordingly - - startx = stepx * gridoffset[0] / 100; // variable offsets v.11.11 - if (startx < 0) startx += stepx; - - starty = stepy * gridoffset[1] / 100; - if (starty < 0) starty += stepy; - - gdk_gc_set_foreground(gdkgc,&white); // white lines - - if (gridon[0] && stepx) - for (px = Dorgx+startx; px < Dorgx+dww; px += stepx) - gdk_draw_line(drWin->window,gdkgc,px,Dorgy,px,Dorgy+dhh); - - if (gridon[1] && stepy) - for (py = Dorgy+starty; py < Dorgy+dhh; py += stepy) - gdk_draw_line(drWin->window,gdkgc,Dorgx,py,Dorgx+dww,py); - - gdk_gc_set_foreground(gdkgc,&black); // adjacent black lines - fg_color = black; // v.10.12 - - if (gridon[0] && stepx) - for (px = Dorgx+startx+1; px < Dorgx+dww; px += stepx) - gdk_draw_line(drWin->window,gdkgc,px,Dorgy,px,Dorgy+dhh); - - if (gridon[1] && stepy) - for (py = Dorgy+starty+1; py < Dorgy+dhh; py += stepy) - gdk_draw_line(drWin->window,gdkgc,Dorgx,py,Dorgx+dww,py); - - return; -} - - -/**************************************************************************/ - -// refresh overlay lines on top of image -// arg = 1: paint lines only (because window repainted) -// 2: erase lines and forget them -// 3: erase old lines, paint new lines, save new in old - -void paint_toplines(int arg) -{ - int ii; - - if (arg == 2 || arg == 3) // erase old lines - for (ii = 0; ii < Nptoplines; ii++) - erase_line(ptoplinex1[ii],ptopliney1[ii],ptoplinex2[ii],ptopliney2[ii]); - - if (arg == 1 || arg == 3) // draw new lines - for (ii = 0; ii < Ntoplines; ii++) - draw_line(toplinex1[ii],topliney1[ii],toplinex2[ii],topliney2[ii]); - - if (arg == 2) { - Nptoplines = Ntoplines = 0; // forget lines - return; - } - - for (ii = 0; ii < Ntoplines; ii++) // save for future erase - { - ptoplinex1[ii] = toplinex1[ii]; - ptopliney1[ii] = topliney1[ii]; - ptoplinex2[ii] = toplinex2[ii]; - ptopliney2[ii] = topliney2[ii]; - } - - Nptoplines = Ntoplines; - - return; -} - - -/**************************************************************************/ - -// refresh overlay arc (circle/ellipse) on top of image -// arg = 1: paint arc only (because window repainted) -// 2: erase arc and forget it -// 3: erase old arc, paint new arc, save new in old - -void paint_toparc(int arg) -{ - int arcx, arcy, arcw, arch; - - if (ptoparc && (arg == 2 || arg == 3)) { // erase old arc - arcx = (ptoparcx-Iorgx) * Mscale + Dorgx + 0.5; // image to window space - arcy = (ptoparcy-Iorgy) * Mscale + Dorgy + 0.5; - arcw = ptoparcw * Mscale; - arch = ptoparch * Mscale; - - gdk_gc_set_function(gdkgc,GDK_INVERT); // invert pixels - gdk_draw_arc(drWin->window,gdkgc,0,arcx,arcy,arcw,arch,0,64*360); // draw arc - gdk_gc_set_function(gdkgc,GDK_COPY); - } - - if (Ftoparc && (arg == 1 || arg == 3)) { // draw new arc - arcx = (toparcx-Iorgx) * Mscale + Dorgx + 0.5; // image to window space - arcy = (toparcy-Iorgy) * Mscale + Dorgy + 0.5; - arcw = toparcw * Mscale; - arch = toparch * Mscale; - - gdk_gc_set_function(gdkgc,GDK_INVERT); // invert pixels - gdk_draw_arc(drWin->window,gdkgc,0,arcx,arcy,arcw,arch,0,64*360); // draw arc - gdk_gc_set_function(gdkgc,GDK_COPY); - } - - if (arg == 2) { - Ftoparc = ptoparc = 0; // forget arcs - return; - } - - ptoparc = Ftoparc; // save for future erase - ptoparcx = toparcx; - ptoparcy = toparcy; - ptoparcw = toparcw; - ptoparch = toparch; - - return; -} - - -/**************************************************************************/ - -// draw dotted line. coordinates are in image space. - -void draw_line(int ix1, int iy1, int ix2, int iy2) -{ - void draw_line_pixel(double pxm, double pym); - - double x1, y1, x2, y2; - double pxm, pym, slope; - - x1 = Mscale * (ix1-Iorgx); // image to window space - y1 = Mscale * (iy1-Iorgy); - x2 = Mscale * (ix2-Iorgx); - y2 = Mscale * (iy2-Iorgy); - - if (abs(y2 - y1) > abs(x2 - x1)) { - slope = 1.0 * (x2 - x1) / (y2 - y1); - if (y2 > y1) { - for (pym = y1; pym <= y2; pym++) { - pxm = round(x1 + slope * (pym - y1)); - draw_line_pixel(pxm,pym); - } - } - else { - for (pym = y1; pym >= y2; pym--) { - pxm = round(x1 + slope * (pym - y1)); - draw_line_pixel(pxm,pym); - } - } - } - else { - slope = 1.0 * (y2 - y1) / (x2 - x1); - if (x2 > x1) { - for (pxm = x1; pxm <= x2; pxm++) { - pym = round(y1 + slope * (pxm - x1)); - draw_line_pixel(pxm,pym); - } - } - else { - for (pxm = x1; pxm >= x2; pxm--) { - pym = round(y1 + slope * (pxm - x1)); - draw_line_pixel(pxm,pym); - } - } - } - - gdk_gc_set_foreground(gdkgc,&black); - fg_color = black; - - return; -} - -void draw_line_pixel(double px, double py) -{ - int pxn, pyn; - static int flip = 0; - - pxn = px; - pyn = py; - - if (pxn < 0 || pxn > dww-1) return; - if (pyn < 0 || pyn > dhh-1) return; - - if (++flip > 4) flip = -5; // black/white line v.10.10 - if (flip < 0) gdk_gc_set_foreground(gdkgc,&black); - else gdk_gc_set_foreground(gdkgc,&white); - gdk_draw_point(drWin->window, gdkgc, pxn + Dorgx, pyn + Dorgy); - - return; -} - - -// erase line. refresh line path from Dpxm8 pixels. - -void erase_line(int ix1, int iy1, int ix2, int iy2) -{ - void erase_line_pixel(double pxm, double pym); - - double x1, y1, x2, y2; - double pxm, pym, slope; - - if (! Dpxm8) zappcrash("Dpxm8 = 0"); // v.10.3 - - x1 = Mscale * (ix1-Iorgx); - y1 = Mscale * (iy1-Iorgy); - x2 = Mscale * (ix2-Iorgx); - y2 = Mscale * (iy2-Iorgy); - - if (abs(y2 - y1) > abs(x2 - x1)) { - slope = 1.0 * (x2 - x1) / (y2 - y1); - if (y2 > y1) { - for (pym = y1; pym <= y2; pym++) { - pxm = x1 + slope * (pym - y1); - erase_line_pixel(pxm,pym); - } - } - else { - for (pym = y1; pym >= y2; pym--) { - pxm = x1 + slope * (pym - y1); - erase_line_pixel(pxm,pym); - } - } - } - else { - slope = 1.0 * (y2 - y1) / (x2 - x1); - if (x2 > x1) { - for (pxm = x1; pxm <= x2; pxm++) { - pym = y1 + slope * (pxm - x1); - erase_line_pixel(pxm,pym); - } - } - else { - for (pxm = x1; pxm >= x2; pxm--) { - pym = y1 + slope * (pxm - x1); - erase_line_pixel(pxm,pym); - } - } - } - - return; -} - -void erase_line_pixel(double px, double py) -{ - int pxn, pyn; - - pxn = px; - pyn = py; - - if (pxn < 0 || pxn > dww-1) return; - if (pyn < 0 || pyn > dhh-1) return; - - uint8 *pixel = (uint8 *) Dpxm8->bmp + (pyn * dww + pxn) * 3; - gdk_draw_rgb_image(drWin->window, gdkgc, pxn + Dorgx, pyn + Dorgy, - 1, 1, NODITHER, pixel, dww * 3); - return; -} - - -// draw one pixel using given color, R/G/B = red/green/black - -void draw_pixel(int px, int py, GdkColor *color) // v.10.12 -{ - int qx, qy; - static int pqx, pqy; - - qx = Mscale * (px-Iorgx) + 0.5; // image to window space - qy = Mscale * (py-Iorgy) + 0.5; - - if (qx == pqx && qy == pqy) return; // avoid redundant points v.9.7 - - pqx = qx; - pqy = qy; - - qx = qx + Dorgx; // image origin in drawing window - qy = qy + Dorgy; - - if (qx < 0 || qx > Dww-1) return; // bugfix v.11.03.1 - if (qy < 0 || qy > Dhh-1) return; - - if (color != &fg_color) { - fg_color = *color; - gdk_gc_set_foreground(gdkgc,&fg_color); - } - - gdk_draw_point(drWin->window,gdkgc,qx,qy); // draw pixel - - return; -} - - -// draw a fat pixel using given color, R/G/B = red/green/black - -void draw_fat_pixel(int px, int py, GdkColor *color) // speedup v.11.04 -{ - int qx, qy; - static int pqx, pqy; - - qx = Mscale * (px-Iorgx) + 0.5; // image to window space - qy = Mscale * (py-Iorgy) + 0.5; - - if (qx == pqx && qy == pqy) return; // avoid redundant points v.9.7 - - pqx = qx; - pqy = qy; - - qx = qx + Dorgx; // image origin in drawing window - qy = qy + Dorgy; - - if (qx < 0 || qy < 0) return; - - if (color != &fg_color) { - fg_color = *color; - gdk_gc_set_foreground(gdkgc,&fg_color); - } - - if (qx < Dww-1 && qy < Dhh-1 && Mscale > 1.0) - gdk_draw_rectangle(drWin->window,gdkgc,0,qx,qy,2,2); // draw fat pixel 2x2 - - else if (qx < Dww && qy < Dhh) - gdk_draw_point(drWin->window,gdkgc,qx,qy); // on edge, draw pixel - - return; -} - - -/**************************************************************************/ - -// maintain a set of text strings written whenever the window is painted - -// add a new text string to the list -// multiple text strings can be added with the same ID -// px and py are image coordinates - -void add_toptext(int ID, int px, int py, cchar *text, cchar *font) // new v.11.07 -{ - if (Ntoptext == maxtoptext) { - printf("maxtoptext exceeded \n"); - return; - } - - int ii = Ntoptext++; - toptext[ii].ID = ID; - toptext[ii].px = px; - toptext[ii].py = py; - toptext[ii].text = text; - toptext[ii].font = font; - - return; -} - - -// delete text strings having the given ID from the list - -void erase_toptext(int ID) // new v.11.07 -{ - int ii, jj; - - for (ii = jj = 0; ii < Ntoptext; ii++) - { - if (toptext[ii].ID == ID) continue; - else toptext[jj++] = toptext[ii]; - } - - Ntoptext = jj; - - return; -} - - -// paint current text strings on window whenever it is repainted -// called from mwpaint() - -void paint_toptext() // new v.11.07 -{ - int ii, px, py; - - for (ii = 0; ii < Ntoptext; ii++) { - px = toptext[ii].px; - py = toptext[ii].py; - px = Mscale * (px - Iorgx) + Dorgx; // image to window space - py = Mscale * (py - Iorgy) + Dorgy; - paint_text(px,py,toptext[ii].text,toptext[ii].font); - } - - return; -} - - -// paint text on window, black on white background -// px and py are window coordinates - -void paint_text(int px, int py, cchar *text, cchar *font) // new v.11.07 -{ - static PangoFontDescription *pangofont = null; - static PangoLayout *pangolayout = null; - static char priorfont[40] = ""; - - if (strNeq(font,priorfont)) { // change font - strncpy0(priorfont,font,40); - if (pangofont) pango_font_description_free(pangofont); - if (pangolayout) g_object_unref(pangolayout); - pangofont = pango_font_description_from_string(font); - pangolayout = gtk_widget_create_pango_layout(drWin,0); - pango_layout_set_font_description(pangolayout,pangofont); - } - - pango_layout_set_text(pangolayout,text,-1); - gdk_draw_layout_with_colors(drWin->window,gdkgc,px,py,pangolayout,&black,&white); - - return; -} - - -/************************************************************************** - - spline curve setup and edit functions - - Support multiple frames with curves in parallel // v.11.01 - (edit curve(s) and image mask curve) - - Usage: - Add frame widget to dialog or zdialog. - Set up drawing in frame: - sd = curve_init(frame, callback_func) - Initialize no. of curves in frame (1-10): - sd->Nspc = n - Initialize vert/horz flag for curve spc: - sd->vert[spc] = hv - Initialize anchor points for curve spc: - sd->nap[spc], sd->apx[spc][xx], sd->apy[spc][yy] - Generate data for curve spc: - splcurve_generate(sd,spc) - Curves will now be shown and edited inside the frame when window is realized. - The callback_func(spc) will be called when curve spc is edited. - Change curve in program: - set anchor points, call splcurve_generate(sd,spc) - Get y-value (0-1) for curve spc and given x-value (0-1): - yval = splcurve_yval(sd,spc,xval) - If faster access to curve is needed (no interpolation): - kk = 1000 * xval; - if (kk > 999) kk = 999; - yval = sd->yval[spc][kk]; - -***/ - -// initialize for spline curve editing -// initial anchor points are pre-loaded into spldat before window is realized - -spldat * splcurve_init(GtkWidget *frame, void func(int spc)) -{ - int cc = sizeof(spldat); // allocate spc curve data area - spldat * sd = (spldat *) zmalloc(cc,"curvedat"); - memset(sd,0,cc); - - sd->drawarea = gtk_drawing_area_new(); // drawing area for curves - gtk_container_add(GTK_CONTAINER(frame),sd->drawarea); - sd->spcfunc = func; // user callback function - - gtk_widget_add_events(sd->drawarea,GDK_BUTTON_PRESS_MASK); // connect mouse events to drawing area - gtk_widget_add_events(sd->drawarea,GDK_BUTTON_RELEASE_MASK); - gtk_widget_add_events(sd->drawarea,GDK_BUTTON1_MOTION_MASK); - G_SIGNAL(sd->drawarea,"motion-notify-event",splcurve_adjust,sd) - G_SIGNAL(sd->drawarea,"button-press-event",splcurve_adjust,sd) - G_SIGNAL(sd->drawarea,"expose-event",splcurve_draw,sd) - - return sd; -} - - -// modify anchor points in curve using mouse - -int splcurve_adjust(void *, GdkEventButton *event, spldat *sd) -{ - int ww, hh, kk; - int mx, my, button, evtype; - static int spc, ap, mbusy = 0, Fdrag = 0; // drag continuation logic v.9.7 - int minspc, minap; - double mxval, myval, cxval, cyval; - double dist2, mindist2 = 0; - - mx = event->x; // mouse position in drawing area - my = event->y; - evtype = event->type; - button = event->button; - - if (evtype == GDK_MOTION_NOTIFY) { - if (mbusy) return 0; // discard excess motion events v.11.01 - mbusy++; - zmainloop(); - mbusy = 0; - } - - if (evtype == GDK_BUTTON_RELEASE) { - Fdrag = 0; - return 0; - } - - ww = sd->drawarea->allocation.width; // drawing area size - hh = sd->drawarea->allocation.height; - - if (mx < 0) mx = 0; // limit edge excursions - if (mx > ww) mx = ww; - if (my < 0) my = 0; - if (my > hh) my = hh; - - if (evtype == GDK_BUTTON_PRESS) Fdrag = 0; // left or right click - - if (Fdrag) // continuation of drag - { - if (sd->vert[spc]) { - mxval = 1.0 * my / hh; // mouse position in curve space - myval = 1.0 * mx / ww; - } - else { - mxval = 1.0 * mx / ww; - myval = 1.0 * (hh - my) / hh; - } - - if (ap < sd->nap[spc]-1 && sd->apx[spc][ap+1] - mxval < 0.05) // disallow < 0.05 from next - return 0; - if (ap > 0 && mxval - sd->apx[spc][ap-1] < 0.05) return 0; // or prior anchor point - } - - else // mouse click or new drag begin - { - minspc = minap = -1; // find closest curve/anchor point - mindist2 = 999999; - - for (spc = 0; spc < sd->Nspc; spc++) // loop curves - { - if (sd->vert[spc]) { - mxval = 1.0 * my / hh; // mouse position in curve space - myval = 1.0 * mx / ww; - } - else { - mxval = 1.0 * mx / ww; - myval = 1.0 * (hh - my) / hh; - } - - for (ap = 0; ap < sd->nap[spc]; ap++) // loop anchor points - { - cxval = sd->apx[spc][ap]; - cyval = sd->apy[spc][ap]; - dist2 = (mxval-cxval)*(mxval-cxval) - + (myval-cyval)*(myval-cyval); - if (dist2 < mindist2) { - mindist2 = dist2; // remember closest anchor point - minspc = spc; - minap = ap; - } - } - } - - if (minspc < 0) return 0; // impossible - spc = minspc; - ap = minap; - } - - if (evtype == GDK_BUTTON_PRESS && button == 3) // right click, remove anchor point - { - if (sqrt(mindist2) > 0.05) return 0; // not close enough - if (sd->nap[spc] < 3) return 0; // < 2 anchor points would remain - sd->nap[spc]--; // decr. before loop v.11.11 - for (kk = ap; kk < sd->nap[spc]; kk++) { - if (! kk) printf("meaningless reference %d",kk); // stop gcc optimization bug v.11.11 ///// - sd->apx[spc][kk] = sd->apx[spc][kk+1]; - sd->apy[spc][kk] = sd->apy[spc][kk+1]; - } - splcurve_generate(sd,spc); // regenerate data for modified curve - splcurve_draw(0,0,sd); // regen and redraw all curves - sd->spcfunc(spc); // call user function - return 0; - } - - if (! Fdrag) // new drag or left click - { - if (sd->vert[spc]) { - mxval = 1.0 * my / hh; // mouse position in curve space - myval = 1.0 * mx / ww; - } - else { - mxval = 1.0 * mx / ww; - myval = 1.0 * (hh - my) / hh; - } - - if (sqrt(mindist2) < 0.05) // existing point close enough, - { // move this anchor point to mouse - if (ap < sd->nap[spc]-1 && sd->apx[spc][ap+1] - mxval < 0.05) - return 0; // disallow < 0.05 from next - if (ap > 0 && mxval - sd->apx[spc][ap-1] < 0.05) return 0; // or prior anchor point - } - - else // none close, add new anchor point - { - minspc = -1; // find closest curve to mouse - mindist2 = 999999; - - for (spc = 0; spc < sd->Nspc; spc++) // loop curves - { - if (sd->vert[spc]) { - mxval = 1.0 * my / hh; // mouse position in curve space - myval = 1.0 * mx / ww; - } - else { - mxval = 1.0 * mx / ww; - myval = 1.0 * (hh - my) / hh; - } - - cyval = splcurve_yval(sd,spc,mxval); - dist2 = fabs(myval - cyval); - if (dist2 < mindist2) { - mindist2 = dist2; // remember closest curve - minspc = spc; - } - } - - if (minspc < 0) return 0; // impossible - if (mindist2 > 0.05) return 0; // not close enough to any curve - spc = minspc; - - if (sd->nap[spc] > 49) { - zmessageACK(mWin,ZTX("Exceed 50 anchor points")); - return 0; - } - - if (sd->vert[spc]) { - mxval = 1.0 * my / hh; // mouse position in curve space - myval = 1.0 * mx / ww; - } - else { - mxval = 1.0 * mx / ww; - myval = 1.0 * (hh - my) / hh; - } - - for (ap = 0; ap < sd->nap[spc]; ap++) // find anchor point with next higher x - if (mxval <= sd->apx[spc][ap]) break; // (ap may come out 0 or nap) - - if (ap < sd->nap[spc] && sd->apx[spc][ap] - mxval < 0.05) // disallow < 0.05 from next - return 0; // or prior anchor point - if (ap > 0 && mxval - sd->apx[spc][ap-1] < 0.05) return 0; - - for (kk = sd->nap[spc]; kk > ap; kk--) { // make hole for new point - sd->apx[spc][kk] = sd->apx[spc][kk-1]; - sd->apy[spc][kk] = sd->apy[spc][kk-1]; - } - - sd->nap[spc]++; // up point count - } - } - - sd->apx[spc][ap] = mxval; // new or moved anchor point - sd->apy[spc][ap] = myval; // at mouse position - - splcurve_generate(sd,spc); // regenerate data for modified curve - splcurve_draw(0,0,sd); // regen and redraw all curves - sd->spcfunc(spc); // call user function - - if (evtype == GDK_MOTION_NOTIFY) Fdrag = 1; // remember drag is underway - return 0; -} - - -// for expose event or when a curve is changed -// draw all curves based on current anchor points - -int splcurve_draw(void *, void *, spldat *sd) -{ - int ww, hh, px, py, qx, qy, spc, ap; - double xval, yval; - - ww = sd->drawarea->allocation.width; // drawing area size - hh = sd->drawarea->allocation.height; - if (ww < 50 || hh < 50) return 0; - - gdk_window_clear(sd->drawarea->window); // clear window - - gdk_gc_set_foreground(gdkgc,&dgray); - - for (int ii = 0; ii < sd->Nscale; ii++) // draw y-scale lines if any v.11.07 - { - px = ww * sd->xscale[0][ii] + 0.5; // any line, not only horizontal v.11.10 - py = hh - hh * sd->yscale[0][ii] + 0.5; - qx = ww * sd->xscale[1][ii] + 0.5; - qy = hh - hh * sd->yscale[1][ii] + 0.5; - gdk_draw_line(sd->drawarea->window,gdkgc,px,py,qx,qy); - } - - gdk_gc_set_foreground(gdkgc,&black); - fg_color = black; - - for (spc = 0; spc < sd->Nspc; spc++) - { - if (sd->vert[spc]) // vert. curve - { - for (py = 0; py < hh; py++) // generate all points for curve - { - xval = 1.0 * py / hh; // remove anchor point limits v.10.9 - yval = splcurve_yval(sd,spc,xval); - px = ww * yval + 0.49; // "almost" round - erratic floating point - gdk_draw_point(sd->drawarea->window,gdkgc,px,py); // causes "bumps" in a flat curve - } - - for (ap = 0; ap < sd->nap[spc]; ap++) // draw boxes at anchor points - { - xval = sd->apx[spc][ap]; - yval = sd->apy[spc][ap]; - px = ww * yval; - py = hh * xval; - for (qx = -2; qx < 3; qx++) - for (qy = -2; qy < 3; qy++) { - if (px+qx < 0 || px+qx >= ww) continue; - if (py+qy < 0 || py+qy >= hh) continue; - gdk_draw_point(sd->drawarea->window,gdkgc,px+qx,py+qy); - } - } - } - else // horz. curve - { - for (px = 0; px < ww; px++) // generate all points for curve - { - xval = 1.0 * px / ww; // remove anchor point limits v.10.9 - yval = splcurve_yval(sd,spc,xval); - py = hh - hh * yval + 0.49; // almost round - erratic FP in Intel CPUs - gdk_draw_point(sd->drawarea->window,gdkgc,px,py); // causes "bumps" in a flat curve - } - - for (ap = 0; ap < sd->nap[spc]; ap++) // draw boxes at anchor points - { - xval = sd->apx[spc][ap]; - yval = sd->apy[spc][ap]; - px = ww * xval; - py = hh - hh * yval; - for (qx = -2; qx < 3; qx++) - for (qy = -2; qy < 3; qy++) { - if (px+qx < 0 || px+qx >= ww) continue; - if (py+qy < 0 || py+qy >= hh) continue; - gdk_draw_point(sd->drawarea->window,gdkgc,px+qx,py+qy); - } - } - } - } - - return 0; -} - - -// generate all curve data points when anchor points are modified - -int splcurve_generate(spldat *sd, int spc) -{ - int kk, kklo, kkhi; - double xval, yvalx; - - spline1(sd->nap[spc],sd->apx[spc],sd->apy[spc]); // compute curve fitting anchor points - - kklo = 1000 * sd->apx[spc][0] - 30; // xval range = anchor point range - if (kklo < 0) kklo = 0; // + 0.03 extra below/above v.9.5 - kkhi = 1000 * sd->apx[spc][sd->nap[spc]-1] + 30; - if (kkhi > 1000) kkhi = 1000; - - for (kk = 0; kk < 1000; kk++) // generate all points for curve - { - xval = 0.001 * kk; // remove anchor point limits v.10.9 - yvalx = spline2(xval); - if (yvalx < 0) yvalx = 0; // yval < 0 not allowed, > 1 OK v.9.5 - sd->yval[spc][kk] = yvalx; - } - - return 0; -} - - -// Retrieve curve data using interpolation of saved table of values - -double splcurve_yval(spldat *sd, int spc, double xval) -{ - int ii; - double x1, x2, y1, y2, y3; - - if (xval <= 0) return sd->yval[spc][0]; - if (xval >= 0.999) return sd->yval[spc][999]; - - x2 = 1000.0 * xval; - ii = x2; - x1 = ii; - y1 = sd->yval[spc][ii]; - y2 = sd->yval[spc][ii+1]; - y3 = y1 + (y2 - y1) * (x2 - x1); - return y3; -} - - -// load curve data from a file -// returns 0 if fail (invalid file data), sd not modified -// returns 1 if succcess, sd is initialized from file data - -int splcurve_load(spldat *sd) // v.11.02 -{ - char *pfile; - int nn, ii, jj; - FILE *fid = 0; - int Nspc, vert[10], nap[10]; - double apx[10][50], apy[10][50]; - - zfuncs::F1_help_topic = "curve_edit"; - - pfile = zgetfile1(ZTX("load curve from a file"),"open",saved_curves_dirk); - if (! pfile) return 0; - - fid = fopen(pfile,"r"); - zfree(pfile); - if (! fid) goto fail; - - nn = fscanf(fid,"%d ",&Nspc); // no. of curves - if (nn != 1) goto fail; - if (Nspc < 1 || Nspc > 10) goto fail; - if (Nspc != sd->Nspc) goto fail2; - - for (ii = 0; ii < Nspc; ii++) // loop each curve - { - nn = fscanf(fid,"%d %d ",&vert[ii],&nap[ii]); // vertical flag, no. anchor points - if (nn != 2) goto fail; - if (vert[ii] < 0 || vert[ii] > 1) goto fail; - if (nap[ii] < 2 || nap[ii] > 50) goto fail; - - for (jj = 0; jj < nap[ii]; jj++) // anchor point values - { - nn = fscanf(fid,"%lf/%lf ",&apx[ii][jj],&apy[ii][jj]); - if (nn != 2) goto fail; - if (apx[ii][jj] < 0 || apx[ii][jj] > 1) goto fail; - if (apy[ii][jj] < 0 || apy[ii][jj] > 1) goto fail; - } - } - - fclose(fid); - - sd->Nspc = Nspc; // copy curve data to caller's arg - - for (ii = 0; ii < Nspc; ii++) - { - sd->vert[ii] = vert[ii]; - sd->nap[ii] = nap[ii]; - - for (jj = 0; jj < nap[ii]; jj++) - { - sd->apx[ii][jj] = apx[ii][jj]; - sd->apy[ii][jj] = apy[ii][jj]; - } - } - - for (ii = 0; ii < Nspc; ii++) // generate curve data from anchor points - splcurve_generate(sd,ii); - - if (sd->drawarea) splcurve_draw(0,0,sd); // regen and redraw all curves - - return 1; - -fail: - if (fid) fclose(fid); - zmessageACK(mWin,ZTX("curve file is invalid")); - return 0; - -fail2: - if (fid) fclose(fid); - zmessageACK(mWin,ZTX("curve file has different no. of curves")); - return 0; -} - - -// save curve data to a file - -int splcurve_save(spldat *sd) // v.11.02 -{ - char *pfile, *pp; - int ii, jj; - FILE *fid; - - zfuncs::F1_help_topic = "curve_edit"; - - pp = zgetfile1(ZTX("save curve to a file"),"save",saved_curves_dirk); - if (! pp) return 0; - - pfile = strdupz(pp,8); - zfree(pp); - - pp = strrchr(pfile,'/'); // force .curve extension - if (pp) pp = strrchr(pp,'.'); - if (pp) strcpy(pp,".curve"); - else strcat(pfile,".curve"); - - fid = fopen(pfile,"w"); - zfree(pfile); - if (! fid) return 0; - - fprintf(fid,"%d \n",sd->Nspc); // no. of curves - - for (ii = 0; ii < sd->Nspc; ii++) // loop each curve - { - fprintf(fid,"%d %d \n",sd->vert[ii],sd->nap[ii]); // vertical flag, no. anchor points - for (jj = 0; jj < sd->nap[ii]; jj++) // anchor point values - fprintf(fid,"%.4f/%.4f ",sd->apx[ii][jj],sd->apy[ii][jj]); - fprintf(fid,"\n"); - } - - fclose(fid); - return 0; -} - - -/************************************************************************** - zdialog mouse capture and release -***************************************************************************/ - -void takeMouse(zdialog *zd, CBfunc func, GdkCursor *cursor) // capture mouse for dialog v.11.03 -{ - freeMouse(); - if (zd && zdialog_widget(zd,"mymouse")) - zdialog_stuff(zd,"mymouse",1); // set zdialog radio button on - mouse_zd = zd; - mouseCBfunc = func; - Mcapture = 1; - gdk_window_set_cursor(drWin->window,cursor); // v.11.03 - return; -} - - -void freeMouse() // free mouse for main window v.10.12 -{ - if (mouse_zd && zdialog_widget(mouse_zd,"mymouse")) - zdialog_stuff(mouse_zd,"mymouse",0); // set radio button off - mouse_zd = 0; - mouseCBfunc = 0; - Mcapture = 0; - paint_toparc(2); // remove mouse circle v.11.04 - gdk_window_set_cursor(drWin->window,0); // set normal cursor v.11.03 - return; -} - - -/************************************************************************** - file menu functions -***************************************************************************/ - -// display image gallery (thumbnails) in a separate window - -void m_gallery(GtkWidget *, cchar *) -{ - zfuncs::F1_help_topic = "navigation"; - - if (curr_file) - image_gallery(0,"paint1",curr_file_posn,m_gallery2,mWin); // overlay main window v.10.9 - else { - char *pp = getcwd(command,ccc); // v.11.09 - if (pp) { - image_gallery(pp,"init",0,m_gallery2,mWin); // use current directory v.11.04 - image_gallery(0,"paint1"); - } - curr_file_posn = 0; // v.11.05 - } - - return; -} - - -// clicked thumbnail will call this function - -void m_gallery2(int Nth, int button) -{ - char *file; - - zfuncs::F1_help_topic = "navigation"; // v.11.08 - - if (Nth == -1) return; // gallery window closed - - file = image_gallery(0,"find",Nth); - if (! file) return; - - if (edit_coll_name && button == 3) // right-click, pass to edit collection - { // v.11.11 - edit_coll_popmenu(null,file); - zfree(file); - return; - } - - f_open(file,1,Nth); // clicked file = current file - zfree(file); - - gtk_window_present(MWIN); // bring main window to front v.10.12 - return; -} - - -/**************************************************************************/ - -// start a new parallel instance of fotoxx -// move my window to right half of desktop -// start new instance to open in left half - -void m_clone1(GtkWidget *, cchar *) -{ - GdkScreen *screen; - int ww, hh, err; - - zfuncs::F1_help_topic = "clone"; // v.10.8 - - screen = gdk_screen_get_default(); // get desktop screen size - ww = gdk_screen_get_width(screen); - hh = gdk_screen_get_height(screen); - ww = ww / 2 - 20; - hh = hh - 50; - gdk_window_move_resize(mWin->window,ww+20,10,ww,hh); // move my window to right half - - snprintf(command,ccc,"fotoxx -clone1 -lang %s",zfuncs::zlanguage); // start new instance - if (curr_file) strncatv(command,ccc," \"",curr_file,"\"",null); - strcat(command," &"); - err = system(command); - if (err) printf("error: %s \n",wstrerror(err)); - return; -} - - -// start a new parallel instance of fotoxx -// new window is slightly down and right from old window - -void m_clone2(GtkWidget *, cchar *) // new v.11.07 -{ - int xx, yy, ww, hh, err; - - zfuncs::F1_help_topic = "clone"; - - gtk_window_get_position(MWIN,&xx,&yy); // get window position and size - gtk_window_get_size(MWIN,&ww,&hh); - - snprintf(command,ccc,"fotoxx -clone2 %d %d %d %d -lang %s",xx,yy,ww,hh,zfuncs::zlanguage); - if (curr_file) strncatv(command,ccc," \"",curr_file,"\"",null); - strcat(command," &"); // start new instance and pass - err = system(command); // my window posn and size - if (err) printf("error: %s \n",wstrerror(err)); - return; -} - - -/**************************************************************************/ - -// open file menu function - -void m_open(GtkWidget *, cchar *) -{ - zfuncs::F1_help_topic = "open_image_file"; - f_open(null,1); - return; -} - - -/**************************************************************************/ - -// open drag-drop file - -void m_open_drag(int x, int y, char *file) -{ - zfuncs::F1_help_topic = "open_image_file"; - f_open(file,1); - return; -} - - -/**************************************************************************/ - -// open a new file in a new parallel instance of fotoxx -// new window is slightly down and right from old window - -void m_open_newin(GtkWidget *, cchar *) // new v.11.07 -{ - int xx, yy, ww, hh, err; - char *file; - - zfuncs::F1_help_topic = "open_image_file"; - - file = zgetfile1(ZTX("Open Image File"),"open",curr_file); // dialog to get filespec - if (! file) return; // canceled - if (image_file_type(file) != 2) return; // not a supported image file v.11.05 - - gtk_window_get_position(MWIN,&xx,&yy); // get window position and size - gtk_window_get_size(MWIN,&ww,&hh); - - snprintf(command,ccc,"fotoxx -c2 %d %d %d %d -l %s",xx,yy,ww,hh,zfuncs::zlanguage); - strncatv(command,ccc," \"",file,"\"",null); - strcat(command," &"); // start new instance and pass - err = system(command); // my window posn and size - if (err) printf("error: %s \n",wstrerror(err)); - return; -} - - -/**************************************************************************/ - -// open the previous file opened (not the same as toolbar [prev] button) -// repeated use will cycle back and forth between two most recent files - -void m_previous(GtkWidget *, cchar *) -{ - int ii, jj, err; - - zfuncs::F1_help_topic = "open_previous_file"; - - if (! menulock(1)) return; // v.11.11 - menulock(0); - if (mod_keep()) return; // v.11.06 - - if (curr_file) jj = 1; // 2nd most recent file v.11.08 - else jj = 0; // no current file, use most recent - - for (ii = jj; ii < Nrecentfiles; ii++) - { - err = f_open(recentfiles[ii],1); // get first one that is still there - if (! err) return; - } - - return; -} - - -/**************************************************************************/ - -// open an image file from the list of recent image files - -void m_recent(GtkWidget *, cchar *) // overhauled v.11.01 -{ - void recentfile2(int Nth, int button); - - int ii, jj, typ; - FILE *fid; - - zfuncs::F1_help_topic = "open_recent_file"; - - if (! menulock(1)) return; - menulock(0); - if (mod_keep()) return; // v.11.11 - - fid = fopen(recentfiles_file,"w"); // revalidate list of recent files - if (! fid) return; // and update disk file - - for (ii = jj = 0; ii < Nrecentfiles; ii++) - { - if (! recentfiles[ii]) continue; // improved v.11.11 - typ = image_file_type(recentfiles[ii]); - if (typ != 2) { - zfree(recentfiles[ii]); - recentfiles[ii] = 0; - continue; - } - if (jj < ii) { - recentfiles[jj] = recentfiles[ii]; - recentfiles[ii] = 0; // bugfix v.11.11.1 - } - fprintf(fid,"%s \n",recentfiles[jj]); - jj++; - } - - fclose(fid); - - if (! jj) return; // no files found - - image_gallery(recentfiles_file,"initF",0,recentfile2,mWin); // generate gallery of recent files - image_gallery(0,"paint1",0); // show new image gallery window - - return; -} - - -// clicked thumbnail will call this function - -void recentfile2(int Nth, int button) -{ - char *file; - - if (Nth == -1) { // gallery window cancelled - if (curr_file) image_gallery(curr_file,"init"); // reset gallery from current file v.11.05 - return; - } - - file = image_gallery(0,"find",Nth); - if (! file) return; - image_gallery(file,"init"); // initz. gallery from chosen file v.11.05 - image_gallery(0,"close"); // close the gallery - f_open(file,1); // open the file - zfree(file); - return; -} - - -/**************************************************************************/ - -// add a file to the list of recent files - -void add_recent_file(cchar *file) -{ - int ii; - - for (ii = 0; ii < Nrecentfiles-1 && recentfiles[ii]; ii++) // find file in recent list - if (strEqu(file,recentfiles[ii])) break; // (or find last entry in list) - if (recentfiles[ii]) zfree(recentfiles[ii]); // free this slot in list - for (; ii > 0; ii--) recentfiles[ii] = recentfiles[ii-1]; // move list UP to fill hole - recentfiles[0] = strdupz(file); // current file >> first in list - return; -} - - -/**************************************************************************/ - -// Open a file and initialize PXM bitmap. -// If flock and menu is locked, do nothing and return. -// Otherwise open the file and display in main window. -// If Nth matches the file position in current file set, curr_file_posn -// will be set to Nth, otherwise it is searched and set correctly -// (a file can be present multiple times in a collection set). -// If fkeepundo is ON, the edit undo image stack is not purged: current -// edits are kept after opening the new file (used by m_saveas()). -// Returns: 0 = OK, +N = error. - -int f_open(cchar *filespec, int flock, int Nth, int fkeepundo) -{ - PXM *temp8; - int err, cc, yn, fposn, nfiles, nimages; - char *pp, *file, *rawfile, titlebar[250]; - char fname[100], fdirk[100]; - cchar *discard = ZTX("Discard special gallery list? \n %s"); - - int Gtype = image_navi::gallerytype; - char *Gname = image_navi::galleryname; - int Grf = 0; - int Gnew = 0; - - if (Gname) Grf = strEqu(Gname,recentfiles_file); // flag, gallery is recent files list - - if (flock && Fmenulock) { - zmessageACK(mWin,ZTX("prior function still active")); // v.11.06 - return 1; - } - - if (mod_keep()) return 2; // unsaved edits - - if (filespec) - file = strdupz(filespec,0,"f_open"); // use passed filespec - else { - if (Gtype == 2 && ! Grf) { // if named collection or search results, - yn = zmessageYN(mWin,discard,image_navi::galleryname); // warn user, gallery will be discarded - if (! yn) return 6; // do not discard v.11.09 - Gnew = 1; // flag, new gallery needed - } - file = zgetfile1(ZTX("Open Image File"),"open",curr_file); // dialog to get filespec - if (! file) return 3; // canceled - } - - if (image_file_type(file) != 2) // not a supported image file type - { - pp = strrchr(file,'.'); - if (! pp || strlen(pp) != 4 || ! strcasestr(RAWfiles,pp)) { // check if a RAW file extension - zfree(file); // v.11.09 - return 3; // no - } - - rawfile = file; // v.11.09 - file = strdupz(rawfile,5,"f_open"); // filename.raw >> filename.tiff - pp = file + (pp - rawfile); - strcpy(pp,".tiff"); - snprintf(command,ccc,"ufraw-batch --wb=camera --out-type=tiff " // convert RAW file to tiff-16 v.11.09 - "--out-depth=16 --overwrite " - "--output=\"%s\" \"%s\" ",file,rawfile); - err = system(command); - if (err) { - zmessageACK(mWin,wstrerror(err)); // failed, clean up - zfree(file); - zfree(rawfile); - return 3; - } - zfree(rawfile); // tiff file will be opened - } - - temp8 = f_load(file,8); // load image as PXM-8 pixmap - if (! temp8) { - zfree(file); // bad image - return 5; - } - // menulock() removed v.11.11 - - free_resources(fkeepundo); // free resources for old image file - - if (curr_file) zfree(curr_file); // current image filespec - curr_file = strdupz(file,8,"curr_file"); - zfree(file); - - if (curr_dirk) zfree(curr_dirk); // set current directory - curr_dirk = strdupz(curr_file,0,"curr_dirk"); // for new current file - pp = strrchr(curr_dirk,'/'); - *pp = 0; - err = chdir(curr_dirk); - - Fpxm8 = temp8; // pixmap for current image - Fww = Fpxm8->ww; - Fhh = Fpxm8->hh; - - strcpy(curr_file_type,f_load_type); // set curr_file_xxx from f_load_xxx - curr_file_bpc = f_load_bpc; - curr_file_size = f_load_size; - - fposn = image_gallery_position(curr_file,Nth); // file position in gallery list - if (fposn < 0 || Gnew) { // not there or break current gallery v.11.09 - image_gallery(curr_file,"init"); // generate new gallery list - fposn = image_gallery_position(curr_file,0); // position and count in gallery list - image_gallery(0,"paint2",fposn); // refresh gallery window if active v.11.07 - } - - nfiles = image_navi::nfiles; // total gallery files (incl. directories) - nimages = image_navi::nimages; // total image files v.11.05 - - curr_file_posn = fposn; // keep track of file position - curr_file_count = image_navi::nimages; // and image gallery count - - add_recent_file(curr_file); // first in recent files list ///////// - - Fzoom = 0; // zoom level = fit window - zoomx = zoomy = 0; // no zoom center - - pp = (char *) strrchr(curr_file,'/'); - strncpy0(fname,pp+1,99); // file name ////// - cc = pp - curr_file; - if (cc < 99) strncpy0(fdirk,curr_file,cc+2); // get dirk/path/ if short enough - else { - strncpy(fdirk,curr_file,96); // or use /dirk/path... - strcpy(fdirk+95,"..."); - } - - fposn = fposn + 1 - nfiles + nimages; // position among images, 1-based - snprintf(titlebar,250,"%s %d/%d %s %s", // window title bar - fversion,fposn,curr_file_count,fname,fdirk); - gtk_window_set_title(MWIN,titlebar); - - mwpaint1(); // immediate paint v.11.11 - gtk_window_present(MWIN); // bring main window to front v.11.04 - zmainloop(); - - if (zdrename) m_rename(0,0); // update active rename dialog - if (zdexifview) info_view(0); // " EXIF/IPTC view window v.10.2 - if (zdexifedit) m_info_edit(0,0); // " EXIF/IPTC edit window v.10.11 - if (zdedittags) m_edit_tags(0,0); // " edit tags dialog - if (zdeditcctext) m_edit_cctext(0,0); // " edit comments dialog v.10.10 - - curr_image_time = get_seconds(); // mark time of file load v.11.07 - - return 0; -} - - -/**************************************************************************/ - -// open previous or next file in current gallery list - -void m_prev(GtkWidget *, cchar *menu) -{ - int err, Nth; - - if (menu) zfuncs::F1_help_topic = "open_image_file"; - - if (Fmenulock) return; - if (mod_keep()) return; - if (! curr_file) return; - - for (Nth = curr_file_posn-1; Nth >= 0; Nth--) // v.11.05 - { - char *pp = image_gallery(0,"find",Nth); - if (! pp) continue; - err = f_open(pp,1,Nth); - zfree(pp); - if (! err) break; - } - - return; -} - -void m_next(GtkWidget *, cchar *menu) -{ - int err, Nth; - int nfiles = image_navi::nfiles; - - if (menu) zfuncs::F1_help_topic = "open_image_file"; - - if (Fmenulock) return; - if (mod_keep()) return; - if (! curr_file) return; - - for (Nth = curr_file_posn+1; Nth < nfiles; Nth++) // v.11.05 - { - char *pp = image_gallery(0,"find",Nth); - if (! pp) continue; - err = f_open(pp,1,Nth); - zfree(pp); - if (! err) break; - } - - return; -} - - -/**************************************************************************/ - -// save (modified) image to same file - -void m_save(GtkWidget *, cchar *menu) -{ - int Fwarn = 1, zstat, suppress; - char *pp; - zdialog *zd; - cchar *warn_message = ZTX("Overwrite original file?"); - cchar *suppress_message = ZTX("Do not warn again"); - - if (! curr_file) return; - if (is_syncbusy()) return; // v.11.11 - - if (menu && strNeq(menu,"nowarn")) // don't change help topic v.11.11 - zfuncs::F1_help_topic = "save_file"; - - if (Fwarnoverwrite) { // warn if overwrite original v.11.10 - pp = strrchr(curr_file,'/'); - if (! pp) return; - pp = strstr(pp,".v"); // look for version notation .vNN - if (pp && pp[2] >= '0' && pp[2] <= '9' - && pp[3] >= '0' && pp[3] <= '9') Fwarn = 0; // found, file not original - - if (Fwarn && ! (menu && strEqu(menu,"nowarn"))) { // no warn if KB rotate save v.11.11 - zd = zdialog_new(ZTX("Warning"),mWin,Bproceed,Bcancel,null); - zdialog_add_widget(zd,"label","lab1","dialog",warn_message,"space=5"); - zdialog_add_widget(zd,"check","suppress","dialog",suppress_message,"space=5"); - zdialog_run(zd); - zstat = zdialog_wait(zd); - zdialog_fetch(zd,"suppress",suppress); - zdialog_free(zd); - if (suppress) { - Fwarnoverwrite = 0; - save_params(); - } - if (zstat != 1) return; - } - } - - strcpy(jpeg_quality,def_jpeg_quality); // default jpeg save quality - - if (strEqu(curr_file_type,"other")) // if gif, bmp, etc. use jpg v.11.03 - strcpy(curr_file_type,"jpg"); - - f_save(curr_file,curr_file_type,curr_file_bpc); // save file - - strcpy(curr_file_type,f_save_type); // update curr_file_xxx from f_save_xxx - curr_file_size = f_save_size; - - return; -} - - -/**************************************************************************/ - -// save (modified) image to new version of same file -// - no confirmation of overwrite. - -void m_savevers(GtkWidget *, cchar *) // new v.11.07 -{ - char *outfile, *pext, *pvers; - cchar *delim; - int ii, err, nvers; - struct stat fstat; - - if (! curr_file) return; - if (is_syncbusy()) return; // v.11.11 - - zfuncs::F1_help_topic = "save_file"; - - strcpy(jpeg_quality,def_jpeg_quality); // default jpeg save quality - - outfile = strdupz(curr_file,12,"curr_file"); // output file name TBD - - pext = strrchr(outfile,'/'); // find file .ext - if (pext) pext = strrchr(pext,'.'); - if (pext && strlen(pext) > 5) pext = 0; - if (! pext) pext = outfile + strlen(outfile); // unknown, none - - pvers = pext - 4; // find curr. version: filename.vNN.ext - if (! strnEqu(pvers,".v",2)) nvers = 0; - else { - err = convSI(pvers+2,nvers,1,98,&delim); // convert NN to number 1-98 - if (err > 1) nvers = 0; // conversion error - if (delim != pext) nvers = 0; // check format is .vNN - } - if (nvers == 0) { // no version in file name - pvers = pext; - pext += 4; - memmove(pext,pvers,6); // make space for .vNN before .ext - strncpy(pvers,".vNN",4); - } - - for (ii = 98; ii > nvers; ii--) // look for higher file versions - { - pvers[2] = ii/10 + '0'; // build filename.vNN.ext - pvers[3] = ii - 10 * (ii/10) + '0'; - err = stat(outfile,&fstat); - if (! err) break; - } - - ii++; // use next version 1-99 - nvers = ii; - pvers[2] = ii/10 + '0'; // build filename.vNN.ext - pvers[3] = ii - 10 * (ii/10) + '0'; - - f_save(outfile,curr_file_type,curr_file_bpc); // save file (fails at 99 versions) - - load_fileinfo(outfile); // update search index file - update_search_index(outfile); - - image_gallery(outfile,"init"); // update gallery - image_gallery(outfile,"paint2",-1); // refresh gallery window if active - - f_open(outfile,1,0,1); // new version = current file v.11.11.1 - - zfree(outfile); - return; -} - - -/**************************************************************************/ - -// save (modified) image to new file -// confirm if overwrite existing file - -GtkWidget *saveas_fchooser; - -void m_saveas(GtkWidget *, cchar *menu) -{ - void saveas_radiobutt(void *, int button); - void saveas_kbkey(void *, GdkEventKey *event); - - GtkWidget *fdialog, *hbox; - GtkWidget *tiff8, *tiff16, *jpeg, *png, *jqlab, *jqval; - GtkWidget *makecurrent; - char *outfile = 0, *outfile2 = 0, *pext; - int ii, err, yn, bpc, status, mkcurr = 0; - struct stat fstat; - cchar *type; - cchar *exts = ".jpg.JPG.jpeg.JPEG.tif.TIF.tiff.TIFF.png.PNG"; - - if (! curr_file) return; - if (is_syncbusy()) return; // v.11.11 - - if (menu) zfuncs::F1_help_topic = "save_file"; - - fdialog = gtk_dialog_new_with_buttons(ZTX("Save File"), // build file save dialog - MWIN, GTK_DIALOG_MODAL, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, null); - gtk_window_set_default_size(GTK_WINDOW(fdialog),600,500); - - saveas_fchooser = gtk_file_chooser_widget_new(GTK_FILE_CHOOSER_ACTION_SAVE); - gtk_container_add(GTK_CONTAINER(GTK_DIALOG(fdialog)->vbox),saveas_fchooser); - - // set_filename() should select the file but does nothing GTK bug ? v.10.9.1 ///// - // set_current_name() puts file name in input box, but does not select the file - gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(saveas_fchooser),curr_file); - char *fname = strrchr(curr_file,'/') + 1; - gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(saveas_fchooser),fname); - - hbox = gtk_hbox_new(0,0); - gtk_container_add(GTK_CONTAINER(GTK_DIALOG(fdialog)->vbox),hbox); - gtk_box_set_child_packing(GTK_BOX(GTK_DIALOG(fdialog)->vbox),hbox,0,0,10,GTK_PACK_END); - - tiff8 = gtk_radio_button_new_with_label(null,"tiff-8"); - tiff16 = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(tiff8),"tiff-16"); - png = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(tiff8),"png"); - jpeg = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(tiff8),"jpeg"); - jqlab = gtk_label_new(ZTX("quality")); - jqval = gtk_entry_new(); - makecurrent = gtk_check_button_new_with_label(ZTX("make current")); - - gtk_entry_set_width_chars(GTK_ENTRY(jqval),2); - gtk_box_pack_start(GTK_BOX(hbox),tiff8,0,0,5); // (o) tiff8 (o) tiff16 (o) png - gtk_box_pack_start(GTK_BOX(hbox),tiff16,0,0,5); - gtk_box_pack_start(GTK_BOX(hbox),png,0,0,5); - gtk_box_pack_start(GTK_BOX(hbox),jpeg,0,0,5); // (o) jpeg jpeg quality [__] - gtk_box_pack_start(GTK_BOX(hbox),jqlab,0,0,0); - gtk_box_pack_start(GTK_BOX(hbox),jqval,0,0,3); - gtk_box_pack_end(GTK_BOX(hbox),makecurrent,0,0,3); // [x] make current - - G_SIGNAL(tiff8,"pressed",saveas_radiobutt,0) // connect file type radio buttons - G_SIGNAL(tiff16,"pressed",saveas_radiobutt,1) // to handler function - G_SIGNAL(png,"pressed",saveas_radiobutt,2) - G_SIGNAL(jpeg,"pressed",saveas_radiobutt,3) - G_SIGNAL(fdialog,"key-release-event",saveas_kbkey,0) - - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(jpeg),1); // set default file type = jpeg - gtk_entry_set_text(GTK_ENTRY(jqval),def_jpeg_quality); // default jpeg save quality - - if (strEqu(curr_file_type,"png")) // default matches file type - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(png),1); // if png or tiff - if (strEqu(curr_file_type,"tiff")) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tiff8),1); - if (curr_file_bpc == 16) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tiff16),1); - -dialog_run: - - gtk_widget_show_all(fdialog); // run dialog - - status = gtk_dialog_run(GTK_DIALOG(fdialog)); - if (status != GTK_RESPONSE_ACCEPT) { // user cancelled - gtk_widget_destroy(fdialog); - return; - } - - outfile2 = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(saveas_fchooser)); - if (! outfile2) goto dialog_run; - outfile = strdupz(outfile2,12,"curr_file"); // add space for possible .vNN and .ext - g_free(outfile2); - - type = "jpg"; // default output type - bpc = 8; - - if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(png))) - type = "png"; - if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(tiff8))) - type = "tif"; - if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(tiff16))) { - type = "tif"; - bpc = 16; - } - - if (strEqu(type,"jpg")) { // set jpeg save quality - ii = atoi(gtk_entry_get_text(GTK_ENTRY(jqval))); - if (ii < 1 || ii > 100) { - zmessageACK(mWin,ZTX("jpeg quality must be 1-100")); - goto dialog_run; - } - sprintf(jpeg_quality,"%d",ii); - } - - pext = strrchr(outfile,'/'); // locate file .ext - if (pext) pext = strrchr(pext,'.'); - if (pext && ! strstr(exts,pext)) pext = 0; // keep .ext and append new v.10.12.1 - if (! pext) { - pext = outfile + strlen(outfile); // missing, add one - strcpy(pext,"."); - strcpy(pext+1,type); - } - - if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(makecurrent))) // make saved file the current file? - mkcurr = 1; - - gtk_widget_destroy(fdialog); // kill dialog /// gtk bug, can crash - - err = stat(outfile,&fstat); // check if file exists - if (! err) { - yn = zmessageYN(mWin,ZTX("Overwrite file? \n %s"),outfile); // confirm overwrite - if (! yn) { - zfree(outfile); - return; - } - } - - f_save(outfile,type,bpc); // save the file - - load_fileinfo(outfile); // update search index file v.11.07 - update_search_index(outfile); - - if (mkcurr) // use the saved file as new current file - f_open(outfile,1,0,1); // and retain edit history v.11.07 - else if (samedirk(outfile,curr_file)) { // if same directory, update gallery - image_gallery(outfile,"init"); // add new file to gallery - image_gallery(0,"paint2",curr_file_posn); // refresh if active, keep position - } - - zfree(outfile); - return; -} - - -// set dialog file type from user selection of file type radio button - -void saveas_radiobutt(void *, int button) // v.9.4 -{ - cchar *filetypes[4] = { ".tif", ".tif", ".png", ".jpg" }; // v.10.9 - char *filespec; - char *filename, *pp; - - filespec = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(saveas_fchooser)); - if (! filespec) return; - filename = strrchr(filespec,'/'); - if (! filename) return; - filename = strdupz(filename+1,6,"saveas"); - pp = strrchr(filename,'.'); - if (! pp || strlen(pp) > 5) pp = filename + strlen(filename); // bugfix v.10.9.1 - strcpy(pp,filetypes[button]); - gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(saveas_fchooser),filename); - gtk_widget_show_all(saveas_fchooser); - zfree(filename); - g_free(filespec); // bugfix, leak v.10.9.1 - return; -} - - -// response function for KB key release - -void saveas_kbkey(void *, GdkEventKey *event) // v.10.5 -{ - if (event->keyval == GDK_F1) - showz_userguide(zfuncs::F1_help_topic); - return; -} - - -// set new image zoom level or magnification - -void m_zoom(GtkWidget *, cchar *menu) -{ - int ii, iww, ihh, Dww, Dhh; - char zoom; - double scalew, scaleh, fitscale; - double scales[11] = { 0.125, 0.176, 0.25, 0.354, 0.5, 0.71, 1.0, 1.41, 2.0, 2.83, 4.0 }; - - if (strnEqu(menu,"Zoom",4)) zoom = menu[4]; // get + or - - else zoom = *menu; - - Dww = drWin->allocation.width; // drawing window size - Dhh = drWin->allocation.height; - - if (E3pxm16) { // bugfix - iww = E3ww; - ihh = E3hh; - } - else { - iww = Fww; - ihh = Fhh; - } - - if (iww > Dww || ihh > Dhh) { // get window fit scale - scalew = 1.0 * Dww / iww; - scaleh = 1.0 * Dhh / ihh; - if (scalew < scaleh) fitscale = scalew; - else fitscale = scaleh; - } - else fitscale = 1.0; // if image < window use 100% - - if (zoom == '+') { // zoom bigger - if (! Fzoom) Fzoom = fitscale / 1.2; - Fzoom = Fzoom * sqrt(2.0); // new scale: 41% bigger - for (ii = 0; ii < 11; ii++) - if (Fzoom < 1.01 * scales[ii]) break; // next higher scale in table - if (ii == 11) ii = 10; - Fzoom = scales[ii]; - if (Fzoom < fitscale) Fzoom = 0; // image < window - } - - if (zoom == '-') Fzoom = 0; // zoom to fit window - - if (zoom == 'Z') { - if (Fzoom != 0) Fzoom = 0; // toggle 100% and fit window - else Fzoom = 1; - } - - if (! Fzoom) zoomx = zoomy = 0; // no req. zoom center - - mwpaint2(); // refresh window - curr_image_time = get_seconds(); // mark time of image change v.11.07 - return; -} - - -/**************************************************************************/ - -// create a new blank image with desired background color - -void m_create(GtkWidget *, cchar *) // v.11.01 -{ - int create_dialog_event(zdialog *zd, cchar *event); - - zdialog *zd; - int zstat; - char *prev_file = 0; - - zfuncs::F1_help_topic = "create"; - - if (is_syncbusy()) return; // v.11.11 - if (mod_keep()) return; // unsaved edits - if (! menulock(1)) return; // lock menus - - if (curr_file) prev_file = strdupz(curr_file); - -// file name [___________________________] .jpg // v.11.05 -// width [____] height [____] (pixels) -// color [____] - - zd = zdialog_new(ZTX("Create Blank Image"),mWin,Bdone,Bcancel,null); - zdialog_add_widget(zd,"hbox","hbf","dialog",0,"space=5"); - zdialog_add_widget(zd,"label","labf","hbf",ZTX("file name"),"space=3"); - zdialog_add_widget(zd,"entry","file","hbf","no-name","space=3|expand"); - zdialog_add_widget(zd,"label","ftype","hbf",".jpg "); - zdialog_add_widget(zd,"hbox","hbz","dialog",0,"space=5"); - zdialog_add_widget(zd,"label","space","hbz",0,"space=3"); - zdialog_add_widget(zd,"label","labw","hbz",ZTX("width")); - zdialog_add_widget(zd,"spin","width","hbz","100|9999|1|1600"); - zdialog_add_widget(zd,"label","space","hbz",0,"space=5"); - zdialog_add_widget(zd,"label","labh","hbz",ZTX("height")); - zdialog_add_widget(zd,"spin","height","hbz","100|9999|1|1000"); - zdialog_add_widget(zd,"label","space","hbz",0,"space=3"); - zdialog_add_widget(zd,"label","labp","hbz","(pixels) "); - zdialog_add_widget(zd,"hbox","hbc","dialog",0,"space=5"); - zdialog_add_widget(zd,"label","space","hbc",0,"space=3"); - zdialog_add_widget(zd,"label","labc","hbc",ZTX("color")); - zdialog_add_widget(zd,"colorbutt","color","hbc","200|200|200"); - - create_dialog_event(zd,"init"); - - zdialog_help(zd,"create"); // zdialog help topic v.11.08 - zdialog_run(zd,create_dialog_event); - zstat = zdialog_wait(zd); - zdialog_free(zd); - - if (zstat != 1) { // cancel - if (prev_file) { - f_open(prev_file,0); // back to previous file - zfree(prev_file); - mwpaint2(); - } - } - - menulock(0); - return; -} - - -// dialog event and completion function - -int create_dialog_event(zdialog *zd, cchar *event) // overhauled v.11.05 -{ - char color[20], fname[100], *filespec; - cchar *pp; - int fncc, ww, hh, err; - static int red, green, blue; - uint8 *pixel; - struct stat statb; - - if (zd->zstat != 1) return 0; // [done] - - zdialog_fetch(zd,"file",fname,100); // get new file name - strTrim2(fname); - if (*fname <= ' ') strcpy(fname,"no-name"); - fncc = strlen(fname); - - filespec = strdupz(curr_dirk,fncc+8,"create"); // make full filespec - strcat(filespec,"/"); - strcat(filespec,fname); - strcat(filespec,".jpg"); - - err = stat(filespec,&statb); // make sure it does not exist - if (! err) { - zmessageACK(mWin,"file already exists"); - zfree(filespec); - zd->zstat = 0; // keep dialog alive - return 0; - } - - if (curr_file) zfree(curr_file); // stop copy of metadata from old file - curr_file = 0; // bugfix v.11.08 - - zdialog_fetch(zd,"width",ww); // get image dimensions - zdialog_fetch(zd,"height",hh); - - zdialog_fetch(zd,"color",color,19); // get image color - pp = strField(color,"|",1); - if (pp) red = atoi(pp); - pp = strField(color,"|",2); - if (pp) green = atoi(pp); - pp = strField(color,"|",3); - if (pp) blue = atoi(pp); - - mutex_lock(&Fpixmap_lock); // lock pixmaps - - PXM_free(Fpxm8); // create new PXM image - Fpxm8 = PXM_make(ww,hh,8); - Fww = Fpxm8->ww; - Fhh = Fpxm8->hh; - pixel = (uint8 *) Fpxm8->bmp; - - for (int ii = 0; ii < ww * hh * 3; ii += 3) { - pixel[ii] = red; - pixel[ii+1] = green; - pixel[ii+2] = blue; - } - - mutex_unlock(&Fpixmap_lock); - - strcpy(jpeg_quality,def_jpeg_quality); - - err = f_save(filespec,"jpg",8); // save to disk - if (err) { - zmessageACK(mWin,"cannot save file"); - zfree(filespec); - return 0; - } - - f_open(filespec,0); // make it the current file - zfree(filespec); - - return 0; -} - - -/**************************************************************************/ - -// Delete image file - move curr_file to trash. -// Use new Linux standard trash function. // v.10.8 -// If not available, revert to Desktop folder for fotoxx trash. - -void m_trash(GtkWidget *, cchar *) -{ - int err, yn; - char *pp, trashdir[200]; - struct stat trstat; - static int gstat, trashworks = 1; // assume it works until otherwise - GError *gerror = 0; - GFile *gfile = 0; - cchar *gerrmess = ZTX("Linux standard trash is not supported. \n" - "Desktop trash folder will be created."); - - zfuncs::F1_help_topic = "trash"; // v.10.8 - - if (! curr_file) return; // nothing to trash - - if (is_syncbusy()) return; // v.11.11 - if (! menulock(1)) return; // check lock but leave unlocked - menulock(0); - - err = stat(curr_file,&trstat); // get file status - if (err) { - zmessLogACK(mWin,strerror(errno)); - return; - } - - if (! (trstat.st_mode & S_IWUSR)) { // check permission - yn = zmessageYN(mWin,ZTX("Move read-only file to trash?")); - if (! yn) return; - trstat.st_mode |= S_IWUSR; - chmod(curr_file,trstat.st_mode); - } - - if (trashworks) // try Linux standard trash - { - gfile = g_file_new_for_path(curr_file); - gstat = g_file_trash(gfile,0,&gerror); - if (! gstat) { - printf("g_file_trash() error: %s \n",gerror->message); - zmessageACK(mWin,gerrmess); - trashworks = 0; // did not work - } - } - - if (! trashworks) - { - snprintf(trashdir,199,"%s/%s",getenv("HOME"),ftrash); // use fotoxx trash filespec - - trstat.st_mode = 0; - err = stat(trashdir,&trstat); - if (! S_ISDIR(trstat.st_mode)) { - err = mkdir(trashdir,0750); // v.11.03 - if (err) { - zmessLogACK(mWin,ZTX("Cannot create trash folder: %s"),wstrerror(err)); - return; - } - } - - snprintf(command,ccc,"cp \"%s\" \"%s\" ",curr_file,trashdir); // copy image file to trash - err = system(command); - if (err) { - zmessLogACK(mWin,ZTX("error: %s"),wstrerror(err)); - return; - } - - err = remove(curr_file); // remove original file v.11.03 - if (err) { - zmessLogACK(mWin,ZTX("error: %s"),wstrerror(err)); - return; - } - } - - delete_search_index(curr_file); // delete in search index file - image_gallery(0,"delete",curr_file_posn); // delete in gallery list - pp = image_gallery(0,"find",curr_file_posn); // open next file (now current position) - if (pp) f_open(pp,1); // v.11.05 - if (pp) zfree(pp); - image_gallery(0,"paint2",curr_file_posn); // refresh gallery window if active v.11.07 - - return; -} - - -/**************************************************************************/ - -// rename menu function -// activate rename dialog, stuff data from current file -// dialog remains active when new file is opened - -char rename_old[100] = ""; -char rename_new[100] = ""; - -void m_rename(GtkWidget *, cchar *menu) -{ - int rename_dialog_event(zdialog *zd, cchar *event); - - char *pdir, *pfile, *pext; - - if (menu) zfuncs::F1_help_topic = "rename"; - - if (! curr_file) return; - if (is_syncbusy()) return; // v.11.11 - - if (! zdrename) // restart dialog - { - zdrename = zdialog_new(ZTX("Rename Image File"),mWin,Bcancel,null); - zdialog_add_widget(zdrename,"hbox","hb1","dialog",0,"space=10"); - zdialog_add_widget(zdrename,"vbox","vb1","hb1",0,"homog|space=5"); - zdialog_add_widget(zdrename,"vbox","vb2","hb1",0,"homog|expand"); - - zdialog_add_widget(zdrename,"button","Bold","vb1",ZTX("old name")); - zdialog_add_widget(zdrename,"button","Bnew","vb1",ZTX("rename to")); - zdialog_add_widget(zdrename,"button","Bprev","vb1",ZTX("previous")); - - zdialog_add_widget(zdrename,"hbox","hb21","vb2",0); // [ old name ] [ oldname ] - zdialog_add_widget(zdrename,"hbox","hb22","vb2",0); // [ new name ] [ newname ] [+1] - zdialog_add_widget(zdrename,"hbox","hb23","vb2",0); // [ previous ] [ prevname ] - - zdialog_add_widget(zdrename,"label","Lold","hb21"); - zdialog_add_widget(zdrename,"entry","Enew","hb22",0,"expand|scc=30"); - zdialog_add_widget(zdrename,"button","B+1","hb22"," +1 ","space=5"); - zdialog_add_widget(zdrename,"label","Lprev","hb23"); - - zdialog_help(zdrename,"rename"); // zdialog help topic v.11.08 - zdialog_run(zdrename,rename_dialog_event); // run dialog - } - - parsefile(curr_file,&pdir,&pfile,&pext); - strncpy0(rename_old,pfile,99); - strncpy0(rename_new,pfile,99); - zdialog_stuff(zdrename,"Lold",rename_old); // current file name - zdialog_stuff(zdrename,"Enew",rename_new); // entered file name - - return; -} - - -// dialog event and completion callback function - -int rename_dialog_event(zdialog *zd, cchar *event) -{ - char *pp, *pdir, *pfile, *pext, *pnew, *pold; - int nseq, digits, ccp, ccn, ccx, err; - struct stat statb; - - if (zd->zstat) { // complete - zdialog_free(zdrename); // kill dialog - return 0; - } - - if (strEqu(event,"Bold")) // reset to current file name - zdialog_stuff(zd,"Enew",rename_old); - - if (strEqu(event,"Bprev")) { // previous name >> new name - zdialog_fetch(zd,"Lprev",rename_new,99); - zdialog_stuff(zd,"Enew",rename_new); - } - - if (strEqu(event,"B+1")) // increment sequence number - { - zdialog_fetch(zd,"Enew",rename_new,94); // get entered filename - pp = rename_new + strlen(rename_new); - digits = 0; - while (pp[-1] >= '0' && pp[-1] <= '9') { - pp--; // look for NNN in filenameNNN - digits++; - } - nseq = 1 + atoi(pp); // NNN + 1 - if (nseq > 9999) nseq = 0; - if (digits < 2) digits = 2; // keep digit count if enough - if (nseq > 99 && digits < 3) digits = 3; // use leading zeros - if (nseq > 999 && digits < 4) digits = 4; - snprintf(pp,digits+1,"%0*d",digits,nseq); - zdialog_stuff(zd,"Enew",rename_new); - } - - if (strEqu(event,"Bnew")) // [rename to] button - { - if (is_syncbusy()) return 0; // v.11.11 - if (! menulock(1)) return 0; // check lock but leave unlocked - menulock(0); - - parsefile(curr_file,&pdir,&pfile,&pext); // existing /directories/file.ext - - zdialog_fetch(zd,"Enew",rename_new,94); // new file name from user - - ccp = strlen(pdir); // length of /directories/ - ccn = strlen(rename_new); // length of file - if (pext) ccx = strlen(pext); // length of .ext - else ccx = 0; - - pnew = zmalloc(ccp + ccn + ccx + 1,"rename"); // put it all together - strncpy(pnew,curr_file,ccp); // /directories/file.ext - strcpy(pnew+ccp,rename_new); - if (ccx) strcpy(pnew+ccp+ccn,pext); - - err = stat(pnew,&statb); // check if new name exists - if (! err) { - zmessageACK(mWin,ZTX("The target file already exists")); - zfree(pnew); - return 0; - } - - snprintf(command,ccc,"cp -p \"%s\" \"%s\"",curr_file,pnew); // copy to new file -p v.10.3 - err = system(command); - if (err) { - zmessageACK(mWin,ZTX("Rename failed: \n %s"),wstrerror(err)); - printf("command: %s \n",command); - zfree(pnew); - return 0; - } - - zdialog_stuff(zd,"Lprev",rename_new); // set previous name in dialog - - load_fileinfo(pnew); // update search index file - update_search_index(pnew); - - pold = strdupz(curr_file,0,"curr_file"); // save file name to be deleted - delete_search_index(pold); // delete in search index v.9.7 - err = remove(pold); // delete file v.11.03 - - err = f_open(pnew,1); // no automatic "next" v.11.08 - image_gallery(curr_file,"init"); // update gallery v.11.05 - image_gallery(0,"paint2",curr_file_posn); // refresh gallery window if active - - zfree(pnew); - zfree(pold); - } - - return 0; -} - - -/**************************************************************************/ - -// menu function - batch rename files - -char **batchrename_filelist = 0; -int batchrename_filecount = 0; - -void m_batchrename(GtkWidget *, cchar *) // new v.9.7 -{ - int batchrename_dialog_event(zdialog *zd, cchar *event); - - zdialog *zd; - - if (zdrename) return; // interactive rename is active - - if (is_syncbusy()) return; // v.11.11 - if (mod_keep()) return; // unsaved edits - if (! menulock(1)) return; // lock menus v.10.8 - - zfuncs::F1_help_topic = "batch_rename"; // v.10.8 - - zd = zdialog_new(ZTX("Batch Rename"),mWin,Bproceed,Bcancel,null); - zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=5"); - zdialog_add_widget(zd,"button","files","hb1",Bselectfiles,"space=10"); - zdialog_add_widget(zd,"label","labcount","hb1",ZTX("%d files selected"),"space=10"); - zdialog_add_widget(zd,"hbox","hb2","dialog","space=5"); - zdialog_add_widget(zd,"label","lab2","hb2",ZTX("new base name"),"space=10"); - zdialog_add_widget(zd,"entry","basename","hb2"); - zdialog_add_widget(zd,"hbox","hb3","dialog",0,"space=5"); - zdialog_add_widget(zd,"label","lab31","hb3",ZTX("starting sequence"),"space=10"); - zdialog_add_widget(zd,"entry","sequence","hb3","100","scc=5"); - zdialog_add_widget(zd,"label","lab32","hb3",ZTX("increment"),"space=10"); - zdialog_add_widget(zd,"entry","increment","hb3","01","scc=3"); - - batchrename_filelist = 0; - batchrename_filecount = 0; - - zdialog_help(zd,"batch_rename"); // zdialog help topic v.11.08 - zdialog_run(zd,batchrename_dialog_event); // run dialog - zdialog_wait(zd); // wait for completion - - zdialog_free(zd); - menulock(0); - return; -} - - -// dialog event and completion callback function - -int batchrename_dialog_event(zdialog *zd, cchar *event) -{ - char **flist = batchrename_filelist, countmess[50]; - cchar *selectmess = ZTX("select files to rename"); - int ii, err, cc, ccp, ccn, ccx; - int sequence, increment, adder; - char basename[100], filename[120], *oldfile, *newfile; - char *pdir, *pfile, *pext; - cchar *errmess = ZTX("base name / sequence / increment not reasonable"); - struct stat statb; - - if (strEqu(event,"files")) // select images to rename - { - if (flist) { // free prior list - for (ii = 0; flist[ii]; ii++) - zfree(flist[ii]); - zfree(flist); - } - - flist = zgetfileN(selectmess,"openN",curr_file); // get file list from user - batchrename_filelist = flist; - - if (flist) // count files in list - for (ii = 0; flist[ii]; ii++); - else ii = 0; - batchrename_filecount = ii; - - snprintf(countmess,50,ZTX("%d files selected"),batchrename_filecount); - zdialog_stuff(zd,"labcount",countmess); - } - - if (! zd->zstat) return 0; // dialog active - - if (zd->zstat != 1) goto cleanup; // dialog canceled - if (! batchrename_filecount) goto cleanup; // no files selected - - zdialog_fetch(zd,"basename",basename,99); - zdialog_fetch(zd,"sequence",sequence); - zdialog_fetch(zd,"increment",increment); - - if (strlen(basename) < 1 || sequence < 1 || increment < 1) { - zd->zstat = 0; // keep dialog alive bugfix v.10.7 - zmessageACK(mWin,errmess); - return 0; - } - - write_popup_text("open","Renaming files",500,200,mWin); // status monitor popup window v.10.3 - - for (ii = 0; flist[ii]; ii++) - { - oldfile = flist[ii]; - parsefile(oldfile,&pdir,&pfile,&pext); - ccp = strlen(pdir); - if (pext) ccx = strlen(pext); - else ccx = 0; - - adder = sequence + ii * increment; - snprintf(filename,119,"%s%d",basename,adder); // removed "-" between v.10.7 - ccn = strlen(filename); - - newfile = zmalloc(ccp + ccn + ccx + 1,"rename"); // construct /path/filename.ext - strcpy(newfile,pdir); - strcpy(newfile+ccp,filename); - if (ccx) strcpy(newfile+ccp+ccn,pext); - - err = stat(newfile,&statb); - if (! err) { - snprintf(command,ccc,"%s %s",ZTX("new file already exists:"),newfile); - write_popup_text("write",command); - zfree(newfile); - break; - } - - cc = snprintf(command,ccc,"cp -p \"%s\" \"%s\"",oldfile,newfile); // copy to new file -p v.10.3 - if (cc >= maxfcc*2) { - snprintf(command,ccc,"%s %s",ZTX("filespec too long:"),oldfile); - write_popup_text("write",command); - zfree(newfile); - break; - } - - write_popup_text("write",command); // report progress - zmainloop(); - - err = system(command); - if (err) { - snprintf(command,ccc,"%s %s",ZTX("Rename failed:"),wstrerror(err)); - write_popup_text("write",command); - zfree(newfile); - break; - } - - load_fileinfo(newfile); // update search index file - update_search_index(newfile); - zfree(newfile); - - err = remove(oldfile); // delete old file v.11.03 - delete_search_index(oldfile); // remove from search index - zmainloop(); - } - - write_popup_text("write","COMPLETED"); - write_popup_text("close",0); - - image_gallery(curr_file,"init"); // update gallery file list - image_gallery(0,"paint2",curr_file_posn); // refresh gallery window if active - -cleanup: - - if (batchrename_filecount) { - for (ii = 0; flist[ii]; ii++) - zfree(flist[ii]); - zfree(flist); - } - - return 0; -} - - -/**************************************************************************/ - -// print current image file - -double print_size[2] = { 29.7, 21.0 }; // default A4 landscape -double print_margins[4] = { 0.5, 0.5, 0.5, 0.5 }; // top, bottom, left, right - -void m_print(GtkWidget *, cchar *) // use GTK print v.9.4 -{ - PXM * print_addgrid(PXM *printimage); // v.11.01 - - int err; - char *printfile; - PXM *printimage, *pxmtemp; - - zfuncs::F1_help_topic = "print"; - - if (! curr_file) return; // no image file - - printfile = strdupz(get_zuserdir(),20,"printfile"); // make temp print file: - strcat(printfile,"/printfile.tif"); // ~/.fotoxx/printfile.tif v.11.03 - - if (Fpxm16) printimage = PXM_convbpc(Fpxm16); - else printimage = PXM_copy(Fpxm8); - - pxmtemp = print_addgrid(printimage); // add grid lines if wanted v.11.01 - if (pxmtemp) { - PXM_free(printimage); - printimage = pxmtemp; - } - - err = PXBwrite(printimage,printfile); - PXM_free(printimage); - - if (err) { - zfree(printfile); // v.10.3 - return; - } - - print_image_paper_setup(); // new v.11.10 - print_image_margins_setup(); - print_image_file(printfile); - - zfree(printfile); - return; -} - - -// add grid lines to print image if wanted - -PXM * print_addgrid(PXM *printimage) // v.11.01 -{ - PXM *temp8; - uint8 *pixel; - int px, py, ww, hh, row; - int startx, starty, stepx, stepy; - - if (! Fgrid) return 0; // grid lines off - - temp8 = f_load(curr_file,8); - if (! temp8) return 0; - - ww = temp8->ww; - hh = temp8->hh; - row = ww * 3; - - stepx = gridspace[0]; // space between grid lines - stepy = gridspace[1]; - - stepx = stepx / Mscale; // window scale to image scale - stepy = stepy / Mscale; - - if (gridcount[0]) stepx = ww / (1 + gridcount[0]); // if line counts specified, - if (gridcount[1]) stepy = hh / ( 1 + gridcount[1]); // set spacing accordingly - - startx = stepx * gridoffset[0] / 100; // variable offsets v.11.11 - if (startx < 0) startx += stepx; - - starty = stepy * gridoffset[1] / 100; - if (starty < 0) starty += stepy; - - if (gridon[0]) { - for (px = startx; px < ww-1; px += stepx) - for (py = 0; py < hh; py++) - { - pixel = PXMpix8(temp8,px,py); // adjoining white and black lines - pixel[0] = pixel[1] = pixel[2] = 255; - pixel[3] = pixel[4] = pixel[5] = 0; - } - } - - if (gridon[1]) { - for (py = starty; py < hh-1; py += stepy) - for (px = 0; px < ww; px++) - { - pixel = PXMpix8(temp8,px,py); - pixel[0] = pixel[1] = pixel[2] = 255; - pixel[row] = pixel[row+1] = pixel[row+2] = 0; - } - } - - return temp8; -} - - -/**************************************************************************/ - -// normal quit menu function - -void m_quit(GtkWidget *, cchar *) -{ - if (mod_keep()) return; // unsaved edits - printf("quit \n"); - Fshutdown++; // bugfix v.10.11 - - for (int ii = 0; ii < 100; ii++) // wait up to a second if something running - if (Ffuncbusy) { // v.11.01 - zmainloop(); - zsleep(0.01); - } - - if (Ffuncbusy) printf("busy function killed"); // v.11.05 - - gtk_window_get_position(MWIN,&mwgeom[0],&mwgeom[1]); // get last window position v.11.07 - gtk_window_get_size(MWIN,&mwgeom[2],&mwgeom[3]); // and size for next session - save_params(); // save state for next session - zdialog_positions("save"); // save dialog positions too v.11.07 - free_resources(); // delete temp files - if (KBzmalloclog) zmalloc_report(); // report memory v.10.8 - fflush(null); // flush stdout, stderr v.11.05 - gtk_main_quit(); // gone forever - return; -} - - -/************************************************************************** - plugin menu functions -**************************************************************************/ - -// process plugin menu selection -// execute correspinding command using current image file - -editfunc EFplugin; - -void m_run_plugin(GtkWidget *, cchar *menu) // v.11.03 -{ - int ii, jj, err; - char *pp = 0, pluginfile[200]; - PXM *pxmtemp; - - zfuncs::F1_help_topic = "plugins"; - - for (ii = 0; ii < Nplugins; ii++) // search plugins for menu name - { - pp = strstr(plugins[ii]," = "); - if (! pp) continue; - *pp = 0; - jj = strEqu(plugins[ii],menu); - *pp = ' '; - if (jj) break; - } - - if (ii == Nplugins) { - zmessageACK(mWin,"plugin menu not found %s",menu); - return; - } - - pp += 3; - if (strlen(pp) < 3) { - zmessageACK(mWin,"no plugin command"); - return; - } - - strncpy0(command,pp,ccc); // corresp. command - strTrim2(command); - - EFplugin.funcname = menu; - if (! edit_setup(EFplugin)) return; // setup edit - - snprintf(pluginfile,199,"%s/plugfile.tif",get_zuserdir()); // /home/user/.fotoxx/plugfile.tif - - TIFFwrite(E1pxm16,pluginfile); // E1 >> plugin_file - - strcat(command," "); // construct: command /.../plugin_file & - strcat(command,pluginfile); - printf("plugin: %s \n",command); - - err = system(command); // execute plugin command - if (err) { - zmessageACK(mWin,"plugin command error"); - edit_cancel(EFplugin); - return; - } - - pxmtemp = TIFFread(pluginfile); // read command output file - if (! pxmtemp) { - zmessageACK(mWin,"plugin failed"); - edit_cancel(EFplugin); - return; - } - - PXM_free(E3pxm16); // plugin_file >> E3 - if (pxmtemp->bpc == 16) E3pxm16 = pxmtemp; - else { - E3pxm16 = PXM_convbpc(pxmtemp); - PXM_free(pxmtemp); - } - - EFplugin.Fmod = 1; // assume image was modified - edit_done(EFplugin); - - return; -} - - -// edit plugins menu - -void m_edit_plugins(GtkWidget *, cchar *) // v.11.03 -{ - int edit_plugins_event(zdialog *zd, cchar *event); - - int ii; - char *pp; - zdialog *zd; - - zfuncs::F1_help_topic = "plugins"; - - zd = zdialog_new("Edit Plugins",mWin,ZTX("Add"),ZTX("Remove"),Bdone,null); - zdialog_add_widget(zd,"hbox","hbm","dialog",0,"space=5"); - zdialog_add_widget(zd,"label","labm","hbm",ZTX("menu name"),"space=5"); - zdialog_add_widget(zd,"comboE","menu","hbm",0,"space=5"); - zdialog_add_widget(zd,"hbox","hbc","dialog",0,"space=5"); - zdialog_add_widget(zd,"label","labc","hbc","command","space=5"); - zdialog_add_widget(zd,"entry","command","hbc",0,"space=5|expand"); - - for (ii = 0; ii < Nplugins; ii++) // stuff combo box with available - { // plugin menu names - pp = strstr(plugins[ii]," = "); - if (! pp) continue; - *pp = 0; - zdialog_cb_app(zd,"menu",plugins[ii]); - *pp = ' '; - } - - zdialog_help(zd,"plugins"); // zdialog help topic v.11.08 - zdialog_run(zd,edit_plugins_event); - return; -} - - -// dialog event function - -int edit_plugins_event(zdialog *zd, cchar *event) -{ - int ii, jj, cc, zstat; - char menu[40], *pp = 0; - - zdialog_fetch(zd,"menu",menu,40); // selected menu - zdialog_fetch(zd,"command",command,ccc); - - if (strEqu(event,"menu")) - { - for (ii = 0; ii < Nplugins; ii++) - { - pp = strstr(plugins[ii]," = "); // find corresp. plugin record - if (! pp) continue; - *pp = 0; - jj = strEqu(plugins[ii],menu); - *pp = ' '; - if (jj) break; - } - - if (ii == Nplugins) return 0; - - pp += 3; - if (strlen(pp) < 3) return 0; - strncpy0(command,pp,ccc); - zdialog_stuff(zd,"command",command); // stuff corresp. command in dialog - - return 0; - } - - zstat = zd->zstat; - if (! zstat) return 0; - - if (zstat == 1) // add new plugin - { - if (strlen(menu) < 3 || strlen(command) < 3) return 0; - if (Nplugins == maxplugins) { - zmessageACK(mWin,"too many plugins"); - return 0; - } - ii = Nplugins; // add plugin record - cc = strlen(menu) + strlen(command) + 5; - plugins[ii] = zmalloc(cc,"plugins"); // format: menu = command - strcpy(plugins[ii],menu); - strcat(plugins[ii]," = "); - strcat(plugins[ii],command); - Nplugins++; - - zmessageACK(mWin,ZTX("Restart Fotoxx to update plugin menu")); - } - - if (zstat == 2) // remove current plugin - { - for (ii = 0; ii < Nplugins; ii++) - { - pp = strstr(plugins[ii]," = "); // find corresp. plugin record - if (! pp) continue; - *pp = 0; - jj = strEqu(plugins[ii],menu); - *pp = ' '; - if (jj) break; - } - - if (ii == Nplugins) return 0; - - Nplugins--; // remove plugin record - for (jj = ii; jj < Nplugins; jj++) - plugins[jj] = plugins[jj+1]; - - zmessageACK(mWin,ZTX("Restart Fotoxx to update plugin menu")); - } - - if (zstat == 3) { // done - zdialog_free(zd); - return 0; - } - - return 0; -} - - -/************************************************************************** - - edit transaction and thread support functions - - edit transaction management - edit_setup() start new edit - copy E3 > E1 - edit_cancel() cancel edit - E1 > E3, delete E1 - edit_done() commit edit - add to undo stack - edit_undo() undo edit - E1 > E3 - edit_redo() redo edit - run thread again - edit_fullsize() convert preview to full-size pixmaps - - main level thread management - start_thread(func,arg) start thread running - signal_thread() signal thread that work is pending - wait_thread_idle() wait for pending work complete - wrapup_thread(command) wait for exit or command thread exit - - thread function - thread_idle_loop() wait for pending work, exit if commanded - thread_exit() exit thread unconditionally - - thread_status (thread ownership - 0 no thread is running - 1 thread is running and idle (no work) - 2 thread is working - 0 thread has exited - - thread_command (main program ownership) - 0 idle, no work pending - 8 exit when pending work is done - 9 exit now, unconditionally - - thread_pend work requested counter - thread_done work done counter - thread_hiwater high water mark - edit_action done/cancel/undo/redo in progress - -***************************************************************************/ - -int thread_command = 0, thread_status = 0; -int thread_pend = 0, thread_done = 0, thread_hiwater = 0; -int edit_action = 0; - - -/************************************************************************** - - Setup for a new edit transaction - Create E1 (edit input) and E3 (edit output) pixmaps from - previous edit output (Fpxm16) or image file (new Fpxm16). - - Fprev 0 edit full-size image - 1 edit preview image unless select area exists - - Farea 0 select_area is invalid and will be deleted (e.g. rotate) - 1 select_area not used but remains valid (e.g. red-eye) - 2 select_area can be used and remains valid (e.g. flatten) - -***************************************************************************/ - -int edit_setup(editfunc &EF) // support parallel edits v.11.07 -{ - int yn; - PXM *pxmtemp = 0; - - if (! curr_file) return 0; // no image file - - if (is_syncbusy()) return 0; // must wait for file sync v.11.11 - - if (! Fpxm16) { // no 16-bit image from prior edit - pxmtemp = f_load(curr_file,16); // check that file can be loaded - if (! pxmtemp) { - printf("f_load (16) failed: %s \n",curr_file); - return 0; - } - } - - if (CEF) { // prior edit function active v.11.07 - if (&EF == CEF) return 0; // 2nd instance of one function - if (EF.Fpara && CEF->Fpara) // check if parallel edits are OK - edit_suspend(); // suspend prior edit - else { - zmessageACK(mWin,ZTX("cannot parallel edit")); - return 0; - } - } - else { // if this is 1st active edit - if (! menulock(1)) return 0; // test menu lock is allowed - menulock(0); // but don't lock yet v.11.07 - } - - if (! Fexiftool && ! Fexifwarned) { - zmessageACK(mWin,ZTX("exiftool is not installed \n" // warn if starting to edit - "edited images will lose EXIF data")); // and exiftool is missing - Fexifwarned = 1; - } - - if (Pundo > maxedits-2) { // undo capacity reached - zmessageACK(mWin,ZTX("Too many edits, please save image")); - return 0; - } - - if (EF.Farea == 0 && sa_stat) { // select area will be lost, warn user - yn = zmessageYN(mWin,ZTX("Select area cannot be kept.\n" - "Continue?")); - if (! yn) return 0; - sa_unselect(); // unselect area - zdialog_free(zdsela); - } - - if (EF.Farea == 2 && sa_stat && ! Factivearea) { // select area exists and can be used, - yn = zmessageYN(mWin,ZTX("Select area not active.\n" // but not active, ask user - "Continue?")); - if (! yn) return 0; - } - - if (! menulock(1)) return 0; // can now commit, lock menu v.11.07 - - Fpreview = 0; // use preview image if supported - if (EF.Fprev && ! (EF.Farea == 2 && Factivearea)) { // and select area will not be used - Fpreview = 1; // use preview image (smaller) - sa_show(0); // hide area if present - curr_image_time = get_seconds(); // mark time of file load v.11.07 - if (Fzoom) { - Fzoom = 0; // bugfix, mwpaint() req. v.11.01 - mwpaint1(); - } - } - - mutex_lock(&Fpixmap_lock); // lock pixmaps - - if (! Fpxm16) Fpxm16 = pxmtemp; // create Fpxm16 if not already - - PXM_fixblue(Fpxm16); // blue=0 >> blue=2 for vpixel() v.11.07 - - if (Fpreview) // edit pixmaps are window-size - E1pxm16 = PXM_rescale(Fpxm16,dww,dhh); // E1pxm16 = Fpxm16 scaled to window - else E1pxm16 = PXM_copy(Fpxm16); // edit pixmaps are full-size - E3pxm16 = PXM_copy(E1pxm16); // E1 >> E3 - - E1ww = E3ww = E1pxm16->ww; // E1 and E3 pixmap dimensions - E1hh = E3hh = E1pxm16->hh; - - mutex_unlock(&Fpixmap_lock); - - if (Pundo == 0) save_undo("initial"); // initial image >> undo stack - - CEF = &EF; // set current edit function - CEF->Fmod = 0; // image not modified yet - - thread_command = thread_status = 0; // no thread running - thread_pend = thread_done = thread_hiwater = 0; // no work pending or done - if (EF.threadfunc) start_thread(EF.threadfunc,0); // start edit thread - - Frefresh++; - mwpaint1(); // mwpaint1() not mwpaint2() - return 1; -} - - -/**************************************************************************/ - -// suspend a parallel edit function so it can be resumed -// edit dialog and curve edit are left active -// logically the equivalent of edit_done() - -void edit_suspend() -{ - wait_thread_idle(); // wait for thread to finish - - if (Fpreview && CEF->Fmod) { // preview image was edited - Fzoom = 0; - edit_fullsize(); // update full image - } - - wrapup_thread(8); // tell thread to finish and exit - - mutex_lock(&Fpixmap_lock); // lock pixmaps - - if (CEF->Fmod) { // image was modified - Fmodified++; // overall mod counter - PXM_free(Fpxm16); - Fpxm16 = E3pxm16; // E3 >> Fpxm16 v.11.07 - E3pxm16 = 0; - PXM_free(Fpxm8); - Fpxm8 = PXM_convbpc(Fpxm16); // Fpxm16 >> Fpxm8 - Fww = Fpxm8->ww; - Fhh = Fpxm8->hh; - Pundo++; // save next undo state - Pumax = Pundo; - save_undo(CEF->funcname); - } - - PXM_free(E1pxm16); // free edit pixmaps - PXM_free(E3pxm16); - PXM_free(ERpxm16); // free redo copy - E1ww = E3ww = ERww = 0; - - mutex_unlock(&Fpixmap_lock); - - CEF = 0; // no current edit func - menulock(0); - mwpaint2(); - return; -} - - -/**************************************************************************/ - -// process edit cancel - -void edit_cancel(editfunc &EF) -{ - if (edit_action) return; - edit_action++; // stop reentry - - if (&EF == CEF) // current edit is canceled v.11.07 - wrapup_thread(9); // tell thread to quit, wait - - if (EF.mousefunc == mouseCBfunc) // if my mouse, free mouse - freeMouse(); - if (EF.zd) zdialog_free(EF.zd); // kill dialog - if (EF.curves) zfree(EF.curves); // free curves data - EF.zd = 0; - EF.curves = 0; - - if (&EF != CEF) { // inactive edit canceled v.11.07 - edit_action = 0; - return; - } - - mutex_lock(&Fpixmap_lock); - PXM_free(E1pxm16); // free edit pixmaps E1, E3 - PXM_free(E3pxm16); - PXM_free(ERpxm16); // free redo copy v.10.3 - E1ww = E3ww = ERww = 0; - mutex_unlock(&Fpixmap_lock); - - if (Fpreview) curr_image_time = get_seconds(); // mark time of file load v.11.07 - Fzoom = 0; // v.11.07 - CEF = 0; // no current edit func - Fpreview = 0; // no preview mode - menulock(0); // unlock menu - mwpaint2(); // refresh window - edit_action = 0; - return; -} - - -/**************************************************************************/ - -// process edit dialog [done] -// E3pxm16 >> Fpxm16 >> Fpxm8 - -void edit_done(editfunc &EF) -{ - if (edit_action) return; - edit_action++; // stop reentry - - if (&EF == CEF) { // current edit is done v.11.07 - wait_thread_idle(); // wait for thread to finish - if (Fpreview && CEF->Fmod) { // preview image was edited - Fzoom = 0; - edit_fullsize(); // update full image - } - wrapup_thread(8); // tell thread to finish and exit - } - - if (EF.mousefunc == mouseCBfunc) // if my mouse, free mouse - freeMouse(); - if (EF.zd) zdialog_free(EF.zd); // kill dialog - if (EF.curves) zfree(EF.curves); // free curves data - EF.zd = 0; - EF.curves = 0; - - if (&EF != CEF) { // inactive edit is done v.11.07 - edit_action = 0; - return; - } - - mutex_lock(&Fpixmap_lock); - - if (CEF->Fmod) { // image was modified - Fmodified++; // overall mod counter - PXM_free(Fpxm16); - Fpxm16 = E3pxm16; // E3 >> Fpxm16 v.11.07 - E3pxm16 = 0; - PXM_free(Fpxm8); - Fpxm8 = PXM_convbpc(Fpxm16); // Fpxm16 >> Fpxm8 - Fww = Fpxm8->ww; - Fhh = Fpxm8->hh; - Pundo++; - Pumax = Pundo; - save_undo(CEF->funcname); // save next undo state - } - - PXM_free(E1pxm16); // free edit pixmaps - PXM_free(E3pxm16); - PXM_free(ERpxm16); // free redo copy v.10.3 - E1ww = E3ww = ERww = 0; - - mutex_unlock(&Fpixmap_lock); - - CEF = 0; // no current edit func - Fpreview = 0; // no preview mode - menulock(0); // unlock menu - mwpaint2(); // update window - edit_action = 0; - return; -} - - -/**************************************************************************/ - -// Setup for edit dialog event or curve edit. -// Call this function before performing any image edit -// (switch current edit function to caller's edit function). - -void edit_takeover(editfunc &EF) // v.11.07 -{ - static int busy = 0; - - if (busy++) return; // KB key bounce - if (CEF && &EF != CEF) { // edit function changed - edit_setup(EF); // close old and setup new edit - if (EF.zd) zdialog_send_event(EF.zd,"reset"); // reset dialog controls v.11.08 - freeMouse(); // free mouse from old dialog v.11.08 - } - busy = 0; - return; -} - - -/**************************************************************************/ - -// edit undo, redo, reset functions -// these apply within an active edit function - -void edit_undo() -{ - if (thread_status == 2) return; // thread busy - if (! CEF->Fmod) return; // not modified - if (edit_action) return; - edit_action++; // stop reentry - - mutex_lock(&Fpixmap_lock); - PXM_free(ERpxm16); // E3 >> redo copy - ERpxm16 = E3pxm16; - ERww = E3ww; - ERhh = E3hh; - E3pxm16 = PXM_copy(E1pxm16); // E1 >> E3 - E3ww = E1ww; - E3hh = E1hh; - mutex_unlock(&Fpixmap_lock); - - CEF->Fmod = 0; // reset image modified status - mwpaint2(); // refresh window - edit_action = 0; - return; -} - - -void edit_redo() -{ - if (thread_status == 2) return; // thread busy - if (! ERpxm16) return; // no prior undo - if (edit_action) return; - edit_action++; // stop reentry - - mutex_lock(&Fpixmap_lock); - PXM_free(E3pxm16); // redo copy >> E3 - E3pxm16 = ERpxm16; - E3ww = ERww; - E3hh = ERhh; - ERpxm16 = 0; - mutex_unlock(&Fpixmap_lock); - - CEF->Fmod = 1; // image modified - Fmodified++; // overall mod counter - mwpaint2(); - edit_action = 0; - return; -} - - -void edit_reset() -{ - if (thread_status == 2) return; // thread busy - if (! CEF->Fmod) return; // not modified - if (edit_action) return; - edit_action++; // stop reentry - - mutex_lock(&Fpixmap_lock); - PXM_free(ERpxm16); // delete redo copy - PXM_free(E3pxm16); - E3pxm16 = PXM_copy(E1pxm16); // E1 >> E3 - E3ww = E1ww; - E3hh = E1hh; - mutex_unlock(&Fpixmap_lock); - - CEF->Fmod = 0; // reset image modified status - mwpaint2(); // refresh window - edit_action = 0; - return; -} - - -void edit_zapredo() -{ - PXM_free(ERpxm16); // no redo copy - return; -} - - -/**************************************************************************/ - -// Convert from preview mode (window-size pixmaps) to full-size pixmaps. -// Can only be used when edit function is in an edit thread with idle_loop -// This function is called directly from some edit functions - -void edit_fullsize() -{ - mutex_lock(&Fpixmap_lock); - PXM_free(E1pxm16); // free preview pixmaps - PXM_free(E3pxm16); - E1pxm16 = PXM_copy(Fpxm16); // make full-size pixmaps - E3pxm16 = PXM_copy(Fpxm16); - E1ww = E3ww = Fww; - E1hh = E3hh = Fhh; - mutex_unlock(&Fpixmap_lock); - - Fpreview = 0; - Fzoom = 0; // v.11.07 - curr_image_time = get_seconds(); // mark time of file load v.11.07 - - if (! CEF->Fmod) return; // no change - signal_thread(); // signal thread, repeat edit - wait_thread_idle(); - return; -} - - -/************************************************************************** - undo / redo toolbar buttons -***************************************************************************/ - -// [undo] menu function - reinstate previous edit in undo/redo stack - -void m_undo(GtkWidget *, cchar *) -{ - if (CEF) { // undo active edit - edit_undo(); // v.11.08 - return; - } - - if (Pundo == 0) return; // undo past edit - if (! menulock(1)) return; - Pundo--; - if (KB_A_key) Pundo = 0; // if KB 'A' key, undo all v.11.11 - load_undo(); - Fmodified = Pundo; // v.11.08 - menulock(0); - return; -} - - -// [redo] menu function - reinstate next edit in undo/redo stack - -void m_redo(GtkWidget *, cchar *) -{ - if (CEF) { // redo active edit - edit_redo(); // v.11.08 - return; - } - - if (Pundo == Pumax) return; - if (! menulock(1)) return; - Pundo++; - if (KB_A_key) Pundo = Pumax; // if KB 'A' key, redo all v.11.11 - load_undo(); - Fmodified = Pundo; // v.11.08 - menulock(0); - return; -} - - -// undo all edits of the current image -// (discard modifications) - -void undo_all() // v.11.04 -{ - if (! menulock(1)) return; - Pundo = 0; // v.11.08 - load_undo(); - Fmodified = 0; // v.11.07 - menulock(0); - return; -} - - -// Save Fpxm16 to undo/redo file stack -// stack position = Pundo - -void save_undo(cchar *funcname) -{ - char *pp, buff[24]; - int fid, cc, cc2; - - pp = strstr(undo_files,"_undo_"); - if (! pp) zappcrash("undo/redo stack corrupted 1"); - snprintf(pp+6,3,"%02d",Pundo); - - fid = open(undo_files,O_WRONLY|O_CREAT|O_TRUNC,0640); - if (! fid) zappcrash("undo/redo stack corrupted 2"); - - snprintf(buff,24," %05d %05d fotoxx ",Fww,Fhh); - cc = write(fid,buff,20); - if (cc != 20) zappcrash("undo/redo stack corrupted 3"); - - cc = Fww * Fhh * 6; - cc2 = write(fid,Fpxm16->bmp,cc); - if (cc2 != cc) zappcrash("undo/redo stack corrupted 4"); - - close(fid); - - pvlist_replace(editlog,Pundo,funcname); // save log of edits done - return; -} - - -// Load Fpxm16 from undo/redo file stack -// stack position = Pundo - -void load_undo() -{ - char *pp, buff[24], fotoxx[8]; - int fid, ww, hh, cc, cc2; - - pp = strstr(undo_files,"_undo_"); - if (! pp) zappcrash("undo/redo stack corrupted 1"); - snprintf(pp+6,3,"%02d",Pundo); - - fid = open(undo_files,O_RDONLY); - if (! fid) zappcrash("undo/redo stack corrupted 2"); - - *fotoxx = 0; - cc = read(fid,buff,20); - sscanf(buff," %d %d %8s ",&ww, &hh, fotoxx); - if (! strEqu(fotoxx,"fotoxx")) zappcrash("undo/redo stack corrupted 4"); - - mutex_lock(&Fpixmap_lock); - - PXM_free(Fpxm16); - Fpxm16 = PXM_make(ww,hh,16); - cc = ww * hh * 6; - cc2 = read(fid,Fpxm16->bmp,cc); - if (cc2 != cc) zappcrash("undo/redo stack corrupted 5"); - close(fid); - - PXM_free(Fpxm8); - Fpxm8 = PXM_convbpc(Fpxm16); - - Fww = ww; - Fhh = hh; - - if (sa_fww != Fww || sa_fhh != Fhh) // disable area if image size changes - sa_disable(); // bugfix v.11.08 - - mutex_unlock(&Fpixmap_lock); - mwpaint2(); - return; -} - - -/**************************************************************************/ - -// ask user if modified image should be kept or discarded -// returns: 0 = mods discarded, 1 = do not discard mods - -int mod_keep() -{ - int keep = 0, choice = 0; - cchar *title = ZTX("Discard edits?"); - cchar *message = ZTX("This action will discard current edits.\n" // more clarity v.11.10 - "Continue to discard edits.\n" - "Go Back to keep edits."); - cchar *continu = ZTX("Continue"); - cchar *goback = ZTX("Go Back"); - - if (Fsaved < Pundo) keep = 1; // curr. edits not saved - if (keep == 0) return 0; // no mods - choice = zdialog_choose(title,mWin,message,continu,goback,null); - if (choice == 2) return 1; // keep mods - undo_all(); // discard mods - return 0; -} - - -/**************************************************************************/ - -// menu lock/unlock - some functions must not run concurrently -// returns 1 if success, else 0 - -int menulock(int lock) -{ - if (! lock && ! Fmenulock) zappcrash("menu lock error"); - if (lock && Fmenulock) { - zmessageACK(mWin,ZTX("prior function still active")); // v.11.06 - return 0; - } - if (lock) Fmenulock++; - else Fmenulock--; - return 1; -} - - -/**************************************************************************/ - -// check if Fsyncbusy is active, return 0 if not, -// otherwise message user and return 1 - -int is_syncbusy() -{ - if (! Fsyncbusy) return 0; - threadmessage = "Synchronize files is running. Edits are blocked. \n" - "You can still navigate and view images normally."; - return 1; -} - - -/**************************************************************************/ - -// start thread that does the edit work - -void start_thread(threadfunc func, void *arg) -{ - thread_status = 1; // thread is running - thread_command = thread_pend = thread_done = thread_hiwater = 0; // nothing pending - start_detached_thread(func,arg); - return; -} - - -// signal thread that work is pending - -void signal_thread() -{ - edit_zapredo(); // reset redo copy - if (thread_status > 0) thread_pend++; - return; -} - - -// wait for edit thread to complete pending work and become idle - -void wait_thread_idle() -{ - while (thread_status && thread_pend > thread_done) - { - zmainloop(); - zsleep(0.01); - } - - return; -} - - -// wait for thread exit or command thread exit -// command = 0 wait for normal completion -// 8 finish pending work and exit -// 9 quit, exit now - -void wrapup_thread(int command) -{ - thread_command = command; // tell thread to quit or finish - - while (thread_status > 0) // wait for thread to finish - { // pending work and exit - zmainloop(); - zsleep(0.01); - } - - return; -} - - -// called only from edit threads -// idle loop - wait for work request or exit command - -void thread_idle_loop() -{ - if (thread_status == 2) Ffuncbusy--; // v.11.05 - thread_status = 1; // status = idle - thread_done = thread_hiwater; // work done = high-water mark - - while (true) - { - if (thread_command == 9) thread_exit(); // quit now command - if (thread_command == 8) // finish work and exit - if (thread_pend <= thread_done) thread_exit(); - if (thread_pend > thread_done) break; // wait for work request - zsleep(0.01); - } - - thread_hiwater = thread_pend; // set high-water mark - thread_status = 2; // thread is working - Ffuncbusy++; // v.11.05 - return; // perform edit -} - - -// exit thread unconditionally, called only from edit threads - -void thread_exit() -{ - if (thread_status == 2) Ffuncbusy--; // v.11.05 - thread_pend = thread_done = thread_hiwater = 0; - thread_status = 0; - pthread_exit(0); // "return" cannot be used here -} - - -/**************************************************************************/ - -// edit support functions for working threads (per processor core) - -void start_wthread(threadfunc func, void *arg) // start and increment busy count -{ - zadd_locked(wthreads_busy,+1); - zadd_locked(Ffuncbusy,+1); // v.11.01 - start_detached_thread(func,arg); - return; -} - - -void exit_wthread() // decrement busy count and exit -{ - zadd_locked(Ffuncbusy,-1); // v.11.01 - zadd_locked(wthreads_busy,-1); - pthread_exit(0); // "return" cannot be used here v.9.4 -} - - -void wait_wthreads() // wait for all working threads done -{ // caller can be main() or a thread - while (wthreads_busy) { - zsleep(0.01); - zmainloop(); // v.11.11.1 - } - return; -} - - -/************************************************************************** - other support functions -***************************************************************************/ - -// help menu function - -void m_help(GtkWidget *, cchar *menu) -{ - if (strEqu(menu,ZTX("About"))) - zmessageACK(mWin,"%s \n%s \n%s \n%s \n\n%s \n\n%s", - fversion,flicense,fhomepage,fcontact,fcredits,ftranslators); - - if (strEqu(menu,ZTX("User Guide"))) - showz_userguide(); - - if (strEqu(menu,ZTX("User Guide Changes"))) - showz_userguide("changes"); - - if (strEqu(menu,ZTX("Help"))) // toolbar button - showz_userguide(zfuncs::F1_help_topic); // show topic if there, or page 1 - - if (strEqu(menu,"README")) - showz_readme(); - - if (strEqu(menu,ZTX("Edit Functions Summary"))) // v.11.11 - showz_doctext("edit-menus"); - - if (strEqu(menu,ZTX("Change Log"))) - showz_changelog(); - - if (strEqu(menu,ZTX("Translations"))) - showz_translations(); - - if (strEqu(menu,ZTX("Home Page"))) - showz_html(fhomepage); - - return; -} - - -/**************************************************************************/ - -// table for loading and saving adjustable parameters between sessions - -typedef struct { - char name[20]; - char type[12]; - int count; - void *location; -} param; - -#define Nparms 32 - -param paramTab[Nparms] = { -// name type count location -{ "fotoxx version", "char", 1, &pversion }, -{ "last session", "char", 1, &last_session }, -{ "first time", "int", 1, &Ffirsttime }, -{ "new files found", "int", 1, &newfiles }, -{ "window geometry", "int", 4, &mwgeom }, -{ "toolbar style", "char", 1, &tbar_style }, -{ "warn overwrite", "int", 1, &Fwarnoverwrite }, -{ "lens name", "char", 4, &lens4_name }, -{ "lens mm", "double", 4, &lens4_mm }, -{ "lens bow", "double", 4, &lens4_bow }, -{ "current lens", "int", 1, &curr_lens }, -{ "trim size", "int", 2, &trimsize }, -{ "trim buttons", "char", 6, &trimbuttons }, -{ "trim ratios", "char", 6, &trimratios }, -{ "edit resize", "int", 2, &editresize }, -{ "batch resize", "int", 2, &batchresize }, -{ "e-mail resize", "int", 2, &emailsize }, -{ "annotate font", "char", 1, &annotate_font }, -{ "annotate text", "char", 1, &annotate_text }, -{ "annotate color", "char", 3, &annotate_color }, -{ "annotate trans", "int", 3, &annotate_trans }, -{ "annotate outline", "int", 1, &annotate_outline }, -{ "annotate angle", "double", 1, &annotate_angle }, -{ "grid spacing", "int", 2, &gridspace }, -{ "grid counts", "int", 2, &gridcount }, -{ "rotate grid", "int", 8, &rotate_grid }, -{ "unbend grid", "int", 8, &unbend_grid }, -{ "warp-curved grid", "int", 8, &warpC_grid }, -{ "warp-linear grid", "int", 8, &warpL_grid }, -{ "warp-affine grid", "int", 8, &warpF_grid }, -{ "slideshow trans", "int", SSNF, &ss_funcs }, -{ "slideshow music", "char", 1, &ss_musicfile } }; - - -// save parameters to file /home//.fotoxx/parameters - -void save_params() // new v.10.9 -{ - FILE *fid; - char buff[1050], text[1000]; // limit for character data cc - char *pp, *name, *type; - int count; - void *location; - char **charloc; - int *intloc; - double *doubleloc; - time_t currtime; - - pversion = strdupz(fversion); // this fotoxx version v.11.10 - - currtime = time(0); - last_session = ctime(&currtime) + 4; // fotoxx session exit time v.11.11 - if (last_session[4] == ' ') last_session[4] = '0'; // format mmm dd hh:mm:ss yyyy - pp = strchr(last_session,'\n'); - if (pp) *pp = 0; - - snprintf(buff,199,"%s/parameters",get_zuserdir()); // open output file - fid = fopen(buff,"w"); - if (! fid) return; - - for (int ii = 0; ii < Nparms; ii++) // write table of state data - { - name = paramTab[ii].name; - type = paramTab[ii].type; - count = paramTab[ii].count; - location = paramTab[ii].location; - charloc = (char **) location; - intloc = (int *) location; - doubleloc = (double *) location; - - fprintf(fid,"%-20s %-8s %02d ",name,type,count); // write parm name, type, count - - for (int kk = 0; kk < count; kk++) // write "value" "value" ... - { - if (strEqu(type,"char")) { - if (! *charloc) printf("bad param data %s %d \n",name,kk); // bugfix v.10.11.1 - if (! *charloc) break; - repl_1str(*charloc++,text,"\n","\\n"); // replace newlines with "\n" v.10.11 - fprintf(fid," \"%s\"",text); - } - if (strEqu(type,"int")) - fprintf(fid," \"%d\"",*intloc++); - - if (strEqu(type,"double")) - fprintf(fid," \"%.2f\"",*doubleloc++); - } - - fprintf(fid,"\n"); // write EOR - } - - fprintf(fid,"\n"); - fclose(fid); // close file - - fid = fopen(recentfiles_file,"w"); // recent files file - if (! fid) return; - - for (int ii = 0; ii < Nrecentfiles; ii++) // save list of recent files - if (recentfiles[ii]) - fprintf(fid,"%s \n",recentfiles[ii]); - - fclose(fid); - - snprintf(buff,199,"%s/plugins",get_zuserdir()); // open file for plugins v.11.03 - fid = fopen(buff,"w"); - if (! fid) return; - - for (int ii = 0; ii < Nplugins; ii++) // save plugins - if (plugins[ii]) - fprintf(fid,"%s \n",plugins[ii]); - - fclose(fid); - - return; -} - - -// load parameters from file /home//.fotoxx/parameters - -void load_params() // new v.10.9 -{ - FILE *fid; - int ii, err, pcount, Idata; - double Rdata; - char buff[1000], text[1000], *pp; - char name[20], type[12], count[8], data[1000]; - void *location; - char **charloc; - int *intloc; - double *doubleloc; - - for (ii = 0; ii < Nparms; ii++) // set string parameters to "undefined" - { // v.10.11 - if (strNeq(paramTab[ii].type,"char")) continue; - charloc = (char **) paramTab[ii].location; - pcount = paramTab[ii].count; - for (int jj = 0; jj < pcount; jj++) - *charloc++ = strdupz("undefined",20); - } - - snprintf(buff,499,"%s/parameters",get_zuserdir()); // open parameters file - fid = fopen(buff,"r"); - if (! fid) return; - - while (true) // read parameters - { - pp = fgets_trim(buff,999,fid,1); - if (! pp) break; - if (*pp == '#') continue; // comment v.10.10 - if (strlen(pp) < 40) continue; // rubbish v.10.10 - - err = 0; - - strncpy0(name,pp,20); // parm name - strTrim2(name); - - strncpy0(type,pp+22,8); // parm type - strTrim2(type); - - strncpy0(count,pp+32,4); // parm count - strTrim2(count); - err = convSI(count,pcount); - - strncpy0(data,pp+38,1000); // parm value(s) - strTrim2(data); - - for (ii = 0; ii < Nparms; ii++) // match file record to param table - { - if (strNeq(name,paramTab[ii].name)) continue; // parm name - if (strNeq(type,paramTab[ii].type)) continue; // parm type - if (paramTab[ii].count != pcount) continue; // parm count - - location = paramTab[ii].location; - charloc = (char **) location; - intloc = (int *) location; - doubleloc = (double *) location; - - for (int kk = 1; kk <= pcount; kk++) - { - pp = (char *) strField(data,' ',kk); - if (! pp) break; - - if (strEqu(type,"char")) { - repl_1str(pp,text,"\\n","\n"); // replace "\n" with real newlines v.10.11 - *charloc++ = strdupz(text,0,"parameters"); // v.11.04 - } - - if (strEqu(type,"int")) { - err = convSI(pp,Idata); - if (err) continue; - *intloc++ = Idata; - } - - if (strEqu(type,"double")) { - err = convSD(pp,Rdata); - if (err) continue; - *doubleloc++ = Rdata; - } - } - } - } - - fclose(fid); - - if (strNeq(pversion,fversion)) // fotoxx version change v.11.10 - printf("new Fotoxx version %s %s \n",pversion,fversion); - - printf("last Fotoxx session: %s \n",last_session); // last session exit time v.11.11 - - fid = fopen(topdirk_file,"r"); // set top directory from v.11.11 - if (fid) { // from top directory file - pp = fgets_trim(buff,499,fid,1); - if (pp && *pp == '/') - topdirk = strdupz(buff,0,"top_dirk"); - fclose(fid); - } - - printf("top image directory: %s \n",topdirk); - - for (ii = 0; ii < Nrecentfiles; ii++) // recent image file list = empty - recentfiles[ii] = 0; - - fid = fopen(recentfiles_file,"r"); // open recent files file - if (fid) { - for (ii = 0; ii < Nrecentfiles; ii++) // read list of recent files - { - pp = fgets_trim(buff,499,fid,1); - if (! pp) break; - if (*pp == '/') - recentfiles[ii] = strdupz(buff,0,"recentfile"); - else ii--; // v.11.11 - } - - fclose(fid); - } - - for (ii = 0; ii < maxplugins; ii++) // plugins list = empty v.11.03 - plugins[ii] = 0; - - plugins[0] = strdupz("Gimp = gimp"); // if empty, default Gimp plugin - Nplugins = 1; - - snprintf(buff,499,"%s/plugins",get_zuserdir()); // open plugins file v.11.03 - fid = fopen(buff,"r"); - if (fid) - { - for (ii = 0; ii < maxplugins; ii++) // read list of plugins - { - pp = fgets_trim(buff,499,fid,1); - if (! pp) break; - plugins[ii] = strdupz(buff,0,"plugins"); - } - - fclose(fid); - Nplugins = ii; - } - - return; -} - - -/**************************************************************************/ - -// Compute the mean brightness of all pixel neighborhoods, // new v.9.6 -// using a Guassian or a flat distribution for the weightings. -// If a select area is active, only inside pixels are calculated. -// The flat method is 10-100x faster. - -int brhood_radius; -double brhood_kernel[200][200]; // up to radius = 99 -float *brhood_brightness = 0; // neighborhood brightness per pixel -char brhood_method; // g = gaussian, f = flat distribution - - -void brhood_calc(int radius, char method) -{ - void * brhood_wthread(void *arg); - - int rad, rad2, dx, dy, cc, ii; - double kern; - - brhood_radius = radius; - brhood_method = method; - - if (brhood_method == 'g') // compute Gaussian kernel - { // (not currently used v.11.02) - rad = brhood_radius; - rad2 = rad * rad; - - for (dy = -rad; dy <= rad; dy++) - for (dx = -rad; dx <= rad; dx++) - { - if (dx*dx + dy*dy <= rad2) // cells within radius - kern = exp( - (dx*dx + dy*dy) / rad2); - else kern = 0; // outside radius - brhood_kernel[dy+rad][dx+rad] = kern; - } - } - - if (brhood_brightness) zfree(brhood_brightness); // allocate memory for pixel map - cc = E1ww * E1hh * sizeof(float); - brhood_brightness = (float *) zmalloc(cc,"brhood"); - memset(brhood_brightness,0,cc); - - if (Factivearea) SB_goal = sa_Npixel; // set up progress tracking - else SB_goal = E1ww * E1hh; - SB_done = 0; // v.11.06 - - for (ii = 0; ii < Nwt; ii++) // start worker threads - start_wthread(brhood_wthread,&wtnx[ii]); - wait_wthreads(); // wait for completion - - SB_goal = 0; - return; -} - - -// worker thread function - -void * brhood_wthread(void *arg) -{ - int index = *((int *) arg); - int rad = brhood_radius; - int ii, px, py, qx, qy, Fstart; - double kern, bsum, bsamp, bmean; - uint16 *pixel; - - if (brhood_method == 'g') // use round gaussian distribution - { - for (py = index; py < E1hh; py += Nwt) - for (px = 0; px < E1ww; px++) - { - if (Factivearea && sa_mode != 7) { // select area, not whole image v.11.02 - ii = py * E1ww + px; // use only inside pixels - if (! sa_pixmap[ii]) continue; - } - - bsum = bsamp = 0; - - for (qy = py-rad; qy <= py+rad; qy++) // computed weighted sum of brightness - for (qx = px-rad; qx <= px+rad; qx++) // for pixels in neighborhood - { - if (qy < 0 || qy > E1hh-1) continue; - if (qx < 0 || qx > E1ww-1) continue; - kern = brhood_kernel[qy+rad-py][qx+rad-px]; - pixel = PXMpix(E1pxm16,qx,qy); - bsum += pixbright(pixel) * kern; // sum brightness * weight - bsamp += kern; // sum weights - } - - bmean = bsum / bsamp; // mean brightness - ii = py * E1ww + px; - brhood_brightness[ii] = bmean; // pixel value - - SB_done++; // track progress v.11.06 - if (drandz() < 0.0001) zsleep(0.001); // trigger sorry kernel scheduler - } - } - - if (brhood_method == 'f') // use square flat distribution - { - Fstart = 1; - bsum = bsamp = 0; - - for (py = index; py < E1hh; py += Nwt) - for (px = 0; px < E1ww; px++) - { - if (Factivearea && sa_mode != 7) { // select area, not whole image v.11.02 - ii = py * E1ww + px; // compute only inside pixels - if (! sa_pixmap[ii]) { - Fstart = 1; - continue; - } - } - - if (px == 0) Fstart = 1; - - if (Fstart) - { - Fstart = 0; - bsum = bsamp = 0; - - for (qy = py-rad; qy <= py+rad; qy++) // add up all columns - for (qx = px-rad; qx <= px+rad; qx++) - { - if (qy < 0 || qy > E1hh-1) continue; - if (qx < 0 || qx > E1ww-1) continue; - pixel = PXMpix(E1pxm16,qx,qy); - bsum += pixbright(pixel); - bsamp += 1; - } - } - else - { - qx = px-rad-1; // subtract first-1 column - if (qx >= 0) { - for (qy = py-rad; qy <= py+rad; qy++) - { - if (qy < 0 || qy > E1hh-1) continue; - pixel = PXMpix(E1pxm16,qx,qy); - bsum -= pixbright(pixel); - bsamp -= 1; - } - } - qx = px+rad; // add last column - if (qx < E1ww) { - for (qy = py-rad; qy <= py+rad; qy++) - { - if (qy < 0 || qy > E1hh-1) continue; - pixel = PXMpix(E1pxm16,qx,qy); - bsum += pixbright(pixel); - bsamp += 1; - } - } - } - - bmean = bsum / bsamp; // mean brightness - ii = py * E1ww + px; - brhood_brightness[ii] = bmean; - - SB_done++; // track progress v.11.06 - if (drandz() < 0.0001) zsleep(0.001); // trigger sorry kernel scheduler - } - } - - exit_wthread(); - return 0; // not executed, avoid gcc warning -} - - -// get the neighborhood brightness for given pixel - -float get_brhood(int px, int py) -{ - int ii = py * E1ww + px; - return brhood_brightness[ii]; -} - - -/**************************************************************************/ - -// free all resources associated with the current image file - -void free_resources(int fkeepundo) -{ - char *pp; - int err; - - mutex_lock(&Fpixmap_lock); // lock pixmaps - - if (! fkeepundo) { - strcpy(command,"rm -f "); // delete all undo files - strcat(command,undo_files); - pp = strstr(command,"_undo_"); // /home/user/.fotoxx/pppppp_undo_* - strcpy(pp + 6,"*"); - err = system(command); - if (err) printf("error: %s \n",wstrerror(err)); - Fmodified = Pundo = Pumax = Fsaved = 0; // reset undo/redo stack - } - - Ntoplines = Nptoplines; // no image overlay lines - freeMouse(); // free mouse v.11.04 - - if (Fshutdown) { // stop here if shutdown mode - mutex_unlock(&Fpixmap_lock); - return; - } - - if (curr_file) { - sa_unselect(); // unselect select area - zdialog_free(zdsela); // kill dialogs if active - zfree(curr_file); // free image file - curr_file = 0; - SB_goal = 0; // v.9.2 - *SB_text = 0; // v.10.7 - } - - if (brhood_brightness) zfree(brhood_brightness); // free brightness map v.9.6 - brhood_brightness = 0; - - PXM_free(Fpxm8); - PXM_free(Dpxm8); - PXM_free(Fpxm16); - PXM_free(E1pxm16); - PXM_free(E3pxm16); - PXM_free(ERpxm16); // v.10.3 - - Fww = E1ww = E3ww = Dww = 0; // make unusable (crash) - - mutex_unlock(&Fpixmap_lock); - return; -} - - -// Get a virtual pixel at location (px,py) (real) in an PXM-16 pixmap. -// Get the overlapping real pixels and build a composite. - -int vpixel(PXM *pxm, double px, double py, uint16 *vpix) -{ - int ww, hh, px0, py0; - uint16 *ppix, *pix0, *pix1, *pix2, *pix3; - double f0, f1, f2, f3; - double red, green, blue; - - ww = pxm->ww; - hh = pxm->hh; - ppix = (uint16 *) pxm->bmp; - - px0 = px; // pixel containing (px,py) - py0 = py; - - if (px0 < 1 || py0 < 1) return 0; // void edge pixels - if (px0 > ww-3 || py0 > hh-3) return 0; - - pix0 = ppix + (py0 * ww + px0) * 3; // 4 pixels based at (px0,py0) - pix1 = pix0 + ww * 3; - pix2 = pix0 + 3; - pix3 = pix0 + ww * 3 + 3; - - f0 = (px0+1 - px) * (py0+1 - py); // overlap of (px,py) - f1 = (px0+1 - px) * (py - py0); // in each of the 4 pixels - f2 = (px - px0) * (py0+1 - py); - f3 = (px - px0) * (py - py0); - - red = f0 * pix0[0] + f1 * pix1[0] + f2 * pix2[0] + f3 * pix3[0]; // sum the weighted inputs - green = f0 * pix0[1] + f1 * pix1[1] + f2 * pix2[1] + f3 * pix3[1]; - blue = f0 * pix0[2] + f1 * pix1[2] + f2 * pix2[2] + f3 * pix3[2]; - - vpix[0] = red; - vpix[1] = green; - vpix[2] = blue; - - if (blue < 1) { // v.10.7 - if (blue < 0.9) return 0; // near edge or voided area - vpix[2] = 1; // avoid 0.999 to integer 0 - } - - return 1; -} - - -// compare two doubles for significant difference -// return: 0 difference not significant -// +1 d1 > d2 -// -1 d1 < d2 - -int sigdiff(double d1, double d2, double signf) -{ - double diff = fabs(d1-d2); - if (diff == 0.0) return 0; - diff = diff / (fabs(d1) + fabs(d2)); - if (diff < signf) return 0; - if (d1 > d2) return 1; - else return -1; -} - - -/************************************************************************** - file read and write utilities - PXM pixmap <--> file on disk -***************************************************************************/ - -// Load an image file into an PXM pixmap of 8 or 16 bits/color -// Also sets the following file scope variables: -// f_load_type = "jpg" "tif" "png" or "other" -// f_load_bpc = disk file bits per color = 1/8/16 -// f_load_size = disk file size - -PXM * f_load(cchar *filespec, int bpc) // use pixbuf or tiff library v.9.8 -{ - int err; - cchar *pext; - PXM *pxm1, *pxm2; - struct stat fstat; - - if (bpc != 8 && bpc != 16) // requested bpc must be 8 or 16 - zappcrash("image_load bpc: %d",bpc); - - err = stat(filespec,&fstat); - if (err) return 0; // file not found - if (! S_ISREG(fstat.st_mode)) return 0; // not a regular file - if (image_file_type(filespec) != 2) return 0; // not a supported image type - f_load_size = fstat.st_size; // disk file bytes - - pext = strrchr(filespec,'/'); - if (! pext) pext = filespec; - - if (pext > filespec+12 && strnEqu(pext-12,"/.thumbnails/",13)) { // refuse thumbnail files v.10.0 - zmessageACK(mWin,ZTX("cannot open thumbnail file")); - return 0; - } - - pext = strrchr(pext,'.'); - if (! pext) pext = ""; - - if (strstr(".jpg .jpeg .JPG .JPEG",pext)) strcpy(f_load_type,"jpg"); - else if (strstr(".tif .tiff .TIF .TIFF",pext)) strcpy(f_load_type,"tif"); - else if (strstr(".png .PNG",pext)) strcpy(f_load_type,"png"); - else strcpy(f_load_type,"other"); - - if (strEqu(f_load_type,"tif")) // use tiff lib to read tiff file - pxm1 = TIFFread(filespec); - else pxm1 = PXBread(filespec); // use pixbuf lib for others - if (! pxm1) return 0; // (both set f_load_bpc = file bpc) - - if (pxm1->bpc != bpc) { - pxm2 = PXM_convbpc(pxm1); // convert to requested bpc - PXM_free(pxm1); // 8 <--> 16 - pxm1 = pxm2; - } - // auto upright image removed v.10.12 - return pxm1; -} - - -/**************************************************************************/ - -// save current image to specified disk file (same or new). -// set f_save_type, f_save_bpc, f_save_size -// update search index file -// return 0 if OK, else +N - -int f_save(char *outfile, cchar *type, int bpc) // use pixbuf or tiff library v.9.8 -{ - PXM *pxm16; - cchar *exifkey[2] = { exif_orientation_key, iptc_editlog_key }; - cchar *exifdata[2]; - char **ppv, funcslist[1000]; - char *pp, *tempfile, *pext; - int nkeys, err = 1, cc1, cc2; - struct stat fstat; - - if ((bpc != 8 && bpc != 16) || ! strstr("jpg tif png",type)) // check args - zappcrash("f_save: %s %d",type,bpc); - - Ffuncbusy++; // v.11.01 - - pext = strrchr(outfile,'/'); // force compatible file extension - if (pext) pext = strrchr(pext,'.'); // if not already - if (! pext) pext = outfile + strlen(outfile); - if (strEqu(type,"jpg") && ! strstr(".jpg .JPG .jpeg .JPEG",pext)) - strcpy(pext,".jpg"); - if (strEqu(type,"png") && ! strstr(".png .PNG",pext)) - strcpy(pext,".png"); - if (strEqu(type,"tif") && ! strstr(".tif .TIF .tiff .TIFF",pext)) - strcpy(pext,".tif"); - - tempfile = strdupz(get_zuserdir(),24,"f_save"); // use temp output file - strcat(tempfile,"/temp_"); // ~/.fotoxx/temp_ppppp.ext - strcat(tempfile,PIDstring); - strcat(tempfile,"."); - strcat(tempfile,type); - - if (strEqu(type,"png")) { // save as PNG file (bpc = 8 always) - if (Fpxm16) err = PXBwrite(Fpxm16,tempfile); - else err = PXBwrite(Fpxm8,tempfile); - bpc = 8; - } - - else if (strEqu(type,"tif")) { // save as tiff file - if (bpc == 8) { - if (Fpxm16) { - PXM_free(Fpxm8); // bugfix v.10.8 - Fpxm8 = PXM_convbpc(Fpxm16); - } - err = TIFFwrite(Fpxm8,tempfile); - } - else if (bpc == 16) { - if (Fpxm16) err = TIFFwrite(Fpxm16,tempfile); // edit file exists, use it - else { - if (curr_file_bpc == 16) pxm16 = TIFFread(curr_file); // use original 16 bpc file - else pxm16 = PXM_convbpc(Fpxm8); // or convert 8 to 16 bpc - if (! pxm16) err = 1; - else { - err = TIFFwrite(pxm16,tempfile); - PXM_free(pxm16); - } - } - } - } - - else { // save as JPEG file (bpc = 8 always) - if (Fpxm16) err = PXBwrite(Fpxm16,tempfile); - else err = PXBwrite(Fpxm8,tempfile); - bpc = 8; - } - - if (err) { - remove(tempfile); // failure, clean up v.11.02 - zfree(tempfile); - Ffuncbusy--; - return 1; - } - - exifdata[0] = ""; // EXIF orientation = upright - nkeys = 1; // remove old width, height v.10.8 - - if (Pundo > 0) // if edits were made, - { // update relevant EXIF key v.10.2 - *funcslist = 0; - ppv = info_get(curr_file,&exifkey[1],1); // get existing list of edits - if (ppv[0]) { - strncpy0(funcslist,ppv[0],998); - zfree(ppv[0]); - } - cc1 = strlen(funcslist); // add blank - if (cc1 && funcslist[cc1-1] != ' ') { - strcpy(funcslist+cc1," "); - cc1++; - } - - for (int ii = 1; ii <= Pundo; ii++) // append new list of edits - { // (omit index 0 = initial) - pp = pvlist_get(editlog,ii); - cc2 = strlen(pp); - if (cc1 + cc2 > 998) break; - strcpy(funcslist+cc1,pp); - strcpy(funcslist+cc1+cc2," "); - cc1 += cc2 + 1; - } - - exifdata[1] = funcslist; // IPTC edit history key, fotoxx edits done - nkeys = 2; - } - - err = stat(curr_file,&fstat); - if (! err && S_ISREG(fstat.st_mode)) { // if current file exists, v.11.05 - err = info_copy(curr_file,tempfile,exifkey,exifdata,nkeys); // copy all EXIF/IPTC data to - if (err) zmessageACK(mWin,"Unable to copy EXIF/IPTC"); // temp file with above revisions - } - - snprintf(command,ccc,"cp -f \"%s\" \"%s\" ",tempfile,outfile); // copy temp file to output file - err = system(command); - if (err) zmessageACK(mWin,"Unable to save image: %s",wstrerror(err)); - - remove(tempfile); // delete temp file v.11.02 - zfree(tempfile); - - save_fileinfo(outfile); // save tag changes if any - if (! curr_file || strNeq(outfile,curr_file)) // if save to new file, v.11.08 - update_search_index(outfile); // update search index file - - Fsaved = Pundo; // update which mods are saved to disk - - add_recent_file(outfile); // first in recent files list - - strcpy(f_save_type,type); // update f_save_xxx data - f_save_bpc = bpc; - - err = stat(outfile,&fstat); - if (err) { - Ffuncbusy--; - return 1; - } - - f_save_size = fstat.st_size; - - Ffuncbusy--; - mwpaint2(); // v.11.03 - return 0; -} - - -/**************************************************************************/ - -// Read from TIFF file using TIFF library. -// Use native TIFF file bits/pixel. - -PXM * TIFFread(cchar *filespec) // overhauled v.10.8.1 -{ - TIFF *tiff; - PXM *pxm; - char *tiffbuff; - uint8 *tiff8, *pxm8; - uint16 *tiff16, *pxm16; - uint16 bpc, nch, fmt; - int ww, hh, rps, stb, nst; // int not uint v.11.03 - int tiffstat, row, col, strip, cc; - - tiff = TIFFOpen(filespec,"r"); - if (! tiff) { - zmessageACK(mWin,ZTX("TIFF open failure")); - return 0; - } - - TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &ww); // width - TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &hh); // height - TIFFGetField(tiff, TIFFTAG_BITSPERSAMPLE, &bpc); // bits per color, 1/8/16 - TIFFGetField(tiff, TIFFTAG_SAMPLESPERPIXEL, &nch); // no. channels (colors), 1/3/4 - TIFFGetField(tiff, TIFFTAG_ROWSPERSTRIP, &rps); // rows per strip - TIFFGetField(tiff, TIFFTAG_SAMPLEFORMAT, &fmt); // data format - stb = TIFFStripSize(tiff); // strip size - nst = TIFFNumberOfStrips(tiff); // number of strips - -// printf("ww %d hh %d nch %d bpc %d rps %d stb %d nst %d fmt %d \n",ww,hh,nch,bpc,rps,stb,nst,fmt); - - if (! (bpc <= 8 || bpc == 16)) { // check for supported bits/color - zmessageACK(mWin,ZTX("TIFF bits/color=%d not supported"),bpc); - TIFFClose(tiff); - return 0; - } - - f_load_bpc = bpc; // for f_load(), file bpc 1/8/16 v.10.12 - - if (bpc <= 8) // use universal TIFF reader - { // if bits/color <= 8 - tiffbuff = zmalloc(ww*hh*4,"tiffbuff"); - - tiffstat = TIFFReadRGBAImage(tiff, ww, hh, (uint *) tiffbuff, 0); - TIFFClose(tiff); - - if (tiffstat != 1) { - zmessageACK(mWin,ZTX("TIFF read failure")); - zfree(tiffbuff); - return 0; - } - - pxm = PXM_make(ww,hh,8); - - tiff8 = (uint8 *) tiffbuff; - - for (row = 0; row < hh; row++) // convert RGBA to RGB - { - pxm8 = (uint8 *) pxm->bmp; - pxm8 += (hh-1 - row) * ww * 3; - - for (col = 0; col < ww; col++) - { - pxm8[0] = tiff8[0]; - pxm8[1] = tiff8[1]; - pxm8[2] = tiff8[2]; - pxm8 += 3; - tiff8 += 4; - } - } - - zfree(tiffbuff); - return pxm; - } - // 16 bits per color - - stb += 1000000; // reduce risk of crash v.10.8.2 - tiffbuff = zmalloc(stb,"tiffbuff"); // read encoded strips - - pxm = PXM_make(ww,hh,16); - - for (strip = 0; strip < nst; strip++) - { - cc = TIFFReadEncodedStrip(tiff,strip,tiffbuff,stb); - if (cc < 0) { - zmessageACK(mWin,ZTX("TIFF read failure")); - TIFFClose(tiff); - zfree(tiffbuff); - PXM_free(pxm); - return 0; - } - - if (cc == 0) break; - - tiff16 = (uint16 *) tiffbuff; - pxm16 = (uint16 *) pxm->bmp; - row = strip * rps; - pxm16 += row * ww * 3; - - while (cc >= 6) // bugfix v.11.03 - { - pxm16[0] = tiff16[0]; - pxm16[1] = tiff16[1]; - pxm16[2] = tiff16[2]; - pxm16 += 3; - tiff16 += nch; - cc -= nch * 2; - } - } - - TIFFClose(tiff); - zfree(tiffbuff); - return pxm; -} - - -// Write to TIFF file using TIFF library. -// File bpc is taken from PXM (8 or 16). -// returns 0 if OK, +N if error. - -int TIFFwrite(PXM *pxm, cchar *filespec) // new v.9.8 -{ - TIFF *tiff; - uint8 *tiff8, *pxm8; - uint16 *tiff16, *pxm16; - int tiffstat = 0; - int ww, hh, row, col, rowcc; // int not uint v.11.03 - int bpc, nch, pm = 2, pc = 1, comp = 5; - char *tiffbuff; - - tiff = TIFFOpen(filespec,"w"); - if (! tiff) { - zmessageACK(mWin,ZTX("TIFF open failure")); - return 1; - } - - ww = pxm->ww; - hh = pxm->hh; - bpc = pxm->bpc; - nch = 3; // alpha channel removed - - TIFFSetField(tiff, TIFFTAG_IMAGEWIDTH, ww); - TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, bpc); - TIFFSetField(tiff, TIFFTAG_SAMPLESPERPIXEL, nch); - TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, pm); // RGB - TIFFSetField(tiff, TIFFTAG_PLANARCONFIG, pc); - TIFFSetField(tiff, TIFFTAG_COMPRESSION, comp); // LZW - - rowcc = TIFFScanlineSize(tiff); - tiffbuff = (char*) zmalloc(rowcc,"tiffbuff"); - - for (row = 0; row < hh; row++) - { - if (bpc == 8) - { - tiff8 = (uint8 *) tiffbuff; - pxm8 = (uint8 *) pxm->bmp + row * ww * 3; - - for (col = 0; col < ww; col++) - { - tiff8[0] = pxm8[0]; - tiff8[1] = pxm8[1]; - tiff8[2] = pxm8[2]; - pxm8 += 3; - tiff8 += nch; - } - } - - if (bpc == 16) - { - tiff16 = (uint16 *) tiffbuff; - pxm16 = (uint16 *) pxm->bmp + row * ww * 3; - - for (col = 0; col < ww; col++) - { - tiff16[0] = pxm16[0]; - tiff16[1] = pxm16[1]; - tiff16[2] = pxm16[2]; - pxm16 += 3; - tiff16 += nch; - } - } - - tiffstat = TIFFWriteScanline(tiff,tiffbuff,row,0); - if (tiffstat != 1) break; - } - - TIFFClose(tiff); - zfree(tiffbuff); - - if (tiffstat == 1) return 0; - zmessageACK(mWin,ZTX("TIFF write failure")); - return 2; -} - - -// intercept TIFF warning messages (many) // new v.9.8 - -void tiffwarninghandler(cchar *module, cchar *format, va_list ap) -{ - return; // stop flood of crap - char message[200]; - vsnprintf(message,199,format,ap); - printf("TIFF warning: %s %s \n",module,message); - return; -} - - -// Read from jpeg/png file using pixbuf library. bpc = 8. - -PXM * PXBread(cchar *filespec) // new v.9.8 -{ - GError *gerror = 0; - PXB *pxb; - PXM *pxm; - int ww, hh, px, py, nch, rowst; - uint8 *bmp1, *bmp2, *pix1, *pix2; - - pxb = gdk_pixbuf_new_from_file(filespec,&gerror); - if (! pxb) { - printf("%s \n",gerror->message); // v.10.8 - zmessageACK(mWin,ZTX("file type not supported")); - return 0; - } - - ww = gdk_pixbuf_get_width(pxb); - hh = gdk_pixbuf_get_height(pxb); - nch = gdk_pixbuf_get_n_channels(pxb); - rowst = gdk_pixbuf_get_rowstride(pxb); - bmp1 = gdk_pixbuf_get_pixels(pxb); - - pxm = PXM_make(ww,hh,8); - bmp2 = (uint8 *) pxm->bmp; - - for (py = 0; py < hh; py++) - { - pix1 = bmp1 + rowst * py; - pix2 = bmp2 + py * ww * 3; - - for (px = 0; px < ww; px++) - { - pix2[0] = pix1[0]; - pix2[1] = pix1[1]; - pix2[2] = pix1[2]; - pix1 += nch; - pix2 += 3; - } - } - - f_load_bpc = 8; // file bits per color for f_load() - g_object_unref(pxb); // (any value on disk becomes 8) - return pxm; -} - - -// Write to jpeg/png file using pixbuf library. bpc = 8. -// returns 0 if OK, +N if error. - -int PXBwrite(PXM *pxm, cchar *filespec) // new v.9.8 -{ - int ww, hh, bpc, px, py, rowst; - uint8 *bmp8, *pix8, *bmp2, *pix2; - uint16 *bmp16, *pix16; - PXB *pxb; - cchar *pext; - GError *gerror = 0; - int pxbstat; - - ww = pxm->ww; - hh = pxm->hh; - bpc = pxm->bpc; - - pxb = gdk_pixbuf_new(RGBCOLOR,0,8,ww,hh); - if (! pxb) zappcrash("pixbuf allocation failure"); - - bmp8 = (uint8 *) pxm->bmp; - bmp16 = (uint16 *) pxm->bmp; - bmp2 = gdk_pixbuf_get_pixels(pxb); - rowst = gdk_pixbuf_get_rowstride(pxb); - - if (bpc == 8) - { - for (py = 0; py < hh; py++) - { - pix8 = bmp8 + py * ww * 3; - pix2 = bmp2 + rowst * py; - - for (px = 0; px < ww; px++) - { - pix2[0] = pix8[0]; - pix2[1] = pix8[1]; - pix2[2] = pix8[2]; - pix2 += 3; - pix8 += 3; - } - } - } - - if (bpc == 16) - { - for (py = 0; py < hh; py++) - { - pix16 = bmp16 + py * ww * 3; - pix2 = bmp2 + rowst * py; - - for (px = 0; px < ww; px++) - { - pix2[0] = pix16[0] >> 8; - pix2[1] = pix16[1] >> 8; - pix2[2] = pix16[2] >> 8; - pix2 += 3; - pix16 += 3; - } - } - } - - pext = strrchr(filespec,'/'); - if (! pext) pext = filespec; - pext = strrchr(pext,'.'); - if (! pext) pext = ""; - - if (strstr(".png .PNG",pext)) - pxbstat = gdk_pixbuf_save(pxb,filespec,"png",&gerror,null); - else pxbstat = gdk_pixbuf_save(pxb,filespec,"jpeg",&gerror,"quality",jpeg_quality,null); - g_object_unref(pxb); - if (pxbstat) return 0; - - printf("%s \n",gerror->message); // v.10.8 - zmessageACK(mWin,ZTX("pixbuf write failure")); - return 1; -} - - -/************************************************************************** - PXM pixmap conversion and rescale functions -***************************************************************************/ - -// initialize PXM pixmap - allocate memory - -PXM * PXM_make(int ww, int hh, int bpc) -{ - if (ww < 1 || hh < 1 || (bpc != 8 && bpc != 16)) - zappcrash("PXM_make() %d %d %d",ww,hh,bpc); - - PXM *pxm = (PXM *) zmalloc(sizeof(PXM),"PXM"); - pxm->ww = ww; - pxm->hh = hh; - pxm->bpc = bpc; - if (bpc == 8) pxm->bmp = zmalloc(ww*hh*3,"PXM.bmp"); - if (bpc == 16) pxm->bmp = zmalloc(ww*hh*6,"PXM.bmp"); - strcpy(pxm->wmi,"rgbrgb"); - return pxm; -} - - -// free PXM pixmap - -void PXM_free(PXM *&pxm) -{ - if (! pxm) return; - if (! strEqu(pxm->wmi,"rgbrgb")) - zappcrash("PXM_free(), bad PXM"); - strcpy(pxm->wmi,"xxxxxx"); - zfree(pxm->bmp); - zfree(pxm); - pxm = 0; // v.11.01 - return; -} - - -// create a copy of an PXM pixmap - -PXM * PXM_copy(PXM *pxm1) -{ - int cc; - PXM *pxm2; - - pxm2 = PXM_make(pxm1->ww, pxm1->hh, pxm1->bpc); - cc = pxm1->ww * pxm1->hh * (pxm1->bpc / 8 * 3); - memcpy(pxm2->bmp,pxm1->bmp,cc); - return pxm2; -} - - -// create a copy of an PXM area - -PXM * PXM_copy_area(PXM *pxm1, int orgx, int orgy, int ww2, int hh2) -{ - uint8 *bmp1, *pix1, *bmp2, *pix2; - uint16 *bmp3, *pix3, *bmp4, *pix4; - PXM *pxm2 = 0; - int ww1, bpc, px1, py1, px2, py2; - - ww1 = pxm1->ww; - bpc = pxm1->bpc; - - if (bpc == 8) - { - pxm2 = PXM_make(ww2,hh2,8); - bmp1 = (uint8 *) pxm1->bmp; - bmp2 = (uint8 *) pxm2->bmp; - - for (py1 = orgy, py2 = 0; py2 < hh2; py1++, py2++) - { - for (px1 = orgx, px2 = 0; px2 < ww2; px1++, px2++) - { - pix1 = bmp1 + (py1 * ww1 + px1) * 3; - pix2 = bmp2 + (py2 * ww2 + px2) * 3; - - pix2[0] = pix1[0]; - pix2[1] = pix1[1]; - pix2[2] = pix1[2]; - pix1 += 3; - pix2 += 3; - } - } - } - - if (bpc == 16) - { - pxm2 = PXM_make(ww2,hh2,16); - bmp3 = (uint16 *) pxm1->bmp; - bmp4 = (uint16 *) pxm2->bmp; - - for (py1 = orgy, py2 = 0; py2 < hh2; py1++, py2++) - { - for (px1 = orgx, px2 = 0; px2 < ww2; px1++, px2++) - { - pix3 = bmp3 + (py1 * ww1 + px1) * 3; - pix4 = bmp4 + (py2 * ww2 + px2) * 3; - - pix4[0] = pix3[0]; - pix4[1] = pix3[1]; - pix4[2] = pix3[2]; - pix3 += 3; - pix4 += 3; - } - } - } - - return pxm2; -} - - -// convert PXM pixmap from 8/16 to 16/8 bits per color - -PXM * PXM_convbpc(PXM *pxm1) -{ - uint8 *bmp8, *pix8; - uint16 *bmp16, *pix16; - PXM *pxm2 = 0; - int ww, hh, bpc, px, py; - - ww = pxm1->ww; - hh = pxm1->hh; - bpc = pxm1->bpc; - - if (bpc == 8) // 8 > 16 - { - pxm2 = PXM_make(ww,hh,16); - bmp8 = (uint8 *) pxm1->bmp; - bmp16 = (uint16 *) pxm2->bmp; - - for (py = 0; py < hh; py++) - { - pix8 = bmp8 + py * ww * 3; - pix16 = bmp16 + py * ww * 3; - - for (px = 0; px < ww; px++) - { - pix16[0] = pix8[0] << 8; - pix16[1] = pix8[1] << 8; - pix16[2] = pix8[2] << 8; - pix8 += 3; - pix16 += 3; - } - } - } - - if (bpc == 16) // 16 > 8 - { - pxm2 = PXM_make(ww,hh,8); - bmp8 = (uint8 *) pxm2->bmp; - bmp16 = (uint16 *) pxm1->bmp; - - for (py = 0; py < hh; py++) - { - pix8 = bmp8 + py * ww * 3; - pix16 = bmp16 + py * ww * 3; - - for (px = 0; px < ww; px++) - { - pix8[0] = pix16[0] >> 8; - pix8[1] = pix16[1] >> 8; - pix8[2] = pix16[2] >> 8; - pix8 += 3; - pix16 += 3; - } - } - } - - return pxm2; -} - - -// rescale PXM pixmap to size ww2 x hh2 - -PXM * PXM_rescale(PXM *pxm1, int ww2, int hh2) -{ - void bmp8_rescale(uint8*, uint8*, int, int, int, int); - void bmp16_rescale(uint16*, uint16*, int, int, int, int); - - PXM *pxm2; - int ww1, hh1, bpc; - uint8 *bmp1, *bmp2; - uint16 *bmp3, *bmp4; - - ww1 = pxm1->ww; - hh1 = pxm1->hh; - bpc = pxm1->bpc; - - pxm2 = PXM_make(ww2,hh2,bpc); - - if (bpc == 8) { - bmp1 = (uint8 *) pxm1->bmp; - bmp2 = (uint8 *) pxm2->bmp; - bmp8_rescale(bmp1,bmp2,ww1,hh1,ww2,hh2); - } - - if (bpc == 16) { - bmp3 = (uint16 *) pxm1->bmp; - bmp4 = (uint16 *) pxm2->bmp; - bmp16_rescale(bmp3,bmp4,ww1,hh1,ww2,hh2); - } - - return pxm2; -} - - -// Copy and rescale a modified area within a PXM-16 image into the -// corresponding area of a PXM-8 image previously rescaled from the -// PXM-16 image. Keep the same mapping of input to output pixels, so -// that the modified area fits seamlessly into the PXM-8 image. Used -// when a section of an image is edited and the window image is updated. -// -// pxm1 PXM-16 image with changed area to rescale and copy -// pxm2 existing rescaled PXM-8 copy of pxm1 -// org1x, org1y pxm1 origin of area to copy (top left corner) -// ww1a, hh1a width and height of area to copy // new v.10.11 - -void PXM_update(PXM *pxm1, PXM *pxm2, int org1x, int org1y, int ww1a, int hh1a) -{ - uint16 *bmp1, *pix1; - uint8 *bmp2, *pix2; - int ww1, hh1, ww2, hh2; - int px1, py1, px2, py2; - int pxl, pyl, pxm, pym, ii; - int *px1L, *py1L; - int maxmapx, maxmapy; - int org2x, end2x, org2y, end2y; - float scalex, scaley; - float px1a, py1a, px1b, py1b; - float fx, fy, ftot; - float red, green, blue; - float *pxmap, *pymap; - - bmp1 = (uint16 *) pxm1->bmp; - bmp2 = (uint8 *) pxm2->bmp; - ww1 = pxm1->ww; - hh1 = pxm1->hh; - ww2 = pxm2->ww; - hh2 = pxm2->hh; - - scalex = 1.0 * ww1 / ww2; // compute x and y scales - scaley = 1.0 * hh1 / hh2; - - if (scalex <= 1) maxmapx = 2; // compute max input pixels - else maxmapx = scalex + 2; // mapping into output pixels - maxmapx += 1; // for both dimensions - if (scaley <= 1) maxmapy = 2; // (pixels may not be square) - else maxmapy = scaley + 2; - maxmapy += 1; - - pymap = (float *) zmalloc(hh2 * maxmapy * sizeof(float)); // maps overlap of < maxmap input - pxmap = (float *) zmalloc(ww2 * maxmapx * sizeof(float)); // pixels per output pixel - - py1L = (int *) zmalloc(hh2 * sizeof(int)); // maps first (lowest) input pixel - px1L = (int *) zmalloc(ww2 * sizeof(int)); // per output pixel - - for (py2 = 0; py2 < hh2; py2++) // loop output y-pixels - { - py1a = py2 * scaley; // corresponding input y-pixels - py1b = py1a + scaley; - if (py1b >= hh1) py1b = hh1 - 0.001; // fix precision limitation - pyl = py1a; - py1L[py2] = pyl; // 1st overlapping input pixel - - for (py1 = pyl, pym = 0; py1 < py1b; py1++, pym++) // loop overlapping input pixels - { - if (py1 < py1a) { // compute amount of overlap - if (py1+1 < py1b) fy = py1+1 - py1a; // 0.0 to 1.0 - else fy = scaley; - } - else if (py1+1 > py1b) fy = py1b - py1; - else fy = 1; - - ii = py2 * maxmapy + pym; // save it - pymap[ii] = 0.9999 * fy / scaley; - } - ii = py2 * maxmapy + pym; // set an end marker after - pymap[ii] = -1; // last overlapping pixel - } - - for (px2 = 0; px2 < ww2; px2++) // do same for x-pixels - { - px1a = px2 * scalex; - px1b = px1a + scalex; - if (px1b >= ww1) px1b = ww1 - 0.001; - pxl = px1a; - px1L[px2] = pxl; - - for (px1 = pxl, pxm = 0; px1 < px1b; px1++, pxm++) - { - if (px1 < px1a) { - if (px1+1 < px1b) fx = px1+1 - px1a; - else fx = scalex; - } - else if (px1+1 > px1b) fx = px1b - px1; - else fx = 1; - - ii = px2 * maxmapx + pxm; - pxmap[ii] = 0.9999 * fx / scalex; - } - ii = px2 * maxmapx + pxm; - pxmap[ii] = -1; - } - - org2x = org1x / scalex; // compute output image rectangle - end2x = (org1x + ww1a) / scalex + 1; // containing any part of input area - if (org2x < 0) org2x = 0; // revised v.10.12 - if (end2x > ww2) end2x = ww2; - - org2y = org1y / scaley; - end2y = (org1y + hh1a) / scaley + 1; - if (org2y < 0) org2y = 0; - if (end2y > hh2) end2y = hh2; - - for (py2 = org2y; py2 < end2y; py2++) // loop output y-pixels - { - pyl = py1L[py2]; // corresp. 1st input y-pixel - - for (px2 = org2x; px2 < end2x; px2++) // loop output x-pixels - { - pxl = px1L[px2]; // corresp. 1st input x-pixel - - red = green = blue = 0; // initz. output pixel - - for (py1 = pyl, pym = 0; ; py1++, pym++) // loop overlapping input y-pixels - { - ii = py2 * maxmapy + pym; // get y-overlap - fy = pymap[ii]; - if (fy < 0) break; // no more pixels - - for (px1 = pxl, pxm = 0; ; px1++, pxm++) // loop overlapping input x-pixels - { - ii = px2 * maxmapx + pxm; // get x-overlap - fx = pxmap[ii]; - if (fx < 0) break; // no more pixels - - ftot = fx * fy; // area overlap = x * y overlap - pix1 = bmp1 + (py1 * ww1 + px1) * 3; - red += pix1[0] * ftot; // add input pixel * overlap - green += pix1[1] * ftot; - blue += pix1[2] * ftot; - } - - pix2 = bmp2 + (py2 * ww2 + px2) * 3; // save output pixel - pix2[0] = int(red) >> 8; - pix2[1] = int(green) >> 8; - pix2[2] = int(blue) >> 8; - } - } - } - - zfree(px1L); - zfree(py1L); - zfree(pxmap); - zfree(pymap); - return; -} - - -// rotate PXM pixmap through given angle in degrees (+ = clockwise) - -PXM * PXM_rotate(PXM *pxm1, double angle) -{ - PXM * PXM_rotate8(PXM *, double); - PXM * PXM_rotate16(PXM *, double); - - PXM *pxm2 = 0; - int bpc; - - bpc = pxm1->bpc; - if (bpc == 8) pxm2 = PXM_rotate8(pxm1,angle); - if (bpc == 16) pxm2 = PXM_rotate16(pxm1,angle); - return pxm2; -} - - -/************************************************************************** - - Rescale 8 bpc image (3 x 8 bits per color) to new width and height. - The scale ratios may be different for width and height. - - Method: - The input and output images are overlayed, stretching or shrinking the - output pixels as needed. The contribution of each input pixel overlapping - an output pixel is proportional to the area of the output pixel covered by - the input pixel. The contributions of all overlaping input pixels are added. - The work is spread among Nwt threads to reduce the elapsed time on modern - computers having multiple SMP processors. - - Example: if the output image is 40% of the input image, then: - outpix[0,0] = 0.16 * inpix[0,0] + 0.16 * inpix[1,0] + 0.08 * inpix[2,0] - + 0.16 * inpix[0,1] + 0.16 * inpix[1,1] + 0.08 * inpix[2,1] - + 0.08 * inpix[0,2] + 0.08 * inpix[1,2] + 0.04 * inpix[2,2] - -*********/ - -namespace bmp8rescale { // data for threads - uint8 *pixmap1; - uint8 *pixmap2; - int ww1; - int hh1; - int ww2; - int hh2; - int *px1L; - int *py1L; - double *pxmap; - double *pymap; - int maxmapx; - int maxmapy; - int busy[max_threads]; -} - - -void bmp8_rescale(uint8 *pixmap1x, uint8 *pixmap2x, int ww1x, int hh1x, int ww2x, int hh2x) -{ - using namespace bmp8rescale; - - void * bmp8_rescale_thread(void *arg); - - int px1, py1, px2, py2; - int pxl, pyl, pxm, pym, ii; - double scalex, scaley; - double px1a, py1a, px1b, py1b; - double fx, fy; - - pixmap1 = pixmap1x; - pixmap2 = pixmap2x; - ww1 = ww1x; - hh1 = hh1x; - ww2 = ww2x; - hh2 = hh2x; - - memset(pixmap2, 0, ww2 * hh2 * 3 * sizeof(uint8)); // clear output pixmap - - scalex = 1.0 * ww1 / ww2; // compute x and y scales - scaley = 1.0 * hh1 / hh2; - - if (scalex <= 1) maxmapx = 2; // compute max input pixels - else maxmapx = scalex + 2; // mapping into output pixels - maxmapx += 1; // for both dimensions - if (scaley <= 1) maxmapy = 2; // (pixels may not be square) - else maxmapy = scaley + 2; - maxmapy += 1; - - pymap = (double *) zmalloc(hh2 * maxmapy * sizeof(double)); // maps overlap of < maxmap input - pxmap = (double *) zmalloc(ww2 * maxmapx * sizeof(double)); // pixels per output pixel - - py1L = (int *) zmalloc(hh2 * sizeof(int)); // maps first (lowest) input pixel - px1L = (int *) zmalloc(ww2 * sizeof(int)); // per output pixel - - for (py2 = 0; py2 < hh2; py2++) // loop output y-pixels - { - py1a = py2 * scaley; // corresponding input y-pixels - py1b = py1a + scaley; - if (py1b >= hh1) py1b = hh1 - 0.001; // fix precision limitation - pyl = py1a; - py1L[py2] = pyl; // 1st overlapping input pixel - - for (py1 = pyl, pym = 0; py1 < py1b; py1++, pym++) // loop overlapping input pixels - { - if (py1 < py1a) { // compute amount of overlap - if (py1+1 < py1b) fy = py1+1 - py1a; // 0.0 to 1.0 - else fy = scaley; - } - else if (py1+1 > py1b) fy = py1b - py1; - else fy = 1; - - ii = py2 * maxmapy + pym; // save it - pymap[ii] = 0.9999 * fy / scaley; - } - ii = py2 * maxmapy + pym; // set an end marker after - pymap[ii] = -1; // last overlapping pixel - } - - for (px2 = 0; px2 < ww2; px2++) // do same for x-pixels - { - px1a = px2 * scalex; - px1b = px1a + scalex; - if (px1b >= ww1) px1b = ww1 - 0.001; - pxl = px1a; - px1L[px2] = pxl; - - for (px1 = pxl, pxm = 0; px1 < px1b; px1++, pxm++) - { - if (px1 < px1a) { - if (px1+1 < px1b) fx = px1+1 - px1a; - else fx = scalex; - } - else if (px1+1 > px1b) fx = px1b - px1; - else fx = 1; - - ii = px2 * maxmapx + pxm; - pxmap[ii] = 0.9999 * fx / scalex; - } - ii = px2 * maxmapx + pxm; - pxmap[ii] = -1; - } - - for (ii = 0; ii < Nwt; ii++) { // start working threads - busy[ii] = 1; - start_detached_thread(bmp8_rescale_thread,&wtnx[ii]); - } - - for (ii = 0; ii < Nwt; ii++) // wait for all done - while (busy[ii]) zsleep(0.004); - - zfree(px1L); - zfree(py1L); - zfree(pxmap); - zfree(pymap); - return; -} - - -void * bmp8_rescale_thread(void *arg) // worker thread function -{ - using namespace bmp8rescale; - - int index = *((int *) arg); - int px1, py1, px2, py2; - int pxl, pyl, pxm, pym, ii; - uint8 *pixel1, *pixel2; - double fx, fy, ftot; - double red, green, blue; - - for (py2 = index; py2 < hh2; py2 += Nwt) // loop output y-pixels - { - pyl = py1L[py2]; // corresp. 1st input y-pixel - - for (px2 = 0; px2 < ww2; px2++) // loop output x-pixels - { - pxl = px1L[px2]; // corresp. 1st input x-pixel - - red = green = blue = 0; // initz. output pixel - - for (py1 = pyl, pym = 0; ; py1++, pym++) // loop overlapping input y-pixels - { - ii = py2 * maxmapy + pym; // get y-overlap - fy = pymap[ii]; - if (fy < 0) break; // no more pixels - - for (px1 = pxl, pxm = 0; ; px1++, pxm++) // loop overlapping input x-pixels - { - ii = px2 * maxmapx + pxm; // get x-overlap - fx = pxmap[ii]; - if (fx < 0) break; // no more pixels - - ftot = fx * fy; // area overlap = x * y overlap - pixel1 = pixmap1 + (py1 * ww1 + px1) * 3; - red += pixel1[0] * ftot; // add input pixel * overlap - green += pixel1[1] * ftot; - blue += pixel1[2] * ftot; - } - - pixel2 = pixmap2 + (py2 * ww2 + px2) * 3; // save output pixel - pixel2[0] = red; - pixel2[1] = green; - pixel2[2] = blue; - } - } - } - - busy[index] = 0; - return 0; -} - - -/************************************************************************** - - Rescale 16 bpc image (3 x 16 bits per color) to new width and height. - Identical to bmp8_rescale except for the following: - uint8 >> uint16 - xxx8 >> xxx16 - -*******/ - -namespace bmp16rescale { // data for threads - uint16 *pixmap1; - uint16 *pixmap2; - int ww1; - int hh1; - int ww2; - int hh2; - int *px1L; - int *py1L; - double *pxmap; - double *pymap; - int maxmapx; - int maxmapy; - int busy[max_threads]; -} - - -void bmp16_rescale(uint16 *pixmap1x, uint16 *pixmap2x, int ww1x, int hh1x, int ww2x, int hh2x) -{ - using namespace bmp16rescale; - - void * bmp16_rescale_thread(void *arg); - - int px1, py1, px2, py2; - int pxl, pyl, pxm, pym, ii; - double scalex, scaley; - double px1a, py1a, px1b, py1b; - double fx, fy; - - pixmap1 = pixmap1x; - pixmap2 = pixmap2x; - ww1 = ww1x; - hh1 = hh1x; - ww2 = ww2x; - hh2 = hh2x; - - memset(pixmap2, 0, ww2 * hh2 * 3 * sizeof(uint16)); // clear output pixmap - - scalex = 1.0 * ww1 / ww2; // compute x and y scales - scaley = 1.0 * hh1 / hh2; - - if (scalex <= 1) maxmapx = 2; // compute max input pixels - else maxmapx = scalex + 2; // mapping into output pixels - maxmapx += 1; // for both dimensions - if (scaley <= 1) maxmapy = 2; // (pixels may not be square) - else maxmapy = scaley + 2; - maxmapy += 1; - - pymap = (double *) zmalloc(hh2 * maxmapy * sizeof(double)); // maps overlap of < maxmap input - pxmap = (double *) zmalloc(ww2 * maxmapx * sizeof(double)); // pixels per output pixel - - py1L = (int *) zmalloc(hh2 * sizeof(int)); // maps first (lowest) input pixel - px1L = (int *) zmalloc(ww2 * sizeof(int)); // per output pixel - - for (py2 = 0; py2 < hh2; py2++) // loop output y-pixels - { - py1a = py2 * scaley; // corresponding input y-pixels - py1b = py1a + scaley; - if (py1b >= hh1) py1b = hh1 - 0.001; // fix precision limitation - pyl = py1a; - py1L[py2] = pyl; // 1st overlapping input pixel - - for (py1 = pyl, pym = 0; py1 < py1b; py1++, pym++) // loop overlapping input pixels - { - if (py1 < py1a) { // compute amount of overlap - if (py1+1 < py1b) fy = py1+1 - py1a; // 0.0 to 1.0 - else fy = scaley; - } - else if (py1+1 > py1b) fy = py1b - py1; - else fy = 1; - - ii = py2 * maxmapy + pym; // save it - pymap[ii] = 0.9999 * fy / scaley; - } - ii = py2 * maxmapy + pym; // set an end marker after - pymap[ii] = -1; // last overlapping pixel - } - - for (px2 = 0; px2 < ww2; px2++) // do same for x-pixels - { - px1a = px2 * scalex; - px1b = px1a + scalex; - if (px1b >= ww1) px1b = ww1 - 0.001; - pxl = px1a; - px1L[px2] = pxl; - - for (px1 = pxl, pxm = 0; px1 < px1b; px1++, pxm++) - { - if (px1 < px1a) { - if (px1+1 < px1b) fx = px1+1 - px1a; - else fx = scalex; - } - else if (px1+1 > px1b) fx = px1b - px1; - else fx = 1; - - ii = px2 * maxmapx + pxm; - pxmap[ii] = 0.9999 * fx / scalex; - } - ii = px2 * maxmapx + pxm; - pxmap[ii] = -1; - } - - for (ii = 0; ii < Nwt; ii++) { // start working threads - busy[ii] = 1; - start_detached_thread(bmp16_rescale_thread,&wtnx[ii]); - } - - for (ii = 0; ii < Nwt; ii++) // wait for all done - while (busy[ii]) zsleep(0.004); - - zfree(px1L); - zfree(py1L); - zfree(pxmap); - zfree(pymap); - return; -} - - -void * bmp16_rescale_thread(void *arg) // worker thread function -{ - using namespace bmp16rescale; - - int index = *((int *) arg); - int px1, py1, px2, py2; - int pxl, pyl, pxm, pym, ii; - uint16 *pixel1, *pixel2; - double fx, fy, ftot; - double red, green, blue; - - for (py2 = index; py2 < hh2; py2 += Nwt) // loop output y-pixels - { - pyl = py1L[py2]; // corresp. 1st input y-pixel - - for (px2 = 0; px2 < ww2; px2++) // loop output x-pixels - { - pxl = px1L[px2]; // corresp. 1st input x-pixel - - red = green = blue = 0; // initz. output pixel - - for (py1 = pyl, pym = 0; ; py1++, pym++) // loop overlapping input y-pixels - { - ii = py2 * maxmapy + pym; // get y-overlap - fy = pymap[ii]; - if (fy < 0) break; // no more pixels - - for (px1 = pxl, pxm = 0; ; px1++, pxm++) // loop overlapping input x-pixels - { - ii = px2 * maxmapx + pxm; // get x-overlap - fx = pxmap[ii]; - if (fx < 0) break; // no more pixels - - ftot = fx * fy; // area overlap = x * y overlap - pixel1 = pixmap1 + (py1 * ww1 + px1) * 3; - red += pixel1[0] * ftot; // add input pixel * overlap - green += pixel1[1] * ftot; - blue += pixel1[2] * ftot; - } - - pixel2 = pixmap2 + (py2 * ww2 + px2) * 3; // save output pixel - pixel2[0] = red; - pixel2[1] = green; - pixel2[2] = blue; - } - } - } - - busy[index] = 0; - return 0; -} - - -/************************************************************************** - - PXM *pxm2 = PXM_rotate8(PXM *pxm1, double angle) - - Rotate PXM-8 pixmap through an arbitrary angle (degrees). - - The returned image has the same size as the original, but the - pixmap size is increased to accomodate the rotated image. - (e.g. a 100x100 image rotated 45 deg. needs a 142x142 pixmap). - The parameters ww and hh are the dimensions of the input - pixmap, and are updated to the dimensions of the output pixmap. - - The space added around the rotated image is black (RGB 0,0,0). - Angle is in degrees. Positive direction is clockwise. - Speed is about 3 million pixels/sec/thread for a 2.4 GHz CPU. - Loss of resolution is less than 1 pixel. - - Work is divided among Nwt threads to gain speed. - - v.9.3: affine transform instead of trig functions, for speed - -***************************************************************************/ - -namespace rotpxm8 { - int busy = 0; - uint8 *pixmap1; - uint8 *pixmap2; - int ww1; - int hh1; - int ww2; - int hh2; - double angle; -} - - -PXM * PXM_rotate8(PXM *pxm1, double anglex) -{ - using namespace rotpxm8; - - void *PXM_rotate8_thread(void *); - - int cc, ii; - PXM *pxm2; - - ww1 = pxm1->ww; - hh1 = pxm1->hh; - pixmap1 = (uint8 *) pxm1->bmp; - angle = anglex; - - while (angle < -180) angle += 360; // normalize, -180 to +180 - while (angle > 180) angle -= 360; - angle = angle * pi / 180; // radians, -pi to +pi - - if (fabs(angle) < 0.001) { // angle = 0 within my precision - pxm2 = PXM_make(ww1,hh1,8); // return a copy of the input - pixmap2 = (uint8 *) pxm2->bmp; - cc = ww1 * hh1 * 3 * sizeof(uint8); - memcpy(pixmap2,pixmap1,cc); - return pxm2; - } - - ww2 = ww1*fabs(cos(angle)) + hh1*fabs(sin(angle)); // rectangle containing rotated image - hh2 = ww1*fabs(sin(angle)) + hh1*fabs(cos(angle)); - - pxm2 = PXM_make(ww2,hh2,8); - pixmap2 = (uint8 *) pxm2->bmp; - - for (ii = 0; ii < Nwt; ii++) // start worker threads - start_detached_thread(PXM_rotate8_thread,&wtnx[ii]); - zadd_locked(busy,+Nwt); - - while (busy) zsleep(0.004); // wait for completion - return pxm2; -} - - -void * PXM_rotate8_thread(void *arg) -{ - using namespace rotpxm8; - - int index = *((int *) (arg)); - int px2, py2, px0, py0; - uint8 *pix0, *pix1, *pix2, *pix3; - double px1, py1; - double f0, f1, f2, f3, red, green, blue; - double a, b, d, e, ww15, hh15, ww25, hh25; - - ww15 = 0.5 * ww1; - hh15 = 0.5 * hh1; - ww25 = 0.5 * ww2; - hh25 = 0.5 * hh2; - - a = cos(angle); - b = sin(angle); - d = - sin(angle); - e = cos(angle); - - for (py2 = index; py2 < hh2; py2 += Nwt) // loop through output pixels - for (px2 = 0; px2 < ww2; px2++) // outer loop y - { - px1 = a * (px2 - ww25) + b * (py2 - hh25) + ww15; // (px1,py1) = corresponding v.9.3 - py1 = d * (px2 - ww25) + e * (py2 - hh25) + hh15; // point within input pixels - - px0 = px1; // pixel containing (px1,py1) - py0 = py1; - - if (px1 < 0 || px0 >= ww1-1 || py1 < 0 || py0 >= hh1-1) { // if outside input pixel array - pix2 = pixmap2 + (py2 * ww2 + px2) * 3; // output is black - pix2[0] = pix2[1] = pix2[2] = 0; - continue; - } - - pix0 = pixmap1 + (py0 * ww1 + px0) * 3; // 4 input pixels based at (px0,py0) - pix1 = pix0 + ww1 * 3; - pix2 = pix0 + 3; - pix3 = pix1 + 3; - - f0 = (px0+1 - px1) * (py0+1 - py1); // overlap of (px1,py1) - f1 = (px0+1 - px1) * (py1 - py0); // in each of the 4 pixels - f2 = (px1 - px0) * (py0+1 - py1); - f3 = (px1 - px0) * (py1 - py0); - - red = f0 * pix0[0] + f1 * pix1[0] + f2 * pix2[0] + f3 * pix3[0]; // sum the weighted inputs - green = f0 * pix0[1] + f1 * pix1[1] + f2 * pix2[1] + f3 * pix3[1]; - blue = f0 * pix0[2] + f1 * pix1[2] + f2 * pix2[2] + f3 * pix3[2]; - - pix2 = pixmap2 + (py2 * ww2 + px2) * 3; // output pixel - pix2[0] = red; - pix2[1] = green; - pix2[2] = blue; - } - - zadd_locked(busy,-1); - return 0; -} - - -/************************************************************************** - - PXM *pxm2 = PXM_rotate16(PXM *pxm1, double angle) - Rotate PXM-16 pixmap through an arbitrary angle (degrees). - Identical to PXM_rotate8() except for: - uint8 >> uint16 - rotpxm8 >> rotpxm16 - 8 >> 16 - -**********/ - -namespace rotpxm16 { - int busy = 0; - uint16 *pixmap1; - uint16 *pixmap2; - int ww1; - int hh1; - int ww2; - int hh2; - double angle; -} - - -PXM * PXM_rotate16(PXM *pxm1, double anglex) -{ - using namespace rotpxm16; - - void *PXM_rotate16_thread(void *); - - int cc, ii; - PXM *pxm2; - - ww1 = pxm1->ww; - hh1 = pxm1->hh; - pixmap1 = (uint16 *) pxm1->bmp; - angle = anglex; - - while (angle < -180) angle += 360; // normalize, -180 to +180 - while (angle > 180) angle -= 360; - angle = angle * pi / 180; // radians, -pi to +pi - - if (fabs(angle) < 0.001) { // angle = 0 within my precision - pxm2 = PXM_make(ww1,hh1,16); // return a copy of the input - pixmap2 = (uint16 *) pxm2->bmp; - cc = ww1 * hh1 * 3 * sizeof(uint16); - memcpy(pixmap2,pixmap1,cc); - return pxm2; - } - - ww2 = ww1*fabs(cos(angle)) + hh1*fabs(sin(angle)); // rectangle containing rotated image - hh2 = ww1*fabs(sin(angle)) + hh1*fabs(cos(angle)); - - pxm2 = PXM_make(ww2,hh2,16); - pixmap2 = (uint16 *) pxm2->bmp; - - for (ii = 0; ii < Nwt; ii++) // start worker threads - start_detached_thread(PXM_rotate16_thread,&wtnx[ii]); - zadd_locked(busy,+Nwt); - - while (busy) zsleep(0.004); // wait for completion - return pxm2; -} - - -void * PXM_rotate16_thread(void *arg) -{ - using namespace rotpxm16; - - int index = *((int *) (arg)); - int px2, py2, px0, py0; - uint16 *pix0, *pix1, *pix2, *pix3; - double px1, py1; - double f0, f1, f2, f3, red, green, blue; - double a, b, d, e, ww15, hh15, ww25, hh25; - - ww15 = 0.5 * ww1; - hh15 = 0.5 * hh1; - ww25 = 0.5 * ww2; - hh25 = 0.5 * hh2; - - a = cos(angle); - b = sin(angle); - d = - sin(angle); - e = cos(angle); - - for (py2 = index; py2 < hh2; py2 += Nwt) // loop through output pixels - for (px2 = 0; px2 < ww2; px2++) // outer loop y - { - px1 = a * (px2 - ww25) + b * (py2 - hh25) + ww15; // (px1,py1) = corresponding v.9.3 - py1 = d * (px2 - ww25) + e * (py2 - hh25) + hh15; // point within input pixels - - px0 = px1; // pixel containing (px1,py1) - py0 = py1; - - if (px1 < 0 || px0 >= ww1-1 || py1 < 0 || py0 >= hh1-1) { // if outside input pixel array - pix2 = pixmap2 + (py2 * ww2 + px2) * 3; // output is black - pix2[0] = pix2[1] = pix2[2] = 0; - continue; - } - - pix0 = pixmap1 + (py0 * ww1 + px0) * 3; // 4 input pixels based at (px0,py0) - pix1 = pix0 + ww1 * 3; - pix2 = pix0 + 3; - pix3 = pix1 + 3; - - f0 = (px0+1 - px1) * (py0+1 - py1); // overlap of (px1,py1) - f1 = (px0+1 - px1) * (py1 - py0); // in each of the 4 pixels - f2 = (px1 - px0) * (py0+1 - py1); - f3 = (px1 - px0) * (py1 - py0); - - red = f0 * pix0[0] + f1 * pix1[0] + f2 * pix2[0] + f3 * pix3[0]; // sum the weighted inputs - green = f0 * pix0[1] + f1 * pix1[1] + f2 * pix2[1] + f3 * pix3[1]; - blue = f0 * pix0[2] + f1 * pix1[2] + f2 * pix2[2] + f3 * pix3[2]; - - pix2 = pixmap2 + (py2 * ww2 + px2) * 3; // output pixel - pix2[0] = red; - pix2[1] = green; - pix2[2] = blue; - } - - zadd_locked(busy,-1); - return 0; -} - - -// replace blue = 0 pixels with blue = 2 in a 16-bit pixmap -// (blue = 0 reserved for pixels voided by warp or overlay offsets) -// all callers of vpixel() need to do this -// needs about 0.013 seconds for 10 megapixel image and 3.3 GHz processor - -void PXM_fixblue(PXM *pxm) // v.11.07 -{ - int size; - uint16 *pixel, *pixel0, *pixelN; - - size = pxm->ww * pxm->hh * 3; - pixel0 = (uint16 *) pxm->bmp + 2; - pixelN = (uint16 *) pixel0 + size; - - for (pixel = pixel0; pixel < pixelN; pixel += 3) // +3 is +6 bytes - if (! *pixel) *pixel = 2; - - return; -} - - - diff -Nru fotoxx-11.11.1/fotoxx-12.01.2.cc fotoxx-12.01.2/fotoxx-12.01.2.cc --- fotoxx-11.11.1/fotoxx-12.01.2.cc 1970-01-01 00:00:00.000000000 +0000 +++ fotoxx-12.01.2/fotoxx-12.01.2.cc 2012-01-04 08:47:11.000000000 +0000 @@ -0,0 +1,5212 @@ +/************************************************************************** + + Fotoxx edit photos and manage collections + + Copyright 2007 2008 2009 2010 2011 2012 Michael Cornelison + Source URL: http://kornelix.squarespace.com/fotoxx + Contact: kornelix2@googlemail.com + + 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 http://www.gnu.org/licenses/. + +***************************************************************************/ + +#define EX // disable extern declarations +#include "fotoxx.h" + + +char *initial_file = 0; // initial file on command line + +// fotoxx main program + +int main(int argc, char *argv[]) +{ + char lang[8] = "", *pp; + int err; + struct stat statb; + int Fclone=0, cloxx=0, cloyy=0, cloww=0, clohh=0; + GdkScreen *screen; + int Fsyncfiles = 0; + int Ftranslate = 0; + + if (argc > 1 && strEqu(argv[1],"-v")) { + printf(fversion "\n"); // print version and exit + return 0; + } + + // initialize externals to default values + // (saved parameters will override) + + Ffirsttime = 1; // first time startup v.11.11 + maxcolor = 0xffff; + for (int ii = 0; ii < 8; ii++) wtnx[ii] = ii; + strcpy(jpeg_quality,def_jpeg_quality); + mwgeom[0] = mwgeom[1] = 100; // default main window geometry v.11.07 + mwgeom[2] = 700; mwgeom[3] = 500; + Mscale = 1.0; + trimsize[0] = 1600; + trimsize[1] = 1000; + editresize[0] = 1600; + editresize[1] = 1200; + batchresize[0] = 1600; + batchresize[1] = 1200; + emailsize[0] = 1000; + emailsize[1] = 800; + lens_mm = lens_settings[0] = 35; // pano lens parameters v.12.01 + lens_bow = lens_settings[1] = 0; + gridcount[0] = gridcount[1] = 5; // set default grid line counts + sa_pixRGB = &green; + ss_funcs[0] = 1; + fsync_lock = "fotoxx_syncfiles"; // file sync lock file v.11.12 + tbar_style = "both"; // default toolbar style v.12.01 + startdisplay = "blank"; // start with blank window v.12.01 + Fwarnoverwrite = 1; // warn original file overwrite v.12.01 + + // command line args + + gtk_init(&argc,&argv); // initz. GTK & strip GTK command line params + + for (int ii = 1; ii < argc; ii++) // command line parameters + { + pp = argv[ii]; + if (strcmpv(pp,"-debug","-d",null)) // -debug + Fdebug = 1; + else if (strcmpv(pp,"-lang","-l",null) && argc > ii+1) // -lang lc_RC (language/region code) + strncpy0(lang,argv[++ii],7); + else if (strcmpv(pp,"-clone1","-c1",null)) // -clone1 (clone1/2 not user options) + Fclone = 1; + else if (strcmpv(pp,"-clone2","-c2",null)) { // -clone2 xpos ypos v.11.07 + Fclone = 2; + cloxx = atoi(argv[ii+1]); // window position and size + cloyy = atoi(argv[ii+2]); // passed from parent instance + cloww = atoi(argv[ii+3]); + clohh = atoi(argv[ii+4]); + ii += 4; + } + else if (strcmpv(pp,"-slideshow","-ss",null) && argc > ii+1) // -slideshow /image/file.jpg v.11.04 + SS_imagefile = strdupz(argv[++ii]); + else if (strcmpv(pp,"-music","-m",null) && argc > ii+1) // -music /music/file.ogg v.11.04 + SS_musicfile = strdupz(argv[++ii]); + else if (strcmpv(pp,"-recent","-r",null)) // recent files gallery v.11.07 + Frecent = 1; + else if (strcmpv(pp,"-previous","-prev","-p",null)) // open previous file v.11.07 + Fprev = 1; + else if (strcmpv(pp,"-blank","-b",null)) // start with blank window v.12.01 + Fblank = 1; + else if (strcmpv(pp,"-syncfiles",null)) { // spawned sync files process v.11.11 + Fsyncfiles = 1; + pp = argv[++ii]; + if (strEqu(pp,"auto")) Fautosync = 1; // set auto or manual sync + if (strEqu(pp,"manual")) Fmansync = 1; + } + else if (strcmpv(pp,"-translate","-t",null)) // start online translation v.11.12 + Ftranslate = 1; + else initial_file = strdupz(pp); // must be initial file or directory + } + + zinitapp("fotoxx",null); // get app directories + ZTXinit(lang); // setup locale and translations + + // get files in user directory /home//.fotoxx/* + + *topdirk_file = 0; + strncatv(topdirk_file,199,get_zuserdir(),"/top_directory",null); // top_directory + + *search_index_file = 0; + strncatv(search_index_file,199,get_zuserdir(),"/search_index",null); // search_index + + *tags_defined_file = 0; + strncatv(tags_defined_file,199,get_zuserdir(),"/tags_defined",null); // tags_defined + + *recentfiles_file = 0; + strncatv(recentfiles_file,199,get_zuserdir(),"/recent_files",null); // recent_files + + *saved_areas_dirk = 0; + strncatv(saved_areas_dirk,199,get_zuserdir(),"/saved_areas/",null); // saved_areas/ + err = stat(saved_areas_dirk,&statb); + if (err) mkdir(saved_areas_dirk,0750); + + *collections_dirk = 0; + strncatv(collections_dirk,199,get_zuserdir(),"/collections/",null); // collections/ + err = stat(collections_dirk,&statb); + if (err) mkdir(collections_dirk,0750); + + *saved_curves_dirk = 0; + strncatv(saved_curves_dirk,199,get_zuserdir(),"/saved_curves/",null); // saved_curves/ + err = stat(saved_curves_dirk,&statb); + if (err) mkdir(saved_curves_dirk,0750); + + *annotations_dirk = 0; + strncatv(annotations_dirk,199,get_zuserdir(),"/annotations/",null); // annotations/ + err = stat(annotations_dirk,&statb); + if (err) mkdir(annotations_dirk,0750); + + load_params(); // restore parameters from last session + + if (Fsyncfiles) { // this is the spawned sync process v.11.11 + gtk_init_add((GtkFunction) syncfiles_func,0); // do the sync function only + gtk_main(); + return 0; + } + + if (! Fsyncfiles && ! Fclone) { // this is the user GUI process + printf("spawn sync files subprocess \n"); + err = system("fotoxx -syncfiles auto &"); // spawn process for sync files + if (err) { + printf("error: %s \n",wstrerror(err)); // quit if failed + return 1; + } + } + + mWin = gtk_window_new(GTK_WINDOW_TOPLEVEL); // create main window + gtk_window_set_title(MWIN,fversion); + + mVbox = gtk_vbox_new(0,0); // add vert. packing box + gtk_container_add(GTK_CONTAINER(mWin),mVbox); + + mMbar = create_menubar(mVbox); // add menus / sub-menus + + if (Ftranslate) { // start online translation v.11.12 + zfuncs::F1_help_topic = "translate"; + ZTX_translation_start(mWin); + } + + GtkWidget *mFile = add_menubar_item(mMbar,ZTX("File"),topmenufunc); + add_submenu_item(mFile, ZTX("Image Gallery"), m_gallery); + add_submenu_item(mFile, ZTX("Clone 50/50"), m_clone1); + add_submenu_item(mFile, ZTX("Clone Overlay"), m_clone2); + add_submenu_item(mFile, ZTX("Open Image File"), m_open); + add_submenu_item(mFile, ZTX("Open in New Window"), m_open_newin); + add_submenu_item(mFile, ZTX("Open Previous File"), m_previous); + add_submenu_item(mFile, ZTX("Open Recent File"), m_recent); + add_submenu_item(mFile, ZTX("Save to Same File"), m_save); + add_submenu_item(mFile, ZTX("Save to New Version"), m_savevers); + add_submenu_item(mFile, ZTX("Save to New File"), m_saveas); + add_submenu_item(mFile, ZTX("Create Blank Image"), m_create); + add_submenu_item(mFile, ZTX("Trash Image File"), m_trash); + add_submenu_item(mFile, ZTX("Rename Image File"), m_rename); + add_submenu_item(mFile, ZTX("Batch Rename Files"), m_batchrename); + add_submenu_item(mFile, ZTX("Print Image File"), m_print); + add_submenu_item(mFile, ZTX("Quit fotoxx"), m_quit); + + GtkWidget *mTools = add_menubar_item(mMbar,ZTX("Tools"),topmenufunc); + add_submenu_item(mTools, ZTX("Manage Collections"), m_manage_collections); + add_submenu_item(mTools, ZTX("Move Collections"), m_move_collections); + add_submenu_item(mTools, ZTX("Batch Convert"), m_batchconvert); + add_submenu_item(mTools, ZTX("Convert RAW files"), m_conv_raw); + add_submenu_item(mTools, ZTX("Slide Show"), m_slideshow); + add_submenu_item(mTools, ZTX("Synchronize Files"), m_syncfiles); + add_submenu_item(mTools, ZTX("Show RGB"), m_show_RGB); + add_submenu_item(mTools, ZTX("Grid Lines"), m_gridlines); + add_submenu_item(mTools, ZTX("Burn Images to CD/DVD"), m_burn); + add_submenu_item(mTools, ZTX("E-mail Images"), m_email); + add_submenu_item(mTools, ZTX("Check Monitor"), m_moncheck); + add_submenu_item(mTools, ZTX("Monitor Gamma"), m_mongamma); + add_submenu_item(mTools, ZTX("Brightness Distribution"), m_histogram); + add_submenu_item(mTools, ZTX("Change Language"), m_lang); + add_submenu_item(mTools, "Edit Translations", m_translate); + add_submenu_item(mTools, ZTX("Menu and Launcher"), m_menu_launcher); + add_submenu_item(mTools, ZTX("User Settings"), m_settings); + add_submenu_item(mTools, ZTX("Memory Usage"), m_memory_usage); + + GtkWidget *mInfo = add_menubar_item(mMbar,"Info",topmenufunc); + add_submenu_item(mInfo, ZTX("Edit Caption/Comments"), m_edit_cctext); + add_submenu_item(mInfo, ZTX("Edit Tags"), m_edit_tags); + add_submenu_item(mInfo, ZTX("Manage Tags"), m_manage_tags); + add_submenu_item(mInfo, ZTX("Batch Add Tags"), m_batchAddTags); + add_submenu_item(mInfo, ZTX("Batch Delete Tag"), m_batchDelTag); + add_submenu_item(mInfo, ZTX("View Info (short)"), m_info_view_short); + add_submenu_item(mInfo, ZTX("View Info (long)"), m_info_view_long); + add_submenu_item(mInfo, ZTX("Edit Info"), m_info_edit); + add_submenu_item(mInfo, ZTX("Delete Info"), m_info_delete); + add_submenu_item(mInfo, ZTX("Search Images"), m_search_images); + add_submenu_item(mInfo, ZTX("Search Metadata"), m_search_metadata); + + GtkWidget *mSelect = add_menubar_item(mMbar,ZTX("Select"),topmenufunc); + add_submenu_item(mSelect, ZTX("Select"), m_select); + add_submenu_item(mSelect, ZTX("Show"), m_select_show); + add_submenu_item(mSelect, ZTX("Hide"), m_select_hide); + add_submenu_item(mSelect, ZTX("Enable"), m_select_enable); + add_submenu_item(mSelect, ZTX("Disable"), m_select_disable); + add_submenu_item(mSelect, ZTX("Invert"), m_select_invert); + add_submenu_item(mSelect, ZTX("Unselect"), m_select_unselect); + add_submenu_item(mSelect, ZTX("Copy"), m_select_copy); + add_submenu_item(mSelect, ZTX("Paste"), m_select_paste); + add_submenu_item(mSelect, ZTX("Open"), m_select_open); + add_submenu_item(mSelect, ZTX("Save"), m_select_save); + add_submenu_item(mSelect, ZTX("Select Whole Image"), m_select_whole_image); + add_submenu_item(mSelect, ZTX("Select and Edit"), m_select_edit); + + GtkWidget *mTransf = add_menubar_item(mMbar,ZTX("Transform"),topmenufunc); + add_submenu_item(mTransf, ZTX("Rotate Image"), m_rotate); + add_submenu_item(mTransf, ZTX("Trim Image"), m_trim); + add_submenu_item(mTransf, ZTX("Auto-Trim Image"), m_autotrim); + add_submenu_item(mTransf, ZTX("Resize Image"), m_resize); + add_submenu_item(mTransf, ZTX("Annotate Image"), m_annotate); + add_submenu_item(mTransf, ZTX("Flip Image"), m_flip); + add_submenu_item(mTransf, ZTX("Make Negative"), m_negate); + add_submenu_item(mTransf, ZTX("Unbend Image"), m_unbend); + add_submenu_item(mTransf, ZTX("Keystone Correction"), m_keystone); + add_submenu_item(mTransf, ZTX("Warp Image (area)"), m_warp_area); + add_submenu_item(mTransf, ZTX("Warp Image (curved)"), m_warp_curved); + add_submenu_item(mTransf, ZTX("Warp Image (linear)"), m_warp_linear); + add_submenu_item(mTransf, ZTX("Warp Image (affine)"), m_warp_affine); + + GtkWidget *mRetouch = add_menubar_item(mMbar,ZTX("Retouch"),topmenufunc); + add_submenu_item(mRetouch, ZTX("Brightness/Color"), m_tune); + add_submenu_item(mRetouch, ZTX("Gamma Curves"), m_gamma); + add_submenu_item(mRetouch, ZTX("Expand Brightness"), m_xbrange); + add_submenu_item(mRetouch, ZTX("Flatten Brightness"), m_flatten); + add_submenu_item(mRetouch, ZTX("Brightness Ramp"), m_brightramp); + add_submenu_item(mRetouch, ZTX("Tone Mapping"), m_tonemap); + add_submenu_item(mRetouch, ZTX("White Balance"), m_whitebal); + add_submenu_item(mRetouch, ZTX("Match Colors"), m_match_color); + add_submenu_item(mRetouch, "DRGB", m_DRGB); + add_submenu_item(mRetouch, ZTX("Revise RGB"), m_revise_RGB); + add_submenu_item(mRetouch, ZTX("Red Eyes"), m_redeye); + add_submenu_item(mRetouch, ZTX("Blur Image"), m_blur); + add_submenu_item(mRetouch, ZTX("Sharpen Image"), m_sharpen); + add_submenu_item(mRetouch, ZTX("Reduce Noise"), m_denoise); + add_submenu_item(mRetouch, ZTX("Smart Erase"), m_smart_erase); + add_submenu_item(mRetouch, ZTX("Remove Dust"), m_dust); + add_submenu_item(mRetouch, ZTX("Fix Stuck Pixels"), m_stuckpix); + add_submenu_item(mRetouch, ZTX("Edit Pixels"), m_pixedit); + + GtkWidget *mArt = add_menubar_item(mMbar,ZTX("Art"),topmenufunc); + add_submenu_item(mArt, ZTX("Color Depth"), m_colordep); + add_submenu_item(mArt, ZTX("Drawing"), m_draw); + add_submenu_item(mArt, ZTX("Outlines"), m_outlines); + add_submenu_item(mArt, ZTX("Embossing"), m_emboss); + add_submenu_item(mArt, ZTX("Tiles"), m_tiles); + add_submenu_item(mArt, ZTX("Dots"), m_dots); + add_submenu_item(mArt, ZTX("Painting"), m_painting); + + GtkWidget *mComb = add_menubar_item(mMbar,ZTX("Combine"),topmenufunc); + add_submenu_item(mComb, ZTX("High Dynamic Range"), m_HDR); + add_submenu_item(mComb, ZTX("High Depth of Field"), m_HDF); + add_submenu_item(mComb, ZTX("Stack / Paint"), m_STP); + add_submenu_item(mComb, ZTX("Stack / Noise"), m_STN); + add_submenu_item(mComb, ZTX("Panorama"), m_pano); + add_submenu_item(mComb, ZTX("Vertical Panorama"), m_vpano); + + GtkWidget *mPlugins = add_menubar_item(mMbar,"Plugins",topmenufunc); // build plugin menu v.11.03 + add_submenu_item(mPlugins,ZTX("Edit Plugins"),m_edit_plugins); + for (int ii = 0; ii < Nplugins; ii++) { + pp = strstr(plugins[ii]," = "); + if (! pp) continue; + *pp = 0; + add_submenu_item(mPlugins,plugins[ii],m_run_plugin); + *pp = ' '; + } + + GtkWidget *mHelp = add_menubar_item(mMbar,ZTX("Help"),topmenufunc); + add_submenu_item(mHelp, ZTX("About"), m_help); + add_submenu_item(mHelp, ZTX("User Guide"), m_help); + add_submenu_item(mHelp, ZTX("User Guide Changes"), m_help); + add_submenu_item(mHelp, ZTX("Edit Functions Summary"), m_help); + add_submenu_item(mHelp, ZTX("Change Log"), m_help); + add_submenu_item(mHelp, ZTX("Translations"), m_help); + add_submenu_item(mHelp, ZTX("Home Page"), m_help); + add_submenu_item(mHelp, "README", m_help); + + mTbar = create_toolbar(mVbox); // toolbar buttons + add_toolbar_button(mTbar, ZTX("Gallery"), ZTX("Image Gallery"), "gallery.png", m_gallery); + add_toolbar_button(mTbar, ZTX("Open"), ZTX("Open Image File"), "open.png", m_open); + add_toolbar_button(mTbar, ZTX("Prev"), ZTX("Open Previous File"), "prev.png", m_prev); + add_toolbar_button(mTbar, ZTX("Next"), ZTX("Open Next File"), "next.png", m_next); + add_toolbar_button(mTbar, "Zoom+", ZTX("Zoom-in (bigger)"), "zoom+.png", m_zoom); + add_toolbar_button(mTbar, "Zoom-", ZTX("Zoom-out (smaller)"), "zoom-.png", m_zoom); + add_toolbar_button(mTbar, ZTX("Undo"), ZTX("Undo One Edit"), "undo.png", m_undo); + add_toolbar_button(mTbar, ZTX("Redo"), ZTX("Redo One Edit"), "redo.png", m_redo); + add_toolbar_button(mTbar, "separator", null, null, null); + add_toolbar_button(mTbar, "separator", null, null, null); + add_toolbar_button(mTbar, ZTX("Save"), ZTX("Save to Same File"), "save.png", m_save); + add_toolbar_button(mTbar, ZTX("Save+V"), ZTX("Save to New Version"), "save+V.png", m_savevers); + add_toolbar_button(mTbar, ZTX("Save+F"), ZTX("Save to New File"), "save+F.png", m_saveas); + add_toolbar_button(mTbar, ZTX("Trash"), ZTX("Move Image to Trash"), "trash.png", m_trash); + add_toolbar_button(mTbar, "separator", null, null, null); + add_toolbar_button(mTbar, "separator", null, null, null); + add_toolbar_button(mTbar, ZTX("Quit"), ZTX("Quit fotoxx"), "quit.png", m_quit); + add_toolbar_button(mTbar, ZTX("Help"), ZTX("Fotoxx Essentials"), "help.png", m_help); + + if (strEqu(tbar_style,"icons")) // set toolbar style v.12.01 + gtk_toolbar_set_style(GTK_TOOLBAR(mTbar),GTK_TOOLBAR_ICONS); + else if (strEqu(tbar_style,"text")) + gtk_toolbar_set_style(GTK_TOOLBAR(mTbar),GTK_TOOLBAR_TEXT); + else gtk_toolbar_set_style(GTK_TOOLBAR(mTbar),GTK_TOOLBAR_BOTH); + + drWin = gtk_drawing_area_new(); // add drawing window + gtk_box_pack_start(GTK_BOX(mVbox),drWin,1,1,0); + + STbar = create_stbar(mVbox); // add status bar + + G_SIGNAL(mWin,"delete_event",delete_event,0); // connect signals + G_SIGNAL(mWin,"destroy",destroy_event,0); + G_SIGNAL(drWin,"expose-event",mwpaint1,0); + + gtk_widget_add_events(drWin,GDK_BUTTON_PRESS_MASK); // connect mouse events + gtk_widget_add_events(drWin,GDK_BUTTON_RELEASE_MASK); + gtk_widget_add_events(drWin,GDK_BUTTON_MOTION_MASK); // motion with button pressed + gtk_widget_add_events(drWin,GDK_POINTER_MOTION_MASK); // pointer motion + gtk_widget_add_events(drWin,GDK_SCROLL_MASK); // scroll wheel v.12.01 + G_SIGNAL(drWin,"button-press-event",mouse_event,0); + G_SIGNAL(drWin,"button-release-event",mouse_event,0); + G_SIGNAL(drWin,"motion-notify-event",mouse_event,0); + G_SIGNAL(drWin,"scroll-event",mouse_event,0); + + G_SIGNAL(mWin,"key-press-event",KBpress,0); // connect KB events + G_SIGNAL(mWin,"key-release-event",KBrelease,0); + + drag_drop_connect(drWin,m_open_drag); // connect drag-drop event + + gtk_window_move(MWIN,mwgeom[0],mwgeom[1]); // main window geometry + gtk_window_set_default_size(MWIN,mwgeom[2],mwgeom[3]); // (defaults or last session params) + gtk_widget_show_all(mWin); // show all widgets + + if (Fclone == 1) { // clone1: left half of desktop + screen = gdk_screen_get_default(); + cloww = gdk_screen_get_width(screen); + clohh = gdk_screen_get_height(screen); + cloww = cloww / 2 - 20; + clohh = clohh - 50; + gtk_window_move(MWIN,10,10); // v.11.07 + gtk_window_resize(MWIN,cloww,clohh); + } + + if (Fclone == 2) { // clone2: open new window v.11.07 + gtk_window_move(MWIN,cloxx+20,cloyy+30); // slightly offset from old window + gtk_window_resize(MWIN,cloww,clohh); + } + + gdkgc = gdk_gc_new(drWin->window); // initz. graphics context + + black.red = black.green = black.blue = 0; // set up colors + white.red = white.green = white.blue = maxcolor; + lgray.red = lgray.green = lgray.blue = 0.9 * maxcolor; + dgray.red = dgray.green = dgray.blue = 0.5 * maxcolor; + red.red = maxcolor; red.green = red.blue = 0; + green.green = maxcolor; green.red = green.blue = 0; + + colormap = gtk_widget_get_colormap(drWin); + gdk_rgb_find_color(colormap,&black); + gdk_rgb_find_color(colormap,&white); + gdk_rgb_find_color(colormap,&lgray); + gdk_rgb_find_color(colormap,&dgray); + gdk_rgb_find_color(colormap,&red); + gdk_rgb_find_color(colormap,&green); + + gdk_gc_set_foreground(gdkgc,&black); + gdk_gc_set_background(gdkgc,&lgray); + gdk_window_set_background(drWin->window,&lgray); // v.11.01 + fg_color = black; + + gdk_gc_set_line_attributes(gdkgc,1,LINEATTRIBUTES); + + arrowcursor = gdk_cursor_new(GDK_TOP_LEFT_ARROW); // cursor for selection + dragcursor = gdk_cursor_new(GDK_CROSSHAIR); // cursor for dragging + drawcursor = gdk_cursor_new(GDK_PENCIL); // cursor for drawing lines + + gtk_init_add((GtkFunction) gtkinitfunc,0); // set initz. call from gtk_main() + gtk_main(); // start processing window events + return 0; +} + + +/**************************************************************************/ + +// initial function called from gtk_main() at startup + +int gtkinitfunc(void *data) +{ + int err, flag, npid; + int ftype, fdirk = 0; + char procfile[20], *ppv; + cchar *pp, *pp2; + struct stat statb; + + menulock(1); // block menus until initz. done v.11.04 + + snprintf(PIDstring,11,"%06d",getpid()); // get process PID 6-digits v.11.12 + + printf(fversion "\n"); // print Fotoxx version + printf("install location: %s \n",get_zprefix()); // install location + printf("last Fotoxx session: %s \n",last_session); // last session exit time + printf("top image directory: %s \n",topdirk); + + if (Ffirsttime) { // first time startup v.11.11 + printf("%s \n",ZTX("first time startup")); + zmessageACK(mWin,"User Guide is available in Help menu"); // inform user of user guide + Ffirsttime = 0; + save_params(); + } + + Nwt = sysconf(_SC_NPROCESSORS_ONLN); // get SMP CPU count + if (Nwt <= 0) Nwt = 1; + if (Nwt > max_threads) Nwt = max_threads; // compile time limit + printf("using %d threads \n",Nwt); + + err = system("which exiftool"); // check for exiftool v.11.05 + if (! err) Fexiftool = 1; + err = system("which xdg-open"); // check for xdg-open + if (! err) Fxdgopen = 1; + err = system("which ufraw-batch"); // check for ufraw-batch + if (! err) Fufraw = 1; + + undo_files = zmalloc(200); + *undo_files = 0; // look for orphaned undo files + strncatv(undo_files,199,get_zuserdir(),"/*_undo_*",null); // /home/user/.fotoxx/*_undo_* + flag = 1; + while ((pp = SearchWild(undo_files,flag))) + { + pp2 = strstr(pp,".fotoxx/"); + if (! pp2) continue; + npid = atoi(pp2+8); // pid of file owner + snprintf(procfile,19,"/proc/%d",npid); + err = stat(procfile,&statb); + if (! err) continue; // pid is active, keep file + printf("orphaned undo file deleted: %s \n",pp); + err = remove(pp); // delete file v.11.03 + } + + *undo_files = 0; // setup undo filespec template + strncatv(undo_files,199,get_zuserdir(),"/",PIDstring,"_undo_nn",null); // /home/user/.fotoxx/pppppp_undo_nn + + editlog = pvlist_create(maxedits); // history log of image edits done + for (int ii = 0; ii < maxedits; ii++) // pre-load all pvlist entries v.10.2 + pvlist_append(editlog,"nothing"); + + mutex_init(&Fpixmap_lock,0); // setup lock for edit pixmaps + zdialog_positions("load"); // load saved dialog positions v.11.07 + +// set up current file and directory from saved parameters or command line + + if (topdirk) curr_dirk = strdupz(topdirk); // use top directory if defined v.11.07 + else { + ppv = getcwd(command,ccc); // or use current directory v.11.09 + if (ppv) curr_dirk = strdupz(ppv); + } + + if (initial_file) { // from command line or previous session + ppv = realpath(initial_file,0); // prepend directory if needed + if (ppv) { + zfree(initial_file); + initial_file = strdupz(ppv); + free(ppv); + } + else { + printf("invalid file: %s \n",initial_file); // invalid file path + zfree(initial_file); + initial_file = 0; + } + } + + if (initial_file) { + ftype = image_file_type(initial_file); + if (ftype == 0) { // non-existent file + printf("invalid file: %s \n",initial_file); + zfree(initial_file); + initial_file = 0; + } + else if (ftype == 1) { // is a directory + if (curr_dirk) zfree(curr_dirk); + curr_dirk = initial_file; + initial_file = 0; + fdirk = 1; + } + else if (ftype == 2) { // supported image file type + if (curr_dirk) zfree(curr_dirk); + curr_dirk = strdupz(initial_file); // set current directory from file + ppv = strrchr(curr_dirk,'/'); + if (ppv) *ppv = 0; + } + else { + printf("unsupported file type: %s \n",initial_file); // unsupported file type + zfree(initial_file); + initial_file = 0; + } + } + + if (curr_dirk) err = chdir(curr_dirk); // set current directory + + menulock(0); // enable menus v.11.04 + + g_timeout_add(200,gtimefunc,0); // start periodic function (200 ms) v.11.06 + + if (SS_imagefile) { // start slide show if wanted v.11.04 + f_open(SS_imagefile,1); + if (SS_musicfile) { + sprintf(command,"xdg-open \"%s\" ",SS_musicfile); // start music if wanted + printf("command: %s \n",command); + err = system(command); + } + m_slideshow(0,0); + return 0; + } + + if (initial_file) // open initial file + f_open(initial_file,1); + + else if (fdirk) { // open gallery for initial directory + image_navi::thumbsize = 128; + m_gallery(0,0); // v.11.08 + } + + else if (Fprev) // start with previous file v.11.08 + m_previous(0,0); + + else if (Frecent) { + image_navi::thumbsize = 180; // start with gallery of recent files + m_recent(0,0); // v.11.07 + } + + else if (Fblank) return 0; // start with blank window v.12.01 + + else if (strEqu(startdisplay,"recent")) { + image_navi::thumbsize = 180; // start with gallery of recent files + m_recent(0,0); // v.11.07 + } + + else if (strEqu(startdisplay,"prev")) { // from user settings v.12.01 + m_previous(0,0); + } + + else if (strEqu(startdisplay,"dirk")) { // v.12.01 + if (! startdirk || *startdirk != '/') return 0; + if (curr_dirk) zfree(curr_dirk); + curr_dirk = strdupz(startdirk); + err = chdir(curr_dirk); + image_navi::thumbsize = 128; + m_gallery(0,0); + } + + else if (strEqu(startdisplay,"file")) { // v.12.01 + f_open(startfile,1); + } + + return 0; // start with blank window +} + + +/**************************************************************************/ + +// Periodic function +// Avoid any thread usage of gtk/gdk functions. + +int gtimefunc(void *arg) +{ + static zdialog *zdmessage = 0; + int syncfd; + + if (Wrepaint) { // window update needed + Wrepaint = 0; + mwpaint1(); + } + + update_statusbar(); // update every cycle v.11.03 + + if (Fslideshow) slideshow_next("timer"); // show next image if time is up + + if (Ffuncbusy) + paint_text(Dww/2-50,Dhh-20,"BUSY","monospace 10"); // write BUSY on window v.11.07 + + if (threadmessage && ! zdmessage) // display message for thread process + zdmessage = zmessage_post(mWin,0,threadmessage); // (avoid use of GTK in threads) v.11.03 + + if (zdmessage && ! threadmessage) // message terminated by thread + zdialog_free(zdmessage); + + if (zdmessage && zdmessage->sentinel != zdsentinel) { // popup window closed by user + zdmessage = 0; + threadmessage = 0; + } + + syncfd = global_lock(fsync_lock); // check for sync files process + if (syncfd >= 0) { // not busy + global_unlock(syncfd); + if (Fsyncbusy) threadmessage = 0; // it was busy, now done v.11.11 + Fsyncbusy = 0; + } + else Fsyncbusy = 1; // sync files still busy + + return 1; +} + + +/**************************************************************************/ + +// update status bar with image data and status +// called from timer function + +void update_statusbar() +{ + static double time1 = 0, time2, cpu1 = 0, cpu2, cpuload; + char text1[300], text2[100]; + int ww, hh, scale, bpc, done; + double file_MB = 1.0 / mega * curr_file_size; + + *text1 = *text2 = 0; + + time2 = get_seconds(); // compute process cpu load + if (time2 - time1 > 1.0) { // at 1 second intervals + cpu2 = jobtime(); // v.11.09 + cpuload = 100.0 * (cpu2 - cpu1) / (time2 - time1); + time1 = time2; + cpu1 = cpu2; + } + + sprintf(text1,"CPU %03.0f%c",cpuload,'%'); // CPU 023% + + if (curr_file) // v.11.04 + { + if (E3pxm16) { + ww = E3ww; + hh = E3hh; + bpc = 16; + } + else if (Fpxm16) { + ww = Fww; + hh = Fhh; + bpc = 16; + } + else { + ww = Fww; + hh = Fhh; + bpc = curr_file_bpc; + } + + snprintf(text2,99," %dx%dx%d",ww,hh,bpc); // 2345x1234x16 (preview) 1.56MB 45% + strcat(text1,text2); + if (Fpreview) strcat(text1," (preview)"); + sprintf(text2," %.2fMB",file_MB); + strcat(text1,text2); + scale = Mscale * 100 + 0.5; + sprintf(text2," %d%c",scale,'%'); + strcat(text1,text2); + + if (Pundo) { // edit undo stack depth + snprintf(text2,99," edits: %d",Pundo); + strcat(text1,text2); + } + } + + if (Fmenulock) strcat(text1," menu locked"); + if (Fsyncbusy) strcat(text1," file sync busy"); // v.11.11 + if (Factivearea) strcat(text1," area active"); // v.11.01 + if (zfuncs::zdialog_busy) strcat(text1," dialog open"); // v.11.11 + + if (SB_goal) { // progress monitor v.9.6 + done = 100.0 * SB_done / SB_goal; // v.11.06 + snprintf(text2,99," progress %d%c",done,'%'); + strcat(text1,text2); + } + + if (*SB_text) { // application text v.10.7 + strcat(text1," "); + strcat(text1,SB_text); + } + + stbar_message(STbar,text1); // write to status bar + + return; +} + + +/**************************************************************************/ + +// functions for main window event signals + +int delete_event() // main window closed +{ + printf("main window delete event \n"); + if (mod_keep()) return 1; // allow user bailout + Fshutdown++; // shutdown in progress + save_params(); // save parameters for next session + zdialog_positions("save"); // save dialog positions too v.11.07 + free_resources(); // delete undo files + return 0; +} + +void destroy_event() // main window destroyed +{ + printf("main window destroy event \n"); + Fshutdown++; // shutdown in progress + free_resources(); // delete undo files v.12.01 + exit(1); // instead of gtk_main_quit(); + return; +} + + +// process top-level menu entry + +void topmenufunc(GtkWidget *, cchar *menu) +{ + topmenu = (char *) menu; // remember top-level menu in case + return; // this is needed somewhere +} + + +/**************************************************************************/ + +// Paint window when created, exposed, resized, or modified (edited). +// This is a full window update. May NOT be called from threads. + +int mwpaint1() +{ + GdkRectangle wrect; + int incrx, incry; // mouse drag + static int pincrx = 0, pincry = 0; // prior mouse drag + static int pdww = 0, pdhh = 0; // prior window size + static int piorgx = 0, piorgy = 0; // prior image origin in window + static double pscale = 1; // prior scale + double wscale, hscale; + int refresh = 0; // flag, image refesh needed + int mousex, mousey; // mouse position after zoom + PXM *pxmtemp; + + if (Fshutdown) return 1; // shutdown underway + + if (! Fpxm8) { + gdk_window_clear(drWin->window); // no image v.11.12 + return 1; + } + + Dww = drWin->allocation.width; // (new) drawing window size + Dhh = drWin->allocation.height; + if (Dww < 20 || Dhh < 20) return 1; // too small + + if (mutex_trylock(&Fpixmap_lock) != 0) { // lock pixmaps + Wrepaint++; // cannot, come back later + return 1; + } + + if (Frefresh) { // image was updated + refresh++; + Frefresh = 0; + } + + if (Dww != pdww || Dhh != pdhh) { // window size changed + refresh++; // image refresh needed + pdww = Dww; + pdhh = Dhh; + } + + if (E3pxm16) { // get image size + Iww = E3ww; + Ihh = E3hh; // edit in progress + } + else { + Iww = Fww; // no edit + Ihh = Fhh; + } + + if (Fzoom == 0) { // scale to fit window + wscale = 1.0 * Dww / Iww; + hscale = 1.0 * Dhh / Ihh; + if (wscale < hscale) Mscale = wscale; // use greatest ww/hh ratio + else Mscale = hscale; + if (Iww < Dww && Ihh < Dhh && ! Fblowup) Mscale = 1.0; // small image 1x unless Fblowup + zoomx = zoomy = 0; + } + else Mscale = Fzoom; // scale to Fzoom level + + if (Mscale != pscale) refresh++; // scale changed, image refresh needed + + if (Mscale > pscale) { // zoom increased + Iorgx += iww * 0.5 * (1.0 - pscale / Mscale); // keep current image center + Iorgy += ihh * 0.5 * (1.0 - pscale / Mscale); + } + pscale = Mscale; + + iww = Dww / Mscale; // image space fitting in window + if (iww > Iww) iww = Iww; + ihh = Dhh / Mscale; + if (ihh > Ihh) ihh = Ihh; + + if (zoomx || zoomy) { // req. zoom center + Iorgx = zoomx - 0.5 * iww; // corresp. image origin + Iorgy = zoomy - 0.5 * ihh; + ///zoomx = zoomy = 0; // v.12.01 + } + + if ((Mxdrag || Mydrag) && Fmousemain) { // scroll via mouse drag v.12.01 + incrx = (Mxdrag - Mxdown) * 1.3 * Iww / iww; // scale + incry = (Mydrag - Mydown) * 1.3 * Ihh / ihh; + if (pincrx > 0 && incrx < 0) incrx = 0; // stop bounce at extremes + if (pincrx < 0 && incrx > 0) incrx = 0; + pincrx = incrx; + if (pincry > 0 && incry < 0) incry = 0; + if (pincry < 0 && incry > 0) incry = 0; + pincry = incry; + Iorgx += incrx; // new image origin after scroll + Iorgy += incry; + Mxdown = Mxdrag + incrx; // new drag origin + Mydown = Mydrag + incry; + Mxdrag = Mydrag = 0; + zoomx = zoomy = 0; // no zoom target v.12.01 + } + + if (iww == Iww) { // scaled image <= window width + Iorgx = 0; // center image in window + Dorgx = 0.5 * (Dww - Iww * Mscale); + } + else Dorgx = 0; // image > window, use entire window + + if (ihh == Ihh) { // same for image height + Iorgy = 0; + Dorgy = 0.5 * (Dhh - Ihh * Mscale); + } + else Dorgy = 0; + + if (Iorgx + iww > Iww) Iorgx = Iww - iww; // set limits + if (Iorgy + ihh > Ihh) Iorgy = Ihh - ihh; + if (Iorgx < 0) Iorgx = 0; + if (Iorgy < 0) Iorgy = 0; + + if (Iorgx != piorgx || Iorgy != piorgy) { // image origin changed + refresh++; // image refresh needed + piorgx = Iorgx; + piorgy = Iorgy; + } + + if (refresh) // image refresh is needed + { + if (E3pxm16) { // edit in progress + PXM_free(Dpxm16); + Dpxm16 = PXM_copy_area(E3pxm16,Iorgx,Iorgy,iww,ihh); // copy E3 image area, PXM-16 + pxmtemp = PXM_convbpc(Dpxm16); // convert to PXM-8 + } + else pxmtemp = PXM_copy_area(Fpxm8,Iorgx,Iorgy,iww,ihh); // no edit, copy PXM-8 image area + + dww = iww * Mscale; // scale to window + dhh = ihh * Mscale; + PXM_free(Dpxm8); + Dpxm8 = PXM_rescale(pxmtemp,dww,dhh); + PXM_free(pxmtemp); + } + + if (zoomx || zoomy) { // zoom target v.12.01 + mousex = (zoomx - Iorgx) * Mscale + Dorgx; + mousey = (zoomy - Iorgy) * Mscale + Dorgy; + gdk_window_move_pointer(drWin->window,mousex,mousey); // pointer follows target + } + + wrect.x = wrect.y = 0; // stop flicker + wrect.width = Dww; + wrect.height = Dhh; + gdk_window_begin_paint_rect(drWin->window,&wrect); + + gdk_draw_rgb_image(drWin->window, gdkgc, Dorgx, Dorgy, dww, dhh, // draw scaled image to window + NODITHER, (uint8 *) Dpxm8->bmp, dww*3); + + if (Ntoplines) paint_toplines(1); // draw line overlays + if (Ftoparc) paint_toparc(1); // draw arc overlay + if (Fgrid) paint_gridlines(); // draw grid lines + if (Ntoptext) paint_toptext(); // draw text strings v.11.07 + if (Ntopcircles) paint_topcircles(); // draw red circles v.11.12 + if (Fshowarea && ! Fpreview) sa_show(1); // draw select area outline + + gdk_window_end_paint(drWin->window); // release all window updates + + zoomx = zoomy = 0; // reset zoom targetv.12.01 v.12.01 + mutex_unlock(&Fpixmap_lock); // unlock pixmaps + Wpainted++; // notify edit function of repaint + histogram_paint(); // update brightness histogram if exists + return 1; +} + + +/**************************************************************************/ + +// Cause (modified) output image to get repainted soon. +// The entire image is repainted (that part within the window). +// MAY be called from threads. + +void mwpaint2() +{ + Frefresh++; + Wrepaint++; // req. repaint by periodic function + return; +} + + +// Repaint a rectangular part of the image being edited. +// px3, py3, ww3, hh3: modified area within E3pxm16 to be repainted +// Dpxm16: 1x copy of E3pxm16 area currently visible in main window +// px2, py2, ww2, hh2: E3pxm16 area copied into Dpxm16 +// Dpxm8: window image, Dpxm16 scaled to window, converted to 8 bits +// May NOT be called from threads. + +void mwpaint3(int px3, int py3, int ww3, int hh3) // overhauled v.10.11 +{ + int px2, py2, ww2, hh2, dx, dy; + uint16 *pix2, *pix3; + uint8 *pxm8area; + + if (! Dpxm16) zappcrash("mwpaint3() no Dpxm16"); // v.10.12 + + px2 = px3 - Iorgx; // map modified area into Dpxm16 + py2 = py3 - Iorgy; + ww2 = ww3; + hh2 = hh3; + + if (px2 < 0) { // if beyond Dpxm16 edge, reduce + px3 -= px2; + ww2 += px2; + px2 = 0; + } + if (px2 + ww2 > iww) ww2 = iww - px2; + + if (py2 < 0) { + py3 -= py2; + hh2 += py2; + py2 = 0; + } + if (py2 + hh2 > ihh) hh2 = ihh - py2; + + if (ww2 <= 0 || hh2 <= 0) return; // completely off Dpxm16 image + + for (dy = 0; dy < hh2; dy++) // copy pixels from E3pxm16 to Dpxm16 + for (dx = 0; dx < ww2; dx++) + { + pix3 = PXMpix(E3pxm16,px3+dx,py3+dy); + pix2 = PXMpix(Dpxm16,px2+dx,py2+dy); + pix2[0] = pix3[0]; + pix2[1] = pix3[1]; + pix2[2] = pix3[2]; + } + + PXM_update(Dpxm16,Dpxm8,px2,py2,ww2,hh2); // copy/rescale Dpxm16 area into Dpxm8 area + + px2 = px2 * Mscale - 1; // Dpxm8 area impacted v.10.12 + py2 = py2 * Mscale - 1; + ww2 = ww2 * Mscale + 1 / Mscale + 2; + hh2 = hh2 * Mscale + 1 / Mscale + 2; + + if (px2 < 0) px2 = 0; // stay within image edge + if (py2 < 0) py2 = 0; + if (px2 + ww2 > dww) ww2 = dww - px2; + if (py2 + hh2 > dhh) hh2 = dhh - py2; + if (ww2 <= 0 || hh2 <= 0) return; // completely off Dpxm8 image + + pxm8area = (uint8 *) Dpxm8->bmp + 3 * (dww * py2 + px2); // origin of area to copy + + gdk_draw_rgb_image(drWin->window, gdkgc, px2 + Dorgx, py2 + Dorgy, // copy into window + ww2, hh2, NODITHER, pxm8area, dww*3); + + if (Fshowarea && ! Fpreview) sa_show(1); // draw select area outline v.12.01 + return; +} + + +/**************************************************************************/ + +// mouse event function - capture buttons and drag movements + +void mouse_event(GtkWidget *, GdkEventButton *event, void *) +{ + void mouse_convert(int &xpos, int &ypos); + + static int bdtime = 0, butime = 0, mbusy = 0; + int button, time, type, scroll; + + type = event->type; + button = event->button; // button, 1/2/3 = left/center/right + time = event->time; + Mxposn = event->x; // mouse position in window + Myposn = event->y; + scroll = ((GdkEventScroll *) event)->direction; // scroll wheel event + + mouse_convert(Mxposn,Myposn); // convert to image space + + if (type == GDK_SCROLL) { // scroll wheel = zoom v.12.01 + zoomx = Mxposn; // zoom center = mouse position (doriano) + zoomy = Myposn; + if (scroll == GDK_SCROLL_UP) m_zoom(null,"in"); + if (scroll == GDK_SCROLL_DOWN) m_zoom(null,"out"); + return; + } + + if (type == GDK_MOTION_NOTIFY) { + if (mbusy) return; // discard excess motion events + mbusy++; + zmainloop(); + mbusy = 0; + } + + if (type == GDK_BUTTON_PRESS) { // button down + bdtime = time; // time of button down + Mxdown = Mxposn; // position at button down time + Mydown = Myposn; + if (button) { + Mdrag++; // possible drag start + Mbutton = button; + } + Mxdrag = Mydrag = 0; + } + + if (type == GDK_BUTTON_RELEASE) { // button up + Mxclick = Myclick = 0; // reset click status + butime = time; // time of button up + if (butime - bdtime < 400) // less than 0.4 secs down + if (Mxposn == Mxdown && Myposn == Mydown) { // and not moving + if (Mbutton == 1) LMclick++; // left mouse click + if (Mbutton == 3) RMclick++; // right mouse click + Mxclick = Mxdown; // click = button down position + Myclick = Mydown; + } + if (button == 2) { // center button click v.12.01 + zoomx = Mxposn; // re-center at mouse (doriano) + zoomy = Myposn; + mwpaint2(); + } + Mxdown = Mydown = Mxdrag = Mydrag = Mdrag = Mbutton = 0; // forget buttons and drag + } + + if (type == GDK_MOTION_NOTIFY && Mdrag) { // drag underway + Mxdrag = Mxposn; + Mydrag = Myposn; + } + + Fmousemain = 1; // mouse acts on main window v.12.01 + if (Mcapture) Fmousemain = 0; + if (mouseCBfunc) Fmousemain = 0; + if (KBcontrolkey) Fmousemain = 1; // Ctrl key >> mouse acts on main window + + if (mouseCBfunc && ! Fmousemain) { // pass to handler function + if (mbusy) return; + mbusy++; // stop re-entrance v.10.8 + (* mouseCBfunc)(); + mbusy = 0; + return; + } + + if (LMclick && Fmousemain) { // left click = zoom request + LMclick = 0; + zoomx = Mxclick; // zoom center = mouse + zoomy = Myclick; + m_zoom(null,"in"); + } + + if (RMclick && Fmousemain) { // right click + RMclick = 0; + if (Fzoom) { + zoomx = zoomy = 0; // reset zoom to fit window + m_zoom(null,"fit"); + } + else if (edit_coll_name && curr_file) // pass file to edit collection + edit_coll_popmenu(null,curr_file); // v.11.11 + } + + if ((Mxdrag || Mydrag) && Fmousemain) mwpaint1(); // drag = scroll + + return; +} + + +// convert mouse position from window space to image space + +void mouse_convert(int &xpos, int &ypos) +{ + xpos = (xpos - Dorgx) / Mscale + Iorgx + 0.5; + ypos = (ypos - Dorgy) / Mscale + Iorgy + 0.5; + + if (xpos < 0) xpos = 0; // if outside image put at edge + if (ypos < 0) ypos = 0; + + if (E3pxm16) { + if (xpos >= E3ww) xpos = E3ww-1; + if (ypos >= E3hh) ypos = E3hh-1; + } + else { + if (xpos >= Fww) xpos = Fww-1; + if (ypos >= Fhh) ypos = Fhh-1; + } + + return; +} + + +/**************************************************************************/ + +// keyboard event function - some toolbar buttons have KB equivalents +// GDK key symbols: /usr/include/gtk-2.0/gdk/gdkkeysyms.h + +int KBpress(GtkWidget *win, GdkEventKey *event, void *) // prevent propagation of key-press +{ // events to toolbar buttons + KBkey = event->keyval; + + if (KBkey == GDK_Control_L || KBkey == GDK_Control_R) // Ctrl key is pressed v.11.07 + KBcontrolkey = 1; + + if (KBkey == GDK_Shift_L || KBkey == GDK_Shift_R) // Shift key is pressed v.11.07 + KBshiftkey = 1; + + if (KBkey == GDK_a || KBkey == GDK_A) // 'A' key is pressed v.11.11 + KB_A_key = 1; // (undo/redo --> undo/redo ALL) + + return 1; +} + +int KBrelease(GtkWidget *win, GdkEventKey *event, void *) +{ + int angle = 0; + PXM *pxm; + + KBkey = event->keyval; + + if (KBcapture) return 1; // let function handle it + + if (KBkey == GDK_Control_L || // Ctrl key released v.11.07 + KBkey == GDK_Control_R) KBcontrolkey = 0; + + if (KBkey == GDK_Shift_L || // Shift key released v.11.07 + KBkey == GDK_Shift_R) KBshiftkey = 0; + + if (KBkey == GDK_a || // 'A' key is released v.11.11 + KBkey == GDK_A) KB_A_key = 0; + + if (KBcontrolkey) { + if (KBkey == GDK_s) m_save(0,0); // Ctrl-* shortcuts + if (KBkey == GDK_S) m_saveas(0,0); + if (KBkey == GDK_v) m_savevers(0,0); + if (KBkey == GDK_V) m_savevers(0,0); + if (KBkey == GDK_q) m_quit(0,0); + if (KBkey == GDK_Q) m_quit(0,0); + } + + if (KBkey == GDK_G || KBkey == GDK_g) // toggle grid lines v.11.11 + toggle_grid(2); + + if (Fslideshow) { // v.11.10 + if (KBkey == GDK_Left) slideshow_next("prev"); // arrow keys = prev/next image + if (KBkey == GDK_Right) slideshow_next("next"); + if (KBkey == GDK_space) slideshow_next("pause"); // spacebar = pause/resume + if (KBkey == GDK_Escape) m_slideshow(0,0); // escape = exit slideshow + } + else { + if (KBkey == GDK_Left) m_prev(0,0); // arrow keys = prev/next image + if (KBkey == GDK_Right) m_next(0,0); + } + + if (KBkey == GDK_plus) m_zoom(null,"in"); // + key >> zoom in + if (KBkey == GDK_minus) m_zoom(null,"fit"); // - key >> fit to window + if (KBkey == GDK_equal) m_zoom(null,"in"); // = key: same as + + if (KBkey == GDK_KP_Add) m_zoom(null,"in"); // keypad + + if (KBkey == GDK_KP_Subtract) m_zoom(null,"fit"); // keypad - + + if (KBkey == GDK_Delete) m_trash(0,0); // delete >> trash + + if (KBkey == GDK_F1) // F1 >> user guide + showz_userguide(zfuncs::F1_help_topic); // show topic if there, or page 1 + + if (! E1pxm16) { // if no edit in progress, + if (KBkey == GDK_R || KBkey == GDK_r) angle = 90; // allow manual rotations + if (KBkey == GDK_L || KBkey == GDK_l) angle = -90; + if (angle) { + mutex_lock(&Fpixmap_lock); // v.10.5 + pxm = PXM_rotate(Fpxm8,angle); + PXM_free(Fpxm8); + Fpxm8 = pxm; + Fww = pxm->ww; + Fhh = pxm->hh; + mutex_unlock(&Fpixmap_lock); + mwpaint2(); + m_save(0,"nowarn"); // auto save uprighted image v.10.12 + } + } + + if (KBcontrolkey && KBkey == GDK_m) { // zmalloc() activity log + KBzmalloclog = 1 - KBzmalloclog; // Ctrl+M = toggle on/off + if (KBzmalloclog) zmalloc_log(999999); + else zmalloc_log(0); + zmalloc_report(); // v.10.8 + } + + if (KBkey == GDK_T || KBkey == GDK_t) m_trim(0,0); // Key T = Trim function v.10.3.1 + if (KBkey == GDK_B || KBkey == GDK_b) m_tune(0,0); // Key B = brightness/color v.10.3.1 + if (KBkey == GDK_N || KBkey == GDK_n) m_rename(0,0); // Key N = rename file v.11.11 + + if (KBkey == GDK_z || KBkey == GDK_Z) { // Z key + if (! KBcontrolkey) m_zoom(null,"100"); // if no CTRL, toggle zoom 1x + else { // if CTRL, v.11.11 + if (KBshiftkey) m_redo(0,0); // with shift: redo edit + else m_undo(0,0); // without shift: undo edit + } + } + + KBkey = 0; + return 1; +} + + +/**************************************************************************/ + +// paint a grid of horizontal and vertical lines + +void paint_gridlines() // revised v.10.10.2 +{ + int px, py, stepx, stepy, startx, starty; + + if (! Fpxm8) return; // no image + if (! Fgrid) return; // grid lines off v.11.11 + + stepx = gridspace[0]; // space between grid lines + stepy = gridspace[1]; + + if (gridcount[0]) stepx = dww / (1 + gridcount[0]); // if line counts specified, v.10.11 + if (gridcount[1]) stepy = dhh / ( 1 + gridcount[1]); // set spacing accordingly + + startx = stepx * gridoffset[0] / 100; // variable offsets v.11.11 + if (startx < 0) startx += stepx; + + starty = stepy * gridoffset[1] / 100; + if (starty < 0) starty += stepy; + + gdk_gc_set_foreground(gdkgc,&white); // white lines + + if (gridon[0] && stepx) + for (px = Dorgx+startx; px < Dorgx+dww; px += stepx) + gdk_draw_line(drWin->window,gdkgc,px,Dorgy,px,Dorgy+dhh); + + if (gridon[1] && stepy) + for (py = Dorgy+starty; py < Dorgy+dhh; py += stepy) + gdk_draw_line(drWin->window,gdkgc,Dorgx,py,Dorgx+dww,py); + + gdk_gc_set_foreground(gdkgc,&black); // adjacent black lines + fg_color = black; // v.10.12 + + if (gridon[0] && stepx) + for (px = Dorgx+startx+1; px < Dorgx+dww; px += stepx) + gdk_draw_line(drWin->window,gdkgc,px,Dorgy,px,Dorgy+dhh); + + if (gridon[1] && stepy) + for (py = Dorgy+starty+1; py < Dorgy+dhh; py += stepy) + gdk_draw_line(drWin->window,gdkgc,Dorgx,py,Dorgx+dww,py); + + return; +} + + +/**************************************************************************/ + +// refresh overlay lines on top of image +// arg = 1: paint lines only (because window repainted) +// 2: erase lines and forget them +// 3: erase old lines, paint new lines, save new in old + +void paint_toplines(int arg) +{ + int ii; + + if (arg == 2 || arg == 3) // erase old lines + for (ii = 0; ii < Nptoplines; ii++) + erase_line(ptoplinex1[ii],ptopliney1[ii],ptoplinex2[ii],ptopliney2[ii]); + + if (arg == 1 || arg == 3) // draw new lines + for (ii = 0; ii < Ntoplines; ii++) + draw_line(toplinex1[ii],topliney1[ii],toplinex2[ii],topliney2[ii]); + + if (arg == 2) { + Nptoplines = Ntoplines = 0; // forget lines + return; + } + + for (ii = 0; ii < Ntoplines; ii++) // save for future erase + { + ptoplinex1[ii] = toplinex1[ii]; + ptopliney1[ii] = topliney1[ii]; + ptoplinex2[ii] = toplinex2[ii]; + ptopliney2[ii] = topliney2[ii]; + } + + Nptoplines = Ntoplines; + + return; +} + + +/**************************************************************************/ + +// refresh overlay arc (circle/ellipse) on top of image +// arg = 1: paint arc only (because window repainted) +// 2: erase arc and forget it +// 3: erase old arc, paint new arc, save new in old + +void paint_toparc(int arg) +{ + int arcx, arcy, arcw, arch; + + if (ptoparc && (arg == 2 || arg == 3)) { // erase old arc + arcx = (ptoparcx-Iorgx) * Mscale + Dorgx + 0.5; // image to window space + arcy = (ptoparcy-Iorgy) * Mscale + Dorgy + 0.5; + arcw = ptoparcw * Mscale; + arch = ptoparch * Mscale; + + gdk_gc_set_function(gdkgc,GDK_INVERT); // invert pixels + gdk_draw_arc(drWin->window,gdkgc,0,arcx,arcy,arcw,arch,0,64*360); // draw arc + gdk_gc_set_function(gdkgc,GDK_COPY); + } + + if (Ftoparc && (arg == 1 || arg == 3)) { // draw new arc + arcx = (toparcx-Iorgx) * Mscale + Dorgx + 0.5; // image to window space + arcy = (toparcy-Iorgy) * Mscale + Dorgy + 0.5; + arcw = toparcw * Mscale; + arch = toparch * Mscale; + + gdk_gc_set_function(gdkgc,GDK_INVERT); // invert pixels + gdk_draw_arc(drWin->window,gdkgc,0,arcx,arcy,arcw,arch,0,64*360); // draw arc + gdk_gc_set_function(gdkgc,GDK_COPY); + } + + if (arg == 2) { + Ftoparc = ptoparc = 0; // forget arcs + return; + } + + ptoparc = Ftoparc; // save for future erase + ptoparcx = toparcx; + ptoparcy = toparcy; + ptoparcw = toparcw; + ptoparch = toparch; + + return; +} + + +/**************************************************************************/ + +// draw dotted line. coordinates are in image space. + +void draw_line(int ix1, int iy1, int ix2, int iy2) +{ + void draw_line_pixel(double pxm, double pym); + + double x1, y1, x2, y2; + double pxm, pym, slope; + + x1 = Mscale * (ix1-Iorgx); // image to window space + y1 = Mscale * (iy1-Iorgy); + x2 = Mscale * (ix2-Iorgx); + y2 = Mscale * (iy2-Iorgy); + + if (abs(y2 - y1) > abs(x2 - x1)) { + slope = 1.0 * (x2 - x1) / (y2 - y1); + if (y2 > y1) { + for (pym = y1; pym <= y2; pym++) { + pxm = round(x1 + slope * (pym - y1)); + draw_line_pixel(pxm,pym); + } + } + else { + for (pym = y1; pym >= y2; pym--) { + pxm = round(x1 + slope * (pym - y1)); + draw_line_pixel(pxm,pym); + } + } + } + else { + slope = 1.0 * (y2 - y1) / (x2 - x1); + if (x2 > x1) { + for (pxm = x1; pxm <= x2; pxm++) { + pym = round(y1 + slope * (pxm - x1)); + draw_line_pixel(pxm,pym); + } + } + else { + for (pxm = x1; pxm >= x2; pxm--) { + pym = round(y1 + slope * (pxm - x1)); + draw_line_pixel(pxm,pym); + } + } + } + + gdk_gc_set_foreground(gdkgc,&black); + fg_color = black; + + return; +} + +void draw_line_pixel(double px, double py) +{ + int pxn, pyn; + static int flip = 0; + + pxn = px; + pyn = py; + + if (pxn < 0 || pxn > dww-1) return; + if (pyn < 0 || pyn > dhh-1) return; + + if (++flip > 4) flip = -5; // black/white line v.10.10 + if (flip < 0) gdk_gc_set_foreground(gdkgc,&black); + else gdk_gc_set_foreground(gdkgc,&white); + gdk_draw_point(drWin->window, gdkgc, pxn + Dorgx, pyn + Dorgy); + + return; +} + + +// erase line. refresh line path from Dpxm8 pixels. + +void erase_line(int ix1, int iy1, int ix2, int iy2) +{ + void erase_line_pixel(double pxm, double pym); + + double x1, y1, x2, y2; + double pxm, pym, slope; + + if (! Dpxm8) zappcrash("Dpxm8 = 0"); // v.10.3 + + x1 = Mscale * (ix1-Iorgx); + y1 = Mscale * (iy1-Iorgy); + x2 = Mscale * (ix2-Iorgx); + y2 = Mscale * (iy2-Iorgy); + + if (abs(y2 - y1) > abs(x2 - x1)) { + slope = 1.0 * (x2 - x1) / (y2 - y1); + if (y2 > y1) { + for (pym = y1; pym <= y2; pym++) { + pxm = x1 + slope * (pym - y1); + erase_line_pixel(pxm,pym); + } + } + else { + for (pym = y1; pym >= y2; pym--) { + pxm = x1 + slope * (pym - y1); + erase_line_pixel(pxm,pym); + } + } + } + else { + slope = 1.0 * (y2 - y1) / (x2 - x1); + if (x2 > x1) { + for (pxm = x1; pxm <= x2; pxm++) { + pym = y1 + slope * (pxm - x1); + erase_line_pixel(pxm,pym); + } + } + else { + for (pxm = x1; pxm >= x2; pxm--) { + pym = y1 + slope * (pxm - x1); + erase_line_pixel(pxm,pym); + } + } + } + + return; +} + +void erase_line_pixel(double px, double py) +{ + int pxn, pyn; + + pxn = px; + pyn = py; + + if (pxn < 0 || pxn > dww-1) return; + if (pyn < 0 || pyn > dhh-1) return; + + uint8 *pixel = (uint8 *) Dpxm8->bmp + (pyn * dww + pxn) * 3; + gdk_draw_rgb_image(drWin->window, gdkgc, pxn + Dorgx, pyn + Dorgy, + 1, 1, NODITHER, pixel, dww * 3); + return; +} + + +// draw one pixel using given color, R/G/B = red/green/black + +void draw_pixel(int px, int py, GdkColor *color) // v.10.12 +{ + int qx, qy; + static int pqx, pqy; + + qx = Mscale * (px-Iorgx) + 0.5; // image to window space + qy = Mscale * (py-Iorgy) + 0.5; + + if (qx == pqx && qy == pqy) return; // avoid redundant points v.9.7 + + pqx = qx; + pqy = qy; + + qx = qx + Dorgx; // image origin in drawing window + qy = qy + Dorgy; + + if (qx < 0 || qx > Dww-1) return; // bugfix v.11.03.1 + if (qy < 0 || qy > Dhh-1) return; + + if (color != &fg_color) { + fg_color = *color; + gdk_gc_set_foreground(gdkgc,&fg_color); + } + + gdk_draw_point(drWin->window,gdkgc,qx,qy); // draw pixel + + return; +} + + +// draw a fat pixel using given color, R/G/B = red/green/black + +void draw_fat_pixel(int px, int py, GdkColor *color) // speedup v.11.04 +{ + int qx, qy; + static int pqx, pqy; + + qx = Mscale * (px-Iorgx) + 0.5; // image to window space + qy = Mscale * (py-Iorgy) + 0.5; + + if (qx == pqx && qy == pqy) return; // avoid redundant points v.9.7 + + pqx = qx; + pqy = qy; + + qx = qx + Dorgx; // image origin in drawing window + qy = qy + Dorgy; + + if (qx < 0 || qy < 0) return; + + if (color != &fg_color) { + fg_color = *color; + gdk_gc_set_foreground(gdkgc,&fg_color); + } + + if (qx < Dww-1 && qy < Dhh-1 && Mscale > 1.0) + gdk_draw_rectangle(drWin->window,gdkgc,0,qx,qy,2,2); // draw fat pixel 2x2 + + else if (qx < Dww && qy < Dhh) + gdk_draw_point(drWin->window,gdkgc,qx,qy); // on edge, draw pixel + + return; +} + + +/**************************************************************************/ + +// maintain a set of text strings written whenever the window is painted + +// add a new text string to the list +// multiple text strings can be added with the same ID +// px and py are image coordinates + +void add_toptext(int ID, int px, int py, cchar *text, cchar *font) // new v.11.07 +{ + if (Ntoptext == maxtoptext) { + printf("maxtoptext exceeded \n"); + return; + } + + int ii = Ntoptext++; + toptext[ii].ID = ID; + toptext[ii].px = px; + toptext[ii].py = py; + toptext[ii].text = text; + toptext[ii].font = font; + + return; +} + + +// delete text strings having the given ID from the list + +void erase_toptext(int ID) // new v.11.07 +{ + int ii, jj; + + for (ii = jj = 0; ii < Ntoptext; ii++) + { + if (toptext[ii].ID == ID) continue; + else toptext[jj++] = toptext[ii]; + } + + Ntoptext = jj; + + return; +} + + +// paint current text strings on window whenever it is repainted +// called from mwpaint() + +void paint_toptext() // new v.11.07 +{ + int ii, px, py; + + for (ii = 0; ii < Ntoptext; ii++) { + px = toptext[ii].px; + py = toptext[ii].py; + px = Mscale * (px - Iorgx) + Dorgx; // image to window space + py = Mscale * (py - Iorgy) + Dorgy; + paint_text(px,py,toptext[ii].text,toptext[ii].font); + } + + return; +} + + +// paint text on window, black on white background +// px and py are window coordinates + +void paint_text(int px, int py, cchar *text, cchar *font) // new v.11.07 +{ + static PangoFontDescription *pangofont = null; + static PangoLayout *pangolayout = null; + static char priorfont[40] = ""; + + if (strNeq(font,priorfont)) { // change font + strncpy0(priorfont,font,40); + if (pangofont) pango_font_description_free(pangofont); + if (pangolayout) g_object_unref(pangolayout); + pangofont = pango_font_description_from_string(font); + pangolayout = gtk_widget_create_pango_layout(drWin,0); + pango_layout_set_font_description(pangolayout,pangofont); + } + + pango_layout_set_text(pangolayout,text,-1); + gdk_draw_layout_with_colors(drWin->window,gdkgc,px,py,pangolayout,&black,&white); + + return; +} + + +/**************************************************************************/ + +// maintain a set of circles written whenever the window is painted + +void add_topcircle(int px, int py, int radius, int color) +{ + if (Ntopcircles == maxtopcircles) { + printf("maxtopcircles exceeded \n"); + return; + } + + int ii = Ntopcircles++; + topcircles[ii].px = px; + topcircles[ii].py = py; + topcircles[ii].radius = radius; + topcircles[ii].color = color; + + return; +} + + +void erase_topcircles() +{ + Ntopcircles = 0; + return; +} + + +void paint_topcircles() +{ + int ii, px, py, rad, color; + + for (ii = 0; ii < Ntopcircles; ii++) + { + px = (topcircles[ii].px - Iorgx) * Mscale + Dorgx + 0.5; // image to window space + py = (topcircles[ii].py - Iorgy) * Mscale + Dorgy + 0.5; + rad = topcircles[ii].radius; // radius is window space + color = topcircles[ii].color; // 1/2/3 = white/black/red + + px -= rad ; // NW corner of enclosing square + py -= rad ; + rad = 2 * rad; // size of enclosing square + + if (color == 1) gdk_gc_set_foreground(gdkgc,&white); // set foreground color + else if (color == 2) gdk_gc_set_foreground(gdkgc,&black); + else gdk_gc_set_foreground(gdkgc,&red); + + gdk_draw_arc(drWin->window,gdkgc,0,px,py,rad,rad,0,64*360); // draw 360 deg. arc + } + + return; +} + + +/************************************************************************** + + spline curve setup and edit functions + + Support multiple frames with curves in parallel // v.11.01 + (edit curve(s) and image mask curve) + + Usage: + Add frame widget to dialog or zdialog. + Set up drawing in frame: + sd = curve_init(frame, callback_func) + Initialize no. of curves in frame (1-10): + sd->Nspc = n + Initialize vert/horz flag for curve spc: + sd->vert[spc] = hv + Initialize anchor points for curve spc: + sd->nap[spc], sd->apx[spc][xx], sd->apy[spc][yy] + Generate data for curve spc: + splcurve_generate(sd,spc) + Curves will now be shown and edited inside the frame when window is realized. + The callback_func(spc) will be called when curve spc is edited. + Change curve in program: + set anchor points, call splcurve_generate(sd,spc) + Get y-value (0-1) for curve spc and given x-value (0-1): + yval = splcurve_yval(sd,spc,xval) + If faster access to curve is needed (no interpolation): + kk = 1000 * xval; + if (kk > 999) kk = 999; + yval = sd->yval[spc][kk]; + +***/ + +// initialize for spline curve editing +// initial anchor points are pre-loaded into spldat before window is realized + +spldat * splcurve_init(GtkWidget *frame, void func(int spc)) +{ + int cc = sizeof(spldat); // allocate spc curve data area + spldat * sd = (spldat *) zmalloc(cc,"curvedat"); + memset(sd,0,cc); + + sd->drawarea = gtk_drawing_area_new(); // drawing area for curves + gtk_container_add(GTK_CONTAINER(frame),sd->drawarea); + sd->spcfunc = func; // user callback function + + gtk_widget_add_events(sd->drawarea,GDK_BUTTON_PRESS_MASK); // connect mouse events to drawing area + gtk_widget_add_events(sd->drawarea,GDK_BUTTON_RELEASE_MASK); + gtk_widget_add_events(sd->drawarea,GDK_BUTTON1_MOTION_MASK); + G_SIGNAL(sd->drawarea,"motion-notify-event",splcurve_adjust,sd); + G_SIGNAL(sd->drawarea,"button-press-event",splcurve_adjust,sd); + G_SIGNAL(sd->drawarea,"expose-event",splcurve_draw,sd); + + return sd; +} + + +// modify anchor points in curve using mouse + +int splcurve_adjust(void *, GdkEventButton *event, spldat *sd) +{ + int ww, hh, kk; + int mx, my, button, evtype; + static int spc, ap, mbusy = 0, Fdrag = 0; // drag continuation logic v.9.7 + int minspc, minap; + double mxval, myval, cxval, cyval; + double dist2, mindist2 = 0; + + mx = event->x; // mouse position in drawing area + my = event->y; + evtype = event->type; + button = event->button; + + if (evtype == GDK_MOTION_NOTIFY) { + if (mbusy) return 0; // discard excess motion events v.11.01 + mbusy++; + zmainloop(); + mbusy = 0; + } + + if (evtype == GDK_BUTTON_RELEASE) { + Fdrag = 0; + return 0; + } + + ww = sd->drawarea->allocation.width; // drawing area size + hh = sd->drawarea->allocation.height; + + if (mx < 0) mx = 0; // limit edge excursions + if (mx > ww) mx = ww; + if (my < 0) my = 0; + if (my > hh) my = hh; + + if (evtype == GDK_BUTTON_PRESS) Fdrag = 0; // left or right click + + if (Fdrag) // continuation of drag + { + if (sd->vert[spc]) { + mxval = 1.0 * my / hh; // mouse position in curve space + myval = 1.0 * mx / ww; + } + else { + mxval = 1.0 * mx / ww; + myval = 1.0 * (hh - my) / hh; + } + + if (ap < sd->nap[spc]-1 && sd->apx[spc][ap+1] - mxval < 0.05) // disallow < 0.05 from next + return 0; + if (ap > 0 && mxval - sd->apx[spc][ap-1] < 0.05) return 0; // or prior anchor point + } + + else // mouse click or new drag begin + { + minspc = minap = -1; // find closest curve/anchor point + mindist2 = 999999; + + for (spc = 0; spc < sd->Nspc; spc++) // loop curves + { + if (sd->vert[spc]) { + mxval = 1.0 * my / hh; // mouse position in curve space + myval = 1.0 * mx / ww; + } + else { + mxval = 1.0 * mx / ww; + myval = 1.0 * (hh - my) / hh; + } + + for (ap = 0; ap < sd->nap[spc]; ap++) // loop anchor points + { + cxval = sd->apx[spc][ap]; + cyval = sd->apy[spc][ap]; + dist2 = (mxval-cxval)*(mxval-cxval) + + (myval-cyval)*(myval-cyval); + if (dist2 < mindist2) { + mindist2 = dist2; // remember closest anchor point + minspc = spc; + minap = ap; + } + } + } + + if (minspc < 0) return 0; // impossible + spc = minspc; + ap = minap; + } + + if (evtype == GDK_BUTTON_PRESS && button == 3) // right click, remove anchor point + { + if (sqrt(mindist2) > 0.05) return 0; // not close enough + if (sd->nap[spc] < 3) return 0; // < 2 anchor points would remain + sd->nap[spc]--; // decr. before loop v.11.11 + for (kk = ap; kk < sd->nap[spc]; kk++) { + if (! kk) printf("meaningless reference %d",kk); // stop gcc optimization bug v.11.11 ///// + sd->apx[spc][kk] = sd->apx[spc][kk+1]; + sd->apy[spc][kk] = sd->apy[spc][kk+1]; + } + splcurve_generate(sd,spc); // regenerate data for modified curve + splcurve_draw(0,0,sd); // regen and redraw all curves + sd->spcfunc(spc); // call user function + return 0; + } + + if (! Fdrag) // new drag or left click + { + if (sd->vert[spc]) { + mxval = 1.0 * my / hh; // mouse position in curve space + myval = 1.0 * mx / ww; + } + else { + mxval = 1.0 * mx / ww; + myval = 1.0 * (hh - my) / hh; + } + + if (sqrt(mindist2) < 0.05) // existing point close enough, + { // move this anchor point to mouse + if (ap < sd->nap[spc]-1 && sd->apx[spc][ap+1] - mxval < 0.05) + return 0; // disallow < 0.05 from next + if (ap > 0 && mxval - sd->apx[spc][ap-1] < 0.05) return 0; // or prior anchor point + } + + else // none close, add new anchor point + { + minspc = -1; // find closest curve to mouse + mindist2 = 999999; + + for (spc = 0; spc < sd->Nspc; spc++) // loop curves + { + if (sd->vert[spc]) { + mxval = 1.0 * my / hh; // mouse position in curve space + myval = 1.0 * mx / ww; + } + else { + mxval = 1.0 * mx / ww; + myval = 1.0 * (hh - my) / hh; + } + + cyval = splcurve_yval(sd,spc,mxval); + dist2 = fabs(myval - cyval); + if (dist2 < mindist2) { + mindist2 = dist2; // remember closest curve + minspc = spc; + } + } + + if (minspc < 0) return 0; // impossible + if (mindist2 > 0.05) return 0; // not close enough to any curve + spc = minspc; + + if (sd->nap[spc] > 49) { + zmessageACK(mWin,ZTX("Exceed 50 anchor points")); + return 0; + } + + if (sd->vert[spc]) { + mxval = 1.0 * my / hh; // mouse position in curve space + myval = 1.0 * mx / ww; + } + else { + mxval = 1.0 * mx / ww; + myval = 1.0 * (hh - my) / hh; + } + + for (ap = 0; ap < sd->nap[spc]; ap++) // find anchor point with next higher x + if (mxval <= sd->apx[spc][ap]) break; // (ap may come out 0 or nap) + + if (ap < sd->nap[spc] && sd->apx[spc][ap] - mxval < 0.05) // disallow < 0.05 from next + return 0; // or prior anchor point + if (ap > 0 && mxval - sd->apx[spc][ap-1] < 0.05) return 0; + + for (kk = sd->nap[spc]; kk > ap; kk--) { // make hole for new point + sd->apx[spc][kk] = sd->apx[spc][kk-1]; + sd->apy[spc][kk] = sd->apy[spc][kk-1]; + } + + sd->nap[spc]++; // up point count + } + } + + sd->apx[spc][ap] = mxval; // new or moved anchor point + sd->apy[spc][ap] = myval; // at mouse position + + splcurve_generate(sd,spc); // regenerate data for modified curve + splcurve_draw(0,0,sd); // regen and redraw all curves + sd->spcfunc(spc); // call user function + + if (evtype == GDK_MOTION_NOTIFY) Fdrag = 1; // remember drag is underway + return 0; +} + + +// for expose event or when a curve is changed +// draw all curves based on current anchor points + +int splcurve_draw(void *, void *, spldat *sd) +{ + int ww, hh, px, py, qx, qy, spc, ap; + double xval, yval; + + ww = sd->drawarea->allocation.width; // drawing area size + hh = sd->drawarea->allocation.height; + if (ww < 50 || hh < 50) return 0; + + gdk_window_clear(sd->drawarea->window); // clear window + + gdk_gc_set_foreground(gdkgc,&dgray); + + for (int ii = 0; ii < sd->Nscale; ii++) // draw y-scale lines if any v.11.07 + { + px = ww * sd->xscale[0][ii] + 0.5; // any line, not only horizontal v.11.10 + py = hh - hh * sd->yscale[0][ii] + 0.5; + qx = ww * sd->xscale[1][ii] + 0.5; + qy = hh - hh * sd->yscale[1][ii] + 0.5; + gdk_draw_line(sd->drawarea->window,gdkgc,px,py,qx,qy); + } + + gdk_gc_set_foreground(gdkgc,&black); + fg_color = black; + + for (spc = 0; spc < sd->Nspc; spc++) + { + if (sd->vert[spc]) // vert. curve + { + for (py = 0; py < hh; py++) // generate all points for curve + { + xval = 1.0 * py / hh; // remove anchor point limits v.10.9 + yval = splcurve_yval(sd,spc,xval); + px = ww * yval + 0.49; // "almost" round - erratic floating point + gdk_draw_point(sd->drawarea->window,gdkgc,px,py); // causes "bumps" in a flat curve + } + + for (ap = 0; ap < sd->nap[spc]; ap++) // draw boxes at anchor points + { + xval = sd->apx[spc][ap]; + yval = sd->apy[spc][ap]; + px = ww * yval; + py = hh * xval; + for (qx = -2; qx < 3; qx++) + for (qy = -2; qy < 3; qy++) { + if (px+qx < 0 || px+qx >= ww) continue; + if (py+qy < 0 || py+qy >= hh) continue; + gdk_draw_point(sd->drawarea->window,gdkgc,px+qx,py+qy); + } + } + } + else // horz. curve + { + for (px = 0; px < ww; px++) // generate all points for curve + { + xval = 1.0 * px / ww; // remove anchor point limits v.10.9 + yval = splcurve_yval(sd,spc,xval); + py = hh - hh * yval + 0.49; // almost round - erratic FP in Intel CPUs + gdk_draw_point(sd->drawarea->window,gdkgc,px,py); // causes "bumps" in a flat curve + } + + for (ap = 0; ap < sd->nap[spc]; ap++) // draw boxes at anchor points + { + xval = sd->apx[spc][ap]; + yval = sd->apy[spc][ap]; + px = ww * xval; + py = hh - hh * yval; + for (qx = -2; qx < 3; qx++) + for (qy = -2; qy < 3; qy++) { + if (px+qx < 0 || px+qx >= ww) continue; + if (py+qy < 0 || py+qy >= hh) continue; + gdk_draw_point(sd->drawarea->window,gdkgc,px+qx,py+qy); + } + } + } + } + + return 0; +} + + +// generate all curve data points when anchor points are modified + +int splcurve_generate(spldat *sd, int spc) +{ + int kk, kklo, kkhi; + double xval, yvalx; + + spline1(sd->nap[spc],sd->apx[spc],sd->apy[spc]); // compute curve fitting anchor points + + kklo = 1000 * sd->apx[spc][0] - 30; // xval range = anchor point range + if (kklo < 0) kklo = 0; // + 0.03 extra below/above v.9.5 + kkhi = 1000 * sd->apx[spc][sd->nap[spc]-1] + 30; + if (kkhi > 1000) kkhi = 1000; + + for (kk = 0; kk < 1000; kk++) // generate all points for curve + { + xval = 0.001 * kk; // remove anchor point limits v.10.9 + yvalx = spline2(xval); + if (yvalx < 0) yvalx = 0; // yval < 0 not allowed, > 1 OK v.9.5 + sd->yval[spc][kk] = yvalx; + } + + return 0; +} + + +// Retrieve curve data using interpolation of saved table of values + +double splcurve_yval(spldat *sd, int spc, double xval) +{ + int ii; + double x1, x2, y1, y2, y3; + + if (xval <= 0) return sd->yval[spc][0]; + if (xval >= 0.999) return sd->yval[spc][999]; + + x2 = 1000.0 * xval; + ii = x2; + x1 = ii; + y1 = sd->yval[spc][ii]; + y2 = sd->yval[spc][ii+1]; + y3 = y1 + (y2 - y1) * (x2 - x1); + return y3; +} + + +// load curve data from a file +// returns 0 if fail (invalid file data), sd not modified +// returns 1 if succcess, sd is initialized from file data + +int splcurve_load(spldat *sd) // v.11.02 +{ + char *pfile; + int nn, ii, jj; + FILE *fid = 0; + int Nspc, vert[10], nap[10]; + double apx[10][50], apy[10][50]; + + zfuncs::F1_help_topic = "curve_edit"; + + pfile = zgetfile1(ZTX("load curve from a file"),"open",saved_curves_dirk); + if (! pfile) return 0; + + fid = fopen(pfile,"r"); + zfree(pfile); + if (! fid) goto fail; + + nn = fscanf(fid,"%d ",&Nspc); // no. of curves + if (nn != 1) goto fail; + if (Nspc < 1 || Nspc > 10) goto fail; + if (Nspc != sd->Nspc) goto fail2; + + for (ii = 0; ii < Nspc; ii++) // loop each curve + { + nn = fscanf(fid,"%d %d ",&vert[ii],&nap[ii]); // vertical flag, no. anchor points + if (nn != 2) goto fail; + if (vert[ii] < 0 || vert[ii] > 1) goto fail; + if (nap[ii] < 2 || nap[ii] > 50) goto fail; + + for (jj = 0; jj < nap[ii]; jj++) // anchor point values + { + nn = fscanf(fid,"%lf/%lf ",&apx[ii][jj],&apy[ii][jj]); + if (nn != 2) goto fail; + if (apx[ii][jj] < 0 || apx[ii][jj] > 1) goto fail; + if (apy[ii][jj] < 0 || apy[ii][jj] > 1) goto fail; + } + } + + fclose(fid); + + sd->Nspc = Nspc; // copy curve data to caller's arg + + for (ii = 0; ii < Nspc; ii++) + { + sd->vert[ii] = vert[ii]; + sd->nap[ii] = nap[ii]; + + for (jj = 0; jj < nap[ii]; jj++) + { + sd->apx[ii][jj] = apx[ii][jj]; + sd->apy[ii][jj] = apy[ii][jj]; + } + } + + for (ii = 0; ii < Nspc; ii++) // generate curve data from anchor points + splcurve_generate(sd,ii); + + if (sd->drawarea) splcurve_draw(0,0,sd); // regen and redraw all curves + + return 1; + +fail: + if (fid) fclose(fid); + zmessageACK(mWin,ZTX("curve file is invalid")); + return 0; + +fail2: + if (fid) fclose(fid); + zmessageACK(mWin,ZTX("curve file has different no. of curves")); + return 0; +} + + +// save curve data to a file + +int splcurve_save(spldat *sd) // v.11.02 +{ + char *pfile, *pp; + int ii, jj; + FILE *fid; + + zfuncs::F1_help_topic = "curve_edit"; + + pp = zgetfile1(ZTX("save curve to a file"),"save",saved_curves_dirk); + if (! pp) return 0; + + pfile = strdupz(pp,8); + zfree(pp); + + pp = strrchr(pfile,'/'); // force .curve extension + if (pp) pp = strrchr(pp,'.'); + if (pp) strcpy(pp,".curve"); + else strcat(pfile,".curve"); + + fid = fopen(pfile,"w"); + zfree(pfile); + if (! fid) return 0; + + fprintf(fid,"%d \n",sd->Nspc); // no. of curves + + for (ii = 0; ii < sd->Nspc; ii++) // loop each curve + { + fprintf(fid,"%d %d \n",sd->vert[ii],sd->nap[ii]); // vertical flag, no. anchor points + for (jj = 0; jj < sd->nap[ii]; jj++) // anchor point values + fprintf(fid,"%.4f/%.4f ",sd->apx[ii][jj],sd->apy[ii][jj]); + fprintf(fid,"\n"); + } + + fclose(fid); + return 0; +} + + +/************************************************************************** + zdialog mouse capture and release +***************************************************************************/ + +void takeMouse(zdialog *zd, CBfunc func, GdkCursor *cursor) // capture mouse for dialog v.11.03 +{ + freeMouse(); + mouseCBfunc = func; + Mcapture = 1; + gdk_window_set_cursor(drWin->window,cursor); // v.11.03 + return; +} + + +void freeMouse() // free mouse for main window v.10.12 +{ + mouseCBfunc = 0; + Mcapture = 0; + paint_toparc(2); // remove mouse circle v.11.04 + gdk_window_set_cursor(drWin->window,0); // set normal cursor v.11.03 + return; +} + + +/************************************************************************** + + edit transaction and thread support functions + + edit transaction management + edit_setup() start new edit - copy E3 > E1 + edit_cancel() cancel edit - E1 > E3, delete E1 + edit_done() commit edit - add to undo stack + edit_undo() undo edit - E1 > E3 + edit_redo() redo edit - run thread again + edit_fullsize() convert preview to full-size pixmaps + + main level thread management + start_thread(func,arg) start thread running + signal_thread() signal thread that work is pending + wait_thread_idle() wait for pending work complete + wrapup_thread(command) wait for exit or command thread exit + + thread function + thread_idle_loop() wait for pending work, exit if commanded + thread_exit() exit thread unconditionally + + thread_status (thread ownership + 0 no thread is running + 1 thread is running and idle (no work) + 2 thread is working + 0 thread has exited + + thread_command (main program ownership) + 0 idle, no work pending + 8 exit when pending work is done + 9 exit now, unconditionally + + thread_pend work requested counter + thread_done work done counter + thread_hiwater high water mark + edit_action done/cancel/undo/redo in progress + +***************************************************************************/ + +int thread_command = 0, thread_status = 0; +int thread_pend = 0, thread_done = 0, thread_hiwater = 0; +int edit_action = 0; + + +/************************************************************************** + + Setup for a new edit transaction + Create E1 (edit input) and E3 (edit output) pixmaps from + previous edit output (Fpxm16) or image file (new Fpxm16). + + Fprev 0 edit full-size image + 1 edit preview image unless select area exists + + Farea 0 select_area is invalid and will be deleted (e.g. rotate) + 1 select_area not used but remains valid (e.g. red-eye) + 2 select_area can be used and remains valid (e.g. flatten) + +***************************************************************************/ + +int edit_setup(editfunc &EF) // support parallel edits v.11.07 +{ + int yn; + PXM *pxmtemp = 0; + + if (! curr_file) return 0; // no image file + if (is_syncbusy()) return 0; // must wait for file sync v.11.11 + + if (! Fpxm16) { // no 16-bit image from prior edit + pxmtemp = f_load(curr_file,16); // check that file can be loaded + if (! pxmtemp) { + printf("f_load (16) failed: %s \n",curr_file); + return 0; + } + } + + if (CEF) { // prior edit function active v.11.07 + if (&EF == CEF) return 0; // 2nd instance of one function + if (EF.Fpara && CEF->Fpara) // check if parallel edits are OK + edit_suspend(); // suspend prior edit + else { + zmessageACK(mWin,ZTX("cannot parallel edit")); + return 0; + } + } + else { // if this is 1st active edit + if (! menulock(1)) return 0; // test menu lock is allowed + menulock(0); // but don't lock yet v.11.07 + } + + if (! Fexiftool && ! Fexifwarned) { + zmessageACK(mWin,ZTX("exiftool is not installed \n" // warn if starting to edit + "edited images will lose EXIF data")); // and exiftool is missing + Fexifwarned = 1; + } + + if (Pundo > maxedits-2) { // undo capacity reached + zmessageACK(mWin,ZTX("Too many edits, please save image")); + return 0; + } + + if (EF.Farea == 0 && sa_stat) { // select area will be lost, warn user + yn = zmessageYN(mWin,ZTX("Select area cannot be kept.\n" + "Continue?")); + if (! yn) return 0; + sa_unselect(); // unselect area + zdialog_free(zdsela); + } + + if (EF.Farea == 2 && sa_stat && ! Factivearea) { // select area exists and can be used, + yn = zmessageYN(mWin,ZTX("Select area not active.\n" // but not active, ask user + "Continue?")); + if (! yn) return 0; + } + + if (! menulock(1)) return 0; // can now commit, lock menu v.11.07 + + Fpreview = 0; // use preview image if supported + if (EF.Fprev && ! (EF.Farea == 2 && Factivearea)) { // and select area will not be used + Fpreview = 1; // use preview image (smaller) + sa_show(0); // hide area if present + curr_image_time = get_seconds(); // mark time of file load v.11.07 + if (Fzoom) { + Fzoom = 0; // bugfix, mwpaint() req. v.11.01 + mwpaint1(); + } + } + + mutex_lock(&Fpixmap_lock); // lock pixmaps + + if (! Fpxm16) Fpxm16 = pxmtemp; // create Fpxm16 if not already + + PXM_fixblue(Fpxm16); // blue=0 >> blue=2 for vpixel() v.11.07 + + if (Fpreview) // edit pixmaps are window-size + E1pxm16 = PXM_rescale(Fpxm16,dww,dhh); // E1pxm16 = Fpxm16 scaled to window + else E1pxm16 = PXM_copy(Fpxm16); // edit pixmaps are full-size + E3pxm16 = PXM_copy(E1pxm16); // E1 >> E3 + + E1ww = E3ww = E1pxm16->ww; // E1 and E3 pixmap dimensions + E1hh = E3hh = E1pxm16->hh; + + mutex_unlock(&Fpixmap_lock); + + if (Pundo == 0) save_undo("initial"); // initial image >> undo stack + + CEF = &EF; // set current edit function + CEF->Fmod = 0; // image not modified yet + + thread_command = thread_status = 0; // no thread running + thread_pend = thread_done = thread_hiwater = 0; // no work pending or done + if (EF.threadfunc) start_thread(EF.threadfunc,0); // start edit thread + + Frefresh++; + mwpaint1(); // mwpaint1() not mwpaint2() + return 1; +} + + +/**************************************************************************/ + +// suspend a parallel edit function so it can be resumed +// edit dialog and curve edit are left active +// logically the equivalent of edit_done() + +void edit_suspend() +{ + wait_thread_idle(); // wait for thread to finish + + if (Fpreview && CEF->Fmod) { // preview image was edited + Fzoom = 0; + edit_fullsize(); // update full image + } + + wrapup_thread(8); // tell thread to finish and exit + + mutex_lock(&Fpixmap_lock); // lock pixmaps + + if (CEF->Fmod) { // image was modified + Fmodified++; // overall mod counter + PXM_free(Fpxm16); + Fpxm16 = E3pxm16; // E3 >> Fpxm16 v.11.07 + E3pxm16 = 0; + PXM_free(Fpxm8); + Fpxm8 = PXM_convbpc(Fpxm16); // Fpxm16 >> Fpxm8 + Fww = Fpxm8->ww; + Fhh = Fpxm8->hh; + Pundo++; // save next undo state + Pumax = Pundo; + save_undo(CEF->funcname); + } + + PXM_free(E1pxm16); // free edit pixmaps + PXM_free(E3pxm16); + PXM_free(ERpxm16); // free redo copy + E1ww = E3ww = ERww = 0; + + mutex_unlock(&Fpixmap_lock); + + CEF = 0; // no current edit func + menulock(0); + mwpaint2(); + return; +} + + +/**************************************************************************/ + +// process edit cancel + +void edit_cancel(editfunc &EF) +{ + if (edit_action) return; + edit_action++; // stop reentry + + if (&EF == CEF) // current edit is canceled v.11.07 + wrapup_thread(9); // tell thread to quit, wait + + if (EF.mousefunc == mouseCBfunc) // if my mouse, free mouse + freeMouse(); + if (EF.zd) zdialog_free(EF.zd); // kill dialog + if (EF.curves) zfree(EF.curves); // free curves data + EF.zd = 0; + EF.curves = 0; + + if (&EF != CEF) { // inactive edit canceled v.11.07 + edit_action = 0; + return; + } + + mutex_lock(&Fpixmap_lock); + PXM_free(E1pxm16); // free edit pixmaps E1, E3 + PXM_free(E3pxm16); + PXM_free(ERpxm16); // free redo copy v.10.3 + E1ww = E3ww = ERww = 0; + mutex_unlock(&Fpixmap_lock); + + if (Fpreview) curr_image_time = get_seconds(); // mark time of file load v.11.07 + Fzoom = 0; // v.11.07 + CEF = 0; // no current edit func + Fpreview = 0; // no preview mode + menulock(0); // unlock menu + mwpaint2(); // refresh window + edit_action = 0; + return; +} + + +/**************************************************************************/ + +// process edit dialog [done] +// E3pxm16 >> Fpxm16 >> Fpxm8 + +void edit_done(editfunc &EF) +{ + if (edit_action) return; + edit_action++; // stop reentry + + if (&EF == CEF) { // current edit is done v.11.07 + wait_thread_idle(); // wait for thread to finish + if (Fpreview && CEF->Fmod) { // preview image was edited + Fzoom = 0; + edit_fullsize(); // update full image + } + wrapup_thread(8); // tell thread to finish and exit + } + + if (EF.mousefunc == mouseCBfunc) // if my mouse, free mouse + freeMouse(); + if (EF.zd) zdialog_free(EF.zd); // kill dialog + if (EF.curves) zfree(EF.curves); // free curves data + EF.zd = 0; + EF.curves = 0; + + if (&EF != CEF) { // inactive edit is done v.11.07 + edit_action = 0; + return; + } + + mutex_lock(&Fpixmap_lock); + + if (CEF->Fmod) { // image was modified + Fmodified++; // overall mod counter + PXM_free(Fpxm16); + Fpxm16 = E3pxm16; // E3 >> Fpxm16 v.11.07 + E3pxm16 = 0; + PXM_free(Fpxm8); + Fpxm8 = PXM_convbpc(Fpxm16); // Fpxm16 >> Fpxm8 + Fww = Fpxm8->ww; + Fhh = Fpxm8->hh; + Pundo++; + Pumax = Pundo; + save_undo(CEF->funcname); // save next undo state + } + + PXM_free(E1pxm16); // free edit pixmaps + PXM_free(E3pxm16); + PXM_free(ERpxm16); // free redo copy v.10.3 + E1ww = E3ww = ERww = 0; + + mutex_unlock(&Fpixmap_lock); + + CEF = 0; // no current edit func + Fpreview = 0; // no preview mode + menulock(0); // unlock menu + mwpaint2(); // update window + edit_action = 0; + return; +} + + +/**************************************************************************/ + +// Setup for edit dialog event or curve edit. +// Call this function before performing any image edit +// (switch current edit function to caller's edit function). + +void edit_takeover(editfunc &EF) // v.11.07 +{ + static int busy = 0; + + if (busy++) return; // KB key bounce + if (CEF && &EF != CEF) { // edit function changed + edit_setup(EF); // close old and setup new edit + if (EF.zd) zdialog_send_event(EF.zd,"reset"); // reset dialog controls v.11.08 + freeMouse(); // free mouse from old dialog v.11.08 + } + busy = 0; + return; +} + + +/**************************************************************************/ + +// edit undo, redo, reset functions +// these apply within an active edit function + +void edit_undo() +{ + if (thread_status == 2) return; // thread busy + if (! CEF->Fmod) return; // not modified + if (edit_action) return; + edit_action++; // stop reentry + + mutex_lock(&Fpixmap_lock); + PXM_free(ERpxm16); // E3 >> redo copy + ERpxm16 = E3pxm16; + ERww = E3ww; + ERhh = E3hh; + E3pxm16 = PXM_copy(E1pxm16); // E1 >> E3 + E3ww = E1ww; + E3hh = E1hh; + mutex_unlock(&Fpixmap_lock); + + CEF->Fmod = 0; // reset image modified status + mwpaint2(); // refresh window + edit_action = 0; + return; +} + + +void edit_redo() +{ + if (thread_status == 2) return; // thread busy + if (! ERpxm16) return; // no prior undo + if (edit_action) return; + edit_action++; // stop reentry + + mutex_lock(&Fpixmap_lock); + PXM_free(E3pxm16); // redo copy >> E3 + E3pxm16 = ERpxm16; + E3ww = ERww; + E3hh = ERhh; + ERpxm16 = 0; + mutex_unlock(&Fpixmap_lock); + + CEF->Fmod = 1; // image modified + Fmodified++; // overall mod counter + mwpaint2(); + edit_action = 0; + return; +} + + +void edit_reset() +{ + if (thread_status == 2) return; // thread busy + if (! CEF->Fmod) return; // not modified + if (edit_action) return; + edit_action++; // stop reentry + + mutex_lock(&Fpixmap_lock); + PXM_free(ERpxm16); // delete redo copy + PXM_free(E3pxm16); + E3pxm16 = PXM_copy(E1pxm16); // E1 >> E3 + E3ww = E1ww; + E3hh = E1hh; + mutex_unlock(&Fpixmap_lock); + + CEF->Fmod = 0; // reset image modified status + mwpaint2(); // refresh window + edit_action = 0; + return; +} + + +void edit_zapredo() +{ + PXM_free(ERpxm16); // no redo copy + return; +} + + +/**************************************************************************/ + +// Convert from preview mode (window-size pixmaps) to full-size pixmaps. +// Can only be used when edit function is in an edit thread with idle_loop +// This function is called directly from some edit functions + +void edit_fullsize() +{ + mutex_lock(&Fpixmap_lock); + PXM_free(E1pxm16); // free preview pixmaps + PXM_free(E3pxm16); + E1pxm16 = PXM_copy(Fpxm16); // make full-size pixmaps + E3pxm16 = PXM_copy(Fpxm16); + E1ww = E3ww = Fww; + E1hh = E3hh = Fhh; + mutex_unlock(&Fpixmap_lock); + + Fpreview = 0; + Fzoom = 0; // v.11.07 + curr_image_time = get_seconds(); // mark time of file load v.11.07 + + if (! CEF->Fmod) return; // no change + signal_thread(); // signal thread, repeat edit + wait_thread_idle(); + return; +} + + +/************************************************************************** + undo / redo toolbar buttons +***************************************************************************/ + +// [undo] menu function - reinstate previous edit in undo/redo stack + +void m_undo(GtkWidget *, cchar *) +{ + if (CEF) { // undo active edit + edit_undo(); // v.11.08 + return; + } + + if (Pundo == 0) return; // undo past edit + if (! menulock(1)) return; + Pundo--; + if (KB_A_key) Pundo = 0; // if KB 'A' key, undo all v.11.11 + load_undo(); + Fmodified = Pundo; // v.11.08 + menulock(0); + return; +} + + +// [redo] menu function - reinstate next edit in undo/redo stack + +void m_redo(GtkWidget *, cchar *) +{ + if (CEF) { // redo active edit + edit_redo(); // v.11.08 + return; + } + + if (Pundo == Pumax) return; + if (! menulock(1)) return; + Pundo++; + if (KB_A_key) Pundo = Pumax; // if KB 'A' key, redo all v.11.11 + load_undo(); + Fmodified = Pundo; // v.11.08 + menulock(0); + return; +} + + +// undo all edits of the current image +// (discard modifications) + +void undo_all() // v.11.04 +{ + if (! menulock(1)) return; + Pundo = 0; // v.11.08 + load_undo(); + Fmodified = 0; // v.11.07 + menulock(0); + return; +} + + +// Save Fpxm16 to undo/redo file stack +// stack position = Pundo + +void save_undo(cchar *funcname) +{ + char *pp, buff[24]; + int fid, cc, cc2; + + pp = strstr(undo_files,"_undo_"); + if (! pp) zappcrash("undo/redo stack corrupted 1"); + snprintf(pp+6,3,"%02d",Pundo); + + fid = open(undo_files,O_WRONLY|O_CREAT|O_TRUNC,0640); + if (! fid) zappcrash("undo/redo stack corrupted 2"); + + snprintf(buff,24," %05d %05d fotoxx ",Fww,Fhh); + cc = write(fid,buff,20); + if (cc != 20) zappcrash("undo/redo stack corrupted 3"); + + cc = Fww * Fhh * 6; + cc2 = write(fid,Fpxm16->bmp,cc); + if (cc2 != cc) zappcrash("undo/redo stack corrupted 4"); + + close(fid); + + pvlist_replace(editlog,Pundo,funcname); // save log of edits done + return; +} + + +// Load Fpxm16 from undo/redo file stack +// stack position = Pundo + +void load_undo() +{ + char *pp, buff[24], fotoxx[8]; + int fid, ww, hh, cc, cc2; + + pp = strstr(undo_files,"_undo_"); + if (! pp) zappcrash("undo/redo stack corrupted 1"); + snprintf(pp+6,3,"%02d",Pundo); + + fid = open(undo_files,O_RDONLY); + if (! fid) zappcrash("undo/redo stack corrupted 2"); + + *fotoxx = 0; + cc = read(fid,buff,20); + sscanf(buff," %d %d %8s ",&ww, &hh, fotoxx); + if (! strEqu(fotoxx,"fotoxx")) zappcrash("undo/redo stack corrupted 4"); + + mutex_lock(&Fpixmap_lock); + + PXM_free(Fpxm16); + Fpxm16 = PXM_make(ww,hh,16); + cc = ww * hh * 6; + cc2 = read(fid,Fpxm16->bmp,cc); + if (cc2 != cc) zappcrash("undo/redo stack corrupted 5"); + close(fid); + + PXM_free(Fpxm8); + Fpxm8 = PXM_convbpc(Fpxm16); + + Fww = ww; + Fhh = hh; + + if (sa_fww != Fww || sa_fhh != Fhh) // disable area if image size changes + sa_disable(); // bugfix v.11.08 + + mutex_unlock(&Fpixmap_lock); + mwpaint2(); + return; +} + + +/**************************************************************************/ + +// ask user if modified image should be kept or discarded +// returns: 0 = mods discarded, 1 = do not discard mods + +int mod_keep() +{ + int keep = 0, choice = 0; + cchar *title = ZTX("Discard edits?"); + cchar *message = ZTX("This action will discard current edits.\n" // more clarity v.11.10 + "Continue to discard edits.\n" + "Go Back to keep edits."); + cchar *continu = ZTX("Continue"); + cchar *goback = ZTX("Go Back"); + + if (Fsaved < Pundo) keep = 1; // curr. edits not saved + if (keep == 0) return 0; // no mods + choice = zdialog_choose(title,mWin,message,continu,goback,null); + if (choice == 2) return 1; // keep mods + undo_all(); // discard mods + return 0; +} + + +/**************************************************************************/ + +// menu lock/unlock - some functions must not run concurrently +// returns 1 if success, else 0 + +int menulock(int lock) +{ + if (! lock && ! Fmenulock) zappcrash("menu lock error"); + if (lock && Fmenulock) { + zmessageACK(mWin,ZTX("prior function still active")); // v.11.06 + return 0; + } + if (lock) Fmenulock++; + else Fmenulock--; + return 1; +} + + +/**************************************************************************/ + +// check if Fsyncbusy is active, return 0 if not, +// otherwise message user and return 1 + +int is_syncbusy() +{ + if (! Fsyncbusy) return 0; + threadmessage = "Synchronize files is running. Edits are blocked. \n" + "You can still navigate and view images normally."; + return 1; +} + + +/**************************************************************************/ + +// start thread that does the edit work + +void start_thread(threadfunc func, void *arg) +{ + thread_status = 1; // thread is running + thread_command = thread_pend = thread_done = thread_hiwater = 0; // nothing pending + start_detached_thread(func,arg); + return; +} + + +// signal thread that work is pending + +void signal_thread() +{ + edit_zapredo(); // reset redo copy + if (thread_status > 0) thread_pend++; + return; +} + + +// wait for edit thread to complete pending work and become idle + +void wait_thread_idle() +{ + while (thread_status && thread_pend > thread_done) + { + zmainloop(); + zsleep(0.01); + } + + return; +} + + +// wait for thread exit or command thread exit +// command = 0 wait for normal completion +// 8 finish pending work and exit +// 9 quit, exit now + +void wrapup_thread(int command) +{ + thread_command = command; // tell thread to quit or finish + + while (thread_status > 0) // wait for thread to finish + { // pending work and exit + zmainloop(); + zsleep(0.01); + } + + return; +} + + +// called only from edit threads +// idle loop - wait for work request or exit command + +void thread_idle_loop() +{ + if (thread_status == 2) Ffuncbusy--; // v.11.05 + thread_status = 1; // status = idle + thread_done = thread_hiwater; // work done = high-water mark + + while (true) + { + if (thread_command == 9) thread_exit(); // quit now command + if (thread_command == 8) // finish work and exit + if (thread_pend <= thread_done) thread_exit(); + if (thread_pend > thread_done) break; // wait for work request + zsleep(0.01); + } + + thread_hiwater = thread_pend; // set high-water mark + thread_status = 2; // thread is working + Ffuncbusy++; // v.11.05 + return; // perform edit +} + + +// exit thread unconditionally, called only from edit threads + +void thread_exit() +{ + if (thread_status == 2) Ffuncbusy--; // v.11.05 + thread_pend = thread_done = thread_hiwater = 0; + thread_status = 0; + pthread_exit(0); // "return" cannot be used here +} + + +/**************************************************************************/ + +// edit support functions for working threads (per processor core) + +void start_wthread(threadfunc func, void *arg) // start and increment busy count +{ + zadd_locked(wthreads_busy,+1); + zadd_locked(Ffuncbusy,+1); // v.11.01 + start_detached_thread(func,arg); + return; +} + + +void exit_wthread() // decrement busy count and exit +{ + zadd_locked(Ffuncbusy,-1); // v.11.01 + zadd_locked(wthreads_busy,-1); + pthread_exit(0); // "return" cannot be used here v.9.4 +} + + +void wait_wthreads() // wait for all working threads done +{ // caller can be main() or a thread + while (wthreads_busy) { + zsleep(0.01); + zmainloop(); // v.11.11.1 + } + return; +} + + +/************************************************************************** + other support functions +***************************************************************************/ + +// help menu function + +void m_help(GtkWidget *, cchar *menu) +{ + if (strEqu(menu,ZTX("About"))) + zmessageACK(mWin,"%s \n%s \n%s \n%s \n%s \n%s", + fversion,flicense,fhomepage,fcontact,fcredits,ftranslators); + + if (strEqu(menu,ZTX("User Guide"))) + showz_userguide(); + + if (strEqu(menu,ZTX("User Guide Changes"))) + showz_userguide("changes"); + + if (strEqu(menu,ZTX("Help"))) // toolbar button + showz_userguide(zfuncs::F1_help_topic); // show topic if there, or page 1 + + if (strEqu(menu,"README")) + showz_readme(); + + if (strEqu(menu,ZTX("Edit Functions Summary"))) // v.11.11 + showz_doctext("edit-menus"); + + if (strEqu(menu,ZTX("Change Log"))) + showz_changelog(); + + if (strEqu(menu,ZTX("Translations"))) + showz_translations(); + + if (strEqu(menu,ZTX("Home Page"))) + showz_html(fhomepage); + + return; +} + + +/**************************************************************************/ + +// table for loading and saving adjustable parameters between sessions + +typedef struct { + char name[20]; + char type[12]; + int count; + void *location; +} param; + +#define Nparms 33 + +param paramTab[Nparms] = { +// name type count location +{ "fotoxx version", "char", 1, &pversion }, +{ "last session", "char", 1, &last_session }, +{ "first time", "int", 1, &Ffirsttime }, +{ "new files found", "int", 1, &newfiles }, +{ "window geometry", "int", 4, &mwgeom }, +{ "toolbar style", "char", 1, &tbar_style }, +{ "warn overwrite", "int", 1, &Fwarnoverwrite }, +{ "zoom ratio", "char", 1, &zoomratio }, +{ "startup display", "char", 1, &startdisplay }, +{ "start image file", "char", 1, &startfile }, +{ "start directory", "char", 1, &startdirk }, +{ "lens mm and bow", "double", 2, &lens_settings }, +{ "trim size", "int", 2, &trimsize }, +{ "trim buttons", "char", 6, &trimbuttons }, +{ "trim ratios", "char", 6, &trimratios }, +{ "edit resize", "int", 2, &editresize }, +{ "batch resize", "int", 2, &batchresize }, +{ "e-mail resize", "int", 2, &emailsize }, +{ "annotate font", "char", 1, &annotate_font }, +{ "annotate text", "char", 1, &annotate_text }, +{ "annotate color", "char", 3, &annotate_color }, +{ "annotate trans", "int", 3, &annotate_trans }, +{ "annotate outline", "int", 1, &annotate_outline }, +{ "annotate angle", "double", 1, &annotate_angle }, +{ "grid spacing", "int", 2, &gridspace }, +{ "grid counts", "int", 2, &gridcount }, +{ "rotate grid", "int", 8, &rotate_grid }, +{ "unbend grid", "int", 8, &unbend_grid }, +{ "warp-curved grid", "int", 8, &warpC_grid }, +{ "warp-linear grid", "int", 8, &warpL_grid }, +{ "warp-affine grid", "int", 8, &warpF_grid }, +{ "slideshow trans", "int", SSNF, &ss_funcs }, +{ "slideshow music", "char", 1, &ss_musicfile } }; + + +// save parameters to file /home//.fotoxx/parameters + +void save_params() // new v.10.9 +{ + FILE *fid; + char buff[1050], text[1000]; // limit for character data cc + char *pp, *name, *type; + int count; + void *location; + char **charloc; + int *intloc; + double *doubleloc; + time_t currtime; + + pversion = strdupz(fversion); // this fotoxx version v.11.10 + + currtime = time(0); + last_session = ctime(&currtime) + 4; // fotoxx session exit time v.11.11 + if (last_session[4] == ' ') last_session[4] = '0'; // format mmm dd hh:mm:ss yyyy + pp = strchr(last_session,'\n'); + if (pp) *pp = 0; + + snprintf(buff,199,"%s/parameters",get_zuserdir()); // open output file + fid = fopen(buff,"w"); + if (! fid) return; + + for (int ii = 0; ii < Nparms; ii++) // write table of state data + { + name = paramTab[ii].name; + type = paramTab[ii].type; + count = paramTab[ii].count; + location = paramTab[ii].location; + charloc = (char **) location; + intloc = (int *) location; + doubleloc = (double *) location; + + fprintf(fid,"%-20s %-8s %02d ",name,type,count); // write parm name, type, count + + for (int kk = 0; kk < count; kk++) // write "value" "value" ... + { + if (strEqu(type,"char")) { + if (! *charloc) printf("bad param data %s %d \n",name,kk); // bugfix v.10.11.1 + if (! *charloc) break; + repl_1str(*charloc++,text,"\n","\\n"); // replace newlines with "\n" v.10.11 + fprintf(fid," \"%s\"",text); + } + if (strEqu(type,"int")) + fprintf(fid," \"%d\"",*intloc++); + + if (strEqu(type,"double")) + fprintf(fid," \"%.2f\"",*doubleloc++); + } + + fprintf(fid,"\n"); // write EOR + } + + fprintf(fid,"\n"); + fclose(fid); // close file + + fid = fopen(recentfiles_file,"w"); // recent files file + if (! fid) return; + + for (int ii = 0; ii < Nrecentfiles; ii++) // save list of recent files + if (recentfiles[ii]) + fprintf(fid,"%s \n",recentfiles[ii]); + + fclose(fid); + + snprintf(buff,199,"%s/plugins",get_zuserdir()); // open file for plugins v.11.03 + fid = fopen(buff,"w"); + if (! fid) return; + + for (int ii = 0; ii < Nplugins; ii++) // save plugins + if (plugins[ii]) + fprintf(fid,"%s \n",plugins[ii]); + + fclose(fid); + + return; +} + + +// load parameters from file /home//.fotoxx/parameters + +void load_params() // new v.10.9 +{ + FILE *fid; + int ii, err, cc, pcount, Idata; + double Rdata; + char buff[1000], text[1000], *pp; + char name[20], type[12], count[8], data[1000]; + void *location; + char **charloc; + int *intloc; + double *doubleloc; + struct stat statb; + + for (ii = 0; ii < Nparms; ii++) // set string parameters to "undefined" + { // v.10.11 + if (strNeq(paramTab[ii].type,"char")) continue; + charloc = (char **) paramTab[ii].location; + pcount = paramTab[ii].count; + for (int jj = 0; jj < pcount; jj++) + *charloc++ = strdupz("undefined",20); + } + + snprintf(buff,499,"%s/parameters",get_zuserdir()); // open parameters file + fid = fopen(buff,"r"); + if (! fid) return; // none, defaults are used + + while (true) // read parameters + { + pp = fgets_trim(buff,999,fid,1); + if (! pp) break; + if (*pp == '#') continue; // comment v.10.10 + if (strlen(pp) < 40) continue; // rubbish v.10.10 + + err = 0; + + strncpy0(name,pp,20); // parm name + strTrim2(name); + + strncpy0(type,pp+22,8); // parm type + strTrim2(type); + + strncpy0(count,pp+32,4); // parm count + strTrim2(count); + err = convSI(count,pcount); + + strncpy0(data,pp+38,1000); // parm value(s) + strTrim2(data); + + for (ii = 0; ii < Nparms; ii++) // match file record to param table + { + if (strNeq(name,paramTab[ii].name)) continue; // parm name + if (strNeq(type,paramTab[ii].type)) continue; // parm type + if (paramTab[ii].count != pcount) continue; // parm count + + location = paramTab[ii].location; + charloc = (char **) location; + intloc = (int *) location; + doubleloc = (double *) location; + + for (int kk = 1; kk <= pcount; kk++) + { + pp = (char *) strField(data,' ',kk); + if (! pp) break; + + if (strEqu(type,"char")) { + repl_1str(pp,text,"\\n","\n"); // replace "\n" with real newlines v.10.11 + *charloc++ = strdupz(text,0,"parameters"); // v.11.04 + } + + if (strEqu(type,"int")) { + err = convSI(pp,Idata); + if (err) continue; + *intloc++ = Idata; + } + + if (strEqu(type,"double")) { + err = convSD(pp,Rdata); + if (err) continue; + *doubleloc++ = Rdata; + } + } + } + } + + fclose(fid); + + if (strNeq(pversion,fversion)) // fotoxx version change v.11.10 + printf("new Fotoxx version %s %s \n",pversion,fversion); + + topdirk = 0; + + fid = fopen(topdirk_file,"r"); // set top directory from v.11.11 + if (fid) { // from top directory file + pp = fgets_trim(buff,499,fid,1); + if (pp && *pp == '/') + topdirk = strdupz(buff,0,"top_dirk"); + fclose(fid); + } + + if (topdirk) { // v.11.12.1 + err = stat(topdirk,&statb); + if (! err && S_ISDIR(statb.st_mode)) { + cc = strlen(topdirk); // remove trailing '/' if present + if (topdirk[cc-1] == '/') topdirk[cc-1] = 0; // v.11.12 + } + else topdirk = 0; // v.11.12.1 + } + + for (ii = 0; ii < Nrecentfiles; ii++) // recent image file list = empty + recentfiles[ii] = 0; + + fid = fopen(recentfiles_file,"r"); // open recent files file + if (fid) { + for (ii = 0; ii < Nrecentfiles; ii++) // read list of recent files + { + pp = fgets_trim(buff,499,fid,1); + if (! pp) break; + if (*pp == '/') + recentfiles[ii] = strdupz(buff,0,"recentfile"); + else ii--; // v.11.11 + } + + fclose(fid); + } + + for (ii = 0; ii < maxplugins; ii++) // plugins list = empty v.11.03 + plugins[ii] = 0; + + plugins[0] = strdupz("Gimp = gimp"); // if empty, default Gimp plugin + Nplugins = 1; + + snprintf(buff,499,"%s/plugins",get_zuserdir()); // open plugins file v.11.03 + fid = fopen(buff,"r"); + if (fid) + { + for (ii = 0; ii < maxplugins; ii++) // read list of plugins + { + pp = fgets_trim(buff,499,fid,1); + if (! pp) break; + plugins[ii] = strdupz(buff,0,"plugins"); + } + + fclose(fid); + Nplugins = ii; + } + + return; +} + + +/**************************************************************************/ + +// Compute the mean brightness of all pixel neighborhoods, // new v.9.6 +// using a Guassian or a flat distribution for the weightings. +// If a select area is active, only inside pixels are calculated. +// The flat method is 10-100x faster. + +int brhood_radius; +double brhood_kernel[200][200]; // up to radius = 99 +float *brhood_brightness = 0; // neighborhood brightness per pixel +char brhood_method; // g = gaussian, f = flat distribution + + +void brhood_calc(int radius, char method) +{ + void * brhood_wthread(void *arg); + + int rad, rad2, dx, dy, cc, ii; + double kern; + + brhood_radius = radius; + brhood_method = method; + + if (brhood_method == 'g') // compute Gaussian kernel + { // (not currently used v.11.02) + rad = brhood_radius; + rad2 = rad * rad; + + for (dy = -rad; dy <= rad; dy++) + for (dx = -rad; dx <= rad; dx++) + { + if (dx*dx + dy*dy <= rad2) // cells within radius + kern = exp( - (dx*dx + dy*dy) / rad2); + else kern = 0; // outside radius + brhood_kernel[dy+rad][dx+rad] = kern; + } + } + + if (brhood_brightness) zfree(brhood_brightness); // allocate memory for pixel map + cc = E1ww * E1hh * sizeof(float); + brhood_brightness = (float *) zmalloc(cc,"brhood"); + memset(brhood_brightness,0,cc); + + if (Factivearea) SB_goal = sa_Npixel; // set up progress tracking + else SB_goal = E1ww * E1hh; + SB_done = 0; // v.11.06 + + for (ii = 0; ii < Nwt; ii++) // start worker threads + start_wthread(brhood_wthread,&wtnx[ii]); + wait_wthreads(); // wait for completion + + SB_goal = 0; + return; +} + + +// worker thread function + +void * brhood_wthread(void *arg) +{ + int index = *((int *) arg); + int rad = brhood_radius; + int ii, px, py, qx, qy, Fstart; + double kern, bsum, bsamp, bmean; + uint16 *pixel; + + if (brhood_method == 'g') // use round gaussian distribution + { + for (py = index; py < E1hh; py += Nwt) + for (px = 0; px < E1ww; px++) + { + if (Factivearea && sa_mode != 7) { // select area, not whole image v.11.02 + ii = py * E1ww + px; // use only inside pixels + if (! sa_pixmap[ii]) continue; + } + + bsum = bsamp = 0; + + for (qy = py-rad; qy <= py+rad; qy++) // computed weighted sum of brightness + for (qx = px-rad; qx <= px+rad; qx++) // for pixels in neighborhood + { + if (qy < 0 || qy > E1hh-1) continue; + if (qx < 0 || qx > E1ww-1) continue; + kern = brhood_kernel[qy+rad-py][qx+rad-px]; + pixel = PXMpix(E1pxm16,qx,qy); + bsum += pixbright(pixel) * kern; // sum brightness * weight + bsamp += kern; // sum weights + } + + bmean = bsum / bsamp; // mean brightness + ii = py * E1ww + px; + brhood_brightness[ii] = bmean; // pixel value + + SB_done++; // track progress v.11.06 + if (drandz() < 0.0001) zsleep(0.001); // trigger sorry kernel scheduler + } + } + + if (brhood_method == 'f') // use square flat distribution + { + Fstart = 1; + bsum = bsamp = 0; + + for (py = index; py < E1hh; py += Nwt) + for (px = 0; px < E1ww; px++) + { + if (Factivearea && sa_mode != 7) { // select area, not whole image v.11.02 + ii = py * E1ww + px; // compute only inside pixels + if (! sa_pixmap[ii]) { + Fstart = 1; + continue; + } + } + + if (px == 0) Fstart = 1; + + if (Fstart) + { + Fstart = 0; + bsum = bsamp = 0; + + for (qy = py-rad; qy <= py+rad; qy++) // add up all columns + for (qx = px-rad; qx <= px+rad; qx++) + { + if (qy < 0 || qy > E1hh-1) continue; + if (qx < 0 || qx > E1ww-1) continue; + pixel = PXMpix(E1pxm16,qx,qy); + bsum += pixbright(pixel); + bsamp += 1; + } + } + else + { + qx = px-rad-1; // subtract first-1 column + if (qx >= 0) { + for (qy = py-rad; qy <= py+rad; qy++) + { + if (qy < 0 || qy > E1hh-1) continue; + pixel = PXMpix(E1pxm16,qx,qy); + bsum -= pixbright(pixel); + bsamp -= 1; + } + } + qx = px+rad; // add last column + if (qx < E1ww) { + for (qy = py-rad; qy <= py+rad; qy++) + { + if (qy < 0 || qy > E1hh-1) continue; + pixel = PXMpix(E1pxm16,qx,qy); + bsum += pixbright(pixel); + bsamp += 1; + } + } + } + + bmean = bsum / bsamp; // mean brightness + ii = py * E1ww + px; + brhood_brightness[ii] = bmean; + + SB_done++; // track progress v.11.06 + if (drandz() < 0.0001) zsleep(0.001); // trigger sorry kernel scheduler + } + } + + exit_wthread(); + return 0; // not executed, avoid gcc warning +} + + +// get the neighborhood brightness for given pixel + +float get_brhood(int px, int py) +{ + int ii = py * E1ww + px; + return brhood_brightness[ii]; +} + + +/**************************************************************************/ + +// free all resources associated with the current image file + +void free_resources(int fkeepundo) +{ + char *pp; + int err; + + mutex_lock(&Fpixmap_lock); // lock pixmaps + + if (! fkeepundo) { + strcpy(command,"rm -f "); // delete all undo files + strcat(command,undo_files); + pp = strstr(command,"_undo_"); // /home/user/.fotoxx/pppppp_undo_* + strcpy(pp + 6,"*"); + err = system(command); + if (err) printf("error: %s \n",wstrerror(err)); + Fmodified = Pundo = Pumax = Fsaved = 0; // reset undo/redo stack + } + + if (Fshutdown) { // stop here if shutdown mode + mutex_unlock(&Fpixmap_lock); + return; + } + + Ntoplines = Nptoplines; // no image overlay lines + freeMouse(); // free mouse v.11.04 + + if (curr_file) { + sa_unselect(); // unselect select area + zdialog_free(zdsela); // kill dialogs if active + zfree(curr_file); // free image file + curr_file = 0; + SB_goal = 0; // v.9.2 + *SB_text = 0; // v.10.7 + } + + if (brhood_brightness) zfree(brhood_brightness); // free brightness map v.9.6 + brhood_brightness = 0; + + PXM_free(Fpxm8); + PXM_free(Dpxm8); + PXM_free(Fpxm16); + PXM_free(E1pxm16); + PXM_free(E3pxm16); + PXM_free(ERpxm16); // v.10.3 + + Fww = E1ww = E3ww = Dww = 0; // make unusable (crash) + + mutex_unlock(&Fpixmap_lock); + return; +} + + +// Get a virtual pixel at location (px,py) (real) in an PXM-16 pixmap. +// Get the overlapping real pixels and build a composite. + +int vpixel(PXM *pxm, double px, double py, uint16 *vpix) +{ + int ww, hh, px0, py0; + uint16 *ppix, *pix0, *pix1, *pix2, *pix3; + double f0, f1, f2, f3; + double red, green, blue; + + ww = pxm->ww; + hh = pxm->hh; + ppix = (uint16 *) pxm->bmp; + + px0 = px; // pixel containing (px,py) + py0 = py; + + if (px0 < 1 || py0 < 1) return 0; // void edge pixels + if (px0 > ww-3 || py0 > hh-3) return 0; + + pix0 = ppix + (py0 * ww + px0) * 3; // 4 pixels based at (px0,py0) + pix1 = pix0 + ww * 3; + pix2 = pix0 + 3; + pix3 = pix0 + ww * 3 + 3; + + f0 = (px0+1 - px) * (py0+1 - py); // overlap of (px,py) + f1 = (px0+1 - px) * (py - py0); // in each of the 4 pixels + f2 = (px - px0) * (py0+1 - py); + f3 = (px - px0) * (py - py0); + + red = f0 * pix0[0] + f1 * pix1[0] + f2 * pix2[0] + f3 * pix3[0]; // sum the weighted inputs + green = f0 * pix0[1] + f1 * pix1[1] + f2 * pix2[1] + f3 * pix3[1]; + blue = f0 * pix0[2] + f1 * pix1[2] + f2 * pix2[2] + f3 * pix3[2]; + + vpix[0] = red; + vpix[1] = green; + vpix[2] = blue; + + if (blue < 1) { // v.10.7 + if (blue < 0.9) return 0; // near edge or voided area + vpix[2] = 1; // avoid 0.999 to integer 0 + } + + return 1; +} + + +// compare two doubles for significant difference +// return: 0 difference not significant +// +1 d1 > d2 +// -1 d1 < d2 + +int sigdiff(double d1, double d2, double signf) +{ + double diff = fabs(d1-d2); + if (diff == 0.0) return 0; + diff = diff / (fabs(d1) + fabs(d2)); + if (diff < signf) return 0; + if (d1 > d2) return 1; + else return -1; +} + + +/************************************************************************** + file read and write utilities + PXM pixmap <--> file on disk +***************************************************************************/ + +// Load an image file into an PXM pixmap of 8 or 16 bits/color +// Also sets the following file scope variables: +// f_load_type = "jpg" "tif" "png" or "other" +// f_load_bpc = disk file bits per color = 1/8/16 +// f_load_size = disk file size + +PXM * f_load(cchar *filespec, int bpc) // use pixbuf or tiff library v.9.8 +{ + int err; + cchar *pext; + PXM *pxm1, *pxm2; + struct stat fstat; + + if (bpc != 8 && bpc != 16) // requested bpc must be 8 or 16 + zappcrash("image_load bpc: %d",bpc); + + err = stat(filespec,&fstat); + if (err) return 0; // file not found + if (! S_ISREG(fstat.st_mode)) return 0; // not a regular file + if (image_file_type(filespec) != 2) return 0; // not a supported image type + f_load_size = fstat.st_size; // disk file bytes + + pext = strrchr(filespec,'/'); + if (! pext) pext = filespec; + + if (pext > filespec+12 && strnEqu(pext-12,"/.thumbnails/",13)) { // refuse thumbnail files v.10.0 + zmessageACK(mWin,ZTX("cannot open thumbnail file")); + return 0; + } + + pext = strrchr(pext,'.'); + if (! pext) pext = ""; + + if (strstr(".jpg .jpeg .JPG .JPEG",pext)) strcpy(f_load_type,"jpg"); + else if (strstr(".tif .tiff .TIF .TIFF",pext)) strcpy(f_load_type,"tif"); + else if (strstr(".png .PNG",pext)) strcpy(f_load_type,"png"); + else strcpy(f_load_type,"other"); + + if (strEqu(f_load_type,"tif")) // use tiff lib to read tiff file + pxm1 = TIFFread(filespec); + else pxm1 = PXBread(filespec); // use pixbuf lib for others + if (! pxm1) return 0; // both set f_load_bpc = file bpc + + if (pxm1->bpc != bpc) { + pxm2 = PXM_convbpc(pxm1); // convert to requested bpc + PXM_free(pxm1); // 8 <--> 16 + pxm1 = pxm2; + } + // auto upright image removed v.10.12 + return pxm1; +} + + +/**************************************************************************/ + +// save current image to specified disk file (same or new). +// set f_save_type, f_save_bpc, f_save_size +// update search index file +// return 0 if OK, else +N + +int f_save(char *outfile, cchar *type, int bpc) // use pixbuf or tiff library v.9.8 +{ + PXM *pxm16; + cchar *exifkey[2] = { exif_orientation_key, iptc_editlog_key }; + cchar *exifdata[2]; + char **ppv, funcslist[1000]; + char *pp, *tempfile, *pext; + int nkeys, err = 1, cc1, cc2; + struct stat fstat; + + if ((bpc != 8 && bpc != 16) || ! strstr("jpg tif png",type)) // check args + zappcrash("f_save: %s %d",type,bpc); + + Ffuncbusy++; // v.11.01 + + pext = strrchr(outfile,'/'); // force compatible file extension + if (pext) pext = strrchr(pext,'.'); // if not already + if (! pext) pext = outfile + strlen(outfile); + if (strEqu(type,"jpg") && ! strstr(".jpg .JPG .jpeg .JPEG",pext)) + strcpy(pext,".jpg"); + if (strEqu(type,"png") && ! strstr(".png .PNG",pext)) + strcpy(pext,".png"); + if (strEqu(type,"tif") && ! strstr(".tif .TIF .tiff .TIFF",pext)) + strcpy(pext,".tif"); + + tempfile = strdupz(get_zuserdir(),24,"f_save"); // use temp output file + strcat(tempfile,"/temp_"); // ~/.fotoxx/temp_ppppp.ext + strcat(tempfile,PIDstring); + strcat(tempfile,"."); + strcat(tempfile,type); + + if (strEqu(type,"png")) { // save as PNG file (bpc = 8 always) + if (Fpxm16) err = PXBwrite(Fpxm16,tempfile); + else err = PXBwrite(Fpxm8,tempfile); + bpc = 8; + } + + else if (strEqu(type,"tif")) { // save as tiff file + if (bpc == 8) { + if (Fpxm16) { + PXM_free(Fpxm8); // bugfix v.10.8 + Fpxm8 = PXM_convbpc(Fpxm16); + } + err = TIFFwrite(Fpxm8,tempfile); + } + else if (bpc == 16) { + if (Fpxm16) err = TIFFwrite(Fpxm16,tempfile); // edit file exists, use it + else { + if (curr_file_bpc == 16) pxm16 = TIFFread(curr_file); // use original 16 bpc file + else pxm16 = PXM_convbpc(Fpxm8); // or convert 8 to 16 bpc + if (! pxm16) err = 1; + else { + err = TIFFwrite(pxm16,tempfile); + PXM_free(pxm16); + } + } + } + } + + else { // save as JPEG file (bpc = 8 always) + if (Fpxm16) err = PXBwrite(Fpxm16,tempfile); + else err = PXBwrite(Fpxm8,tempfile); + bpc = 8; + } + + if (err) { + remove(tempfile); // failure, clean up v.11.02 + zfree(tempfile); + Ffuncbusy--; + return 1; + } + + exifdata[0] = ""; // EXIF orientation = upright + nkeys = 1; // remove old width, height v.10.8 + + if (Pundo > 0) // if edits were made, + { // update relevant EXIF key v.10.2 + *funcslist = 0; + ppv = info_get(curr_file,&exifkey[1],1); // get existing list of edits + if (ppv[0]) { + strncpy0(funcslist,ppv[0],998); + zfree(ppv[0]); + } + cc1 = strlen(funcslist); // add blank + if (cc1 && funcslist[cc1-1] != ' ') { + strcpy(funcslist+cc1," "); + cc1++; + } + + for (int ii = 1; ii <= Pundo; ii++) // append new list of edits + { // (omit index 0 = initial) + pp = pvlist_get(editlog,ii); + cc2 = strlen(pp); + if (cc1 + cc2 > 998) break; + strcpy(funcslist+cc1,pp); + strcpy(funcslist+cc1+cc2," "); + cc1 += cc2 + 1; + } + + exifdata[1] = funcslist; // IPTC edit history key, fotoxx edits done + nkeys = 2; + } + + err = stat(curr_file,&fstat); + if (! err && S_ISREG(fstat.st_mode)) { // if current file exists, v.11.05 + err = info_copy(curr_file,tempfile,exifkey,exifdata,nkeys); // copy all EXIF/IPTC data to + if (err) zmessageACK(mWin,"Unable to copy EXIF/IPTC"); // temp file with above revisions + } + + snprintf(command,ccc,"cp -f \"%s\" \"%s\" ",tempfile,outfile); // copy temp file to output file + err = system(command); + if (err) zmessageACK(mWin,"Unable to save image: %s",wstrerror(err)); + + remove(tempfile); // delete temp file v.11.02 + zfree(tempfile); + + save_fileinfo(outfile); // save tag changes if any + if (! curr_file || strNeq(outfile,curr_file)) // if save to new file, v.11.08 + update_search_index(outfile); // update search index file + + Fsaved = Pundo; // update which mods are saved to disk + + add_recent_file(outfile); // first in recent files list + + strcpy(f_save_type,type); // update f_save_xxx data + f_save_bpc = bpc; + + err = stat(outfile,&fstat); + if (err) { + Ffuncbusy--; + return 1; + } + + f_save_size = fstat.st_size; + + Ffuncbusy--; + mwpaint2(); // v.11.03 + return 0; +} + + +/**************************************************************************/ + +// intercept TIFF warning messages (many) // new v.9.8 + +void tiffwarninghandler(cchar *module, cchar *format, va_list ap) +{ + return; // stop flood of crap + char message[200]; + vsnprintf(message,199,format,ap); + printf("TIFF warning: %s %s \n",module,message); + return; +} + + +// Read from TIFF file using TIFF library. +// Use native TIFF file bits/pixel. + +PXM * TIFFread(cchar *filespec) // overhauled v.10.8.1 +{ + static int ftf = 1; + TIFF *tiff; + PXM *pxm; + char *tiffbuff; + uint8 *tiff8, *pxm8; + uint16 *tiff16, *pxm16; + uint16 bpc, nch, fmt; + int ww, hh, rps, stb, nst; // int not uint v.11.03 + int tiffstat, row, col, strip, cc; + + if (ftf) { + TIFFSetWarningHandler(tiffwarninghandler); // intercept TIFF warning messages + ftf = 0; + } + + tiff = TIFFOpen(filespec,"r"); + if (! tiff) { + zmessageACK(mWin,ZTX("TIFF open failure")); + return 0; + } + + TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &ww); // width + TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &hh); // height + TIFFGetField(tiff, TIFFTAG_BITSPERSAMPLE, &bpc); // bits per color, 1/8/16 + TIFFGetField(tiff, TIFFTAG_SAMPLESPERPIXEL, &nch); // no. channels (colors), 1/3/4 + TIFFGetField(tiff, TIFFTAG_ROWSPERSTRIP, &rps); // rows per strip + TIFFGetField(tiff, TIFFTAG_SAMPLEFORMAT, &fmt); // data format + stb = TIFFStripSize(tiff); // strip size + nst = TIFFNumberOfStrips(tiff); // number of strips + +// printf("ww %d hh %d nch %d bpc %d rps %d stb %d nst %d fmt %d \n",ww,hh,nch,bpc,rps,stb,nst,fmt); + + if (! (bpc <= 8 || bpc == 16)) { // check for supported bits/color + zmessageACK(mWin,ZTX("TIFF bits/color=%d not supported"),bpc); + TIFFClose(tiff); + return 0; + } + + f_load_bpc = bpc; // for f_load(), file bpc 1/8/16 v.10.12 + + if (bpc <= 8) // use universal TIFF reader + { // if bits/color <= 8 + tiffbuff = zmalloc(ww*hh*4,"tiffbuff"); + + tiffstat = TIFFReadRGBAImage(tiff, ww, hh, (uint *) tiffbuff, 0); + TIFFClose(tiff); + + if (tiffstat != 1) { + zmessageACK(mWin,ZTX("TIFF read failure")); + zfree(tiffbuff); + return 0; + } + + pxm = PXM_make(ww,hh,8); + + tiff8 = (uint8 *) tiffbuff; + + for (row = 0; row < hh; row++) // convert RGBA to RGB + { + pxm8 = (uint8 *) pxm->bmp; + pxm8 += (hh-1 - row) * ww * 3; + + for (col = 0; col < ww; col++) + { + pxm8[0] = tiff8[0]; + pxm8[1] = tiff8[1]; + pxm8[2] = tiff8[2]; + pxm8 += 3; + tiff8 += 4; + } + } + + zfree(tiffbuff); + return pxm; + } + // 16 bits per color + + stb += 1000000; // reduce risk of crash v.10.8.2 + tiffbuff = zmalloc(stb,"tiffbuff"); // read encoded strips + + pxm = PXM_make(ww,hh,16); + + for (strip = 0; strip < nst; strip++) + { + cc = TIFFReadEncodedStrip(tiff,strip,tiffbuff,stb); + if (cc < 0) { + zmessageACK(mWin,ZTX("TIFF read failure")); + TIFFClose(tiff); + zfree(tiffbuff); + PXM_free(pxm); + return 0; + } + + if (cc == 0) break; + + tiff16 = (uint16 *) tiffbuff; + pxm16 = (uint16 *) pxm->bmp; + row = strip * rps; + pxm16 += row * ww * 3; + + while (cc >= 6) // bugfix v.11.03 + { + pxm16[0] = tiff16[0]; + pxm16[1] = tiff16[1]; + pxm16[2] = tiff16[2]; + pxm16 += 3; + tiff16 += nch; + cc -= nch * 2; + } + } + + TIFFClose(tiff); + zfree(tiffbuff); + return pxm; +} + + +// Write to TIFF file using TIFF library. +// File bpc is taken from PXM (8 or 16). +// returns 0 if OK, +N if error. + +int TIFFwrite(PXM *pxm, cchar *filespec) // new v.9.8 +{ + static int ftf = 1; + TIFF *tiff; + uint8 *tiff8, *pxm8; + uint16 *tiff16, *pxm16; + int tiffstat = 0; + int ww, hh, row, col, rowcc; // int not uint v.11.03 + int bpc, nch, pm = 2, pc = 1, comp = 5; + char *tiffbuff; + + if (ftf) { + TIFFSetWarningHandler(tiffwarninghandler); // intercept TIFF warning messages + ftf = 0; + } + + tiff = TIFFOpen(filespec,"w"); + if (! tiff) { + zmessageACK(mWin,ZTX("TIFF open failure")); + return 1; + } + + ww = pxm->ww; + hh = pxm->hh; + bpc = pxm->bpc; + nch = 3; // alpha channel removed + + TIFFSetField(tiff, TIFFTAG_IMAGEWIDTH, ww); + TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, bpc); + TIFFSetField(tiff, TIFFTAG_SAMPLESPERPIXEL, nch); + TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, pm); // RGB + TIFFSetField(tiff, TIFFTAG_PLANARCONFIG, pc); + TIFFSetField(tiff, TIFFTAG_COMPRESSION, comp); // LZW + + rowcc = TIFFScanlineSize(tiff); + tiffbuff = (char*) zmalloc(rowcc,"tiffbuff"); + + for (row = 0; row < hh; row++) + { + if (bpc == 8) + { + tiff8 = (uint8 *) tiffbuff; + pxm8 = (uint8 *) pxm->bmp + row * ww * 3; + + for (col = 0; col < ww; col++) + { + tiff8[0] = pxm8[0]; + tiff8[1] = pxm8[1]; + tiff8[2] = pxm8[2]; + pxm8 += 3; + tiff8 += nch; + } + } + + if (bpc == 16) + { + tiff16 = (uint16 *) tiffbuff; + pxm16 = (uint16 *) pxm->bmp + row * ww * 3; + + for (col = 0; col < ww; col++) + { + tiff16[0] = pxm16[0]; + tiff16[1] = pxm16[1]; + tiff16[2] = pxm16[2]; + pxm16 += 3; + tiff16 += nch; + } + } + + tiffstat = TIFFWriteScanline(tiff,tiffbuff,row,0); + if (tiffstat != 1) break; + } + + TIFFClose(tiff); + zfree(tiffbuff); + + if (tiffstat == 1) return 0; + zmessageACK(mWin,ZTX("TIFF write failure")); + return 2; +} + + +/**************************************************************************/ + +// Read from jpeg/png file using pixbuf library. bpc = 8. + +PXM * PXBread(cchar *filespec) // new v.9.8 +{ + GError *gerror = 0; + PXB *pxb; + PXM *pxm; + int ww, hh, px, py, nch, rowst; + uint8 *bmp1, *bmp2, *pix1, *pix2; + + pxb = gdk_pixbuf_new_from_file(filespec,&gerror); + if (! pxb) { + printf("%s \n",gerror->message); // v.10.8 + zmessageACK(mWin,ZTX("file type not supported")); + return 0; + } + + ww = gdk_pixbuf_get_width(pxb); + hh = gdk_pixbuf_get_height(pxb); + nch = gdk_pixbuf_get_n_channels(pxb); + rowst = gdk_pixbuf_get_rowstride(pxb); + bmp1 = gdk_pixbuf_get_pixels(pxb); + + pxm = PXM_make(ww,hh,8); + bmp2 = (uint8 *) pxm->bmp; + + for (py = 0; py < hh; py++) + { + pix1 = bmp1 + rowst * py; + pix2 = bmp2 + py * ww * 3; + + for (px = 0; px < ww; px++) + { + pix2[0] = pix1[0]; + pix2[1] = pix1[1]; + pix2[2] = pix1[2]; + pix1 += nch; + pix2 += 3; + } + } + + f_load_bpc = 8; // file bits per color for f_load() + g_object_unref(pxb); // (any value on disk becomes 8) + return pxm; +} + + +// Write to jpeg/png file using pixbuf library. bpc = 8. +// returns 0 if OK, +N if error. + +int PXBwrite(PXM *pxm, cchar *filespec) // new v.9.8 +{ + int ww, hh, bpc, px, py, rowst; + uint8 *bmp8, *pix8, *bmp2, *pix2; + uint16 *bmp16, *pix16; + PXB *pxb; + cchar *pext; + GError *gerror = 0; + int pxbstat; + + ww = pxm->ww; + hh = pxm->hh; + bpc = pxm->bpc; + + pxb = gdk_pixbuf_new(RGBCOLOR,0,8,ww,hh); + if (! pxb) zappcrash("pixbuf allocation failure"); + + bmp8 = (uint8 *) pxm->bmp; + bmp16 = (uint16 *) pxm->bmp; + bmp2 = gdk_pixbuf_get_pixels(pxb); + rowst = gdk_pixbuf_get_rowstride(pxb); + + if (bpc == 8) + { + for (py = 0; py < hh; py++) + { + pix8 = bmp8 + py * ww * 3; + pix2 = bmp2 + rowst * py; + + for (px = 0; px < ww; px++) + { + pix2[0] = pix8[0]; + pix2[1] = pix8[1]; + pix2[2] = pix8[2]; + pix2 += 3; + pix8 += 3; + } + } + } + + if (bpc == 16) + { + for (py = 0; py < hh; py++) + { + pix16 = bmp16 + py * ww * 3; + pix2 = bmp2 + rowst * py; + + for (px = 0; px < ww; px++) + { + pix2[0] = pix16[0] >> 8; + pix2[1] = pix16[1] >> 8; + pix2[2] = pix16[2] >> 8; + pix2 += 3; + pix16 += 3; + } + } + } + + pext = strrchr(filespec,'/'); + if (! pext) pext = filespec; + pext = strrchr(pext,'.'); + if (! pext) pext = ""; + + if (strstr(".png .PNG",pext)) + pxbstat = gdk_pixbuf_save(pxb,filespec,"png",&gerror,null); + else pxbstat = gdk_pixbuf_save(pxb,filespec,"jpeg",&gerror,"quality",jpeg_quality,null); + g_object_unref(pxb); + if (pxbstat) return 0; + + printf("%s \n",gerror->message); // v.10.8 + zmessageACK(mWin,ZTX("pixbuf write failure")); + return 1; +} + + +/************************************************************************** + PXM pixmap conversion and rescale functions +***************************************************************************/ + +// initialize PXM pixmap - allocate memory + +PXM * PXM_make(int ww, int hh, int bpc) +{ + if (ww < 1 || hh < 1 || (bpc != 8 && bpc != 16)) + zappcrash("PXM_make() %d %d %d",ww,hh,bpc); + + PXM *pxm = (PXM *) zmalloc(sizeof(PXM),"PXM"); + pxm->ww = ww; + pxm->hh = hh; + pxm->bpc = bpc; + if (bpc == 8) pxm->bmp = zmalloc(ww*hh*3,"PXM.bmp"); + if (bpc == 16) pxm->bmp = zmalloc(ww*hh*6,"PXM.bmp"); + strcpy(pxm->wmi,"rgbrgb"); + return pxm; +} + + +// free PXM pixmap + +void PXM_free(PXM *&pxm) +{ + if (! pxm) return; + if (! strEqu(pxm->wmi,"rgbrgb")) + zappcrash("PXM_free(), bad PXM"); + strcpy(pxm->wmi,"xxxxxx"); + zfree(pxm->bmp); + zfree(pxm); + pxm = 0; // v.11.01 + return; +} + + +// create a copy of an PXM pixmap + +PXM * PXM_copy(PXM *pxm1) +{ + int cc; + PXM *pxm2; + + pxm2 = PXM_make(pxm1->ww, pxm1->hh, pxm1->bpc); + cc = pxm1->ww * pxm1->hh * (pxm1->bpc / 8 * 3); + memcpy(pxm2->bmp,pxm1->bmp,cc); + return pxm2; +} + + +// create a copy of an PXM area + +PXM * PXM_copy_area(PXM *pxm1, int orgx, int orgy, int ww2, int hh2) +{ + uint8 *bmp1, *pix1, *bmp2, *pix2; + uint16 *bmp3, *pix3, *bmp4, *pix4; + PXM *pxm2 = 0; + int ww1, bpc, px1, py1, px2, py2; + + ww1 = pxm1->ww; + bpc = pxm1->bpc; + + if (bpc == 8) + { + pxm2 = PXM_make(ww2,hh2,8); + bmp1 = (uint8 *) pxm1->bmp; + bmp2 = (uint8 *) pxm2->bmp; + + for (py1 = orgy, py2 = 0; py2 < hh2; py1++, py2++) + { + for (px1 = orgx, px2 = 0; px2 < ww2; px1++, px2++) + { + pix1 = bmp1 + (py1 * ww1 + px1) * 3; + pix2 = bmp2 + (py2 * ww2 + px2) * 3; + + pix2[0] = pix1[0]; + pix2[1] = pix1[1]; + pix2[2] = pix1[2]; + pix1 += 3; + pix2 += 3; + } + } + } + + if (bpc == 16) + { + pxm2 = PXM_make(ww2,hh2,16); + bmp3 = (uint16 *) pxm1->bmp; + bmp4 = (uint16 *) pxm2->bmp; + + for (py1 = orgy, py2 = 0; py2 < hh2; py1++, py2++) + { + for (px1 = orgx, px2 = 0; px2 < ww2; px1++, px2++) + { + pix3 = bmp3 + (py1 * ww1 + px1) * 3; + pix4 = bmp4 + (py2 * ww2 + px2) * 3; + + pix4[0] = pix3[0]; + pix4[1] = pix3[1]; + pix4[2] = pix3[2]; + pix3 += 3; + pix4 += 3; + } + } + } + + return pxm2; +} + + +// convert PXM pixmap from 8/16 to 16/8 bits per color + +PXM * PXM_convbpc(PXM *pxm1) +{ + uint8 *bmp8, *pix8; + uint16 *bmp16, *pix16; + PXM *pxm2 = 0; + int ww, hh, bpc, px, py; + + ww = pxm1->ww; + hh = pxm1->hh; + bpc = pxm1->bpc; + + if (bpc == 8) // 8 > 16 + { + pxm2 = PXM_make(ww,hh,16); + bmp8 = (uint8 *) pxm1->bmp; + bmp16 = (uint16 *) pxm2->bmp; + + for (py = 0; py < hh; py++) + { + pix8 = bmp8 + py * ww * 3; + pix16 = bmp16 + py * ww * 3; + + for (px = 0; px < ww; px++) + { + pix16[0] = pix8[0] << 8; + pix16[1] = pix8[1] << 8; + pix16[2] = pix8[2] << 8; + pix8 += 3; + pix16 += 3; + } + } + } + + if (bpc == 16) // 16 > 8 + { + pxm2 = PXM_make(ww,hh,8); + bmp8 = (uint8 *) pxm2->bmp; + bmp16 = (uint16 *) pxm1->bmp; + + for (py = 0; py < hh; py++) + { + pix8 = bmp8 + py * ww * 3; + pix16 = bmp16 + py * ww * 3; + + for (px = 0; px < ww; px++) + { + pix8[0] = pix16[0] >> 8; + pix8[1] = pix16[1] >> 8; + pix8[2] = pix16[2] >> 8; + pix8 += 3; + pix16 += 3; + } + } + } + + return pxm2; +} + + +// replace blue = 0 pixels with blue = 2 in a 16-bit pixmap +// (blue = 0 reserved for pixels voided by warp or overlay offsets) +// all callers of vpixel() need to do this +// needs about 0.013 seconds for 10 megapixel image and 3.3 GHz processor + +void PXM_fixblue(PXM *pxm) // v.11.07 +{ + int size; + uint16 *pixel, *pixel0, *pixelN; + + size = pxm->ww * pxm->hh * 3; + pixel0 = (uint16 *) pxm->bmp + 2; + pixelN = (uint16 *) pixel0 + size; + + for (pixel = pixel0; pixel < pixelN; pixel += 3) // +3 is +6 bytes + if (! *pixel) *pixel = 2; + + return; +} + + +// rescale PXM pixmap to size ww2 x hh2 + +PXM * PXM_rescale(PXM *pxm1, int ww2, int hh2) +{ + void bmp8_rescale(uint8*, uint8*, int, int, int, int); + void bmp16_rescale(uint16*, uint16*, int, int, int, int); + + PXM *pxm2; + int ww1, hh1, bpc; + uint8 *bmp1, *bmp2; + uint16 *bmp3, *bmp4; + + ww1 = pxm1->ww; + hh1 = pxm1->hh; + bpc = pxm1->bpc; + + pxm2 = PXM_make(ww2,hh2,bpc); + + if (bpc == 8) { + bmp1 = (uint8 *) pxm1->bmp; + bmp2 = (uint8 *) pxm2->bmp; + bmp8_rescale(bmp1,bmp2,ww1,hh1,ww2,hh2); + } + + if (bpc == 16) { + bmp3 = (uint16 *) pxm1->bmp; + bmp4 = (uint16 *) pxm2->bmp; + bmp16_rescale(bmp3,bmp4,ww1,hh1,ww2,hh2); + } + + return pxm2; +} + + +/************************************************************************** + + Rescale 8 bpc image (3 x 8 bits per color) to new width and height. + The scale ratios may be different for width and height. + + Method: + The input and output images are overlayed, stretching or shrinking the + output pixels as needed. The contribution of each input pixel overlapping + an output pixel is proportional to the area of the output pixel covered by + the input pixel. The contributions of all overlaping input pixels are added. + The work is spread among Nwt threads to reduce the elapsed time on modern + computers having multiple SMP processors. + + Example: if the output image is 40% of the input image, then: + outpix[0,0] = 0.16 * inpix[0,0] + 0.16 * inpix[1,0] + 0.08 * inpix[2,0] + + 0.16 * inpix[0,1] + 0.16 * inpix[1,1] + 0.08 * inpix[2,1] + + 0.08 * inpix[0,2] + 0.08 * inpix[1,2] + 0.04 * inpix[2,2] + +*********/ + +namespace bmp8rescale { // data for threads + uint8 *pixmap1; + uint8 *pixmap2; + int ww1; + int hh1; + int ww2; + int hh2; + int *px1L; + int *py1L; + double *pxmap; + double *pymap; + int maxmapx; + int maxmapy; + int busy[max_threads]; +} + + +void bmp8_rescale(uint8 *pixmap1x, uint8 *pixmap2x, int ww1x, int hh1x, int ww2x, int hh2x) +{ + using namespace bmp8rescale; + + void * bmp8_rescale_thread(void *arg); + + int px1, py1, px2, py2; + int pxl, pyl, pxm, pym, ii; + double scalex, scaley; + double px1a, py1a, px1b, py1b; + double fx, fy; + + pixmap1 = pixmap1x; + pixmap2 = pixmap2x; + ww1 = ww1x; + hh1 = hh1x; + ww2 = ww2x; + hh2 = hh2x; + + memset(pixmap2, 0, ww2 * hh2 * 3 * sizeof(uint8)); // clear output pixmap + + scalex = 1.0 * ww1 / ww2; // compute x and y scales + scaley = 1.0 * hh1 / hh2; + + if (scalex <= 1) maxmapx = 2; // compute max input pixels + else maxmapx = scalex + 2; // mapping into output pixels + maxmapx += 1; // for both dimensions + if (scaley <= 1) maxmapy = 2; // (pixels may not be square) + else maxmapy = scaley + 2; + maxmapy += 1; + + pymap = (double *) zmalloc(hh2 * maxmapy * sizeof(double)); // maps overlap of < maxmap input + pxmap = (double *) zmalloc(ww2 * maxmapx * sizeof(double)); // pixels per output pixel + + py1L = (int *) zmalloc(hh2 * sizeof(int)); // maps first (lowest) input pixel + px1L = (int *) zmalloc(ww2 * sizeof(int)); // per output pixel + + for (py2 = 0; py2 < hh2; py2++) // loop output y-pixels + { + py1a = py2 * scaley; // corresponding input y-pixels + py1b = py1a + scaley; + if (py1b >= hh1) py1b = hh1 - 0.001; // fix precision limitation + pyl = py1a; + py1L[py2] = pyl; // 1st overlapping input pixel + + for (py1 = pyl, pym = 0; py1 < py1b; py1++, pym++) // loop overlapping input pixels + { + if (py1 < py1a) { // compute amount of overlap + if (py1+1 < py1b) fy = py1+1 - py1a; // 0.0 to 1.0 + else fy = scaley; + } + else if (py1+1 > py1b) fy = py1b - py1; + else fy = 1; + + ii = py2 * maxmapy + pym; // save it + pymap[ii] = 0.9999 * fy / scaley; + } + ii = py2 * maxmapy + pym; // set an end marker after + pymap[ii] = -1; // last overlapping pixel + } + + for (px2 = 0; px2 < ww2; px2++) // do same for x-pixels + { + px1a = px2 * scalex; + px1b = px1a + scalex; + if (px1b >= ww1) px1b = ww1 - 0.001; + pxl = px1a; + px1L[px2] = pxl; + + for (px1 = pxl, pxm = 0; px1 < px1b; px1++, pxm++) + { + if (px1 < px1a) { + if (px1+1 < px1b) fx = px1+1 - px1a; + else fx = scalex; + } + else if (px1+1 > px1b) fx = px1b - px1; + else fx = 1; + + ii = px2 * maxmapx + pxm; + pxmap[ii] = 0.9999 * fx / scalex; + } + ii = px2 * maxmapx + pxm; + pxmap[ii] = -1; + } + + for (ii = 0; ii < Nwt; ii++) { // start working threads + busy[ii] = 1; + start_detached_thread(bmp8_rescale_thread,&wtnx[ii]); + } + + for (ii = 0; ii < Nwt; ii++) // wait for all done + while (busy[ii]) zsleep(0.004); + + zfree(px1L); + zfree(py1L); + zfree(pxmap); + zfree(pymap); + return; +} + + +void * bmp8_rescale_thread(void *arg) // worker thread function +{ + using namespace bmp8rescale; + + int index = *((int *) arg); + int px1, py1, px2, py2; + int pxl, pyl, pxm, pym, ii; + uint8 *pixel1, *pixel2; + double fx, fy, ftot; + double red, green, blue; + + for (py2 = index; py2 < hh2; py2 += Nwt) // loop output y-pixels + { + pyl = py1L[py2]; // corresp. 1st input y-pixel + + for (px2 = 0; px2 < ww2; px2++) // loop output x-pixels + { + pxl = px1L[px2]; // corresp. 1st input x-pixel + + red = green = blue = 0; // initz. output pixel + + for (py1 = pyl, pym = 0; ; py1++, pym++) // loop overlapping input y-pixels + { + ii = py2 * maxmapy + pym; // get y-overlap + fy = pymap[ii]; + if (fy < 0) break; // no more pixels + + for (px1 = pxl, pxm = 0; ; px1++, pxm++) // loop overlapping input x-pixels + { + ii = px2 * maxmapx + pxm; // get x-overlap + fx = pxmap[ii]; + if (fx < 0) break; // no more pixels + + ftot = fx * fy; // area overlap = x * y overlap + pixel1 = pixmap1 + (py1 * ww1 + px1) * 3; + red += pixel1[0] * ftot; // add input pixel * overlap + green += pixel1[1] * ftot; + blue += pixel1[2] * ftot; + } + + pixel2 = pixmap2 + (py2 * ww2 + px2) * 3; // save output pixel + pixel2[0] = red; + pixel2[1] = green; + pixel2[2] = blue; + } + } + } + + busy[index] = 0; + return 0; +} + + +/************************************************************************** + + Rescale 16 bpc image (3 x 16 bits per color) to new width and height. + Identical to bmp8_rescale except for the following: + uint8 >> uint16 + xxx8 >> xxx16 + +*******/ + +namespace bmp16rescale { // data for threads + uint16 *pixmap1; + uint16 *pixmap2; + int ww1; + int hh1; + int ww2; + int hh2; + int *px1L; + int *py1L; + double *pxmap; + double *pymap; + int maxmapx; + int maxmapy; + int busy[max_threads]; +} + + +void bmp16_rescale(uint16 *pixmap1x, uint16 *pixmap2x, int ww1x, int hh1x, int ww2x, int hh2x) +{ + using namespace bmp16rescale; + + void * bmp16_rescale_thread(void *arg); + + int px1, py1, px2, py2; + int pxl, pyl, pxm, pym, ii; + double scalex, scaley; + double px1a, py1a, px1b, py1b; + double fx, fy; + + pixmap1 = pixmap1x; + pixmap2 = pixmap2x; + ww1 = ww1x; + hh1 = hh1x; + ww2 = ww2x; + hh2 = hh2x; + + memset(pixmap2, 0, ww2 * hh2 * 3 * sizeof(uint16)); // clear output pixmap + + scalex = 1.0 * ww1 / ww2; // compute x and y scales + scaley = 1.0 * hh1 / hh2; + + if (scalex <= 1) maxmapx = 2; // compute max input pixels + else maxmapx = scalex + 2; // mapping into output pixels + maxmapx += 1; // for both dimensions + if (scaley <= 1) maxmapy = 2; // (pixels may not be square) + else maxmapy = scaley + 2; + maxmapy += 1; + + pymap = (double *) zmalloc(hh2 * maxmapy * sizeof(double)); // maps overlap of < maxmap input + pxmap = (double *) zmalloc(ww2 * maxmapx * sizeof(double)); // pixels per output pixel + + py1L = (int *) zmalloc(hh2 * sizeof(int)); // maps first (lowest) input pixel + px1L = (int *) zmalloc(ww2 * sizeof(int)); // per output pixel + + for (py2 = 0; py2 < hh2; py2++) // loop output y-pixels + { + py1a = py2 * scaley; // corresponding input y-pixels + py1b = py1a + scaley; + if (py1b >= hh1) py1b = hh1 - 0.001; // fix precision limitation + pyl = py1a; + py1L[py2] = pyl; // 1st overlapping input pixel + + for (py1 = pyl, pym = 0; py1 < py1b; py1++, pym++) // loop overlapping input pixels + { + if (py1 < py1a) { // compute amount of overlap + if (py1+1 < py1b) fy = py1+1 - py1a; // 0.0 to 1.0 + else fy = scaley; + } + else if (py1+1 > py1b) fy = py1b - py1; + else fy = 1; + + ii = py2 * maxmapy + pym; // save it + pymap[ii] = 0.9999 * fy / scaley; + } + ii = py2 * maxmapy + pym; // set an end marker after + pymap[ii] = -1; // last overlapping pixel + } + + for (px2 = 0; px2 < ww2; px2++) // do same for x-pixels + { + px1a = px2 * scalex; + px1b = px1a + scalex; + if (px1b >= ww1) px1b = ww1 - 0.001; + pxl = px1a; + px1L[px2] = pxl; + + for (px1 = pxl, pxm = 0; px1 < px1b; px1++, pxm++) + { + if (px1 < px1a) { + if (px1+1 < px1b) fx = px1+1 - px1a; + else fx = scalex; + } + else if (px1+1 > px1b) fx = px1b - px1; + else fx = 1; + + ii = px2 * maxmapx + pxm; + pxmap[ii] = 0.9999 * fx / scalex; + } + ii = px2 * maxmapx + pxm; + pxmap[ii] = -1; + } + + for (ii = 0; ii < Nwt; ii++) { // start working threads + busy[ii] = 1; + start_detached_thread(bmp16_rescale_thread,&wtnx[ii]); + } + + for (ii = 0; ii < Nwt; ii++) // wait for all done + while (busy[ii]) zsleep(0.004); + + zfree(px1L); + zfree(py1L); + zfree(pxmap); + zfree(pymap); + return; +} + + +void * bmp16_rescale_thread(void *arg) // worker thread function +{ + using namespace bmp16rescale; + + int index = *((int *) arg); + int px1, py1, px2, py2; + int pxl, pyl, pxm, pym, ii; + uint16 *pixel1, *pixel2; + double fx, fy, ftot; + double red, green, blue; + + for (py2 = index; py2 < hh2; py2 += Nwt) // loop output y-pixels + { + pyl = py1L[py2]; // corresp. 1st input y-pixel + + for (px2 = 0; px2 < ww2; px2++) // loop output x-pixels + { + pxl = px1L[px2]; // corresp. 1st input x-pixel + + red = green = blue = 0; // initz. output pixel + + for (py1 = pyl, pym = 0; ; py1++, pym++) // loop overlapping input y-pixels + { + ii = py2 * maxmapy + pym; // get y-overlap + fy = pymap[ii]; + if (fy < 0) break; // no more pixels + + for (px1 = pxl, pxm = 0; ; px1++, pxm++) // loop overlapping input x-pixels + { + ii = px2 * maxmapx + pxm; // get x-overlap + fx = pxmap[ii]; + if (fx < 0) break; // no more pixels + + ftot = fx * fy; // area overlap = x * y overlap + pixel1 = pixmap1 + (py1 * ww1 + px1) * 3; + red += pixel1[0] * ftot; // add input pixel * overlap + green += pixel1[1] * ftot; + blue += pixel1[2] * ftot; + } + + pixel2 = pixmap2 + (py2 * ww2 + px2) * 3; // save output pixel + pixel2[0] = red; + pixel2[1] = green; + pixel2[2] = blue; + } + } + } + + busy[index] = 0; + return 0; +} + + +// Copy and rescale a modified area within a PXM-16 image into the +// corresponding area of a PXM-8 image previously rescaled from the +// PXM-16 image. Keep the same mapping of input to output pixels, so +// that the modified area fits seamlessly into the PXM-8 image. Used +// when a section of an image is edited and the window image is updated. +// +// pxm1 PXM-16 image with changed area to rescale and copy +// pxm2 existing rescaled PXM-8 copy of pxm1 +// org1x, org1y pxm1 origin of area to copy (top left corner) +// ww1a, hh1a width and height of area to copy // new v.10.11 + +void PXM_update(PXM *pxm1, PXM *pxm2, int org1x, int org1y, int ww1a, int hh1a) +{ + uint16 *bmp1, *pix1; + uint8 *bmp2, *pix2; + int ww1, hh1, ww2, hh2; + int px1, py1, px2, py2; + int pxl, pyl, pxm, pym, ii; + int *px1L, *py1L; + int maxmapx, maxmapy; + int org2x, end2x, org2y, end2y; + float scalex, scaley; + float px1a, py1a, px1b, py1b; + float fx, fy, ftot; + float red, green, blue; + float *pxmap, *pymap; + + bmp1 = (uint16 *) pxm1->bmp; + bmp2 = (uint8 *) pxm2->bmp; + ww1 = pxm1->ww; + hh1 = pxm1->hh; + ww2 = pxm2->ww; + hh2 = pxm2->hh; + + scalex = 1.0 * ww1 / ww2; // compute x and y scales + scaley = 1.0 * hh1 / hh2; + + if (scalex <= 1) maxmapx = 2; // compute max input pixels + else maxmapx = scalex + 2; // mapping into output pixels + maxmapx += 1; // for both dimensions + if (scaley <= 1) maxmapy = 2; // (pixels may not be square) + else maxmapy = scaley + 2; + maxmapy += 1; + + pymap = (float *) zmalloc(hh2 * maxmapy * sizeof(float)); // maps overlap of < maxmap input + pxmap = (float *) zmalloc(ww2 * maxmapx * sizeof(float)); // pixels per output pixel + + py1L = (int *) zmalloc(hh2 * sizeof(int)); // maps first (lowest) input pixel + px1L = (int *) zmalloc(ww2 * sizeof(int)); // per output pixel + + for (py2 = 0; py2 < hh2; py2++) // loop output y-pixels + { + py1a = py2 * scaley; // corresponding input y-pixels + py1b = py1a + scaley; + if (py1b >= hh1) py1b = hh1 - 0.001; // fix precision limitation + pyl = py1a; + py1L[py2] = pyl; // 1st overlapping input pixel + + for (py1 = pyl, pym = 0; py1 < py1b; py1++, pym++) // loop overlapping input pixels + { + if (py1 < py1a) { // compute amount of overlap + if (py1+1 < py1b) fy = py1+1 - py1a; // 0.0 to 1.0 + else fy = scaley; + } + else if (py1+1 > py1b) fy = py1b - py1; + else fy = 1; + + ii = py2 * maxmapy + pym; // save it + pymap[ii] = 0.9999 * fy / scaley; + } + ii = py2 * maxmapy + pym; // set an end marker after + pymap[ii] = -1; // last overlapping pixel + } + + for (px2 = 0; px2 < ww2; px2++) // do same for x-pixels + { + px1a = px2 * scalex; + px1b = px1a + scalex; + if (px1b >= ww1) px1b = ww1 - 0.001; + pxl = px1a; + px1L[px2] = pxl; + + for (px1 = pxl, pxm = 0; px1 < px1b; px1++, pxm++) + { + if (px1 < px1a) { + if (px1+1 < px1b) fx = px1+1 - px1a; + else fx = scalex; + } + else if (px1+1 > px1b) fx = px1b - px1; + else fx = 1; + + ii = px2 * maxmapx + pxm; + pxmap[ii] = 0.9999 * fx / scalex; + } + ii = px2 * maxmapx + pxm; + pxmap[ii] = -1; + } + + org2x = org1x / scalex; // compute output image rectangle + end2x = (org1x + ww1a) / scalex + 1; // containing any part of input area + if (org2x < 0) org2x = 0; // revised v.10.12 + if (end2x > ww2) end2x = ww2; + + org2y = org1y / scaley; + end2y = (org1y + hh1a) / scaley + 1; + if (org2y < 0) org2y = 0; + if (end2y > hh2) end2y = hh2; + + for (py2 = org2y; py2 < end2y; py2++) // loop output y-pixels + { + pyl = py1L[py2]; // corresp. 1st input y-pixel + + for (px2 = org2x; px2 < end2x; px2++) // loop output x-pixels + { + pxl = px1L[px2]; // corresp. 1st input x-pixel + + red = green = blue = 0; // initz. output pixel + + for (py1 = pyl, pym = 0; ; py1++, pym++) // loop overlapping input y-pixels + { + ii = py2 * maxmapy + pym; // get y-overlap + fy = pymap[ii]; + if (fy < 0) break; // no more pixels + + for (px1 = pxl, pxm = 0; ; px1++, pxm++) // loop overlapping input x-pixels + { + ii = px2 * maxmapx + pxm; // get x-overlap + fx = pxmap[ii]; + if (fx < 0) break; // no more pixels + + ftot = fx * fy; // area overlap = x * y overlap + pix1 = bmp1 + (py1 * ww1 + px1) * 3; + red += pix1[0] * ftot; // add input pixel * overlap + green += pix1[1] * ftot; + blue += pix1[2] * ftot; + } + + pix2 = bmp2 + (py2 * ww2 + px2) * 3; // save output pixel + pix2[0] = int(red) >> 8; + pix2[1] = int(green) >> 8; + pix2[2] = int(blue) >> 8; + } + } + } + + zfree(px1L); + zfree(py1L); + zfree(pxmap); + zfree(pymap); + return; +} + + +// rotate PXM pixmap through given angle in degrees (+ = clockwise) + +PXM * PXM_rotate(PXM *pxm1, double angle) +{ + PXM * PXM_rotate8(PXM *, double); + PXM * PXM_rotate16(PXM *, double); + + PXM *pxm2 = 0; + int bpc; + + bpc = pxm1->bpc; + if (bpc == 8) pxm2 = PXM_rotate8(pxm1,angle); + if (bpc == 16) pxm2 = PXM_rotate16(pxm1,angle); + return pxm2; +} + + +/************************************************************************** + + PXM *pxm2 = PXM_rotate8(PXM *pxm1, double angle) + + Rotate PXM-8 pixmap through an arbitrary angle (degrees). + + The returned image has the same size as the original, but the + pixmap size is increased to accomodate the rotated image. + (e.g. a 100x100 image rotated 45 deg. needs a 142x142 pixmap). + The parameters ww and hh are the dimensions of the input + pixmap, and are updated to the dimensions of the output pixmap. + + The space added around the rotated image is black (RGB 0,0,0). + Angle is in degrees. Positive direction is clockwise. + Speed is about 3 million pixels/sec/thread for a 2.4 GHz CPU. + Loss of resolution is less than 1 pixel. + + Work is divided among Nwt threads to gain speed. + + v.9.3: affine transform instead of trig functions, for speed + +***************************************************************************/ + +namespace rotpxm8 { + int busy = 0; + uint8 *pixmap1; + uint8 *pixmap2; + int ww1; + int hh1; + int ww2; + int hh2; + double angle; +} + + +PXM * PXM_rotate8(PXM *pxm1, double anglex) +{ + using namespace rotpxm8; + + void *PXM_rotate8_thread(void *); + + int cc, ii; + PXM *pxm2; + + ww1 = pxm1->ww; + hh1 = pxm1->hh; + pixmap1 = (uint8 *) pxm1->bmp; + angle = anglex; + + while (angle < -180) angle += 360; // normalize, -180 to +180 + while (angle > 180) angle -= 360; + angle = angle * pi / 180; // radians, -pi to +pi + + if (fabs(angle) < 0.001) { // angle = 0 within my precision + pxm2 = PXM_make(ww1,hh1,8); // return a copy of the input + pixmap2 = (uint8 *) pxm2->bmp; + cc = ww1 * hh1 * 3 * sizeof(uint8); + memcpy(pixmap2,pixmap1,cc); + return pxm2; + } + + ww2 = ww1*fabs(cos(angle)) + hh1*fabs(sin(angle)); // rectangle containing rotated image + hh2 = ww1*fabs(sin(angle)) + hh1*fabs(cos(angle)); + + pxm2 = PXM_make(ww2,hh2,8); + pixmap2 = (uint8 *) pxm2->bmp; + + for (ii = 0; ii < Nwt; ii++) // start worker threads + start_detached_thread(PXM_rotate8_thread,&wtnx[ii]); + zadd_locked(busy,+Nwt); + + while (busy) zsleep(0.004); // wait for completion + return pxm2; +} + + +void * PXM_rotate8_thread(void *arg) +{ + using namespace rotpxm8; + + int index = *((int *) (arg)); + int px2, py2, px0, py0; + uint8 *pix0, *pix1, *pix2, *pix3; + double px1, py1; + double f0, f1, f2, f3, red, green, blue; + double a, b, d, e, ww15, hh15, ww25, hh25; + + ww15 = 0.5 * ww1; + hh15 = 0.5 * hh1; + ww25 = 0.5 * ww2; + hh25 = 0.5 * hh2; + + a = cos(angle); + b = sin(angle); + d = - sin(angle); + e = cos(angle); + + for (py2 = index; py2 < hh2; py2 += Nwt) // loop through output pixels + for (px2 = 0; px2 < ww2; px2++) // outer loop y + { + px1 = a * (px2 - ww25) + b * (py2 - hh25) + ww15; // (px1,py1) = corresponding v.9.3 + py1 = d * (px2 - ww25) + e * (py2 - hh25) + hh15; // point within input pixels + + px0 = px1; // pixel containing (px1,py1) + py0 = py1; + + if (px1 < 0 || px0 >= ww1-1 || py1 < 0 || py0 >= hh1-1) { // if outside input pixel array + pix2 = pixmap2 + (py2 * ww2 + px2) * 3; // output is black + pix2[0] = pix2[1] = pix2[2] = 0; + continue; + } + + pix0 = pixmap1 + (py0 * ww1 + px0) * 3; // 4 input pixels based at (px0,py0) + pix1 = pix0 + ww1 * 3; + pix2 = pix0 + 3; + pix3 = pix1 + 3; + + f0 = (px0+1 - px1) * (py0+1 - py1); // overlap of (px1,py1) + f1 = (px0+1 - px1) * (py1 - py0); // in each of the 4 pixels + f2 = (px1 - px0) * (py0+1 - py1); + f3 = (px1 - px0) * (py1 - py0); + + red = f0 * pix0[0] + f1 * pix1[0] + f2 * pix2[0] + f3 * pix3[0]; // sum the weighted inputs + green = f0 * pix0[1] + f1 * pix1[1] + f2 * pix2[1] + f3 * pix3[1]; + blue = f0 * pix0[2] + f1 * pix1[2] + f2 * pix2[2] + f3 * pix3[2]; + + pix2 = pixmap2 + (py2 * ww2 + px2) * 3; // output pixel + pix2[0] = red; + pix2[1] = green; + pix2[2] = blue; + } + + zadd_locked(busy,-1); + return 0; +} + + +/************************************************************************** + + PXM *pxm2 = PXM_rotate16(PXM *pxm1, double angle) + Rotate PXM-16 pixmap through an arbitrary angle (degrees). + Identical to PXM_rotate8() except for: + uint8 >> uint16 + rotpxm8 >> rotpxm16 + 8 >> 16 + +**********/ + +namespace rotpxm16 { + int busy = 0; + uint16 *pixmap1; + uint16 *pixmap2; + int ww1; + int hh1; + int ww2; + int hh2; + double angle; +} + + +PXM * PXM_rotate16(PXM *pxm1, double anglex) +{ + using namespace rotpxm16; + + void *PXM_rotate16_thread(void *); + + int cc, ii; + PXM *pxm2; + + ww1 = pxm1->ww; + hh1 = pxm1->hh; + pixmap1 = (uint16 *) pxm1->bmp; + angle = anglex; + + while (angle < -180) angle += 360; // normalize, -180 to +180 + while (angle > 180) angle -= 360; + angle = angle * pi / 180; // radians, -pi to +pi + + if (fabs(angle) < 0.001) { // angle = 0 within my precision + pxm2 = PXM_make(ww1,hh1,16); // return a copy of the input + pixmap2 = (uint16 *) pxm2->bmp; + cc = ww1 * hh1 * 3 * sizeof(uint16); + memcpy(pixmap2,pixmap1,cc); + return pxm2; + } + + ww2 = ww1*fabs(cos(angle)) + hh1*fabs(sin(angle)); // rectangle containing rotated image + hh2 = ww1*fabs(sin(angle)) + hh1*fabs(cos(angle)); + + pxm2 = PXM_make(ww2,hh2,16); + pixmap2 = (uint16 *) pxm2->bmp; + + for (ii = 0; ii < Nwt; ii++) // start worker threads + start_detached_thread(PXM_rotate16_thread,&wtnx[ii]); + zadd_locked(busy,+Nwt); + + while (busy) zsleep(0.004); // wait for completion + return pxm2; +} + + +void * PXM_rotate16_thread(void *arg) +{ + using namespace rotpxm16; + + int index = *((int *) (arg)); + int px2, py2, px0, py0; + uint16 *pix0, *pix1, *pix2, *pix3; + double px1, py1; + double f0, f1, f2, f3, red, green, blue; + double a, b, d, e, ww15, hh15, ww25, hh25; + + ww15 = 0.5 * ww1; + hh15 = 0.5 * hh1; + ww25 = 0.5 * ww2; + hh25 = 0.5 * hh2; + + a = cos(angle); + b = sin(angle); + d = - sin(angle); + e = cos(angle); + + for (py2 = index; py2 < hh2; py2 += Nwt) // loop through output pixels + for (px2 = 0; px2 < ww2; px2++) // outer loop y + { + px1 = a * (px2 - ww25) + b * (py2 - hh25) + ww15; // (px1,py1) = corresponding v.9.3 + py1 = d * (px2 - ww25) + e * (py2 - hh25) + hh15; // point within input pixels + + px0 = px1; // pixel containing (px1,py1) + py0 = py1; + + if (px1 < 0 || px0 >= ww1-1 || py1 < 0 || py0 >= hh1-1) { // if outside input pixel array + pix2 = pixmap2 + (py2 * ww2 + px2) * 3; // output is black + pix2[0] = pix2[1] = pix2[2] = 0; + continue; + } + + pix0 = pixmap1 + (py0 * ww1 + px0) * 3; // 4 input pixels based at (px0,py0) + pix1 = pix0 + ww1 * 3; + pix2 = pix0 + 3; + pix3 = pix1 + 3; + + f0 = (px0+1 - px1) * (py0+1 - py1); // overlap of (px1,py1) + f1 = (px0+1 - px1) * (py1 - py0); // in each of the 4 pixels + f2 = (px1 - px0) * (py0+1 - py1); + f3 = (px1 - px0) * (py1 - py0); + + red = f0 * pix0[0] + f1 * pix1[0] + f2 * pix2[0] + f3 * pix3[0]; // sum the weighted inputs + green = f0 * pix0[1] + f1 * pix1[1] + f2 * pix2[1] + f3 * pix3[1]; + blue = f0 * pix0[2] + f1 * pix1[2] + f2 * pix2[2] + f3 * pix3[2]; + + pix2 = pixmap2 + (py2 * ww2 + px2) * 3; // output pixel + pix2[0] = red; + pix2[1] = green; + pix2[2] = blue; + } + + zadd_locked(busy,-1); + return 0; +} + + + diff -Nru fotoxx-11.11.1/fotoxx-12.01.2.spec fotoxx-12.01.2/fotoxx-12.01.2.spec --- fotoxx-11.11.1/fotoxx-12.01.2.spec 1970-01-01 00:00:00.000000000 +0000 +++ fotoxx-12.01.2/fotoxx-12.01.2.spec 2012-01-04 08:47:11.000000000 +0000 @@ -0,0 +1,48 @@ +# RPM spec file for fotoxx +# ufraw, exiftool, xdg-open: needed for execution but not for build. + +Name: fotoxx +Version: 12.01.2 +Release: 1 +Summary: photo editor and collection manager +Vendor: kornelix +Packager: kornelix2@googlemail.com +License: GPL3 +Group: Graphics/Photography +Source: %{name}-%{version}.tar.gz +URL: http://kornelix.squarespace.com/%{name} + +%description +Navigate your image collection using a thumbnail browser. View and +edit images. Convert RAW files to TIFF and edit with 16-bit color. +Edit a selected area or object within an image. Edit using movable +curves with fast full-screen feedback. Adjust brightness, color, +contrast, gamma. Perform tone mapping, trim, rescale, rotate, warp, +sharpen, blur. Reduce noise, fix red-eyes, erase power lines, fix +perspective. Make composite images: HDR, HDF, stack, and panorama. +Annotate images. Make artful transforms. Do a slide show. Create +named collections. Burn a CD or DVD. Edit tags, comments, captions, +dates and star-ratings. Search images using these criteria plus +directory and file names. + +%prep +%setup -q + +%build +make + +%install +make install PREFIX=$RPM_BUILD_ROOT/usr + +%clean +rm -rf $RPM_BUILD_ROOT + +%files +%defattr(-,root,root) +/usr/bin/%{name} +/usr/share/%{name} +/usr/share/doc/%{name} +/usr/share/applications/kornelix-%{name}.desktop +/usr/share/man/man1/%{name}.1.gz + + diff -Nru fotoxx-11.11.1/fotoxx_area.cc fotoxx-12.01.2/fotoxx_area.cc --- fotoxx-11.11.1/fotoxx_area.cc 2011-11-05 05:30:36.000000000 +0000 +++ fotoxx-12.01.2/fotoxx_area.cc 1970-01-01 00:00:00.000000000 +0000 @@ -1,2672 +0,0 @@ -/************************************************************************** - - Fotoxx edit photos and manage collections - - Copyright 2007 2008 2009 2010 2011 Michael Cornelison - Source URL: http://kornelix.squarespace.com/fotoxx - Contact: kornelix2@googlemail.com - - 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 http://www.gnu.org/licenses/. - -***************************************************************************/ - -#define EX extern // enable extern declarations -#include "fotoxx.h" - -/************************************************************************** - - Fotoxx image editor - select area functions - - Select an area within the current image. - Subsequent edit functions are carried out within the area. - Otherwise, edit functions apply to the entire image. - - sa_stat 0/1/2/3 = none/edit/pause/complete - sa_mode is current area selection method: - 1 select rectangle by drag or clicks - 2 select ellipse by drag - 3 freehand draw by drag - 4 follow edge indicated by clicks - 5 select adjacent pixels matching color - 6 select pixels within mouse radius - 7 select whole image - -***************************************************************************/ - -// user select area dialog -// line drawing and selection by color range are combined // v.9.7 - -void m_select(GtkWidget *, cchar *) // menu function -{ - int select_dialog_event(zdialog *, cchar *event); // dialog event and completion funcs - - cchar *title = ZTX("Select Area for Edits"); - cchar *helptext = ZTX("Press F1 for help"); - - zfuncs::F1_help_topic = "select_area"; - - if (! curr_file) return; // no image - if (zdsela) return; // already active - - if (CEF && CEF->Farea != 2) { // active edit function - zmessageACK(mWin,ZTX("Select Area not supported \n" // v.11.08 - "by this edit function")); - return; - } - - if (Fpreview) edit_fullsize(); // use full-size image - - if (! Fpxm16) { // create Fpxm16 if not already - mutex_lock(&Fpixmap_lock); - Fpxm16 = f_load(curr_file,16); - mutex_unlock(&Fpixmap_lock); - if (! Fpxm16) return; - } - -/*** v.11.02 - _________________________________________________________ - | Press F1 for help | - | (o) select rectangle | - | (o) select ellipse | - | (o) draw: freehand | - | (o) draw: follow edge | - | (o) select by mouse radius [__] | - | (o) select by color match [__] | - | [x] my mouse [x] firewall Blend Width [__] | - | | - | [Show] [Hide] [Color] [Finish] [Unfinish] | - | [Enable] [Disable] [Invert] [Unselect] [Done] | - |_________________________________________________________| - -***/ - - zdsela = zdialog_new(title,mWin,null); - zdialog_add_widget(zdsela,"label","labhelp","dialog",helptext); - zdialog_add_widget(zdsela,"hbox","hb1","dialog"); - zdialog_add_widget(zdsela,"vbox","vb1","hb1",0,"homog"); - zdialog_add_widget(zdsela,"vbox","vb2","hb1",0,"homog"); - zdialog_add_widget(zdsela,"radio","rbrect","vb1",ZTX("rectangle")); - zdialog_add_widget(zdsela,"radio","rbelips","vb1",ZTX("ellipse")); - zdialog_add_widget(zdsela,"radio","rbdraw","vb1",ZTX("draw: freehand")); - zdialog_add_widget(zdsela,"radio","rbfollow","vb1",ZTX("draw: follow edge")); - zdialog_add_widget(zdsela,"radio","rbmouse","vb1",ZTX("select by mouse")); - zdialog_add_widget(zdsela,"radio","rbcolor","vb1",ZTX("select by color")); - - zdialog_add_widget(zdsela,"label","space1","vb2"); - zdialog_add_widget(zdsela,"label","space2","vb2"); - zdialog_add_widget(zdsela,"label","space3","vb2"); - zdialog_add_widget(zdsela,"label","space4","vb2"); - - zdialog_add_widget(zdsela,"hbox","hbmouserad","vb2"); - zdialog_add_widget(zdsela,"label","labmouserad","hbmouserad",ZTX("radius"),"space=5"); - zdialog_add_widget(zdsela,"spin","mouseradius","hbmouserad","1|300|1|20"); - - zdialog_add_widget(zdsela,"hbox","hbcolor","vb2"); - zdialog_add_widget(zdsela,"label","labmatch","hbcolor",ZTX("match"),"space=5"); - zdialog_add_widget(zdsela,"spin","colormatch","hbcolor","0|100|1|90"); - - zdialog_add_widget(zdsela,"hbox","hbb1","dialog",0,"space=5"); - zdialog_add_widget(zdsela,"check","mymouse","hbb1",BmyMouse,"space=5"); - zdialog_add_widget(zdsela,"check","firewall","hbb1",ZTX("firewall"),"space=5"); - zdialog_add_widget(zdsela,"label","labblend","hbb1",Bblendwidth,"space=5"); - zdialog_add_widget(zdsela,"spin","blendwidth","hbb1","0|500|1|0"); - - zdialog_add_widget(zdsela,"hbox","hbb2","dialog",0,"space=5"); - zdialog_add_widget(zdsela,"button","show","hbb2",Bshow); - zdialog_add_widget(zdsela,"button","hide","hbb2",Bhide); - zdialog_add_widget(zdsela,"button","color","hbb2",Bcolor); - zdialog_add_widget(zdsela,"button","finish","hbb2",Bfinish); - zdialog_add_widget(zdsela,"button","unfinish","hbb2",Bunfinish); - - zdialog_add_widget(zdsela,"hbox","hbb3","dialog",0,"space=3"); - zdialog_add_widget(zdsela,"button","enable","hbb3",Benable); - zdialog_add_widget(zdsela,"button","disable","hbb3",Bdisable); - zdialog_add_widget(zdsela,"button","invert","hbb3",Binvert); - zdialog_add_widget(zdsela,"button","unselect","hbb3",Bunselect); - zdialog_add_widget(zdsela,"button","done","hbb3",Bdone); - - zdialog_help(zdsela,"select_area"); // v.11.08 - zdialog_run(zdsela,select_dialog_event,"save"); // run dialog - parallel v.11.07 - - sa_mouseradius = 20; // initial values matching dialog - sa_colormatch = 90; - sa_blend = 0; - sa_firewall = 0; - sa_mode = 3; // default mode = freehand draw - zdialog_stuff(zdsela,"rbdraw",1); - sa_show(1); // show existing area, if any - - return; -} - - -// dialog event and completion callback function - -int select_dialog_event(zdialog *zd, cchar *event) -{ - int ii, cc, mymouse; - - if (strEqu(event,"done") || zd->zstat) // done or cancel - { - freeMouse(); // disconnect mouse function v.10.12 - zdialog_free(zdsela); // kill dialog - return 0; - } - - if (CEF && CEF->Farea != 2) { // select area not supported v.11.08 - printf("select area ignored \n"); - return 0; - } - - if (sa_fww != Fww || sa_fhh != Fhh) // delete area not valid for image - sa_unselect(); // bugfix v.11.08 - - if (! sa_stat) { // no area, create one v.11.07 - cc = Fww * Fhh * sizeof(uint16); // allocate sa_pixmap[] for new area - sa_pixmap = (uint16 *) zmalloc(cc,"sa_select"); // maps pixels in area - memset(sa_pixmap,0,cc); - sa_currseq = sa_Ncurrseq = 0; // reset selection sequence - sa_Npixel = sa_blend = sa_calced = Factivearea = 0; - sa_fww = Fww; // valid image size for area v.11.08 - sa_fhh = Fhh; - sa_stat = 1; // status = edit - } - - ii = strcmpv(event,"rbrect","rbelips","rbdraw","rbfollow","rbcolor","rbmouse",null); - if (ii) { - sa_mode = ii; // radio button 1-6 - sa_stat = 1; // resume edit - sa_Npixel = sa_blend = sa_calced = Factivearea = 0; - zdialog_stuff(zd,"blendwidth",0); // reset blend width v.11.01 - sa_show(1); // show area v.11.04 - } - - if (strEqu(event,"mouseradius")) // mouse selection radius - zdialog_fetch(zd,"mouseradius",sa_mouseradius); - - if (strEqu(event,"colormatch")) // color match range, 0 to 99.9 - zdialog_fetch(zdsela,"colormatch",sa_colormatch); - - if (strEqu(event,"firewall")) // color select firewall on/off v.10.11 - zdialog_fetch(zdsela,"firewall",sa_firewall); - - if (strEqu(event,"mymouse")) { // toggle mouse capture v.10.12 - zdialog_fetch(zd,"mymouse",mymouse); - if (mymouse) { - sa_stat = 1; // resume edit - sa_Npixel = sa_blend = sa_calced = Factivearea = 0; - zdialog_stuff(zd,"blendwidth",0); // reset blend width v.11.01 - sa_show(1); - } - else sa_stat = 2; // pause edit - } - - if (strEqu(event,"show")) sa_show(1); // show area - - if (strEqu(event,"hide")) sa_show(0); // hide area - - if (strEqu(event,"color")) { // switch colors - if (sa_pixRGB == &red) sa_pixRGB = &green; - else if (sa_pixRGB == &green) sa_pixRGB = &black; - else sa_pixRGB = &red; - sa_show(1); - } - - if (strstr("finish unselect able invert blend",event)) { // dialog buttons - freeMouse(); // disconnect mouse v.11.04 - gdk_window_set_cursor(drWin->window,null); // normal cursor v.11.03 - } - - if (strEqu(event,"finish")) sa_finish(); // finish (finalize) area - if (strEqu(event,"unfinish")) sa_unfinish(); // unfinish area v.11.07 - if (strEqu(event,"unselect")) sa_unselect(); // unselect area - if (strEqu(event,"enable")) sa_enable(); // enable area - if (strEqu(event,"disable")) sa_disable(); // disable area - if (strEqu(event,"invert")) sa_invert(); // invert area - - if (strEqu(event,"blendwidth") && Factivearea) { // blend width changed - sa_edgecalc(); // do edge calc. if not already - if (sa_calced && CEF && CEF->zd) { // edit is active - zdialog_fetch(zd,"blendwidth",sa_blend); // update sa_blend - zdialog_send_event(CEF->zd,event); // notify edit dialog - } - } // "ignore once" logic removed v.11.01 - - if (sa_stat == 1) // active edit mode - { - if (sa_mode == 1) takeMouse(zd,sa_geom_mousefunc,dragcursor); // rectangle v.11.03 - if (sa_mode == 2) takeMouse(zd,sa_geom_mousefunc,dragcursor); // ellipse - if (sa_mode == 3) takeMouse(zd,sa_draw_mousefunc,drawcursor); // freehand draw - if (sa_mode == 4) takeMouse(zd,sa_draw_mousefunc,drawcursor); // follow edge - if (sa_mode == 5) takeMouse(zd,sa_color_mousefunc,0); // color match - if (sa_mode == 6) takeMouse(zd,sa_radius_mousefunc,0); // mouse radius - if (sa_mode < 3) sa_geom1 = sa_geom2 = 0; // new rectangle or ellipse - if (sa_mode < 5) paint_toparc(2); // erase radius circle - } - else // edit paused - freeMouse(); // disconnect mouse v.10.12 - - return 0; -} - - -// select area mouse function - select a rectangle or ellipse - -void sa_geom_mousefunc() // new v.11.03 -{ - static int mx1, my1, mx2, my2; - static int mdx0, mdy0; - - if (sa_stat != 1) return; // area gone? v.11.07 - - if (sa_currseq > sa_maxseq-2) { - zmessageACK(mWin,ZTX("exceed %d edits"),sa_maxseq); // cannot continue - return; - } - - if (RMclick) // right mouse click - { - RMclick = 0; - sa_unselect_pixels(); // remove latest selection - sa_geom1 = sa_geom2 = 0; - mwpaint2(); - return; - } - - if (! Mxdrag && ! Mydrag) return; // v.11.04 - - if (Mxdown != mdx0 || Mydown != mdy0) { // new drag initiated - mdx0 = Mxdown; - mdy0 = Mydown; - mx1 = mdx0; // drag start, one corner - my1 = mdy0; - sa_geom1 = 1; - sa_geom2 = 0; - return; - } - - if (sa_geom2) sa_unselect_pixels(); // remove prior selection - mx2 = Mxdrag; // drag continues, 2nd corner - my2 = Mydrag; - sa_geom2 = 1; - - sa_nextseq(); // next sequence number - - if (sa_mode == 1) // draw rectangle - { - sa_draw_line(mx1,my1,mx2,my1); - sa_draw_line(mx2,my1,mx2,my2); - sa_draw_line(mx2,my2,mx1,my2); - sa_draw_line(mx1,my2,mx1,my1); - } - - if (sa_mode == 2) // draw ellipse - { - double a, b, a2, b2; - double x, y, x2, y2, cx, cy; - int px, py; - - a = abs(mx2 - mx1); // ellipse constants from v.11.04 - b = abs(my2 - my1); // enclosing rectangle - a2 = a * a; - b2 = b * b; - cx = mx1; // center at drag origin v.11.04 - cy = my1; - - for (y = -b; y < b; y++) // step through y values - { - y2 = y * y; - x2 = a2 * (1 - y2 / b2); - x = sqrt(x2); // corresp. x values, + and - - py = y + cy; - px = cx - x + 0.5; - sa_draw1pix(px,py); // draw 2 points on ellipse - px = cx + x + 0.5; - sa_draw1pix(px,py); - } - - for (x = -a; x < a; x++) // step through x values - { - x2 = x * x; - y2 = b2 * (1 - x2 / a2); - y = sqrt(y2); // corresp. y values, + and - - px = cx + x; - py = cy - y + 0.5; - sa_draw1pix(px,py); // draw 2 points on ellipse - py = cy + y + 0.5; - sa_draw1pix(px,py); - } - } - - mwpaint2(); - return; -} - - -// select area mouse function - freehand draw and follow edge - -void sa_draw_mousefunc() -{ - void sa_follow_edge(int mx1, int my1, int mx2, int my2); - - int mx1, my1, mx2, my2; - int npdist, npx, npy; - int ii, click, newseq, thresh; - static int drag = 0, mdx0, mdy0, mdx1, mdy1; - - if (sa_stat != 1) return; // area gone? v.11.07 - - sa_thresh = 4.0 / Mscale + 1; // mouse pixel distance threshold - click = newseq = 0; - - if (LMclick || Mxdrag || Mydrag) // left mouse click or mouse drag - { - if (LMclick) // left mouse click - { - LMclick = 0; - mx1 = mx2 = Mxclick; // click position - my1 = my2 = Myclick; - newseq++; - click++; - drag = 0; - } - else // drag motion - { - if (Mxdown != mdx0 || Mydown != mdy0) { // new drag initiated - mdx0 = mdx1 = Mxdown; - mdy0 = mdy1 = Mydown; - newseq++; - } - mx1 = mdx1; // drag start - my1 = mdy1; - mx2 = Mxdrag; // drag position - my2 = Mydrag; - mdx1 = mx2; // next drag start - mdy1 = my2; - drag++; - click = 0; - } - - if (Mbutton == 3) // right mouse >> erase - { - while (true) { - thresh = sa_thresh; - npdist = sa_nearpix(mx2,my2,thresh,npx,npy); - if (! npdist) break; - ii = npy * Fww + npx; - sa_pixmap[ii] = 0; - } - mwpaint2(); - return; - } - - if (sa_currseq > sa_maxseq-2) { - zmessageACK(mWin,ZTX("exceed %d edits"),sa_maxseq); // cannot continue - return; - } - - if (sa_currseq == 0 && newseq) // 1st pixel(s) of 1st sequence - { - sa_nextseq(); // set next (1st) sequence no. v.10.8 - sa_draw_line(mx1,my1,mx2,my2); // draw initial pixel or line - sa_endpx[sa_currseq] = mx2; - sa_endpy[sa_currseq] = my2; - return; - } - - if (click) { - mx1 = sa_endpx[sa_currseq]; // prior sequence end pixel - my1 = sa_endpy[sa_currseq]; // (before this click) - } - - if (drag) { - if (newseq) thresh = 2 * sa_thresh; // new drag threshold - else thresh = 5 * sa_thresh; // continuation drag threshold - npx = sa_endpx[sa_currseq]; // distance from prior end pixel - npy = sa_endpy[sa_currseq]; // (before this drag) - if (abs(mx1-npx) < thresh && abs(my1-npy) < thresh) { - mx1 = sa_endpx[sa_currseq]; // if < threshold, connect this - my1 = sa_endpy[sa_currseq]; // drag to prior drag or click - } - } - - if (newseq || drag > 50) { - sa_nextseq(); // set next sequence no. v.10.8 - drag = 1; // drag length within sequence - } - - if (sa_mode == 4) sa_follow_edge(mx1,my1,mx2,my2); // follow edge or draw line - else sa_draw_line(mx1,my1,mx2,my2); // from end pixel to mouse - - sa_endpx[sa_currseq] = mx2; // set end pixel for this sequence - sa_endpy[sa_currseq] = my2; - } - - else if (RMclick) // right mouse click - { - RMclick = 0; - sa_unselect_pixels(); // remove latest selection v.10.8 - mwpaint2(); - } - - return; -} - - -// Find the nearest drawn pixel within a radius of a given pixel. -// Returns distance to pixel, or zero if nothing found. -// Returns 1 for adjacent or diagonally adjacent pixel. - -int sa_nearpix(int mx, int my, int rad2, int &npx, int &npy) -{ - int ii, rad, qx, qy, dx, dy; - int mindist, dist; - - npx = npy = 0; - mindist = (rad2+1) * (rad2+1); - - for (rad = 1; rad <= rad2; rad++) // seek neighbors within range - { - if (rad * rad > mindist) break; // can stop searching now - - for (qx = mx-rad; qx <= mx+rad; qx++) // search within rad - for (qy = my-rad; qy <= my+rad; qy++) - { - if (qx != mx-rad && qx != mx+rad && // exclude within rad-1 - qy != my-rad && qy != my+rad) continue; // (already searched) - if (qx < 0 || qx > Fww-1) continue; - if (qy < 0 || qy > Fhh-1) continue; - ii = qy * Fww + qx; - if (! sa_pixmap[ii]) continue; - dx = (mx - qx) * (mx - qx); // found pixel - dy = (my - qy) * (my - qy); - dist = dx + dy; // distance**2 - if (dist < mindist) { - mindist = dist; - npx = qx; // save nearest pixel found - npy = qy; - } - } - } - - if (npx + npy) return sqrt(mindist) + 0.5; - return 0; -} - - -// draw a line between two given pixels -// add all in-line pixels to sa_pixmap[] - -void sa_draw_line(int px1, int py1, int px2, int py2) -{ - void sa_draw1pix(int px, int py); - - int pxm, pym; - double slope; - - if (sa_stat != 1) return; // area gone? v.11.07 - - if (px1 == px2 && py1 == py2) { // only one pixel - sa_draw1pix(px1,py1); - return; - } - - if (abs(py2 - py1) > abs(px2 - px1)) { - slope = 1.0 * (px2 - px1) / (py2 - py1); - if (py2 > py1) { - for (pym = py1; pym <= py2; pym++) { - pxm = round(px1 + slope * (pym - py1)); - sa_draw1pix(pxm,pym); - } - } - else { - for (pym = py1; pym >= py2; pym--) { - pxm = round(px1 + slope * (pym - py1)); - sa_draw1pix(pxm,pym); - } - } - } - else { - slope = 1.0 * (py2 - py1) / (px2 - px1); - if (px2 > px1) { - for (pxm = px1; pxm <= px2; pxm++) { - pym = round(py1 + slope * (pxm - px1)); - sa_draw1pix(pxm,pym); - } - } - else { - for (pxm = px1; pxm >= px2; pxm--) { - pym = round(py1 + slope * (pxm - px1)); - sa_draw1pix(pxm,pym); - } - } - } - - return; -} - - -// draw one pixel only if not already drawn - -void sa_draw1pix(int px, int py) -{ - if (px < 0 || px > Fww-1) return; // bugfix v.11.03.1 - if (py < 0 || py > Fhh-1) return; - int ii = Fww * py + px; - if (sa_pixmap[ii]) return; // map to curr. selection sequence - sa_pixmap[ii] = sa_currseq; - sa_Ncurrseq++; // v.10.8 - draw_fat_pixel(px,py,sa_pixRGB); // v.11.04 - return; -} - - -// Find series of edge pixels from px1/py1 to px2/py2 and connect them together. - -void sa_follow_edge(int px1, int py1, int px2, int py2) // v.10.8 -{ - double sa_get_contrast(int px, int py); - - double px3, py3, px4, py4, px5, py5, px6, py6; - double dx, dy, dist, contrast, maxcontrast; - - if (sa_stat != 1) return; // area gone? v.11.07 - - px3 = px1; // p3 progresses from p1 to p2 - py3 = py1; - - while (true) - { - dx = px2 - px3; - dy = py2 - py3; - - dist = sqrt(dx * dx + dy * dy); // last segment - if (dist < 3) break; - - px4 = px3 + dx / dist; // p4 = p3 moved toward p2 - py4 = py3 + dy / dist; - - maxcontrast = 0; - px6 = px4; - py6 = py4; - - for (int ii = -2; ii <= +2; ii++) // p5 points are in a line through p4 - { // and perpendicular to p4 - p2 - px5 = px4 + ii * dy / dist; - py5 = py4 - ii * dx / dist; - contrast = sa_get_contrast(px5,py5); - contrast *= (7 - abs(ii)); // favor points closer together v.10.9 - if (contrast > maxcontrast) { - px6 = px5; // p6 = highest contrast point in p5 - py6 = py5; - maxcontrast = contrast; - } - } - - sa_draw_line(px3,py3,px6,py6); // draw p3 to p6 - - px3 = px6; // next p3 - py3 = py6; - } - - sa_draw_line(px3,py3,px2,py2); - return; -} - - -// Find max. contrast between neighbors on opposite sides of given pixel - -double sa_get_contrast(int px, int py) // v.10.8 -{ - int map[4][2] = { {1, 0}, {1, 1}, {0, 1}, {-1, 1} }; - int ii, qx, qy; - uint16 *pix1, *pix2; - double red, green, blue; - double contrast, maxcontrast = 0; - double f65k = 1.0 / 65535.0; - - if (px < 1 || px > Fww-2) return 0; // avoid edge pixels - if (py < 1 || py > Fhh-2) return 0; - - for (ii = 0; ii < 4; ii++) // compare pixels around target - { // e.g. (px-1,py) to (px+1,py) - qx = map[ii][0]; - qy = map[ii][1]; - pix1 = PXMpix(Fpxm16,px+qx,py+qy); - pix2 = PXMpix(Fpxm16,px-qx,py-qy); - red = f65k * abs(pix1[0] - pix2[0]); - green = f65k * abs(pix1[1] - pix2[1]); - blue = f65k * abs(pix1[2] - pix2[2]); - contrast = (1.0 - red) * (1.0 - green) * (1.0 - blue); // no contrast = 1.0 - contrast = 1.0 - contrast; // max. contrast = 1.0 - if (contrast > maxcontrast) maxcontrast = contrast; - } - - return maxcontrast; -} - - -// select area by color range - mouse function - -void sa_color_mousefunc() -{ - void sa_find_color_pixels(); - - int cc; - static int mxdown, mydown, drag = 0; - - if (sa_stat != 1) return; // area gone? v.11.07 - - sa_radius = sa_mouseradius; // use mouse radius - sa_radius2 = sa_radius * sa_radius; - - toparcx = Mxposn - sa_radius; // draw radius outline circle - toparcy = Myposn - sa_radius; - toparcw = toparch = 2 * sa_radius; - Ftoparc = 1; - paint_toparc(3); - - if (sa_stackdirec) zfree(sa_stackdirec); // allocate pixel search stack - if (sa_stackii) zfree(sa_stackii); - cc = Fww * Fhh; - sa_stackdirec = zmalloc(cc,"sa_color"); - sa_stackii = (int *) zmalloc(4*cc,"sa_color"); - sa_maxstack = cc; - sa_Nstack = 0; - - sa_mousex = sa_mousey = 0; - - if (LMclick) { // get mouse position at click - sa_mousex = Mxclick; - sa_mousey = Myclick; - LMclick = 0; - sa_nextseq(); // set next sequence no. v.10.8 - drag = 1; - } - - if ((Mxdrag || Mydrag) && Mbutton == 3) { // right drag, unselect within radius - sa_radius_mousefunc(); - mwpaint2(); - } - - if ((Mxdrag || Mydrag) && Mbutton == 1) { // left drag, select matching colors - sa_mousex = Mxdrag; - sa_mousey = Mydrag; - Mxdrag = Mydrag = 0; - - if (Mxdown != mxdown || Mydown != mydown) { // detect if new drag started - mxdown = Mxdown; - mydown = Mydown; - sa_nextseq(); // set next sequence no. v.10.8 - drag = 1; - } - else if (++drag > 30) { // limit work per sequence no. - sa_nextseq(); // set next sequence no. v.10.8 - drag = 1; - } - } - - if (sa_mousex || sa_mousey) { - sa_find_color_pixels(); // accumulate pixels - mwpaint2(); - } - - if (RMclick) { - RMclick = 0; - sa_unselect_pixels(); // remove latest selection v.10.8 - mwpaint2(); - } - - return; -} - - -// find all contiguous pixels within the specified range of colors to match - -void sa_find_color_pixels() // overhauled v.11.02 -{ - int ii, kk, cc, px, py, rx, ry, rad2; - int ppx, ppy, npx, npy; - uint16 *matchpix; - double match1, match2, ff = 1.0 / 65536.0; - double dred, dgreen, dblue; - char direc; - - match1 = 0.01 * sa_colormatch; // color match level, 0.01 to 1.0 - - px = sa_mousex; - py = sa_mousey; - if (px < 0 || px > Fww-1) return; // mouse outside image - if (py < 0 || py > Fhh-1) return; - - cc = Fww * Fhh; // allocate selection map - sa_pixselc = zmalloc(cc,"sa_color"); - memset(sa_pixselc,0,cc); - - sa_Nmatch = 0; // match color count - - for (rx = -sa_radius; rx <= sa_radius; rx++) // loop every pixel in radius of mouse - for (ry = -sa_radius; ry <= sa_radius; ry++) - { - rad2 = rx * rx + ry * ry; - if (rad2 > sa_radius2) continue; // outside radius - px = sa_mousex + rx; - py = sa_mousey + ry; - if (px < 0 || px > Fww-1) continue; // off the image edge - if (py < 0 || py > Fhh-1) continue; - - matchpix = PXMpix(Fpxm16,px,py); // get color at mouse position - - for (ii = 0; ii < sa_Nmatch; ii++) // see if color is already included - { - dred = ff * abs(sa_matchRGB[ii][0] - matchpix[0]); // 0 = perfect match - dgreen = ff * abs(sa_matchRGB[ii][1] - matchpix[1]); - dblue = ff * abs(sa_matchRGB[ii][2] - matchpix[2]); - match2 = (1.0 - dred) * (1.0 - dgreen) * (1.0 - dblue); // 1 = perfect match - if (match2 >= match1) break; // matches close enough - } - - if (ii == sa_Nmatch) { // no close match - sa_matchRGB[ii][0] = matchpix[0]; // add new match color to list - sa_matchRGB[ii][1] = matchpix[1]; - sa_matchRGB[ii][2] = matchpix[2]; - sa_Nmatch++; - if (sa_Nmatch == 1000) goto startsearch; // capacity limit - } - } - -startsearch: - - sa_Ncurrseq = 0; // count newly selected pixels - - px = sa_mousex; // pixel at mouse - py = sa_mousey; - ii = Fww * py + px; - sa_pixselc[ii] = 1; // pixel is in current selection - - if (! sa_pixmap[ii]) { // if selected for the first time, v.10.12 - sa_pixmap[ii] = sa_currseq; // map pixel to current sequence - sa_Ncurrseq++; // current sequence pixel count - } - - sa_stackii[0] = ii; // put 1st pixel into stack - sa_stackdirec[0] = 'a'; // direction = ahead v.11.04 - sa_Nstack = 1; // stack count - - while (sa_Nstack) - { - kk = sa_Nstack - 1; // get last pixel in stack - ii = sa_stackii[kk]; - direc = sa_stackdirec[kk]; - - py = ii / Fww; // reconstruct px, py - px = ii - Fww * py; - - if (direc == 'x') { // no neighbors left to check - sa_Nstack--; - continue; - } - - if (sa_Nstack > 1) { - ii = sa_Nstack - 2; // get prior pixel in stack - ii = sa_stackii[ii]; - ppy = ii / Fww; - ppx = ii - ppy * Fww; - } - else { - ppx = px - 1; // if only one, assume prior = left - ppy = py; - } - - if (direc == 'a') { // next ahead pixel v.11.04 - npx = px + px - ppx; - npy = py + py - ppy; - sa_stackdirec[kk] = 'r'; // next search direction - } - - else if (direc == 'r') { // next right pixel v.11.04 - npx = px + py - ppy; - npy = py + px - ppx; - sa_stackdirec[kk] = 'l'; - } - - else { /* direc = 'l' */ // next left pixel v.11.04 - npx = px + ppy - py; - npy = py + ppx - px; - sa_stackdirec[kk] = 'x'; - } - - if (npx < 0 || npx > Fww-1) continue; // pixel off the edge v.11.04 - if (npy < 0 || npy > Fhh-1) continue; - - rx = npx - Mxposn; // limit search to 3 * mouse radius - ry = npy - Myposn; // v.11.04 - rad2 = rx * rx + ry * ry; - if (rad2 > 9 * sa_radius2) continue; - - ii = npy * Fww + npx; - if (sa_pixselc[ii]) continue; // already in current selection v.10.8 - - if (sa_firewall && sa_pixmap[ii]) // aleady selected, firewall mode v.10.12 - if (rad2 > sa_radius2) continue; // and pixel outside mouse radius - - matchpix = PXMpix(Fpxm16,npx,npy); - for (kk = 0; kk < sa_Nmatch; kk++) { // compare pixel RGB to match colors - dred = ff * abs(sa_matchRGB[kk][0] - matchpix[0]); // v.10.8 - dgreen = ff * abs(sa_matchRGB[kk][1] - matchpix[1]); - dblue = ff * abs(sa_matchRGB[kk][2] - matchpix[2]); - match2 = (1.0 - dred) * (1.0 - dgreen) * (1.0 - dblue); // 1 = perfect match - if (match2 >= match1) break; // within range - } - if (kk == sa_Nmatch) continue; // not within range of any color - - sa_pixselc[ii] = 1; // map pixel to current selection v.10.8 - - if (! sa_pixmap[ii]) { // if selected for the first time, v.10.12 - sa_pixmap[ii] = sa_currseq; // map pixel to current sequence - sa_Ncurrseq++; // current sequence pixel count - } - - if (sa_Nstack == sa_maxstack) continue; // stack is full - kk = sa_Nstack++; // push pixel into stack - sa_stackii[kk] = ii; - sa_stackdirec[kk] = 'a'; // direction = ahead v.11.04 - } - - zfree(sa_pixselc); // free memory - return; -} - - -// select or un-select all pixels within radius - mouse function - -void sa_radius_mousefunc() -{ - int ii, px, py, rx, ry; - - if (sa_stat != 1) return; // area gone? v.11.07 - - sa_radius = sa_mouseradius; // pixel selection radius - sa_radius2 = sa_radius * sa_radius; - - toparcx = Mxposn - sa_radius; // draw radius outline circle - toparcy = Myposn - sa_radius; - toparcw = toparch = 2 * sa_radius; - Ftoparc = 1; - paint_toparc(3); - - if (LMclick || RMclick) { // mouse click - sa_nextseq(); // set next sequence no. v.10.8 - LMclick = RMclick = 0; - } - - if (Mbutton != 1 && Mbutton != 3) { // button released - sa_nextseq(); // set next sequence no. v.10.8 - return; // (if some pixels mapped) - } - - for (rx = -sa_radius; rx <= sa_radius; rx++) // loop every pixel in radius - for (ry = -sa_radius; ry <= sa_radius; ry++) - { - if (rx * rx + ry * ry > sa_radius2) continue; // outside radius - px = Mxposn + rx; - py = Myposn + ry; - if (px < 0 || px > Fww-1) continue; // off the image edge - if (py < 0 || py > Fhh-1) continue; - - ii = Fww * py + px; - - if (Mbutton == 3) // right mouse button - sa_pixmap[ii] = 0; // remove pixel from select area - - if (Mbutton == 1) // left mouse button - { - if (sa_pixmap[ii]) continue; // pixel already selected - - if (sa_Ncurrseq > 1000) // start new sequence no. - sa_nextseq(); // after 1000 pixels - - sa_pixmap[ii] = sa_currseq; // map pixel to current sequence - sa_Ncurrseq++; - } - } - - mwpaint2(); -} - - -// set next sequence number for pixels about to be selected - -void sa_nextseq() // v.10.8 -{ - if (sa_Ncurrseq > 0) sa_currseq++; // increase only if some pixels mapped - if (sa_currseq < sa_initseq) sa_currseq = sa_initseq; // start at initial value - sa_Ncurrseq = 0; - return; -} - - -// un-select all pixels mapped to current sequence number -// reduce sequence number and set pixel count = 1 - -void sa_unselect_pixels() -{ - if (sa_stat != 1) return; // area gone? v.11.07 - if (! sa_currseq) return; // no pixels mapped - - for (int ii = 0; ii < Fww * Fhh; ii++) - if (sa_pixmap[ii] == sa_currseq) sa_pixmap[ii] = 0; // unmap current selection - - if (sa_currseq > sa_initseq) { // reduce sequence no. v.10.8 - sa_currseq--; - sa_Ncurrseq = 1; // unknown but > 0 - } - else sa_Ncurrseq = 0; // initial sequence no. reached - - return; -} - - -// Finish select area - map pixels enclosed by edge pixels -// into sa_pixmap[ii]: 0/1/2 = outside/edge/inside (ii=py*Fww+px) -// total count = sa_Npixel - -zdialog *safinzd = 0; - -void sa_finish() // overhauled v.11.02 -{ - void sa_finish_mousefunc(); - int sa_finish_dialog_event(zdialog *, cchar *event); - - cchar *fmess = ZTX("Click one time inside each enclosed area \n" - "(possible gaps in the outline will be found). \n" - "Press F1 for help."); - - GtkWidget *pwin = zdialog_widget(zdsela,"dialog"); - int ii, cc, px, py; - - if (! sa_stat) return; // no area? v.11.07 - if (sa_fww != Fww || sa_fhh != Fhh) return; // area not valid for image v.11.08 - if (sa_mode == 7) return; // a whole image area - - sa_Npixel = Factivearea = 0; // area disabled, unfinished - sa_hole = 0; // no hole detected yet - sa_show(1); // show outline - - sa_minx = Fww; - sa_maxx = 0; - sa_miny = Fhh; - sa_maxy = 0; - - for (ii = 0; ii < Fww * Fhh; ii++) // get enclosing rectangle - { // for selected area - if (! sa_pixmap[ii]) continue; - py = ii / Fww; - px = ii - Fww * py; - if (px >= sa_maxx) sa_maxx = px+1; // like Fww, sa_maxx = last + 1 - if (px < sa_minx) sa_minx = px; - if (py >= sa_maxy) sa_maxy = py+1; - if (py < sa_miny) sa_miny = py; - } - - sa_minx -= 10; // add margins where possible - if (sa_minx < 0) sa_minx = 0; - sa_maxx += 10; - if (sa_maxx > Fww) sa_maxx = Fww; - sa_miny -= 10; - if (sa_miny < 0) sa_miny = 0; - sa_maxy += 10; - if (sa_maxy > Fhh) sa_maxy = Fhh; - - sa_map_pixels(); // map edge and interior pixels - if (sa_Npixel < 10) return; // ridiculous - - for (py = sa_miny; py < sa_maxy; py++) // loop pixels in rectangle v.10.12 - for (px = sa_minx; px < sa_maxx; px++) - { - ii = Fww * py + px; - if (sa_pixmap[ii] == 2) sa_pixmap[ii] = 0; // eliminate interior pixels - } - - cc = (sa_maxx-sa_minx) * (sa_maxy-sa_miny); // allocate stack memory - if (sa_stackdirec) zfree(sa_stackdirec); - sa_stackdirec = zmalloc(cc,"sa_finish"); - if (sa_stackii) zfree(sa_stackii); - sa_stackii = (int *) zmalloc(cc * 4,"sa_finish"); - sa_maxstack = cc; - - safinzd = zdialog_new(ZTX("finish area"),pwin,Bdone,Bcancel,null); // dialog for user to click inside - zdialog_add_widget(safinzd,"label","fmess","dialog",fmess,"space=5"); // each enclosed area - zdialog_add_widget(safinzd,"hbox","hbstat","dialog"); - zdialog_add_widget(safinzd,"label","labstat","hbstat","status:","space=5"); - zdialog_add_widget(safinzd,"label","statmess","hbstat",0); - - takeMouse(safinzd,sa_finish_mousefunc,dragcursor); // connect mouse function v.11.03 - - zdialog_run(safinzd,sa_finish_dialog_event,"save"); // run dialog, parallel v.11.07 - zdialog_wait(safinzd); - return; -} - - -// mouse function - get user clicks and perform pixel searches - -void sa_finish_mousefunc() // overhauled v.11.02 -{ - int px, py, ii, kk; - int ppx, ppy, npx, npy; - char direc; - - if (! LMclick) return; - LMclick = 0; - - if (! sa_stat) return; // area gone? v.11.07 - - ii = Fww * Myclick + Mxclick; // seed pixel from mouse click - if (sa_pixmap[ii] == 1) return; // ignore if edge pixel v.11.07 - sa_pixmap[ii] = 2; // map the pixel, inside area - sa_stackii[0] = ii; // put seed pixel into stack - sa_stackdirec[0] = 'a'; // direction = ahead v.11.04 - sa_Nstack = 1; // stack count - - zdialog_stuff(safinzd,"statmess",ZTX("searching")); - zmainloop(); - zsleep(0.2); - - Ffuncbusy++; - - while (sa_Nstack) // find all pixels outside enclosed area(s) - { - kk = sa_Nstack - 1; // get last pixel in stack - ii = sa_stackii[kk]; - direc = sa_stackdirec[kk]; - - py = ii / Fww; // reconstruct px, py - px = ii - Fww * py; - - if (px < sa_minx || px >= sa_maxx || py < sa_miny || py >= sa_maxy) // moved v.11.08 - { - sa_hole++; // ran off the edge, seed pixel was - break; // not inside area or area has a hole - } - - if (direc == 'x') { // no neighbors left to check - sa_Nstack--; - continue; - } - - if (sa_Nstack > 1) { - ii = sa_Nstack - 2; // get prior pixel in stack - ii = sa_stackii[ii]; - ppy = ii / Fww; - ppx = ii - ppy * Fww; - } - else { - ppx = px - 1; // if only one, assume prior = left - ppy = py; - } - - if (direc == 'a') { // next ahead pixel v.11.04 - npx = px + px - ppx; - npy = py + py - ppy; - sa_stackdirec[kk] = 'r'; // next search direction - } - - else if (direc == 'r') { // next right pixel v.11.04 - npx = px + py - ppy; - npy = py + px - ppx; - sa_stackdirec[kk] = 'l'; - } - - else { /* direc = 'l' */ // next left pixel v.11.04 - npx = px + ppy - py; - npy = py + ppx - px; - sa_stackdirec[kk] = 'x'; - } - - if (npx < 0 || npx > Fww-1) continue; // next pixel off the image edge - if (npy < 0 || npy > Fhh-1) continue; // bugfix v.11.04 - - ii = npy * Fww + npx; - if (sa_pixmap[ii]) continue; // pixel already mapped - - sa_pixmap[ii] = 2; // map the pixel, inside area - kk = sa_Nstack++; // put pixel into stack - sa_stackii[kk] = ii; - sa_stackdirec[kk] = 'a'; // direction = ahead v.11.04 - draw_pixel(npx,npy,sa_pixRGB); // color mapped pixels - zmainloop(30); // let window update v.11.07 - } - - Ffuncbusy--; - - if (sa_hole) - zdialog_stuff(safinzd,"statmess",ZTX("outline has a gap")); - else - zdialog_stuff(safinzd,"statmess",ZTX("success")); // all pixels found and mapped - return; -} - - -// dialog event and completion callback function - -int sa_finish_dialog_event(zdialog *zd, cchar *event) -{ - int zstat; - - freeMouse(); // disconnect mouse - zstat = zd->zstat; - zdialog_free(safinzd); // kill dialog - - if (! sa_stat) return 0; // area gone? v.11.07 - - if (zstat != 1 || sa_hole) // user cancel or pixel search failure - { - sa_unfinish(); // unmap interior pixels, set edit mode - return 0; // v.11.07 - } - - sa_map_pixels(); // count pixels, map interior pixels - - sa_stat = 3; // area is finished - Factivearea = 1; // area is active by default - sa_calced = sa_blend = 0; // edge calculation is missing - mwpaint2(); - return 0; -} - - -// Finish select area automatically when the -// interior selected pixels are already known. - -void sa_finish_auto() -{ - int ii, px, py; - - if (! sa_stat) return; // no area? v.11.07 - if (sa_fww != Fww || sa_fhh != Fhh) return; // area not valid for image v.11.08 - - sa_Npixel = Factivearea = 0; // area disabled, unfinished - - sa_minx = Fww; - sa_maxx = 0; - sa_miny = Fhh; - sa_maxy = 0; - - for (ii = 0; ii < Fww * Fhh; ii++) // get enclosing rectangle - { // for selected area - if (! sa_pixmap[ii]) continue; - py = ii / Fww; - px = ii - Fww * py; - if (px >= sa_maxx) sa_maxx = px+1; // like Fww, sa_maxx = last + 1 - if (px < sa_minx) sa_minx = px; - if (py >= sa_maxy) sa_maxy = py+1; - if (py < sa_miny) sa_miny = py; - } - - sa_minx -= 10; // add margins where possible - if (sa_minx < 0) sa_minx = 0; - sa_maxx += 10; - if (sa_maxx > Fww) sa_maxx = Fww; - sa_miny -= 10; - if (sa_miny < 0) sa_miny = 0; - sa_maxy += 10; - if (sa_maxy > Fhh) sa_maxy = Fhh; - - sa_map_pixels(); // count pixels, map interior pixels - - sa_stat = 3; // area is finished - Factivearea = 1; // area is active by default - sa_calced = sa_blend = 0; // edge calculation is missing - mwpaint2(); - return; -} - - -// private function -// map edge and interior pixels (sa_pixmap[*] = 1 or 2) -// set sa_Npixel = total pixel count - -void sa_map_pixels() // v.11.07 -{ - int npix, px, py, ii, kk; - - if (! sa_stat) return; // no area? - - npix = 0; - - for (py = sa_miny; py < sa_maxy; py++) // find edge pixels - for (px = sa_minx; px < sa_maxx; px++) - { - ii = py * Fww + px; - if (! sa_pixmap[ii]) continue; - npix++; - - if (px == 0 || px == Fww-1 || py == 0 || py == Fhh-1) // edge of image - goto edgepix; - - if (! sa_pixmap[ii-1] || ! sa_pixmap[ii+1]) goto edgepix; // check 8 neighbor pixels - kk = ii - Fww; - if (! sa_pixmap[kk] || ! sa_pixmap[kk-1] || ! sa_pixmap[kk+1]) goto edgepix; - kk = ii + Fww; - if (! sa_pixmap[kk] || ! sa_pixmap[kk-1] || ! sa_pixmap[kk+1]) goto edgepix; - - sa_pixmap[ii] = 2; // interior pixel - continue; - - edgepix: - sa_pixmap[ii] = 1; // edge pixel - } - - sa_Npixel = npix; // total pixel count - return; -} - - -// unfinish an area - unmap interior pixels and put back in edit mode - -void sa_unfinish() // v.11.07 -{ - int px, py, ii; - - if (! sa_stat) return; // no area? - - for (py = sa_miny; py < sa_maxy; py++) // loop pixels in rectangle - for (px = sa_minx; px < sa_maxx; px++) - { - ii = py * Fww + px; // clear interior pixels found - if (sa_pixmap[ii] == 2) sa_pixmap[ii] = 0; // by finish search function - } - - sa_stat = 1; // resume edit mode - Factivearea = 0; - sa_calced = sa_blend = 0; - mwpaint2(); - return; -} - - -// menu function for show, hide, enable, disable, invert, unselect -// (also implemented as buttons in select area dialog) - -void m_select_show(GtkWidget *, cchar *menu) -{ - zfuncs::F1_help_topic = "area_show_hide"; - sa_show(1); - return; -} - - -void m_select_hide(GtkWidget *, cchar *menu) -{ - zfuncs::F1_help_topic = "area_show_hide"; - sa_show(0); - return; -} - - -void m_select_enable(GtkWidget *, cchar *menu) -{ - zfuncs::F1_help_topic = "area_enable_disable"; - sa_enable(); - return; -} - - -void m_select_disable(GtkWidget *, cchar *menu) -{ - zfuncs::F1_help_topic = "area_enable_disable"; - sa_disable(); - return; -} - - -void m_select_invert(GtkWidget *, cchar *menu) -{ - zfuncs::F1_help_topic = "area_invert"; - sa_invert(); - return; -} - - -void m_select_unselect(GtkWidget *, cchar *menu) // delete the area -{ - zfuncs::F1_help_topic = "area_unselect"; - sa_unselect(); - return; -} - - -// show or hide outline of select area -// also called from mwpaint1() if Fshowarea = 1 - -void sa_show(int flag) -{ - int px, py, ii, kk; - - if (! sa_stat) return; // no area - if (sa_fww != Fww || sa_fhh != Fhh) return; // area not valid for image - if (sa_mode == 7) return; // a whole image area - if (Fpreview) return; // preview mode, area ignored - - Fshowarea = flag; // flag for mwpaint1() - - if (! flag) { - mwpaint2(); // erase area outline v.10.8 - return; - } - - for (py = 0; py < Fhh; py++) // find pixels in area bugfix v.10.9 - for (px = 0; px < Fww; px++) - { - ii = py * Fww + px; - if (! sa_pixmap[ii]) continue; // outside of area - - if (px == 0 || px == Fww-1 || py == 0 || py == Fhh-1) // edge of image - goto edgepix; - - if (! sa_pixmap[ii-1] || ! sa_pixmap[ii+1]) goto edgepix; // check 8 neighbor pixels - kk = ii - Fww; - if (! sa_pixmap[kk] || ! sa_pixmap[kk-1] || ! sa_pixmap[kk+1]) goto edgepix; - kk = ii + Fww; - if (! sa_pixmap[kk] || ! sa_pixmap[kk-1] || ! sa_pixmap[kk+1]) goto edgepix; - continue; - - edgepix: - draw_fat_pixel(px,py,sa_pixRGB); // draw fat pixels v.11.04 - } - - return; -} - - -// enable select area that was disabled - -void sa_enable() -{ - if (sa_fww != Fww || sa_fhh != Fhh) return; // area not valid for image v.11.08 - - if (sa_stat != 3) { - zmessageACK(mWin,ZTX("the area is not finished")); // v.11.08 - return; // v.11.06.1 - } - - Factivearea = 1; - sa_show(1); // v.10.11 - return; -} - - -// disable select area - -void sa_disable() -{ - Factivearea = 0; // v.9.7 - sa_show(0); // v.10.11 - return; -} - - -// invert a selected area - -void sa_invert() -{ - int ii, jj, px, py, npix; - - if (sa_fww != Fww || sa_fhh != Fhh) return; // area not valid for image v.11.08 - - if (sa_stat != 3) { // v.11.06.1 - zmessageACK(mWin,ZTX("the area is not finished")); - return; - } - - if (sa_mode == 7) return; // a whole image area - - npix = 0; - - for (py = 0; py < Fhh; py++) // loop all pixels - for (px = 0; px < Fww; px++) - { - ii = py * Fww + px; - jj = sa_pixmap[ii]; // 0/1/2+ = outside/edge/inside - - if (px == 0 || px == Fww-1 || py == 0 || py == Fhh-1) // pixel on image edge v.10.12 - { - if (jj == 0) { - sa_pixmap[ii] = 1; // outside pixel >> edge pixel - npix++; // count - } - else sa_pixmap[ii] = 0; // edge pixel >> outside - continue; - } - - if (jj > 1) sa_pixmap[ii] = 0; // inside pixel (2+) >> outside (0) - else { - sa_pixmap[ii] = 2 - jj; // edge/outside (1/0) >> edge/inside (1/2) - npix++; // count - } - } - - sa_Npixel = npix; // new select area pixel count - sa_calced = sa_blend = 0; // edge calculation missing - if (zdsela) zdialog_stuff(zdsela,"blendwidth",0); // reset blend width v.11.01 - - sa_minx = Fww; // new enclosing rectangle bugfix v.11.01 - sa_maxx = 0; - sa_miny = Fhh; - sa_maxy = 0; - - for (ii = 0; ii < Fww * Fhh; ii++) - { - if (! sa_pixmap[ii]) continue; - py = ii / Fww; - px = ii - Fww * py; - if (px >= sa_maxx) sa_maxx = px + 1; - if (px < sa_minx) sa_minx = px; - if (py >= sa_maxy) sa_maxy = py + 1; - if (py < sa_miny) sa_miny = py; - } - - return; -} - - -// unselect current area (delete the area) - -void sa_unselect() -{ - sa_stat = sa_Npixel = sa_blend = sa_calced = Factivearea = 0; - sa_currseq = sa_Ncurrseq = 0; - sa_fww = sa_fhh = 0; // v.11.08 - if (sa_pixmap) zfree(sa_pixmap); - if (sa_stackii) zfree(sa_stackii); - if (sa_stackdirec) zfree(sa_stackdirec); - sa_pixmap = 0; - sa_stackii = 0; - sa_stackdirec = 0; - if (zdsela) zdialog_stuff(zdsela,"blendwidth",0); // reset blend width v.11.01 - mwpaint2(); - return; -} - - -// compute distance from all pixels in area to nearest edge -// output: sa_pixmap[*] = 0/1/2+ = outside, edge, inside distance from edge - -namespace sa_edgecalc_names -{ - uint16 *sa_edgepx, *sa_edgepy, *sa_edgedist; - int sa_Nedge; -} - -void sa_edgecalc() -{ - using namespace sa_edgecalc_names; - - int edgecalc_dialog_event(zdialog*, cchar *event); - void * edgecalc_thread(void *); - - int ii, nn, cc, px, py; - zdialog *zd = 0; - cchar *zectext = ZTX("Edge calculation in progress"); - - if (! sa_stat) return; // area gone? v.11.07 - if (sa_mode == 7) return; // a whole image area - - if (sa_calced) return; // done already - if (! Factivearea) sa_finish(); // finish if needed - if (! Factivearea) return; // no finished area - - zd = zdialog_new(ZTX("Area Edge Calc"),mWin,Bcancel,null); // start dialog for user cancel - zdialog_add_widget(zd,"label","lab1","dialog",zectext,"space=10"); - zdialog_run(zd,edgecalc_dialog_event); - Fkillfunc = 0; - - cc = Fww * Fhh * sizeof(uint16); // allocate memory for calculations - sa_edgedist = (uint16 *) zmalloc(cc,"sa_edgecalc"); - memset(sa_edgedist,0,cc); - - for (ii = nn = 0; ii < Fww * Fhh; ii++) // count edge pixels in select area - if (sa_pixmap[ii] == 1) nn++; - - cc = nn * sizeof(uint16); - sa_edgepx = (uint16 *) zmalloc(cc,"sa_edgecalc"); // allocate memory - sa_edgepy = (uint16 *) zmalloc(cc,"sa_edgecalc"); - - for (ii = nn = 0; ii < Fww * Fhh; ii++) // build list of edge pixels - { // v.9.6 - if (sa_pixmap[ii] != 1) continue; - py = ii / Fww; - px = ii - py * Fww; - if (px < 3 || px > Fww-4) continue; // omit pixels < 3 from image edge - if (py < 3 || py > Fhh-4) continue; - sa_edgepx[nn] = px; - sa_edgepy[nn] = py; - nn++; - } - - sa_Nedge = nn; - - SB_goal = sa_Npixel; - SB_done = 0; - - for (ii = 0; ii < Nwt; ii++) // start worker threads to calculate - start_wthread(edgecalc_thread,&wtnx[ii]); // sa_pixmap[] edge distances - wait_wthreads(); // wait for completion - - SB_goal = 0; - - if (! Fkillfunc) { // v.11.07 - for (ii = 0; ii < Fww * Fhh; ii++) // copy data from sa_edgedist[] - { // to sa_pixmap[] - if (sa_pixmap[ii] < 2) continue; // skip outside and edge pixels - sa_pixmap[ii] = sa_edgedist[ii]; // interior pixel edge distance - } - } - - zdialog_free(zd); // kill dialog - zfree(sa_edgedist); // free memory - zfree(sa_edgepx); - zfree(sa_edgepy); - - if (Fkillfunc) { - Fkillfunc = 0; - sa_calced = 0; - if (zdsela) zdialog_stuff(zdsela,"blendwidth",0); // reset blend width v.11.01 - } - - sa_calced = 1; // edge calculation available - - mwpaint2(); - return; -} - - -// dialog event and completion callback function - -int edgecalc_dialog_event(zdialog *zd, cchar *event) // respond to user cancel -{ - Fkillfunc = 1; - printf("edge calc killed \n"); - return 0; -} - - -void * edgecalc_thread(void *arg) // worker thread function -{ // new algorithm v.11.05 - using namespace sa_edgecalc_names; - - void edgecalc_f1(int px, int py); - - int index = *((int *) (arg)); - int midx, midy, radx, rady, rad; - int ii, px, py; - - midx = (sa_maxx + sa_minx) / 2; - midy = (sa_maxy + sa_miny) / 2; - radx = (sa_maxx - sa_minx) / 2 + 1; - rady = (sa_maxy - sa_miny) / 2 + 1; - px = midx; // center of enclosing rectangle - py = midy; - - ii = py * Fww + px; - if (sa_pixmap[ii]) edgecalc_f1(px,py); // do center pixel first - - for (rad = 1; rad < radx || rad < rady; rad++) // expanding square from the center - { - for (px = midx-rad; px <= midx+rad; px += 2 * rad) // process edges only, interior already done - for (py = midy-rad+index; py <= midy+rad; py += Nwt) - { - if (px < 0 || px > Fww-1) continue; - if (py < 0 || py > Fhh-1) continue; - ii = py * Fww + px; - if (! sa_pixmap[ii]) continue; - if (sa_edgedist[ii]) continue; - edgecalc_f1(px,py); - if (Fkillfunc) exit_wthread(); - } - - for (py = midy-rad; py <= midy+rad; py += 2 * rad) - for (px = midx-rad+index; px <= midx+rad; px += Nwt) - { - if (px < 0 || px > Fww-1) continue; - if (py < 0 || py > Fhh-1) continue; - ii = py * Fww + px; - if (! sa_pixmap[ii]) continue; - if (sa_edgedist[ii]) continue; - edgecalc_f1(px,py); - if (Fkillfunc) exit_wthread(); - } - } - - exit_wthread(); - return 0; // not executed, stop gcc warning -} - - -// Find the nearest edge pixel for a given pixel. -// For all pixels in a line from the given pixel to the edge pixel, -// the same edge pixel is used to compute edge distance. - -void edgecalc_f1(int px1, int py1) -{ - using namespace sa_edgecalc_names; - - int ii, px2, py2, mindist; - uint dist2, mindist2; - int epx, epy, pxm, pym, dx, dy, inc; - double slope; - - mindist = 9999; - mindist2 = mindist * mindist; - epx = epy = 0; - - for (ii = 0; ii < sa_Nedge; ii++) // loop all edge pixels - { - px2 = sa_edgepx[ii]; - py2 = sa_edgepy[ii]; - dx = px2 - px1; - if (dx >= mindist) continue; // speedup v.11.05 - dy = py2 - py1; - if (dy >= mindist) continue; - dist2 = dx*dx + dy*dy; // avoid sqrt() - if (dist2 < mindist2) { - mindist2 = dist2; // remember minimum - epx = px2; // remember nearest edge pixel - mindist = sqrt(dist2); - epy = py2; - } - } - - if (abs(epy - py1) > abs(epx - px1)) { // find all pixels along a line - slope = 1.0 * (epx - px1) / (epy - py1); // to the edge pixel - if (epy > py1) inc = 1; - else inc = -1; - for (pym = py1; pym != epy; pym += inc) { - pxm = px1 + slope * (pym - py1); - ii = pym * Fww + pxm; - if (sa_edgedist[ii]) break; - dx = epx - pxm; // calculate distance to edge - dy = epy - pym; - dist2 = sqrt(dx*dx + dy*dy) + 0.5; - sa_edgedist[ii] = dist2; // save - SB_done++; // track progress v.11.06 - } - } - - else { - slope = 1.0 * (epy - py1) / (epx - px1); - if (epx > px1) inc = 1; - else inc = -1; - for (pxm = px1; pxm != epx; pxm += inc) { - pym = py1 + slope * (pxm - px1); - ii = pym * Fww + pxm; - if (sa_edgedist[ii]) break; - dx = epx - pxm; - dy = epy - pym; - dist2 = sqrt(dx*dx + dy*dy) + 0.5; - sa_edgedist[ii] = dist2; - SB_done++; - } - } - - return; -} - - -/************************************************************************** - select area copy and paste menu functions -***************************************************************************/ - -PXM *sacp_image16 = 0; // select area pixmap image -PXM *sacp_info16 = 0; // opacity and edge distance -int sacp_ww, sacp_hh; // original dimensions - -PXM *sacpR_image16 = 0; // resized/rotated image -PXM *sacpR_info16 = 0; // resized/rotated info -int sacpR_ww, sacpR_hh; // resized/rotated dimensions - -double sacp_resize; // size, 1.0 = original size -double sacp_angle; // angle of rotation, -180 to +180 -int sacp_orgx, sacp_orgy; // origin in target image -double sacp_blend; // edge blend with target image - - -// copy selected area, save in memory - -void m_select_copy(GtkWidget *, cchar *menu) // overhauled v.11.02 -{ - int ii, px, py; - int pxmin, pxmax, pymin, pymax; - uint16 *pix1, *pix2; - - if (menu) zfuncs::F1_help_topic = "area_copy_paste"; - - if (sa_mode == 7) return; // a whole image area v.11.01 - if (! Factivearea) sa_finish(); // finish area if not already - if (! Factivearea) return; - sa_edgecalc(); // do edge calc if not already - sa_show(0); - - pxmin = Fww; - pxmax = 0; - pymin = Fhh; - pymax = 0; - - for (ii = 0; ii < Fww * Fhh; ii++) // find pixels in select area - { // v.9.6 - if (! sa_pixmap[ii]) continue; - py = ii / Fww; - px = ii - py * Fww; - if (px > pxmax) pxmax = px; // find enclosing rectangle - if (px < pxmin) pxmin = px; - if (py > pymax) pymax = py; - if (py < pymin) pymin = py; - } - - PXM_free(sacp_image16); // free prior if any - PXM_free(sacp_info16); - PXM_free(sacpR_image16); - PXM_free(sacpR_info16); - - sacp_ww = pxmax - pxmin + 1; // new area image PXM - sacp_hh = pymax - pymin + 1; - sacp_image16 = PXM_make(sacp_ww,sacp_hh,16); - sacp_info16 = PXM_make(sacp_ww,sacp_hh,16); // new info PXM - - for (ii = 0; ii < Fww * Fhh; ii++) // find pixels in select area - { - if (! sa_pixmap[ii]) continue; // 0/1/2+ = outside/edge/inside edge distance - py = ii / Fww; - px = ii - py * Fww; - pix1 = PXMpix(Fpxm16,px,py); // copy pixels into image PXM - px = px - pxmin; - py = py - pymin; - pix2 = PXMpix(sacp_image16,px,py); - pix2[0] = pix1[0]; - pix2[1] = pix1[1]; - pix2[2] = pix1[2]; - pix2 = PXMpix(sacp_info16,px,py); // build info PXM v.11.02 - pix2[0] = 65535; // opacity - pix2[1] = sa_pixmap[ii]; // edge distance - pix2[2] = 0; - } - - return; -} - - -// paste selected area into current image -// this is an edit function - select area image is copied into main image - -int sacp_porg = 0; // pasted area is present -int sacp_porgx, sacp_porgy; // pasted area origin in image -int sacp_pww, sacp_phh; // pasted area dimensions - -editfunc EFpaste; - -void m_select_paste(GtkWidget *, cchar *menu) // menu function -{ - int select_paste_dialog_event(zdialog *, cchar *event); - void select_paste_mousefunc(); - - cchar *dragmess = ZTX("position with mouse click/drag"); - - if (menu) zfuncs::F1_help_topic = "area_copy_paste"; - - if (! sacp_image16) return; // nothing to paste - sa_unselect(); // unselect area if present - - EFpaste.funcname = "paste"; - if (! edit_setup(EFpaste)) return; // setup edit for paste - - sacp_resize = 1.0; // size = 1x - sacp_blend = 1; // edge blend = 1 - sacp_angle = 0; // angle = 0 - - PXM_free(sacpR_image16); // free prior if any - PXM_free(sacpR_info16); - - sacpR_ww = sacp_ww; // setup resized paste image - sacpR_hh = sacp_hh; // (initially 1x, 0 rotation) - sacpR_image16 = PXM_copy(sacp_image16); - sacpR_info16 = PXM_copy(sacp_info16); - - sacp_porg = 0; // no image paste location yet - - CEF->zd = zdialog_new(ZTX("Paste Image"),mWin,Bdone,Bcancel,null); - zdialog_add_widget(CEF->zd,"hbox","hb0","dialog",0,"space=8"); - zdialog_add_widget(CEF->zd,"label","lab1","hb0",dragmess,"space=8"); - zdialog_add_widget(CEF->zd,"check","mymouse","hb0",BmyMouse); - - zdialog_add_widget(CEF->zd,"hbox","hbres","dialog",0,"space=5"); - zdialog_add_widget(CEF->zd,"label","labres","hbres","resize"); - zdialog_add_widget(CEF->zd,"button","+.1%","hbres","+.1%"); - zdialog_add_widget(CEF->zd,"button","+1%","hbres","+1%"); - zdialog_add_widget(CEF->zd,"button","+10%","hbres","+10%"); - zdialog_add_widget(CEF->zd,"button","-.1%","hbres","-.1%"); - zdialog_add_widget(CEF->zd,"button","-1%","hbres","-1%"); - zdialog_add_widget(CEF->zd,"button","-10%","hbres","-10%"); - - zdialog_add_widget(CEF->zd,"hbox","hbang","dialog",0,"space=5"); // rotation v.11.02 - zdialog_add_widget(CEF->zd,"label","labang","hbang",ZTX("angle")); - zdialog_add_widget(CEF->zd,"button","+.1°","hbang","+.1°"); - zdialog_add_widget(CEF->zd,"button","+1°","hbang","+1°"); - zdialog_add_widget(CEF->zd,"button","+10°","hbang","+10°"); - zdialog_add_widget(CEF->zd,"button","-.1°","hbang","-.1°"); - zdialog_add_widget(CEF->zd,"button","-1°","hbang","-1°"); - zdialog_add_widget(CEF->zd,"button","-10°","hbang","-10°"); - - zdialog_add_widget(CEF->zd,"hbox","hbbl","dialog",0,"space=5"); - zdialog_add_widget(CEF->zd,"label","lab2","hbbl","edge blend"); - zdialog_add_widget(CEF->zd,"hscale","blend","hbbl","0|20|0.3|0","expand"); // v.11.06 - - zdialog_help(CEF->zd,"area_copy_paste"); // zdialog help topic v.11.08 - zdialog_run(CEF->zd,select_paste_dialog_event,"80/20"); // v.11.07 - - takeMouse(CEF->zd,select_paste_mousefunc,0); // connect mouse function - zdialog_stuff(CEF->zd,"mymouse",1); // v.11.03 - - return; -} - - -// Dialog event and completion callback function -// Get dialog values and convert image. When done, commit edited image -// (with pasted area) and set up a new select area for the pasted area, -// allowing further editing of the area. - -int select_paste_dialog_event(zdialog *zd, cchar *event) -{ - void select_paste_mousefunc(); - void select_paste_pixmap(); - void select_paste_makearea(); - - int mymouse, ww, hh; - PXM *pxm_temp; - - if (zd->zstat) // dialog completed - { - freeMouse(); // disconnect mouse - - if (zd->zstat != 1 || ! sacp_porg) { // cancel paste - edit_cancel(EFpaste); // cancel edit, restore image - sa_unselect(); - return 0; - } - - edit_done(EFpaste); // commit the edit (pasted image) - select_paste_makearea(); // make equivalent select area - PXM_free(sacpR_image16); // free memory - PXM_free(sacpR_info16); - return 0; - } - - if (strEqu(event,"mymouse")) { // toggle mouse capture v.10.12 - zdialog_fetch(zd,"mymouse",mymouse); - if (mymouse) takeMouse(zd,select_paste_mousefunc,0); - else freeMouse(); - return 0; - } - - if (strstr(event,"%") || strstr(event,"°")) // new size or angle - { - if (strEqu(event,"+.1%")) sacp_resize *= 1.001; - if (strEqu(event,"+1%")) sacp_resize *= 1.01; - if (strEqu(event,"+10%")) sacp_resize *= 1.10; - if (strEqu(event,"-.1%")) sacp_resize *= 0.999001; - if (strEqu(event,"-1%")) sacp_resize *= 0.990099; - if (strEqu(event,"-10%")) sacp_resize *= 0.909091; // -10% is really 1.0/1.10 - - if (strEqu(event,"+.1°")) sacp_angle += 0.1; // rotation v.11.02 - if (strEqu(event,"+1°")) sacp_angle += 1.0; - if (strEqu(event,"+10°")) sacp_angle += 10.0; - if (strEqu(event,"-.1°")) sacp_angle -= 0.1; - if (strEqu(event,"-1°")) sacp_angle -= 1.0; - if (strEqu(event,"-10°")) sacp_angle -= 10.0; - - PXM_free(sacpR_image16); // free prior if any - PXM_free(sacpR_info16); - - ww = sacp_resize * sacp_ww; // new size - hh = sacp_resize * sacp_hh; - - pxm_temp = PXM_rescale(sacp_image16,ww,hh); // resized area image - sacpR_image16 = PXM_rotate(pxm_temp,sacp_angle); // rotated area image - PXM_free(pxm_temp); - - pxm_temp = PXM_rescale(sacp_info16,ww,hh); // resized area info - sacpR_info16 = PXM_rotate(pxm_temp,sacp_angle); // rotated/resized area info - PXM_free(pxm_temp); - - sacpR_ww = sacpR_image16->ww; // size after resize/rotate - sacpR_hh = sacpR_image16->hh; - - select_paste_pixmap(); // copy onto target image - } - - if (strEqu(event,"blend") && sacp_porg) { - zdialog_fetch(zd,"blend",sacp_blend); // new edge blend distance - select_paste_pixmap(); // copy onto target image - } - - CEF->Fmod = 1; // image is modified - mwpaint2(); - return 0; -} - - -// convert the pasted image area into an equivalent select area by mouse - -void select_paste_makearea() -{ - int cc, ii; - int px1, py1, px2, py2; - uint16 *pix2; - - sa_unselect(); // unselect old area - - cc = Fww * Fhh * sizeof(uint16); - sa_pixmap = (uint16 *) zmalloc(cc,"sa_paste"); // pixel map for new area - memset(sa_pixmap,0,cc); - - for (py1 = 0; py1 < sacpR_hh; py1++) // map non-transparent pixels - for (px1 = 0; px1 < sacpR_ww; px1++) // into sa_pixmap[] - { - pix2 = PXMpix(sacpR_info16,px1,py1); // opacity and edge distance - if (pix2[0] == 0) continue; // transparent - px2 = px1 + sacp_orgx; - py2 = py1 + sacp_orgy; - if (px2 < 0 || px2 > Fww-1) continue; // parts may be beyond edges - if (py2 < 0 || py2 > Fhh-1) continue; - ii = py2 * Fww + px2; - sa_pixmap[ii] = 1; - } - - sa_stat = 1; - sa_mode = 6; // equivalent select-mouse area - sa_fww = Fww; // v.11.08 - sa_fhh = Fhh; - sa_finish_auto(); // v.11.04 - sa_show(1); - return; -} - - -// mouse function - follow mouse drags and move pasted area accordingly - -void select_paste_mousefunc() -{ - void select_paste_pixmap(); - - int mx1, my1, mx2, my2; - static int mdx0, mdy0, mdx1, mdy1; - - if (LMclick) { // left mouse click - LMclick = 0; - sacp_orgx = Mxclick - sacpR_ww / 2; // position image at mouse v.10.11 - sacp_orgy = Myclick - sacpR_hh / 2; - select_paste_pixmap(); - CEF->Fmod = 1; // image is modified - } - - if (! sacp_porg) return; // no select area paste yet - - if (Mxposn < sacp_orgx || Mxposn > sacp_orgx + sacpR_ww || // mouse outside select area - Myposn < sacp_orgy || Myposn > sacp_orgy + sacpR_hh) - gdk_window_set_cursor(drWin->window,0); // set normal cursor v.11.03 - else - gdk_window_set_cursor(drWin->window,dragcursor); // set drag cursor v.11.03 - - if (Mxdrag + Mydrag == 0) return; // no drag underway - - if (Mxdown != mdx0 || Mydown != mdy0) { // new drag initiated - mdx0 = mdx1 = Mxdown; - mdy0 = mdy1 = Mydown; - } - - mx1 = mdx1; // drag start - my1 = mdy1; - mx2 = Mxdrag; // drag position - my2 = Mydrag; - mdx1 = mx2; // next drag start - mdy1 = my2; - - sacp_orgx += (mx2 - mx1); // move position of select area - sacp_orgy += (my2 - my1); // by mouse drag amount - select_paste_pixmap(); // re-copy area to new position - CEF->Fmod = 1; // image is modified - - return; -} - - -// copy select area into edit image, starting at sacp_orgx/y - -void select_paste_pixmap() // overhauled v.11.02 -{ - int px1, py1, px3, py3, opac, dist; - uint16 *pix1, *pix3; - double f1, f2; - - if (sacp_porg) // prior area overlap rectangle - { - for (py1 = 0; py1 < sacp_phh; py1++) // restore original image pixels v.10.11 - for (px1 = 0; px1 < sacp_pww; px1++) - { - px3 = px1 + sacp_porgx; - py3 = py1 + sacp_porgy; - if (px3 < 0 || px3 >= E3ww) continue; // parts may be beyond edges - if (py3 < 0 || py3 >= E3hh) continue; - pix1 = PXMpix(E1pxm16,px3,py3); - pix3 = PXMpix(E3pxm16,px3,py3); - pix3[0] = pix1[0]; - pix3[1] = pix1[1]; - pix3[2] = pix1[2]; - } - } - - for (py1 = 0; py1 < sacpR_hh; py1++) // copy paste area pixels to new - for (px1 = 0; px1 < sacpR_ww; px1++) // image overlap rectangle - { - pix1 = PXMpix(sacpR_info16,px1,py1); // opacity and edge distance - opac = pix1[0]; - dist = pix1[1]; - if (opac == 0) continue; // skip transparent pixel - px3 = px1 + sacp_orgx; - py3 = py1 + sacp_orgy; - if (px3 < 0 || px3 >= E3ww) continue; // parts may be beyond edges - if (py3 < 0 || py3 >= E3hh) continue; - - pix1 = PXMpix(sacpR_image16,px1,py1); // paste image pixel - pix3 = PXMpix(E3pxm16,px3,py3); // target image pixel - if (dist > sacp_blend) f1 = 1.0; // minor bugfix v.11.06 - else f1 = 1.0 * dist / sacp_blend; // opacity reduction from edge blend - f1 = f1 * opac / 65535.0; // opacity reduction from resize/rescale - f2 = 1.0 - f1; - pix3[0] = f1 * pix1[0] + f2 * pix3[0]; // blend paste and target images - pix3[1] = f1 * pix1[1] + f2 * pix3[1]; - pix3[2] = f1 * pix1[2] + f2 * pix3[2]; - } - - mwpaint3(sacp_porgx,sacp_porgy,sacp_pww,sacp_phh); // update window for old overlap area - mwpaint3(sacp_orgx,sacp_orgy,sacpR_ww,sacpR_hh); // update window for new overlap area - - sacp_porgx = sacp_orgx; // remember location for next call - sacp_porgy = sacp_orgy; - sacp_pww = sacpR_ww; - sacp_phh = sacpR_hh; - sacp_porg = 1; - return; -} - - -/************************************************************************** - select area load from file and save to file functions v.9.9 -***************************************************************************/ - -// Load a select area from a disk file and paste into current image. - -void m_select_open(GtkWidget *, cchar *) -{ - char *pfile1, *pfile2, *pp; - - zfuncs::F1_help_topic = "area_open_save"; // v.10.8 - - pp = zgetfile1(ZTX("load select area from a file"),"open",saved_areas_dirk); - if (! pp) return; - - pfile1 = strdupz(pp,8,"select_open"); - zfree(pp); - pp = strrchr(pfile1,'/'); - if (pp) pp = strrchr(pp,'.'); - if (pp) strcpy(pp,".tiff"); - else strcat(pfile1,".tiff"); - - pfile2 = strdupz(pfile1,0,"select_open"); - pp = strrchr(pfile2,'.'); - strcpy(pp,".info"); - - PXM_free(sacp_image16); // free prior if any - PXM_free(sacp_info16); - - sacp_image16 = TIFFread(pfile1); // .tiff file --> image PXM - if (! sacp_image16) goto fail; - - sacp_info16 = TIFFread(pfile2); // .info file --> info PXM - if (! sacp_info16) goto fail; - - zfree(pfile1); - zfree(pfile2); - - sacp_ww = sacp_image16->ww; // paste into current image - sacp_hh = sacp_image16->hh; - m_select_paste(0,0); - return; - -fail: - zfree(pfile1); - zfree(pfile2); - zmessageACK(mWin,ZTX("cannot open .tiff and .info files")); - return; -} - - -// save a select area as a disk file - -void m_select_save(GtkWidget *, cchar *) -{ - char *pfile1, *pfile2, *pp; - - zfuncs::F1_help_topic = "area_open_save"; // v.10.11 - - if (sa_mode == 7) return; // a whole image area v.11.01 - if (! Factivearea) sa_finish(); // finish select area if not already - if (! Factivearea) return; // v.11.06.1 - m_select_copy(0,0); // copy select area to memory - if (! sacp_image16) return; - - pp = zgetfile1(ZTX("save select area to a file"),"save",saved_areas_dirk); - if (! pp) return; - - pfile1 = strdupz(pp,8,"select_save"); - zfree(pp); - pp = strrchr(pfile1,'/'); - if (pp) pp = strrchr(pp,'.'); - if (pp) strcpy(pp,".tiff"); - else strcat(pfile1,".tiff"); - - pfile2 = strdupz(pfile1,0,"select_save"); - pp = strrchr(pfile2,'.'); - strcpy(pp,".info"); - - TIFFwrite(sacp_image16,pfile1); // image PXM --> .tiff file - TIFFwrite(sacp_info16,pfile2); // info PXM --> .info file - - return; -} - - -/**************************************************************************/ - -// Select the whole image as an area. -// Set "edge distance" 1 to 255 from pixel or RGB color brightness. -// Set "blend width" to 255 -// Edit function coefficient = edge distance / blend width. - -spldat * select_whole_image_curve; - -void m_select_whole_image(GtkWidget *, cchar *) // new v.11.01 -{ - int select_whole_image_event(zdialog *, cchar *event); // dialog event and completion func - void select_whole_image_curve_update(int spc); // curve update callback function - - cchar *title = ZTX("Select Whole Image"); - cchar *legend = ZTX("Edit Function Amplifier"); - - zfuncs::F1_help_topic = "select_whole_image"; - - if (! curr_file) return; // no image - if (zdsela) return; // select dialog already active - if (Fpreview) edit_fullsize(); // use full-size image - -/*** - Edit Function Amplifier - ------------------------------------------ - | | - | | - | curve drawing area | - | | - | | - ------------------------------------------ - darker areas lighter areas - - [+++] [---] [+ -] [- +] [+-+] [-+-] - (o) Brightness (o) Red (o) Green (o) Blue - Curve File: [ Open ] [ Save ] - [ Done ] -***/ - - zdsela = zdialog_new(title,mWin,Bdone,null); - - zdialog_add_widget(zdsela,"label","labt","dialog",legend); - zdialog_add_widget(zdsela,"frame","fr1","dialog",0,"expand"); - zdialog_add_widget(zdsela,"hbox","hba","dialog"); - zdialog_add_widget(zdsela,"label","labda","hba",Bdarker,"space=5"); - zdialog_add_widget(zdsela,"label","space","hba",0,"expand"); - zdialog_add_widget(zdsela,"label","labba","hba",Blighter,"space=5"); - zdialog_add_widget(zdsela,"hbox","hbb","dialog",0,"space=5"); - zdialog_add_widget(zdsela,"button","b +++","hbb","+++"); - zdialog_add_widget(zdsela,"button","b ---","hbb","‒ ‒ ‒"); - zdialog_add_widget(zdsela,"button","b +-", "hbb"," + ‒ "); - zdialog_add_widget(zdsela,"button","b -+", "hbb"," ‒ + "); - zdialog_add_widget(zdsela,"button","b +-+","hbb","+ ‒ +"); - zdialog_add_widget(zdsela,"button","b -+-","hbb","‒ + ‒"); - - zdialog_add_widget(zdsela,"hbox","hbbr","dialog",0,"space=5"); - zdialog_add_widget(zdsela,"radio","bright","hbbr",Bbrightness,"space=5"); - zdialog_add_widget(zdsela,"radio","red","hbbr",Bred,"space=5"); - zdialog_add_widget(zdsela,"radio","green","hbbr",Bgreen,"space=5"); - zdialog_add_widget(zdsela,"radio","blue","hbbr",Bblue,"space=5"); - - zdialog_add_widget(zdsela,"hbox","hbcf","dialog",0,"space=5"); - zdialog_add_widget(zdsela,"label","labcf","hbcf",Bcurvefile,"space=5"); - zdialog_add_widget(zdsela,"button","load","hbcf",Bopen,"space=5"); - zdialog_add_widget(zdsela,"button","save","hbcf",Bsave,"space=5"); - - GtkWidget *frame = zdialog_widget(zdsela,"fr1"); // setup for curve editing - spldat *sd = splcurve_init(frame,select_whole_image_curve_update); // v.11.01 - select_whole_image_curve = sd; - - sd->Nspc = 1; - sd->vert[0] = 0; - sd->nap[0] = 3; // initial curve anchor points - sd->apx[0][0] = 0.01; - sd->apy[0][0] = 0.5; - sd->apx[0][1] = 0.50; - sd->apy[0][1] = 0.5; - sd->apx[0][2] = 0.99; - sd->apy[0][2] = 0.5; - splcurve_generate(sd,0); // generate curve data - - zdialog_stuff(zdsela,"bright",1); - zdialog_stuff(zdsela,"red",0); - zdialog_stuff(zdsela,"green",0); - zdialog_stuff(zdsela,"blue",0); - zdialog_stuff(zdsela,"check",0); - - sa_unselect(); // unselect current area if any - - zdialog_resize(zdsela,0,360); - zdialog_help(zdsela,"select_whole_image"); // zdialog help topic v.11.08 - zdialog_run(zdsela,select_whole_image_event,"80/20"); // run dialog - parallel v.11.07 - select_whole_image_event(zdsela,"init"); // initialize default params - return; -} - - -// dialog event and completion function - -int select_whole_image_event(zdialog *zd, cchar *event) -{ - int ii, kk, cc, base, pixbright, pixdist; - double px, py, xval, yval; - uint8 *pixel; - spldat *sd = select_whole_image_curve; - - if (zd->zstat) { // done, kill dialog - zdialog_free(zdsela); - zfree(sd); // free curve edit memory - return 0; - } - - if (! sa_stat) - { - cc = Fww * Fhh * sizeof(uint16); // allocate sa_pixmap[] for new area - sa_pixmap = (uint16 *) zmalloc(cc,"sa_select_image"); - - sa_minx = 0; // enclosing rectangle - sa_maxx = Fww; - sa_miny = 0; - sa_maxy = Fhh; - - sa_Npixel = Fww * Fhh; - sa_stat = 3; // area status = complete - sa_mode = 7; // area mode = whole image - sa_calced = 1; // edge calculation complete - sa_blend = 255; // "blend width" = 255 - sa_fww = Fww; // valid image dimensions v.11.08 - sa_fhh = Fhh; - Factivearea = 1; // area is active - } - - if (strEqu(event,"load")) { // load saved curve v.11.02 - splcurve_load(sd); - if (CEF && CEF->zd) zdialog_send_event(CEF->zd,"blendwidth"); // notify edit dialog - return 0; - } - - if (strEqu(event,"save")) { // save curve to file v.11.02 - splcurve_save(sd); - return 0; - } - - base = 0; - zdialog_fetch(zd,"bright",ii); // set brightness or color to be used - if (ii) base = 1; - zdialog_fetch(zd,"red",ii); - if (ii) base = 2; - zdialog_fetch(zd,"green",ii); - if (ii) base = 3; - zdialog_fetch(zd,"blue",ii); - if (ii) base = 4; - if (! base) return 0; - - if (strnEqu(event,"b ",2)) { // button to move entire curve - for (ii = 0; ii < sd->nap[0]; ii++) { - px = sd->apx[0][ii]; - py = sd->apy[0][ii]; - if (strEqu(event,"b +++")) py += 0.1; - if (strEqu(event,"b ---")) py -= 0.1; - if (strEqu(event,"b +-")) py += 0.1 - 0.2 * px; - if (strEqu(event,"b -+")) py -= 0.1 - 0.2 * px; - if (strEqu(event,"b +-+")) py -= 0.05 - 0.2 * fabs(px-0.5); - if (strEqu(event,"b -+-")) py += 0.05 - 0.2 * fabs(px-0.5); - if (py > 1) py = 1; - if (py < 0) py = 0; - sd->apy[0][ii] = py; - } - } - - splcurve_generate(sd,0); // regenerate the curve - splcurve_draw(0,0,sd); - - pixel = (uint8 *) Fpxm8->bmp; - - for (ii = 0; ii < Fww * Fhh; ii++) // loop all pixels - { - pixbright = pixel[0] + pixel[1] + pixel[2] + 1; // brightness of pixel, 1 - 766 - if (base == 1) pixbright = pixbright / 3; // brightness, 0 - 255 bugfix v.11.01.2 - else if (base == 2) pixbright = 255 * pixel[0] / pixbright; // red part: 0 - 255 = 100% red - else if (base == 3) pixbright = 255 * pixel[1] / pixbright; // green part - else if (base == 4) pixbright = 255 * pixel[2] / pixbright; // blue part - xval = pixbright / 256.0; // curve x-value, 0 to 0.999 - kk = 1000 * xval; // speedup v.11.06 - if (kk > 999) kk = 999; - yval = sd->yval[0][kk]; - pixdist = 255 * yval; // pixel "edge distance" 0 to 255 - sa_pixmap[ii] = pixdist | 1; // avoid 0 (pixel outside area) - pixel += 3; - } - - if (CEF && CEF->zd) zdialog_send_event(CEF->zd,"blendwidth"); // notify edit dialog - - return 0; -} - - -// this function is called when curve is edited using mouse - -void select_whole_image_curve_update(int) -{ - select_whole_image_event(zdsela,"edit"); - return; -} - - -/**************************************************************************/ - -// select area and edit in parallel -// current edit function is applied to areas painted with the mouse -// mouse can be weak or strong, and edits are applied incrementally -// method: -// entire image is a select area with all pixel edge distance = 0 (outside area) -// blendwidth = 10000 -// pixels painted with mouse have increasing edge distance to amplify edits - -int select_edit_radius; -int select_edit_cpower; -int select_edit_epower; - -void m_select_edit(GtkWidget *, cchar *) // menu function v.11.02 -{ - int select_edit_dialog_event(zdialog *, cchar *event); // dialog event function - void select_edit_mousefunc(); // mouse function - - cchar *title = ZTX("Select Area for Edits"); - cchar *helptext = ZTX("Press F1 for help"); - int cc; - - zfuncs::F1_help_topic = "select_edit"; - - if (! curr_file) return; // no image - if (zdsela) return; // select area already active - if (Fpreview) edit_fullsize(); // use full-size image - - if (! Fpxm16) { // create Fpxm16 if not already - mutex_lock(&Fpixmap_lock); - Fpxm16 = f_load(curr_file,16); - mutex_unlock(&Fpixmap_lock); - if (! Fpxm16) return; - } - -/*** - ____________________________________________ - | Press F1 for help | - | | - | mouse radius [___|v] | - | power: center [___|v] edge [___|v] | - | [x] my mouse [reset area] | - | [done] | - |____________________________________________| - -***/ - - zdsela = zdialog_new(title,mWin,Bdone,null); - zdialog_add_widget(zdsela,"label","labhelp","dialog",helptext,"space=5"); - zdialog_add_widget(zdsela,"hbox","hbr","dialog",0,"space=3"); - zdialog_add_widget(zdsela,"label","labr","hbr",ZTX("mouse radius"),"space=5"); - zdialog_add_widget(zdsela,"spin","radius","hbr","2|500|1|50"); - zdialog_add_widget(zdsela,"hbox","hbt","dialog",0,"space=3"); - zdialog_add_widget(zdsela,"label","labtc","hbt",ZTX("power: center"),"space=5"); - zdialog_add_widget(zdsela,"spin","center","hbt","0|100|1|50"); - zdialog_add_widget(zdsela,"label","labte","hbt",ZTX("edge"),"space=5"); - zdialog_add_widget(zdsela,"spin","edge","hbt","0|100|1|0"); - zdialog_add_widget(zdsela,"hbox","hbr","dialog",0,"space=5"); - zdialog_add_widget(zdsela,"check","mymouse","hbr",BmyMouse,"space=5"); - zdialog_add_widget(zdsela,"button","reset","hbr",ZTX("reset area"),"space=20"); - - select_edit_radius = 50; - select_edit_cpower = 50; - select_edit_epower = 0; - - sa_unselect(); // unselect current area if any - cc = Fww * Fhh * sizeof(uint16); // allocate sa_pixmap[] for new area - sa_pixmap = (uint16 *) zmalloc(cc,"sa_select_edit"); - memset(sa_pixmap,0,cc); // edge distance = 0 for all pixels - - sa_minx = 0; // enclosing rectangle - sa_maxx = Fww; - sa_miny = 0; - sa_maxy = Fhh; - - sa_Npixel = Fww * Fhh; - sa_stat = 3; // area status = complete - sa_mode = 7; // area mode = whole image - sa_calced = 1; // edge calculation complete - sa_blend = 10000; // "blend width" - sa_fww = Fww; // valid image dimensions v.11.08 - sa_fhh = Fhh; - Factivearea = 1; // area is active - - zdialog_help(zdsela,"select_edit"); // zdialog help topic v.11.08 - zdialog_run(zdsela,select_edit_dialog_event,"80/20"); // run dialog - parallel v.11.07 - return; -} - - -// tailor whole image area to increase edit power for pixels within the mouse radius -// sa_pixmap[*] = 0 = never touched by mouse -// = 1 = minimum edit power (barely painted) -// = sa_blend = maximum edit power (edit fully applied) - -int select_edit_dialog_event(zdialog *zd, cchar *event) -{ - void select_edit_mousefunc(); // mouse function - int cc, mymouse; - - if (! Factivearea) return 1; // area gone v.11.06.1 - - if (zd->zstat) // done or cancel - { - freeMouse(); // disconnect mouse function - zdialog_free(zdsela); // kill dialog - sa_unselect(); // unselect area - return 0; - } - - if (strEqu(event,"mymouse")) { // toggle mouse capture - zdialog_fetch(zd,"mymouse",mymouse); - if (mymouse) { - if (! CEF) { - zmessageACK(mWin,ZTX("start edit function first")); // no edit function active - zdialog_stuff(zd,"mymouse",0); - return 1; - } - takeMouse(zd,select_edit_mousefunc,0); // connect mouse function - } - else freeMouse(); // disconnect mouse - } - - if (strEqu(event,"radius")) - zdialog_fetch(zd,"radius",select_edit_radius); // set mouse radius - - if (strEqu(event,"center")) - zdialog_fetch(zd,"center",select_edit_cpower); // set mouse center power - - if (strEqu(event,"edge")) - zdialog_fetch(zd,"edge",select_edit_epower); // set mouse edge power - - if (strEqu(event,"reset")) { - sa_unselect(); // unselect current area if any - cc = Fww * Fhh * sizeof(uint16); // allocate sa_pixmap[] for new area - sa_pixmap = (uint16 *) zmalloc(cc,"sa_select_edit"); - memset(sa_pixmap,0,cc); // edge distance = 0 for all pixels - - sa_minx = 0; // enclosing rectangle - sa_maxx = Fww; - sa_miny = 0; - sa_maxy = Fhh; - - sa_Npixel = Fww * Fhh; - sa_stat = 3; // area status = complete - sa_mode = 7; // area mode = whole image - sa_calced = 1; // edge calculation complete - sa_blend = 10000; // "blend width" - sa_fww = Fww; // valid image dimensions v.11.08 - sa_fhh = Fhh; - Factivearea = 1; // area is active - } - - return 1; -} - - -// mouse function - adjust edit strength for areas within mouse radius -// "edge distance" is increased for more strength, decreased for less - -void select_edit_mousefunc() -{ - int ii, cc, px, py, rx, ry; - int radius, radius2, cpower, epower; - double rad, rad2, power; // v.11.06 - - if (! CEF) { // no active edit - freeMouse(); - return; - } - - if (! sa_stat) // area gone? v.11.07 - { - cc = Fww * Fhh * sizeof(uint16); // allocate sa_pixmap[] for new area - sa_pixmap = (uint16 *) zmalloc(cc,"sa_select_edit"); - memset(sa_pixmap,0,cc); // clear to zeros - - sa_minx = 0; // enclosing rectangle - sa_maxx = Fww; - sa_miny = 0; - sa_maxy = Fhh; - - sa_Npixel = Fww * Fhh; - sa_stat = 3; // area status = complete - sa_mode = 7; // area mode = whole image - sa_calced = 1; // edge calculation complete - sa_blend = 10000; // "blend width" - sa_fww = Fww; // valid image dimensions v.11.08 - sa_fhh = Fhh; - Factivearea = 1; // area is active - } - - radius = select_edit_radius; // pixel selection radius - radius2 = radius * radius; - cpower = select_edit_cpower; - epower = select_edit_epower; - - toparcx = Mxposn - radius; // draw mouse outline circle - toparcy = Myposn - radius; - toparcw = toparch = 2 * radius; - Ftoparc = 1; - paint_toparc(3); - - if (LMclick || RMclick) // mouse click - LMclick = RMclick = 0; - - if (Mbutton != 1 && Mbutton != 3) // button released - return; - - for (rx = -radius; rx <= radius; rx++) // loop every pixel in radius - for (ry = -radius; ry <= radius; ry++) - { - rad2 = rx * rx + ry * ry; - if (rad2 > radius2) continue; // outside radius - px = Mxposn + rx; - py = Myposn + ry; - if (px < 0 || px > Fww-1) continue; // off the image edge - if (py < 0 || py > Fhh-1) continue; - - ii = Fww * py + px; - rad = sqrt(rad2); - power = cpower + rad / radius * (epower - cpower); // power at pixel radius v.11.06 - - if (Mbutton == 1) // left mouse button - { // increase edit power - sa_pixmap[ii] += power; - if (sa_pixmap[ii] > sa_blend) sa_pixmap[ii] = sa_blend; - } - - if (Mbutton == 3) // right mouse button - { // weaken edit power - if (sa_pixmap[ii] <= power) sa_pixmap[ii] = 0; - else sa_pixmap[ii] -= power; - } - } - - sa_minx = Mxposn - radius; // set temp. smaller area around mouse - if (sa_minx < 0) sa_minx = 0; // speedup v.11.06 - sa_maxx = Mxposn + radius; - if (sa_maxx > Fww) sa_maxx = Fww; - sa_miny = Myposn - radius; - if (sa_miny < 0) sa_miny = 0; - sa_maxy = Myposn + radius; - if (sa_maxy > Fhh) sa_maxy = Fhh; - sa_Npixel = (sa_maxx - sa_minx) * (sa_maxy - sa_miny); - - paint_toparc(2); // remove mouse outline - - zdialog_send_event(CEF->zd,"blendwidth"); // notify edit dialog - - Ftoparc = 1; // restore mouse outline - paint_toparc(3); - - sa_minx = 0; // restore whole image area v.11.06 - sa_maxx = Fww; - sa_miny = 0; - sa_maxy = Fhh; - sa_Npixel = Fww * Fhh; - - return; -} - - - diff -Nru fotoxx-11.11.1/fotoxx_art.cc fotoxx-12.01.2/fotoxx_art.cc --- fotoxx-11.11.1/fotoxx_art.cc 2011-11-05 05:30:36.000000000 +0000 +++ fotoxx-12.01.2/fotoxx_art.cc 1970-01-01 00:00:00.000000000 +0000 @@ -1,1805 +0,0 @@ -/************************************************************************** - - Fotoxx edit photos and manage collections - - Copyright 2007 2008 2009 2010 2011 Michael Cornelison - Source URL: http://kornelix.squarespace.com/fotoxx - Contact: kornelix2@googlemail.com - - 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 http://www.gnu.org/licenses/. - -***************************************************************************/ - -#define EX extern // enable extern declarations -#include "fotoxx.h" - - -/************************************************************************** - - Fotoxx image edit - arty transformation functions - -***************************************************************************/ - - -// image color-depth reduction - -int colordep_depth = 16; // bits per RGB color - -editfunc EFcolordep; - - -void m_colordep(GtkWidget *, cchar *) -{ - int colordep_dialog_event(zdialog *zd, cchar *event); - void * colordep_thread(void *); - - cchar *colmess = ZTX("Set color depth to 1-16 bits"); - - zfuncs::F1_help_topic = "color_depth"; // v.10.8 - - EFcolordep.funcname = "color-depth"; - EFcolordep.Fprev = 1; // use preview - EFcolordep.Farea = 2; // select area usable - EFcolordep.threadfunc = colordep_thread; // thread function - if (! edit_setup(EFcolordep)) return; // setup edit - - zdialog *zd = zdialog_new(ZTX("Set Color Depth"),mWin,Bdone,Bcancel,null); - EFcolordep.zd = zd; - - zdialog_add_widget(zd,"label","lab1","dialog",colmess,"space=5"); - zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=10"); - zdialog_add_widget(zd,"spin","colors","hb1","1|16|1|16","space=5"); - - zdialog_help(zd,"color_depth"); // zdialog help topic v.11.08 - zdialog_run(zd,colordep_dialog_event,"-10/20"); // run dialog, parallel v.11.07 - - colordep_depth = 16; - return; -} - - -// dialog event and completion callback function - -int colordep_dialog_event(zdialog *zd, cchar *event) -{ - if (zd->zstat) // dialog complete - { - if (zd->zstat == 1) edit_done(EFcolordep); - else edit_cancel(EFcolordep); - return 0; - } - - if (strEqu(event,"undo")) edit_undo(); // v.10.2 - if (strEqu(event,"redo")) edit_redo(); // v.10.3 - if (strEqu(event,"blendwidth")) signal_thread(); // v.10.3 - - if (strEqu(event,"colors")) { - zdialog_fetch(zd,"colors",colordep_depth); - signal_thread(); - } - - return 0; -} - - -// image color depth thread function - -void * colordep_thread(void *) -{ - int ii, px, py, rgb, dist = 0; - uint16 m1, m2, val1, val3; - uint16 *pix1, *pix3; - double fmag, f1, f2; - - while (true) - { - thread_idle_loop(); // wait for work or exit request - - m1 = 0xFFFF << (16 - colordep_depth); // 5 > 1111100000000000 - m2 = 0x8000 >> colordep_depth; // 5 > 0000010000000000 - - fmag = 65535.0 / m1; - - for (py = 0; py < E3hh; py++) - for (px = 0; px < E3ww; px++) - { - if (Factivearea) { // select area active - ii = py * Fww + px; - dist = sa_pixmap[ii]; // distance from edge - if (! dist) continue; // outside pixel - } - - pix1 = PXMpix(E1pxm16,px,py); // input pixel - pix3 = PXMpix(E3pxm16,px,py); // output pixel - - for (rgb = 0; rgb < 3; rgb++) - { - val1 = pix1[rgb]; - if (val1 < m1) val3 = (val1 + m2) & m1; - else val3 = m1; - val3 = uint(val3 * fmag); - - if (Factivearea && dist < sa_blend) { // select area is active, - f2 = 1.0 * dist / sa_blend; // blend changes over sa_blend - f1 = 1.0 - f2; - val3 = int(f1 * val1 + f2 * val3); - } - - pix3[rgb] = val3; - } - } - - CEF->Fmod = 1; - mwpaint2(); // update window - } - - return 0; // not executed, stop g++ warning -} - - -/**************************************************************************/ - -// convert image to simulate a drawing - -int draw_contrast; -int draw_threshold; -int draw_pixcon; -int draw_reverse; -double draw_trfunc[256]; -double draw_pixcon3; -uint8 *draw_pixcon_map = 0; - -editfunc EFdraw; - - -void m_draw(GtkWidget *, cchar *) -{ - int draw_dialog_event(zdialog* zd, cchar *event); - void * draw_thread(void *); - - cchar *title = ZTX("Simulate Drawing"); - uint16 *pix1, *pix2; - int ii, px, py, qx, qy; - int red, green, blue, con, maxcon; - - zfuncs::F1_help_topic = "drawing"; // v.10.8 - - EFdraw.funcname = "drawing"; - EFdraw.Farea = 2; // select area usable - EFdraw.threadfunc = draw_thread; // thread function - if (! edit_setup(EFdraw)) return; // setup edit - - draw_pixcon_map = (uint8 *) zmalloc(E1ww*E1hh,"draw"); // set up pixel contrast map - memset(draw_pixcon_map,0,E1ww*E1hh); - - for (py = 1; py < E1hh-1; py++) // scan image pixels - for (px = 1; px < E1ww-1; px++) - { - pix1 = PXMpix(E1pxm16,px,py); // pixel at (px,py) - red = pix1[0]; // pixel RGB levels - green = pix1[1]; - blue = pix1[2]; - maxcon = 0; - - for (qy = py-1; qy < py+2; qy++) // loop 3x3 block of neighbor - for (qx = px-1; qx < px+2; qx++) // pixels around pix1 - { - pix2 = PXMpix(E1pxm16,qx,qy); // find max. contrast with - con = abs(red-pix2[0]) + abs(green-pix2[1]) + abs(blue-pix2[2]); // neighbor pixel - if (con > maxcon) maxcon = con; - } - - ii = py * E1ww + px; - draw_pixcon_map[ii] = (maxcon/3) >> 8; // contrast for (px,py) 0-255 - } - - zdialog *zd = zdialog_new(title,mWin,Bdone,Bcancel,null); - EFdraw.zd = zd; - - zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=10"); - zdialog_add_widget(zd,"vbox","vb1","hb1",0,"homog"); - zdialog_add_widget(zd,"vbox","vb2","hb1",0,"homog|expand"); - zdialog_add_widget(zd,"label","lab1","vb1",ZTX("contrast")); - zdialog_add_widget(zd,"label","lab2","vb1",Bthresh); - zdialog_add_widget(zd,"label","lab3","vb1",ZTX("outlines")); - zdialog_add_widget(zd,"hscale","contrast","vb2","0|100|1|0","expand"); - zdialog_add_widget(zd,"hscale","threshold","vb2","0|100|1|0","expand"); - zdialog_add_widget(zd,"hscale","pixcon","vb2","0|255|1|0","expand"); - zdialog_add_widget(zd,"hbox","hb4","dialog"); - zdialog_add_widget(zd,"radio","pencil","hb4",ZTX("pencil"),"space=10"); - zdialog_add_widget(zd,"radio","chalk","hb4",ZTX("chalk"),"space=10"); - - zdialog_resize(zd,300,0); - zdialog_help(zd,"drawing"); // zdialog help topic v.11.08 - zdialog_run(zd,draw_dialog_event,"-10/20"); // run dialog, parallel v.11.07 - - return; -} - - -// dialog event and completion callback function - -int draw_dialog_event(zdialog *zd, cchar *event) // draw dialog event function -{ - if (zd->zstat) // dialog complete - { - if (zd->zstat == 1) edit_done(EFdraw); - else edit_cancel(EFdraw); - zfree(draw_pixcon_map); - return 0; - } - - if (strEqu(event,"undo")) edit_undo(); // v.10.2 - if (strEqu(event,"redo")) edit_redo(); // v.10.3 - if (strEqu(event,"blendwidth")) signal_thread(); // v.10.3 - - if (strcmpv(event,"contrast","threshold","pixcon","chalk",null)) - { - zdialog_fetch(zd,"contrast",draw_contrast); // get slider values - zdialog_fetch(zd,"threshold",draw_threshold); - zdialog_fetch(zd,"pixcon",draw_pixcon); - zdialog_fetch(zd,"chalk",draw_reverse); - signal_thread(); // trigger update thread - } - - return 1; -} - - -// thread function - use multiple working threads - -void * draw_thread(void *) -{ - void * draw_wthread(void *arg); - - int ii; - double threshold, contrast, trf; - - while (true) - { - thread_idle_loop(); // wait for work or exit request - - threshold = 0.01 * draw_threshold; // range 0 to 1 - contrast = 0.01 * draw_contrast; // range 0 to 1 - - for (ii = 0; ii < 256; ii++) // brightness transfer function - { - trf = 1.0 - 0.003906 * (256 - ii) * contrast; // ramp-up from 0-1 to 1 - if (ii < 256 * threshold) trf = 0; // 0 if below threshold - draw_trfunc[ii] = trf; - } - - for (ii = 0; ii < Nwt; ii++) // start worker threads - start_wthread(draw_wthread,&wtnx[ii]); - wait_wthreads(); // wait for completion - - CEF->Fmod = 1; - mwpaint2(); // update window - } - - return 0; // not executed, stop g++ warning -} - - -void * draw_wthread(void *arg) // worker thread function -{ - void draw_1pix(int px, int py); - - int index = *((int *) (arg)); - int px, py; - double pixcon; - - pixcon = draw_pixcon / 255.0; // 0-1 linear ramp - draw_pixcon3 = 255 * pixcon * pixcon * pixcon; // 0-255 cubic ramp - - for (py = index+1; py < E1hh-1; py += Nwt) // process all pixels - for (px = 1; px < E1ww-1; px++) - draw_1pix(px,py); - - exit_wthread(); - return 0; // not executed, avoid gcc warning -} - - -void draw_1pix(int px, int py) // process one pixel -{ - uint16 *pix1, *pix3; - int ii, dist = 0; - int bright1, bright2; - int red1, green1, blue1; - int red3, green3, blue3; - double dold, dnew; - double pixcon = draw_pixcon3; - - if (Factivearea) { // select area active - ii = py * Fww + px; - dist = sa_pixmap[ii]; // distance from edge - if (! dist) return; // outside pixel - } - - pix1 = PXMpix(E1pxm16,px,py); // input pixel - pix3 = PXMpix(E3pxm16,px,py); // output pixel - - red1 = pix1[0]; - green1 = pix1[1]; - blue1 = pix1[2]; - - bright1 = ((red1 + green1 + blue1) / 3) >> 8; // old brightness 0-255 - bright2 = bright1 * draw_trfunc[bright1]; // new brightness 0-255 - - ii = py * E1ww + px; - if (draw_pixcon_map[ii] < pixcon) bright2 = 255; - - if (pixcon > 1 && bright2 > draw_threshold) bright2 = 255; // empirical !!! - - if (draw_reverse) bright2 = 255 - bright2; // negate if "chalk" - - red3 = green3 = blue3 = bright2 << 8; // gray scale, new brightness - - if (Factivearea && dist < sa_blend) { // select area is active, - dnew = 1.0 * dist / sa_blend; - dold = 1.0 - dnew; - red3 = dnew * red3 + dold * red1; - green3 = dnew * green3 + dold * green1; - blue3 = dnew * blue3 + dold * blue1; - } - - pix3[0] = red3; - pix3[1] = green3; - pix3[2] = blue3; - - return; -} - - -/**************************************************************************/ - -// make an image outline drawing from edge pixels -// superimpose outlines and image and vary brightness of each - -double outlines_olth, outlines_olww, outlines_imbr; - -editfunc EFoutlines; - - -void m_outlines(GtkWidget *, cchar *) -{ - int outlines_dialog_event(zdialog* zd, cchar *event); - void * outlines_thread(void *); - - cchar *title = ZTX("Add Image Outlines"); - - zfuncs::F1_help_topic = "outlines"; - - EFoutlines.funcname = "outlines"; - EFoutlines.Farea = 2; // select area usable - EFoutlines.threadfunc = outlines_thread; // thread function - if (! edit_setup(EFoutlines)) return; // setup edit - - zdialog *zd = zdialog_new(title,mWin,Bdone,Bcancel,null); - EFoutlines.zd = zd; - - zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=5"); - zdialog_add_widget(zd,"label","lab1","hb1",ZTX("outline threshold"),"space=5"); - zdialog_add_widget(zd,"hscale","olth","hb1","0|100|1|90","expand|space=5"); - zdialog_add_widget(zd,"hbox","hb2","dialog",0,"space=5"); - zdialog_add_widget(zd,"label","lab2","hb2",ZTX("outline width"),"space=5"); - zdialog_add_widget(zd,"hscale","olww","hb2","0|100|1|50","expand|space=5"); - zdialog_add_widget(zd,"hbox","hb3","dialog",0,"space=5"); - zdialog_add_widget(zd,"label","lab3","hb3",ZTX("image brightness"),"space=5"); - zdialog_add_widget(zd,"hscale","imbr","hb3","0|100|1|10","expand|space=5"); - - outlines_olth = 90; - outlines_olww = 50; - outlines_imbr = 10; - - zdialog_resize(zd,300,0); - zdialog_help(zd,"outlines"); // zdialog help topic v.11.08 - zdialog_run(zd,outlines_dialog_event,"-10/20"); // run dialog, parallel v.11.07 - - signal_thread(); - return; -} - - -// dialog event and completion callback function - -int outlines_dialog_event(zdialog *zd, cchar *event) // dialog event function -{ - if (zd->zstat) - { - if (zd->zstat == 1) edit_done(EFoutlines); // done - else edit_cancel(EFoutlines); // cancel or destroy - PXM_free(E8pxm16); - PXM_free(E9pxm16); - return 0; - } - - if (strEqu(event,"olth")) { - zdialog_fetch(zd,"olth",outlines_olth); // get outline threshold 0-100 - signal_thread(); - } - - if (strEqu(event,"olww")) { - zdialog_fetch(zd,"olww",outlines_olww); // get outline width 0-100 - signal_thread(); - } - - if (strEqu(event,"imbr")) { - zdialog_fetch(zd,"imbr",outlines_imbr); // get image brightness 0-100 - signal_thread(); - } - - if (strEqu(event,"undo")) edit_undo(); - if (strEqu(event,"redo")) edit_redo(); - if (strEqu(event,"blendwidth")) signal_thread(); - - return 1; -} - - -// thread function to update image - -void * outlines_thread(void *) -{ - void * outlines_wthread(void *arg); - - int px, py, ww, hh; - double olww, red3, green3, blue3; - double red3h, red3v, green3h, green3v, blue3h, blue3v; - uint16 *pix8, *pix9; - uint16 *pixa, *pixb, *pixc, *pixd, *pixe, *pixf, *pixg, *pixh; - - while (true) - { - thread_idle_loop(); // wait for work or exit request - - olww = 0.01 * outlines_olww; // outline width, 0 - 1.0 - olww = 1.0 - olww; // 1.0 - 0 - olww = 0.8 * olww + 0.2; // 1.0 - 0.2 - - ww = Fww * olww + 0.5; // create smaller outline image - hh = Fhh * olww + 0.5; - - if (! E9pxm16 || ww != E9pxm16->ww) // initial or changed outline brightness - { - PXM_free(E8pxm16); - PXM_free(E9pxm16); - - E8pxm16 = PXM_rescale(E1pxm16,ww,hh); - E9pxm16 = PXM_copy(E8pxm16); - - for (py = 1; py < hh-1; py++) - for (px = 1; px < ww-1; px++) - { - pix8 = PXMpix(E8pxm16,px,py); // input pixel - pix9 = PXMpix(E9pxm16,px,py); // output pixel - - pixa = pix8-3*ww-3; // 8 neighboring pixels are used - pixb = pix8-3*ww; // to get edge brightness using - pixc = pix8-3*ww+3; // a Sobel filter - pixd = pix8-3; - pixe = pix8+3; - pixf = pix8+3*ww-3; - pixg = pix8+3*ww; - pixh = pix8+3*ww+3; - - red3h = -pixa[0] -2 * pixb[0] -pixc[0] + pixf[0] + 2 * pixg[0] + pixh[0]; - red3v = -pixa[0] -2 * pixd[0] -pixf[0] + pixc[0] + 2 * pixe[0] + pixh[0]; - green3h = -pixa[1] -2 * pixb[1] -pixc[1] + pixf[1] + 2 * pixg[1] + pixh[1]; - green3v = -pixa[1] -2 * pixd[1] -pixf[1] + pixc[1] + 2 * pixe[1] + pixh[1]; - blue3h = -pixa[2] -2 * pixb[2] -pixc[2] + pixf[2] + 2 * pixg[2] + pixh[2]; - blue3v = -pixa[2] -2 * pixd[2] -pixf[2] + pixc[2] + 2 * pixe[2] + pixh[2]; - - red3 = (abs(red3h) + abs(red3v)) / 2; // average vertical and horizontal brightness - green3 = (abs(green3h) + abs(green3v)) / 2; - blue3 = (abs(blue3h) + abs(blue3v)) / 2; - - if (red3 > 65535) red3 = 65535; - if (green3 > 65535) green3 = 65535; - if (blue3 > 65535) blue3 = 65535; - - pix9[0] = red3; - pix9[1] = green3; - pix9[2] = blue3; - } - } - - PXM_free(E8pxm16); // scale back to full-size - E8pxm16 = PXM_rescale(E9pxm16,Fww,Fhh); - - for (int ii = 0; ii < Nwt; ii++) // start worker threads - start_wthread(outlines_wthread,&wtnx[ii]); - wait_wthreads(); // wait for completion - - CEF->Fmod = 1; - mwpaint2(); // update window - } - - return 0; // not executed, stop g++ warning -} - - -void * outlines_wthread(void *arg) // worker thread function -{ - int index = *((int *) arg); - int px, py, ii, dist = 0; - double olth, imbr, br8, dold, dnew; - double red1, green1, blue1, red3, green3, blue3; - uint16 *pix1, *pix8, *pix3; - - olth = 0.01 * outlines_olth; // outline threshold, 0 - 1.0 - olth = 1.0 - olth; // 1.0 - 0 - imbr = 0.01 * outlines_imbr; // image brightness, 0 - 1.0 - - for (py = index+1; py < Fhh-1; py += Nwt) - for (px = 1; px < Fww-1; px++) - { - if (Factivearea) { // select area active - ii = py * Fww + px; - dist = sa_pixmap[ii]; // distance from edge - if (! dist) continue; // pixel outside area - } - - pix1 = PXMpix(E1pxm16,px,py); // input image pixel - pix8 = PXMpix(E8pxm16,px,py); // input outline pixel - pix3 = PXMpix(E3pxm16,px,py); // output image pixel - - red1 = pix1[0]; // input image pixel - green1 = pix1[1]; - blue1 = pix1[2]; - - br8 = pixbright(pix8); // outline brightness - br8 = br8 / 65536.0; // scale 0 - 1.0 - - if (br8 > olth) { // > threshold, use outline pixel - red3 = pix8[0]; - green3 = pix8[1]; - blue3 = pix8[2]; - } - else { // use image pixel dimmed by user control - red3 = red1 * imbr; - green3 = green1 * imbr; - blue3 = blue1 * imbr; - } - - if (Factivearea && dist < sa_blend) { // select area is active, - dnew = 1.0 * dist / sa_blend; // blend changes over sa_blend - dold = 1.0 - dnew; - red3 = dnew * red3 + dold * red1; - green3 = dnew * green3 + dold * green1; - blue3 = dnew * blue3 + dold * blue1; - } - - pix3[0] = red3; - pix3[1] = green3; - pix3[2] = blue3; - } - - exit_wthread(); - return 0; // not executed, stop gcc warning -} - - -/**************************************************************************/ - -// convert image to simulate an embossing - -int emboss_radius, emboss_color; -double emboss_depth; -double emboss_kernel[20][20]; // support radius <= 9 - -editfunc EFemboss; - - -void m_emboss(GtkWidget *, cchar *) -{ - int emboss_dialog_event(zdialog* zd, cchar *event); - void * emboss_thread(void *); - - cchar *title = ZTX("Simulate Embossing"); - - zfuncs::F1_help_topic = "embossing"; // v.10.8 - - EFemboss.funcname = "emboss"; - EFemboss.Farea = 2; // select area usable - EFemboss.threadfunc = emboss_thread; // thread function - if (! edit_setup(EFemboss)) return; // setup edit - - zdialog *zd = zdialog_new(title,mWin,Bdone,Bcancel,null); - EFemboss.zd = zd; - - zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=10"); - zdialog_add_widget(zd,"label","lab1","hb1",Bradius,"space=5"); - zdialog_add_widget(zd,"spin","radius","hb1","0|9|1|0"); - zdialog_add_widget(zd,"label","lab2","hb1",ZTX("depth"),"space=5"); - zdialog_add_widget(zd,"spin","depth","hb1","0|99|1|0"); - zdialog_add_widget(zd,"check","color","hb1",ZTX("color"),"space=8"); - - zdialog_help(zd,"embossing"); // zdialog help topic v.11.08 - zdialog_run(zd,emboss_dialog_event,"-10/20"); // run dialog, parallel v.11.07 - return; -} - - -// dialog event and completion callback function - -int emboss_dialog_event(zdialog *zd, cchar *event) // emboss dialog event function -{ - if (zd->zstat) // dialog complete - { - if (zd->zstat == 1) edit_done(EFemboss); - else edit_cancel(EFemboss); - return 0; - } - - if (strEqu(event,"undo")) edit_undo(); // v.10.2 - if (strEqu(event,"redo")) edit_redo(); // v.10.3 - if (strEqu(event,"blendwidth")) signal_thread(); // v.10.3 - - if (strcmpv(event,"radius","depth","color",null)) - { - zdialog_fetch(zd,"radius",emboss_radius); // get user inputs - zdialog_fetch(zd,"depth",emboss_depth); - zdialog_fetch(zd,"color",emboss_color); - signal_thread(); // trigger update thread - } - - return 1; -} - - -// thread function - use multiple working threads - -void * emboss_thread(void *) -{ - void * emboss_wthread(void *arg); - - int ii, dx, dy, rad; - double depth, kern, coeff; - - while (true) - { - thread_idle_loop(); // wait for work or exit request - - rad = emboss_radius; - depth = emboss_depth; - - coeff = 0.1 * depth / (rad * rad + 1); - - for (dy = -rad; dy <= rad; dy++) // build kernel with radius and depth - for (dx = -rad; dx <= rad; dx++) - { - kern = coeff * (dx + dy); - emboss_kernel[dx+rad][dy+rad] = kern; - } - - emboss_kernel[rad][rad] = 1; // kernel center cell = 1 - - for (ii = 0; ii < Nwt; ii++) // start worker threads - start_wthread(emboss_wthread,&wtnx[ii]); - wait_wthreads(); // wait for comletion - - CEF->Fmod = 1; - mwpaint2(); // update window - } - - return 0; // not executed, stop g++ warning -} - - -void * emboss_wthread(void *arg) // worker thread function -{ - void emboss_1pix(int px, int py); - - int index = *((int *) (arg)); - int px, py; - - for (py = index; py < E1hh; py += Nwt) // process all pixels - for (px = 0; px < E1ww; px++) - emboss_1pix(px,py); - - exit_wthread(); - return 0; // not executed, avoid gcc warning -} - - -void emboss_1pix(int px, int py) // process one pixel -{ - int ii, dist = 0; - int bright1, bright3; - int rgb, dx, dy, rad; - uint16 *pix1, *pix3, *pixN; - double sumpix, kern, dold, dnew; - - if (Factivearea) { // select area active - ii = py * Fww + px; - dist = sa_pixmap[ii]; // distance from edge - if (! dist) return; // outside pixel - } - - rad = emboss_radius; - - if (px < rad || py < rad) return; - if (px > E3ww-rad-1 || py > E3hh-rad-1) return; - - pix1 = PXMpix(E1pxm16,px,py); // input pixel - pix3 = PXMpix(E3pxm16,px,py); // output pixel - - if (emboss_color) - { - for (rgb = 0; rgb < 3; rgb++) - { - sumpix = 0; - - for (dy = -rad; dy <= rad; dy++) // loop surrounding block of pixels - for (dx = -rad; dx <= rad; dx++) - { - pixN = pix1 + (dy * E1ww + dx) * 3; - kern = emboss_kernel[dx+rad][dy+rad]; - sumpix += kern * pixN[rgb]; - - bright1 = pix1[rgb]; - bright3 = sumpix; - if (bright3 < 0) bright3 = 0; - if (bright3 > 65535) bright3 = 65535; - - if (Factivearea && dist < sa_blend) { // select area is active, - dnew = 1.0 * dist / sa_blend; // blend changes over sa_blend - dold = 1.0 - dnew; - bright3 = dnew * bright3 + dold * bright1; - } - - pix3[rgb] = bright3; - } - } - } - - else // use gray scale - { - sumpix = 0; - - for (dy = -rad; dy <= rad; dy++) // loop surrounding block of pixels - for (dx = -rad; dx <= rad; dx++) - { - pixN = pix1 + (dy * E1ww + dx) * 3; - kern = emboss_kernel[dx+rad][dy+rad]; - sumpix += kern * (pixN[0] + pixN[1] + pixN[2]); - } - - bright1 = 0.3333 * (pix1[0] + pix1[1] + pix1[2]); - bright3 = 0.3333 * sumpix; - if (bright3 < 0) bright3 = 0; - if (bright3 > 65535) bright3 = 65535; - - if (Factivearea && dist < sa_blend) { // select area is active, - dnew = 1.0 * dist / sa_blend; // blend changes over sa_blend - dold = 1.0 - dnew; - bright3 = dnew * bright3 + dold * bright1; - } - - pix3[0] = pix3[1] = pix3[2] = bright3; - } - - return; -} - - -/**************************************************************************/ - -// convert image to simulate square tiles - -int tile_size, tile_gap; -uint16 *tile_pixmap = 0; - -editfunc EFtiles; - - -void m_tiles(GtkWidget *, cchar *) -{ - int tiles_dialog_event(zdialog *zd, cchar *event); - void * tiles_thread(void *); - - zfuncs::F1_help_topic = "tiles"; // v.10.8 - - EFtiles.funcname = "tiles"; - EFtiles.Farea = 2; // select area usable - EFtiles.threadfunc = tiles_thread; // thread function - if (! edit_setup(EFtiles)) return; // setup edit - - zdialog *zd = zdialog_new(ZTX("Simulate Tiles"),mWin,Bdone,Bcancel,null); - EFtiles.zd = zd; - - zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=5"); - zdialog_add_widget(zd,"label","labt","hb1",ZTX("tile size"),"space=5"); - zdialog_add_widget(zd,"spin","size","hb1","1|99|1|5","space=5"); - zdialog_add_widget(zd,"button","apply","hb1",Bapply,"space=10"); - zdialog_add_widget(zd,"hbox","hb2","dialog",0,"space=5"); - zdialog_add_widget(zd,"label","labg","hb2",ZTX("tile gap"),"space=5"); - zdialog_add_widget(zd,"spin","gap","hb2","0|9|1|1","space=5"); - - zdialog_help(zd,"tiles"); // zdialog help topic v.11.08 - zdialog_run(zd,tiles_dialog_event,"-10/20"); // run dialog, parallel v.11.07 - - tile_size = 5; - tile_gap = 1; - - tile_pixmap = (uint16 *) zmalloc(E1ww*E1hh*6,"tiles"); // set up pixel color map - memset(tile_pixmap,0,E1ww*E1hh*6); - - return; -} - - -// dialog event and completion callback function - -int tiles_dialog_event(zdialog * zd, cchar *event) -{ - if (zd->zstat) // dialog complete - { - if (zd->zstat == 1) edit_done(EFtiles); - else edit_cancel(EFtiles); - zfree(tile_pixmap); - return 0; - } - - if (strEqu(event,"undo")) edit_undo(); // v.10.2 - if (strEqu(event,"redo")) edit_redo(); // v.10.3 - if (strEqu(event,"blendwidth")) signal_thread(); // v.10.3 - - if (strNeq(event,"apply")) return 0; - - zdialog_fetch(zd,"size",tile_size); // get tile size - zdialog_fetch(zd,"gap",tile_gap); // get tile gap - - if (tile_size < 2) { - edit_reset(); // restore original image - return 0; - } - - signal_thread(); // trigger working thread - return 1; -} - - -// image tiles thread function - -void * tiles_thread(void *) -{ - int sg, gg; - int sumpix, red, green, blue; - int ii, jj, px, py, qx, qy, dist; - double dnew, dold; - uint16 *pix1, *pix3; - - while (true) - { - thread_idle_loop(); // wait for work or exit request - - sg = tile_size + tile_gap; - gg = tile_gap; - - for (py = 0; py < E1hh; py += sg) // initz. pixel color map for - for (px = 0; px < E1ww; px += sg) // given pixel size - { - sumpix = red = green = blue = 0; - - for (qy = py + gg; qy < py + sg; qy++) // get mean color for pixel block - for (qx = px + gg; qx < px + sg; qx++) - { - if (qy > E1hh-1 || qx > E1ww-1) continue; - - pix1 = PXMpix(E1pxm16,qx,qy); - red += pix1[0]; - green += pix1[1]; - blue += pix1[2]; - sumpix++; - } - - if (sumpix) { - red = (red / sumpix); - green = (green / sumpix); - blue = (blue / sumpix); - } - - for (qy = py; qy < py + sg; qy++) // set color for pixels in block - for (qx = px; qx < px + sg; qx++) - { - if (qy > E1hh-1 || qx > E1ww-1) continue; - - jj = (qy * E1ww + qx) * 3; - - if (qx-px < gg || qy-py < gg) { - tile_pixmap[jj] = tile_pixmap[jj+1] = tile_pixmap[jj+2] = 0; - continue; - } - - tile_pixmap[jj] = red; - tile_pixmap[jj+1] = green; - tile_pixmap[jj+2] = blue; - } - } - - if (Factivearea) // process selected area - { - for (ii = 0; ii < Fww * Fhh; ii++) // find pixels in select area - { // v.9.6 - if (! sa_pixmap[ii]) continue; - py = ii / Fww; - px = ii - py * Fww; - dist = sa_pixmap[ii]; // distance from edge - pix3 = PXMpix(E3pxm16,px,py); - jj = (py * E3ww + px) * 3; - - if (dist >= sa_blend) { // blend changes over sa_blend v.10.2 - pix3[0] = tile_pixmap[jj]; - pix3[1] = tile_pixmap[jj+1]; // apply block color to member pixels - pix3[2] = tile_pixmap[jj+2]; - } - else { - dnew = 1.0 * dist / sa_blend; - dold = 1.0 - dnew; - pix1 = PXMpix(E1pxm16,px,py); - pix3[0] = dnew * tile_pixmap[jj] + dold * pix1[0]; - pix3[1] = dnew * tile_pixmap[jj+1] + dold * pix1[1]; - pix3[2] = dnew * tile_pixmap[jj+2] + dold * pix1[2]; - } - } - } - - else // process entire image - { - for (py = 0; py < E3hh-1; py++) // loop all image pixels - for (px = 0; px < E3ww-1; px++) - { - pix3 = PXMpix(E3pxm16,px,py); // target pixel - jj = (py * E3ww + px) * 3; // color map for (px,py) - pix3[0] = tile_pixmap[jj]; - pix3[1] = tile_pixmap[jj+1]; - pix3[2] = tile_pixmap[jj+2]; - } - } - - CEF->Fmod = 1; - mwpaint2(); // update window - } - - return 0; // not executed, stop g++ warning -} - - -/**************************************************************************/ - -// convert image to dot grid (like Roy Lichtenstein) - -int dot_size; // tile size enclosing dots - -editfunc EFdots; - - -void m_dots(GtkWidget *, cchar *) // v.11.01 -{ - int dots_dialog_event(zdialog *zd, cchar *event); - void * dots_thread(void *); - - zfuncs::F1_help_topic = "dot_matrix"; - - EFdots.funcname = "dots"; - EFdots.Farea = 2; // select area usable - EFdots.threadfunc = dots_thread; // thread function - if (! edit_setup(EFdots)) return; // setup edit - - zdialog *zd = zdialog_new(ZTX("Convert Image to Dots"),mWin,Bdone,Bcancel,null); - EFdots.zd = zd; - - zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=5"); - zdialog_add_widget(zd,"label","labt","hb1",ZTX("dot size"),"space=5"); - zdialog_add_widget(zd,"spin","size","hb1","3|99|1|9","space=5"); - zdialog_add_widget(zd,"button","apply","hb1",Bapply,"space=10"); - zdialog_add_widget(zd,"hbox","hb2","dialog",0,"space=5"); - - zdialog_help(zd,"dot_matrix"); // zdialog help topic v.11.08 - zdialog_run(zd,dots_dialog_event,"-10/20"); // run dialog, parallel v.11.07 - - dot_size = 9; - return; -} - - -// dialog event and completion callback function - -int dots_dialog_event(zdialog * zd, cchar *event) -{ - if (zd->zstat) // dialog complete - { - if (zd->zstat == 1) edit_done(EFdots); - else edit_cancel(EFdots); - return 0; - } - - if (strEqu(event,"undo")) edit_undo(); - if (strEqu(event,"redo")) edit_redo(); - if (strEqu(event,"blendwidth")) signal_thread(); - if (strNeq(event,"apply")) return 0; // wait for [apply] - - zdialog_fetch(zd,"size",dot_size); // get dot size - signal_thread(); // trigger working thread - return 1; -} - - -// image dots thread function - -void * dots_thread(void *) -{ - int ds, sumpix, red, green, blue; - int cc, maxrgb, ii, dist, shift1, shift2; - int px, py, px1, px2, py1, py2; - int qx, qy, qx1, qx2, qy1, qy2; - uint16 *pix1, *pix3; - double relmax, radius, radius2a, radius2b, f1, f2; - double f64K = 1.0 / 65536.0; - double fpi = 1.0 / 3.14159; - double dcx, dcy, qcx, qcy, qdist2; - - while (true) - { - thread_idle_loop(); // wait for work or exit request - - mutex_lock(&Fpixmap_lock); - - ds = dot_size; // dot size and tile size - - cc = E3ww * E3hh * 6; // clear output image to black - memset(E3pxm16->bmp,0,cc); - - px1 = 0; // limits for tiles - px2 = Fww - ds; - py1 = 0; - py2 = Fhh - ds; - - if (Factivearea) { // reduce for active area - px1 = sa_minx; - px2 = sa_maxx; - py1 = sa_miny; - py2 = sa_maxy; - if (px2 > Fww - ds) px2 = Fww - ds; - if (py2 > Fhh - ds) py2 = Fhh - ds; - } - - shift1 = 0; - - for (py = py1; py < py2; py += ds) // loop all tiles in input image - { - shift1 = 1 - shift1; // offset alternate rows v.11.02 - shift2 = 0.5 * shift1 * ds; - - for (px = px1 + shift2; px < px2; px += ds) - { - sumpix = red = green = blue = 0; - - for (qy = py; qy < py + ds; qy++) // loop all pixels in tile - for (qx = px; qx < px + ds; qx++) // get mean RGB levels for tile - { - pix1 = PXMpix(E1pxm16,qx,qy); - red += pix1[0]; - green += pix1[1]; - blue += pix1[2]; - sumpix++; - } - - red = (red / sumpix); // mean RGB levels, 0 to 64K - green = (green / sumpix); - blue = (blue / sumpix); - - maxrgb = red; // max. mean RGB level, 0 to 64K - if (green > maxrgb) maxrgb = green; - if (blue > maxrgb) maxrgb = blue; - relmax = f64K * maxrgb; // max. RGB as 0 to 0.999 - - radius = ds * sqrt(fpi * relmax); // radius of dot with maximized color - radius = radius * 0.9; // deliberate reduction v.11.05 - if (radius < 0.5) continue; - - red = 65535.0 * red / maxrgb; // dot color, maximized - green = 65535.0 * green / maxrgb; - blue = 65535.0 * blue / maxrgb; - - dcx = px + 0.5 * ds; // center of dot / tile - dcy = py + 0.5 * ds; - - qx1 = dcx - radius; // pixels within dot radius of center - qx2 = dcx + radius; - qy1 = dcy - radius; - qy2 = dcy + radius; - - radius2a = (radius + 0.5) * (radius + 0.5); - radius2b = (radius - 0.5) * (radius - 0.5); - - for (qy = qy1; qy <= qy2; qy++) // loop all pixels within dot radius - for (qx = qx1; qx <= qx2; qx++) - { - qcx = qx + 0.5; // center of pixel - qcy = qy + 0.5; - qdist2 = (qcx-dcx)*(qcx-dcx) + (qcy-dcy)*(qcy-dcy); // pixel distance**2 from center of dot - if (qdist2 > radius2a) f1 = 0.0; // pixel outside dot, no color - else if (qdist2 < radius2b) f1 = 1.0; // pixel inside dot, full color - else f1 = 1.0 - sqrt(qdist2) + radius - 0.5; // pixel straddles edge, some color - pix3 = PXMpix(E3pxm16,qx,qy); - pix3[0] = f1 * red; - pix3[1] = f1 * green; - pix3[2] = f1 * blue; - } - } - } - - if (Factivearea) // select area active - { - pix1 = (uint16 *) E1pxm16->bmp; - pix3 = (uint16 *) E3pxm16->bmp; - - for (ii = 0; ii < Fww * Fhh; ii++) // loop all pixels - { - dist = sa_pixmap[ii]; - if (dist == 0) memmove(pix3,pix1,6); // pixel outside area, output pixel = input - else if (dist < sa_blend) { - f1 = 1.0 * dist / sa_blend; // pixel in blend region - f2 = 1.0 - f1; - pix3[0] = f1 * pix3[0] + f2 * pix1[0]; // output pixel is mix of input and output - pix3[1] = f1 * pix3[1] + f2 * pix1[1]; - pix3[2] = f1 * pix3[2] + f2 * pix1[2]; - } - pix1 += 3; - pix3 += 3; - } - } - - mutex_unlock(&Fpixmap_lock); - - CEF->Fmod = 1; - mwpaint2(); // update window - } - - return 0; // not executed, stop g++ warning -} - - -/**************************************************************************/ - -// convert image to simulate a painting -// processing a 10 megapixel image needs 140 MB of main memory - -namespace painting_names -{ - editfunc EFpainting; - - int color_depth; - int group_area; - double color_match; - int borders; - - typedef struct { - int16 px, py; - char direc; - } spixstack; - - int Nstack; - spixstack *pixstack; // pixel group search memory - int *pixgroup; // maps (px,py) to pixel group no. - int *groupcount; // count of pixels in each group - - int group; - char direc; - uint16 gcolor[3]; -} - - -void m_painting(GtkWidget *, cchar *) -{ - using namespace painting_names; - - int painting_dialog_event(zdialog *zd, cchar *event); - void * painting_thread(void *); - - zfuncs::F1_help_topic = "painting"; // v.10.8 - - EFpainting.funcname = "painting"; - EFpainting.Farea = 2; // select area usable - EFpainting.threadfunc = painting_thread; // thread function - if (! edit_setup(EFpainting)) return; // setup edit - - zdialog *zd = zdialog_new(ZTX("Simulate Painting"),mWin,Bdone,Bcancel,null); - EFpainting.zd = zd; - - zdialog_add_widget(zd,"hbox","hbcd","dialog",0,"space=1"); - zdialog_add_widget(zd,"label","lab1","hbcd",ZTX("color depth"),"space=5"); - zdialog_add_widget(zd,"spin","colordepth","hbcd","1|5|1|3","space=5"); - - zdialog_add_widget(zd,"hbox","hbts","dialog",0,"space=1"); - zdialog_add_widget(zd,"label","labts","hbts",ZTX("patch area goal"),"space=5"); - zdialog_add_widget(zd,"spin","grouparea","hbts","0|9999|10|1000","space=5"); - - zdialog_add_widget(zd,"hbox","hbcm","dialog",0,"space=1"); - zdialog_add_widget(zd,"label","labcm","hbcm",ZTX("req. color match"),"space=5"); - zdialog_add_widget(zd,"spin","colormatch","hbcm","0|99|1|50","space=5"); - - zdialog_add_widget(zd,"hbox","hbbd","dialog",0,"space=1"); - zdialog_add_widget(zd,"label","labbd","hbbd",ZTX("borders"),"space=5"); - zdialog_add_widget(zd,"check","borders","hbbd",0,"space=2"); - zdialog_add_widget(zd,"button","apply","hbbd",Bapply,"space=10"); - - zdialog_help(zd,"painting"); // zdialog help topic v.11.08 - zdialog_run(zd,painting_dialog_event,"-10/20"); // run dialog, parallel v.11.07 - - return; -} - - -// dialog event and completion callback function - -int painting_dialog_event(zdialog *zd, cchar *event) -{ - using namespace painting_names; - - if (zd->zstat) // dialog complete - { - if (zd->zstat == 1) edit_done(EFpainting); - else edit_cancel(EFpainting); - return 0; - } - - if (strEqu(event,"undo")) edit_undo(); // v.10.2 - if (strEqu(event,"redo")) edit_redo(); // v.10.3 - if (strEqu(event,"blendwidth")) signal_thread(); // v.10.3 - - if (strEqu(event,"apply")) { // apply user settings - zdialog_fetch(zd,"colordepth",color_depth); // color depth - zdialog_fetch(zd,"grouparea",group_area); // target group area (pixels) - zdialog_fetch(zd,"colormatch",color_match); // req. color match to combine groups - zdialog_fetch(zd,"borders",borders); // borders wanted - color_match = 0.01 * color_match; // scale 0 to 1 - - signal_thread(); // do the work - wait_thread_idle(); - } - - return 0; -} - - -// painting thread function - -void * painting_thread(void *) -{ - void painting_colordepth(); - void painting_pixgroups(); - void painting_mergegroups(); - void painting_paintborders(); - void painting_blend(); - - while (true) - { - thread_idle_loop(); // wait for work or exit request - - painting_colordepth(); // set new color depth - painting_pixgroups(); // group pixel patches of a color - painting_mergegroups(); // merge smaller into larger groups - painting_paintborders(); // add borders around groups - painting_blend(); // blend edges of selected area - - CEF->Fmod = 1; - mwpaint2(); // update window - } - - return 0; // not executed, stop g++ warning -} - - -// set the specified color depth, 1-5 bits/color - -void painting_colordepth() -{ - using namespace painting_names; - - int ii, px, py, rgb; - double fmag; - uint16 m1, m2, val1, val3; - uint16 *pix1, *pix3; - - m1 = 0xFFFF << (16 - color_depth); // 5 > 1111100000000000 - m2 = 0x8000 >> color_depth; // 5 > 0000010000000000 - - fmag = 65535.0 / m1; // full brightness range - - if (Factivearea) // process select area - { - for (ii = 0; ii < Fww * Fhh; ii++) - { // v.9.6 - if (! sa_pixmap[ii]) continue; - py = ii / Fww; - px = ii - py * Fww; - - pix1 = PXMpix(E1pxm16,px,py); // input pixel - pix3 = PXMpix(E3pxm16,px,py); // output pixel - - for (rgb = 0; rgb < 3; rgb++) - { - val1 = pix1[rgb]; - if (val1 < m1) val3 = (val1 + m2) & m1; - else val3 = m1; - val3 = uint(val3 * fmag); - pix3[rgb] = val3; - } - } - } - - else // process entire image - { - for (py = 0; py < E3hh; py++) // loop all pixels - for (px = 0; px < E3ww; px++) - { - pix1 = PXMpix(E1pxm16,px,py); // input pixel - pix3 = PXMpix(E3pxm16,px,py); // output pixel - - for (rgb = 0; rgb < 3; rgb++) - { - val1 = pix1[rgb]; - if (val1 < m1) val3 = (val1 + m2) & m1; - else val3 = m1; - val3 = uint(val3 * fmag); - pix3[rgb] = val3; - } - } - } - - return; -} - - -// find all groups of contiguous pixels with the same color - -void painting_pixgroups() -{ - using namespace painting_names; - - void painting_pushpix(int px, int py); - - int cc1, cc2; - int ii, kk, px, py; - int ppx, ppy, npx, npy; - uint16 *pix3; - - cc1 = E3ww * E3hh; - - cc2 = cc1 * sizeof(int); - pixgroup = (int *) zmalloc(cc2,"painting"); // maps pixel to assigned group - memset(pixgroup,0,cc2); - - if (Factivearea) cc1 = sa_Npixel; - - cc2 = cc1 * sizeof(spixstack); - pixstack = (spixstack *) zmalloc(cc2,"painting"); // memory stack for pixel search - memset(pixstack,0,cc2); - - cc2 = cc1 * sizeof(int); - groupcount = (int *) zmalloc(cc2,"painting"); // counts pixels per group - memset(groupcount,0,cc2); - - group = 0; - - for (py = 0; py < E3hh; py++) // loop all pixels - for (px = 0; px < E3ww; px++) - { - kk = py * E3ww + px; - if (Factivearea && ! sa_pixmap[kk]) continue; - if (pixgroup[kk]) continue; // already assigned to group - - pixgroup[kk] = ++group; // assign next group - ++groupcount[group]; - - pix3 = PXMpix(E3pxm16,px,py); - gcolor[0] = pix3[0]; - gcolor[1] = pix3[1]; - gcolor[2] = pix3[2]; - - pixstack[0].px = px; // put pixel into stack with - pixstack[0].py = py; // direction = ahead v.11.04 - pixstack[0].direc = 'a'; - Nstack = 1; - - while (Nstack) // overhauled v.11.02 - { - kk = Nstack - 1; // get last pixel in stack - px = pixstack[kk].px; - py = pixstack[kk].py; - direc = pixstack[kk].direc; - - if (direc == 'x') { - Nstack--; - continue; - } - - if (Nstack > 1) { - ii = Nstack - 2; // get prior pixel in stack - ppx = pixstack[ii].px; - ppy = pixstack[ii].py; - } - else { - ppx = px - 1; // if only one, assume prior = left - ppy = py; - } - - if (direc == 'a') { // next ahead pixel v.11.04 - npx = px + px - ppx; - npy = py + py - ppy; - pixstack[kk].direc = 'r'; // next search direction - } - - else if (direc == 'r') { // next right pixel v.11.04 - npx = px + py - ppy; - npy = py + px - ppx; - pixstack[kk].direc = 'l'; - } - - else { /* direc = 'l' */ // next left pixel v.11.04 - npx = px + ppy - py; - npy = py + ppx - px; - pixstack[kk].direc = 'x'; - } - - if (npx < 0 || npx > E3ww-1) continue; // pixel off the edge v.11.04 - if (npy < 0 || npy > E3hh-1) continue; - - kk = npy * E3ww + npx; - - if (Factivearea && ! sa_pixmap[kk]) continue; // pixel outside area - - if (pixgroup[kk]) continue; // pixel already assigned - - pix3 = PXMpix(E3pxm16,npx,npy); - if (pix3[0] != gcolor[0] || pix3[1] != gcolor[1] // not same color as group - || pix3[2] != gcolor[2]) continue; - - pixgroup[kk] = group; // assign pixel to group - ++groupcount[group]; - - kk = Nstack++; // put pixel into stack - pixstack[kk].px = npx; - pixstack[kk].py = npy; - pixstack[kk].direc = 'a'; // direction = ahead v.11.04 - } - } - - return; -} - - -// merge small pixel groups into adjacent larger groups with best color match - -void painting_mergegroups() -{ - using namespace painting_names; - - int ii, jj, kk, px, py, npx, npy; - int nccc, mcount, group2; - double ff = 1.0 / 65536.0; - double fred, fgreen, fblue, match; - int nnpx[4] = { 0, -1, +1, 0 }; - int nnpy[4] = { -1, 0, 0, +1 }; - uint16 *pix3, *pixN; - - typedef struct { - int group; - double match; - uint16 pixM[3]; - } snewgroup; - - snewgroup *newgroup; - - nccc = (group + 1) * sizeof(snewgroup); - newgroup = (snewgroup *) zmalloc(nccc,"painting"); - - if (Factivearea) // process select area - { - while (true) - { - memset(newgroup,0,nccc); - - for (ii = 0; ii < Fww * Fhh; ii++) // find pixels in select area - { // v.9.6 - if (! sa_pixmap[ii]) continue; - py = ii / Fww; - px = ii - py * Fww; - - kk = E3ww * py + px; // get assigned group - group = pixgroup[kk]; - if (groupcount[group] >= group_area) continue; // group count large enough - - pix3 = PXMpix(E3pxm16,px,py); - - for (jj = 0; jj < 4; jj++) // get 4 neighbor pixels - { - npx = px + nnpx[jj]; - npy = py + nnpy[jj]; - - if (npx < 0 || npx >= E3ww) continue; // off the edge - if (npy < 0 || npy >= E3hh) continue; - - kk = E3ww * npy + npx; - if (! sa_pixmap[kk]) continue; // pixel outside area - if (pixgroup[kk] == group) continue; // already in same group - - pixN = PXMpix(E3pxm16,npx,npy); // match color of group neighbor - fred = ff * abs(pix3[0] - pixN[0]); // to color of group - fgreen = ff * abs(pix3[1] - pixN[1]); - fblue = ff * abs(pix3[2] - pixN[2]); - match = (1.0 - fred) * (1.0 - fgreen) * (1.0 - fblue); // color match, 0 to 1.0 - if (match < color_match) continue; - - if (match > newgroup[group].match) { - newgroup[group].match = match; // remember best match - newgroup[group].group = pixgroup[kk]; // and corresp. group no. - newgroup[group].pixM[0] = pixN[0]; // and corresp. new color - newgroup[group].pixM[1] = pixN[1]; - newgroup[group].pixM[2] = pixN[2]; - } - } - } - - mcount = 0; - - for (ii = 0; ii < Fww * Fhh; ii++) // find pixels in select area - { // v.9.6 - if (! sa_pixmap[ii]) continue; - py = ii / Fww; - px = ii - py * Fww; - - kk = E3ww * py + px; - group = pixgroup[kk]; // test for new group assignment - group2 = newgroup[group].group; - if (! group2) continue; - - if (groupcount[group] > groupcount[group2]) continue; // accept only bigger new group - - pixgroup[kk] = group2; // make new group assignment - --groupcount[group]; - ++groupcount[group2]; - - pix3 = PXMpix(E3pxm16,px,py); // make new color assignment - pix3[0] = newgroup[group].pixM[0]; - pix3[1] = newgroup[group].pixM[1]; - pix3[2] = newgroup[group].pixM[2]; - - mcount++; - } - - if (mcount == 0) break; - } - } - - else // process entire image - { - while (true) - { - memset(newgroup,0,nccc); - - for (py = 0; py < E3hh; py++) // loop all pixels - for (px = 0; px < E3ww; px++) - { - kk = E3ww * py + px; // get assigned group - group = pixgroup[kk]; - if (groupcount[group] >= group_area) continue; // group count large enough - - pix3 = PXMpix(E3pxm16,px,py); - - for (jj = 0; jj < 4; jj++) // get 4 neighbor pixels - { - npx = px + nnpx[jj]; - npy = py + nnpy[jj]; - - if (npx < 0 || npx >= E3ww) continue; // off the edge - if (npy < 0 || npy >= E3hh) continue; - - kk = E3ww * npy + npx; - if (pixgroup[kk] == group) continue; // in same group - - pixN = PXMpix(E3pxm16,npx,npy); // match color of group neighbor - fred = ff * abs(pix3[0] - pixN[0]); // to color of group - fgreen = ff * abs(pix3[1] - pixN[1]); - fblue = ff * abs(pix3[2] - pixN[2]); - match = (1.0 - fred) * (1.0 - fgreen) * (1.0 - fblue); // color match, 0 to 1.0 - if (match < color_match) continue; - - if (match > newgroup[group].match) { - newgroup[group].match = match; // remember best match - newgroup[group].group = pixgroup[kk]; // and corresp. group no. - newgroup[group].pixM[0] = pixN[0]; // and corresp. new color - newgroup[group].pixM[1] = pixN[1]; - newgroup[group].pixM[2] = pixN[2]; - } - } - } - - mcount = 0; - - for (py = 0; py < E3hh; py++) // loop all pixels - for (px = 0; px < E3ww; px++) - { - kk = E3ww * py + px; - group = pixgroup[kk]; // test for new group assignment - group2 = newgroup[group].group; - if (! group2) continue; - - if (groupcount[group] > groupcount[group2]) continue; // accept only bigger new group - - pixgroup[kk] = group2; // make new group assignment - --groupcount[group]; - ++groupcount[group2]; - - pix3 = PXMpix(E3pxm16,px,py); // make new color assignment - pix3[0] = newgroup[group].pixM[0]; - pix3[1] = newgroup[group].pixM[1]; - pix3[2] = newgroup[group].pixM[2]; - - mcount++; - } - - if (mcount == 0) break; - } - } - - zfree(pixgroup); - zfree(pixstack); - zfree(groupcount); - zfree(newgroup); - - return; -} - - -// paint borders between the groups of contiguous pixels - -void painting_paintborders() -{ - using namespace painting_names; - - int ii, kk, px, py, cc; - uint16 *pix3, *pixL, *pixA; - - if (! borders) return; - - cc = E3ww * E3hh; - char * pixblack = zmalloc(cc,"painting"); - memset(pixblack,0,cc); - - if (Factivearea) - { - for (ii = 0; ii < Fww * Fhh; ii++) // find pixels in select area - { // v.9.6 - if (! sa_pixmap[ii]) continue; - py = ii / Fww; - px = ii - py * Fww; - if (px < 1 || py < 1) continue; - - pix3 = PXMpix(E3pxm16,px,py); - pixL = PXMpix(E3pxm16,px-1,py); - pixA = PXMpix(E3pxm16,px,py-1); - - if (pix3[0] != pixL[0] || pix3[1] != pixL[1] || pix3[2] != pixL[2]) - { - kk = ii - 1; - if (pixblack[kk]) continue; - kk += 1; - pixblack[kk] = 1; - continue; - } - - if (pix3[0] != pixA[0] || pix3[1] != pixA[1] || pix3[2] != pixA[2]) - { - kk = ii - E3ww; - if (pixblack[kk]) continue; - kk += E3ww; - pixblack[kk] = 1; - } - } - - for (ii = 0; ii < Fww * Fhh; ii++) // find pixels in select area - { // v.9.6 - if (! sa_pixmap[ii]) continue; - py = ii / Fww; - px = ii - py * Fww; - if (px < 1 || py < 1) continue; - - if (! pixblack[ii]) continue; - pix3 = PXMpix(E3pxm16,px,py); - pix3[0] = pix3[1] = pix3[2] = 0; - } - } - - else - { - for (py = 1; py < E3hh; py++) // loop all pixels - for (px = 1; px < E3ww; px++) // omit top and left - { - pix3 = PXMpix(E3pxm16,px,py); // output pixel - pixL = PXMpix(E3pxm16,px-1,py); // pixel to left - pixA = PXMpix(E3pxm16,px,py-1); // pixel above - - if (pix3[0] != pixL[0] || pix3[1] != pixL[1] || pix3[2] != pixL[2]) - { - kk = E3ww * py + px-1; // have horiz. transition - if (pixblack[kk]) continue; - kk += 1; - pixblack[kk] = 1; - continue; - } - - if (pix3[0] != pixA[0] || pix3[1] != pixA[1] || pix3[2] != pixA[2]) - { - kk = E3ww * (py-1) + px; // have vertical transition - if (pixblack[kk]) continue; - kk += E3ww; - pixblack[kk] = 1; - } - } - - for (py = 1; py < E3hh; py++) - for (px = 1; px < E3ww; px++) - { - kk = E3ww * py + px; - if (! pixblack[kk]) continue; - pix3 = PXMpix(E3pxm16,px,py); - pix3[0] = pix3[1] = pix3[2] = 0; - } - } - - zfree(pixblack); - return; -} - - -// blend edges of selected area - -void painting_blend() -{ - int ii, px, py, dist; - uint16 *pix1, *pix3; - double f1, f2; - - if (Factivearea && sa_blend > 0) - { - for (ii = 0; ii < Fww * Fhh; ii++) // find pixels in select area - { // v.9.6 - dist = sa_pixmap[ii]; - if (! dist || dist >= sa_blend) continue; - - py = ii / Fww; - px = ii - py * Fww; - pix1 = PXMpix(E1pxm16,px,py); // input pixel - pix3 = PXMpix(E3pxm16,px,py); // output pixel - - f2 = 1.0 * dist / sa_blend; // changes over distance sa_blend - f1 = 1.0 - f2; - - pix3[0] = int(f1 * pix1[0] + f2 * pix3[0]); - pix3[1] = int(f1 * pix1[1] + f2 * pix3[1]); - pix3[2] = int(f1 * pix1[2] + f2 * pix3[2]); - } - } - - return; -} - - - diff -Nru fotoxx-11.11.1/fotoxx_comp.cc fotoxx-12.01.2/fotoxx_comp.cc --- fotoxx-11.11.1/fotoxx_comp.cc 2011-11-05 05:30:36.000000000 +0000 +++ fotoxx-12.01.2/fotoxx_comp.cc 1970-01-01 00:00:00.000000000 +0000 @@ -1,5897 +0,0 @@ -/************************************************************************** - - Fotoxx edit photos and manage collections - - Copyright 2007 2008 2009 2010 2011 Michael Cornelison - Source URL: http://kornelix.squarespace.com/fotoxx - Contact: kornelix2@googlemail.com - - 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 http://www.gnu.org/licenses/. - -***************************************************************************/ - -#define EX extern // enable extern declarations -#include "fotoxx.h" - - -/************************************************************************** - - Fotoxx image edit functions - composite functions - -***************************************************************************/ - - -// File scope variables and functions for composite images -// used by HDR, HDF, STP, STN, Panorama. - - -int cimNF; // image count, <= 10 -char *cimFile[10]; // image files -PXM *cimPXMf[10]; // original images -PXM *cimPXMs[10]; // alignment images, scaled and curved (pano) -PXM *cimPXMw[10]; // alignment images, warped - -struct cimoffs { // image alignment offsets - double xf, yf, tf; // x, y, theta offsets - double wx[4], wy[4]; // x/y corner warps, 0=NW, 1=NE, 2=SE, 3=SW -}; -cimoffs cimOffs[10]; // image alignment data in E3 output image - -double cimScale; // alignment image size relative to full image -double cimBlend; // image blend width at overlap, pixels (pano) -double cimSearchRange; // alignment search range, pixels -double cimSearchStep; // alignment search step, vpixels -double cimWarpRange; // alignment corner warp range, pixels -double cimWarpStep; // alignment corner warp step, vpixels -double cimSampSize; // pixel sample size -int cimOv1xlo, cimOv1xhi, cimOv1ylo, cimOv1yhi; // rectangle enclosing overlap area, -int cimOv2xlo, cimOv2xhi, cimOv2ylo, cimOv2yhi; // image 1 and image2 coordinates -double cimRGBmf1[3][65536]; // RGB matching factors for pixel comparisons: -double cimRGBmf2[3][65536]; // cimRGBmf1[*][pix1[*]] == cimRGBmf2[*][pix2[*]] -char *cimRedpix = 0; // maps high-contrast pixels for alignment -int cimRedImage; // which image has red pixels -int cimNsearch; // alignment search counter -int cimShowIm1, cimShowIm2; // two images for cim_show_images() -int cimShowAll; // if > 0, show all images -int cimShrink; // image shrinkage from pano image curving -int cimPano; // pano mode flag for cim_align_image() -int cimPanoV; // vertical pano flag - -int cim_load_files(); // load and check selected files -void cim_scale_image(int im, PXM **); // scale image, 1.0 to cimScale (normally < 1) -double cim_get_overlap(int im1, int im2, PXM **); // get overlap area for images (horiz or vert) -void cim_match_colors(int im1, int im2, PXM **); // match image RGB levels >> match data -void cim_adjust_colors(PXM *pxm, int fwhich); // adjust RGB levels from match data -void cim_get_redpix(int im1); // find high-contrast pixels in overlap area -void cim_curve_image(int im); // curve cimPXMs[im] using lens parameters -void cim_curve_Vimage(int im); // vertical pano version -void cim_warp_image(int im); // warp image corners: cimPXMs[im] >> cimPXMw[im] -void cim_warp_image_pano(int im, int fblend); // pano version, all / left side / blend stripe -void cim_warp_image_Vpano(int im, int fblend); // vertical pans version: bottom side corners -void cim_align_image(int im1, int im2); // align image im2 to im1, modify im2 offsets -double cim_match_images(int im1, int im2); // compute match for overlapped images -void cim_show_images(int fnew, int fblend); // combine images >> E3pxm16 >> main window -void cim_show_Vimages(int fnew, int fblend); // vertical pano version -void cim_trim(); // cut-off edges where all images do not overlap -void cim_dump_offsets(cchar *text); // diagnostic tool - - -// load image file into pixmaps cimPXMf[*] and check for errors -// returns 0 if error - -int cim_load_files() // v.10.7 -{ - PXM *pxm; - - for (int imx = 0; imx < cimNF; imx++) - { - PXM_free(cimPXMf[imx]); - pxm = f_load(cimFile[imx],16); // will diagnose errors - if (! pxm) return 0; - cimPXMf[imx] = pxm; - - PXM_fixblue(pxm); // blue=0 >> blue=2 for vpixel() v.11.07 - } - - return 1; -} - - -// scale image from full size) to cimScale (normally < 1.0) - -void cim_scale_image(int im, PXM** pxmout) // v.10.7 -{ - int ww, hh; - - ww = cimScale * cimPXMf[im]->ww; - hh = cimScale * cimPXMf[im]->hh; - - PXM_free(pxmout[im]); - pxmout[im] = PXM_rescale(cimPXMf[im],ww,hh); - - PXM_fixblue(pxmout[im]); // blue=0 >> blue=2 for vpixel() v.11.07 - - return; -} - - -// get overlap area for a pair of images im1 and im2 -// outputs are coordinates of overlap area in im1 and in im2 -// returns overlap width as fraction of image width <= 1.0 - -double cim_get_overlap(int im1, int im2, PXM **pxmx) // v.11.04 -{ - double x1, y1, t1, x2, y2, t2; - double xoff, yoff, toff, costf, sintf; - int ww1, ww2, hh1, hh2, pxM; - PXM *pxm1, *pxm2; - - x1 = cimOffs[im1].xf; // im1, im2 absolute offsets - y1 = cimOffs[im1].yf; - t1 = cimOffs[im1].tf; - x2 = cimOffs[im2].xf; - y2 = cimOffs[im2].yf; - t2 = cimOffs[im2].tf; - - xoff = (x2 - x1) * cos(t1) + (y2 - y1) * sin(t1); // offset of im2 relative to im1 - yoff = (y2 - y1) * cos(t1) - (x2 - x1) * sin(t1); - toff = t2 - t1; - - costf = cos(toff); - sintf = sin(toff); - - pxm1 = pxmx[im1]; - pxm2 = pxmx[im2]; - - ww1 = pxm1->ww; - hh1 = pxm1->hh; - ww2 = pxm2->ww; - hh2 = pxm2->hh; - - cimOv1xlo = 0; // lowest x overlap - if (xoff > 0) cimOv1xlo = xoff; - - cimOv1xhi = ww1-1; // highest x overlap - if (cimOv1xhi > xoff + ww2-1) cimOv1xhi = xoff + ww2-1; - - cimOv1ylo = 0; // lowest y overlap - if (yoff > 0) cimOv1ylo = yoff; - - cimOv1yhi = hh1-1; // highest y overlap - if (cimOv1yhi > yoff + hh2-1) cimOv1yhi = yoff + hh2-1; - - if (toff < 0) cimOv1xlo -= toff * (cimOv1yhi - cimOv1ylo); // reduce for theta offset - if (toff < 0) cimOv1yhi += toff * (cimOv1xhi - cimOv1xlo); - if (toff > 0) cimOv1xhi -= toff * (cimOv1yhi - cimOv1ylo); - if (toff > 0) cimOv1ylo += toff * (cimOv1xhi - cimOv1xlo); - - cimOv1xlo += cimShrink + 3; // account for void areas from - cimOv1xhi += - cimShrink - 3; // image shrinkage from - cimOv1ylo += cimShrink + 3; // cim_curve_image() - cimOv1yhi += - cimShrink - 3; // v.11.04 - - if (cimPanoV) { - if (cimBlend && cimBlend < (cimOv1yhi - cimOv1ylo)) { // reduce y range to cimBlend v.11.04 - pxM = (cimOv1yhi + cimOv1ylo) / 2; - cimOv1ylo = pxM - cimBlend / 2; - cimOv1yhi = pxM + cimBlend / 2; - } - } - else { - if (cimBlend && cimBlend < (cimOv1xhi - cimOv1xlo)) { // reduce x range to cimBlend - pxM = (cimOv1xhi + cimOv1xlo) / 2; - cimOv1xlo = pxM - cimBlend / 2; - cimOv1xhi = pxM + cimBlend / 2; - } - } - - cimOv2xlo = costf * (cimOv1xlo - xoff) + sintf * (cimOv1ylo - yoff); // overlap area in im2 coordinates - cimOv2xhi = costf * (cimOv1xhi - xoff) + sintf * (cimOv1yhi - yoff); - cimOv2ylo = costf * (cimOv1ylo - yoff) + sintf * (cimOv1xlo - xoff); - cimOv2yhi = costf * (cimOv1yhi - yoff) + sintf * (cimOv1xhi - xoff); - - if (cimOv1xlo < 0) cimOv1xlo = 0; // take care of limits - if (cimOv1ylo < 0) cimOv1ylo = 0; - if (cimOv2xlo < 0) cimOv2xlo = 0; - if (cimOv2ylo < 0) cimOv2ylo = 0; - if (cimOv1xhi > ww1-1) cimOv1xhi = ww1-1; - if (cimOv1yhi > hh1-1) cimOv1yhi = hh1-1; - if (cimOv2xhi > ww2-1) cimOv2xhi = ww2-1; - if (cimOv2yhi > hh2-1) cimOv2yhi = hh2-1; - - if (cimPanoV) return 1.0 * (cimOv1yhi - cimOv1ylo) / hh1; // return overlap height <= 1.0 v.11.04 - else return 1.0 * (cimOv1xhi - cimOv1xlo) / ww1; // return overlap width <= 1.0 v.11.03 -} - - -// Get the RGB brightness distribution in the overlap area for each image. -// Compute matching factors to compare pixels within the overlap area. -// compare cimRGBmf1[rgb][pix1[rgb]] to cimRGBmf2[rgb][pix2[rgb]] - -void cim_match_colors(int im1, int im2, PXM **pxmx) // v.10.7 -{ - double Bratios1[3][256]; // image2/image1 brightness ratio per color per level - double Bratios2[3][256]; // image1/image2 brightness ratio per color per level - - uint16 *pix1, vpix2[3]; - int vstat2, px1, py1; - int ii, jj, rgb; - int npix, npix1, npix2, npix3; - int brdist1[3][256], brdist2[3][256]; - double x1, y1, t1, x2, y2, t2; - double xoff, yoff, toff, costf, sintf; - double px2, py2; - double brlev1[3][256], brlev2[3][256]; - double a1, a2, b1, b2, bratio = 1; - double r256 = 1.0 / 256.0; - PXM *pxm1, *pxm2; - - pxm1 = pxmx[im1]; - pxm2 = pxmx[im2]; - - x1 = cimOffs[im1].xf; // im1, im2 absolute offsets - y1 = cimOffs[im1].yf; - t1 = cimOffs[im1].tf; - x2 = cimOffs[im2].xf; - y2 = cimOffs[im2].yf; - t2 = cimOffs[im2].tf; - - xoff = (x2 - x1) * cos(t1) + (y2 - y1) * sin(t1); // offset of im2 relative to im1 - yoff = (y2 - y1) * cos(t1) - (x2 - x1) * sin(t1); - toff = t2 - t1; - - costf = cos(toff); - sintf = sin(toff); - - for (rgb = 0; rgb < 3; rgb++) // clear distributions - for (ii = 0; ii < 256; ii++) - brdist1[rgb][ii] = brdist2[rgb][ii] = 0; - - npix = 0; - - for (py1 = cimOv1ylo; py1 < cimOv1yhi; py1++) // loop overlapped rows - for (px1 = cimOv1xlo; px1 < cimOv1xhi; px1++) // loop overlapped columns - { - pix1 = PXMpix(pxm1,px1,py1); // image1 pixel - if (! pix1[2]) continue; // ignore void pixels - - px2 = costf * (px1 - xoff) + sintf * (py1 - yoff); // corresponding image2 pixel - py2 = costf * (py1 - yoff) - sintf * (px1 - xoff); - vstat2 = vpixel(pxm2,px2,py2,vpix2); - if (! vstat2) continue; // does not exist - - ++npix; // count overlapping pixels - - for (rgb = 0; rgb < 3; rgb++) // accumulate distributions - { // by color in 256 bins - ++brdist1[rgb][int(r256*pix1[rgb])]; - ++brdist2[rgb][int(r256*vpix2[rgb])]; - } - } - - npix1 = npix / 256; // 1/256th of total pixels - - for (rgb = 0; rgb < 3; rgb++) // get brlev1[rgb][N] = mean bright - for (ii = jj = 0; jj < 256; jj++) // for Nth group of image1 pixels - { // for color rgb - brlev1[rgb][jj] = 0; - npix2 = npix1; // 1/256th of total pixels - - while (npix2 > 0 && ii < 256) // next 1/256th group from distr, - { - npix3 = brdist1[rgb][ii]; - if (npix3 == 0) { ++ii; continue; } - if (npix3 > npix2) npix3 = npix2; - brlev1[rgb][jj] += ii * npix3; // brightness * (pixels with) - brdist1[rgb][ii] -= npix3; - npix2 -= npix3; - } - - brlev1[rgb][jj] = brlev1[rgb][jj] / npix1; // mean brightness for group, 0-255 - } - - for (rgb = 0; rgb < 3; rgb++) // do same for image2 - for (ii = jj = 0; jj < 256; jj++) - { - brlev2[rgb][jj] = 0; - npix2 = npix1; - - while (npix2 > 0 && ii < 256) - { - npix3 = brdist2[rgb][ii]; - if (npix3 == 0) { ++ii; continue; } - if (npix3 > npix2) npix3 = npix2; - brlev2[rgb][jj] += ii * npix3; - brdist2[rgb][ii] -= npix3; - npix2 -= npix3; - } - - brlev2[rgb][jj] = brlev2[rgb][jj] / npix1; - } - - for (rgb = 0; rgb < 3; rgb++) // color - for (ii = jj = 0; ii < 256; ii++) // brlev1 brightness, 0 to 255 - { - if (ii == 0) bratio = 1; - while (ii > brlev2[rgb][jj] && jj < 256) ++jj; // find matching brlev2 brightness - a2 = brlev2[rgb][jj]; // next higher value - b2 = brlev1[rgb][jj]; - if (a2 > 0 && b2 > 0) { - if (jj > 0) { - a1 = brlev2[rgb][jj-1]; // next lower value - b1 = brlev1[rgb][jj-1]; - } - else a1 = b1 = 0; - if (ii == 0) bratio = b2 / a2; - else bratio = (b1 + (ii-a1)/(a2-a1) * (b2-b1)) / ii; // interpolate - } - - if (bratio < 0.2) bratio = 0.2; // contain outliers - if (bratio > 5) bratio = 5; - Bratios2[rgb][ii] = bratio; - } - - for (rgb = 0; rgb < 3; rgb++) // color - for (ii = jj = 0; ii < 256; ii++) // brlev2 brightness, 0 to 255 - { - if (ii == 0) bratio = 1; - while (ii > brlev1[rgb][jj] && jj < 256) ++jj; // find matching brlev1 brightness - a2 = brlev1[rgb][jj]; // next higher value - b2 = brlev2[rgb][jj]; - if (a2 > 0 && b2 > 0) { - if (jj > 0) { - a1 = brlev1[rgb][jj-1]; // next lower value - b1 = brlev2[rgb][jj-1]; - } - else a1 = b1 = 0; - if (ii == 0) bratio = b2 / a2; - else bratio = (b1 + (ii-a1)/(a2-a1) * (b2-b1)) / ii; // interpolate - } - - if (bratio < 0.2) bratio = 0.2; // contain outliers - if (bratio > 5) bratio = 5; - Bratios1[rgb][ii] = bratio; - } - - for (ii = 0; ii < 65536; ii++) // convert brightness ratios into - { // conversion factors - jj = ii / 256; - - for (rgb = 0; rgb < 3; rgb++) - { - cimRGBmf1[rgb][ii] = sqrt(Bratios1[rgb][jj]) * ii; // use sqrt(ratio) so that adjustment - cimRGBmf2[rgb][ii] = sqrt(Bratios2[rgb][jj]) * ii; // can be applied to both images - } - } - - return; -} - - -// Use color match data from cim_match_colors() to -// modify images so the colors match. - -void cim_adjust_colors(PXM *pxm, int fwhich) // v.10.7 -{ - int ww, hh, px, py; - int red, green, blue, max; - uint16 *pix; - double f1; - - ww = pxm->ww; - hh = pxm->hh; - - for (py = 0; py < hh; py++) - for (px = 0; px < ww; px++) - { - pix = PXMpix(pxm,px,py); - red = pix[0]; - green = pix[1]; - blue = pix[2]; - if (! blue) continue; - - if (fwhich == 1) { - red = cimRGBmf1[0][red]; - green = cimRGBmf1[1][green]; - blue = cimRGBmf1[2][blue]; - } - - if (fwhich == 2) { - red = cimRGBmf2[0][red]; - green = cimRGBmf2[1][green]; - blue = cimRGBmf2[2][blue]; - } - - if (red > 65535 || green > 65535 || blue > 65535) { - max = red; - if (green > max) max = green; - if (blue > max) max = blue; - f1 = 65535.0 / max; - red = red * f1; - green = green * f1; - blue = blue * f1; - } - - if (! blue) blue = 1; // avoid 0 v.10.7 - - pix[0] = red; - pix[1] = green; - pix[2] = blue; - } - - return; -} - - -// find pixels of greatest contrast within overlap area -// flag high-contrast pixels to use in each image compare region - -void cim_get_redpix(int im1) // v.10.7 -{ - int ww, hh, samp, xzone, yzone; - int pxL, pxH, pyL, pyH; - int px, py, ii, jj, npix; - int red1, green1, blue1, red2, green2, blue2, tcon; - int ov1xlo, ov1xhi, ov1ylo, ov1yhi; - int Hdist[256], Vdist[256], Hmin, Vmin; - double s8 = 1.0 / 770.0; - double zsamp[16] = { 4,6,6,4,6,9,9,6,6,9,9,6,4,6,6,4 }; // % sample per zone, sum = 100 - uchar *Hcon, *Vcon; - uint16 *pix1, *pix2; - PXM *pxm; - - pxm = cimPXMs[im1]; // v.11.04 - ww = pxm->ww; - hh = pxm->hh; - - if (cimRedpix) zfree(cimRedpix); // clear prior - cimRedpix = zmalloc(ww*hh,"cimRedpix"); - memset(cimRedpix,0,ww*hh); - - cimRedImage = im1; // image with red pixels - - ov1xlo = cimOv1xlo + cimSearchRange; // stay within x/y search range - ov1xhi = cimOv1xhi - cimSearchRange; // so that red pixels persist - ov1ylo = cimOv1ylo + cimSearchRange; // over offset changes - ov1yhi = cimOv1yhi - cimSearchRange; - - for (yzone = 0; yzone < 4; yzone++) // loop 16 zones v.10.8 - for (xzone = 0; xzone < 4; xzone++) - { - pxL = ov1xlo + 0.25 * xzone * (ov1xhi - ov1xlo); // px and py zone limits - pxH = ov1xlo + 0.25 * (xzone+1) * (ov1xhi - ov1xlo); - pyL = ov1ylo + 0.25 * yzone * (ov1yhi - ov1ylo); - pyH = ov1ylo + 0.25 * (yzone+1) * (ov1yhi - ov1ylo); - - npix = (pxH - pxL) * (pyH - pyL); // zone pixels - Hcon = (uchar *) zmalloc(npix,"cimRedpix"); // horizontal pixel contrast 0-255 - Vcon = (uchar *) zmalloc(npix,"cimRedpix"); // vertical pixel contrast 0-255 - - ii = 4 * yzone + xzone; - samp = cimSampSize * 0.01 * zsamp[ii]; // sample size for zone - if (samp > 0.1 * npix) samp = 0.1 * npix; // limit to 10% of zone pixels - - for (py = pyL; py < pyH; py++) // scan image pixels in zone - for (px = pxL; px < pxH; px++) - { - ii = (py-pyL) * (pxH-pxL) + (px-pxL); - Hcon[ii] = Vcon[ii] = 0; // horiz. = vert. contrast = 0 - - if (py < 8 || py > hh-9) continue; // keep away from image edges - if (px < 8 || px > ww-9) continue; - - pix1 = PXMpix(pxm,px,py-6); // verify not near void areas - if (! pix1[2]) continue; - pix1 = PXMpix(pxm,px+6,py); - if (! pix1[2]) continue; - pix1 = PXMpix(pxm,px,py+6); - if (! pix1[2]) continue; - pix1 = PXMpix(pxm,px-6,py); - if (! pix1[2]) continue; - - pix1 = PXMpix(pxm,px,py); // candidate red pixel - red1 = pix1[0]; - green1 = pix1[1]; - blue1 = pix1[2]; - - pix2 = PXMpix(pxm,px+2,py); // 2 pixels to right - red2 = pix2[0]; - green2 = pix2[1]; - blue2 = pix2[2]; - - tcon = abs(red1-red2) + abs(green1-green2) + abs(blue1-blue2); // horizontal contrast - Hcon[ii] = int(tcon * s8); // scale 0 - 255 - - pix2 = PXMpix(pxm,px,py+2); // 2 pixels below - red2 = pix2[0]; - green2 = pix2[1]; - blue2 = pix2[2]; - - tcon = abs(red1-red2) + abs(green1-green2) + abs(blue1-blue2); // vertical contrast - Vcon[ii] = int(tcon * s8); - } - - for (ii = 0; ii < 256; ii++) Hdist[ii] = Vdist[ii] = 0; // clear contrast distributions - - for (py = pyL; py < pyH; py++) // scan image pixels - for (px = pxL; px < pxH; px++) - { // build contrast distributions - ii = (py-pyL) * (pxH-pxL) + (px-pxL); - ++Hdist[Hcon[ii]]; - ++Vdist[Vcon[ii]]; - } - - for (npix = 0, ii = 255; ii > 0; ii--) // find minimum contrast needed to get - { // enough pixels for sample size - npix += Hdist[ii]; // (horizontal contrast pixels) - if (npix > samp) break; - } - Hmin = ii; - - for (npix = 0, ii = 255; ii > 0; ii--) // (verticle contrast pixels) - { - npix += Vdist[ii]; - if (npix > samp) break; - } - Vmin = ii; - - for (py = pyL; py < pyH; py++) // scan zone pixels - for (px = pxL; px < pxH; px++) - { - ii = (py-pyL) * (pxH-pxL) + (px-pxL); - jj = py * ww + px; - if (Hcon[ii] > Hmin) cimRedpix[jj] = 1; // flag pixels above min. contrast - if (Vcon[ii] > Vmin) cimRedpix[jj] = 1; - } - - zfree(Hcon); - zfree(Vcon); - - for (py = pyL; py < pyH; py++) // scan zone pixels - for (px = pxL; px < pxH; px++) - { - ii = (py-pyL) * (pxH-pxL) + (px-pxL); - jj = py * ww + px; - if (! cimRedpix[jj]) continue; - npix = cimRedpix[jj-1] + cimRedpix[jj+1]; // eliminate flagged pixels with no - npix += cimRedpix[jj-ww] + cimRedpix[jj+ww]; // neighboring flagged pixels - npix += cimRedpix[jj-ww-1] + cimRedpix[jj+ww-1]; // v.11.03 - npix += cimRedpix[jj-ww+1] + cimRedpix[jj+ww+1]; - if (npix < 2) cimRedpix[jj] = 0; - } - - for (py = pyL; py < pyH; py++) // scan zone pixels - for (px = pxL; px < pxH; px++) - { - ii = (py-pyL) * (pxH-pxL) + (px-pxL); - jj = py * ww + px; - - if (cimRedpix[jj] == 1) { // flag horizontal group of 3 - cimRedpix[jj+1] = 2; - cimRedpix[jj+2] = 2; - cimRedpix[jj+ww] = 2; // and vertical group of 3 - cimRedpix[jj+2*ww] = 2; - } - } - } - - return; -} - - -// curve image based on lens parameters (pano) -// replaces cimPXMs[im] with curved version - -void cim_curve_image(int im) // overhauled v.11.03 -{ - int px, py, ww, hh, vstat; - double ww2, hh2; - double dx, dy; - double F = lens_mm; // lens focal length, 35mm equivalent - double S = 35.0; // corresponding image width - double R1, R2, G, T, bow; - PXM *pxmin, *pxmout; - uint16 vpix[3], *pix; - - pxmin = cimPXMs[im]; // input and output image - ww = pxmin->ww; // 200 - hh = pxmin->hh; - ww2 = 0.5 * ww; // 100 - hh2 = 0.5 * hh; - - if (hh > ww) S = S * ww / hh; // vertical format - F = F / S; // 28 / 35 // scale to image dimensions - S = ww2; // 100 - F = F * ww; // 160 - R1 = F; // cylinder tangent to image plane - - bow = -lens_bow * 0.01 / hh2 / hh2; // lens bow % to fraction - if (hh > ww) - bow = -lens_bow * 0.01 / ww2 / ww2; - - pxmout = PXM_make(ww,hh,16); // temp. output PXM - - for (py = 0; py < hh; py++) // cylindrical projection v.11.03 - for (px = 0; px < ww; px++) - { - dx = px - ww2; - dy = py - hh2; - T = dx / R1; - dx = F * tan(T); - R2 = sqrt(dx * dx + F * F); - G = R1 - R2; - dy = (dy * R2) / (R2 + G); - dx += bow * dx * dy * dy; // barrel distortion - dx += ww2; - dy += hh2; - vstat = vpixel(pxmin,dx,dy,vpix); // input virtual pixel - pix = PXMpix(pxmout,px,py); // output real pixel - if (vstat) { - pix[0] = vpix[0]; - pix[1] = vpix[1]; - pix[2] = vpix[2]; - } - else pix[0] = pix[1] = pix[2] = 0; // voided pixels are (0,0,0) - } - - for (px = 1; px < ww2; px++) { // compute image shrinkage - pix = PXMpix(pxmout,px,hh/2); - if (pix[2]) break; - } - cimShrink = px-1; // = 0 if no curvature - - PXM_free(pxmin); // replace input with output PXM - cimPXMs[im] = pxmout; - - return; -} - - -// version for vertical panorama - -void cim_curve_Vimage(int im) // v.11.04 -{ - int px, py, ww, hh, vstat; - double ww2, hh2; - double dx, dy; - double F = lens_mm; // lens focal length, 35mm equivalent - double S = 35.0; // corresponding image width - double R1, R2, G, T, bow; - PXM *pxmin, *pxmout; - uint16 vpix[3], *pix; - - pxmin = cimPXMs[im]; // input and output image - ww = pxmin->ww; // 200 - hh = pxmin->hh; - ww2 = 0.5 * ww; // 100 - hh2 = 0.5 * hh; - - if (hh > ww) S = S * ww / hh; // vertical format - F = F / S; // 28 / 35 // scale to image dimensions - S = ww2; // 100 - F = F * ww; // 160 - R1 = F; // cylinder tangent to image plane - - bow = -lens_bow * 0.01 / hh2 / hh2; // lens bow % to fraction - if (hh > ww) - bow = -lens_bow * 0.01 / ww2 / ww2; - - pxmout = PXM_make(ww,hh,16); // temp. output PXM - - for (py = 0; py < hh; py++) // cylindrical projection v.11.03 - for (px = 0; px < ww; px++) - { - dx = px - ww2; - dy = py - hh2; - T = dy / R1; - dy = F * tan(T); - R2 = sqrt(dy * dy + F * F); - G = R1 - R2; - dx = (dx * R2) / (R2 + G); - dy += bow * dy * dx * dx; // barrel distortion - dx += ww2; - dy += hh2; - vstat = vpixel(pxmin,dx,dy,vpix); // input virtual pixel - pix = PXMpix(pxmout,px,py); // output real pixel - if (vstat) { - pix[0] = vpix[0]; - pix[1] = vpix[1]; - pix[2] = vpix[2]; - } - else pix[0] = pix[1] = pix[2] = 0; // voided pixels are (0,0,0) - } - - for (py = 1; py < hh2; py++) { // compute image shrinkage - pix = PXMpix(pxmout,ww/2,py); - if (pix[2]) break; - } - cimShrink = py-1; // = 0 if no curvature - - PXM_free(pxmin); // replace input with output PXM - cimPXMs[im] = pxmout; - - return; -} - - -// Warp 4 image corners according to cimOffs[im].wx[ii] and .wy[ii] -// corner = 0 = NW, 1 = NE, 2 = SE, 3 = SW -// 4 corners move by these pixel amounts and center does not move. -// input: cimPXMs[im] (flat or curved) output: cimPXMw[im] - -namespace cim_warp_image_names { - PXM *pxmin, *pxmout; - double ww, hh, wwi, hhi; - double wx0, wy0, wx1, wy1, wx2, wy2, wx3, wy3; -} - -void cim_warp_image(int im) // caller function v.10.8 -{ - using namespace cim_warp_image_names; - - void * cim_warp_image_wthread(void *arg); - - pxmin = cimPXMs[im]; // input and output pixmaps - pxmout = cimPXMw[im]; - - PXM_free(pxmout); // v.11.04 - pxmout = PXM_copy(pxmin); - cimPXMw[im] = pxmout; - - ww = pxmin->ww; - hh = pxmin->hh; - wwi = 1.0 / ww; - hhi = 1.0 / hh; - - wx0 = cimOffs[im].wx[0]; // corner warps - wy0 = cimOffs[im].wy[0]; - wx1 = cimOffs[im].wx[1]; - wy1 = cimOffs[im].wy[1]; - wx2 = cimOffs[im].wx[2]; - wy2 = cimOffs[im].wy[2]; - wx3 = cimOffs[im].wx[3]; - wy3 = cimOffs[im].wy[3]; - - for (int ii = 0; ii < Nwt; ii++) // start worker threads - start_wthread(cim_warp_image_wthread,&wtnx[ii]); - wait_wthreads(); // wait for completion - - return; -} - - -void * cim_warp_image_wthread(void *arg) // worker thread function v.10.8 -{ - using namespace cim_warp_image_names; - - int index = *((int *) arg); - int pxm, pym, vstat; - uint16 vpix[3], *pixm; - double px, py, dx, dy, coeff; - - for (pym = index; pym < hh; pym += Nwt) // loop all pixels for this thread - for (pxm = 0; pxm < ww; pxm++) - { - dx = dy = 0.0; - - coeff = (1.0 - pym * hhi - pxm * wwi); // corner 0 NW - if (coeff > 0) { - dx += coeff * wx0; - dy += coeff * wy0; - } - coeff = (1.0 - pym * hhi - (ww - pxm) * wwi); // corner 1 NE - if (coeff > 0) { - dx += coeff * wx1; - dy += coeff * wy1; - } - coeff = (1.0 - (hh - pym) * hhi - (ww - pxm) * wwi); // corner 2 SE - if (coeff > 0) { - dx += coeff * wx2; - dy += coeff * wy2; - } - coeff = (1.0 - (hh - pym) * hhi - pxm * wwi); // corner 3 SW - if (coeff > 0) { - dx += coeff * wx3; - dy += coeff * wy3; - } - - px = pxm + dx; // source pixel location - py = pym + dy; - - vstat = vpixel(pxmin,px,py,vpix); // input virtual pixel - pixm = PXMpix(pxmout,pxm,pym); // output real pixel - - if (vstat) { - pixm[0] = vpix[0]; - pixm[1] = vpix[1]; - pixm[2] = vpix[2]; - } - else pixm[0] = pixm[1] = pixm[2] = 0; - } - - exit_wthread(); - return 0; // not executed, avoid gcc warning -} - - -// warp image for pano, left side corners only, reduced warp range -// input: cimPXMs[im] (curved) -// output: cimPXMw[im] (warped) -// fblend: 0 = process entire image -// 1 = process left half only -// 2 = process blend stripe only - -void cim_warp_image_pano(int im, int fblend) // v.10.8 -{ - int ww, hh, ww2, hh2, pxL, pxH; - int pxm, pym, vstat; - uint16 vpix[3], *pixm; - double ww2i, hh2i, pxs, pys, xdisp, ydisp; - double wx0, wy0, wx3, wy3; - PXM *pxmin, *pxmout; - - pxmin = cimPXMs[im]; // input and output pixmaps - pxmout = cimPXMw[im]; - - PXM_free(pxmout); // v.11.04 - pxmout = PXM_copy(pxmin); - cimPXMw[im] = pxmout; - - ww = pxmin->ww; - hh = pxmin->hh; - - ww2 = ww / 2; - hh2 = hh / 2; - - ww2i = 1.0 / ww2; // v.10.8 - hh2i = 1.0 / hh2; - - wx0 = cimOffs[im].wx[0]; // NW corner warp - wy0 = cimOffs[im].wy[0]; - - wx3 = cimOffs[im].wx[3]; // SW corner warp - wy3 = cimOffs[im].wy[3]; - - pxL = 0; // entire image v.10.8 - pxH = ww; - - if (fblend == 1) // left half - pxH = ww2; - - if (fblend == 2) { - pxL = cimOv2xlo; // limit to overlap/blend width - pxH = cimOv2xhi; - } - - for (pym = 0; pym < hh; pym++) // loop all output pixels - for (pxm = pxL; pxm < pxH; pxm++) - { - pixm = PXMpix(pxmout,pxm,pym); // output pixel - - xdisp = (pxm - ww2) * ww2i; // -1 ... 0 ... +1 - ydisp = (pym - hh2) * hh2i; // v.11.04 - - if (xdisp > 0) { // right half, no warp - pxs = pxm; - pys = pym; - } - else if (ydisp < 0) { // use NW corner warp - pxs = pxm + wx0 * xdisp * ydisp; - pys = pym + wy0 * xdisp * ydisp; - } - else { // use SW corner warp - pxs = pxm + wx3 * xdisp * ydisp; - pys = pym + wy3 * xdisp * ydisp; - } - - vstat = vpixel(pxmin,pxs,pys,vpix); // input virtual pixel - - if (vstat) { - pixm[0] = vpix[0]; - pixm[1] = vpix[1]; - pixm[2] = vpix[2]; - } - else pixm[0] = pixm[1] = pixm[2] = 0; - } - - for (pxm = 1; pxm < ww2; pxm++) { // compute image shrinkage - pixm = PXMpix(pxmout,pxm,hh2); // used by cim_get_overlap() - if (pixm[2]) break; - } - cimShrink = pxm-1; - - return; -} - - -// vertical pano version - warp top side corners (NW, NE) - -void cim_warp_image_Vpano(int im, int fblend) // v.11.04 -{ - int ww, hh, ww2, hh2, pyL, pyH; - int pxm, pym, vstat; - uint16 vpix[3], *pixm; - double ww2i, hh2i, pxs, pys, xdisp, ydisp; - double wx0, wy0, wx1, wy1; - PXM *pxmin, *pxmout; - - pxmin = cimPXMs[im]; // input and output pixmaps - pxmout = cimPXMw[im]; - - PXM_free(pxmout); // v.11.04 - pxmout = PXM_copy(pxmin); - cimPXMw[im] = pxmout; - - ww = pxmin->ww; - hh = pxmin->hh; - - ww2 = ww / 2; - hh2 = hh / 2; - - ww2i = 1.0 / ww2; // v.10.8 - hh2i = 1.0 / hh2; - - wx0 = cimOffs[im].wx[0]; // NW corner warp - wy0 = cimOffs[im].wy[0]; - - wx1 = cimOffs[im].wx[1]; // NE corner warp - wy1 = cimOffs[im].wy[1]; - - pyL = 0; // entire image v.10.8 - pyH = hh; - - if (fblend == 1) // top half - pyH = hh2; - - if (fblend == 2) { - pyL = cimOv2ylo; // limit to overlap/blend width - pyH = cimOv2yhi; - } - - for (pym = pyL; pym < pyH; pym++) // loop all output pixels - for (pxm = 0; pxm < ww; pxm++) - { - pixm = PXMpix(pxmout,pxm,pym); // output pixel - - xdisp = (pxm - ww2) * ww2i; // -1 ... 0 ... +1 - ydisp = (pym - hh2) * hh2i; - - if (ydisp > 0) { // bottom half, no warp - pxs = pxm; - pys = pym; - } - else if (xdisp < 0) { // use NW corner warp - pxs = pxm + wx0 * xdisp * ydisp; - pys = pym + wy0 * xdisp * ydisp; - } - else { // use NE corner warp - pxs = pxm + wx1 * xdisp * ydisp; - pys = pym + wy1 * xdisp * ydisp; - } - - vstat = vpixel(pxmin,pxs,pys,vpix); // input virtual pixel - - if (vstat) { - pixm[0] = vpix[0]; - pixm[1] = vpix[1]; - pixm[2] = vpix[2]; - } - else pixm[0] = pixm[1] = pixm[2] = 0; - } - - for (pym = 1; pym < hh2; pym++) { // compute image shrinkage - pixm = PXMpix(pxmout,ww2,pym); // used by cim_get_overlap() - if (pixm[2]) break; - } - cimShrink = pym-1; - - return; -} - - -// fine-align a pair of images im1 and im2 -// cimPXMs[im2] is aligned with cimPXMs[im1] -// inputs are cimOffs[im1] and cimOffs[im2] (x/y/t and corner offsets) -// output is adjusted offsets and corner warp values for im2 only -// (im1 is used as-is without corner warps) - -void cim_align_image(int im1, int im2) // speedup v.11.03 -{ - int ii, corner1, cornerstep, cornerN, pass; - double xyrange, xystep, trange, tstep, wrange, wstep; - double xfL, xfH, yfL, yfH, tfL, tfH; - double wxL, wxH, wyL, wyH; - double match, matchB; - cimoffs offsets0, offsetsB; - - offsets0 = cimOffs[im2]; // initial offsets - offsetsB = offsets0; // = best offsets so far - matchB = cim_match_images(im1,im2); // = best image match level - - if (cimPanoV) cim_show_Vimages(0,0); // v.11.04 - else cim_show_images(0,0); // show with 50/50 blend - - for (pass = 1; pass <=2; pass++) // main pass and 2nd pass v.10.8 - { - xyrange = cimSearchRange; // x/y search range and step - xystep = cimSearchStep; - - trange = xyrange / (cimOv1yhi - cimOv1ylo); // angle range, radians - tstep = trange * xystep / xyrange; - - if (pass == 2) { - xyrange = 0.5 * xyrange; // 2nd pass, reduce range and step - xystep = 0.5 * xystep; // v.11.04 - trange = 0.5 * trange; - tstep = 0.5 * tstep; - } - - // search x/y/t range for best match - - xfL = cimOffs[im2].xf - xyrange; - xfH = cimOffs[im2].xf + xyrange + 0.5 * xystep; - yfL = cimOffs[im2].yf - xyrange; - yfH = cimOffs[im2].yf + xyrange + 0.5 * xystep; - tfL = cimOffs[im2].tf - trange; - tfH = cimOffs[im2].tf + trange + 0.5 * tstep; - - for (cimOffs[im2].xf = xfL; cimOffs[im2].xf < xfH; cimOffs[im2].xf += xystep) - for (cimOffs[im2].yf = yfL; cimOffs[im2].yf < yfH; cimOffs[im2].yf += xystep) - for (cimOffs[im2].tf = tfL; cimOffs[im2].tf < tfH; cimOffs[im2].tf += tstep) - { - match = cim_match_images(im1,im2); // get match level - - if (sigdiff(match,matchB,0.00001) > 0) { - matchB = match; // save best match - offsetsB = cimOffs[im2]; - } - - sprintf(SB_text,"align: %d match: %.5f",cimNsearch++,matchB); // update status bar - zmainloop(); // v.11.11.1 - } - - cimOffs[im2] = offsetsB; // restore best match - - if (cimPanoV) cim_show_Vimages(0,0); // v.11.04 - else cim_show_images(0,0); - - // warp corners and search for best match - - wrange = cimWarpRange; // corner warp range and step - wstep = cimWarpStep; - if (! wrange) continue; - - if (pass == 2) { // 2nd pass, 1/4 range and 1/2 step - wrange = wrange / 4; - wstep = wstep / 2; - } - - corner1 = 0; // process all 4 corners - cornerN = 3; - cornerstep = 1; - - if (cimPano) { - corner1 = 0; // left side corners 0, 3 - cornerN = 3; - cornerstep = 3; - } - - if (cimPanoV) { - corner1 = 0; // top side corners 0, 1 v.11.04 - cornerN = 1; - cornerstep = 1; - } - - matchB = cim_match_images(im1,im2); // initial image match level - - for (ii = corner1; ii <= cornerN; ii += cornerstep) // modify one corner at a time - { - wxL = cimOffs[im2].wx[ii] - wrange; - wxH = cimOffs[im2].wx[ii] + wrange + 0.5 * wstep; - wyL = cimOffs[im2].wy[ii] - wrange; - wyH = cimOffs[im2].wy[ii] + wrange + 0.5 * wstep; - - for (cimOffs[im2].wx[ii] = wxL; cimOffs[im2].wx[ii] < wxH; cimOffs[im2].wx[ii] += wstep) - for (cimOffs[im2].wy[ii] = wyL; cimOffs[im2].wy[ii] < wyH; cimOffs[im2].wy[ii] += wstep) - { - match = cim_match_images(im1,im2); // get match level - - if (sigdiff(match,matchB,0.00001) > 0) { - matchB = match; // save best match - offsetsB = cimOffs[im2]; - } - - sprintf(SB_text,"warp: %d match: %.5f",cimNsearch++,matchB); - zmainloop(); // v.11.11.1 - } - - cimOffs[im2] = offsetsB; // restore best match - } - - if (cimPano) cim_warp_image_pano(im2,1); // apply corner warps v.11.04 - else if (cimPanoV) cim_warp_image_Vpano(im2,1); - else cim_warp_image(im2); - - if (cimPanoV) cim_show_Vimages(0,0); // v.11.04 - else cim_show_images(0,0); - } - - return; -} - - -// Compare 2 pixels using precalculated brightness ratios -// 1.0 = perfect match 0 = total mismatch (black/white) - -inline double cim_match_pixels(uint16 *pix1, uint16 *pix2) // v.10.7 -{ - double red1, green1, blue1, red2, green2, blue2; - double reddiff, greendiff, bluediff, match; - double ff = 1.0 / 65536.0; - - red1 = pix1[0]; - green1 = pix1[1]; - blue1 = pix1[2]; - - red2 = pix2[0]; - green2 = pix2[1]; - blue2 = pix2[2]; - - reddiff = ff * fabs(red1-red2); // 0 = perfect match - greendiff = ff * fabs(green1-green2); // 1 = total mismatch - bluediff = ff * fabs(blue1-blue2); - - match = (1.0 - reddiff) * (1.0 - greendiff) * (1.0 - bluediff); // 1 = perfect match - return match; -} - - -// Compare two images in overlapping areas. -// Use the high-contrast pixels from cim_get_redpix() -// return: 1 = perfect match, 0 = total mismatch (black/white) -// cimPXMs[im1] is matched to cimPXMs[im2] + virtual warps - -double cim_match_images(int im1, int im2) // v.11.03 -{ - uint16 *pix1, vpix2[3]; - int ww, hh, ww2, hh2; - int px1, py1, ii, vstat; - double wwi, hhi, ww2i, hh2i, xdisp, ydisp; - double wx0, wy0, wx1, wy1, wx2, wy2, wx3, wy3; - double dx, dy, px2, py2; - double x1, y1, t1, x2, y2, t2; - double xoff, yoff, toff, costf, sintf, coeff; - double match, cmatch, maxcmatch; - PXM *pxm1, *pxm2; - - x1 = cimOffs[im1].xf; // im1, im2 absolute offsets - y1 = cimOffs[im1].yf; - t1 = cimOffs[im1].tf; - x2 = cimOffs[im2].xf; - y2 = cimOffs[im2].yf; - t2 = cimOffs[im2].tf; - - xoff = (x2 - x1) * cos(t1) + (y2 - y1) * sin(t1); // offset of im2 relative to im1 - yoff = (y2 - y1) * cos(t1) - (x2 - x1) * sin(t1); - toff = t2 - t1; - - costf = cos(toff); - sintf = sin(toff); - - wx0 = cimOffs[im2].wx[0]; // im2 corner warps - wy0 = cimOffs[im2].wy[0]; - wx1 = cimOffs[im2].wx[1]; - wy1 = cimOffs[im2].wy[1]; - wx2 = cimOffs[im2].wx[2]; - wy2 = cimOffs[im2].wy[2]; - wx3 = cimOffs[im2].wx[3]; - wy3 = cimOffs[im2].wy[3]; - - pxm1 = cimPXMs[im1]; // base image - pxm2 = cimPXMs[im2]; // comparison image (virtual warps) - - ww = pxm1->ww; - hh = pxm1->hh; - ww2 = ww / 2; - hh2 = hh / 2; - - wwi = 1.0 / ww; - hhi = 1.0 / hh; - ww2i = 1.0 / ww2; - hh2i = 1.0 / hh2; - - cmatch = 0; - maxcmatch = 1; - - if (cimPano) - { - for (py1 = cimOv1ylo; py1 < cimOv1yhi; py1++) // loop overlapping pixels - for (px1 = cimOv1xlo; px1 < cimOv1xhi; px1++) - { - ii = py1 * ww + px1; // skip low-contrast pixels - if (! cimRedpix[ii]) continue; - - pix1 = PXMpix(pxm1,px1,py1); // image1 pixel - if (! pix1[2]) continue; // ignore void pixels - - px2 = costf * (px1 - xoff) + sintf * (py1 - yoff); // corresponding image2 pixel - py2 = costf * (py1 - yoff) - sintf * (px1 - xoff); - - dx = dy = 0.0; // corner warp - - xdisp = (px2 - ww2) * ww2i; // -1 ... 0 ... +1 - ydisp = (py2 - hh2) * hh2i; // v.11.04 - - if (xdisp > 0) // right half, no warp - dx = dy = 0; - - else if (ydisp < 0) { // use NW corner warp - dx = wx0 * xdisp * ydisp; - dy = wy0 * xdisp * ydisp; - } - - else { // use SW corner warp - dx = wx3 * xdisp * ydisp; - dy = wy3 * xdisp * ydisp; - } - - px2 += dx; // source pixel location - py2 += dy; // after corner warps - - vstat = vpixel(pxm2,px2,py2,vpix2); - if (! vstat) continue; - - match = cim_match_pixels(pix1,vpix2); // compare brightness adjusted - cmatch += match; // accumulate total match - maxcmatch += 1.0; - } - } - - else if (cimPanoV) - { - for (py1 = cimOv1ylo; py1 < cimOv1yhi; py1++) // loop overlapping pixels - for (px1 = cimOv1xlo; px1 < cimOv1xhi; px1++) - { - ii = py1 * ww + px1; // skip low-contrast pixels - if (! cimRedpix[ii]) continue; - - pix1 = PXMpix(pxm1,px1,py1); // image1 pixel - if (! pix1[2]) continue; // ignore void pixels - - px2 = costf * (px1 - xoff) + sintf * (py1 - yoff); // corresponding image2 pixel - py2 = costf * (py1 - yoff) - sintf * (px1 - xoff); - - dx = dy = 0.0; // corner warp - - xdisp = (px2 - ww2) * ww2i; // -1 ... 0 ... +1 - ydisp = (py2 - hh2) * hh2i; - - if (ydisp > 0) // bottom half, no warp - dx = dy = 0; - - else if (xdisp < 0) { // use NW corner warp - dx = wx0 * xdisp * ydisp; - dy = wy0 * xdisp * ydisp; - } - - else { // use NE corner warp - dx = wx1 * xdisp * ydisp; - dy = wy1 * xdisp * ydisp; - } - - px2 += dx; // source pixel location - py2 += dy; // after corner warps - - vstat = vpixel(pxm2,px2,py2,vpix2); - if (! vstat) continue; - - match = cim_match_pixels(pix1,vpix2); // compare brightness adjusted - cmatch += match; // accumulate total match - maxcmatch += 1.0; - } - } - - else - { - for (py1 = cimOv1ylo; py1 < cimOv1yhi; py1++) // loop overlapping pixels - for (px1 = cimOv1xlo; px1 < cimOv1xhi; px1++) - { - ii = py1 * ww + px1; // skip low-contrast pixels - if (! cimRedpix[ii]) continue; - - pix1 = PXMpix(pxm1,px1,py1); // image1 pixel - if (! pix1[2]) continue; // ignore void pixels - - px2 = costf * (px1 - xoff) + sintf * (py1 - yoff); // corresponding image2 pixel - py2 = costf * (py1 - yoff) - sintf * (px1 - xoff); - - dx = dy = 0.0; // corner warp - - coeff = (1.0 - py2 * hhi - px2 * wwi); // corner 0 NW - if (coeff > 0) { - dx += coeff * wx0; - dy += coeff * wy0; - } - coeff = (1.0 - py2 * hhi - (ww - px2) * wwi); // corner 1 NE - if (coeff > 0) { - dx += coeff * wx1; - dy += coeff * wy1; - } - coeff = (1.0 - (hh - py2) * hhi - (ww - px2) * wwi); // corner 2 SE - if (coeff > 0) { - dx += coeff * wx2; - dy += coeff * wy2; - } - coeff = (1.0 - (hh - py2) * hhi - px2 * wwi); // corner 3 SW - if (coeff > 0) { - dx += coeff * wx3; - dy += coeff * wy3; - } - - px2 += dx; // source pixel location - py2 += dy; // after corner warps - - vstat = vpixel(pxm2,px2,py2,vpix2); - if (! vstat) continue; - - match = cim_match_pixels(pix1,vpix2); // compare brightness adjusted - cmatch += match; // accumulate total match - maxcmatch += 1.0; - } - } - - return cmatch / maxcmatch; -} - - -// combine and show all images -// fnew >> make new E3 output image and adjust x and y offsets -// cimPXMw[*] >> E3pxm16 >> main window -// fblend: 0 > 50/50 blend, 1 > gradual blend - -namespace cim_show_images_names { - int im1, im2, iminc, fblendd; - int wwlo[10], wwhi[10]; - int hhlo[10], hhhi[10]; - double costf[10], sintf[10]; -} - -void cim_show_images(int fnew, int fblend) // v.10.7 -{ - using namespace cim_show_images_names; - - void * cim_show_images_wthread(void *arg); - - int imx, pxr, pyr, ii, px3, py3; - int ww, hh, wwmin, wwmax, hhmin, hhmax, bmid; - double xf, yf, tf; - uint16 *pix3; - - mutex_lock(&Fpixmap_lock); // stop window updates - - fblendd = fblend; // blend 50/50 or gradual ramp - - im1 = cimShowIm1; // two images to show - im2 = cimShowIm2; - iminc = im2 - im1; // v.10.9 - - if (cimShowAll) { // show all images v.10.9 - im1 = 0; - im2 = cimNF-1; - iminc = 1; - } - - for (imx = 0; imx < cimNF; imx++) { // pre-calculate - costf[imx] = cos(cimOffs[imx].tf); - sintf[imx] = sin(cimOffs[imx].tf); - } - - if (fnew) PXM_free(E3pxm16); // force new output pixmap - - if (! E3pxm16) // allocate output pixmap - { - wwmin = hhmin = 9999; // initial values - wwmax = cimPXMw[im2]->ww; - hhmax = cimPXMw[im2]->hh; - - for (imx = im1; imx <= im2; imx += iminc) // find min and max ww and hh extents - { - xf = cimOffs[imx].xf; - yf = cimOffs[imx].yf; - tf = cimOffs[imx].tf; - ww = cimPXMw[imx]->ww; - hh = cimPXMw[imx]->hh; - if (xf < wwmin) wwmin = xf; - if (xf - tf * hh < wwmin) wwmin = xf + tf * hh; - if (xf + ww > wwmax) wwmax = xf + ww; - if (xf + ww - tf * hh > wwmax) wwmax = xf + ww - tf * hh; - if (yf < hhmin) hhmin = yf; - if (yf + tf * ww < hhmin) hhmin = yf + tf * ww; - if (yf + hh > hhmax) hhmax = yf + hh; - if (yf + hh + tf * ww > hhmax) hhmax = yf + hh + tf * ww; - } - - for (imx = im1; imx <= im2; imx += iminc) { // align to top and left edges - cimOffs[imx].xf -= wwmin; - cimOffs[imx].yf -= hhmin; - } - wwmax = wwmax - wwmin; - hhmax = hhmax - hhmin; - wwmin = hhmin = 0; - - if (cimPano) { - for (imx = im1; imx <= im2; imx += iminc) // deliberate margins v.11.03 - cimOffs[imx].yf += 10; - hhmax += 20; - } - - if (cimPanoV) { - for (imx = im1; imx <= im2; imx += iminc) // deliberate margins v.11.04 - cimOffs[imx].xf += 10; - wwmax += 20; - } - - E3pxm16 = PXM_make(wwmax,hhmax,16); // allocate output image - E3ww = wwmax; - E3hh = hhmax; - } - - for (imx = im1; imx <= im2; imx += iminc) // get ww range of each image - { - ww = cimPXMw[imx]->ww; - hh = cimPXMw[imx]->hh; - tf = cimOffs[imx].tf; - wwlo[imx] = cimOffs[imx].xf; - wwhi[imx] = wwlo[imx] + ww; - wwlo[imx] -= 0.5 * tf * hh; // use midpoint of sloping edges - wwhi[imx] -= 0.5 * tf * hh; - } - - if (cimBlend) { // blend width active - for (imx = im1; imx <= im2-1; imx += iminc) // reduce for blend width - { - if (wwhi[imx] - wwlo[imx+1] > cimBlend) { - bmid = (wwhi[imx] + wwlo[imx+1]) / 2; - wwlo[imx+1] = bmid - cimBlend / 2; - wwhi[imx] = bmid + cimBlend / 2; - } - } - } - - for (ii = 0; ii < Nwt; ii++) // start worker threads v.10.7 - start_wthread(cim_show_images_wthread,&wtnx[ii]); - wait_wthreads(); // wait for completion - - if (cimRedpix) - { - imx = cimRedImage; // paint red pixels for current image - ww = cimPXMw[imx]->ww; // being aligned - hh = cimPXMw[imx]->hh; - - for (ii = 0; ii < ww * hh; ii++) - { - if (cimRedpix[ii]) { - pyr = ii / ww; // red pixel - pxr = ii - pyr * ww; - px3 = cimOffs[imx].xf + pxr * costf[imx] - pyr * sintf[imx] + 0.5; - py3 = cimOffs[imx].yf + pyr * costf[imx] + pxr * sintf[imx] + 0.5; - pix3 = PXMpix(E3pxm16,px3,py3); - pix3[0] = 65535; pix3[1] = pix3[2] = 1; - } - } - } - - mutex_unlock(&Fpixmap_lock); - mwpaint2(); // update window - zmainloop(); // v.11.11.1 - - return; -} - - -void * cim_show_images_wthread(void *arg) // working thread v.10.7 -{ - using namespace cim_show_images_names; - - int index = *((int *) (arg)); - int imx, imy; - int px3, py3; - int vstat, vstat1, vstat2; - int red1, green1, blue1; - int red2, green2, blue2; - int red3, green3, blue3; - double f1, f2, px, py; - uint16 vpix[3], *pix3; - - red1 = green1 = blue1 = 0; - - f1 = f2 = 0.5; // to use if no fblend flag - - for (py3 = index; py3 < E3hh; py3 += Nwt) // loop E3 rows - for (px3 = 0; px3 < E3ww; px3++) // loop E3 columns - { - vstat1 = vstat2 = 0; - - for (imx = imy = im1; imx <= im2; imx += iminc) // find which images overlap this pixel - { - if (px3 < wwlo[imx] || px3 > wwhi[imx]) continue; - px = costf[imx] * (px3 - cimOffs[imx].xf) + sintf[imx] * (py3 - cimOffs[imx].yf); - py = costf[imx] * (py3 - cimOffs[imx].yf) - sintf[imx] * (px3 - cimOffs[imx].xf); - vstat = vpixel(cimPXMw[imx],px,py,vpix); - if (! vstat) continue; - - if (! vstat1) { // first overlapping image - vstat1 = 1; - imy = imx; - red1 = vpix[0]; - green1 = vpix[1]; - blue1 = vpix[2]; - } - else { // second image - vstat2 = 1; - red2 = vpix[0]; - green2 = vpix[1]; - blue2 = vpix[2]; - break; - } - } - - imx = imy; // first of 1 or 2 overlapping images - - if (vstat1) { - if (! vstat2) { - red3 = red1; // use image1 pixel - green3 = green1; - blue3 = blue1; - } - else { // use blended image1 + image2 pixels - if (fblendd) { - f1 = wwhi[imx] - px3; // gradual blend - f2 = px3 - wwlo[imx+1]; - f1 = f1 / (f1 + f2); - f2 = 1.0 - f1; - } - red3 = f1 * red1 + f2 * red2 + 0.5; - green3 = f1 * green1 + f2 * green2 + 0.5; - blue3 = f1 * blue1 + f2 * blue2 + 0.5; - } - } - - else red3 = green3 = blue3 = 0; // no overlapping image, use black pixel - - pix3 = PXMpix(E3pxm16,px3,py3); // output pixel - pix3[0] = red3; - pix3[1] = green3; - pix3[2] = blue3; - } - - exit_wthread(); - return 0; // not executed, avoid gcc warning -} - - -// version for vertical panorama - -void cim_show_Vimages(int fnew, int fblend) // v.11.04 -{ - using namespace cim_show_images_names; - - void * cim_show_Vimages_wthread(void *arg); - - int imx, pxr, pyr, ii, px3, py3; - int ww, hh, wwmin, wwmax, hhmin, hhmax, bmid; - double xf, yf, tf; - uint16 *pix3; - - mutex_lock(&Fpixmap_lock); // stop window updates - - fblendd = fblend; // blend 50/50 or gradual ramp - - im1 = 0; // show all images (pano) - im2 = cimNF-1; - - for (imx = 0; imx < cimNF; imx++) { // pre-calculate - costf[imx] = cos(cimOffs[imx].tf); - sintf[imx] = sin(cimOffs[imx].tf); - } - - if (fnew) PXM_free(E3pxm16); // force new output pixmap - - if (! E3pxm16) // allocate output pixmap - { - wwmin = hhmin = 9999; - wwmax = hhmax = 0; - - for (imx = im1; imx <= im2; imx++) // find min and max ww and hh extents - { - xf = cimOffs[imx].xf; - yf = cimOffs[imx].yf; - tf = cimOffs[imx].tf; - ww = cimPXMw[imx]->ww; - hh = cimPXMw[imx]->hh; - if (xf < wwmin) wwmin = xf; - if (xf - tf * hh < wwmin) wwmin = xf + tf * hh; - if (xf + ww > wwmax) wwmax = xf + ww; - if (xf + ww - tf * hh > wwmax) wwmax = xf + ww - tf * hh; - if (yf < hhmin) hhmin = yf; - if (yf + tf * ww < hhmin) hhmin = yf + tf * ww; - if (yf + hh > hhmax) hhmax = yf + hh; - if (yf + hh + tf * ww > hhmax) hhmax = yf + hh + tf * ww; - } - - for (imx = im1; imx <= im2; imx++) { // align to top and left edges - cimOffs[imx].xf -= wwmin; - cimOffs[imx].yf -= hhmin; - } - wwmax = wwmax - wwmin; - hhmax = hhmax - hhmin; - wwmin = hhmin = 0; - - for (imx = im1; imx <= im2; imx++) // deliberate margins - cimOffs[imx].xf += 10; - wwmax += 20; - - E3pxm16 = PXM_make(wwmax,hhmax,16); // allocate output image - E3ww = wwmax; - E3hh = hhmax; - } - - for (imx = im1; imx <= im2; imx++) // get hh range of each image - { - ww = cimPXMw[imx]->ww; - hh = cimPXMw[imx]->hh; - tf = cimOffs[imx].tf; - hhlo[imx] = cimOffs[imx].yf; - hhhi[imx] = hhlo[imx] + hh; - hhlo[imx] += 0.5 * tf * ww; // use midpoint of sloping edges - hhhi[imx] += 0.5 * tf * ww; - } - - if (cimBlend) { // blend width active - for (imx = im1; imx <= im2-1; imx++) // reduce for blend width - { - if (hhhi[imx] - hhlo[imx+1] > cimBlend) { - bmid = (hhhi[imx] + hhlo[imx+1]) / 2; - hhlo[imx+1] = bmid - cimBlend / 2; - hhhi[imx] = bmid + cimBlend / 2; - } - } - } - - for (ii = 0; ii < Nwt; ii++) // start worker threads v.10.7 - start_wthread(cim_show_Vimages_wthread,&wtnx[ii]); - wait_wthreads(); // wait for completion - - if (cimRedpix) - { - imx = cimRedImage; // paint red pixels for current image - ww = cimPXMw[imx]->ww; // being aligned - hh = cimPXMw[imx]->hh; - - for (ii = 0; ii < ww * hh; ii++) - { - if (cimRedpix[ii]) { - pyr = ii / ww; // red pixel - pxr = ii - pyr * ww; - px3 = cimOffs[imx].xf + pxr * costf[imx] - pyr * sintf[imx] + 0.5; - py3 = cimOffs[imx].yf + pyr * costf[imx] + pxr * sintf[imx] + 0.5; - pix3 = PXMpix(E3pxm16,px3,py3); - pix3[0] = 65535; pix3[1] = pix3[2] = 1; - } - } - } - - mutex_unlock(&Fpixmap_lock); - mwpaint2(); // update window - zmainloop(); // v.11.11.1 - return; -} - - -void * cim_show_Vimages_wthread(void *arg) // working thread v.11.04 -{ - using namespace cim_show_images_names; - - int index = *((int *) (arg)); - int imx, imy; - int px3, py3; - int vstat, vstat1, vstat2; - int red1, green1, blue1; - int red2, green2, blue2; - int red3, green3, blue3; - double f1, f2, px, py; - uint16 vpix[3], *pix3; - - red1 = green1 = blue1 = 0; - - f1 = f2 = 0.5; // to use if no fblend flag - - for (py3 = index; py3 < E3hh; py3 += Nwt) // loop E3 rows - for (px3 = 0; px3 < E3ww; px3++) // loop E3 columns - { - vstat1 = vstat2 = 0; - - for (imx = imy = im1; imx <= im2; imx++) // find which images overlap this pixel - { - if (py3 < hhlo[imx] || py3 > hhhi[imx]) continue; - px = costf[imx] * (px3 - cimOffs[imx].xf) + sintf[imx] * (py3 - cimOffs[imx].yf); - py = costf[imx] * (py3 - cimOffs[imx].yf) - sintf[imx] * (px3 - cimOffs[imx].xf); - vstat = vpixel(cimPXMw[imx],px,py,vpix); - if (! vstat) continue; - - if (! vstat1) { // first overlapping image - vstat1 = 1; - imy = imx; - red1 = vpix[0]; - green1 = vpix[1]; - blue1 = vpix[2]; - } - else { // second image - vstat2 = 1; - red2 = vpix[0]; - green2 = vpix[1]; - blue2 = vpix[2]; - break; - } - } - - imx = imy; // first of 1 or 2 overlapping images - - if (vstat1) { - if (! vstat2) { - red3 = red1; // use image1 pixel - green3 = green1; - blue3 = blue1; - } - else { // use blended image1 + image2 pixels - if (fblendd) { - f1 = hhhi[imx] - py3; // gradual blend - f2 = py3 - hhlo[imx+1]; - f1 = f1 / (f1 + f2); - f2 = 1.0 - f1; - } - red3 = f1 * red1 + f2 * red2 + 0.5; - green3 = f1 * green1 + f2 * green2 + 0.5; - blue3 = f1 * blue1 + f2 * blue2 + 0.5; - } - } - - else red3 = green3 = blue3 = 0; // no overlapping image, use black pixel - - pix3 = PXMpix(E3pxm16,px3,py3); // output pixel - pix3[0] = red3; - pix3[1] = green3; - pix3[2] = blue3; - } - - exit_wthread(); - return 0; // not executed, avoid gcc warning -} - - -// cut-off edges of output image where all input images do not overlap -// (HDR HDF Stack) - -void cim_trim() // v.10.9 -{ - int edgex[8] = { 0, 1, 2, 2, 2, 1, 0, 0 }; // 4 corners and 4 midpoints of rectangle - int edgey[8] = { 0, 0, 0, 1, 2, 2, 2, 1 }; // 0 and 2 mark corners, 1 marks midpoints - int edgewx[4] = { +1, -1, -1, +1 }; - int edgewy[4] = { +1, +1, -1, -1 }; - - int imx, ii, jj, ww, hh, px3, py3, px9, py9; - int wwmin, wwmax, hhmin, hhmax; - double xf, yf, tf, sintf, costf, px, py, wx, wy; - uint16 *pix3, *pix9; - - wwmin = hhmin = 0; - wwmax = E3ww; - hhmax = E3hh; - - for (imx = 0; imx < cimNF; imx++) // loop all images - { - ww = cimPXMw[imx]->ww; // image size - hh = cimPXMw[imx]->hh; - xf = cimOffs[imx].xf; // alignment offsets - yf = cimOffs[imx].yf; - tf = cimOffs[imx].tf; - sintf = sin(tf); - costf = cos(tf); - - for (ii = 0; ii < 8; ii++) // 8 points around image rectangle - { - px = ww * edgex[ii] / 2; // coordinates before warping - py = hh * edgey[ii] / 2; - - if (edgex[ii] != 1 && edgey[ii] != 1) { // if a corner - jj = ii / 2; - wx = cimOffs[imx].wx[jj]; // corner warp - wy = cimOffs[imx].wy[jj]; - if (edgewx[jj] > 0 && wx < 0) px -= wx; // if warp direction inwards, - if (edgewx[jj] < 0 && wx > 0) px -= wx; // reduce px/py by warp - if (edgewy[jj] > 0 && wy < 0) py -= wy; - if (edgewy[jj] < 0 && wy > 0) py -= wy; - } - - px3 = xf + px * costf - py * sintf; // map px/py to output image px3/py3 - py3 = yf + py * costf + px * sintf; - - if (edgex[ii] != 1) { - if (px3 < ww/2 && px3 > wwmin) wwmin = px3; // remember px3/py3 extremes - if (px3 > ww/2 && px3 < wwmax) wwmax = px3; - } - - if (edgey[ii] != 1) { - if (py3 < hh/2 && py3 > hhmin) hhmin = py3; - if (py3 > hh/2 && py3 < hhmax) hhmax = py3; - } - } - } - - wwmin += 2; // compensate rounding - wwmax -= 2; - hhmin += 2; - hhmax -= 2; - - ww = wwmax - wwmin; // new image size - hh = hhmax - hhmin; - - if (ww < 0.7 * E3ww) return; // sanity check - if (hh < 0.7 * E3hh) return; - - E9pxm16 = PXM_make(ww,hh,16); - - for (py3 = hhmin; py3 < hhmax; py3++) // E9 = trimmed E3 - for (px3 = wwmin; px3 < wwmax; px3++) - { - px9 = px3 - wwmin; - py9 = py3 - hhmin; - pix3 = PXMpix(E3pxm16,px3,py3); - pix9 = PXMpix(E9pxm16,px9,py9); - pix9[0] = pix3[0]; - pix9[1] = pix3[1]; - pix9[2] = pix3[2]; - } - - PXM_free(E3pxm16); // E3 = E9 - E3pxm16 = E9pxm16; - E9pxm16 = 0; - E3ww = ww; - E3hh = hh; - - return; -} - - -// dump offsets to stdout - diagnostic tool - -void cim_dump_offsets(cchar *text) -{ - printf("\n offsets: %s \n",text); - - for (int imx = 0; imx < cimNF; imx++) - { - printf(" imx %d x/y/t: %.1f %.1f %.4f w0: %.1f %.1f w1: %.1f %.1f w2: %.1f %.1f w3: %.1f %.1f \n", - imx, cimOffs[imx].xf, cimOffs[imx].yf, cimOffs[imx].tf, - cimOffs[imx].wx[0], cimOffs[imx].wy[0], cimOffs[imx].wx[1], cimOffs[imx].wy[1], - cimOffs[imx].wx[2], cimOffs[imx].wy[2], cimOffs[imx].wx[3], cimOffs[imx].wy[3]); - } - - return; -} - - -/************************************************************************** - - Make an HDR (high dynamic range) image from several images of the same - subject with different exposure levels. The composite image has better - visibility of detail in both the brightest and darkest areas. - -***************************************************************************/ - -int HDRstat; // 1 = OK, 0 = failed or canceled -double HDRinitAlignSize = 160; // initial align image size -double HDRimageIncrease = 1.6; // image size increase per align cycle -double HDRsampSize = 6000; // pixel sample size 11.03 - -double HDRinitSearchRange = 8.0; // initial search range, +/- pixels -double HDRinitSearchStep = 1.0; // initial search step, pixels -double HDRinitWarpRange = 3.0; // initial corner warp range, +/- pixels -double HDRinitWarpStep = 0.67; // initial corner warp step, pixels -double HDRsearchRange = 2.0; // normal search range, +/- pixels -double HDRsearchStep = 0.67; // normal search step, pixels -double HDRwarpRange = 2.0; // normal corner warp range, +/- pixels -double HDRwarpStep = 0.67; // normal corner warp step, pixels - -float *HDRbright = 0; // maps brightness per pixel -zdialog *HDRzd = 0; // tweak dialog -double HDR_respfac[10][1000]; // contribution / image / pixel brightness - -void * HDR_align_thread(void *); // align 2 images -void HDR_brightness(); // compute pixel brightness levels -void HDR_tweak(); // adjust image contribution curves -void * HDR_combine_thread(void *); // combine images per contribution curves - -editfunc EFhdr; // edit function data - - -// menu function - -void m_HDR(GtkWidget *, cchar *) // v.10.7 -{ - char **flist, *ftemp; - int imx, jj, err, px, py, ww, hh; - double diffw, diffh; - double fbright[10], btemp; - double pixsum, fnorm = 3.0 / 65536.0; - uint16 *pixel; - PXM *pxmtemp; - - zfuncs::F1_help_topic = "HDR"; // help topic - - if (mod_keep()) return; // warn unsaved changes - if (! menulock(1)) return; // test menu lock v.11.07 - menulock(0); - - for (imx = 0; imx < 10; imx++) - { // clear all file and PXM data - cimFile[imx] = 0; - cimPXMf[imx] = cimPXMs[imx] = cimPXMw[imx] = 0; - } - - cimNF = 0; - HDRbright = 0; - - flist = zgetfileN(ZTX("Select 2 to 9 files"),"openN",curr_file); // select images to combine - if (! flist) return; - - for (imx = 0; flist[imx]; imx++); // count selected files - if (imx < 2 || imx > 9) { - zmessageACK(mWin,ZTX("Select 2 to 9 files")); - goto cleanup; - } - - cimNF = imx; // file count - for (imx = 0; imx < cimNF; imx++) - cimFile[imx] = strdupz(flist[imx],0,"HDR"); // set up file list - - if (! cim_load_files()) goto cleanup; // load and check all files - - ww = cimPXMf[0]->ww; - hh = cimPXMf[0]->hh; - - for (imx = 1; imx < cimNF; imx++) // check image compatibility - { - diffw = abs(ww - cimPXMf[imx]->ww); - diffw = diffw / ww; - diffh = abs(hh - cimPXMf[imx]->hh); - diffh = diffh / hh; - - if (diffw > 0.02 || diffh > 0.02) { - zmessageACK(mWin,ZTX("Images are not all the same size")); - goto cleanup; - } - } - - free_resources(); // ready to commit - - err = f_open(cimFile[0],0); // curr_file = 1st file in list - if (err) goto cleanup; - - EFhdr.funcname = "HDR"; - if (! edit_setup(EFhdr)) goto cleanup; // setup edit (will lock) - - for (imx = 0; imx < cimNF; imx++) // compute image brightness levels - { - pixsum = 0; - for (py = 0; py < Fhh; py++) - for (px = 0; px < Fww; px++) - { - pixel = PXMpix(cimPXMf[imx],px,py); - pixsum += fnorm * (pixel[0] + pixel[1] + pixel[2]); - } - fbright[imx] = pixsum / (Fww * Fhh); - } - - for (imx = 0; imx < cimNF; imx++) // sort file and pixmap lists - for (jj = imx+1; jj < cimNF; jj++) // by decreasing brightness - { - if (fbright[jj] > fbright[imx]) { // bubble sort - btemp = fbright[jj]; - fbright[jj] = fbright[imx]; - fbright[imx] = btemp; - ftemp = cimFile[jj]; - cimFile[jj] = cimFile[imx]; - cimFile[imx] = ftemp; - pxmtemp = cimPXMf[jj]; - cimPXMf[jj] = cimPXMf[imx]; - cimPXMf[imx] = pxmtemp; - } - } - - start_thread(HDR_align_thread,0); // align each pair of images - wrapup_thread(0); // wait for completion - if (HDRstat != 1) goto cancel; - - HDR_brightness(); // compute pixel brightness levels - if (HDRstat != 1) goto cancel; - - HDR_tweak(); // combine images based on user inputs - if (HDRstat != 1) goto cancel; - - CEF->Fmod = 1; // done - edit_done(EFhdr); - goto cleanup; - -cancel: - edit_cancel(EFhdr); - -cleanup: - - if (flist) { - for (imx = 0; flist[imx]; imx++) // free file list - zfree(flist[imx]); - zfree(flist); - } - - for (imx = 0; imx < cimNF; imx++) { // free cim file and PXM data - if (cimFile[imx]) zfree(cimFile[imx]); - if (cimPXMf[imx]) PXM_free(cimPXMf[imx]); - if (cimPXMs[imx]) PXM_free(cimPXMs[imx]); - if (cimPXMw[imx]) PXM_free(cimPXMw[imx]); - } - - if (HDRbright) zfree(HDRbright); - *SB_text = 0; - - return; -} - - -// HDR align each pair of input images, output combined image to E3pxm16 -// cimPXMf[*] original image -// cimPXMs[*] scaled and color adjusted for pixel comparisons -// cimPXMw[*] warped for display - -void * HDR_align_thread(void *) // v.10.7 -{ - int imx, im1, im2, ww, hh, ii, nn; - double R, maxtf, mintf, midtf; - double xoff, yoff, toff, dxoff, dyoff; - cimoffs offsets[10]; // x/y/t offsets after alignment - - Fzoom = 0; // fit to window if big - Fblowup = 1; // scale up to window if small - Ffuncbusy++; // v.11.01 - cimShrink = 0; // no warp shrinkage (pano) - cimPano = cimPanoV = 0; // no pano mode - - for (imx = 0; imx < cimNF; imx++) // bugfix v.10.8 - memset(&offsets[imx],0,sizeof(cimoffs)); - - for (im1 = 0; im1 < cimNF-1; im1++) // loop each pair of images - { - im2 = im1 + 1; - - memset(&cimOffs[im1],0,sizeof(cimoffs)); // initial image offsets = 0 - memset(&cimOffs[im2],0,sizeof(cimoffs)); - - ww = cimPXMf[im1]->ww; // image dimensions - hh = cimPXMf[im1]->hh; - - nn = ww; // use larger of ww, hh - if (hh > ww) nn = hh; - cimScale = HDRinitAlignSize / nn; // initial align image size - if (cimScale > 1.0) cimScale = 1.0; - - cimBlend = 0; // no blend width (use all) - cim_get_overlap(im1,im2,cimPXMf); // get overlap area - cim_match_colors(im1,im2,cimPXMf); // get color matching factors - - cimSearchRange = HDRinitSearchRange; // initial align search range - cimSearchStep = HDRinitSearchStep; // initial align search step - cimWarpRange = HDRinitWarpRange; // initial align corner warp range - cimWarpStep = HDRinitWarpStep; // initial align corner warp step - cimSampSize = HDRsampSize; // pixel sample size for align/compare - cimNsearch = 0; // reset align search counter - - while (true) // loop, increasing image size - { - cim_scale_image(im1,cimPXMs); // scale images to cimScale - cim_scale_image(im2,cimPXMs); - - cim_adjust_colors(cimPXMs[im1],1); // apply color adjustments - cim_adjust_colors(cimPXMs[im2],2); - - cim_warp_image(im1); // make warped images to show - cim_warp_image(im2); - - cimShowIm1 = im1; // show two images with 50/50 blend - cimShowIm2 = im2; - cimShowAll = 0; - cim_show_images(1,0); // (x/y offsets can change) - - cim_get_overlap(im1,im2,cimPXMs); // get overlap area v.11.04 - cim_get_redpix(im1); // get high-contrast pixels - - cim_align_image(im1,im2); // align im2 to im1 - - zfree(cimRedpix); // clear red pixels - cimRedpix = 0; - - if (cimScale == 1.0) break; // done - - R = HDRimageIncrease; // next larger image size - cimScale = cimScale * R; - if (cimScale > 0.85) { // if close to end, jump to end - R = R / cimScale; - cimScale = 1.0; - } - - cimOffs[im1].xf *= R; // scale offsets for larger image - cimOffs[im1].yf *= R; - cimOffs[im2].xf *= R; - cimOffs[im2].yf *= R; - - for (ii = 0; ii < 4; ii++) { - cimOffs[im1].wx[ii] *= R; - cimOffs[im1].wy[ii] *= R; - cimOffs[im2].wx[ii] *= R; - cimOffs[im2].wy[ii] *= R; - } - - cimSearchRange = HDRsearchRange; // align search range - cimSearchStep = HDRsearchStep; // align search step size - cimWarpRange = HDRwarpRange; // align corner warp range - cimWarpStep = HDRwarpStep; // align corner warp step size - } - - offsets[im2].xf = cimOffs[im2].xf - cimOffs[im1].xf; // save im2 offsets from im1 - offsets[im2].yf = cimOffs[im2].yf - cimOffs[im1].yf; - offsets[im2].tf = cimOffs[im2].tf - cimOffs[im1].tf; - - for (ii = 0; ii < 4; ii++) { - offsets[im2].wx[ii] = cimOffs[im2].wx[ii] - cimOffs[im1].wx[ii]; - offsets[im2].wy[ii] = cimOffs[im2].wy[ii] - cimOffs[im1].wy[ii]; - } - } - - for (imx = 0; imx < cimNF; imx++) // offsets[*] >> cimOffs[*] - cimOffs[imx] = offsets[imx]; - - cimOffs[0].xf = cimOffs[0].yf = cimOffs[0].tf = 0; // image 0 at (0,0,0) - - for (im1 = 0; im1 < cimNF-1; im1++) // absolute offsets for image 1 to last - { - im2 = im1 + 1; - cimOffs[im2].xf += cimOffs[im1].xf; // x/y/t offsets are additive - cimOffs[im2].yf += cimOffs[im1].yf; - cimOffs[im2].tf += cimOffs[im1].tf; - - for (ii = 0; ii < 4; ii++) { // corner warps are additive - cimOffs[im2].wx[ii] += cimOffs[im1].wx[ii]; - cimOffs[im2].wy[ii] += cimOffs[im1].wy[ii]; - } - } - - for (imx = 1; imx < cimNF; imx++) // re-warp to absolute v.10.8 - cim_warp_image(imx); - - toff = cimOffs[0].tf; // balance +/- thetas - maxtf = mintf = toff; - for (imx = 1; imx < cimNF; imx++) { - toff = cimOffs[imx].tf; - if (toff > maxtf) maxtf = toff; - if (toff < mintf) mintf = toff; - } - midtf = 0.5 * (maxtf + mintf); - - for (imx = 0; imx < cimNF; imx++) - cimOffs[imx].tf -= midtf; - - for (im1 = 0; im1 < cimNF-1; im1++) // adjust x/y offsets for images after im1 - for (im2 = im1+1; im2 < cimNF; im2++) // due to im1 theta offset - { - toff = cimOffs[im1].tf; - xoff = cimOffs[im2].xf - cimOffs[im1].xf; - yoff = cimOffs[im2].yf - cimOffs[im1].yf; - dxoff = yoff * sin(toff); - dyoff = xoff * sin(toff); - cimOffs[im2].xf -= dxoff; - cimOffs[im2].yf += dyoff; - } - - Fzoom = Fblowup = 0; - Ffuncbusy--; - HDRstat = 1; - thread_exit(); - return 0; // not executed -} - - -// Compute mean image pixel brightness levels. -// (basis for setting image contributions per brightness level) - -void HDR_brightness() // v.10.7 -{ - int px3, py3, ww, hh, imx, kk, vstat; - double px, py, red, green, blue; - double bright, maxbright, minbright; - double xoff, yoff, sintf[10], costf[10]; - double norm, fnorm = 1.0 / 65536.0; - uint16 vpix[3], *pix3; - - cimScale = 1.0; - - for (imx = 0; imx < cimNF; imx++) // replace alignment images - { // (color adjusted for pixel matching) - PXM_free(cimPXMs[imx]); // with the original images - cimPXMs[imx] = PXM_copy(cimPXMf[imx]); - cim_warp_image(imx); // re-apply warps - } - - for (imx = 0; imx < cimNF; imx++) // pre-calculate trig functions - { - sintf[imx] = sin(cimOffs[imx].tf); - costf[imx] = cos(cimOffs[imx].tf); - } - - ww = E3pxm16->ww; - hh = E3pxm16->hh; - - HDRbright = (float *) zmalloc(ww*hh*sizeof(int),"HDR"); // get memory for brightness array - - minbright = 1.0; - maxbright = 0.0; - - for (py3 = 0; py3 < hh; py3++) // step through all output pixels - for (px3 = 0; px3 < ww; px3++) - { - red = green = blue = 0; - vstat = 0; - - for (imx = 0; imx < cimNF; imx++) // step through all input images - { - xoff = cimOffs[imx].xf; - yoff = cimOffs[imx].yf; - - px = costf[imx] * (px3 - xoff) + sintf[imx] * (py3 - yoff); // image N pixel, after offsets - py = costf[imx] * (py3 - yoff) - sintf[imx] * (px3 - xoff); - vstat = vpixel(cimPXMw[imx],px,py,vpix); - if (! vstat) break; - - red += fnorm * vpix[0]; // sum input pixels - green += fnorm * vpix[1]; - blue += fnorm * vpix[2]; - } - - if (! vstat) { // pixel outside some image - pix3 = PXMpix(E3pxm16,px3,py3); // output pixel = black - pix3[0] = pix3[1] = pix3[2] = 0; - kk = py3 * ww + px3; - HDRbright[kk] = 0; - continue; - } - - bright = (red + green + blue) / (3 * cimNF); // mean pixel brightness, 0.0 to 1.0 - kk = py3 * ww + px3; - HDRbright[kk] = bright; - - if (bright > maxbright) maxbright = bright; - if (bright < minbright) minbright = bright; - - pix3 = PXMpix(E3pxm16,px3,py3); // output pixel - pix3[0] = red * 65535.0 / cimNF; - pix3[1] = green * 65535.0 / cimNF; - pix3[2] = blue * 65535.0 / cimNF; - } - - norm = 0.999 / (maxbright - minbright); // normalize to range 0.0 to 0.999 - - for (int ii = 0; ii < ww * hh; ii++) - HDRbright[ii] = (HDRbright[ii] - minbright) * norm; - - mwpaint2(); // update window - return; -} - - -// Dialog for user to control the contributions of each input image -// while watching the output image which is updated in real time. - -void HDR_tweak() // v.10.7 -{ - int HDR_tweak_event(zdialog *zd, cchar *event); - void HDR_curvedit(int); - - int imx; - double cww = 1.0 / (cimNF-1); - - HDRzd = zdialog_new(ZTX("Adjust Image Contributions"),mWin,Bdone,Bcancel,null); - zdialog_add_widget(HDRzd,"frame","brframe","dialog",0,"expand|space=2"); - zdialog_add_widget(HDRzd,"hbox","hb1","dialog",0); - zdialog_add_widget(HDRzd,"label","lab11","hb1",ZTX("dark pixels"),"space=3"); - zdialog_add_widget(HDRzd,"label","lab12","hb1",0,"expand"); - zdialog_add_widget(HDRzd,"label","lab13","hb1",ZTX("light pixels"),"space=3"); - zdialog_add_widget(HDRzd,"hbox","hb2","dialog",0,"space=3"); - zdialog_add_widget(HDRzd,"label","labf1","hb2",ZTX("file:"),"space=3"); - zdialog_add_widget(HDRzd,"label","labf2","hb2","*"); - - zdialog_add_widget(HDRzd,"hbox","hbcf","dialog",0,"space=5"); - zdialog_add_widget(HDRzd,"label","labcf","hbcf",Bcurvefile,"space=5"); - zdialog_add_widget(HDRzd,"button","load","hbcf",Bopen,"space=5"); - zdialog_add_widget(HDRzd,"button","save","hbcf",Bsave,"space=5"); - - GtkWidget *brframe = zdialog_widget(HDRzd,"brframe"); // set up curve edit - spldat *sd = splcurve_init(brframe,HDR_curvedit); // v.11.01 - EFhdr.curves = sd; - - sd->Nspc = cimNF; // no. curves = no. files - - for (imx = 0; imx < cimNF; imx++) // set up initial response curve - { // anchor points - sd->vert[imx] = 0; - sd->nap[imx] = 2; - sd->apx[imx][0] = 0.01; // flatter curves, v.9.3 - sd->apx[imx][1] = 0.99; - sd->apy[imx][0] = 0.9 - imx * 0.8 * cww; - sd->apy[imx][1] = 0.1 + imx * 0.8 * cww; - splcurve_generate(sd,imx); - } - - start_thread(HDR_combine_thread,0); // start working thread - signal_thread(); - - zdialog_resize(HDRzd,400,360); - zdialog_run(HDRzd,HDR_tweak_event,"-10/20"); // run dialog v.11.07 - zdialog_wait(HDRzd); // wait for completion - - return; -} - - -// dialog event and completion callback function - -int HDR_tweak_event(zdialog *zd, cchar *event) -{ - spldat *sd = EFhdr.curves; - - if (strEqu(event,"load")) { // load saved curve v.11.02 - splcurve_load(sd); - zdialog_stuff(HDRzd,"labf2","*"); - signal_thread(); - return 0; - } - - if (strEqu(event,"save")) { // save curve to file v.11.02 - splcurve_save(sd); - return 0; - } - - if (zd->zstat) // dialog complete - { - wrapup_thread(8); - if (zd->zstat == 1) HDRstat = 1; - else HDRstat = 0; - zdialog_free(HDRzd); - if (HDRstat == 1) cim_trim(); // cut-off edges v.10.9 - } - - return 1; -} - - -// this function is called when a curve is edited - -void HDR_curvedit(int spc) -{ - cchar *pp; - - pp = strrchr(cimFile[spc],'/'); - zdialog_stuff(HDRzd,"labf2",pp+1); - signal_thread(); - return; -} - - -// Combine all input images >> E3pxm16 based on image response curves. - -void * HDR_combine_thread(void *) -{ - void * HDR_combine_wthread(void *arg); - - int imx, ii, kk; - double xlo, xhi, xval, yval, sumrf; - spldat *sd = EFhdr.curves; - - while (true) - { - thread_idle_loop(); // wait for work or exit request - - for (imx = 0; imx < cimNF; imx++) // loop input images - { - ii = sd->nap[imx]; // get low and high anchor points - xlo = sd->apx[imx][0]; // for image response curve - xhi = sd->apx[imx][ii-1]; - if (xlo < 0.02) xlo = 0; // snap-to scale end points - if (xhi > 0.98) xhi = 1; - - for (ii = 0; ii < 1000; ii++) // loop all brightness levels - { - HDR_respfac[imx][ii] = 0; - xval = 0.001 * ii; - if (xval < xlo || xval > xhi) continue; // no influence for brightness level - kk = 1000 * xval; // speedup v.11.06 - yval = sd->yval[imx][kk]; - HDR_respfac[imx][ii] = yval; // = contribution of this input image - } - } - - for (ii = 0; ii < 1000; ii++) // normalize the factors so that - { // they sum to 1.0 - sumrf = 0; - for (imx = 0; imx < cimNF; imx++) - sumrf += HDR_respfac[imx][ii]; - if (! sumrf) continue; - for (imx = 0; imx < cimNF; imx++) - HDR_respfac[imx][ii] = HDR_respfac[imx][ii] / sumrf; - } - - mutex_lock(&Fpixmap_lock); // stop window updates - - for (ii = 0; ii < Nwt; ii++) // start worker threads v.10.7 - start_wthread(HDR_combine_wthread,&wtnx[ii]); - wait_wthreads(); // wait for completion - - mutex_unlock(&Fpixmap_lock); - mwpaint2(); // update window - } - - return 0; // not executed -} - - -void * HDR_combine_wthread(void *arg) // working thread -{ - int index = *((int *) (arg)); - int imx, ww, hh, ii, px3, py3, vstat; - double sintf[10], costf[10], xoff, yoff; - double px, py, red, green, blue, bright, factor; - uint16 vpix[3], *pix3; - - for (imx = 0; imx < cimNF; imx++) // pre-calculate trig functions - { - sintf[imx] = sin(cimOffs[imx].tf); - costf[imx] = cos(cimOffs[imx].tf); - } - - ww = E3pxm16->ww; - hh = E3pxm16->hh; - - for (py3 = index; py3 < hh; py3 += Nwt) // step through all output pixels - for (px3 = 0; px3 < ww; px3++) - { - ii = py3 * ww + px3; - bright = HDRbright[ii]; // mean brightness, 0.0 to 1.0 - ii = 1000 * bright; - - red = green = blue = 0; - - for (imx = 0; imx < cimNF; imx++) // loop input images - { - factor = HDR_respfac[imx][ii]; // image contribution to this pixel - if (! factor) continue; // none - - xoff = cimOffs[imx].xf; - yoff = cimOffs[imx].yf; - - px = costf[imx] * (px3 - xoff) + sintf[imx] * (py3 - yoff); // input virtual pixel mapping to - py = costf[imx] * (py3 - yoff) - sintf[imx] * (px3 - xoff); // this output pixel - - vstat = vpixel(cimPXMw[imx],px,py,vpix); // get input pixel - if (! vstat) continue; - - red += factor * vpix[0]; // accumulate brightness contribution - green += factor * vpix[1]; - blue += factor * vpix[2]; - } - - pix3 = PXMpix(E3pxm16,px3,py3); // output pixel - - pix3[0] = red; // = sum of input pixel contributions - pix3[1] = green; - pix3[2] = blue; - } - - exit_wthread(); - return 0; // not executed -} - - -/************************************************************************** - - Make an HDF (high depth of field) image from several images of the same - subject with different focus settings. Combine the images and allow the - user to "paint" the output composite image using the mouse and choosing - the sharpest input image for each area of the output image. The result - is an image with a depth of field that exceeds the camera capability. - - The images are aligned at the center, but small differences in camera - position (hand-held photos) will cause parallax errors that prevent - perfect alignment of the images. Also, the images with nearer focus - will be slightly larger than those with farther focus. These problems - can be compensated by dragging and warping the images using the mouse. v.10.7 - -**************************************************************************/ - -int HDFstat; // 1 = OK, 0 = failed or canceled -double HDFinitAlignSize = 160; // initial align image size -double HDFimageIncrease = 1.6; // image size increase per align cycle -double HDFsampSize = 6000; // pixel sample size - -double HDFinitSearchRange = 8.0; // initial search range, +/- pixels -double HDFinitSearchStep = 1.0; // initial search step, pixels -double HDFinitWarpRange = 4.0; // initial corner warp range -double HDFinitWarpStep = 1.0; // initial corner warp step -double HDFsearchRange = 2.0; // normal search range -double HDFsearchStep = 1.0; // normal search step -double HDFwarpRange = 1.0; // normal corner warp range v.11.03 -double HDFwarpStep = 0.67; // normal corner warp step - -void * HDF_align_thread(void *); -void HDF_tweak(); -void HDF_mousefunc(); -void * HDF_combine_thread(void *); - -editfunc EFhdf; // edit function data - - -// menu function - -void m_HDF(GtkWidget *, cchar *) // v.10.7 -{ - char **flist; - int imx, err, ww, hh; - double diffw, diffh; - - zfuncs::F1_help_topic = "HDF"; // help topic - - if (mod_keep()) return; // warn unsaved changes - if (! menulock(1)) return; // test menu lock v.11.07 - menulock(0); - - for (imx = 0; imx < 10; imx++) - { // clear all file and PXM data - cimFile[imx] = 0; - cimPXMf[imx] = cimPXMs[imx] = cimPXMw[imx] = 0; - } - - cimNF = 0; - - flist = zgetfileN(ZTX("Select 2 to 9 files"),"openN",curr_file); // select images to combine - if (! flist) return; - - for (imx = 0; flist[imx]; imx++); // count selected files - if (imx < 2 || imx > 9) { - zmessageACK(mWin,ZTX("Select 2 to 9 files")); - goto cleanup; - } - - cimNF = imx; // file count - for (imx = 0; imx < cimNF; imx++) - cimFile[imx] = strdupz(flist[imx],0,"HDF"); // set up file list - - if (! cim_load_files()) goto cleanup; // load and check all files - - ww = cimPXMf[0]->ww; - hh = cimPXMf[0]->hh; - - for (imx = 1; imx < cimNF; imx++) // check image compatibility - { - diffw = abs(ww - cimPXMf[imx]->ww); - diffw = diffw / ww; - diffh = abs(hh - cimPXMf[imx]->hh); - diffh = diffh / hh; - - if (diffw > 0.02 || diffh > 0.02) { - zmessageACK(mWin,ZTX("Images are not all the same size")); - goto cleanup; - } - } - - free_resources(); // ready to commit - - err = f_open(cimFile[0],0); // curr_file = 1st file in list - if (err) goto cleanup; - - EFhdf.funcname = "HDF"; - if (! edit_setup(EFhdf)) goto cleanup; // setup edit (will lock) - - start_thread(HDF_align_thread,0); // align each pair of images - wrapup_thread(0); // wait for completion - if (HDFstat != 1) goto cancel; - - HDF_tweak(); // combine images based on user inputs - if (HDFstat != 1) goto cancel; - - CEF->Fmod = 1; // done - edit_done(EFhdf); - goto cleanup; - -cancel: - edit_cancel(EFhdf); - -cleanup: - - if (flist) { - for (imx = 0; flist[imx]; imx++) // free file list - zfree(flist[imx]); - zfree(flist); - } - - for (imx = 0; imx < cimNF; imx++) { // free cim file and PXM data - if (cimFile[imx]) zfree(cimFile[imx]); - if (cimPXMf[imx]) PXM_free(cimPXMf[imx]); - if (cimPXMs[imx]) PXM_free(cimPXMs[imx]); - if (cimPXMw[imx]) PXM_free(cimPXMw[imx]); - } - - *SB_text = 0; - return; -} - - -// HDF align each pair of input images, output combined image to E3pxm16 -// cimPXMf[*] original image -// cimPXMs[*] scaled and color adjusted for pixel comparisons -// cimPXMw[*] warped for display - -void * HDF_align_thread(void *) // v.10.7 -{ - int imx, im1, im2, ww, hh, ii, nn; - double R, maxtf, mintf, midtf; - double xoff, yoff, toff, dxoff, dyoff; - cimoffs offsets[10]; // x/y/t offsets after alignment - - Fzoom = 0; // fit to window if big - Fblowup = 1; // scale up to window if small - Ffuncbusy++; // v.11.01 - cimShrink = 0; // no warp shrinkage (pano) - cimPano = cimPanoV = 0; // no pano mode - - for (imx = 0; imx < cimNF; imx++) // bugfix v.10.8 - memset(&offsets[imx],0,sizeof(cimoffs)); - - for (im1 = 0; im1 < cimNF-1; im1++) // loop each pair of images - { - im2 = im1 + 1; - - memset(&cimOffs[im1],0,sizeof(cimoffs)); // initial image offsets = 0 - memset(&cimOffs[im2],0,sizeof(cimoffs)); - - ww = cimPXMf[im1]->ww; // image dimensions - hh = cimPXMf[im1]->hh; - - nn = ww; // use larger of ww, hh - if (hh > ww) nn = hh; - cimScale = HDFinitAlignSize / nn; // initial align image size - if (cimScale > 1.0) cimScale = 1.0; - - cimBlend = 0; // no blend width (use all) - cim_get_overlap(im1,im2,cimPXMf); // get overlap area - cim_match_colors(im1,im2,cimPXMf); // get color matching factors - - cimSearchRange = HDFinitSearchRange; // initial align search range - cimSearchStep = HDFinitSearchStep; // initial align search step - cimWarpRange = HDFinitWarpRange; // initial align corner warp range - cimWarpStep = HDFinitWarpStep; // initial align corner warp step - cimSampSize = HDFsampSize; // pixel sample size for align/compare - cimNsearch = 0; // reset align search counter - - while (true) // loop, increasing image size - { - cim_scale_image(im1,cimPXMs); // scale images to cimScale - cim_scale_image(im2,cimPXMs); - - cim_adjust_colors(cimPXMs[im1],1); // apply color adjustments - cim_adjust_colors(cimPXMs[im2],2); - - cim_warp_image(im1); // warp images for show - cim_warp_image(im2); - - cimShowIm1 = im1; // show these two images - cimShowIm2 = im2; // with 50/50 blend - cimShowAll = 0; - cim_show_images(1,0); // (y offset can change) - - cim_get_overlap(im1,im2,cimPXMs); // get overlap area v.11.04 - cim_get_redpix(im1); // get high-contrast pixels - - cim_align_image(im1,im2); // align im2 to im1 - - zfree(cimRedpix); // clear red pixels - cimRedpix = 0; - - if (cimScale == 1.0) break; // done - - R = HDFimageIncrease; // next larger image size - cimScale = cimScale * R; - if (cimScale > 0.85) { // if close to end, jump to end - R = R / cimScale; - cimScale = 1.0; - } - - cimOffs[im1].xf *= R; // scale offsets for larger image - cimOffs[im1].yf *= R; - cimOffs[im2].xf *= R; - cimOffs[im2].yf *= R; - - for (ii = 0; ii < 4; ii++) { - cimOffs[im1].wx[ii] *= R; - cimOffs[im1].wy[ii] *= R; - cimOffs[im2].wx[ii] *= R; - cimOffs[im2].wy[ii] *= R; - } - - cimSearchRange = HDFsearchRange; // align search range - cimSearchStep = HDFsearchStep; // align search step size - cimWarpRange = HDFwarpRange; // align corner warp range - cimWarpStep = HDFwarpStep; // align corner warp step size - } - - offsets[im2].xf = cimOffs[im2].xf - cimOffs[im1].xf; // save im2 offsets from im1 - offsets[im2].yf = cimOffs[im2].yf - cimOffs[im1].yf; - offsets[im2].tf = cimOffs[im2].tf - cimOffs[im1].tf; - - for (ii = 0; ii < 4; ii++) { - offsets[im2].wx[ii] = cimOffs[im2].wx[ii] - cimOffs[im1].wx[ii]; - offsets[im2].wy[ii] = cimOffs[im2].wy[ii] - cimOffs[im1].wy[ii]; - } - } - - for (imx = 0; imx < cimNF; imx++) // offsets[*] >> cimOffs[*] - cimOffs[imx] = offsets[imx]; - - cimOffs[0].xf = cimOffs[0].yf = cimOffs[0].tf = 0; // image 0 at (0,0,0) - - for (im1 = 0; im1 < cimNF-1; im1++) // absolute offsets for image 1 to last - { - im2 = im1 + 1; - cimOffs[im2].xf += cimOffs[im1].xf; // x/y/t offsets are additive - cimOffs[im2].yf += cimOffs[im1].yf; - cimOffs[im2].tf += cimOffs[im1].tf; - - for (ii = 0; ii < 4; ii++) { // corner warps are additive - cimOffs[im2].wx[ii] += cimOffs[im1].wx[ii]; - cimOffs[im2].wy[ii] += cimOffs[im1].wy[ii]; - } - } - - for (imx = 1; imx < cimNF; imx++) // re-warp to absolute v.10.8 - cim_warp_image(imx); - - toff = cimOffs[0].tf; // balance +/- thetas - maxtf = mintf = toff; - for (imx = 1; imx < cimNF; imx++) { - toff = cimOffs[imx].tf; - if (toff > maxtf) maxtf = toff; - if (toff < mintf) mintf = toff; - } - midtf = 0.5 * (maxtf + mintf); - - for (imx = 0; imx < cimNF; imx++) - cimOffs[imx].tf -= midtf; - - for (im1 = 0; im1 < cimNF-1; im1++) // adjust x/y offsets for images after im1 - for (im2 = im1+1; im2 < cimNF; im2++) // due to im1 theta offset - { - toff = cimOffs[im1].tf; - xoff = cimOffs[im2].xf - cimOffs[im1].xf; - yoff = cimOffs[im2].yf - cimOffs[im1].yf; - dxoff = yoff * sin(toff); - dyoff = xoff * sin(toff); - cimOffs[im2].xf -= dxoff; - cimOffs[im2].yf += dyoff; - } - - for (imx = 0; imx < cimNF; imx++) // use final warped images as basis - { // for manual align adjustments - PXM_free(cimPXMs[imx]); // bugfix v.11.04 - cimPXMs[imx] = PXM_copy(cimPXMw[imx]); - } - - Fzoom = Fblowup = 0; - Ffuncbusy--; - HDFstat = 1; - thread_exit(); - return 0; // not executed -} - - -// paint and warp output image - -zdialog *HDFzd = 0; // paint dialog -int HDFmode; // mode: paint or warp -int HDFimage; // current image (0 based) -int HDFradius; // paint mode radius -char *HDFpixmap = 0; // map input image per output pixel -float *HDFwarpx[10], *HDFwarpy[10]; // warp memory, pixel displacements - - -void HDF_tweak() // v.10.7 -{ - char imageN[8] = "imageN", labN[4] = "0"; - int cc, imx, ww, hh; - - int HDF_tweak_dialog_event(zdialog *zd, cchar *event); - - // image (o) 1 (o) 2 (o) 3 ... - // (o) paint radius [___] - // (o) warp [__] - // [x] my mouse - - HDFzd = zdialog_new(ZTX("Paint and Warp Image"),mWin,Bdone,Bcancel,null); - - zdialog_add_widget(HDFzd,"hbox","hbim","dialog",0,"space=3"); - zdialog_add_widget(HDFzd,"label","labim","hbim",ZTX("image"),"space=5"); - zdialog_add_widget(HDFzd,"hbox","hbpw","dialog",0,"space=3"); - zdialog_add_widget(HDFzd,"vbox","vbpw1","hbpw",0,"homog|space=5"); - zdialog_add_widget(HDFzd,"vbox","vbpw2","hbpw",0,"homog|space=5"); - zdialog_add_widget(HDFzd,"radio","paint","vbpw1",ZTX("paint")); - zdialog_add_widget(HDFzd,"radio","warp","vbpw1",ZTX("warp")); - zdialog_add_widget(HDFzd,"hbox","hbp","vbpw2"); - zdialog_add_widget(HDFzd,"label","labpr","hbp",Bradius,"space=5"); - zdialog_add_widget(HDFzd,"spin","radius","hbp","1|400|1|100"); - zdialog_add_widget(HDFzd,"label","space","vbpw2"); - zdialog_add_widget(HDFzd,"hbox","hbsr","dialog"); - zdialog_add_widget(HDFzd,"check","mymouse","hbsr",BmyMouse,"space=5"); - - for (imx = 0; imx < cimNF; imx++) { // add radio button for each image - imageN[5] = '1' + imx; - labN[0] = '1' + imx; - zdialog_add_widget(HDFzd,"radio",imageN,"hbim",labN); - } - - zdialog_stuff(HDFzd,"paint",1); // paint button on - zdialog_stuff(HDFzd,"warp",0); // warp button off - zdialog_stuff(HDFzd,"image1",1); // initial image = 1st - - HDFmode = 0; // start in paint mode - HDFimage = 0; // initial image - HDFradius = 100; // paint radius - - takeMouse(HDFzd,HDF_mousefunc,0); // connect mouse function v.10.12 - - cc = E3ww * E3hh; // allocate pixel map - HDFpixmap = zmalloc(cc,"HDF"); - memset(HDFpixmap,cimNF,cc); // initial state, blend all images - - for (imx = 0; imx < cimNF; imx++) { // allocate warp memory - ww = cimPXMw[imx]->ww; - hh = cimPXMw[imx]->hh; - HDFwarpx[imx] = (float *) zmalloc(ww * hh * sizeof(float),"HDF"); - HDFwarpy[imx] = (float *) zmalloc(ww * hh * sizeof(float),"HDF"); - } - - start_thread(HDF_combine_thread,0); // start working thread - signal_thread(); - - zdialog_resize(HDFzd,250,0); // stretch a bit v.11.07 - zdialog_run(HDFzd,HDF_tweak_dialog_event,"-10/20"); // run dialog, parallel v.11.07 - zdialog_wait(HDFzd); // wait for completion - - return; -} - - -// dialog event and completion callback function - -int HDF_tweak_dialog_event(zdialog *zd, cchar *event) // v.10.7 -{ - int imx, nn, mymouse; - - if (zd->zstat) // dialog finish - { - freeMouse(); // disconnect mouse function v.10.12 - signal_thread(); - wrapup_thread(8); - if (zd->zstat == 1) HDFstat = 1; - else HDFstat = 0; - if (HDFstat == 1) cim_trim(); // cut-off edges v.10.9 - zdialog_free(HDFzd); - HDFmode = 0; - zfree(HDFpixmap); // free pixel map - for (imx = 0; imx < cimNF; imx++) { - zfree(HDFwarpx[imx]); // free warp memory - zfree(HDFwarpy[imx]); - } - } - - if (strEqu(event,"paint")) { // set paint mode - zdialog_fetch(zd,"paint",nn); - if (! nn) return 1; - HDFmode = 0; - gdk_window_set_cursor(drWin->window,0); // no drag cursor v.11.03 - } - - if (strEqu(event,"warp")) { // set warp mode - zdialog_fetch(zd,"warp",nn); - if (! nn) return 1; - HDFmode = 1; - paint_toparc(2); // stop brush outline - zdialog_fetch(zd,"mymouse",mymouse); - if (mymouse) - gdk_window_set_cursor(drWin->window,dragcursor); // set drag cursor v.11.03 - } - - if (strnEqu(event,"image",5)) { // image radio button - nn = event[5] - '0'; // 1 to cimNF - if (nn > 0 && nn <= cimNF) - HDFimage = nn - 1; // 0 to cimNF-1 - signal_thread(); - } - - if (strEqu(event,"radius")) // change paint radius - zdialog_fetch(zd,"radius",HDFradius); - - if (strEqu(event,"mymouse")) { // toggle mouse capture v.10.12 - zdialog_fetch(zd,"mymouse",mymouse); - if (mymouse) { - takeMouse(zd,HDF_mousefunc,0); // connect mouse function - if (HDFmode == 1) - gdk_window_set_cursor(drWin->window,dragcursor); // warp mode, drag cursor v.11.03 - signal_thread(); - } - else freeMouse(); // disconnect mouse - } - - return 1; -} - - -// HDF dialog mouse function -// paint: during drag, selected image >> HDFpixmap (within paint radius) >> E3 -// warp: for selected image, cimPXMs >> warp >> cimPXMw >> E3 - -void HDF_mousefunc() // v.10.7 -{ - uint16 vpix1[3], *pix2, *pix3; - int imx, radius, radius2, vstat1; - int mx, my, dx, dy, px3, py3; - char imageN[8] = "imageN"; - double px1, py1; - double xoff, yoff, sintf[10], costf[10]; - int ii, px, py, ww, hh; - double mag, dispx, dispy, d1, d2; - PXM *pxm1, *pxm2; - - if (HDFmode == 0) goto paint; - if (HDFmode == 1) goto warp; - return; - -paint: - - radius = HDFradius; // paintbrush radius - radius2 = radius * radius; - - toparcx = Mxposn - radius; // paintbrush outline circle - toparcy = Myposn - radius; - toparcw = toparch = 2 * radius; - Ftoparc = 1; - paint_toparc(3); - - if (LMclick || RMclick) { // mouse click - LMclick = RMclick = 0; - return; // ignore v.10.8 - } - - else if (Mxdrag || Mydrag) { // drag in progress - mx = Mxdrag; - my = Mydrag; - } - - else return; - - if (mx < 0 || mx > E3ww-1 || my < 0 || my > E3hh-1) // mouse outside image area - return; - - for (imx = 0; imx < cimNF; imx++) // pre-calculate trig funcs - { - sintf[imx] = sin(cimOffs[imx].tf); - costf[imx] = cos(cimOffs[imx].tf); - } - - for (dy = -radius; dy <= radius; dy++) // loop pixels around mouse - for (dx = -radius; dx <= radius; dx++) - { - if (dx*dx + dy*dy > radius2) continue; // outside radius - - px3 = mx + dx; // output pixel - py3 = my + dy; - if (px3 < 0 || px3 > E3ww-1) continue; // outside image - if (py3 < 0 || py3 > E3hh-1) continue; - - pix3 = PXMpix(E3pxm16,px3,py3); // output pixel - - imx = py3 * E3ww + px3; // update pixmap to selected image - HDFpixmap[imx] = HDFimage; - - imx = HDFimage; - xoff = cimOffs[imx].xf; - yoff = cimOffs[imx].yf; - px1 = costf[imx] * (px3 - xoff) + sintf[imx] * (py3 - yoff); // input virtual pixel - py1 = costf[imx] * (py3 - yoff) - sintf[imx] * (px3 - xoff); - vstat1 = vpixel(cimPXMw[imx],px1,py1,vpix1); - if (vstat1) { - pix3[0] = vpix1[0]; - pix3[1] = vpix1[1]; - pix3[2] = vpix1[2]; - } - else pix3[0] = pix3[1] = pix3[2] = 0; - } - - mx = mx - radius - 1; // update window v.10.12 - my = my - radius - 1; - ww = 2 * radius + 3; - paint_toparc(2); - mwpaint3(mx,my,ww,ww); - Ftoparc = 1; - paint_toparc(3); - - return; - -warp: - - if (LMclick || RMclick) { // mouse click - LMclick = RMclick = 0; // ignore v.10.8 - return; - } - - else if (Mxdrag || Mydrag) { // drag in progress - mx = Mxdrag; - my = Mydrag; - } - - else return; - - if (mx < 0 || mx > E3ww-1 || my < 0 || my > E3hh-1) // mouse outside image area - return; - - imx = my * E3ww + mx; // if pixel has been painted, - imx = HDFpixmap[imx]; // select corresp. image to warp - if (imx == cimNF) return; // else no action v.10.8 - - if (imx != HDFimage) { - HDFimage = imx; // update selected image and - imageN[5] = '1' + imx; // dialog radio button - zdialog_stuff(HDFzd,imageN,1); - } - - pxm1 = cimPXMs[imx]; // input image - pxm2 = cimPXMw[imx]; // output image - ww = pxm2->ww; - hh = pxm2->hh; - - mx = Mxdown; // drag origin, image coordinates - my = Mydown; - dx = Mxdrag - Mxdown; // drag increment - dy = Mydrag - Mydown; - Mxdown = Mxdrag; // next drag origin - Mydown = Mydrag; - - d1 = ww * ww + hh * hh; - - for (py = 0; py < hh; py++) // process all output pixels - for (px = 0; px < ww; px++) - { - d2 = (px-mx)*(px-mx) + (py-my)*(py-my); - mag = (1.0 - d2 / d1); - mag = mag * mag * mag * mag; - mag = mag * mag * mag * mag; - mag = mag * mag * mag * mag; - - dispx = -dx * mag; // displacement = drag * mag - dispy = -dy * mag; - - ii = py * ww + px; - HDFwarpx[imx][ii] += dispx; // add this drag to prior sum - HDFwarpy[imx][ii] += dispy; - - dispx = HDFwarpx[imx][ii]; - dispy = HDFwarpy[imx][ii]; - - vstat1 = vpixel(pxm1,px+dispx,py+dispy,vpix1); // input virtual pixel - pix2 = PXMpix(pxm2,px,py); // output pixel - if (vstat1) { - pix2[0] = vpix1[0]; - pix2[1] = vpix1[1]; - pix2[2] = vpix1[2]; - } - else pix2[0] = pix2[1] = pix2[2] = 0; - } - - signal_thread(); // combine images >> E3 >> main window - return; -} - - -// Combine images in E3pxm16 (not reallocated). Update main window. - -void * HDF_combine_thread(void *) // v.10.7 -{ - void * HDF_combine_wthread(void *); - - while (true) - { - thread_idle_loop(); // wait for work or exit request - - mutex_lock(&Fpixmap_lock); // stop window updates - - for (int ii = 0; ii < Nwt; ii++) // start worker threads v.10.7 - start_wthread(HDF_combine_wthread,&wtnx[ii]); - wait_wthreads(); // wait for completion - - mutex_unlock(&Fpixmap_lock); // update window - mwpaint2(); - } - - return 0; // not executed -} - - -void * HDF_combine_wthread(void *arg) // worker thread -{ - int index = *((int *) (arg)); // no more paint and warp modes v.10.8 - int px3, py3, vstat1; - int imx, red, green, blue; - double px, py; - double xoff, yoff, sintf[10], costf[10]; - uint16 vpix1[3], *pix3; - - for (imx = 0; imx < cimNF; imx++) // pre-calculate trig funcs - { - sintf[imx] = sin(cimOffs[imx].tf); - costf[imx] = cos(cimOffs[imx].tf); - } - - for (py3 = index+1; py3 < E3hh-1; py3 += Nwt) // step through output pixels - for (px3 = 1; px3 < E3ww-1; px3++) - { - pix3 = PXMpix(E3pxm16,px3,py3); - - imx = py3 * E3ww + px3; - imx = HDFpixmap[imx]; - - if (imx < cimNF) // specific image maps to pixel - { - xoff = cimOffs[imx].xf; - yoff = cimOffs[imx].yf; - px = costf[imx] * (px3 - xoff) + sintf[imx] * (py3 - yoff); - py = costf[imx] * (py3 - yoff) - sintf[imx] * (px3 - xoff); - vstat1 = vpixel(cimPXMw[imx],px,py,vpix1); // corresp. input vpixel - if (vstat1) { - pix3[0] = vpix1[0]; - pix3[1] = vpix1[1]; - pix3[2] = vpix1[2]; - } - else pix3[0] = pix3[1] = pix3[2] = 0; - } - - else // use blend of all images - { - red = green = blue = 0; - - for (imx = 0; imx < cimNF; imx++) - { - xoff = cimOffs[imx].xf; - yoff = cimOffs[imx].yf; - px = costf[imx] * (px3 - xoff) + sintf[imx] * (py3 - yoff); - py = costf[imx] * (py3 - yoff) - sintf[imx] * (px3 - xoff); - vstat1 = vpixel(cimPXMw[imx],px,py,vpix1); - if (vstat1) { - red += vpix1[0]; - green += vpix1[1]; - blue += vpix1[2]; - } - } - - pix3[0] = red / cimNF; - pix3[1] = green / cimNF; - pix3[2] = blue / cimNF; - } - } - - exit_wthread(); - return 0; // not executed, avoid gcc warning -} - - -/************************************************************************** - - Stack/Paint function - Combine multiple images of one subject taken at different times from - (almost) the same camera position. Align the images and allow the user - to choose which input image to use for each area of the output image, - by "painting" with the mouse. Use this to remove tourists and cars that - move in and out of a scene being photographed. - -**************************************************************************/ - -int STPstat; // 1 = OK, 0 = failed or canceled -double STPinitAlignSize = 160; // initial align image size -double STPimageIncrease = 1.6; // image size increase per align cycle -double STPsampSize = 10000; // pixel sample size v.11.03 - -double STPinitSearchRange = 5.0; // initial search range, +/- pixels -double STPinitSearchStep = 1.0; // initial search step, pixels -double STPinitWarpRange = 2.0; // initial corner warp range -double STPinitWarpStep = 1.0; // initial corner warp step -double STPsearchRange = 2.0; // normal search range -double STPsearchStep = 1.0; // normal search step -double STPwarpRange = 1.0; // normal corner warp range -double STPwarpStep = 0.67; // normal corner warp step - -void * STP_align_thread(void *); -void STP_tweak(); -void STP_mousefunc(); -void * STP_combine_thread(void *); - -editfunc EFstp; // edit function data - - -// menu function - -void m_STP(GtkWidget *, cchar *) // v.11.02 -{ - char **flist; - int imx, err, ww, hh; - double diffw, diffh; - - zfuncs::F1_help_topic = "stack_paint"; // help topic - - if (mod_keep()) return; // warn unsaved changes - if (! menulock(1)) return; // test menu lock v.11.07 - menulock(0); - - for (imx = 0; imx < 10; imx++) - { // clear all file and PXM data - cimFile[imx] = 0; - cimPXMf[imx] = cimPXMs[imx] = cimPXMw[imx] = 0; - } - - cimNF = 0; - - flist = zgetfileN(ZTX("Select 2 to 9 files"),"openN",curr_file); // select images to combine - if (! flist) return; - - for (imx = 0; flist[imx]; imx++); // count selected files - if (imx < 2 || imx > 9) { - zmessageACK(mWin,ZTX("Select 2 to 9 files")); - goto cleanup; - } - - cimNF = imx; // file count - for (imx = 0; imx < cimNF; imx++) - cimFile[imx] = strdupz(flist[imx],0,"STP"); // set up file list - - if (! cim_load_files()) goto cleanup; // load and check all files - - ww = cimPXMf[0]->ww; - hh = cimPXMf[0]->hh; - - for (imx = 1; imx < cimNF; imx++) // check image compatibility - { - diffw = abs(ww - cimPXMf[imx]->ww); - diffw = diffw / ww; - diffh = abs(hh - cimPXMf[imx]->hh); - diffh = diffh / hh; - - if (diffw > 0.02 || diffh > 0.02) { - zmessageACK(mWin,ZTX("Images are not all the same size")); - goto cleanup; - } - } - - free_resources(); // ready to commit - - err = f_open(cimFile[0],0); // curr_file = 1st file in list - if (err) goto cleanup; - - EFstp.funcname = "stack-paint"; - if (! edit_setup(EFstp)) goto cleanup; // setup edit (will lock) - - start_thread(STP_align_thread,0); // align each pair of images - wrapup_thread(0); // wait for completion - if (STPstat != 1) goto cancel; - - STP_tweak(); // combine images based on user inputs - if (STPstat != 1) goto cancel; - - CEF->Fmod = 1; // done - edit_done(EFstp); - goto cleanup; - -cancel: - edit_cancel(EFstp); - -cleanup: - - if (flist) { - for (imx = 0; flist[imx]; imx++) // free file list - zfree(flist[imx]); - zfree(flist); - } - - for (imx = 0; imx < cimNF; imx++) { // free cim file and PXM data - if (cimFile[imx]) zfree(cimFile[imx]); - if (cimPXMf[imx]) PXM_free(cimPXMf[imx]); - if (cimPXMs[imx]) PXM_free(cimPXMs[imx]); - if (cimPXMw[imx]) PXM_free(cimPXMw[imx]); - } - - *SB_text = 0; - return; -} - - -// align each pair of input images, output combined image to E3pxm16 -// cimPXMf[*] original image -// cimPXMs[*] scaled and color adjusted for pixel comparisons -// cimPXMw[*] warped for display - -void * STP_align_thread(void *) // v.11.02 -{ - int imx, im1, im2, ww, hh, ii, nn; - double R, maxtf, mintf, midtf; - double xoff, yoff, toff, dxoff, dyoff; - cimoffs offsets[10]; // x/y/t offsets after alignment - - Fzoom = 0; // fit to window if big - Fblowup = 1; // scale up to window if small - Ffuncbusy++; - cimShrink = 0; // no warp shrinkage (pano) - cimPano = cimPanoV = 0; // no pano mode - - for (imx = 0; imx < cimNF; imx++) - memset(&offsets[imx],0,sizeof(cimoffs)); - - for (im1 = 0; im1 < cimNF-1; im1++) // loop each pair of images - { - im2 = im1 + 1; - - memset(&cimOffs[im1],0,sizeof(cimoffs)); // initial image offsets = 0 - memset(&cimOffs[im2],0,sizeof(cimoffs)); - - ww = cimPXMf[im1]->ww; // image dimensions - hh = cimPXMf[im1]->hh; - - nn = ww; // use larger of ww, hh - if (hh > ww) nn = hh; - cimScale = STPinitAlignSize / nn; // initial align image size - if (cimScale > 1.0) cimScale = 1.0; - - cimBlend = 0; // no blend width (use all) - cim_get_overlap(im1,im2,cimPXMf); // get overlap area - cim_match_colors(im1,im2,cimPXMf); // get color matching factors - - cimSearchRange = STPinitSearchRange; // initial align search range - cimSearchStep = STPinitSearchStep; // initial align search step - cimWarpRange = STPinitWarpRange; // initial align corner warp range - cimWarpStep = STPinitWarpStep; // initial align corner warp step - cimSampSize = STPsampSize; // pixel sample size for align/compare - cimNsearch = 0; // reset align search counter - - while (true) // loop, increasing image size - { - cim_scale_image(im1,cimPXMs); // scale images to cimScale - cim_scale_image(im2,cimPXMs); - - cim_adjust_colors(cimPXMs[im1],1); // apply color adjustments - cim_adjust_colors(cimPXMs[im2],2); - - cim_warp_image(im1); // warp images for show - cim_warp_image(im2); - - cimShowIm1 = im1; // show these two images - cimShowIm2 = im2; // with 50/50 blend - cimShowAll = 0; - cim_show_images(1,0); // (y offset can change) - - cim_get_overlap(im1,im2,cimPXMs); // get overlap area v.11.04 - cim_get_redpix(im1); // get high-contrast pixels - - cim_align_image(im1,im2); // align im2 to im1 - - zfree(cimRedpix); // clear red pixels - cimRedpix = 0; - - if (cimScale == 1.0) break; // done - - R = STPimageIncrease; // next larger image size - cimScale = cimScale * R; - if (cimScale > 0.85) { // if close to end, jump to end - R = R / cimScale; - cimScale = 1.0; - } - - cimOffs[im1].xf *= R; // scale offsets for larger image - cimOffs[im1].yf *= R; - cimOffs[im2].xf *= R; - cimOffs[im2].yf *= R; - - for (ii = 0; ii < 4; ii++) { - cimOffs[im1].wx[ii] *= R; - cimOffs[im1].wy[ii] *= R; - cimOffs[im2].wx[ii] *= R; - cimOffs[im2].wy[ii] *= R; - } - - cimSearchRange = STPsearchRange; // align search range - cimSearchStep = STPsearchStep; // align search step size - cimWarpRange = STPwarpRange; // align corner warp range - cimWarpStep = STPwarpStep; // align corner warp step size - } - - offsets[im2].xf = cimOffs[im2].xf - cimOffs[im1].xf; // save im2 offsets from im1 - offsets[im2].yf = cimOffs[im2].yf - cimOffs[im1].yf; - offsets[im2].tf = cimOffs[im2].tf - cimOffs[im1].tf; - - for (ii = 0; ii < 4; ii++) { - offsets[im2].wx[ii] = cimOffs[im2].wx[ii] - cimOffs[im1].wx[ii]; - offsets[im2].wy[ii] = cimOffs[im2].wy[ii] - cimOffs[im1].wy[ii]; - } - } - - for (imx = 0; imx < cimNF; imx++) // offsets[*] >> cimOffs[*] - cimOffs[imx] = offsets[imx]; - - cimOffs[0].xf = cimOffs[0].yf = cimOffs[0].tf = 0; // image 0 at (0,0,0) - - for (im1 = 0; im1 < cimNF-1; im1++) // absolute offsets for image 1 to last - { - im2 = im1 + 1; - cimOffs[im2].xf += cimOffs[im1].xf; // x/y/t offsets are additive - cimOffs[im2].yf += cimOffs[im1].yf; - cimOffs[im2].tf += cimOffs[im1].tf; - - for (ii = 0; ii < 4; ii++) { // corner warps are additive - cimOffs[im2].wx[ii] += cimOffs[im1].wx[ii]; - cimOffs[im2].wy[ii] += cimOffs[im1].wy[ii]; - } - } - - for (imx = 1; imx < cimNF; imx++) // re-warp to absolute - cim_warp_image(imx); - - toff = cimOffs[0].tf; // balance +/- thetas - maxtf = mintf = toff; - for (imx = 1; imx < cimNF; imx++) { - toff = cimOffs[imx].tf; - if (toff > maxtf) maxtf = toff; - if (toff < mintf) mintf = toff; - } - midtf = 0.5 * (maxtf + mintf); - - for (imx = 0; imx < cimNF; imx++) - cimOffs[imx].tf -= midtf; - - for (im1 = 0; im1 < cimNF-1; im1++) // adjust x/y offsets for images after im1 - for (im2 = im1+1; im2 < cimNF; im2++) // due to im1 theta offset - { - toff = cimOffs[im1].tf; - xoff = cimOffs[im2].xf - cimOffs[im1].xf; - yoff = cimOffs[im2].yf - cimOffs[im1].yf; - dxoff = yoff * sin(toff); - dyoff = xoff * sin(toff); - cimOffs[im2].xf -= dxoff; - cimOffs[im2].yf += dyoff; - } - - Fzoom = Fblowup = 0; - Ffuncbusy--; - STPstat = 1; - thread_exit(); - return 0; // not executed -} - - -// paint output image - -zdialog *STPzd = 0; // paint dialog -int STPimage; // current image (0 based) -int STPradius; // paint mode radius -char *STPpixmap = 0; // map input image per output pixel - - -void STP_tweak() // v.11.02 -{ - char imageN[8] = "imageN", labN[4] = "0"; - int cc, imx; - - int STP_tweak_dialog_event(zdialog *zd, cchar *event); - - // image (o) 1 (o) 2 (o) 3 ... - // [x] my mouse radius [___] - - STPzd = zdialog_new(ZTX("Select and Paint Image"),mWin,Bdone,Bcancel,null); - zdialog_add_widget(STPzd,"hbox","hbim","dialog",0,"space=3"); - zdialog_add_widget(STPzd,"label","labim","hbim",ZTX("image"),"space=5"); - zdialog_add_widget(STPzd,"hbox","hbmr","dialog",0,"space=3"); - zdialog_add_widget(STPzd,"check","mymouse","hbmr",BmyMouse,"space=5"); - zdialog_add_widget(STPzd,"label","labr","hbmr",Bradius,"space=5"); - zdialog_add_widget(STPzd,"spin","radius","hbmr","1|400|1|100"); - - for (imx = 0; imx < cimNF; imx++) { // add radio button for each image - imageN[5] = '1' + imx; - labN[0] = '1' + imx; - zdialog_add_widget(STPzd,"radio",imageN,"hbim",labN); - } - - zdialog_stuff(STPzd,"image1",1); // initial image = 1st - - STPimage = 0; // initial image - STPradius = 100; // paint radius - - takeMouse(STPzd,STP_mousefunc,0); // connect mouse function - - cc = E3ww * E3hh; // allocate pixel map - STPpixmap = zmalloc(cc,"STP"); - memset(STPpixmap,cimNF,cc); // initial state, blend all images - - start_thread(STP_combine_thread,0); // start working thread - signal_thread(); - - zdialog_run(STPzd,STP_tweak_dialog_event,"-10/20"); // run dialog, parallel v.11.07 - zdialog_wait(STPzd); // wait for completion - - return; -} - - -// dialog event and completion callback function - -int STP_tweak_dialog_event(zdialog *zd, cchar *event) // v.11.02 -{ - int nn, mymouse; - - if (zd->zstat) // dialog finish - { - freeMouse(); // disconnect mouse function - signal_thread(); - wrapup_thread(8); - if (zd->zstat == 1) STPstat = 1; - else STPstat = 0; - if (STPstat == 1) cim_trim(); // cut-off edges - zdialog_free(STPzd); - zfree(STPpixmap); // free pixel map - } - - if (strnEqu(event,"image",5)) { // image radio button - nn = event[5] - '0'; // 1 to cimNF - if (nn > 0 && nn <= cimNF) - STPimage = nn - 1; // 0 to cimNF-1 - signal_thread(); - } - - if (strEqu(event,"radius")) // change paint radius - zdialog_fetch(zd,"radius",STPradius); - - if (strEqu(event,"mymouse")) { // toggle mouse capture - zdialog_fetch(zd,"mymouse",mymouse); - if (mymouse) { - takeMouse(zd,STP_mousefunc,0); // connect mouse function - signal_thread(); - } - else freeMouse(); // disconnect mouse - } - - return 1; -} - - -// STP dialog mouse function -// paint: during drag, selected image >> STPpixmap (within paint radius) >> E3 -// warp: for selected image, cimPXMs >> warp >> cimPXMw >> E3 - -void STP_mousefunc() // v.11.02 -{ - uint16 vpix1[3], *pix3; - int imx, radius, radius2, vstat1; - int mx, my, dx, dy, px3, py3, ww; - double px1, py1; - double xoff, yoff, sintf[10], costf[10]; - - radius = STPradius; // paintbrush radius - radius2 = radius * radius; - - toparcx = Mxposn - radius; // paintbrush outline circle - toparcy = Myposn - radius; - toparcw = toparch = 2 * radius; - Ftoparc = 1; - paint_toparc(3); - - if (LMclick || RMclick) { // mouse click - LMclick = RMclick = 0; - return; // ignore - } - - else if (Mxdrag || Mydrag) { // drag in progress - mx = Mxdrag; - my = Mydrag; - } - - else return; - - if (mx < 0 || mx > E3ww-1 || my < 0 || my > E3hh-1) // mouse outside image area - return; - - for (imx = 0; imx < cimNF; imx++) // pre-calculate trig funcs - { - sintf[imx] = sin(cimOffs[imx].tf); - costf[imx] = cos(cimOffs[imx].tf); - } - - for (dy = -radius; dy <= radius; dy++) // loop pixels around mouse - for (dx = -radius; dx <= radius; dx++) - { - if (dx*dx + dy*dy > radius2) continue; // outside radius - - px3 = mx + dx; // output pixel - py3 = my + dy; - if (px3 < 0 || px3 > E3ww-1) continue; // outside image - if (py3 < 0 || py3 > E3hh-1) continue; - - pix3 = PXMpix(E3pxm16,px3,py3); // output pixel - - imx = py3 * E3ww + px3; // update pixmap to selected image - STPpixmap[imx] = STPimage; - - imx = STPimage; - xoff = cimOffs[imx].xf; - yoff = cimOffs[imx].yf; - px1 = costf[imx] * (px3 - xoff) + sintf[imx] * (py3 - yoff); // input virtual pixel - py1 = costf[imx] * (py3 - yoff) - sintf[imx] * (px3 - xoff); - vstat1 = vpixel(cimPXMw[imx],px1,py1,vpix1); - if (vstat1) { - pix3[0] = vpix1[0]; - pix3[1] = vpix1[1]; - pix3[2] = vpix1[2]; - } - else pix3[0] = pix3[1] = pix3[2] = 0; - } - - mx = mx - radius - 1; // update window - my = my - radius - 1; - ww = 2 * radius + 3; - paint_toparc(2); - mwpaint3(mx,my,ww,ww); - Ftoparc = 1; - paint_toparc(3); - return; -} - - -// Combine images in E3pxm16 (not reallocated). Update main window. - -void * STP_combine_thread(void *) // v.11.02 -{ - void * STP_combine_wthread(void *); - - while (true) - { - thread_idle_loop(); // wait for work or exit request - - mutex_lock(&Fpixmap_lock); // stop window updates - - for (int ii = 0; ii < Nwt; ii++) // start worker threads - start_wthread(STP_combine_wthread,&wtnx[ii]); - wait_wthreads(); // wait for completion - - mutex_unlock(&Fpixmap_lock); // update window - mwpaint2(); - } - - return 0; // not executed -} - - -void * STP_combine_wthread(void *arg) // worker thread -{ - int index = *((int *) (arg)); - int px3, py3, vstat1; - int imx, red, green, blue; - double px, py; - double xoff, yoff, sintf[10], costf[10]; - uint16 vpix1[3], *pix3; - - for (imx = 0; imx < cimNF; imx++) // pre-calculate trig funcs - { - sintf[imx] = sin(cimOffs[imx].tf); - costf[imx] = cos(cimOffs[imx].tf); - } - - for (py3 = index+1; py3 < E3hh-1; py3 += Nwt) // step through output pixels - for (px3 = 1; px3 < E3ww-1; px3++) - { - pix3 = PXMpix(E3pxm16,px3,py3); - - imx = py3 * E3ww + px3; - imx = STPpixmap[imx]; - - if (imx < cimNF) // specific image maps to pixel - { - xoff = cimOffs[imx].xf; - yoff = cimOffs[imx].yf; - px = costf[imx] * (px3 - xoff) + sintf[imx] * (py3 - yoff); - py = costf[imx] * (py3 - yoff) - sintf[imx] * (px3 - xoff); - vstat1 = vpixel(cimPXMw[imx],px,py,vpix1); // corresp. input vpixel - if (vstat1) { - pix3[0] = vpix1[0]; - pix3[1] = vpix1[1]; - pix3[2] = vpix1[2]; - } - else pix3[0] = pix3[1] = pix3[2] = 0; - } - - else // use blend of all images - { - red = green = blue = 0; - - for (imx = 0; imx < cimNF; imx++) - { - xoff = cimOffs[imx].xf; - yoff = cimOffs[imx].yf; - px = costf[imx] * (px3 - xoff) + sintf[imx] * (py3 - yoff); - py = costf[imx] * (py3 - yoff) - sintf[imx] * (px3 - xoff); - vstat1 = vpixel(cimPXMw[imx],px,py,vpix1); - if (vstat1) { - red += vpix1[0]; - green += vpix1[1]; - blue += vpix1[2]; - } - } - - pix3[0] = red / cimNF; - pix3[1] = green / cimNF; - pix3[2] = blue / cimNF; - } - } - - exit_wthread(); - return 0; // not executed, avoid gcc warning -} - - -/************************************************************************** - - Stack/Noise function - Combine multiple photos of the same subject and average the - pixels for noise reduction. - -**************************************************************************/ - -double STN_initAlignSize = 160; // initial align image size -double STN_imageIncrease = 1.6; // image size increase per align cycle -double STN_sampSize = 6000; // pixel sample size - -double STN_initSearchRange = 5.0; // initial search range, +/- pixels -double STN_initSearchStep = 1.0; // initial search step, pixels -double STN_initWarpRange = 2.0; // initial corner warp range -double STN_initWarpStep = 1.0; // initial corner warp step -double STN_searchRange = 2.0; // normal search range -double STN_searchStep = 1.0; // normal search step -double STN_warpRange = 1.0; // normal corner warp range -double STN_warpStep = 0.67; // normal corner warp step - -int STN_stat; // 1 = OK, 0 = failed or canceled -int STN_average = 1, STN_median = 0; // use average/median of input pixels -int STN_exlow = 0, STN_exhigh = 0; // exclude low/high pixel - -void * STN_align_thread(void *); -void STN_tweak(); -void * STN_combine_thread(void *); - -editfunc EFstn; // edit function data - - -// menu function - -void m_STN(GtkWidget *, cchar *) // new v.10.9 -{ - char **flist; - int imx, err, ww, hh; - double diffw, diffh; - - zfuncs::F1_help_topic = "stack_noise"; // help topic - - if (mod_keep()) return; // warn unsaved changes - if (! menulock(1)) return; // test menu lock v.11.07 - menulock(0); - - for (imx = 0; imx < 10; imx++) - { // clear all file and PXM data - cimFile[imx] = 0; - cimPXMf[imx] = cimPXMs[imx] = cimPXMw[imx] = 0; - } - - cimNF = 0; - - flist = zgetfileN(ZTX("Select 2 to 9 files"),"openN",curr_file); // select images to combine - if (! flist) return; - - for (imx = 0; flist[imx]; imx++); // count selected files - if (imx < 2 || imx > 9) { - zmessageACK(mWin,ZTX("Select 2 to 9 files")); - goto cleanup; - } - - cimNF = imx; // file count - for (imx = 0; imx < cimNF; imx++) - cimFile[imx] = strdupz(flist[imx],0,"STN"); // set up file list - - if (! cim_load_files()) goto cleanup; // load and check all files - - ww = cimPXMf[0]->ww; - hh = cimPXMf[0]->hh; - - for (imx = 1; imx < cimNF; imx++) // check image compatibility - { - diffw = abs(ww - cimPXMf[imx]->ww); - diffw = diffw / ww; - diffh = abs(hh - cimPXMf[imx]->hh); - diffh = diffh / hh; - - if (diffw > 0.02 || diffh > 0.02) { - zmessageACK(mWin,ZTX("Images are not all the same size")); - goto cleanup; - } - } - - free_resources(); // ready to commit - - err = f_open(cimFile[0],0); // curr_file = 1st file in list - if (err) goto cleanup; - - EFstn.funcname = "stack-noise"; - if (! edit_setup(EFstn)) goto cleanup; // setup edit (will lock) - - start_thread(STN_align_thread,0); // align each pair of images - wrapup_thread(0); // wait for completion - if (STN_stat != 1) goto cancel; - - STN_tweak(); // combine images based on user inputs - if (STN_stat != 1) goto cancel; - - CEF->Fmod = 1; // done - edit_done(EFstn); - goto cleanup; - -cancel: - edit_cancel(EFstn); - -cleanup: - - if (flist) { - for (imx = 0; flist[imx]; imx++) // free file list - zfree(flist[imx]); - zfree(flist); - } - - for (imx = 0; imx < cimNF; imx++) { // free cim file and PXM data - if (cimFile[imx]) zfree(cimFile[imx]); - if (cimPXMf[imx]) PXM_free(cimPXMf[imx]); - if (cimPXMs[imx]) PXM_free(cimPXMs[imx]); - if (cimPXMw[imx]) PXM_free(cimPXMw[imx]); - } - - *SB_text = 0; - return; -} - - -// align each image 2nd-last to 1st image -// cimPXMf[*] original image -// cimPXMs[*] scaled and color adjusted for pixel comparisons -// cimPXMw[*] warped for display - -void * STN_align_thread(void *) // v.10.9 -{ - int imx, im1, im2, ww, hh, ii, nn; - double R, maxtf, mintf, midtf; - double xoff, yoff, toff, dxoff, dyoff; - - Fzoom = 0; // fit to window if big - Fblowup = 1; // scale up to window if small - Ffuncbusy++; // v.11.01 - cimShrink = 0; // no warp shrinkage (pano) - cimPano = cimPanoV = 0; // no pano mode - - for (imx = 1; imx < cimNF; imx++) // loop 2nd to last image - { - im1 = 0; // images to align - im2 = imx; - - memset(&cimOffs[im1],0,sizeof(cimoffs)); // initial image offsets = 0 - memset(&cimOffs[im2],0,sizeof(cimoffs)); - - ww = cimPXMf[im1]->ww; // image dimensions - hh = cimPXMf[im1]->hh; - - nn = ww; // use larger of ww, hh - if (hh > ww) nn = hh; - cimScale = STN_initAlignSize / nn; // initial align image size - if (cimScale > 1.0) cimScale = 1.0; - - cimBlend = 0; // no blend width (use all) - cim_get_overlap(im1,im2,cimPXMf); // get overlap area - cim_match_colors(im1,im2,cimPXMf); // get color matching factors - - cimSearchRange = STN_initSearchRange; // initial align search range - cimSearchStep = STN_initSearchStep; // initial align search step - cimWarpRange = STN_initWarpRange; // initial align corner warp range - cimWarpStep = STN_initWarpStep; // initial align corner warp step - cimSampSize = STN_sampSize; // pixel sample size for align/compare - cimNsearch = 0; // reset align search counter - - while (true) // loop, increasing image size - { - cim_scale_image(im1,cimPXMs); // scale images to cimScale - cim_scale_image(im2,cimPXMs); - - cim_adjust_colors(cimPXMs[im1],1); // apply color adjustments - cim_adjust_colors(cimPXMs[im2],2); - - cim_warp_image(im1); // warp images for show - cim_warp_image(im2); - - cimShowIm1 = im1; // show these two images - cimShowIm2 = im2; // with 50/50 blend - cimShowAll = 0; - cim_show_images(1,0); // (y offset can change) - - cim_get_overlap(im1,im2,cimPXMs); // get overlap area v.11.04 - cim_get_redpix(im1); // get high-contrast pixels - - cim_align_image(im1,im2); // align im2 to im1 - - zfree(cimRedpix); // clear red pixels - cimRedpix = 0; - - if (cimScale == 1.0) break; // done - - R = STN_imageIncrease; // next larger image size - cimScale = cimScale * R; - if (cimScale > 0.85) { // if close to end, jump to end - R = R / cimScale; - cimScale = 1.0; - } - - cimOffs[im1].xf *= R; // scale offsets for larger image - cimOffs[im1].yf *= R; - cimOffs[im2].xf *= R; - cimOffs[im2].yf *= R; - - for (ii = 0; ii < 4; ii++) { - cimOffs[im1].wx[ii] *= R; - cimOffs[im1].wy[ii] *= R; - cimOffs[im2].wx[ii] *= R; - cimOffs[im2].wy[ii] *= R; - } - - cimSearchRange = STN_searchRange; // align search range - cimSearchStep = STN_searchStep; // align search step size - cimWarpRange = STN_warpRange; // align corner warp range - cimWarpStep = STN_warpStep; // align corner warp step size - } - } - - toff = cimOffs[0].tf; // balance +/- thetas - maxtf = mintf = toff; - for (imx = 1; imx < cimNF; imx++) { - toff = cimOffs[imx].tf; - if (toff > maxtf) maxtf = toff; - if (toff < mintf) mintf = toff; - } - midtf = 0.5 * (maxtf + mintf); - - for (imx = 0; imx < cimNF; imx++) - cimOffs[imx].tf -= midtf; - - for (im1 = 0; im1 < cimNF-1; im1++) // adjust x/y offsets for images after im1 - for (im2 = im1+1; im2 < cimNF; im2++) // due to im1 theta offset - { - toff = cimOffs[im1].tf; - xoff = cimOffs[im2].xf - cimOffs[im1].xf; - yoff = cimOffs[im2].yf - cimOffs[im1].yf; - dxoff = yoff * sin(toff); - dyoff = xoff * sin(toff); - cimOffs[im2].xf -= dxoff; - cimOffs[im2].yf += dyoff; - } - - Fzoom = Fblowup = 0; - Ffuncbusy--; - STN_stat = 1; - thread_exit(); - return 0; // not executed -} - - -// change pixel combination according to user input - -void STN_tweak() // v.10.9 -{ - zdialog *zd; - - int STN_tweak_dialog_event(zdialog *zd, cchar *event); - - // Adjust Pixel Composition - // - // (o) use average (o) use median - // [x] omit lowest value - // [x] omit highest value - - zd = zdialog_new(ZTX("Adjust Pixel Composition"),mWin,Bdone,Bcancel,null); - zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=3"); - zdialog_add_widget(zd,"radio","average","hb1","use average","space=3"); - zdialog_add_widget(zd,"radio","median","hb1","use median","space=3"); - zdialog_add_widget(zd,"hbox","hb2","dialog",0,"space=3"); - zdialog_add_widget(zd,"check","exlow","hb2","omit low pixel","space=3"); - zdialog_add_widget(zd,"check","exhigh","hb2","omit high pixel","space=3"); - - zdialog_stuff(zd,"average",1); // default = average - zdialog_stuff(zd,"median",0); - zdialog_stuff(zd,"exlow",0); - zdialog_stuff(zd,"exhigh",0); - - STN_average = 1; - STN_median = 0; - STN_exlow = 0; - STN_exhigh = 0; - - start_thread(STN_combine_thread,0); // start working thread - signal_thread(); - - zdialog_resize(zd,250,0); - zdialog_run(zd,STN_tweak_dialog_event,"-10/20"); // run dialog, parallel v.11.07 - zdialog_wait(zd); // wait for completion - - return; -} - - -// dialog event and completion callback function - -int STN_tweak_dialog_event(zdialog *zd, cchar *event) // v.10.9 -{ - if (zd->zstat) { // dialog finish - if (zd->zstat == 1) STN_stat = 1; - else STN_stat = 0; - wrapup_thread(8); - zdialog_free(zd); - if (STN_stat == 1) cim_trim(); // trim edges v.10.9 - } - - if (strEqu(event,"average")) { - zdialog_fetch(zd,"average",STN_average); - signal_thread(); - } - - if (strEqu(event,"median")) { - zdialog_fetch(zd,"median",STN_median); - signal_thread(); - } - - if (strEqu(event,"exlow")) { - zdialog_fetch(zd,"exlow",STN_exlow); - signal_thread(); - } - - if (strEqu(event,"exhigh")) { - zdialog_fetch(zd,"exhigh",STN_exhigh); - signal_thread(); - } - - return 1; -} - - -// compute mean/median mix for each output pixel and update E3 image - -void * STN_combine_thread(void *) // v.10.9 -{ - void * STN_combine_wthread(void *arg); // worker thread - - while (true) - { - thread_idle_loop(); // wait for work or exit request - - for (int ii = 0; ii < Nwt; ii++) // start worker threads - start_wthread(STN_combine_wthread,&wtnx[ii]); - wait_wthreads(); // wait for completion - - CEF->Fmod = 1; - mwpaint2(); // update window - } - - return 0; // not executed -} - - -// worker thread - -void * STN_combine_wthread(void *arg) // v.10.9 -{ - int index = *((int *) arg); - int imx, vstat, px3, py3; - int red, green, blue; - int ii, ns, ns1, ns2; - int Rlist[10], Glist[10], Blist[10]; - double px, py; - double xoff, yoff, sintf[10], costf[10]; - uint16 *pix3, vpix[3]; - - // input layers 0 1 2 3 4 5 6 7 8 9 10 - int nsx[11][2] = { {0,0}, {0,0}, {0,1}, {1,1}, {1,2}, {2,2}, {2,3}, {2,4}, {2,5}, {3,5}, {3,6} }; - - for (imx = 0; imx < cimNF; imx++) // pre-calculate trig funcs - { - sintf[imx] = sin(cimOffs[imx].tf); - costf[imx] = cos(cimOffs[imx].tf); - } - - for (py3 = index+1; py3 < E3hh-1; py3 += Nwt) // step through output pixels - for (px3 = 1; px3 < E3ww-1; px3++) - { - for (imx = ns = 0; imx < cimNF; imx++) // get aligned input pixels - { - xoff = cimOffs[imx].xf; - yoff = cimOffs[imx].yf; - px = costf[imx] * (px3 - xoff) + sintf[imx] * (py3 - yoff); - py = costf[imx] * (py3 - yoff) - sintf[imx] * (px3 - xoff); - - vstat = vpixel(cimPXMw[imx],px,py,vpix); - if (vstat) { - Rlist[ns] = vpix[0]; // add pixel RGB values to list - Glist[ns] = vpix[1]; - Blist[ns] = vpix[2]; - ns++; - } - } - - if (! ns) continue; - - if (STN_exlow || STN_exhigh || STN_median) { // RGB values must be sorted - HeapSort(Rlist,ns); - HeapSort(Glist,ns); - HeapSort(Blist,ns); - } - - red = green = blue = 0; - - if (STN_average) // average the input pixels - { - ns1 = 0; // low and high RGB values - ns2 = ns - 1; - - if (STN_exlow) { // exclude low - ns1++; - if (ns1 > ns2) ns1--; - } - - if (STN_exhigh) { // exclude high - ns2--; - if (ns1 > ns2) ns2++; - } - - for (ii = ns1; ii <= ns2; ii++) // sum remaining RGB levels - { - red += Rlist[ii]; - green += Glist[ii]; - blue += Blist[ii]; - } - - ns = ns2 - ns1 + 1; // sample count - - red = red / ns; // output RGB = average - green = green / ns; - blue = blue / ns; - } - - if (STN_median) // use median input pixels - { - ns1 = nsx[ns][0]; // middle group of pixels - ns2 = nsx[ns][1]; - - for (ii = ns1; ii <= ns2; ii++) - { - red += Rlist[ii]; - green += Glist[ii]; - blue += Blist[ii]; - } - - ns = ns2 - ns1 + 1; // sample count - - red = red / ns; // output RGB = average - green = green / ns; - blue = blue / ns; - } - - pix3 = PXMpix(E3pxm16,px3,py3); // output pixel - pix3[0] = red; - pix3[1] = green; - pix3[2] = blue; - } - - exit_wthread(); - return 0; // not executed -} - - -/************************************************************************** - - Panorama function: join 2, 3, or 4 images. - -***************************************************************************/ - -int panStat; // 1 = OK -zdialog *panozd = 0; // pre-align dialog - -double panPreAlignSize = 1000; // pre-align image size (ww) -double panInitAlignSize = 200; // initial align image size -double panImageIncrease = 1.6; // image size increase per align cycle -double panSampSize = 10000; // pixel sample size - -double panPreAlignBlend = 0.30; // pre-align blend width * ww -double panInitBlend = 0.20; // initial blend width during auto-align -double panFinalBlend = 0.08; // final blend width * ww -double panBlendDecrease = 0.8; // blend width reduction per align cycle - -double panInitSearchRange = 5.0; // initial search range, +/- pixels -double panInitSearchStep = 0.7; // initial search step, pixels -double panInitWarpRange = 4.0; // initial corner warp range, +/- pixels -double panInitWarpStep = 1.0; // initial corner warp step, pixels -double panSearchRange = 3.0; // normal search range, +/- pixels -double panSearchStep = 1.0; // normal search step, pixels -double panWarpRange = 2.0; // normal corner warp range, +/- pixels -double panWarpStep = 1.0; // normal corner warp step, pixels - -void pano_prealign(); // manual pre-align -void pano_align(); // auto fine-align -void pano_tweak(); // user color tweak - -editfunc EFpano; // edit function data - - -// menu function - -void m_pano(GtkWidget *, cchar *) // v.10.7 -{ - int imx, err; - char **flist = 0; - - zfuncs::F1_help_topic = "panorama"; // help topic - - if (mod_keep()) return; // warn unsaved changes - if (! menulock(1)) return; // test menu lock v.11.07 - menulock(0); - - for (imx = 0; imx < 10; imx++) - { // clear all file and PXM data - cimFile[imx] = 0; - cimPXMf[imx] = cimPXMs[imx] = cimPXMw[imx] = 0; - } - cimNF = 0; - - flist = zgetfileN(ZTX("Select 2 to 4 files"),"openN",curr_file); // select images to combine - if (! flist) return; - - for (imx = 0; flist[imx]; imx++); // count selected files - if (imx < 2 || imx > 4) { - zmessageACK(mWin,ZTX("Select 2 to 4 files")); - goto cleanup; - } - - cimNF = imx; // file count - for (imx = 0; imx < cimNF; imx++) - cimFile[imx] = strdupz(flist[imx],0,"pano"); // set up file list - - if (! cim_load_files()) goto cleanup; // load and check all files - - free_resources(); // ready to commit - - err = f_open(cimFile[0],0); // curr_file = 1st file in list - if (err) goto cleanup; - - EFpano.funcname = "pano"; - if (! edit_setup(EFpano)) goto cleanup; // setup edit (will lock) - - cimShowAll = 1; // for cim_show_images(), show all v.10.9 - cimShrink = 0; // no warp shrinkage v.11.04 - cimPano = 1; // horizontal pano mode v.11.04 - cimPanoV = 0; - - pano_prealign(); // manual pre-alignment - if (panStat != 1) goto cancel; - - pano_align(); // auto full alignment - if (panStat != 1) goto cancel; - - pano_tweak(); // manual color adjustment - if (panStat != 1) goto cancel; - - CEF->Fmod = 1; // done - edit_done(EFpano); - goto cleanup; - -cancel: // failed or canceled - edit_cancel(EFpano); - -cleanup: - - if (flist) { - for (imx = 0; flist[imx]; imx++) // free file list - zfree(flist[imx]); - zfree(flist); - } - - for (imx = 0; imx < cimNF; imx++) { // free cim file and PXM data - if (cimFile[imx]) zfree(cimFile[imx]); - if (cimPXMf[imx]) PXM_free(cimPXMf[imx]); - if (cimPXMs[imx]) PXM_free(cimPXMs[imx]); - if (cimPXMw[imx]) PXM_free(cimPXMw[imx]); - } - - *SB_text = 0; - return; -} - - -// perform manual pre-align of all images -// returns alignment data in cimOffs[*] -// lens_mm and lens_bow may also be altered - -void pano_prealign() // v.10.7 -{ - int pano_prealign_event(zdialog *zd, cchar *event); // dialog event function - void * pano_prealign_thread(void *); // working thread - - int imx, ww, err = 0; - cchar *exifkey = { exif_focal_length_key }; - char lensname[40], **pp = 0; - - cchar *align_mess = ZTX("Drag images into rough alignment.\n" - "To rotate, drag from lower edge."); - cchar *search_mess = ZTX("Search for lens mm and bow"); - - pp = info_get(curr_file,&exifkey,1); // get lens mm from EXIF if available - if (pp && *pp) { - err = convSD(*pp, lens_mm, 20, 1000); // leave lens_bow unchanged (no source) - strcpy(lensname,"(EXIF)"); // lens name = EXIF - } - - if (! pp || ! *pp || err) { // not available - lens_mm = lens4_mm[curr_lens]; // get curr. lens mm, bow, name - lens_bow = lens4_bow[curr_lens]; - *lensname = 0; - strncatv(lensname,40,"(",lens4_name[curr_lens],")",null); - } - - for (imx = 0; imx < 10; imx++) // set all alignment offsets = 0 - memset(&cimOffs[imx],0,sizeof(cimoffs)); - - for (imx = ww = 0; imx < cimNF; imx++) // sum image widths - ww += cimPXMf[imx]->ww; - - cimScale = 1.4 * panPreAlignSize / ww; // set alignment image scale - if (cimScale > 1.0) cimScale = 1.0; // (* 0.7 after overlaps) - - for (imx = 0; imx < cimNF; imx++) // scale images > cimPXMs[*] - cim_scale_image(imx,cimPXMs); - - for (imx = 0; imx < cimNF; imx++) { // curve images, cimPXMs[*] replaced - cim_curve_image(imx); - cimPXMw[imx] = PXM_copy(cimPXMs[imx]); // copy to cimPXMw[*] for display - } - - cimOffs[0].xf = cimOffs[0].yf = 0; // first image at (0,0) - - for (imx = 1; imx < cimNF; imx++) // position images with 30% overlap - { // in horizontal row - cimOffs[imx].xf = cimOffs[imx-1].xf + 0.7 * cimPXMw[imx-1]->ww; - cimOffs[imx].yf = cimOffs[imx-1].yf; - } - - Fzoom = 0; // scale image to fit window - Fblowup = 1; // magnify small image to window size - - cimBlend = panPreAlignBlend * cimPXMw[1]->ww; // overlap in align window - cim_show_images(1,0); // combine and show images in main window - - panozd = zdialog_new(ZTX("Pre-align Images"),mWin,Bproceed,Bcancel,null); // start pre-align dialog - zdialog_add_widget(panozd,"label","lab1","dialog",align_mess,"space=5"); - zdialog_add_widget(panozd,"hbox","hb1","dialog",0,"space=2"); - zdialog_add_widget(panozd,"spin","spmm","hb1","22|200|0.1|35","space=5"); // [ 35 ] lens mm (source) - zdialog_add_widget(panozd,"label","labmm","hb1",ZTX("lens mm")); // [ 0.3 ] lens bow - zdialog_add_widget(panozd,"label","lablens","hb1","","space=5"); // [resize] resize window - zdialog_add_widget(panozd,"hbox","hb2","dialog",0,"space=2"); // [search] search lens mm and bow - zdialog_add_widget(panozd,"spin","spbow","hb2","-9|9|0.01|0","space=5"); - zdialog_add_widget(panozd,"label","labbow","hb2",ZTX("lens bow")); - zdialog_add_widget(panozd,"hbox","hb3","dialog",0,"space=2"); - zdialog_add_widget(panozd,"button","resize","hb3",ZTX("Resize"),"space=5"); - zdialog_add_widget(panozd,"label","labsiz","hb3",ZTX("resize window"),"space=5"); - zdialog_add_widget(panozd,"hbox","hb4","dialog",0,"space=2"); - zdialog_add_widget(panozd,"button","search","hb4",Bsearch,"space=5"); - zdialog_add_widget(panozd,"label","labsearch","hb4",search_mess,"space=5"); - - zdialog_stuff(panozd,"spmm",lens_mm); // stuff lens data - zdialog_stuff(panozd,"spbow",lens_bow); - zdialog_stuff(panozd,"lablens",lensname); // show source of lens data - - panStat = -1; // busy status - gdk_window_set_cursor(drWin->window,dragcursor); // set drag cursor v.11.03 - zdialog_run(panozd,pano_prealign_event,"-10/20"); // start dialog v.11.07 - start_thread(pano_prealign_thread,0); // start working thread - zdialog_wait(panozd); // wait for dialog completion - gdk_window_set_cursor(drWin->window,0); // restore normal cursor v.11.03 - Fzoom = Fblowup = 0; - return; -} - - -// pre-align dialog event function - -int pano_prealign_event(zdialog *zd, cchar *event) // v.10.7 -{ - int imx; - double overlap; - - if (strstr("spmm spbow",event)) { - zdialog_fetch(zd,"spmm",lens_mm); // get revised lens data - zdialog_fetch(zd,"spbow",lens_bow); - } - - if (strEqu(event,"resize")) // allocate new E3 image - cim_show_images(1,0); - - if (strEqu(event,"search")) { // search for optimal lens parms - if (cimNF != 2) - zmessageACK(mWin,ZTX("use two images only")); - else panStat = 2; // tell thread to search - return 0; - } - - if (zd->zstat) // dialog complete - { - if (zd->zstat == 1) // proceed - panStat = 1; - else // cancel or other - panStat = 0; - - zdialog_free(panozd); // kill dialog - wrapup_thread(0); // wait for thread - - if (! panStat) return 0; // canceled - - for (imx = 0; imx < cimNF-1; imx++) // check for enough overlap - { - overlap = cim_get_overlap(imx,imx+1,cimPXMs); // v.11.04 - if (overlap < panFinalBlend) { // v.11.09 - zmessageACK(mWin,ZTX("Too little overlap, cannot align")); - panStat = 0; - return 0; - } - } - } - - return 0; -} - - -// pre-align working thread -// convert mouse and KB events into image movements // overhauled v.11.02 - -void * pano_prealign_thread(void *) -{ - void pano_autolens(); - - cimoffs offstemp; - PXM *pxmtemp; - char *ftemp; - int im1, im2, imm, imx; - int mx0, my0, mx, my; // mouse drag origin, position - int xoff, yoff, lox, hix; - int sepx, minsep; - int ww, hh, rotate, midx; - double lens_mm0, lens_bow0; - double dx, dy, t1, t2, dt; - - imm = ww = hh = rotate = xoff = yoff = 0; // stop compiler warnings - - lens_mm0 = lens_mm; // to detect changes - lens_bow0 = lens_bow; - - mx0 = my0 = 0; // no drag in progress - Mcapture = KBcapture = 1; // capture mouse drag and KB keys - - cimBlend = 0; // full blend during pre-align - - while (true) // loop and align until done - { - zsleep(0.05); // logic simplified - - if (panStat == 2) { // dialog search button - panStat = -1; // back to busy status - pano_autolens(); - } - - if (panStat != -1) break; // quit signal from dialog - - if (lens_mm != lens_mm0 || lens_bow != lens_bow0) { // change in lens parameters - lens_mm0 = lens_mm; - lens_bow0 = lens_bow; - - for (imx = 0; imx < cimNF; imx++) { // re-curve images - cim_scale_image(imx,cimPXMs); - cim_curve_image(imx); - PXM_free(cimPXMw[imx]); - cimPXMw[imx] = PXM_copy(cimPXMs[imx]); - } - - cim_show_images(1,0); // combine and show images - continue; - } - - if (KBkey) { // KB input - if (KBkey == GDK_Left) cimOffs[imm].xf -= 0.5; // tweak alignment offsets - if (KBkey == GDK_Right) cimOffs[imm].xf += 0.5; - if (KBkey == GDK_Up) cimOffs[imm].yf -= 0.5; - if (KBkey == GDK_Down) cimOffs[imm].yf += 0.5; - if (KBkey == GDK_r) cimOffs[imm].tf += 0.0005; - if (KBkey == GDK_l) cimOffs[imm].tf -= 0.0005; - KBkey = 0; - - cim_show_images(0,0); // combine and show images - continue; - } - - if (! Mxdrag && ! Mydrag) // no drag underway - mx0 = my0 = 0; // reset drag origin - - if (Mxdrag || Mydrag) // mouse drag underway - { - mx = Mxdrag; // mouse position in image - my = Mydrag; - - if (! mx0 && ! my0) // new drag - { - mx0 = mx; // set drag origin - my0 = my; - minsep = 9999; - - for (imx = 0; imx < cimNF; imx++) // find image with midpoint - { // closest to mouse x - lox = cimOffs[imx].xf; - hix = lox + cimPXMw[imx]->ww; - midx = (lox + hix) / 2; - sepx = abs(midx - mx0); - if (sepx < minsep) { - minsep = sepx; - imm = imx; // image to drag or rotate - } - } - - xoff = cimOffs[imm].xf; - yoff = cimOffs[imm].yf; - ww = cimPXMw[imm]->ww; - hh = cimPXMw[imm]->hh; - - rotate = 0; // if drag at bottom edge, - if (my0 > yoff + 0.85 * hh) rotate = 1; // set rotate flag v.11.04 - } - - if (mx != mx0 || my != my0) // drag is progressing - { - dx = mx - mx0; // mouse movement - dy = my - my0; - - if (rotate && my0 > yoff && my > yoff) // rotation - { - if (imm > 0) { - lox = cimOffs[imm].xf; // if there is an image to the left, - hix = cimOffs[imm-1].xf + cimPXMw[imm-1]->ww; // midx = midpoint of overlap - midx = (lox + hix) / 2; - } - else midx = 0; // this is the leftmost image - - t1 = atan(1.0 * (mx0-xoff) / (my0-yoff)); - t2 = atan(1.0 * (mx-xoff) / (my-yoff)); - dt = t1 - t2; // angle change - dx = dt * (hh/2 + yoff); // pivot = middle of overlap on left - dy = -dt * (midx-xoff); - } - - else dt = 0; // x/y drag - - cimOffs[imm].xf += dx; // update image - cimOffs[imm].yf += dy; - cimOffs[imm].tf += dt; - xoff = cimOffs[imm].xf; // v.11.04 - yoff = cimOffs[imm].yf; - - cim_show_images(0,0); // show combined images - - mx0 = mx; // next drag origin = current mouse - my0 = my; - } - } - - for (im1 = 0; im1 < cimNF-1; im1++) // track image order changes - { - im2 = im1 + 1; - if (cimOffs[im2].xf < cimOffs[im1].xf) - { - ftemp = cimFile[im2]; // switch filespecs - cimFile[im2] = cimFile[im1]; - cimFile[im1] = ftemp; - pxmtemp = cimPXMf[im2]; // switch images - cimPXMf[im2] = cimPXMf[im1]; - cimPXMf[im1] = pxmtemp; - pxmtemp = cimPXMs[im2]; // scaled images - cimPXMs[im2] = cimPXMs[im1]; - cimPXMs[im1] = pxmtemp; - pxmtemp = cimPXMw[im2]; // warped images - cimPXMw[im2] = cimPXMw[im1]; - cimPXMw[im1] = pxmtemp; - offstemp = cimOffs[im2]; // offsets - cimOffs[im2] = cimOffs[im1]; - cimOffs[im1] = offstemp; - if (imm == im1) imm = im2; // current drag image - else if (imm == im2) imm = im1; - break; - } - } - } - - KBcapture = Mcapture = 0; - thread_exit(); - return 0; // not executed, stop g++ warning -} - - -// optimize lens parameters -// inputs and outputs: -// pre-aligned images cimPXMw[0] and [1] -// offsets in cimOffs[0] and [1] -// lens_mm, lens_bow - -void pano_autolens() // v.10.7 -{ - double mm_range, bow_range, xf_range, yf_range, tf_range; - double squeeze, xf_rfinal, rnum, matchB, matchlev; - double overlap, lens_mmB, lens_bowB; - int imx, randcount = 0; - cimoffs offsetsB; - - overlap = cim_get_overlap(0,1,cimPXMs); // v.11.04 - if (overlap < 0.1) { - threadmessage = ZTX("Too little overlap, cannot align"); - return; - } - - Ffuncbusy++; // v.11.01 - - cimSampSize = 2000; // v.11.03 - cimNsearch = 0; - - mm_range = 0.1 * lens_mm; // set initial search ranges v.11.03 - bow_range = 0.3 * lens_bow; - if (bow_range < 0.5) bow_range = 0.5; - xf_range = 7; - yf_range = 7; - tf_range = 0.01; - xf_rfinal = 0.3; // final xf range - when to quit - - cim_match_colors(0,1,cimPXMw); // adjust colors for image matching - cim_adjust_colors(cimPXMs[0],1); - cim_adjust_colors(cimPXMw[0],1); - cim_adjust_colors(cimPXMs[1],2); - cim_adjust_colors(cimPXMw[1],2); - - lens_mmB = lens_mm; // starting point - lens_bowB = lens_bow; - offsetsB = cimOffs[1]; - cimSearchRange = 7; - - matchB = 0; - - while (true) - { - srand48(time(0) + randcount++); - lens_mm = lens_mmB + mm_range * (drand48() - 0.5); // new random lens factors - lens_bow = lens_bowB + bow_range * (drand48() - 0.5); // within search range - - for (imx = 0; imx <= 1; imx++) { // re-curve images - cim_scale_image(imx,cimPXMs); - cim_curve_image(imx); - PXM_free(cimPXMw[imx]); - cimPXMw[imx] = PXM_copy(cimPXMs[imx]); - } - - cim_get_redpix(0); // get high-contrast pixels v.11.03 - cim_show_images(0,0); // combine and show images - - squeeze = 0.97; // search range reduction v.10.7 - - for (int ii = 0; ii < 1000; ii++) // loop random x/y/t alignments - { - rnum = drand48(); - if (rnum < 0.33) // random change some alignment offset - cimOffs[1].xf = offsetsB.xf + xf_range * (drand48() - 0.5); - else if (rnum < 0.67) - cimOffs[1].yf = offsetsB.yf + yf_range * (drand48() - 0.5); - else - cimOffs[1].tf = offsetsB.tf + tf_range * (drand48() - 0.5); - - matchlev = cim_match_images(0,1); // test quality of image alignment - - sprintf(SB_text,"align: %d match: %.5f lens: %.1f %.2f", // update status bar - ++cimNsearch, matchB, lens_mmB, lens_bowB); - zmainloop(); // v.11.11.1 - - if (sigdiff(matchlev,matchB,0.00001) > 0) { - matchB = matchlev; // save new best fit - lens_mmB = lens_mm; // alignment is better - lens_bowB = lens_bow; - offsetsB = cimOffs[1]; - cim_show_images(0,0); - squeeze = 1; // keep same search range as long - break; // as improvements are found - } - - if (panStat != -1) goto done; // user kill - } - - if (xf_range < xf_rfinal) goto done; // finished - - sprintf(SB_text,"align: %d match: %.5f lens: %.1f %.2f", // update status bar - cimNsearch, matchB, lens_mmB, lens_bowB); - zmainloop(); // v.11.11.1 - - mm_range = squeeze * mm_range; // reduce search range if no - if (mm_range < 0.02 * lens_mmB) mm_range = 0.02 * lens_mmB; // improvements were found - bow_range = squeeze * bow_range; - if (bow_range < 0.1 * lens_bowB) bow_range = 0.1 * lens_bowB; - if (bow_range < 0.2) bow_range = 0.2; - xf_range = squeeze * xf_range; - yf_range = squeeze * yf_range; - tf_range = squeeze * tf_range; - } - -done: - zfree(cimRedpix); - cimRedpix = 0; - - lens_mm = lens_mmB; // save best lens params found - lens_bow = lens_bowB; - if (panStat == -1 && panozd) { // unless killed - zdialog_stuff(panozd,"spmm",lens_mm); - zdialog_stuff(panozd,"spbow",lens_bow); - } - - cimSampSize = panSampSize; // restore - Ffuncbusy--; - cim_show_images(1,0); // images are left color-matched - return; -} - - -// fine-alignment -// start with very small image size -// search around offset values for best match -// increase image size and loop until full-size - -void pano_align() // v.10.7 -{ - int imx, im1, im2, ww; - double R, dx, dy, dt; - double overlap; - cimoffs offsets0; - - Fzoom = 0; // scale E3 to fit window - Fblowup = 1; // magnify small image to window size - Ffuncbusy++; // v.11.01 - - for (imx = 0; imx < cimNF; imx++) { - cimOffs[imx].xf = cimOffs[imx].xf / cimScale; // scale x/y offsets for full-size images - cimOffs[imx].yf = cimOffs[imx].yf / cimScale; - } - - cimScale = 1.0; // full-size - - for (imx = 0; imx < cimNF; imx++) { - PXM_free(cimPXMs[imx]); - cimPXMs[imx] = PXM_copy(cimPXMf[imx]); // copy full-size images - cim_curve_image(imx); // curve them - } - - cimBlend = 0.3 * cimPXMs[0]->ww; - cim_get_overlap(0,1,cimPXMs); // match images 0 & 1 in overlap area - cim_match_colors(0,1,cimPXMs); - cim_adjust_colors(cimPXMf[0],1); // image 0 << profile 1 - cim_adjust_colors(cimPXMf[1],2); // image 1 << profile 2 - - if (cimNF > 2) { - cimBlend = 0.3 * cimPXMs[1]->ww; - cim_get_overlap(1,2,cimPXMs); - cim_match_colors(1,2,cimPXMs); - cim_adjust_colors(cimPXMf[0],1); - cim_adjust_colors(cimPXMf[1],1); - cim_adjust_colors(cimPXMf[2],2); - } - - if (cimNF > 3) { - cimBlend = 0.3 * cimPXMs[2]->ww; - cim_get_overlap(2,3,cimPXMs); - cim_match_colors(2,3,cimPXMs); - cim_adjust_colors(cimPXMf[0],1); - cim_adjust_colors(cimPXMf[1],1); - cim_adjust_colors(cimPXMf[2],1); - cim_adjust_colors(cimPXMf[3],2); - } - - cimScale = panInitAlignSize / cimPXMf[1]->hh; // initial align image scale - if (cimScale > 1.0) cimScale = 1.0; - - for (imx = 0; imx < cimNF; imx++) { // scale offsets for image scale - cimOffs[imx].xf = cimOffs[imx].xf * cimScale; - cimOffs[imx].yf = cimOffs[imx].yf * cimScale; - } - - cimSearchRange = panInitSearchRange; // initial align search range - cimSearchStep = panInitSearchStep; // initial align search step - cimWarpRange = panInitWarpRange; // initial align corner warp range - cimWarpStep = panInitWarpStep; // initial align corner warp step - ww = cimPXMf[0]->ww * cimScale; // initial align image width - cimBlend = ww * panInitBlend; // initial align blend width - cimSampSize = panSampSize; // pixel sample size for align/compare - cimNsearch = 0; // reset align search counter - - while (true) // loop, increasing image size - { - for (imx = 0; imx < cimNF; imx++) { // prepare images - cim_scale_image(imx,cimPXMs); // scale to new size - cim_curve_image(imx); // curve based on lens params - cim_warp_image_pano(imx,1); // apply corner warps - } - - cim_show_images(1,0); // show with 50/50 blend in overlaps - - for (im1 = 0; im1 < cimNF-1; im1++) // fine-align each image with left neighbor - { - im2 = im1 + 1; - - offsets0 = cimOffs[im2]; // save initial alignment offsets - overlap = cim_get_overlap(im1,im2,cimPXMs); // get overlap area v.11.04 - if (overlap < panFinalBlend-2) { - zmessageACK(mWin,ZTX("Too little overlap, cannot align")); // v.11.03 - goto fail; - } - cim_get_redpix(im1); // get high-contrast pixels - - cim_align_image(im1,im2); // search for best offsets and warps - - zfree(cimRedpix); // clear red pixels - cimRedpix = 0; - - dx = cimOffs[im2].xf - offsets0.xf; // changes from initial offsets - dy = cimOffs[im2].yf - offsets0.yf; - dt = cimOffs[im2].tf - offsets0.tf; - - for (imx = im2+1; imx < cimNF; imx++) // propagate to following images - { - cimOffs[imx].xf += dx; - cimOffs[imx].yf += dy; - cimOffs[imx].tf += dt; - ww = cimOffs[imx].xf - cimOffs[im2].xf; - cimOffs[imx].yf += ww * dt; - } - } - - if (cimScale == 1.0) goto success; // done - - R = panImageIncrease; // next larger image size - cimScale = cimScale * R; - if (cimScale > 0.85) { // if close to end, jump to end - R = R / cimScale; - cimScale = 1.0; - } - - for (imx = 0; imx < cimNF; imx++) // scale offsets for new size - { - cimOffs[imx].xf *= R; - cimOffs[imx].yf *= R; - - for (int ii = 0; ii < 4; ii++) { - cimOffs[imx].wx[ii] *= R; - cimOffs[imx].wy[ii] *= R; - } - } - - cimSearchRange = panSearchRange; // align search range - cimSearchStep = panSearchStep; // align search step size - cimWarpRange = panWarpRange; // align corner warp range - cimWarpStep = panWarpStep; // align corner warp step size - - cimBlend = cimBlend * panBlendDecrease * R; // blend width, reduced - ww = cimPXMf[0]->ww * cimScale; - if (cimBlend < panFinalBlend * ww) - cimBlend = panFinalBlend * ww; // stay above minimum - } - -success: - panStat = 1; - goto align_done; -fail: - panStat = 0; -align_done: - cimBlend = 1; // tiny blend (increase in tweak if wanted) - Fzoom = Fblowup = 0; - Ffuncbusy--; - cim_show_images(0,0); - return; -} - - -// get user inputs for RGB changes and blend width, update cimPXMw[*] - -void pano_tweak() // v.10.7 -{ - int pano_tweak_event(zdialog *zd, cchar *event); // dialog event function - - cchar *tweaktitle = ZTX("Match Brightness and Color"); - char imageN[8] = "imageN"; - int imx; - - cimBlend = 1; // init. blend width - - panozd = zdialog_new(tweaktitle,mWin,Bdone,Bcancel,null); - - zdialog_add_widget(panozd,"hbox","hbim","dialog",0,"space=5"); - zdialog_add_widget(panozd,"label","labim","hbim",ZTX("image"),"space=5"); // image (o) (o) (o) (o) - zdialog_add_widget(panozd,"hbox","hbc1","dialog",0,"homog"); // - zdialog_add_widget(panozd,"label","labred","hbc1",Bred); // red green blue - zdialog_add_widget(panozd,"label","labgreen","hbc1",Bgreen); // [_____] [_____] [_____] - zdialog_add_widget(panozd,"label","labblue","hbc1",Bblue); // - zdialog_add_widget(panozd,"hbox","hbc2","dialog",0,"homog"); // brightness [___] [apply] - zdialog_add_widget(panozd,"spin","red","hbc2","50|200|0.1|100","space=5"); // - zdialog_add_widget(panozd,"spin","green","hbc2","50|200|0.1|100","space=5"); // -------------------------- - zdialog_add_widget(panozd,"spin","blue","hbc2","50|200|0.1|100","space=5"); // - zdialog_add_widget(panozd,"hbox","hbbri","dialog",0,"space=5"); // [auto color] [file color] - zdialog_add_widget(panozd,"label","labbr","hbbri",Bbrightness,"space=5"); // - zdialog_add_widget(panozd,"spin","bright","hbbri","50|200|0.1|100"); // -------------------------- - zdialog_add_widget(panozd,"button","brapp","hbbri",Bapply,"space=10"); // - zdialog_add_widget(panozd,"hsep","hsep","dialog",0,"space=5"); // blend width [___] [apply] - zdialog_add_widget(panozd,"hbox","hbc3","dialog",0,"space=5"); // - zdialog_add_widget(panozd,"button","auto","hbc3",ZTX("auto color"),"space=5"); // [done] [cancel] - zdialog_add_widget(panozd,"button","file","hbc3",ZTX("file color"),"space=5"); - zdialog_add_widget(panozd,"hsep","hsep","dialog",0,"space=5"); - zdialog_add_widget(panozd,"hbox","hbblen","dialog",0); - zdialog_add_widget(panozd,"label","labbl","hbblen",Bblendwidth,"space=5"); - zdialog_add_widget(panozd,"spin","blend","hbblen","1|300|1|1"); - zdialog_add_widget(panozd,"button","blapp","hbblen",Bapply,"space=15"); - - for (imx = 0; imx < cimNF; imx++) { // add radio button per image - imageN[5] = '0' + imx; - zdialog_add_widget(panozd,"radio",imageN,"hbim",0,"space=5"); - } - - zdialog_stuff(panozd,"image0",1); // pre-select 1st image - zdialog_resize(panozd,300,0); - - panStat = -1; // busy status - zdialog_run(panozd,pano_tweak_event,"-10/20"); // run dialog, parallel v.11.07 - zdialog_wait(panozd); // wait for dialog completion - return; -} - - -// dialog event function - -int pano_tweak_event(zdialog *zd, cchar *event) // v.10.7 -{ - char imageN[8] = "imageN"; - double red, green, blue, bright, bright2; - double red1, green1, blue1; - int nn, im0, imx, im1, im2, ww, hh, px, py; - uint16 *pixel; - - if (zd->zstat) // dialog complete - { - if (zd->zstat == 1) panStat = 1; // done - if (zd->zstat == 2) panStat = 0; // cancel - zdialog_free(panozd); // kill dialog - return 0; - } - - for (im0 = 0; im0 < cimNF; im0++) { // get which image is selected - imageN[5] = '0' + im0; // by the radio buttons - zdialog_fetch(zd,imageN,nn); - if (nn) break; - } - if (im0 == cimNF) return 1; - - zdialog_fetch(zd,"red",red); // get color adjustments - zdialog_fetch(zd,"green",green); - zdialog_fetch(zd,"blue",blue); - zdialog_fetch(zd,"bright",bright); // brightness adjustment - - bright2 = (red + green + blue) / 3; // RGB brightness - bright = bright / bright2; // bright setpoint / RGB brightness - red = red * bright; // adjust RGB brightness - green = green * bright; - blue = blue * bright; - - bright = (red + green + blue) / 3; - zdialog_stuff(zd,"red",red); // force back into consistency - zdialog_stuff(zd,"green",green); - zdialog_stuff(zd,"blue",blue); - zdialog_stuff(zd,"bright",bright); - - if (strEqu(event,"brapp")) // apply color & brightness changes - { - red = red / 100; // normalize 0.5 ... 2.0 - green = green / 100; - blue = blue / 100; - - cim_warp_image_pano(im0,0); // refresh cimPXMw from cimPXMs - - ww = cimPXMw[im0]->ww; - hh = cimPXMw[im0]->hh; - - for (py = 0; py < hh; py++) // loop all image pixels - for (px = 0; px < ww; px++) - { - pixel = PXMpix(cimPXMw[im0],px,py); - red1 = red * pixel[0]; // apply color factors - green1 = green * pixel[1]; - blue1 = blue * pixel[2]; - if (! blue1) continue; - - if (red1 > 65535 || green1 > 65535 || blue1 > 65535) { - bright = red1; // avoid overflow - if (green1 > bright) bright = green1; - if (blue1 > bright) bright = blue1; - bright = 65535.0 / bright; - red1 = red1 * bright; - green1 = green1 * bright; - blue1 = blue1 * bright; - } - - if (blue1 < 1) blue1 = 1; // avoid 0 v.10.7 - - pixel[0] = red1; - pixel[1] = green1; - pixel[2] = blue1; - } - - cimBlend = 1; - zdialog_stuff(zd,"blend",cimBlend); // v.11.04 - cim_show_images(0,0); // combine and show with 50/50 blend - } - - if (strEqu(event,"auto")) // auto match color of selected image - { - for (im1 = im0; im1 < cimNF-1; im1++) // from selected image to last image - { - im2 = im1 + 1; - cimBlend = 0.3 * cimPXMw[im2]->ww; - cim_get_overlap(im1,im2,cimPXMw); // match images in overlap area - cim_match_colors(im1,im2,cimPXMw); - cim_adjust_colors(cimPXMw[im1],1); // image im1 << profile 1 - cim_adjust_colors(cimPXMw[im2],2); // image im2 << profile 2 - for (imx = im1-1; imx >= im0; imx--) - cim_adjust_colors(cimPXMw[imx],1); - cimBlend = 1; - zdialog_stuff(zd,"blend",cimBlend); // v.11.04 - cim_show_images(0,0); - } - - for (im1 = im0-1; im1 >= 0; im1--) // from selected image to 1st image - { - im2 = im1 + 1; - cimBlend = 0.3 * cimPXMw[im2]->ww; - cim_get_overlap(im1,im2,cimPXMw); // match images in overlap area - cim_match_colors(im1,im2,cimPXMw); - cim_adjust_colors(cimPXMw[im1],1); // image im1 << profile 1 - cim_adjust_colors(cimPXMw[im2],2); // image im2 << profile 2 - for (imx = im2+1; imx < cimNF; imx++) - cim_adjust_colors(cimPXMw[imx],2); - cimBlend = 1; - zdialog_stuff(zd,"blend",cimBlend); // v.11.04 - cim_show_images(0,0); - } - } - - if (strEqu(event,"file")) // use original file colors - { - if (! cim_load_files()) return 1; - - for (imx = 0; imx < cimNF; imx++) { - PXM_free(cimPXMs[imx]); - cimPXMs[imx] = PXM_copy(cimPXMf[imx]); - cim_curve_image(imx); // curve and warp - cim_warp_image_pano(imx,0); - } - - cimBlend = 1; - zdialog_stuff(zd,"blend",cimBlend); // v.11.04 - cim_show_images(0,0); - } - - if (strEqu(event,"blapp")) // apply new blend width - { - zdialog_fetch(zd,"blend",cimBlend); // can be zero - cim_show_images(0,1); // show with gradual blend - } - - return 1; -} - - -/************************************************************************** - - Vertical Panorama function: join 2, 3, or 4 images. - -***************************************************************************/ - -void vpano_prealign(); // manual pre-align -void vpano_align(); // auto fine-align -void vpano_tweak(); // user color tweak - -editfunc EFvpano; // edit function data - - -// menu function - -void m_vpano(GtkWidget *, cchar *) // v.11.04 -{ - int imx, err; - char **flist = 0; - - zfuncs::F1_help_topic = "panorama"; // help topic - - if (mod_keep()) return; // warn unsaved changes - if (! menulock(1)) return; // test menu lock v.11.07 - menulock(0); - - for (imx = 0; imx < 10; imx++) - { // clear all file and PXM data - cimFile[imx] = 0; - cimPXMf[imx] = cimPXMs[imx] = cimPXMw[imx] = 0; - } - cimNF = 0; - - flist = zgetfileN(ZTX("Select 2 to 4 files"),"openN",curr_file); // select images to combine - if (! flist) return; - - for (imx = 0; flist[imx]; imx++); // count selected files - if (imx < 2 || imx > 4) { - zmessageACK(mWin,ZTX("Select 2 to 4 files")); - goto cleanup; - } - - cimNF = imx; // file count - for (imx = 0; imx < cimNF; imx++) - cimFile[imx] = strdupz(flist[imx],0,"pano"); // set up file list - - if (! cim_load_files()) goto cleanup; // load and check all files - - free_resources(); // ready to commit - - err = f_open(cimFile[0],0); // curr_file = 1st file in list - if (err) goto cleanup; - - EFvpano.funcname = "vpano"; - if (! edit_setup(EFvpano)) goto cleanup; // setup edit (will lock) - - cimShowAll = 1; // for cim_show_images(), show all - cimShrink = 0; // no warp shrinkage v.11.04 - cimPano = 0; // vertical pano mode v.11.04 - cimPanoV = 1; - - vpano_prealign(); // manual pre-alignment - if (panStat != 1) goto cancel; - - vpano_align(); // auto full alignment - if (panStat != 1) goto cancel; - - vpano_tweak(); // manual color adjustment - if (panStat != 1) goto cancel; - - CEF->Fmod = 1; // done - edit_done(EFvpano); - goto cleanup; - -cancel: // failed or canceled - edit_cancel(EFvpano); - -cleanup: - - if (flist) { - for (imx = 0; flist[imx]; imx++) // free file list - zfree(flist[imx]); - zfree(flist); - } - - for (imx = 0; imx < cimNF; imx++) { // free cim file and PXM data - if (cimFile[imx]) zfree(cimFile[imx]); - if (cimPXMf[imx]) PXM_free(cimPXMf[imx]); - if (cimPXMs[imx]) PXM_free(cimPXMs[imx]); - if (cimPXMw[imx]) PXM_free(cimPXMw[imx]); - } - - *SB_text = 0; - return; -} - - -// perform manual pre-align of all images -// returns alignment data in cimOffs[*] -// lens_mm and lens_bow may also be altered - -void vpano_prealign() -{ - int vpano_prealign_event(zdialog *zd, cchar *event); // dialog event function - void * vpano_prealign_thread(void *); // working thread - - int imx, hh, err = 0; - cchar *exifkey = { exif_focal_length_key }; - char lensname[40], **pp = 0; - - cchar *align_mess = ZTX("Drag images into rough alignment.\n" - "To rotate, drag from right edge."); - - pp = info_get(curr_file,&exifkey,1); // get lens mm from EXIF if available - if (pp && *pp) { - err = convSD(*pp, lens_mm, 20, 1000); // leave lens_bow unchanged (no source) - strcpy(lensname,"(EXIF)"); // lens name = EXIF - } - - if (! pp || ! *pp || err) { // not available - lens_mm = lens4_mm[curr_lens]; // get curr. lens mm, bow, name - lens_bow = lens4_bow[curr_lens]; - *lensname = 0; - strncatv(lensname,40,"(",lens4_name[curr_lens],")",null); - } - - for (imx = 0; imx < 10; imx++) // set all alignment offsets = 0 - memset(&cimOffs[imx],0,sizeof(cimoffs)); - - for (imx = hh = 0; imx < cimNF; imx++) // sum image heights - hh += cimPXMf[imx]->hh; - - cimScale = 1.4 * panPreAlignSize / hh; // set alignment image scale - if (cimScale > 1.0) cimScale = 1.0; // (* 0.7 after overlaps) - - for (imx = 0; imx < cimNF; imx++) // scale images > cimPXMs[*] - cim_scale_image(imx,cimPXMs); - - for (imx = 0; imx < cimNF; imx++) { // curve images, cimPXMs[*] replaced - cim_curve_Vimage(imx); - cimPXMw[imx] = PXM_copy(cimPXMs[imx]); // copy to cimPXMw[*] for display - } - - cimOffs[0].xf = cimOffs[0].yf = 0; // first image at (0,0) - - for (imx = 1; imx < cimNF; imx++) // position images with 30% overlap - { // in vertical row - cimOffs[imx].yf = cimOffs[imx-1].yf + 0.7 * cimPXMw[imx-1]->hh; - cimOffs[imx].xf = cimOffs[imx-1].xf; - } - - Fzoom = 0; // scale image to fit window - Fblowup = 1; // magnify small image to window size - - cimBlend = panPreAlignBlend * cimPXMw[1]->hh; // overlap in align window - cim_show_Vimages(1,0); // combine and show images in main window - - panozd = zdialog_new(ZTX("Pre-align Images"),mWin,Bproceed,Bcancel,null); // start pre-align dialog - zdialog_add_widget(panozd,"label","lab1","dialog",align_mess,"space=5"); - zdialog_add_widget(panozd,"hbox","hb1","dialog",0,"space=2"); - zdialog_add_widget(panozd,"spin","spmm","hb1","22|200|0.1|35","space=5"); // [ 35 ] lens mm (source) - zdialog_add_widget(panozd,"label","labmm","hb1",ZTX("lens mm")); // [ 0.3 ] lens bow - zdialog_add_widget(panozd,"label","lablens","hb1","","space=5"); // [resize] resize window - zdialog_add_widget(panozd,"hbox","hb2","dialog",0,"space=2"); - zdialog_add_widget(panozd,"spin","spbow","hb2","-9|9|0.01|0","space=5"); - zdialog_add_widget(panozd,"label","labbow","hb2",ZTX("lens bow")); - zdialog_add_widget(panozd,"hbox","hb3","dialog",0,"space=2"); - zdialog_add_widget(panozd,"button","resize","hb3",ZTX("Resize"),"space=5"); - zdialog_add_widget(panozd,"label","labsiz","hb3",ZTX("resize window"),"space=5"); - - zdialog_stuff(panozd,"spmm",lens_mm); // stuff lens data - zdialog_stuff(panozd,"spbow",lens_bow); - zdialog_stuff(panozd,"lablens",lensname); // show source of lens data - - panStat = -1; // busy status - gdk_window_set_cursor(drWin->window,dragcursor); // set drag cursor - zdialog_run(panozd,vpano_prealign_event,"-10/20"); // start dialog v.11.07 - start_thread(vpano_prealign_thread,0); // start working thread - zdialog_wait(panozd); // wait for dialog completion - gdk_window_set_cursor(drWin->window,0); // restore normal cursor - Fzoom = Fblowup = 0; - return; -} - - -// pre-align dialog event function - -int vpano_prealign_event(zdialog *zd, cchar *event) -{ - int imx; - double overlap; - - if (strstr("spmm spbow",event)) { - zdialog_fetch(zd,"spmm",lens_mm); // get revised lens data - zdialog_fetch(zd,"spbow",lens_bow); - } - - if (strEqu(event,"resize")) // allocate new E3 image - cim_show_Vimages(1,0); - - if (zd->zstat) // dialog complete - { - if (zd->zstat == 1) // proceed - panStat = 1; - else // cancel or other - panStat = 0; - - zdialog_free(panozd); // kill dialog - wrapup_thread(0); // wait for thread - - if (! panStat) return 0; // canceled - - for (imx = 0; imx < cimNF-1; imx++) // check for enough overlap - { - overlap = cim_get_overlap(imx,imx+1,cimPXMs); // v.11.04 - if (overlap < panFinalBlend) { // v.11.09 - zmessageACK(mWin,ZTX("Too little overlap, cannot align")); - panStat = 0; - return 0; - } - } - } - - return 0; -} - - -// pre-align working thread -// convert mouse and KB events into image movements // overhauled - -void * vpano_prealign_thread(void *) -{ - cimoffs offstemp; - PXM *pxmtemp; - char *ftemp; - int im1, im2, imm, imx; - int mx0, my0, mx, my; // mouse drag origin, position - int xoff, yoff, loy, hiy; - int sepy, minsep; - int ww, hh, rotate, midy; - double lens_mm0, lens_bow0; - double dx, dy, t1, t2, dt; - - imm = ww = hh = rotate = xoff = yoff = 0; // stop compiler warnings - - lens_mm0 = lens_mm; // to detect changes - lens_bow0 = lens_bow; - - mx0 = my0 = 0; // no drag in progress - Mcapture = KBcapture = 1; // capture mouse drag and KB keys - - cimBlend = 0; // full blend during pre-align - - while (true) // loop and align until done - { - zsleep(0.05); // logic simplified - - if (panStat != -1) break; // quit signal from dialog - - if (lens_mm != lens_mm0 || lens_bow != lens_bow0) { // change in lens parameters - lens_mm0 = lens_mm; - lens_bow0 = lens_bow; - - for (imx = 0; imx < cimNF; imx++) { // re-curve images - cim_scale_image(imx,cimPXMs); - cim_curve_Vimage(imx); - PXM_free(cimPXMw[imx]); - cimPXMw[imx] = PXM_copy(cimPXMs[imx]); - } - - cim_show_Vimages(1,0); // combine and show images - continue; - } - - if (KBkey) { // KB input - if (KBkey == GDK_Left) cimOffs[imm].xf -= 0.5; // tweak alignment offsets - if (KBkey == GDK_Right) cimOffs[imm].xf += 0.5; - if (KBkey == GDK_Up) cimOffs[imm].yf -= 0.5; - if (KBkey == GDK_Down) cimOffs[imm].yf += 0.5; - if (KBkey == GDK_r) cimOffs[imm].tf += 0.0005; - if (KBkey == GDK_l) cimOffs[imm].tf -= 0.0005; - KBkey = 0; - - cim_show_Vimages(0,0); // combine and show images - continue; - } - - if (! Mxdrag && ! Mydrag) // no drag underway - mx0 = my0 = 0; // reset drag origin - - if (Mxdrag || Mydrag) // mouse drag underway - { - mx = Mxdrag; // mouse position in image - my = Mydrag; - - if (! mx0 && ! my0) // new drag - { - mx0 = mx; // set drag origin - my0 = my; - minsep = 9999; - - for (imx = 0; imx < cimNF; imx++) // find image with midpoint - { // closest to mouse y - loy = cimOffs[imx].yf; - hiy = loy + cimPXMw[imx]->hh; - midy = (loy + hiy) / 2; - sepy = abs(midy - my0); - if (sepy < minsep) { - minsep = sepy; - imm = imx; // image to drag or rotate - } - } - - xoff = cimOffs[imm].xf; - yoff = cimOffs[imm].yf; - ww = cimPXMw[imm]->ww; - hh = cimPXMw[imm]->hh; - - rotate = 0; // if drag at right edge, - if (mx0 > xoff + 0.85 * ww) rotate = 1; // set rotate flag - } - - if (mx != mx0 || my != my0) // drag is progressing - { - dx = mx - mx0; // mouse movement - dy = my - my0; - - if (rotate && my0 > yoff && my > yoff) // rotation - { - if (imm > 0) { - loy = cimOffs[imm].yf; // if there is an image above, - hiy = cimOffs[imm-1].yf + cimPXMw[imm-1]->hh; // midy = midpoint of overlap - midy = (loy + hiy) / 2; - } - else midy = 0; // this is the topmist image - - t1 = atan(1.0 * (my0-yoff) / (mx0-xoff)); - t2 = atan(1.0 * (my-yoff) / (mx-xoff)); - dt = t2 - t1; // angle change - dy = - dt * ww / 2; // pivot = middle of overlap above - dx = dt * (midy-yoff); - } - - else dt = 0; // x/y drag - - cimOffs[imm].xf += dx; // update image - cimOffs[imm].yf += dy; - cimOffs[imm].tf += dt; - xoff = cimOffs[imm].xf; // v.11.04 - yoff = cimOffs[imm].yf; - - cim_show_Vimages(0,0); // show combined images - - mx0 = mx; // next drag origin = current mouse - my0 = my; - } - } - - for (im1 = 0; im1 < cimNF-1; im1++) // track image order changes - { - im2 = im1 + 1; - if (cimOffs[im2].yf < cimOffs[im1].yf) - { - ftemp = cimFile[im2]; // switch filespecs - cimFile[im2] = cimFile[im1]; - cimFile[im1] = ftemp; - pxmtemp = cimPXMf[im2]; // switch images - cimPXMf[im2] = cimPXMf[im1]; - cimPXMf[im1] = pxmtemp; - pxmtemp = cimPXMs[im2]; // scaled images - cimPXMs[im2] = cimPXMs[im1]; - cimPXMs[im1] = pxmtemp; - pxmtemp = cimPXMw[im2]; // warped images - cimPXMw[im2] = cimPXMw[im1]; - cimPXMw[im1] = pxmtemp; - offstemp = cimOffs[im2]; // offsets - cimOffs[im2] = cimOffs[im1]; - cimOffs[im1] = offstemp; - if (imm == im1) imm = im2; // current drag image - else if (imm == im2) imm = im1; - break; - } - } - } - - KBcapture = Mcapture = 0; - thread_exit(); - return 0; // not executed, stop g++ warning -} - - -// fine-alignment -// start with very small image size -// search around offset values for best match -// increase image size and loop until full-size - -void vpano_align() -{ - int imx, im1, im2, ww, hh; - double R, dx, dy, dt; - double overlap; - cimoffs offsets0; - - Fzoom = 0; // scale E3 to fit window - Fblowup = 1; // magnify small image to window size - Ffuncbusy++; - - for (imx = 0; imx < cimNF; imx++) { - cimOffs[imx].xf = cimOffs[imx].xf / cimScale; // scale x/y offsets for full-size images - cimOffs[imx].yf = cimOffs[imx].yf / cimScale; - } - - cimScale = 1.0; // full-size - - for (imx = 0; imx < cimNF; imx++) { - PXM_free(cimPXMs[imx]); - cimPXMs[imx] = PXM_copy(cimPXMf[imx]); // copy full-size images - cim_curve_Vimage(imx); // curve them - } - - cimBlend = 0.3 * cimPXMs[0]->hh; - cim_get_overlap(0,1,cimPXMs); // match images 0 & 1 in overlap area - cim_match_colors(0,1,cimPXMs); - cim_adjust_colors(cimPXMf[0],1); // image 0 << profile 1 - cim_adjust_colors(cimPXMf[1],2); // image 1 << profile 2 - - if (cimNF > 2) { - cimBlend = 0.3 * cimPXMs[1]->hh; - cim_get_overlap(1,2,cimPXMs); - cim_match_colors(1,2,cimPXMs); - cim_adjust_colors(cimPXMf[0],1); - cim_adjust_colors(cimPXMf[1],1); - cim_adjust_colors(cimPXMf[2],2); - } - - if (cimNF > 3) { - cimBlend = 0.3 * cimPXMs[2]->hh; - cim_get_overlap(2,3,cimPXMs); - cim_match_colors(2,3,cimPXMs); - cim_adjust_colors(cimPXMf[0],1); - cim_adjust_colors(cimPXMf[1],1); - cim_adjust_colors(cimPXMf[2],1); - cim_adjust_colors(cimPXMf[3],2); - } - - cimScale = panInitAlignSize / cimPXMf[1]->hh; // initial align image scale - if (cimScale > 1.0) cimScale = 1.0; - - for (imx = 0; imx < cimNF; imx++) { // scale offsets for image scale - cimOffs[imx].xf = cimOffs[imx].xf * cimScale; - cimOffs[imx].yf = cimOffs[imx].yf * cimScale; - } - - cimSearchRange = panInitSearchRange; // initial align search range - cimSearchStep = panInitSearchStep; // initial align search step - cimWarpRange = panInitWarpRange; // initial align corner warp range - cimWarpStep = panInitWarpStep; // initial align corner warp step - hh = cimPXMf[0]->hh * cimScale; // initial align image width - cimBlend = hh * panInitBlend; // initial align blend width - cimSampSize = panSampSize; // pixel sample size for align/compare - cimNsearch = 0; // reset align search counter - - while (true) // loop, increasing image size - { - for (imx = 0; imx < cimNF; imx++) { // prepare images - cim_scale_image(imx,cimPXMs); // scale to new size - cim_curve_Vimage(imx); // curve based on lens params - cim_warp_image_Vpano(imx,1); // apply corner warps - } - - cim_show_Vimages(1,0); // show with 50/50 blend in overlaps - - for (im1 = 0; im1 < cimNF-1; im1++) // fine-align each image with top neighbor - { - im2 = im1 + 1; - - offsets0 = cimOffs[im2]; // save initial alignment offsets - overlap = cim_get_overlap(im1,im2,cimPXMs); // get overlap area v.11.04 - if (overlap < panFinalBlend-2) { - zmessageACK(mWin,ZTX("Too little overlap, cannot align")); - goto fail; - } - - cim_get_redpix(im1); // get high-contrast pixels - - cim_align_image(im1,im2); // search for best offsets and warps - - zfree(cimRedpix); // clear red pixels - cimRedpix = 0; - - dx = cimOffs[im2].xf - offsets0.xf; // changes from initial offsets - dy = cimOffs[im2].yf - offsets0.yf; - dt = cimOffs[im2].tf - offsets0.tf; - - for (imx = im2+1; imx < cimNF; imx++) // propagate to following images - { - cimOffs[imx].xf += dx; - cimOffs[imx].yf += dy; - cimOffs[imx].tf += dt; - ww = cimOffs[imx].xf - cimOffs[im2].xf; - cimOffs[imx].yf += ww * dt; - } - } - - if (cimScale == 1.0) goto success; // done - - R = panImageIncrease; // next larger image size - cimScale = cimScale * R; - if (cimScale > 0.85) { // if close to end, jump to end - R = R / cimScale; - cimScale = 1.0; - } - - for (imx = 0; imx < cimNF; imx++) // scale offsets for new size - { - cimOffs[imx].xf *= R; - cimOffs[imx].yf *= R; - - for (int ii = 0; ii < 4; ii++) { - cimOffs[imx].wx[ii] *= R; - cimOffs[imx].wy[ii] *= R; - } - } - - cimSearchRange = panSearchRange; // align search range - cimSearchStep = panSearchStep; // align search step size - cimWarpRange = panWarpRange; // align corner warp range - cimWarpStep = panWarpStep; // align corner warp step size - - cimBlend = cimBlend * panBlendDecrease * R; // blend width, reduced - hh = cimPXMf[0]->hh * cimScale; - if (cimBlend < panFinalBlend * hh) - cimBlend = panFinalBlend * hh; // stay above minimum - } - -success: - panStat = 1; - goto align_done; -fail: - panStat = 0; -align_done: - Fzoom = Fblowup = 0; - Ffuncbusy--; - cimBlend = 1; // tiny blend (increase in tweak if wanted) - cim_show_Vimages(0,0); - return; -} - - -// get user inputs for RGB changes and blend width, update cimPXMw[*] - -void vpano_tweak() -{ - int vpano_tweak_event(zdialog *zd, cchar *event); // dialog event function - - cchar *tweaktitle = ZTX("Match Brightness and Color"); - char imageN[8] = "imageN"; - int imx; - - cimBlend = 1; // init. blend width - - panozd = zdialog_new(tweaktitle,mWin,Bdone,Bcancel,null); - - zdialog_add_widget(panozd,"hbox","hbim","dialog",0,"space=5"); - zdialog_add_widget(panozd,"label","labim","hbim",ZTX("image"),"space=5"); // image (o) (o) (o) (o) - zdialog_add_widget(panozd,"hbox","hbc1","dialog",0,"homog"); // - zdialog_add_widget(panozd,"label","labred","hbc1",Bred); // red green blue - zdialog_add_widget(panozd,"label","labgreen","hbc1",Bgreen); // [_____] [_____] [_____] - zdialog_add_widget(panozd,"label","labblue","hbc1",Bblue); // - zdialog_add_widget(panozd,"hbox","hbc2","dialog",0,"homog"); // brightness [___] [apply] - zdialog_add_widget(panozd,"spin","red","hbc2","50|200|0.1|100","space=5"); // - zdialog_add_widget(panozd,"spin","green","hbc2","50|200|0.1|100","space=5"); // -------------------------- - zdialog_add_widget(panozd,"spin","blue","hbc2","50|200|0.1|100","space=5"); // - zdialog_add_widget(panozd,"hbox","hbbri","dialog",0,"space=5"); // [auto color] [file color] - zdialog_add_widget(panozd,"label","labbr","hbbri",Bbrightness,"space=5"); // - zdialog_add_widget(panozd,"spin","bright","hbbri","50|200|0.1|100"); // -------------------------- - zdialog_add_widget(panozd,"button","brapp","hbbri",Bapply,"space=10"); // - zdialog_add_widget(panozd,"hsep","hsep","dialog",0,"space=5"); // blend width [___] [apply] - zdialog_add_widget(panozd,"hbox","hbc3","dialog",0,"space=5"); // - zdialog_add_widget(panozd,"button","auto","hbc3",ZTX("auto color"),"space=5"); // [done] [cancel] - zdialog_add_widget(panozd,"button","file","hbc3",ZTX("file color"),"space=5"); - zdialog_add_widget(panozd,"hsep","hsep","dialog",0,"space=5"); - zdialog_add_widget(panozd,"hbox","hbblen","dialog",0); - zdialog_add_widget(panozd,"label","labbl","hbblen",Bblendwidth,"space=5"); - zdialog_add_widget(panozd,"spin","blend","hbblen","1|300|1|1"); - zdialog_add_widget(panozd,"button","blapp","hbblen",Bapply,"space=15"); - - for (imx = 0; imx < cimNF; imx++) { // add radio button per image - imageN[5] = '0' + imx; - zdialog_add_widget(panozd,"radio",imageN,"hbim",0,"space=5"); - } - - zdialog_stuff(panozd,"image0",1); // pre-select 1st image - zdialog_resize(panozd,300,0); - - panStat = -1; // busy status - zdialog_run(panozd,vpano_tweak_event,"-10/20"); // run dialog, parallel v.11.07 - zdialog_wait(panozd); // wait for dialog completion - return; -} - - -// dialog event function - -int vpano_tweak_event(zdialog *zd, cchar *event) -{ - char imageN[8] = "imageN"; - double red, green, blue, bright, bright2; - double red1, green1, blue1; - int nn, im0, imx, im1, im2, ww, hh, px, py; - uint16 *pixel; - - if (zd->zstat) // dialog complete - { - if (zd->zstat == 1) panStat = 1; // done - if (zd->zstat == 2) panStat = 0; // cancel - zdialog_free(panozd); // kill dialog - return 0; - } - - for (im0 = 0; im0 < cimNF; im0++) { // get which image is selected - imageN[5] = '0' + im0; // by the radio buttons - zdialog_fetch(zd,imageN,nn); - if (nn) break; - } - if (im0 == cimNF) return 1; - - zdialog_fetch(zd,"red",red); // get color adjustments - zdialog_fetch(zd,"green",green); - zdialog_fetch(zd,"blue",blue); - zdialog_fetch(zd,"bright",bright); // brightness adjustment - - bright2 = (red + green + blue) / 3; // RGB brightness - bright = bright / bright2; // bright setpoint / RGB brightness - red = red * bright; // adjust RGB brightness - green = green * bright; - blue = blue * bright; - - bright = (red + green + blue) / 3; - zdialog_stuff(zd,"red",red); // force back into consistency - zdialog_stuff(zd,"green",green); - zdialog_stuff(zd,"blue",blue); - zdialog_stuff(zd,"bright",bright); - - if (strEqu(event,"brapp")) // apply color & brightness changes - { - red = red / 100; // normalize 0.5 ... 2.0 - green = green / 100; - blue = blue / 100; - - cim_warp_image_Vpano(im0,0); // refresh cimPXMw from cimPXMs - - ww = cimPXMw[im0]->ww; - hh = cimPXMw[im0]->hh; - - for (py = 0; py < hh; py++) // loop all image pixels - for (px = 0; px < ww; px++) - { - pixel = PXMpix(cimPXMw[im0],px,py); - red1 = red * pixel[0]; // apply color factors - green1 = green * pixel[1]; - blue1 = blue * pixel[2]; - if (! blue1) continue; - - if (red1 > 65535 || green1 > 65535 || blue1 > 65535) { - bright = red1; // avoid overflow - if (green1 > bright) bright = green1; - if (blue1 > bright) bright = blue1; - bright = 65535.0 / bright; - red1 = red1 * bright; - green1 = green1 * bright; - blue1 = blue1 * bright; - } - - if (blue1 < 1) blue1 = 1; // avoid 0 - - pixel[0] = red1; - pixel[1] = green1; - pixel[2] = blue1; - } - - cimBlend = 1; - zdialog_stuff(zd,"blend",cimBlend); - cim_show_Vimages(0,0); // combine and show with 50/50 blend - } - - if (strEqu(event,"auto")) // auto match color of selected image - { - for (im1 = im0; im1 < cimNF-1; im1++) // from selected image to last image - { - im2 = im1 + 1; - cimBlend = 0.3 * cimPXMw[im2]->hh; - cim_get_overlap(im1,im2,cimPXMw); // match images in overlap area - cim_match_colors(im1,im2,cimPXMw); - cim_adjust_colors(cimPXMw[im1],1); // image im1 << profile 1 - cim_adjust_colors(cimPXMw[im2],2); // image im2 << profile 2 - for (imx = im1-1; imx >= im0; imx--) - cim_adjust_colors(cimPXMw[imx],1); - cimBlend = 1; - zdialog_stuff(zd,"blend",cimBlend); - cim_show_Vimages(0,0); - } - - for (im1 = im0-1; im1 >= 0; im1--) // from selected image to 1st image - { - im2 = im1 + 1; - cimBlend = 0.3 * cimPXMw[im2]->hh; - cim_get_overlap(im1,im2,cimPXMw); // match images in overlap area - cim_match_colors(im1,im2,cimPXMw); - cim_adjust_colors(cimPXMw[im1],1); // image im1 << profile 1 - cim_adjust_colors(cimPXMw[im2],2); // image im2 << profile 2 - for (imx = im2+1; imx < cimNF; imx++) - cim_adjust_colors(cimPXMw[imx],2); - cimBlend = 1; - zdialog_stuff(zd,"blend",cimBlend); - cim_show_Vimages(0,0); - } - } - - if (strEqu(event,"file")) // use original file colors - { - if (! cim_load_files()) return 1; - - for (imx = 0; imx < cimNF; imx++) { - PXM_free(cimPXMs[imx]); - cimPXMs[imx] = PXM_copy(cimPXMf[imx]); - cim_curve_Vimage(imx); // curve and warp - cim_warp_image_Vpano(imx,0); - } - - cimBlend = 1; - zdialog_stuff(zd,"blend",cimBlend); - cim_show_Vimages(0,0); - } - - if (strEqu(event,"blapp")) // apply new blend width - { - zdialog_fetch(zd,"blend",cimBlend); // can be zero - cim_show_Vimages(0,1); // show with gradual blend - } - - return 1; -} - - diff -Nru fotoxx-11.11.1/fotoxx.h fotoxx-12.01.2/fotoxx.h --- fotoxx-11.11.1/fotoxx.h 2011-11-05 05:30:36.000000000 +0000 +++ fotoxx-12.01.2/fotoxx.h 2012-01-04 08:47:11.000000000 +0000 @@ -24,6 +24,17 @@ #include #include "zfuncs.h" +// Fotoxx definitions + +#define fversion "Fotoxx v.12.01.2" // this fotoxx version +#define flicense "Free software - GNU General Public License v.3" +#define fhomepage "http://kornelix.squarespace.com/fotoxx" +#define ftranslators \ + "Translators: Jie Luo, Justa, Peter Landgren, Alexander Krasnopolsky, \n" \ + " Arthur Kalverboer, André Campos Rodovalho, Doriano Blengino" +#define fcredits "Software used: GTK, libtiff, ufraw, exiftool" +#define fcontact "Bug reports: kornelix2@gmail.com" + // GTK definitions #define PXB GdkPixbuf @@ -61,8 +72,9 @@ #define pixbright(pix) (0.25*(pix)[0]+0.65*(pix)[1]+0.10*(pix)[2]) // pixel brightness, 0-64K #define pixred(pix) (25 * pix[0] / (pixbright(pix)+1)) // pixel redness, 0-100% #define Nrecentfiles 100 // most recent image files -#define max_threads 6 // max. working threads v.10.10 +#define max_threads 6 // max. working threads #define maxedits 100 // max. edits, undo/redo depth +#define MAXIMAGES 100000 // max. image files supported #define maxtagcats 200 // max tag categories #define tagcc 50 // max cc for one tag or category ID @@ -88,7 +100,7 @@ // externals from zfuncs module namespace zfuncs { - extern char zlanguage[8]; // current language lc_RC + extern char zlang[8]; // current language lc_RC extern cchar *F1_help_topic; // F1 context help topic extern char zicondir[200]; // where application icons live extern int zdialog_busy; // tracks open zdialog's @@ -97,8 +109,10 @@ namespace image_navi { // image_gallery() data extern char *galleryname; // directory or file list name - extern int gallerytype; // 1/2 = directory / file list + extern int gallerytype; // 1/2/3 = directory/file-list/metadata extern int nfiles, nimages; // file counts, total and images + extern char **flist; // image file list + extern char **mdlist; // metadata list extern int xwinW, xwinH; // image gallery window size extern int thumbfilesize; // thumbnail file image size extern int thumbsize; // curr. thumbnail display size @@ -145,6 +159,8 @@ EX int Fslideshow; // slide show mode is active EX int Frecent; // start with recent files gallery EX int Fprev; // start with previous file +EX int Fblank; // start with blank window +EX int KBzmalloclog; // KB toggle for zmalloc reporting EX int Fautosync; // auto file sync is requested EX int Fmansync; // manual file sync is requested @@ -179,7 +195,7 @@ // files and directories in /home//.fotoxx/ -EX char topdirk_file[200]; // top directory file v.11.11 +EX char topdirk_file[200]; // top directory save file v.11.11 EX char tags_defined_file[200]; // tags defined file EX char search_index_file[200]; // search index file v.11.02 EX char recentfiles_file[200]; // file of recent image files v.11.09 @@ -191,9 +207,9 @@ // fotoxx PXM pixmaps typedef struct { // PXM pixmap - char wmi[8]; - int ww, hh, bpc; // width, height, bits per color - void *bmp; // uint8*/uint16* (bpc=8/16) + char wmi[8]; + int ww, hh, bpc; // width, height, bits per color + void *bmp; // uint8*/uint16* (bpc=8/16) } PXM; EX PXM *Fpxm8; // input file pixmap, PXM-8 @@ -231,10 +247,15 @@ EX int Mxdown, Mydown, Mxdrag, Mydrag; // mouse drag vector EX int Mdrag; // mouse drag underway EX int Mcapture; // mouse captured by edit function +EX int Fmousemain; // flag, mouse acts on main window EX int KBcapture; // KB key captured by edit function EX int KBkey; // active keyboard key +EX int KBcontrolkey; // keyboard key states, 1 = down +EX int KBshiftkey; +EX int KB_A_key; + EX int Ntoplines, Nptoplines; // lines on top of image in window EX int toplinex1[4], topliney1[4], toplinex2[4], topliney2[4]; EX int ptoplinex1[4], ptopliney1[4], ptoplinex2[4], ptopliney2[4]; @@ -252,12 +273,14 @@ EX toptext_t toptext[100]; // text strings written on main window EX int Ntoptext; // current count -EX zdialog *zdedittags; // edit tags zdialog -EX zdialog *zdexifview; // view EXIF/IPTC data -EX zdialog *zdexifedit; // edit EXIF/IPTC data -EX zdialog *zdeditcctext; // edit IPTC caption and EXIF user comments -EX zdialog *zdrename; // rename file zdialog -EX zdialog *zdsela; // select area dialog +struct topcircle_t { // list of red circles that are + int px, py; // painted over image whenever + int radius; // the main window is updated + int color; // 1/2/3 = white/black/red +}; +#define maxtopcircles 100 // max. number of circles +EX topcircle_t topcircles[100]; // circles written on main window +EX int Ntopcircles; // current count // select area data @@ -267,13 +290,16 @@ EX uint16 sa_endpx[10000], sa_endpy[10000]; // last pixel drawn per seqence no. EX int sa_thresh; // mouse pixel distance threshold EX int sa_mouseradius; // mouse selection radius +EX int sa_searchrange; // search range (* mouse radius) EX int sa_mousex, sa_mousey; // mouse position in image +EX int sa_matchcolor; // search using color match Y/N EX double sa_colormatch; // color range to match (0.001 to 1.0) EX uint16 sa_matchRGB[1000][3]; // match colors, up to 1000 EX int sa_Nmatch; // count of match colors -EX int sa_firewall; // selected pixels block propagation +EX int sa_firewall; // selected pixels block propagation Y/N EX GdkColor *sa_pixRGB; // select area outline color -EX int sa_radius, sa_radius2; // current mouse radius, radius**2 +EX int sa_radius, sa_radius2; // current mouse radius, radius **2 +EX int sa_radius3; // search range **2 EX int sa_calced; // edge calculation done EX int sa_blend; // edge blend width EX int sa_minx, sa_maxx; // enclosing rectangle for area @@ -284,7 +310,8 @@ EX int sa_Nstack; EX int sa_stat; // 0/1/2/3 = none/edit/pause/complete EX int sa_mode; // 1-7 = curr. select area edit method -EX int sa_hole; // finish failure (outline has a hole) +EX int sa_finOK; // finish area - success +EX int sa_finhole; // finish area - area has a hole EX int sa_currseq; // current select sequence no. EX int sa_Ncurrseq; // current sequence pixel count EX char *sa_pixselc; // maps pixels (re)selected in current cycle @@ -293,6 +320,7 @@ EX int sa_fww, sa_fhh; // valid image dimensions for select area EX int Fshowarea; // show select area outline EX int Factivearea; // select area complete and enabled +EX int areanumber; // increasing sequential number // spline curve data @@ -350,13 +378,14 @@ EX int Ffirsttime; // first time startup EX int newfiles; // new files found since last synch EX int mwgeom[4]; // main window position and size -EX cchar *tbar_style; // toolbar style +EX cchar *tbar_style; // toolbar style: icons/text/both +EX cchar *startdisplay; // display: recent/prev/blank/file/dirk +EX char *startdirk; // start directory (startdisplay=dirk) +EX char *startfile; // start image file (startdisplay=file) EX int Fwarnoverwrite; // warn overwrite of original image -EX char *lens4_name[4]; // names for 4 lenses -EX double lens4_mm[4], lens4_bow[4]; // characteristics for 4 lenses -EX double lens_mm, lens_bow; // current lens characteristics -EX int curr_lens; // current lens, 0-3 -EX char lensname[40]; // current lens name +EX double lens_mm, lens_bow; // pano lens mm and bow +EX double lens_settings[2]; // " user settings if no EXIF data +EX cchar *zoomratio; // zoom ratio, "1.xxxxxx" EX int trimsize[2]; // trim (crop) width, height EX char *trimbuttons[6]; // trim dialog button labels EX char *trimratios[6]; // corresponding aspect ratios @@ -383,6 +412,15 @@ EX int ss_funcs[SSNF]; // user preferred transitions EX char *ss_musicfile; // music file or playlist +// dialogs with global visibility + +EX zdialog *zdedittags; // edit tags zdialog +EX zdialog *zdexifview; // view EXIF/IPTC data +EX zdialog *zdexifedit; // edit EXIF/IPTC data +EX zdialog *zdeditcctext; // edit IPTC caption and EXIF user comments +EX zdialog *zdrename; // rename file zdialog +EX zdialog *zdsela; // select area dialog + // GTK functions int main(int argc, char * argv[]); // main program @@ -409,10 +447,12 @@ void erase_toptext(int ID); // remove all text strings with ID void paint_toptext(); // paint text strings when window repainted void paint_text(int px, int py, cchar *text, cchar *font); // paint text on window (window space) +void add_topcircle(int px, int py, int radius, int color); // paint circles on window (image space) +void erase_topcircles(); // remove all red circles +void paint_topcircles(); // paint red circles when window repainted typedef void CBfunc(); // callback function type EX CBfunc *mouseCBfunc; // current mouse handler function -EX zdialog *mouse_zd; // current dialog holding mouse void takeMouse(zdialog *zd, CBfunc func, GdkCursor *); // capture mouse for dialog v.11.03 void freeMouse(); // free mouse for main window @@ -458,32 +498,31 @@ void m_manage_collections(GtkWidget *, cchar *); // create and edit image collections void m_move_collections(GtkWidget *, cchar *); // change top image directory void edit_coll_popmenu(GtkWidget *, char *file); // popup menu for editing collections -void m_moncheck(GtkWidget *, cchar *); // check monitor brightness and color -void m_mongamma(GtkWidget *, cchar *); // adjust monitor gamma -void m_histogram(GtkWidget *, cchar *); // start brightness histogram -void histogram_paint(); // update brightness histogram -void histogram_destroy(); // remove histogram window +void m_batchconvert(GtkWidget *, cchar *); // convert/resize/export multiple image files +void m_conv_raw(GtkWidget *, cchar *); // convert RAW files to tiff void m_slideshow(GtkWidget *, cchar *); // enter or leave slideshow mode void slideshow_next(cchar *); // show prev/next image +void m_syncfiles(GtkWidget *, cchar *); // rebuild thumbnails and search index +int syncfiles_func(void *); // sync files function (in subprocess) void m_show_RGB(GtkWidget *, cchar *); // show RGB values at mouse click void m_gridlines(GtkWidget *, cchar *); // set up grid lines void load_grid(int *griddata); // load grid from saved state void save_grid(int *griddata); // save grid to saved state void toggle_grid(int action); // set grid off/on or toggle (0/1/2) -void m_lensparms(GtkWidget *, cchar *); // edit lens parameters +void m_burn(GtkWidget *, cchar *); // burn selected images to CD/DVD +void m_email(GtkWidget *, cchar *); // e-mail selected images +void m_moncheck(GtkWidget *, cchar *); // check monitor brightness and color +void m_mongamma(GtkWidget *, cchar *); // adjust monitor gamma +void m_histogram(GtkWidget *, cchar *); // start brightness histogram +void histogram_paint(); // update brightness histogram +void histogram_destroy(); // remove histogram window void m_lang(GtkWidget *, cchar *); // change language void m_translate(GtkWidget *, cchar *); // edit translation void m_menu_launcher(GtkWidget *, cchar *); // make desktop menu entry and launcher -void m_conv_raw(GtkWidget *, cchar *); // convert RAW files to tiff -void m_burn(GtkWidget *, cchar *); // burn selected images to CD/DVD -void m_email(GtkWidget *, cchar *); // e-mail selected images -void m_syncfiles(GtkWidget *, cchar *); // rebuild thumbnails and search index -int syncfiles_func(void *); // sync files function (in subprocess) -void m_tbar_style(GtkWidget *, cchar *); // customize toolbar style dialog -void tbar_style_set(cchar *style); // set toolbar style (initz. and dialog) +void m_settings(GtkWidget *, cchar *); // user settings void m_memory_usage(GtkWidget *, cchar *); // report memory consumption by category -// Image Information menu functions (EXIF, IPTC, etc.) +// info menu functions (EXIF, IPTC, etc.) void m_edit_cctext(GtkWidget *, cchar *); // edit caption and user comments dialog void m_edit_tags(GtkWidget *, cchar *); // edit tags dialog @@ -500,9 +539,11 @@ void m_info_edit(GtkWidget *, cchar *); // add or change EXIF/IPTC data void m_info_delete(GtkWidget *, cchar *); // delete EXIF/IPTC data char ** info_get(cchar *file, cchar **keys, int nkeys); // get EXIF/IPTC data for given key(s) +char ** info_getN(cchar **files, int NF, cchar **keys, int NK); // " " data for given keys and files int info_put(cchar *file, cchar **keys, cchar **text, int nkeys); // put EXIF/IPTC data for given key(s) int info_copy(cchar *f1, cchar *f2, cchar **k, cchar **t, int nk); // copy EXIF/IPTC data from file to file void m_search_images(GtkWidget *, cchar *); // search tags, comments, captions, files +void m_search_metadata(GtkWidget *, cchar *); // search and report image metadata // select area menu functions @@ -527,8 +568,7 @@ int sa_nearpix(int mx, int my, int rad, int &npx, int &npy); // find nearest line-end void sa_draw_line(int px1, int py1, int px2, int py2); // draw a connected line void sa_draw1pix(int px, int py); // draw one pixel if not already -void sa_color_mousefunc(); // color range select function -void sa_radius_mousefunc(); // radius select function +void sa_mouse_mousefunc(); // select by radius and color match void sa_nextseq(); // start next sequence number void sa_unselect_pixels(); // remove current selection @@ -549,8 +589,8 @@ void m_rotate(GtkWidget *, cchar *); // rotate image void m_trim(GtkWidget *, cchar *); // trim image +void m_autotrim(GtkWidget *, cchar *); // autotrim image after rotate, warp void m_resize(GtkWidget *, cchar *); // resize image -void m_batchresize(GtkWidget *, cchar *); // resize many images void m_annotate(GtkWidget *, cchar *); // annotate image void m_flip(GtkWidget *, cchar *); // flip horizontally or vertically void m_negate(GtkWidget *, cchar *); // B+W and color negatives @@ -579,6 +619,7 @@ void m_denoise(GtkWidget *, cchar *); // image noise reduction void m_smart_erase(GtkWidget *, const char *); // smart erase object void m_dust(GtkWidget *, const char *); // remove dust +void m_stuckpix(GtkWidget *, const char *); // fix stuck pixels void m_pixedit(GtkWidget *, cchar *); // edit pixels // image edit functions - art menu @@ -656,7 +697,6 @@ int f_save(char *outfile, cchar *type, int bpc); // save current image pixmap to a file PXM * TIFFread(cchar *filespec); // read TIFF file, native bpc int TIFFwrite(PXM *pxm, cchar *filespec); // write TIFF file, bpc from pxm -void tiffwarninghandler(cchar *mod, cchar *fmt, va_list); // intercepts TIFF lib warnings PXM * PXBread(cchar *filespec); // read using pixbuf library, bpc = 8 int PXBwrite(PXM *pxm, cchar *filespec); // write using pixbuf library, bpc = 8 @@ -667,10 +707,21 @@ PXM * PXM_copy(PXM *pxm); // copy PXM pixmap PXM * PXM_copy_area(PXM *pxm, int orgx, int orgy, int ww, int hh); // copy section of PXM pixmap PXM * PXM_convbpc(PXM *pxm); // convert from 8/16 to 16/8 bpc +void PXM_fixblue(PXM *pxm); // set blue = 0 pixels to blue = 2 PXM * PXM_rescale(PXM *pxm, int ww, int hh); // rescale PXM pixmap (ww/hh) void PXM_update(PXM *p16, PXM *p8, int orgx, int orgy, int ww, int hh); // copy section of PXM-16 into PXM-8 PXM * PXM_rotate(PXM *pxm, double angle); // rotate PXM pixmap -void PXM_fixblue(PXM *pxm); // set blue = 0 pixels to blue = 1 + +// image navigation and thumbnail gallery functions +// for functions returning char *, caller responsible for zfree() + +char * image_gallery(cchar *filez, cchar *action, int Nth = 0, // display image gallery window, navigate, + void ufunc(int Nth, int butt) = 0, GtkWidget *parent = 0); // do callback for clicked thumbnails +int image_gallery_position(cchar *file, int Nth); // get relative position of file in gallery +int image_file_type(cchar *file); // determine if directory or image file type +char * image_thumbfile(char *imagefile); // get thumbnail filespec, create if missing +GdkPixbuf * image_thumbnail(char *imagefile, int size = 0); // get thumbnail pixbuf, create if missing +char ** image_gallery_getfiles(char *startdir, GtkWidget *parent = 0); // select files from gallery window // translatable strings used in multiple dialogs @@ -680,6 +731,7 @@ #define Ball ZTX("All") #define Bamount ZTX("Amount") #define Bapply ZTX("Apply") +#define Bblack ZTX("Black") #define Bblendwidth ZTX("Blend Width") #define Bblue ZTX("Blue") #define Bbrightness ZTX("Brightness") @@ -694,6 +746,7 @@ #define Bdarker ZTX("Darker Areas") #define Bdelete ZTX("Delete") #define Bdisable ZTX("Disable") +#define Bdiscard ZTX("Discard special gallery list? \n %s") #define Bdone ZTX("Done") #define Bedit ZTX("Edit") #define Benable ZTX("Enable") @@ -710,7 +763,6 @@ #define Binvert ZTX("Invert") #define Blighter ZTX("Lighter Areas") #define Blimit ZTX("limit") -#define BmyMouse ZTX("my mouse") #define Bnew ZTX("New") #define Bnext ZTX("Next") #define BOK ZTX("OK") @@ -736,12 +788,14 @@ #define Bshow ZTX("Show") #define Bstart ZTX("Start") #define Bthresh ZTX("Threshold") +#define Btoomanyfiles ZTX("exceed %d files") #define Bundoall ZTX("Undo All") #define Bundolast ZTX("Undo Last") #define Bundo ZTX("Undo") #define Bunfinish ZTX("Unfinish") #define Bunselect ZTX("Unselect") #define Bview ZTX("View") +#define Bwhite ZTX("White") #define Bwidth ZTX("Width") diff -Nru fotoxx-11.11.1/fotoxx_info.cc fotoxx-12.01.2/fotoxx_info.cc --- fotoxx-11.11.1/fotoxx_info.cc 2011-11-05 05:30:36.000000000 +0000 +++ fotoxx-12.01.2/fotoxx_info.cc 1970-01-01 00:00:00.000000000 +0000 @@ -1,2651 +0,0 @@ -/************************************************************************** - - Fotoxx edit photos and manage collections - - Copyright 2007 2008 2009 2010 2011 Michael Cornelison - Source URL: http://kornelix.squarespace.com/fotoxx - Contact: kornelix2@googlemail.com - - 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 http://www.gnu.org/licenses/. - -***************************************************************************/ - -#define EX extern // enable extern declarations -#include "fotoxx.h" - - -/************************************************************************** - - Fotoxx image editor - image metadata functions, EXIF/IPTC etc. - -***************************************************************************/ - -int get_mouse_tag(GtkTextView *, int px, int py, cchar *); // get tag selected by mouse -int add_tag(char *tag, char *taglist, int maxcc); // add tag if unique and enough space -int del_tag(char *tag, char *taglist); // remove tag from tag list -int add_recentag(char *tag); // add tag to recent tags, keep most recent -void load_deftags(); // tags_defined file >> tags_deftags[] -void save_deftags(); // tags_deftags[] >> defined_tags file -int find_deftag(char *tag); // find tag in tags_deftags[] -int add_deftag(char *catg, char *tag); // add tag to tags_deftags[] -int del_deftag(char *tag); // remove tag from tags_deftags[] -void deftags_stuff(zdialog *zd); // tags_deftags[] >> dialog widget "deftags" - -char tags_date[12] = ""; // image date, yyyymmdd -char tags_prdate[12] = ""; // previous image date read or set -char tags_stars = '0'; // image rating in stars, '0' to '5' -char tags_cliktag[tagcc] = ""; // tag clicked by mouse -char tags_clikcatg[tagcc] = ""; // category clicked by mouse -char *tags_deftags[maxtagcats]; // defined tags: catg: tag1, tag2, ... tagN, -char tags_deftext[tagTcc] = ""; // defined tags as flat text buffer -char tags_filetags[tagFcc] = ""; // tags for current image file -char tags_recentags[tagRcc] = ""; // recently added tags list -char tags_batchAddTags[tagMcc] = ""; // batch add tags list -char tags_searchtags[tagScc] = ""; // search tags list -char tags_searchtext[tagScc] = ""; // search comments & captions word list -char tags_searchfiles[tagScc] = ""; // search files list -char tags_comments[tagFcc]; // image comments -char tags_caption[tagFcc]; // image caption - - -/**************************************************************************/ - -// View and edit IPTC Caption and EXIF UserComment data - -void m_edit_cctext(GtkWidget *, cchar *menu) // 2 functions combined v.11.09 -{ - int edit_cctext_dialog_event(zdialog *zd, cchar *event); - char text[tagFcc]; - cchar *title = ZTX("Edit Caption and Comments"); - - if (menu) zfuncs::F1_help_topic = "edit_cctext"; - - if (! curr_file) return; - - if (! Fexiftool) { // exiftool is required - zmessageACK(mWin,Bexiftoolmissing); - return; - } - - if (! zdeditcctext) // popup dialog if not already - { - zdeditcctext = zdialog_new(title,mWin,Bapply,Bcancel,null); - zdialog *zd = zdeditcctext; - zdialog_add_widget(zd,"hbox","hbcap","dialog"); - zdialog_add_widget(zd,"label","labcap","hbcap","Caption","space=5"); - zdialog_add_widget(zd,"frame","framecap","hbcap",0,"expand"); - zdialog_add_widget(zd,"edit","textcap","framecap",0,"space=5|wrap"); - zdialog_add_widget(zd,"hbox","hbcom","dialog"); - zdialog_add_widget(zd,"label","labcom","hbcom","Comments","space=5"); - zdialog_add_widget(zd,"frame","framecom","hbcom",0,"expand"); - zdialog_add_widget(zd,"edit","textcom","framecom",0,"space=5|wrap"); - zdialog_resize(zd,300,0); - zdialog_help(zd,"edit_cctext"); // zdialog help topic v.11.08 - zdialog_run(zd,edit_cctext_dialog_event); - } - - load_fileinfo(curr_file); // get current caption and comments - repl_1str(tags_caption,text,"\\n","\n"); // replace "\n" with real newlines - zdialog_stuff(zdeditcctext,"textcap",text); // stuff into dialog - repl_1str(tags_comments,text,"\\n","\n"); // replace "\n" with real newlines - zdialog_stuff(zdeditcctext,"textcom",text); // stuff into dialog - - return; -} - - -// dialog event and completion callback function - -int edit_cctext_dialog_event(zdialog *zd, cchar *event) -{ - char text[tagFcc]; - - if (! zd->zstat) return 0; - - else if (zd->zstat == 1) // apply, save text - { - zd->zstat = 0; // keep dialog active - if (is_syncbusy()) return 0; // must wait for file sync v.11.11 - zdialog_fetch(zd,"textcap",text,tagFcc); // get new cctext - repl_1str(text,tags_caption,"\n","\\n"); // replace newlines with "\n" - zdialog_fetch(zd,"textcom",text,tagFcc); // get new cctext - repl_1str(text,tags_comments,"\n","\\n"); // replace newlines with "\n" - Ftagschanged = 1; - save_fileinfo(curr_file); // save in image file - } - - else zdialog_free(zdeditcctext); // cancel - - return 1; -} - - -/**************************************************************************/ - -// edit tags menu function - -void m_edit_tags(GtkWidget *, cchar *menu) -{ - void edittags_fixwidget(zdialog *, cchar * widgetname); // fix tags widget for selecting with mouse - int edittags_dialog_event(zdialog *zd, cchar *event); - - char *ppv, starsN[12]; - - if (menu) zfuncs::F1_help_topic = "edit_tags"; - - if (! Fexiftool) { // exiftool is required - zmessageACK(mWin,Bexiftoolmissing); - return; - } - - if (! curr_file) return; - - if (! zdedittags) // (re) start tag edit dialog - { - zdedittags = zdialog_new(ZTX("Edit Tags"),mWin,Bapply,Bcancel,null); - - zdialog_add_widget(zdedittags,"hbox","hb1","dialog",0,"space=5"); - zdialog_add_widget(zdedittags,"label","labfile","hb1",ZTX("file:"),"space=5"); - zdialog_add_widget(zdedittags,"label","file","hb1"); - - zdialog_add_widget(zdedittags,"hbox","hb2","dialog",0,"space=5"); - zdialog_add_widget(zdedittags,"label","lab21","hb2",ZTX("image date (yyyymmdd)"),"space=5"); - zdialog_add_widget(zdedittags,"entry","date","hb2",0,"scc=12"); - zdialog_add_widget(zdedittags,"button","prdate","hb2",ZTX("use last"),"space=5"); - - zdialog_add_widget(zdedittags,"hbox","hb3","dialog",0,"space=5"); - zdialog_add_widget(zdedittags,"label","labstars","hb3",ZTX("image stars"),"space=5"); - zdialog_add_widget(zdedittags,"vbox","vb3","hb3"); - zdialog_add_widget(zdedittags,"hbox","hb31","vb3",0,"homog"); - zdialog_add_widget(zdedittags,"hbox","hb32","vb3",0,"homog"); - zdialog_add_widget(zdedittags,"label","lab30","hb31","0"); - zdialog_add_widget(zdedittags,"label","lab31","hb31","1"); - zdialog_add_widget(zdedittags,"label","lab32","hb31","2"); - zdialog_add_widget(zdedittags,"label","lab33","hb31","3"); - zdialog_add_widget(zdedittags,"label","lab34","hb31","4"); - zdialog_add_widget(zdedittags,"label","lab35","hb31","5"); - zdialog_add_widget(zdedittags,"radio","stars0","hb32",0); - zdialog_add_widget(zdedittags,"radio","stars1","hb32",0); - zdialog_add_widget(zdedittags,"radio","stars2","hb32",0); - zdialog_add_widget(zdedittags,"radio","stars3","hb32",0); - zdialog_add_widget(zdedittags,"radio","stars4","hb32",0); - zdialog_add_widget(zdedittags,"radio","stars5","hb32",0); - - zdialog_add_widget(zdedittags,"hbox","hb4","dialog",0,"space=5"); - zdialog_add_widget(zdedittags,"label","lab4","hb4",ZTX("current tags"),"space=5"); - zdialog_add_widget(zdedittags,"frame","frame4","hb4",0,"expand"); - zdialog_add_widget(zdedittags,"edit","filetags","frame4",0,"expand|wrap"); // v.11.06 - - zdialog_add_widget(zdedittags,"hbox","hb5","dialog",0,"space=5"); - zdialog_add_widget(zdedittags,"label","recent","hb5",ZTX("recent tags"),"space=5"); - zdialog_add_widget(zdedittags,"frame","frame5","hb5",0,"expand"); - zdialog_add_widget(zdedittags,"edit","recentags","frame5",0,"expand|wrap"); // v.11.06 - - zdialog_add_widget(zdedittags,"hbox","hb8","dialog"); - zdialog_add_widget(zdedittags,"label","labdeftags","hb8",ZTX("defined tags"),"space=5"); - zdialog_add_widget(zdedittags,"hbox","hb9","dialog",0,"expand"); - zdialog_add_widget(zdedittags,"frame","frame8","hb9",0,"space=5|expand"); - zdialog_add_widget(zdedittags,"scrwin","scrwin8","frame8",0,"expand"); - zdialog_add_widget(zdedittags,"edit","deftags","scrwin8",0,"expand|wrap"); // v.11.06 - - zdialog_resize(zdedittags,500,500); // run dialog - zdialog_help(zdedittags,"edit_tags"); // zdialog help topic v.11.08 - zdialog_run(zdedittags,edittags_dialog_event); - - edittags_fixwidget(zdedittags,"filetags"); // setup for mouse tag selection - edittags_fixwidget(zdedittags,"recentags"); - edittags_fixwidget(zdedittags,"deftags"); - - load_deftags(); // stuff defined tags into dialog - deftags_stuff(zdedittags); - } - - load_fileinfo(curr_file); // get EXIF/IPTC data - - ppv = (char *) strrchr(curr_file,'/'); - zdialog_stuff(zdedittags,"file",ppv+1); // stuff dialog file name - - zdialog_stuff(zdedittags,"date",tags_date); // stuff dialog data - sprintf(starsN,"stars%c",tags_stars); - zdialog_stuff(zdedittags,starsN,1); - zdialog_stuff(zdedittags,"filetags",tags_filetags); - zdialog_stuff(zdedittags,"recentags",tags_recentags); - - return; -} - - -// setup tag display widget for tag selection using mouse clicks - -void edittags_fixwidget(zdialog *zd, cchar * widgetname) -{ - void edittags_mouse(GtkTextView *, GdkEventButton *, cchar *); // select tag via mouse click - - GtkWidget *widget; - GdkWindow *gdkwin; - - widget = zdialog_widget(zd,widgetname); // make widget wrap text - gtk_text_view_set_editable(GTK_TEXT_VIEW(widget),0); // disable widget editing - - gdkwin = gtk_text_view_get_window(GTK_TEXT_VIEW(widget),TEXTWIN); // cursor for tag selection - gdk_window_set_cursor(gdkwin,arrowcursor); - - gtk_widget_add_events(widget,GDK_BUTTON_PRESS_MASK); // connect mouse-click event - G_SIGNAL(widget,"button-press-event",edittags_mouse,widgetname) -} - - -// edit tags mouse-click event function -// get clicked tag and add to or remove from file tags and recent tags - -void edittags_mouse(GtkTextView *widget, GdkEventButton *event, cchar *widgetname) -{ - int mpx, mpy; - - if (event->type != GDK_BUTTON_PRESS) return; - mpx = int(event->x); // mouse click position - mpy = int(event->y); - - get_mouse_tag(widget,mpx,mpy,widgetname); // tags_cliktag = clicked tag in list - if (! *tags_cliktag) return; - - if (strEqu(widgetname,"filetags")) { // remove tag from file tags - del_tag(tags_cliktag,tags_filetags); - zdialog_stuff(zdedittags,"filetags",tags_filetags); // update dialog widgets - } - - if (strEqu(widgetname,"recentags")) { // add recent tag to file tags - add_tag(tags_cliktag,tags_filetags,tagFcc); - zdialog_stuff(zdedittags,"filetags",tags_filetags); - } - - if (strEqu(widgetname,"deftags")) { // add defined tag to file tags - add_tag(tags_cliktag,tags_filetags,tagFcc); - zdialog_stuff(zdedittags,"filetags",tags_filetags); - add_recentag(tags_cliktag); // and to recent tags - zdialog_stuff(zdedittags,"recentags",tags_recentags); - } - - *tags_cliktag = 0; - return; -} - - -// dialog event and completion callback function - -int edittags_dialog_event(zdialog *zd, cchar *event) -{ - int err; - - if (zd->zstat) { - if (zd->zstat == 1) { // [apply] - zd->zstat = 0; // keep dialog active - if (is_syncbusy()) return 0; // must wait for file sync v.11.11 - save_fileinfo(curr_file); // save tag changes - return 0; - } - - zdialog_free(zdedittags); // cancel - kill dialog - return 0; - } - - if (strEqu(event,"date")) { // image date revised - err = zdialog_fetch(zd,"date",tags_date,11); - if (err) return 1; - if (strlen(tags_date) == 4) strcat(tags_date,"0101"); // yyyy >> yyyy0101 - if (strlen(tags_date) == 6) strcat(tags_date,"01"); // yyyymm >> yyyymm01 - Ftagschanged++; - } - - if (strEqu(event,"prdate")) { // repeat last date used - if (*tags_prdate) { - zdialog_stuff(zd,"date",tags_prdate); - strcpy(tags_date,tags_prdate); - Ftagschanged++; - } - } - - if (strnEqu(event,"stars",5)) { // event = stars0 to stars5 - tags_stars = event[5]; // '0' to '5' - Ftagschanged++; - } - - if (strEqu(event,"tags-changed")) // get new defined tags data - deftags_stuff(zdedittags); // v.11.02 - - return 0; -} - - -/**************************************************************************/ - -// manage tags menu function - -zdialog *zdmanagetags = 0; - -void m_manage_tags(GtkWidget *, cchar *) // v.11.02 - separate edit and manage tags -{ - void managetags_fixwidget(zdialog *, cchar * widgetname); // fix tags widget for selecting with mouse - int managetags_dialog_event(zdialog *zd, cchar *event); - - zfuncs::F1_help_topic = "manage_tags"; - - if (zdmanagetags) return; - zdmanagetags = zdialog_new(ZTX("Manage Tags"),mWin,Bcancel,null); - - zdialog_add_widget(zdmanagetags,"hbox","hb7","dialog",0,"space=5"); - zdialog_add_widget(zdmanagetags,"label","labcatg","hb7",ZTX("category"),"space=5"); - zdialog_add_widget(zdmanagetags,"entry","catg","hb7",0,"scc=12"); - zdialog_add_widget(zdmanagetags,"label","space","hb7",0,"space=5"); - zdialog_add_widget(zdmanagetags,"label","labtag","hb7",ZTX("tag"),"space=5"); - zdialog_add_widget(zdmanagetags,"entry","tag","hb7",0,"scc=20|expand"); - zdialog_add_widget(zdmanagetags,"label","space","hb7",0,"space=5"); - zdialog_add_widget(zdmanagetags,"button","create","hb7",ZTX("create")); - zdialog_add_widget(zdmanagetags,"button","delete","hb7",ZTX("delete")); - - zdialog_add_widget(zdmanagetags,"hbox","hb8","dialog"); - zdialog_add_widget(zdmanagetags,"label","labdeftags","hb8",ZTX("defined tags"),"space=5"); - zdialog_add_widget(zdmanagetags,"hbox","hb9","dialog",0,"expand"); - zdialog_add_widget(zdmanagetags,"frame","frame8","hb9",0,"space=5|expand"); - zdialog_add_widget(zdmanagetags,"scrwin","scrwin8","frame8",0,"expand"); - zdialog_add_widget(zdmanagetags,"edit","deftags","scrwin8",0,"expand|wrap"); // v.11.06 - - zdialog_resize(zdmanagetags,0,400); // run dialog - zdialog_help(zdmanagetags,"manage_tags"); // zdialog help topic v.11.08 - zdialog_run(zdmanagetags,managetags_dialog_event); - - managetags_fixwidget(zdmanagetags,"deftags"); // setup for mouse tag selection - - load_deftags(); // stuff defined tags into dialog - deftags_stuff(zdmanagetags); - - return; -} - - -// setup tag display widget for tag selection using mouse clicks - -void managetags_fixwidget(zdialog *zd, cchar * widgetname) -{ - void managetags_mouse(GtkTextView *, GdkEventButton *, cchar *); // select tag via mouse click - - GtkWidget *widget; - GdkWindow *gdkwin; - - widget = zdialog_widget(zd,widgetname); // make widget wrap text - gtk_text_view_set_editable(GTK_TEXT_VIEW(widget),0); // disable widget editing - - gdkwin = gtk_text_view_get_window(GTK_TEXT_VIEW(widget),TEXTWIN); // cursor for tag selection - gdk_window_set_cursor(gdkwin,arrowcursor); - - gtk_widget_add_events(widget,GDK_BUTTON_PRESS_MASK); // connect mouse-click event - G_SIGNAL(widget,"button-press-event",managetags_mouse,widgetname) -} - - -// manage tags mouse-click event function -// get clicked tag category or tag name - -void managetags_mouse(GtkTextView *widget, GdkEventButton *event, cchar *widgetname) -{ - int mpx, mpy, cc; - - if (event->type != GDK_BUTTON_PRESS) return; - mpx = int(event->x); // mouse click position - mpy = int(event->y); - - cc = get_mouse_tag(widget,mpx,mpy,widgetname); // tags_cliktag = clicked tag in list - - if (! cc) { - if (*tags_clikcatg) // selected category >> dialog widget - zdialog_stuff(zdmanagetags,"catg",tags_clikcatg); - return; - } - - zdialog_stuff(zdmanagetags,"tag",tags_cliktag); // selected tag >> dialog widget - return; -} - - -// dialog event and completion callback function - -int managetags_dialog_event(zdialog *zd, cchar *event) -{ - char tag[tagcc], catg[tagcc]; - int changed = 0; - - if (zd->zstat) { - zdialog_free(zdmanagetags); - return 0; - } - - if (strEqu(event,"create")) { // add new tag to defined tags - zdialog_fetch(zd,"catg",catg,tagcc); - zdialog_fetch(zd,"tag",tag,tagcc); - add_deftag(catg,tag); - changed++; - } - - if (strEqu(event,"delete")) { // remove tag from defined tags - zdialog_fetch(zd,"tag",tag,tagcc); - del_deftag(tag); - changed++; - } - - if (changed) { - save_deftags(); // save tag updates to file - deftags_stuff(zdmanagetags); // update dialog "deftags" window - if (zdedittags) // and edit tags window if active - zdialog_send_event(zdedittags,"tags-changed"); - } - - return 0; -} - - -/**************************************************************************/ - -// Convert mouse click position in a tag list into the selected tag. -// cc of selected tag is returned, or zero if no tag clicked. -// Selected tag is returned in tags_cliktag, or null if no tag clicked. -// If a category is clicked, it is returned in tags_clikcatg and zero is returned. - -int get_mouse_tag(GtkTextView *widget, int mpx, int mpy, cchar *widgetname) -{ - GtkTextIter iter; - int tbx, tby, offset, cc; - char *ptext, *pp1, *pp2; - - *tags_cliktag = *tags_clikcatg = 0; // start with no tag or category v.11.05 - - gtk_text_view_window_to_buffer_coords(widget,GTK_TEXT_WINDOW_TEXT,mpx,mpy,&tbx,&tby); - gtk_text_view_get_iter_at_location(widget,&iter,tbx,tby); - offset = gtk_text_iter_get_offset(&iter); // graphic position in widget text - - ptext = 0; - if (strEqu(widgetname,"filetags")) ptext = tags_filetags; // get corresponding text - if (strEqu(widgetname,"recentags")) ptext = tags_recentags; - if (strEqu(widgetname,"batchAddTags")) ptext = tags_batchAddTags; - if (strEqu(widgetname,"searchtags")) ptext = tags_searchtags; - if (strEqu(widgetname,"deftags")) ptext = tags_deftext; - if (! ptext) return 0; - - pp1 = ptext + utf8_position(ptext,offset); // graphic position to byte position - - if (! *pp1 || strchr(tagdelims":\n",*pp1)) return 0; // reject edge position or delimiter - while (pp1 > ptext && ! strchr(tagdelims":\n",pp1[-1])) pp1--; // find start of tag - pp2 = pp1; - while (pp2[1] && ! strchr(tagdelims":\n",pp2[1])) pp2++; // find following delimiter including ":" - while (*pp1 == ' ') pp1++; // no leading or trailing blanks - while (*pp2 == ' ') pp2--; - cc = pp2 - pp1 + 1; - if (cc <= 1) return 0; // reject tag < 2 chars. - if (cc >= tagcc) return 0; // reject tag too big - if (pp2[1] == ':') { - strncpy0(tags_clikcatg,pp1,cc+1); // tags_clikcatg = selected category - return 0; // return 0 - } - strncpy0(tags_cliktag,pp1,cc+1); // tags_cliktag = selected tag - return cc; // return cc -} - - -/**************************************************************************/ - -// add input tag to output tag list if not already there and enough room -// returns: 0 = added OK 1 = not unique (case ignored) -// 2 = overflow 3 = bad utf8 characters 4 = null tag - -int add_tag(char *tag, char *taglist, int maxcc) -{ - char *pp1, *pp2, tag1[tagcc], tag2[tagcc]; - int cc, cc1, cc2; - - strncpy0(tag1,tag,tagcc); // remove leading and trailing blanks - cc = strTrim2(tag2,tag1); - if (! cc) return 4; - - if (utf8_check(tag2)) { // check for valid utf8 encoding - printf("bad utf8 characters: %s \n",tag2); - return 3; - } - - while ((pp1 = strpbrk(tag2,tagdelims":"))) *pp1 = '-'; // replace problem characters - - strcpy(tag,tag2); // replace tag with sanitized version - - pp1 = taglist; - cc1 = strlen(tag); - - while (true) // check if already in tag list - { - while (*pp1 == ' ' || *pp1 == tagdelim1) pp1++; - if (! *pp1) break; - pp2 = pp1 + 1; - while (*pp2 && *pp2 != tagdelim1) pp2++; - cc2 = pp2 - pp1; - if (cc2 == cc1 && strncaseEqu(tag,pp1,cc1)) return 1; - pp1 = pp2; - } - - cc2 = strlen(taglist); // append to tag list if space enough - if (cc1 + cc2 + 3 > maxcc) return 2; - strcpy(taglist + cc2,tag); - strcpy(taglist + cc2 + cc1, tagdelim2); // add delimiter + space - - if (taglist == tags_filetags) // image tags were changed - Ftagschanged++; - return 0; -} - - -// remove tag from taglist, if present -// returns: 0 if found and deleted, otherwise 1 - -int del_tag(char *tag, char *taglist) -{ - int ii, ftcc, atcc, found; - char *temptags; - cchar *pp; - - temptags = strdupz(taglist,0,"del_tag"); - - *taglist = 0; - ftcc = found = 0; - - for (ii = 1; ; ii++) - { - pp = strField(temptags,tagdelims,ii); // next tag - if (! pp) { - zfree(temptags); - if (found && taglist == tags_filetags) // image tags were changed - Ftagschanged++; - return 1-found; - } - if (*pp == ' ') continue; - - if (strcaseEqu(pp,tag)) { // skip matching tag - found = 1; - continue; - } - - atcc = strlen(pp); // copy non-matching tag - strcpy(taglist + ftcc, pp); - ftcc += atcc; - strcpy(taglist + ftcc, tagdelim2); // + delim + blank - ftcc += 2; - } -} - - -// add new tag to recent tags, if not already. -// remove oldest to make space if needed. - -int add_recentag(char *tag) -{ - int err; - char *pp, temptags[tagRcc]; - - err = add_tag(tag,tags_recentags,tagRcc); // add tag to recent tags - - while (err == 2) // overflow - { - strncpy0(temptags,tags_recentags,tagRcc); // remove oldest to make room - pp = strpbrk(temptags,tagdelims); - if (! pp) return 0; - strcpy(tags_recentags,pp+2); // delimiter + blank before tag - err = add_tag(tag,tags_recentags,tagRcc); - } - - return 0; -} - - -/**************************************************************************/ - -// Load tags_defined file into tags_deftags[ii] => category: tag1, tag2, ... -// Read search_index file and add unmatched tags: => nocatg: tag1, tag2, ... - -void load_deftags() -{ - int tags_Ucomp(cchar *tag1, cchar *tag2); - - static int Floaded = 0; - FILE *fid; - int ii, jj, ntags, err, cc, tcc; - int ncats, catoverflow; - int nocat, nocatcc; - char tag[tagcc], catg[tagcc]; - char tagsbuff[tagGcc]; - char *pp1, *pp2; - char ptags[tagntc][tagcc]; - - if (Floaded) return; // use memory tags if already there v.11.02 - Floaded++; - - for (ii = 0; ii < maxtagcats; ii++) // clean memory - tags_deftags[ii] = 0; - - ncats = catoverflow = 0; - - fid = fopen(tags_defined_file,"r"); // read tags_defined file - if (fid) { - while (true) { - pp1 = fgets_trim(tagsbuff,tagGcc,fid); - if (! pp1) break; - if (ncats == maxtagcats-1) goto toomanycats; - pp2 = strchr(pp1,':'); // isolate "category:" - if (! pp2) continue; // reject bad data - cc = pp2 - pp1 + 1; - if (cc > tagcc-1) continue; - strncpy0(catg,pp1,cc); // (for error message) - if (strlen(pp1) > tagGcc-2) goto cattoobig; - pp2++; - while (*pp2 == ' ') pp2++; - if (strlen(pp2) < 3) continue; - while ((pp2 = strpbrk(pp2,tagdelims))) *pp2++ = tagdelim1; // force comma delimiter v.11.02 - tags_deftags[ncats] = strdupz(pp1,0,"def_tags"); // tags_deftags[ii] - ncats++; // = category: tag1, tag2, ... tagN, - } - err = fclose(fid); - if (err) goto deftagserr; - } - - nocat = ncats; // make last category "nocatg" for - ncats++; // unmatched tags in search_index file - tags_deftags[nocat] = zmalloc(tagGcc,"deftags"); - strcpy(tags_deftags[nocat],"nocatg: "); - nocatcc = 8; - - fid = fopen(search_index_file,"r"); // read search_index file - if (! fid) return; - - while (true) - { - pp1 = fgets_trim(tagsbuff,tagGcc,fid); // next image file tags record - if (! pp1) break; - if (strnNeq(tagsbuff,"tags: ",6)) continue; - pp1 = pp1 + 6; - - while (true) - { - while (*pp1 && strchr(tagdelims" ",*pp1)) pp1++; // next image tag start - if (! *pp1) break; - pp2 = strpbrk(pp1,tagdelims); // end - if (! pp2) pp2 = pp1 + strlen(pp1); - cc = pp2 - pp1; - if (cc > tagcc-1) { - pp1 = pp2; // bugfix v.10.9 - continue; // ignore huge tag - } - - strncpy0(tag,pp1,cc+1); // look for tag in defined tags - err = find_deftag(tag); - if (! err) { // found - pp1 = pp2; - continue; - } - - if (nocatcc + cc + 2 > tagGcc-2) { - catoverflow = 1; // nocatg: length limit reached - break; - } - else { - strcpy(tags_deftags[nocat] + nocatcc, tag); // append tag to list - nocatcc += cc; - strcpy(tags_deftags[nocat] + nocatcc, tagdelim2); // + delim + blank - nocatcc += 2; - } - - pp1 = pp2; - } - } - - err = fclose(fid); - if (err) goto filetagserr; - if (catoverflow) goto cattoobig; - -// parse all the tags in each category and sort in ascending order - - for (ii = 0; ii < ncats; ii++) - { - pp1 = tags_deftags[ii]; - pp2 = strchr(pp1,':'); - cc = pp2 - pp1 + 1; - strncpy0(catg,pp1,cc); - pp1 = pp2 + 1; - while (*pp1 == ' ') pp1++; - tcc = 0; - - for (jj = 0; jj < tagntc; jj++) - { - if (! *pp1) break; - pp2 = strchr(pp1,tagdelim1); - if (pp2) cc = pp2 - pp1; - else cc = strlen(pp1); - if (cc > tagcc-1) cc = tagcc-1; - strncpy0(ptags[jj],pp1,cc+1); - pp1 += cc + 1; - tcc += cc; - while (*pp1 == ' ') pp1++; - } - - ntags = jj; - if (ntags == tagntc) goto cattoobig; - HeapSort((char *) ptags,tagcc,ntags,tags_Ucomp); - - pp1 = tags_deftags[ii]; - tcc += strlen(catg) + 2 + 2 * ntags + 2; // category, all tags, delimiters - pp2 = zmalloc(tcc,"deftags"); - - tags_deftags[ii] = pp2; // swap memory - zfree(pp1); - - strcpy(pp2,catg); - pp2 += strlen(catg); - strcpy(pp2,": "); // pp2 = "category: " - pp2 += 2; - - for (jj = 0; jj < ntags; jj++) // add the sorted tags - { - strcpy(pp2,ptags[jj]); // append tag + delim + blank - pp2 += strlen(pp2); - strcpy(pp2,tagdelim2); - pp2 += 2; - } - - *pp2 = 0; - } - -// sort the categories in ascending order -// leave "nocatg" at the end - - for (ii = 0; ii < ncats-1; ii++) - for (jj = ii+1; jj < ncats-1; jj++) // v.11.02 - { - pp1 = tags_deftags[ii]; - pp2 = tags_deftags[jj]; - if (strcasecmp(pp1,pp2) > 0) { - tags_deftags[ii] = pp2; - tags_deftags[jj] = pp1; - } - } - - return; - -toomanycats: - zmessLogACK(mWin,"more than %d categories",maxtagcats); - fclose(fid); - return; - -cattoobig: - zmessLogACK(mWin,"category %s is too big",catg); - fclose(fid); - return; - -deftagserr: - zmessLogACK(mWin,"tags_defined file error: %s",strerror(errno)); - return; - -filetagserr: - zmessLogACK(mWin,"search_index file error: %s",strerror(errno)); - return; -} - - -// compare function for tag sorting -// wcscasecmp does not work for plain ascii -// so what happens to Chinese, etc? - -int tags_Ucomp(cchar *tag1, cchar *tag2) -{ - return strcasecmp(tag1,tag2); -} - - -// write tags_deftags[] memory data to the defined tags file if any changes were made - -void save_deftags() -{ - int ii, err; - FILE *fid; - - fid = fopen(tags_defined_file,"w"); // write tags_defined file - if (! fid) goto deftagserr; - - for (ii = 0; ii < maxtagcats; ii++) - { - if (! tags_deftags[ii+1]) break; // omit last category, "nocatg" - err = fprintf(fid,"%s\n",tags_deftags[ii]); // each record: - if (err < 0) goto deftagserr; // category: tag1, tag2, ... tagN, - } - - err = fclose(fid); - if (err) goto deftagserr; - return; - -deftagserr: - zmessLogACK(mWin,"tags_defined file error: %s",strerror(errno)); - return; -} - - -// find a given tag in tags_deftags[] -// return: 0 = found, 1 = not found - -int find_deftag(char *tag) -{ - int ii, cc; - char tag2[tagcc+4]; - char *pp; - - if (! tag || *tag <= ' ') return 0; // bad tag - - strncpy0(tag2,tag,tagcc); // construct tag + delim + blank - cc = strlen(tag2); - strcpy(tag2+cc,tagdelim2); - cc += 2; - - for (ii = 0; ii < maxtagcats; ii++) - { - pp = tags_deftags[ii]; // category: tag1, tag2, ... tagN, - if (! pp) return 1; // not found - - while (pp) - { - pp = strcasestr(pp,tag2); // look for delim + blank + tag + delim - if (! pp) break; - if (strchr(tagdelims":", pp[-2])) return 0; - pp += cc; - } - } - - return 1; -} - - -// add new tag to tags_deftags[] >> category: tag1, tag2, ... newtag, -// returns: 0 = added OK 1 = not unique (case ignored) -// 2 = overflow 3 = bad utf8 characters 4 = null tag -// if tag present under another category, it is moved to new category - -int add_deftag(char *catg, char *tag) -{ - int ii, cc, cc1, cc2; - char tag1[tagcc], tag2[tagcc]; - char *pp1, *pp2; - - strncpy0(tag1,tag,tagcc); // remove leading and trailing blanks - cc = strTrim2(tag2,tag1); - if (! cc) return 4; - - if (utf8_check(tag2)) { // check for valid utf8 encoding - printf("bad utf8 characters: %s \n",tag2); - return 3; - } - - while ((pp1 = strpbrk(tag2,tagdelims":"))) *pp1 = '-'; // replace problem characters - - strcpy(tag,tag2); // replace tag with sanitized version - - del_deftag(tag); // delete if already there - - if (! catg || *catg <= ' ') catg = (char *) "nocatg"; - - cc1 = strlen(catg); - - for (ii = 0; ii < maxtagcats; ii++) // look for given category - { - pp1 = tags_deftags[ii]; - if (! pp1) goto newcatg; - if (! strnEqu(catg,pp1,cc1)) continue; - if (pp1[cc1] == ':') goto oldcatg; - } - -newcatg: - if (ii == maxtagcats) goto toomanycats; - cc1 = strlen(catg) + strlen(tag) + 6; - pp1 = zmalloc(cc1,"deftags"); - *pp1 = 0; - strncatv(pp1,cc1,catg,": ",tag,tagdelim2,null); // category: + tag + delim + blank - tags_deftags[ii] = tags_deftags[ii-1]; // move "nocatg" record to next slot - tags_deftags[ii-1] = pp1; // insert new record before - return 0; - -oldcatg: - cc1 = strlen(tag); - pp2 = pp1 + 2; - while (true) { - pp2 = strcasestr(pp2,tag); // look for delim + blank + tag + delim - if (! pp2) break; // or colon + blank + tag + delim - if (strchr(tagdelims,pp2[cc]) && strchr(tagdelims":", pp2[-2])) - return 1; // tag not unique - pp2 += cc1; - } - cc2 = strlen(pp1); // add new tag to old record - if (cc1 + cc2 + 4 > tagGcc) goto cattoobig; - pp2 = strdupz(pp1,cc2+4,"def_tags"); // expand string - zfree(pp1); - tags_deftags[ii] = pp2; - strcpy(pp2+cc2,tag); // old record + tag + delim + blank - strcpy(pp2+cc2+cc1,tagdelim2); - return 0; - -toomanycats: - zmessLogACK(mWin,"more than %d categories",maxtagcats); - return 2; - -cattoobig: - zmessLogACK(mWin,"category is too big"); - return 2; -} - - -// delete tag from defined tags list, tags_deftags[] -// return: 0 = found and deleted, 1 = not found - -int del_deftag(char *tag) -{ - int ii, cc; - char tag2[tagcc+4]; - char *pp, *pp1, *pp2; - - if (! tag || *tag <= ' ') return 1; // bad tag - - strncpy0(tag2,tag,tagcc); // construct tag + delim + blank - cc = strlen(tag2); - strcpy(tag2+cc,tagdelim2); - cc += 2; - - for (ii = 0; ii < maxtagcats; ii++) - { - pp = tags_deftags[ii]; - if (! pp) return 1; // not found - - while (pp) - { - pp = strcasestr(pp,tag2); // look for prior delim or colon - if (! pp) break; - if (strchr(tagdelims":", pp[-2])) goto found; - pp += cc; - } - } - -found: - for (pp1 = pp, pp2 = pp+cc; *pp2; pp1++, pp2++) // eliminate tag, delim, blank - *pp1 = *pp2; - *pp1 = 0; - - return 0; -} - - -// stuff tags_deftags[] into given text widget and format by category -// create tags_deftext with flat list of tags for mouse clicking - -void deftags_stuff(zdialog *zd) -{ - GtkWidget *widget; - GtkTextBuffer *textbuff; - GtkTextIter iter1, iter2; - int ii, cc; - char catgname[tagcc+3]; - char *pp1, *pp2; - - widget = zdialog_widget(zd,"deftags"); - wclear(widget); - - for (ii = 0; ii < maxtagcats; ii++) - { - pp1 = tags_deftags[ii]; - if (! pp1) break; - pp2 = strchr(pp1,':'); - if (! pp2) continue; - if (pp2 > pp1 + tagcc-3) continue; - pp2 += 2; - cc = pp2 - pp1 + 1; - strncpy0(catgname,pp1,cc); - wprintx(widget,0,catgname,"monospace bold 9"); - if (*pp2) wprintx(widget,0,pp2,"monospace 9"); - wprintx(widget,0,"\n"); - } - - textbuff = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget)); - gtk_text_buffer_get_bounds(textbuff,&iter1,&iter2); - pp1 = gtk_text_buffer_get_text(textbuff,&iter1,&iter2,0); - strncpy0(tags_deftext,pp1,tagTcc); - - return; -} - - -/**************************************************************************/ - -// image file EXIF/IPTC data >> tags_date, tags_stars, tags_filetags, -// tags_comments, tags_caption in memory - -void load_fileinfo(cchar *file) -{ - void exif_tagdate(cchar *exifdate, char *tagdate); - - int ii, jj, cc; - char *pp; - cchar *exifkeys[5] = { exif_date_key, iptc_tags_key, iptc_rating_key, - exif_comment_key, iptc_caption_key }; - char **ppv, *imagedate, *imagetags, *imagestars, *imagecomms, *imagecapt; - - *tags_filetags = *tags_date = *tags_comments = *tags_caption = 0; - tags_stars = '0'; - - ppv = info_get(file,exifkeys,5); // stars rating added v.10.0 - imagedate = ppv[0]; - imagetags = ppv[1]; - imagestars = ppv[2]; - imagecomms = ppv[3]; - imagecapt = ppv[4]; - - if (imagedate) { - exif_tagdate(imagedate,tags_date); // EXIF date/time >> yyyymmdd - strcpy(tags_prdate,tags_date); - zfree(imagedate); - } - - if (imagetags) - { - for (ii = 1; ; ii++) - { - pp = (char *) strField(imagetags,tagdelims,ii); - if (! pp) break; - if (*pp == ' ') continue; - cc = strlen(pp); - if (cc >= tagcc) continue; // reject tags too big - for (jj = 0; jj < cc; jj++) - if (pp[jj] > 0 && pp[jj] < ' ') break; // reject tags with control characters - if (jj < cc) continue; - add_tag(pp,tags_filetags,tagFcc); // add to file tags if unique - } - - zfree(imagetags); - } - - if (imagestars) { // v.10.0 - tags_stars = *imagestars; - if (tags_stars < '0' || tags_stars > '5') tags_stars = '0'; - zfree(imagestars); - } - - if (imagecomms) { // v.10.11 - strncpy0(tags_comments,imagecomms,tagFcc); - zfree(imagecomms); - } - - if (imagecapt) { // v.10.12 - strncpy0(tags_caption,imagecapt,tagFcc); - zfree(imagecapt); - } - - Ftagschanged = 0; - return; -} - - -// tags_date, tags_stars, tags_filetags in memory >> image file EXIF/IPTC data -// update defined tags file if any changes - -void save_fileinfo(cchar *file) -{ - void tag_exifdate(cchar *tagdate, char *exifdate); - - cchar *exifkeys[5] = { exif_date_key, iptc_tags_key, iptc_rating_key, - exif_comment_key, iptc_caption_key }; - cchar *exifdata[5]; - char imagedate[24], sstars[4]; - - if (! Ftagschanged) return; // no changes to tags etc. - Ftagschanged = 0; - - *imagedate = 0; - if (*tags_date) { - tag_exifdate(tags_date,imagedate); // yyyymmdd >> EXIF date/time - strcpy(tags_prdate,tags_date); - } - - sstars[0] = tags_stars; // string for stars rating - sstars[1] = 0; - - exifdata[0] = imagedate; // update file EXIF/IPTC data - exifdata[1] = tags_filetags; - exifdata[2] = sstars; - exifdata[3] = tags_comments; // v.10.11 - exifdata[4] = tags_caption; // v.10.12 - info_put(file,exifkeys,exifdata,5); - - update_search_index(file); // update search index file - - if (zdexifview) info_view(0); // live EXIF/IPTC update v.10.2 - return; -} - - -// update search index file (replace updated file data) // overhauled v.10.11 - -void update_search_index(cchar *file) -{ - char *ppv, temp_search_index_file[200]; - char imagedate[12], filedate[16]; - char buff[tagrecl]; - int err, fcopy = 0; - FILE *fidr, *fidw; - struct stat statb; - struct tm bdt; - - if (is_syncbusy()) return; // must wait for file sync v.11.11 - - strcpy(temp_search_index_file,search_index_file); // temp tag file - strcat(temp_search_index_file,"_temp"); - - fidw = fopen(temp_search_index_file,"w"); // write temp tag file (new) - if (! fidw) goto tagserror; - - fidr = fopen(search_index_file,"r"); // read tag file (old) - - if (fidr) - { - while (true) // copy search index file to temp - { // file, omitting this image file - ppv = fgets_trim(buff,tagrecl,fidr); - if (! ppv) break; - - if (strnEqu(buff,"file: ",6)) { // start of next file entry - if (strEqu(buff+6,file)) fcopy = 0; // my file, skip this entry - else fcopy = 1; - } - - if (fcopy) fprintf(fidw,"%s\n",buff); // copy data for other file entries - } - - err = fclose(fidr); - if (err) goto tagserror; - } - -// append input file and tags data to end of search index file - - err = fprintf(fidw,"file: %s\n",file); // output filespec - if (err <= 0) goto tagserror; - - if (*tags_date) { // image date - strncpy(imagedate,tags_date,4); - strncpy(imagedate+5,tags_date+4,2); // yyyymmdd >> yyyy:mm:dd - strncpy(imagedate+8,tags_date+6,2); - imagedate[4] = imagedate[7] = ':'; - imagedate[10] = 0; - } - else strcpy(imagedate,"null"); // missing image date - - err = stat(file,&statb); - gmtime_r(&statb.st_mtime,&bdt); - sprintf(filedate,"%04d%02d%02d%02d%02d%02d", // file date = yyyymmddhhmmss - bdt.tm_year + 1900, bdt.tm_mon + 1, bdt.tm_mday, - bdt.tm_hour, bdt.tm_min, bdt.tm_sec); - - err = fprintf(fidw,"date: %s %s\n",imagedate,filedate); // output image and file date - - if (*tags_filetags) // output filetags - err = fprintf(fidw,"tags: %s\n",tags_filetags); - else err = fprintf(fidw,"tags: null" tagdelim2 "\n"); // "null" tag if none v.11.02 - - err = fprintf(fidw,"stars: %c\n",tags_stars); // output stars rating - - if (*tags_comments) // output user comments - err = fprintf(fidw,"comms: %s\n",tags_comments); - else err = fprintf(fidw,"comms: null \n"); // "null" if none - - if (*tags_caption) // output user caption v.10.12 - err = fprintf(fidw,"capt: %s\n",tags_caption); - else err = fprintf(fidw,"capt: null \n"); // "null" if none - - err = fprintf(fidw,"\n"); // EOL - - err = fclose(fidw); // close temp file - if (err) goto tagserror; - - err = rename(temp_search_index_file,search_index_file); // replace tags file with temp file - if (err) goto tagserror; - - return; - -tagserror: - zmessLogACK(mWin,ZTX("search index file error: %s"),strerror(errno)); - return; -} - - -// file is deleted from search index file - -void delete_search_index(cchar *file) // overhauled v.10.11.2 -{ - char *ppv, temp_search_index_file[200]; - char indexbuff[tagrecl]; - char filebuff[tagrecl], datebuff[tagrecl]; - char tagsbuff[tagrecl], starsbuff[tagrecl]; - char commsbuff[tagrecl], captbuff[tagrecl]; - int err, ftf = 1; - FILE *fidr, *fidw; - - if (is_syncbusy()) return; // must wait for file sync v.11.11 - - strcpy(temp_search_index_file,search_index_file); // temp tag file - strcat(temp_search_index_file,"_temp"); - - fidr = fopen(search_index_file,"r"); // read tag file - if (! fidr) return; - - fidw = fopen(temp_search_index_file,"w"); // write temp tag file - if (! fidw) goto tagserror; - - while (true) // copy search index file to temp - { // file, omitting this image file - ppv = fgets_trim(indexbuff,tagrecl,fidr); - - if (! ppv || strnEqu(indexbuff,"file: ",6)) // EOF or start of next file - { - if (! ftf && strNeq(filebuff+6,file)) // not 1st time and not file to omit - { - fprintf(fidw,"%s\n",filebuff); // output completed data for previous file - fprintf(fidw,"%s\n",datebuff); - fprintf(fidw,"%s\n",tagsbuff); - fprintf(fidw,"%s\n",starsbuff); - fprintf(fidw,"%s\n",commsbuff); - fprintf(fidw,"%s\n",captbuff); - fprintf(fidw,"\n"); - } - - if (! ppv) break; // EOF - - ftf = 0; - strncpy0(filebuff,indexbuff,tagrecl); // next file: filespec record - strcpy(datebuff,"date: null "); // initz. remaining data = empty - strcpy(tagsbuff,"tags: null"tagdelim2); // v.11.02 - strcpy(starsbuff,"stars: 0 "); - strcpy(commsbuff,"comms: null "); - strcpy(captbuff,"capt: null "); - } - - if (strnEqu(indexbuff,"date: ",6)) // copy whatever is found - strncpy0(datebuff,indexbuff,tagrecl); - - if (strnEqu(indexbuff,"tags: ",6)) - strncpy0(tagsbuff,indexbuff,tagrecl); - - if (strnEqu(indexbuff,"stars: ",7)) - strncpy0(starsbuff,indexbuff,tagrecl); - - if (strnEqu(indexbuff,"comms: ",7)) - strncpy0(commsbuff,indexbuff,tagrecl); - - if (strnEqu(indexbuff,"capt: ",6)) - strncpy0(captbuff,indexbuff,tagrecl); - } - - err = fclose(fidr); - if (err) goto tagserror; - - err = fclose(fidw); - if (err) goto tagserror; - - err = rename(temp_search_index_file,search_index_file); // replace tags file with temp file - if (err) goto tagserror; - - return; - -tagserror: - zmessLogACK(mWin,ZTX("search index file error: %s"),strerror(errno)); - return; -} - - -/**************************************************************************/ - -// menu function - add tags to many files at once - -char **batchAddTags_filelist = 0; -int batchAddTags_filecount = 0; -zdialog *zdbatchAddTags = null; // batch add tags dialog - -void m_batchAddTags(GtkWidget *, cchar *) // new v.9.7 -{ - void batchAddTags_fixwidget(zdialog *zd, cchar * widgetname); - int batchAddTags_dialog_event(zdialog *zd, cchar *event); - - char *ptag, **flist, *file; - int ii, jj, err; - - zfuncs::F1_help_topic = "batch_add_tags"; // v.10.8 - - if (! Fexiftool) { // exiftool is required - zmessageACK(mWin,Bexiftoolmissing); - return; - } - - if (is_syncbusy()) return; // must wait for file sync v.11.11 - if (mod_keep()) return; // unsaved edits - if (! menulock(1)) return; // v.10.5 - - zdbatchAddTags = zdialog_new(ZTX("Batch Add Tags"),mWin,Bproceed,Bcancel,null); - - zdialog_add_widget(zdbatchAddTags,"hbox","hb1","dialog",0,"space=5"); - zdialog_add_widget(zdbatchAddTags,"label","lab1","hb1",ZTX("tags to add"),"space=10"); - zdialog_add_widget(zdbatchAddTags,"frame","frame1","hb1",0,"expand"); - zdialog_add_widget(zdbatchAddTags,"edit","batchAddTags","frame1",0,"expand|wrap"); // v.11.06 - - zdialog_add_widget(zdbatchAddTags,"hbox","hb2","dialog",0,"space=5"); - zdialog_add_widget(zdbatchAddTags,"button","createtag","hb2",ZTX("create tag"),"space=10"); - zdialog_add_widget(zdbatchAddTags,"entry","ctag","hb2",0); - - zdialog_add_widget(zdbatchAddTags,"hbox","hb3","dialog",0,"space=5"); - zdialog_add_widget(zdbatchAddTags,"button","files","hb3",Bselectfiles,"space=10"); - zdialog_add_widget(zdbatchAddTags,"label","labcount","hb3","0 files selected","space=10"); - - zdialog_add_widget(zdbatchAddTags,"hbox","space","dialog",0,"space=3"); - zdialog_add_widget(zdbatchAddTags,"hbox","hb5","dialog"); - zdialog_add_widget(zdbatchAddTags,"label","labdeftags","hb5",ZTX("defined tags")); - zdialog_add_widget(zdbatchAddTags,"frame","frame5","dialog",0,"space=5|expand"); - zdialog_add_widget(zdbatchAddTags,"scrwin","scrwin5","frame5",0,"expand"); - zdialog_add_widget(zdbatchAddTags,"edit","deftags","scrwin5",0,"expand|wrap"); // v.11.06 - - load_deftags(); // stuff defined tags into dialog - deftags_stuff(zdbatchAddTags); - - batchAddTags_filelist = 0; - batchAddTags_filecount = 0; - *tags_batchAddTags = 0; - - zdialog_resize(zdbatchAddTags,400,400); // run dialog - zdialog_help(zdbatchAddTags,"batch_add_tags"); // zdialog help topic v.11.08 - zdialog_run(zdbatchAddTags,batchAddTags_dialog_event); - - batchAddTags_fixwidget(zdbatchAddTags,"batchAddTags"); // setup for mouse tag selection - batchAddTags_fixwidget(zdbatchAddTags,"deftags"); - - zdialog_wait(zdbatchAddTags); // wait for dialog completion - - flist = batchAddTags_filelist; - - if (zdbatchAddTags->zstat != 1) goto cleanup; - if (! batchAddTags_filecount) goto cleanup; - if (*tags_batchAddTags <= ' ') goto cleanup; // v.10.5 - - write_popup_text("open","Adding Tags",500,200,mWin); // status monitor popup window v.11.01 - - for (ii = 0; flist[ii]; ii++) // loop all selected files - { - file = flist[ii]; // display image - err = f_open(file,0); - if (err) continue; - - write_popup_text("write",file); // report progress - zmainloop(); - - load_fileinfo(file); // load current file tags - - for (jj = 1; ; jj++) // add new tags unless already - { - ptag = (char *) strField(tags_batchAddTags,tagdelims,jj); - if (! ptag) break; - if (*ptag == ' ') continue; - err = add_tag(ptag,tags_filetags,tagFcc); - if (err == 2) - zmessageACK(mWin,ZTX("%s \n too many tags"),file); - } - - save_fileinfo(file); // save tag changes - } - - write_popup_text("write","COMPLETED"); - write_popup_text("close",0); - -cleanup: - - zdialog_free(zdbatchAddTags); - - if (batchAddTags_filecount) { - for (ii = 0; flist[ii]; ii++) - zfree(flist[ii]); - zfree(flist); - } - - menulock(0); - return; -} - - -// setup tag display widget for tag selection using mouse clicks - -void batchAddTags_fixwidget(zdialog *zd, cchar * widgetname) -{ - void batchAddTags_mouse(GtkTextView *widget, GdkEventButton *event, cchar *widgetname); - - GtkWidget *widget; - GdkWindow *gdkwin; - - widget = zdialog_widget(zd,widgetname); // make widget wrap text - gtk_text_view_set_editable(GTK_TEXT_VIEW(widget),0); // disable widget editing - - gdkwin = gtk_text_view_get_window(GTK_TEXT_VIEW(widget),TEXTWIN); // cursor for tag selection - gdk_window_set_cursor(gdkwin,arrowcursor); - - gtk_widget_add_events(widget,GDK_BUTTON_PRESS_MASK); // connect mouse-click event - G_SIGNAL(widget,"button-press-event",batchAddTags_mouse,widgetname) -} - - -// batchAddTags mouse-click event function -// get clicked tag and add to or remove from tags_batchAddTags - -void batchAddTags_mouse(GtkTextView *widget, GdkEventButton *event, cchar *widgetname) -{ - int mpx, mpy, cc; - - if (event->type != GDK_BUTTON_PRESS) return; - mpx = int(event->x); // mouse click position - mpy = int(event->y); - - cc = get_mouse_tag(widget,mpx,mpy,widgetname); // tags_cliktag = clicked tag in list - if (! cc) return; - - if (strEqu(widgetname,"batchAddTags")) { - del_tag(tags_cliktag,tags_batchAddTags); // remove tag from tags_batchAddTags - zdialog_stuff(zdbatchAddTags,"batchAddTags",tags_batchAddTags); // update dialog widgets - } - - if (strEqu(widgetname,"deftags")) { - add_tag(tags_cliktag,tags_batchAddTags,tagMcc); // add defined tag to tags_batchAddTags - zdialog_stuff(zdbatchAddTags,"batchAddTags",tags_batchAddTags); - } - - return; -} - - -// batchAddTags dialog event function - -int batchAddTags_dialog_event(zdialog *zd, cchar *event) -{ - int ii, err; - char tag[tagcc]; - char **flist = batchAddTags_filelist, countmess[50]; - - if (strEqu(event,"createtag")) { - err = zdialog_fetch(zd,"ctag",tag,tagcc); // add new tag to list - if (err) return 0; // reject too big tag - add_tag(tag,tags_batchAddTags,tagMcc); // add tag to tags_batchAddTags - zdialog_stuff(zd,"batchAddTags",tags_batchAddTags); // update dialog widgets - zdialog_stuff(zd,"ctag",""); - } - - if (strEqu(event,"files")) // select images to add tags - { - if (flist) { // free prior list - for (ii = 0; flist[ii]; ii++) - zfree(flist[ii]); - zfree(flist); - } - - flist = image_gallery_getfiles(0,mWin); // get file list from user - batchAddTags_filelist = flist; - - if (flist) // count files in list - for (ii = 0; flist[ii]; ii++); - else ii = 0; - batchAddTags_filecount = ii; - - snprintf(countmess,50,ZTX("%d files selected"),batchAddTags_filecount); - zdialog_stuff(zd,"labcount",countmess); - } - - return 0; -} - - -/**************************************************************************/ - -// menu function - delete or replace a tag for many files at once - -char **batchDelTag_filelist = 0; - -void m_batchDelTag(GtkWidget *, cchar *) // new v.10.9 -{ - int batchDelTag_dialog_event(zdialog *zd, cchar *event); - - char **flist, *file; - char deltag[tagcc], reptag[tagcc]; - int ii, err; - zdialog *zd; - - zfuncs::F1_help_topic = "batch_delete_tag"; - - if (! Fexiftool) { // exiftool is required - zmessageACK(mWin,Bexiftoolmissing); - return; - } - - if (is_syncbusy()) return; // must wait for file sync v.11.11 - if (mod_keep()) return; // unsaved edits - if (! menulock(1)) return; // v.10.5 - - zd = zdialog_new(ZTX("Batch Delete Tag"),mWin,Bproceed,Bcancel,null); - - zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=5"); - zdialog_add_widget(zd,"label","lab1","hb1",ZTX("tag to remove"),"space=10"); - zdialog_add_widget(zd,"entry","deltag","hb1",0,"scc=20"); - - zdialog_add_widget(zd,"hbox","hb2","dialog",0,"space=5"); - zdialog_add_widget(zd,"label","lab2","hb2",ZTX("optional replacement"),"space=10"); - zdialog_add_widget(zd,"entry","reptag","hb2",0,"scc=20"); - - zdialog_add_widget(zd,"hbox","hb3","dialog",0,"space=5"); - zdialog_add_widget(zd,"button","files","hb3",Bselectfiles,"space=10"); - zdialog_add_widget(zd,"label","labcount","hb3",ZTX("0 files selected"),"space=10"); - - zdialog_add_widget(zd,"hbox","hb4","dialog",0,"space=5"); - zdialog_add_widget(zd,"check","allfiles","hb4",ZTX("search all files"),"space=10"); - - batchDelTag_filelist = flist = 0; - - zdialog_help(zd,"batch_delete_tag"); // zdialog help topic v.11.08 - zdialog_run(zd,batchDelTag_dialog_event); // run dialog - zdialog_wait(zd); // wait for completion - - if (zd->zstat != 1) goto cleanup; // canceled - - flist = batchDelTag_filelist; // get selected files - if (! flist) goto cleanup; - - zdialog_fetch(zd,"deltag",deltag,tagcc); // get tag to delete - strTrim2(deltag); // remove leading and trailing blanks - strToLower(deltag); // use lower case for matching - if (! *deltag) goto cleanup; - - zdialog_fetch(zd,"reptag",reptag,tagcc); // optional replacement tag - strTrim2(reptag); - - write_popup_text("open","Deleting Tags",500,200,mWin); // status monitor popup window v.11.01 - - for (ii = 0; flist[ii]; ii++) // loop all selected files - { - file = flist[ii]; - err = f_open(file,0); // display image - if (err) continue; - - write_popup_text("write",file); // report progress - zmainloop(); - - load_fileinfo(file); // load current file tags - - err = del_tag(deltag,tags_filetags); // remove tag, if present - if (err) continue; // not present - - if (*reptag) { // add replacement tag, if defined - err = add_tag(reptag,tags_filetags,tagFcc); - if (err == 2) - zmessageACK(mWin,ZTX("%s \n too many tags"),file); - } - - save_fileinfo(file); // save tag changes - } - - write_popup_text("write","COMPLETED"); - write_popup_text("close",0); - -cleanup: - - zdialog_free(zd); - - if (flist) { - for (ii = 0; flist[ii]; ii++) - zfree(flist[ii]); - zfree(flist); - } - - menulock(0); - return; -} - - -// batchDelTag dialog event function - -int batchDelTag_dialog_event(zdialog *zd, cchar *event) -{ - FILE *fidr; - struct stat statbuf; - char deltag[tagcc]; - char **flist = batchDelTag_filelist; - int err, nfiles, ii, allfiles; - char filebuff[tagrecl], tagsbuff[tagrecl]; - char *ppv, *file, *tags, countmess[50]; - cchar *ppf; - int maxfiles = 100000; // max. files with tag to delete v.11.04 - - zdialog_fetch(zd,"deltag",deltag,tagcc); // get tag to delete - strTrim2(deltag); // remove leading and trailing blanks - strToLower(deltag); // use lower case for matching - - if (zd->zstat == 1) // [proceed] - { - if (! flist) { - zmessageACK(mWin,ZTX("no files selected")); // v.11.01 - zd->zstat = 0; // keep dialog active - goto finish; - } - - if (! *deltag) { - zmessageACK(mWin,ZTX("no tag specified")); // v.11.01 - zd->zstat = 0; - goto finish; - } - - return 0; - } - - if (strEqu(event,"deltag")) // tag changed - { - if (flist) { // clear file list v.11.01 - for (ii = 0; flist[ii]; ii++) - zfree(flist[ii]); - zfree(flist); - flist = 0; - } - - zdialog_stuff(zd,"allfiles",0); // reset "all files" checkbox v.11.01 - goto finish; - } - - if (strEqu(event,"files")) // select images to delete tags - { - if (! *deltag) { - zmessageACK(mWin,ZTX("specify tag")); // v.11.01 - goto finish; - } - - if (flist) { // free prior list - for (ii = 0; flist[ii]; ii++) - zfree(flist[ii]); - zfree(flist); - flist = 0; - } - - flist = image_gallery_getfiles(0,mWin); // get file list from user - zdialog_stuff(zd,"allfiles",0); // reset "all files" checkbox v.11.01 - goto finish; - } - - if (strEqu(event,"allfiles")) - { - if (flist) { // clear file list - for (ii = 0; flist[ii]; ii++) - zfree(flist[ii]); - zfree(flist); - flist = 0; - } - - zdialog_fetch(zd,"allfiles",allfiles); // get checkbox "all files" - if (! allfiles) goto finish; // was unselected - - if (! *deltag) { - zmessageACK(mWin,ZTX("specify tag")); // v.11.01 - goto finish; - } - - fidr = fopen(search_index_file,"r"); // read search index file - if (! fidr) goto finish; // no file - - flist = (char **) zmalloc(maxfiles*sizeof(char *),"DeleteTag"); // list for files found - nfiles = 0; // count files found - flist[0] = 0; - - while (true) - { - ppv = fgets_trim(filebuff,tagrecl,fidr,1); // next record - if (! ppv) break; // EOF - - if (! strnEqu(ppv,"file: ",6)) continue; // file: /dir.../filename.jpg - - file = ppv+6; - err=stat(file,&statbuf); // check file exists - if (err) continue; - if (! S_ISREG(statbuf.st_mode)) continue; - - ppv = fgets_trim(tagsbuff,tagrecl,fidr); // next record - if (! ppv) break; - if (! strnEqu(ppv,"date: ",6)) continue; // date: yyyy:mm:dd - - ppv = fgets_trim(tagsbuff,tagrecl,fidr); // next record - if (! ppv) break; - if (! strnEqu(ppv,"tags: ",6)) continue; // tags: xxxx, xxxxx, ... - - tags = ppv + 6; - strToLower(tags); // use lower case for matching - - for (ii = 1; ; ii++) // step thru file tags - { - ppf = strField(tags,tagdelims,ii); - if (! ppf) break; - if (*ppf == ' ') continue; - if (strEqu(ppf,deltag)) break; // look for my tag - } - - if (! ppf) continue; // tag not found - - flist[nfiles] = strdupz(file,0,"batch_del_tag"); - nfiles++; - if (nfiles == maxfiles-1) break; - } - - fclose(fidr); // close search index file - flist[nfiles] = 0; // EOL marker - } - -finish: - - batchDelTag_filelist = flist; // file list to process - - if (flist) // count files in list - for (ii = 0; flist[ii]; ii++); - else ii = 0; - - snprintf(countmess,50,ZTX("%d files selected"),ii); // stuff file count into dialog - zdialog_stuff(zd,"labcount",countmess); - - return 0; -} - - -/************************************************************************** - functions to view and edit metadata: EXIF, IPTC, etc. -***************************************************************************/ - -// menu function and popup dialog to show EXIF/IPTC data -// window is updated when navigating to another image - -void m_info_view_short(GtkWidget *, cchar *menu) // v.10.12 -{ - zfuncs::F1_help_topic = "view_info"; - info_view(1); - return; -} - -void m_info_view_long(GtkWidget *, cchar *menu) // v.10.12 -{ - zfuncs::F1_help_topic = "view_info"; - info_view(2); - return; -} - -void info_view(int arg) -{ - int info_view_dialog_event(zdialog *zd, cchar *event); - - static int length = 1; - char *buff; - int contx = 0; - GtkWidget *widget; - - if (! Fexiftool) { // exiftool is required - zmessageACK(mWin,Bexiftoolmissing); - return; - } - - if (! curr_file) return; - - if (arg > 0) length = arg; // change short/long report mode - - if (! zdexifview) // popup dialog if not already - { - zdexifview = zdialog_new(ZTX("View Info"),mWin,Bcancel,null); - zdialog_add_widget(zdexifview,"scrwin","scroll","dialog",0,"expand"); - zdialog_add_widget(zdexifview,"edit","exifdata","scroll",0,"expand|wrap"); - zdialog_resize(zdexifview,500,400); - zdialog_help(zdexifview,"view_info"); // zdialog help topic v.11.08 - zdialog_run(zdexifview,info_view_dialog_event); - } - - widget = zdialog_widget(zdexifview,"exifdata"); // v.10.12 - gtk_text_view_set_editable(GTK_TEXT_VIEW(widget),0); // disable widget editing - gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(widget),GTK_WRAP_NONE); // disable text wrap - - if (length == 1) // short report - { - snprintf(command,ccc,"exiftool -common -%s -%s -%s -%s -%s -%s \"%s\" ", - iptc_tags_key, iptc_rating_key, iptc_editlog_key, exif_comment_key, - iptc_caption_key, exif_focal_length_key, curr_file); - } - else - snprintf(command,ccc,"exiftool -e \"%s\" ",curr_file); // long, output everything - - widget = zdialog_widget(zdexifview,"exifdata"); // widget for output - wclear(widget); - - while ((buff = command_output(contx,command))) { // run command, output into window - wprintf(widget,"%s\n",buff); - zfree(buff); // memory leak v.11.03 - } - - command_status(contx); // free resources - - return; -} - - -// dialog event and completion callback function - -int info_view_dialog_event(zdialog *zd, cchar *event) // kill dialog -{ - if (! zd->zstat) return 0; - zdialog_free(zdexifview); - return 0; -} - - -/**************************************************************************/ - -// edit EXIF/IPTC data - add or change specified EXIF/IPTC/etc. key - -void m_info_edit(GtkWidget *, cchar *menu) // new v.10.2 -{ - char keyname[40], keydata[1000]; - cchar *pp1[1]; - char **pp2; - - int info_edit_dialog_event(zdialog *zd, cchar *event); - - if (menu) zfuncs::F1_help_topic = "edit_info"; - - if (! Fexiftool) { // exiftool is required - zmessageACK(mWin,Bexiftoolmissing); - return; - } - - if (! curr_file) return; - - if (! zdexifedit) // popup dialog if not already v.10.8 - { - zdexifedit = zdialog_new(ZTX("Edit Info"),mWin,Bfetch,Bsave,Bcancel,null); - zdialog_add_widget(zdexifedit,"vbox","hb1","dialog"); - zdialog_add_widget(zdexifedit,"hbox","hbkey","dialog",0,"space=5"); - zdialog_add_widget(zdexifedit,"hbox","hbdata","dialog",0,"space=5"); - zdialog_add_widget(zdexifedit,"label","labkey","hbkey","key name"); - zdialog_add_widget(zdexifedit,"entry","keyname","hbkey",0,"scc=20"); - zdialog_add_widget(zdexifedit,"label","labdata","hbdata","key value"); - zdialog_add_widget(zdexifedit,"entry","keydata","hbdata",0,"expand"); - zdialog_help(zdexifedit,"edit_info"); // zdialog help topic v.11.08 - zdialog_run(zdexifedit,info_edit_dialog_event); - } - - zdialog_fetch(zdexifedit,"keyname",keyname,40); // get key name from dialog - strCompress(keyname); // v.10.8 - - if (*keyname) // update live dialog v.10.8 - { - pp1[0] = keyname; // look for key data - pp2 = info_get(curr_file,pp1,1); - if (pp2[0]) { - strncpy0(keydata,pp2[0],999); - zfree(pp2[0]); - } - else *keydata = 0; - zdialog_stuff(zdexifedit,"keydata",keydata); // stuff into dialog - } - - return; -} - - -// dialog event and completion callback function - -int info_edit_dialog_event(zdialog *zd, cchar *event) -{ - char keyname[40], keydata[1000]; // v.11.02 (was 100) - cchar *pp1[1], *pp2[1]; - char **pp3; - int err; - - if (! zd->zstat) return 0; - - zdialog_fetch(zd,"keyname",keyname,40); - zdialog_fetch(zd,"keydata",keydata,1000); - strCompress(keyname); // remove blanks v.10.8 - - if (zd->zstat == 1) // fetch - { - zd->zstat = 0; - if (! *keyname) return 0; // bugfix v.11.02 - pp1[0] = keyname; - pp3 = info_get(curr_file,pp1,1); - if (pp3[0]) { - strncpy0(keydata,pp3[0],99); - zfree(pp3[0]); - } - else *keydata = 0; - zdialog_stuff(zd,"keydata",keydata); - } - - else if (zd->zstat == 2) // save - { - zd->zstat = 0; // keep dialog active - if (! *keyname) return 0; // bugfix v.11.02 - if (is_syncbusy()) return 0; // must wait for file sync v.11.11 - pp1[0] = keyname; - pp2[0] = keydata; - err = info_put(curr_file,pp1,pp2,1); - if (err) zmessageACK(mWin,"error: %s",strerror(err)); - if (zdexifview) info_view(0); // update exif view if active - } - - else zdialog_free(zdexifedit); // other - - return 1; -} - - -/**************************************************************************/ - -// delete EXIF/IPTC data, specific key or all data - -void m_info_delete(GtkWidget *, cchar *menu) // new v.10.2 -{ - int info_delete_dialog_event(zdialog *zd, cchar *event); - - zdialog *zd; - - zfuncs::F1_help_topic = "delete_info"; // v.10.8 - - if (! Fexiftool) { // exiftool is required - zmessageACK(mWin,Bexiftoolmissing); - return; - } - - if (! curr_file) return; - if (is_syncbusy()) return; // must wait for file sync v.11.11 - - zd = zdialog_new(ZTX("Delete Info"),mWin,Bapply,Bcancel,null); - zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=5"); - zdialog_add_widget(zd,"radio","kall","hb1",ZTX("All"),"space=5"); - zdialog_add_widget(zd,"radio","key1","hb1",ZTX("One Key:")); - zdialog_add_widget(zd,"entry","keyname","hb1",0,"scc=20"); - zdialog_stuff(zd,"key1",1); - - zdialog_help(zd,"delete_info"); // zdialog help topic v.11.08 - zdialog_run(zd,info_delete_dialog_event); - return; -} - - -// dialog event and completion callback function - -int info_delete_dialog_event(zdialog *zd, cchar *event) -{ - int kall, key1, err; - char keyname[40]; - - if (! zd->zstat) return 0; - - if (zd->zstat != 1) { // canceled - zdialog_free(zd); - return 1; - } - - zd->zstat = 0; // dialog remains active - - zdialog_fetch(zd,"kall",kall); - zdialog_fetch(zd,"key1",key1); - zdialog_fetch(zd,"keyname",keyname,40); - strCompress(keyname); // v.10.8 - // bugfix - quotes around file v.10.3 - if (kall) - snprintf(command,ccc,"exiftool -m -q -overwrite_original -all= \"%s\"",curr_file); - else if (key1) - snprintf(command,ccc,"exiftool -m -q -overwrite_original -%s= \"%s\"",keyname,curr_file); - else return 1; - - err = system(command); - if (err) zmessageACK(mWin,"%s",wstrerror(err)); - - if (zdexifview) info_view(0); // update exif view if active - - return 1; -} - - -/**************************************************************************/ - -// get EXIF/IPTC metadata for given image file and EXIF/IPTC key(s) -// returns array of pointers to corresponding key values -// if a key is missing, corresponding pointer is null -// returned strings belong to caller, are subject for zfree() -// up to 9 keynames may be requested per call -// command: -// exiftool -keyname1 -keyname2 ... "file" -// command output: -// keyname1: keyvalue1 -// keyname2: keyvalue2 -// ... -// The overhead for this call is about 0.1 seconds elapsed on a -// 2.67 GHz computer with a 10,000 rpm disk. - -char ** info_get(cchar *file, cchar **keys, int nkeys) -{ - char *pp; - static char *rettext[10]; - int contx = 0, err, ii; - uint cc; - - if (nkeys < 1 || nkeys > 9) zappcrash("info_get nkeys: %d",nkeys); - - strcpy(command,"exiftool -m -q -S -fast"); - - for (ii = 0; ii < nkeys; ii++) - { - rettext[ii] = null; - strncatv(command,ccc," -",keys[ii],null); // "-exif:" replaced with "-" v.10.0 - } - - strncatv(command,ccc," \"",file,"\"",null); - - while (true) - { - pp = command_output(contx,command); - if (! pp) break; - - for (ii = 0; ii < nkeys; ii++) - { - cc = strlen(keys[ii]); - if (strncasecmp(pp,keys[ii],cc) == 0) // ignore case bugfix v.10.2 - if (strlen(pp) > cc+2) - rettext[ii] = strdupz(pp+cc+2,0,"info"); // check not empty - } - - zfree(pp); - } - - err = command_status(contx); - if (err) printf(" info_get: %s \n",wstrerror(err)); // v.10.8 - - return rettext; -} - - -/**************************************************************************/ - -// create or change EXIF/IPTC metadata for given image file and key(s) -// up to 9 keys may be processed -// command: -// exiftool -overwrite_original -keyname="keyvalue" ... "file" -// -// NOTE: exiftool replaces \n (newline) in "keyvalue" with "." (period) v.10.12 - -int info_put(cchar *file, cchar **keys, cchar **text, int nkeys) -{ - int ii, err; - char *pp; - - if (nkeys < 1 || nkeys > 9) zappcrash("info_put nkeys: %d",nkeys); - - for (ii = 0; ii < nkeys; ii++) - if (! text[ii]) text[ii] = ""; // if null pointer use empty string - - for (ii = 0; ii < nkeys; ii++) // replace imbedded " with \" - if (strchr(text[ii],'"')) { // else exiftool command fails - pp = strdupz(text[ii],20,"info"); // bugfix v.10.12 - repl_1str(text[ii],pp,"\"","\\\""); -// zfree((char *) (text[ii])); // small memory leak, needs redesign ///// - text[ii] = pp; - } - - strcpy(command,"exiftool -m -q -overwrite_original"); - - for (ii = 0; ii < nkeys; ii++) - strncatv(command,ccc," -",keys[ii],"=\"",text[ii],"\"",null); // "-exif:" replaced with "-" v.10.0 - strncatv(command,ccc," \"",file,"\"",null); - - err = system(command); - if (err) printf(" info_put: %s \n",wstrerror(err)); - return err; -} - - -/**************************************************************************/ - -// copy EXIF/IPTC data from original image file to new (edited) image file -// if nkeys > 0, up to 9 keys may be replaced with new values -// exiftool command revised: parameter sequence and -icc_profile v.10.8.4 - -int info_copy(cchar *file1, cchar *file2, cchar **keys, cchar **text, int nkeys) -{ - int ii, err; - - strcpy(command,"exiftool -m -q -tagsfromfile"); // exiftool -m -q -tagsfromfile "file1" - strncatv(command,ccc," \"",file1,"\"",null); - - strncatv(command,ccc," -all -icc_profile",null); // -all -icc_profile - - for (ii = 0; ii < nkeys; ii++) // -keyname="keyvalue" ... (options) - if (text[ii]) - strncatv(command,ccc," -",keys[ii],"=\"",text[ii],"\"",null); - - strncatv(command,ccc," \"",file2,"\""," -overwrite_original",null); // "file2" -overwrite_original - - err = system(command); - if (err) printf(" exiftool: %s \n",wstrerror(err)); - return err; -} - - -/**************************************************************************/ - -// convert between EXIF and fotoxx tag date formats -// EXIF date: yyyy:mm:dd hh:mm:ss[.ss] -// tag date: yyyymmdd -// - -void exif_tagdate(cchar *exifdate, char *tagdate) -{ - time_t tnow; - struct tm *snow; - - if (! exifdate || strlen(exifdate) < 10) { // bad EXIF date, use current date - tnow = time(0); - snow = localtime(&tnow); - snprintf(tagdate,8,"%4d%02d%02d", - snow->tm_year+1900, snow->tm_mon+1, snow->tm_mday); - tagdate[8] = 0; - return; - } - - strncpy(tagdate,exifdate,4); // convert - strncpy(tagdate+4,exifdate+5,2); - strncpy(tagdate+6,exifdate+8,2); - tagdate[8] = 0; - return; -} - -void tag_exifdate(cchar *tagdate, char *exifdate) -{ - int cc; - time_t tnow; - struct tm *snow; - - if (! tagdate || strlen(tagdate) < 4) { - tnow = time(0); - snow = localtime(&tnow); - snprintf(exifdate,20,"%4d:%02d:%02d %02d:%02d:%02d", - snow->tm_year+1900, snow->tm_mon+1, snow->tm_mday, - snow->tm_hour, snow->tm_min, snow->tm_sec); - exifdate[19] = 0; - return; - } - - strncpy(exifdate,tagdate,4); - strcpy(exifdate+4,":01:01 00:00:00"); - cc = strlen(tagdate); - if (cc >= 6) strncpy(exifdate+5,tagdate+4,2); - if (cc >= 8) strncpy(exifdate+8,tagdate+6,2); - exifdate[19] = 0; - return; -} - - -/**************************************************************************/ - -// search image tags, dates, stars, comments, captions for matching images - -char searchDateFrom[12] = ""; // image search date range -char searchDateTo[12] = ""; -char searchStarsFrom[4] = ""; // image search stars range -char searchStarsTo[4] = ""; -zdialog *zdsearchtags = 0; // search tags dialog - - -void m_search_images(GtkWidget *, cchar *) -{ - void searchtags_fixwidget(zdialog *zd, cchar * widgetname); - int searchtags_dialog_event(zdialog*, cchar *event); - - if (is_syncbusy()) return; // must wait for file sync v.11.11 - if (mod_keep()) return; // unsaved edits - if (! menulock(1)) return; - menulock(0); - - zfuncs::F1_help_topic = "search_images"; // v.10.8 - -/*** - date range [_______] [_______] (yyyymmdd) - stars range [__] [__] all any - search tags [________________________] (o) (o) - search text [________________________] (o) (o) - file names [________________________] (o) (o) - - defined tags - -------------------------------------------- - | | - | | - | | - | | - | | - -------------------------------------------- - [search] [cancel] -***/ - - zdsearchtags = zdialog_new(ZTX("Search Tags, Comments, File Names"),mWin,Bproceed,Bcancel,null); - - zdialog_add_widget(zdsearchtags,"hbox","hb1","dialog",0,"space=5"); - zdialog_add_widget(zdsearchtags,"vbox","vb1","hb1",0,"homog|space=3"); - zdialog_add_widget(zdsearchtags,"vbox","vb2","hb1",0,"homog|space=3|expand"); - - zdialog_add_widget(zdsearchtags,"label","labD","vb1",ZTX("date range")); - zdialog_add_widget(zdsearchtags,"label","labS","vb1",ZTX("stars range")); - zdialog_add_widget(zdsearchtags,"label","labT","vb1",ZTX("search tags")); - zdialog_add_widget(zdsearchtags,"label","labT","vb1",ZTX("search text")); - zdialog_add_widget(zdsearchtags,"label","labF","vb1",ZTX("file names")); - - zdialog_add_widget(zdsearchtags,"hbox","hbD","vb2",0,"space=1"); - zdialog_add_widget(zdsearchtags,"entry","datefrom","hbD",0,"scc=10"); - zdialog_add_widget(zdsearchtags,"entry","dateto","hbD",0,"scc=10"); - zdialog_add_widget(zdsearchtags,"label","labD","hbD",ZTX("(yyyymmdd)"),"space=5"); - - zdialog_add_widget(zdsearchtags,"hbox","hbS","vb2",0,"space=1"); - zdialog_add_widget(zdsearchtags,"entry","starsfrom","hbS",0,"scc=2"); - zdialog_add_widget(zdsearchtags,"entry","starsto","hbS",0,"scc=2"); - zdialog_add_widget(zdsearchtags,"label","space","hbS",0,"expand"); - zdialog_add_widget(zdsearchtags,"label","all-any","hbS",ZTX("all/any")); - - zdialog_add_widget(zdsearchtags,"hbox","hbT","vb2",0,"space=1"); - zdialog_add_widget(zdsearchtags,"frame","frameT","hbT",0,"expand"); - zdialog_add_widget(zdsearchtags,"edit","searchtags","frameT",0,"expand|wrap"); // v.11.06 - zdialog_add_widget(zdsearchtags,"radio","alltags","hbT",0); - zdialog_add_widget(zdsearchtags,"radio","anytags","hbT",0); - - zdialog_add_widget(zdsearchtags,"hbox","hbC","vb2",0,"space=1|expand"); - zdialog_add_widget(zdsearchtags,"entry","searchtext","hbC",0,"expand"); - zdialog_add_widget(zdsearchtags,"radio","alltext","hbC",0); - zdialog_add_widget(zdsearchtags,"radio","anytext","hbC",0); - - zdialog_add_widget(zdsearchtags,"hbox","hbF","vb2",0,"space=1|expand"); - zdialog_add_widget(zdsearchtags,"entry","searchfiles","hbF",0,"expand"); - zdialog_add_widget(zdsearchtags,"radio","allfiles","hbF",0); - zdialog_add_widget(zdsearchtags,"radio","anyfiles","hbF",0); - - zdialog_add_widget(zdsearchtags,"hbox","space","dialog",0,"space=3"); - zdialog_add_widget(zdsearchtags,"hbox","hbA1","dialog"); - zdialog_add_widget(zdsearchtags,"label","labdeftags","hbA1",ZTX("defined tags"),"space=5"); - zdialog_add_widget(zdsearchtags,"hbox","hbA2","dialog",0,"expand"); - zdialog_add_widget(zdsearchtags,"frame","frameA","hbA2",0,"space=5|expand"); - zdialog_add_widget(zdsearchtags,"scrwin","scrwinA","frameA",0,"expand"); - zdialog_add_widget(zdsearchtags,"edit","deftags","scrwinA",0,"expand|wrap"); // v.11.06 - - zdialog_resize(zdsearchtags,400,400); // start dialog - zdialog_help(zdsearchtags,"search_images"); // zdialog help topic v.11.08 - zdialog_run(zdsearchtags,searchtags_dialog_event); - - searchtags_fixwidget(zdsearchtags,"deftags"); // setup tag selection via mouse - searchtags_fixwidget(zdsearchtags,"searchtags"); - - zdialog_stuff(zdsearchtags,"datefrom",searchDateFrom); // stuff previous date range - zdialog_stuff(zdsearchtags,"dateto",searchDateTo); - zdialog_stuff(zdsearchtags,"starsfrom",searchStarsFrom); - zdialog_stuff(zdsearchtags,"starsto",searchStarsTo); - zdialog_stuff(zdsearchtags,"searchtags",tags_searchtags); // stuff previous search tags - zdialog_stuff(zdsearchtags,"searchtext",tags_searchtext); // stuff previous search text - zdialog_stuff(zdsearchtags,"searchfiles",tags_searchfiles); // stuff previous search files - - zdialog_stuff(zdsearchtags,"alltags",0); // default any tags, text, files - zdialog_stuff(zdsearchtags,"anytags",1); - zdialog_stuff(zdsearchtags,"alltext",0); - zdialog_stuff(zdsearchtags,"anytext",1); - zdialog_stuff(zdsearchtags,"allfiles",0); - zdialog_stuff(zdsearchtags,"anyfiles",1); - - load_deftags(); // stuff defined tags into dialog - deftags_stuff(zdsearchtags); - - return; -} - - -// setup tag display widget for tag selection using mouse clicks - -void searchtags_fixwidget(zdialog *zd, cchar * widgetname) -{ - void searchtags_mouse(GtkTextView *widget, GdkEventButton *event, cchar *widgetname); - - GtkWidget *widget; - GdkWindow *gdkwin; - - widget = zdialog_widget(zd,widgetname); // make widget wrap text - gtk_text_view_set_editable(GTK_TEXT_VIEW(widget),0); // disable widget editing - - gdkwin = gtk_text_view_get_window(GTK_TEXT_VIEW(widget),TEXTWIN); // cursor for tag selection - gdk_window_set_cursor(gdkwin,arrowcursor); - - gtk_widget_add_events(widget,GDK_BUTTON_PRESS_MASK); // connect mouse-click event - G_SIGNAL(widget,"button-press-event",searchtags_mouse,widgetname) -} - - -// search tags mouse-click event function -// get clicked tag and add to or remove from tags_searchtags - -void searchtags_mouse(GtkTextView *widget, GdkEventButton *event, cchar *widgetname) -{ - int mpx, mpy, cc; - - if (event->type != GDK_BUTTON_PRESS) return; - mpx = int(event->x); // mouse click position - mpy = int(event->y); - - cc = get_mouse_tag(widget,mpx,mpy,widgetname); // tags_cliktag = clicked tag in list - if (! cc) return; - - if (strEqu(widgetname,"deftags")) { - add_tag(tags_cliktag,tags_searchtags,tagScc); // add defined tag to search tags - zdialog_stuff(zdsearchtags,"searchtags",tags_searchtags); - } - - if (strEqu(widgetname,"searchtags")) { // v.10.6 - del_tag(tags_cliktag,tags_searchtags); // remove tag from searchtags - zdialog_stuff(zdsearchtags,"searchtags",tags_searchtags); // update dialog widgets - } - - return; -} - - -// dialog event and completion callback function - -int searchtags_dialog_event(zdialog *zd, cchar *event) -{ - int searchtags_text(char *textbuff, int Fmall); - - cchar *pps, *ppf; - char resultsfile[tagrecl]; - char *pp, *ppv, *tags; - char indexbuff[tagrecl], filebuff[tagrecl], textbuff[tagrecl]; - char date1[12], date2[12], lcfile[tagrecl], temp[tagScc+50]; - int err, nfiles, iis, iif, cc, stars, nmatch, nfail; - int Fdates, Ftext, Ffiles, Ftags, Fstars, Faccept, Freject; - int Falltags, Falltext, Fallfiles; - FILE *fidr, *fidw; - struct stat statbuf; - - if (! zd->zstat) return 0; // wait for completion - - if (zd->zstat != 1) { - zdialog_free(zdsearchtags); // cancel - return 0; - } - - zd->zstat = 0; // keep dialog active v.10.12 - - zdialog_fetch(zd,"datefrom",searchDateFrom,10); // get search date range - zdialog_fetch(zd,"dateto",searchDateTo,10); - zdialog_fetch(zd,"starsfrom",searchStarsFrom,2); // get search stars range - zdialog_fetch(zd,"starsto",searchStarsTo,2); - zdialog_fetch(zd,"searchtags",tags_searchtags,tagScc); // get search tags - zdialog_fetch(zd,"searchtext",tags_searchtext,tagScc); // get search text* - zdialog_fetch(zd,"searchfiles",tags_searchfiles,tagScc); // get search /path*/file* - - zdialog_fetch(zd,"alltags",Falltags); // get match all/any options - zdialog_fetch(zd,"alltext",Falltext); - zdialog_fetch(zd,"allfiles",Fallfiles); - - strcpy(date1,"0000:01:01"); // defaults for missing dates - strcpy(date2,"9999:12:31"); // v.10.12 - - Fdates = 0; - - if (*searchDateFrom) { // date from was given - Fdates++; - strncpy(date1,searchDateFrom,4); // convert format - if (searchDateFrom[4] >= '0') // yyyymmdd >> yyyy:mm:dd - strncpy(date1+5,searchDateFrom+4,2); - if (searchDateFrom[6] >= '0') - strncpy(date1+8,searchDateFrom+6,2); - } - if (*searchDateTo) { // date to was given - Fdates++; - strncpy(date2,searchDateTo,4); - if (searchDateTo[4] >= '0') - strncpy(date2+5,searchDateTo+4,2); - if (searchDateTo[6] >= '0') - strncpy(date2+8,searchDateTo+6,2); - } - - Fstars = 0; - if (*searchStarsFrom || *searchStarsTo) Fstars = 1; // stars was given - - Ffiles = 0; - if (! blank_null(tags_searchfiles)) Ffiles = 1; // search /path*/file* was given - - Ftext = 0; - if (! blank_null(tags_searchtext)) Ftext = 1; // search text* was given - - Ftags = 0; - if (! blank_null(tags_searchtags)) Ftags = 1; // search tags was given - - if (Ffiles) strToLower(tags_searchfiles); // all comparisons in lower case - if (Ftags) strToLower(tags_searchtags); - if (Ftext) strToLower(tags_searchtext); - - if (Ffiles) { - for (cc = 0, iis = 1; ; iis++) { // add wildcards around file names - pps = strField(tags_searchfiles,' ',iis); // unless already present v.10.12 - if (! pps) break; - temp[cc++] = ' '; - if (*pps != '*') temp[cc++] = '*'; - strcpy(temp+cc,pps); - cc += strlen(pps); - if (temp[cc-1] != '*') temp[cc++] = '*'; - } - temp[cc] = 0; - strcpy(tags_searchfiles,temp); - } - - fidr = fopen(search_index_file,"r"); // read search index file - if (! fidr) goto nodeftags; - - snprintf(resultsfile,199,"%s/search_results",get_zuserdir()); - fidw = fopen(resultsfile,"w"); // search results output file - if (! fidw) goto writerror; - - nfiles = 0; // matching files found - Faccept = 0; // no previous file - Freject = 1; - - while (true) - { - ppv = fgets_trim(indexbuff,tagrecl,fidr); // read next index file record - - if (! ppv || strnEqu(indexbuff,"file: ",6)) // start of next file, - { // finish testing previous file - if (! Freject && Ftext) { - while ((pp = strstr(textbuff,"\\n"))) strncpy(pp," ",2); // replace "\n" (EOL) with " " - if (searchtags_text(textbuff,Falltext)) Faccept++; // test for matching text - else Freject++; - } - - if (Faccept && ! Freject) { - fprintf(fidw,"%s\n",filebuff); // output matching filespec - nfiles++; - } - - if (! ppv) break; // EOF - - Faccept = Freject = 0; // initz. match and fail counts - *textbuff = 0; // initz. no comments or caption - } - - if (strnEqu(indexbuff,"file: ",6)) // index record is file: /filespec - { - strncpy0(filebuff,indexbuff+6,tagrecl); - - err=stat(filebuff,&statbuf); // check file exists - if (err) Freject++; - if (! S_ISREG(statbuf.st_mode)) Freject++; - - if (! Freject && Ffiles) // file name match is wanted - { - strToLower(lcfile,filebuff); - nmatch = nfail = 0; - - for (iis = 1; ; iis++) - { - pps = strField(tags_searchfiles,' ',iis); // step thru search file names - if (! pps) break; - if (MatchWild(pps,lcfile) == 0) nmatch++; - else nfail++; - } - if (nmatch == 0) Freject++; // no match to any file - if (Fallfiles && nfail) Freject++; // no match to all files - if (! Freject) Faccept++; - } - } - - else if (strnEqu(indexbuff,"date: ",6)) // index record is date: yyyy:mm:dd - { - if (! Freject && Fdates) // date match is wanted - { - if (strcmp(ppv+6,date1) < 0) Freject++; - if (strcmp(ppv+6,date2) > 0) Freject++; - if (! Freject) Faccept++; - } - } - - else if (strnEqu(indexbuff,"tags: ",6)) // index record is tags: xxxx, xxxx, ... - { - if (! Freject && Ftags) // tags match is wanted - { - tags = indexbuff + 6; - strToLower(tags); - nmatch = nfail = 0; - - for (iis = 1; ; iis++) // step thru search tags - { - pps = strField(tags_searchtags,tagdelims,iis); // (delimited, wildcards) - if (! pps) break; - if (*pps == ' ') continue; - - for (iif = 1; ; iif++) // step thru file tags (delimited) - { - ppf = strField(tags,tagdelims,iif); - if (! ppf) { nfail++; break; } // count matches and fails - if (*ppf == ' ') continue; - if (MatchWild(pps,ppf) == 0) { nmatch++; break; } // wildcard match - } - } - - if (nmatch == 0) Freject++; // no match to any tag - if (Falltags && nfail) Freject++; // no match to all tags - if (! Freject) Faccept++; - } - } - - else if (strnEqu(indexbuff,"stars: ",7)) // index record is stars: N - { - if (! Freject && Fstars) - { - stars = ppv[7]; - if (*searchStarsFrom && stars < *searchStarsFrom) Freject++; - if (*searchStarsTo && stars > *searchStarsTo) Freject++; - if (! Freject) Faccept++; - } - } - - else if (strnEqu(indexbuff,"comms: ",7)) // index record is comms: user comments - { - if (! Freject && Ftext) - strncatv(textbuff,tagrecl,indexbuff+6,null); // save combined comments & caption - } - - else if (strnEqu(indexbuff,"capt: ",6)) // index record is capt: image caption - { - if (! Freject && Ftext) - strncatv(textbuff,tagrecl,indexbuff+5,null); // save combined comments & caption - } - - else - { - if (strlen(indexbuff) > 1) - printf("unknown tags record: %s \n",indexbuff); - } - } - - fclose(fidr); - - err = fclose(fidw); - if (err) goto writerror; - - if (! nfiles) { - zmessageACK(mWin,ZTX("No matching images found")); - return 0; - } - - zdialog_free(zdsearchtags); // cancel dialog - - image_gallery(resultsfile,"initF",0,m_gallery2,mWin); // generate gallery of matching files - image_gallery(0,"sort"); // sort by filespec v.11.01 - image_gallery(0,"find",0); // top of list v.11.01 - image_gallery(0,"paint1"); // show new image gallery window - return 0; - -nodeftags: - zmessageACK(mWin,ZTX("No search index file present")); - return 0; - -writerror: - zmessLogACK(mWin,ZTX("Search results file error %s"),strerror(errno)); - return 0; -} - - -// search image comments and captions for matching text strings - -int searchtags_text(char *textbuff, int Fmall) -{ - int iis, iif, nmatch, nfail; - cchar *pps, *ppf; - cchar *text_delims = " ,.!@#$%^&()-+={}[]:;<>?/"; // non-western languages? - - strToLower(textbuff); - nmatch = nfail = 0; - - for (iis = 1; ; iis++) // step thru search words - { - pps = strField(tags_searchtext,' ',iis); // (blank delimited, wildcards) - if (! pps) break; - if (*pps == ' ') continue; - - for (iif = 1; ; iif++) // step thru comments/captions (words) - { - ppf = strField(textbuff,text_delims,iif); - if (! ppf) { nfail++; break; } - if (*ppf == ' ') continue; - if (MatchWild(pps,ppf) == 0) { nmatch++; break; } // wildcard match - } - } - - if (nmatch == 0) return 0; // no match to any word - if (Fmall && nfail) return 0; // no match to all words - return 1; -} - - diff -Nru fotoxx-11.11.1/fotoxx_retouch.cc fotoxx-12.01.2/fotoxx_retouch.cc --- fotoxx-11.11.1/fotoxx_retouch.cc 2011-11-05 05:30:36.000000000 +0000 +++ fotoxx-12.01.2/fotoxx_retouch.cc 1970-01-01 00:00:00.000000000 +0000 @@ -1,6310 +0,0 @@ -/************************************************************************** - - Fotoxx edit photos and manage collections - - Copyright 2007 2008 2009 2010 2011 Michael Cornelison - Source URL: http://kornelix.squarespace.com/fotoxx - Contact: kornelix2@googlemail.com - - 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 http://www.gnu.org/licenses/. - -***************************************************************************/ - -#define EX extern // enable extern declarations -#include "fotoxx.h" - - -/************************************************************************** - - Fotoxx image edit - retouch functions - -***************************************************************************/ - - -// brightness / color / contrast adjustment - -void tune_curve_update(int spc); // curve update callback function -void tune_update_image(); // process all pixels -void tune_update_pixel(int px, int py); // process one pixel -void *tune_thread(void *); // thread process for all pixels - -int tune_spc; // current spline curve 1-5 -int tune_spc_moved[6]; // tracks which curves changed - -double tune_pow[10000]; // pow(2,x) for x = -5.0 to +5.0 -int tune_ftf = 1; - -editfunc EFtune; - - -void m_tune(GtkWidget *, cchar *) // menu function -{ - int tune_dialog_event(zdialog *zd, cchar *event); - - cchar *title = ZTX("Adjust Brightness and Color"); - zfuncs::F1_help_topic = "tune"; // v.10.8 - - EFtune.funcname = "bright-color"; - EFtune.Fprev = 1; // use preview - EFtune.Farea = 2; // select area usable - EFtune.Fpara = 1; // parallel edit OK - EFtune.threadfunc = tune_thread; - if (! edit_setup(EFtune)) return; // setup edit - - if (tune_ftf) { - tune_ftf = 0; // pre-compute pow(2,x) - for (int ii = 0; ii < 10000; ii++) // for x = -5.0 to +4.999 - tune_pow[ii] = pow(2,(ii/1000.0 - 5.0)); - } - -/*** - ____________________________________________ - | | - | | - | curve drawing area | - | | - | | - |____________________________________________| - darker areas lighter areas - - [+++] [---] [+ -] [- +] [+-+] [-+-] - Curve File: [ Open ] [ Save ] - (o) brightness [reset 1] [reset all] - (o) color saturation [histogram] - (o) red - (o) green - (o) blue - [done] [cancel] -***/ - - zdialog *zd = zdialog_new(title,mWin,Bdone,Bcancel,null); - EFtune.zd = zd; - - zdialog_add_widget(zd,"frame","fr1","dialog",0,"expand"); - zdialog_add_widget(zd,"hbox","hba","dialog"); - zdialog_add_widget(zd,"label","labda","hba",Bdarker,"space=5"); - zdialog_add_widget(zd,"label","space","hba",0,"expand"); - zdialog_add_widget(zd,"label","labba","hba",Blighter,"space=5"); - - zdialog_add_widget(zd,"hbox","hbb","dialog",0,"space=5"); - zdialog_add_widget(zd,"button","b +++","hbb","+++"); - zdialog_add_widget(zd,"button","b ---","hbb","‒ ‒ ‒"); - zdialog_add_widget(zd,"button","b +-", "hbb"," + ‒ "); - zdialog_add_widget(zd,"button","b -+", "hbb"," ‒ + "); - zdialog_add_widget(zd,"button","b +-+","hbb","+ ‒ +"); - zdialog_add_widget(zd,"button","b -+-","hbb","‒ + ‒"); - - zdialog_add_widget(zd,"hbox","hbcf","dialog",0,"space=5"); - zdialog_add_widget(zd,"check","smallstep","hbcf",ZTX("small-steps")); - zdialog_add_widget(zd,"label","labcf","hbcf",Bcurvefile,"space=5"); - zdialog_add_widget(zd,"button","load","hbcf",Bopen); - zdialog_add_widget(zd,"button","save","hbcf",Bsave,"space=5"); - - zdialog_add_widget(zd,"hbox","hb2","dialog"); - zdialog_add_widget(zd,"vbox","vb21","hb2"); - zdialog_add_widget(zd,"vbox","vb22","hb2"); - zdialog_add_widget(zd,"radio","radbri","vb21",Bbrightness); - zdialog_add_widget(zd,"radio","radsat","vb21",ZTX("color saturation")); - zdialog_add_widget(zd,"radio","radR","vb21",Bred); - zdialog_add_widget(zd,"radio","radG","vb21",Bgreen); - zdialog_add_widget(zd,"radio","radB","vb21",Bblue); - - zdialog_add_widget(zd,"hbox","hbrs","vb22",0,"space=5"); - zdialog_add_widget(zd,"label","space","hbrs",0,"space=10"); - zdialog_add_widget(zd,"button","reset1","hbrs",ZTX(" reset 1 ")); - zdialog_add_widget(zd,"button","resetA","hbrs",ZTX("reset all")); - zdialog_add_widget(zd,"hbox","hbhist","vb22",0,"space=6"); - zdialog_add_widget(zd,"label","space","hbhist",0,"space=10"); - zdialog_add_widget(zd,"button","histo","hbhist",Bhistogram); - - GtkWidget *frame = zdialog_widget(zd,"fr1"); // setup for curve editing - spldat *sd = splcurve_init(frame,tune_curve_update); // v.11.01 - EFtune.curves = sd; - - sd->Nscale = 3; // y-scale lines at 1.0 EV intervals - sd->xscale[0][0] = 0.00; // x and y values v.11.10 - sd->yscale[0][0] = 0.25; - sd->xscale[1][0] = 1.00; - sd->yscale[1][0] = 0.25; - sd->xscale[0][1] = 0.00; - sd->yscale[0][1] = 0.50; - sd->xscale[1][1] = 1.00; - sd->yscale[1][1] = 0.50; - sd->xscale[0][2] = 0.00; - sd->yscale[0][2] = 0.75; - sd->xscale[1][2] = 1.00; - sd->yscale[1][2] = 0.75; - - for (int spc = 0; spc < 6; spc++) // setup 6 spline curves - { // no. 0 is active curve - sd->vert[spc] = 0; // all curves are horizontal - sd->nap[spc] = 3; // curves 1-6 are copied to 0 when active - sd->apx[spc][0] = 0.01; - sd->apy[spc][0] = 0.5; - sd->apx[spc][1] = 0.5; - sd->apy[spc][1] = 0.5; - sd->apx[spc][2] = 0.99; - sd->apy[spc][2] = 0.5; - splcurve_generate(sd,spc); - tune_spc_moved[spc] = 0; - } - - sd->Nspc = 1; // only one at a time is active - tune_spc = 1; // default curve = brightness - - zdialog_stuff(zd,"radbri",1); // stuff default selection - - zdialog_resize(zd,0,500); - zdialog_help(zd,"tune"); // zdialog help topic v.11.08 - zdialog_run(zd,tune_dialog_event,"save"); // run dialog - parallel v.11.07 - return; -} - - -// dialog event and completion callback function - -int tune_dialog_event(zdialog *zd, cchar *event) -{ - int Fupdate = 0; - int ii, jj, nn; - static int smallstep = 0; - double step, step2, step4; - double px, py; - spldat *sd = EFtune.curves; - spldat sdtemp; - - if (zd->zstat) - { - if (zd->zstat == 1) edit_done(EFtune); // done - else edit_cancel(EFtune); // cancel or destroy - return 0; - } - - edit_takeover(EFtune); // set my edit function - - if (strEqu(event,"reset")) // reset dialog controls v.11.08 - event = "resetA"; - - if (strEqu(event,"blendwidth")) tune_update_image(); // v.10.3 - if (strEqu(event,"histo")) m_histogram(0,0); // popup brightness histogram - - if (strnEqu(event,"rad",3)) { // new choice of curve - ii = strcmpv(event,"radbri","radsat","radR","radG","radB",null); - tune_spc = ii; - sd->nap[0] = sd->nap[ii]; // copy active curve to curve 0 - for (jj = 0; jj < sd->nap[0]; jj++) { - sd->apx[0][jj] = sd->apx[ii][jj]; - sd->apy[0][jj] = sd->apy[ii][jj]; - } - Fupdate++; - } - - if (strEqu(event,"smallstep")) // toggle [+++] etc. step size - zdialog_fetch(zd,"smallstep",smallstep); - - ii = tune_spc; // current active curve - - if (strnEqu(event,"b ",2)) { // button [+++] etc. - move entire curve - for (jj = 0; jj < sd->nap[ii]; jj++) { - px = sd->apx[0][jj]; - py = sd->apy[0][jj]; - - step = 0.025; // 1/40 - if (smallstep) step = step * 0.3333; - step2 = 2 * step; - step4 = 4 * step; - - if (strEqu(event,"b +++")) py += step; // range is 40 steps v.11.07 - if (strEqu(event,"b ---")) py -= step; // = -2.0 to +2.0 EV - if (strEqu(event,"b +-")) py += step - step2 * px; // normal steps are 0.1 EV or 0.03 OD - if (strEqu(event,"b -+")) py -= step - step2 * px; // small steps are 1/3 as big - if (strEqu(event,"b +-+")) py -= step - step4 * fabs(px-0.5); - if (strEqu(event,"b -+-")) py += step - step4 * fabs(px-0.5); - if (py > 1) py = 1; - if (py < 0) py = 0; - sd->apy[0][jj] = py; - } - tune_spc_moved[ii] = 1; - Fupdate++; - } - - if (strEqu(event,"reset1")) { // reset current curve - sd->nap[0] = 3; - sd->apx[0][0] = 0.01; // 3 anchor points, flatline - sd->apy[0][0] = 0.5; - sd->apx[0][1] = 0.5; - sd->apy[0][1] = 0.5; - sd->apx[0][2] = 0.99; - sd->apy[0][2] = 0.5; - Fupdate++; - tune_spc_moved[ii] = 0; - } - - if (strEqu(event,"resetA")) - { - for (jj = 0; jj < 6; jj++) { // reset all curves - sd->nap[jj] = 3; - sd->apx[jj][0] = 0.01; - sd->apy[jj][0] = 0.5; - sd->apx[jj][1] = 0.5; - sd->apy[jj][1] = 0.5; - sd->apx[jj][2] = 0.99; - sd->apy[jj][2] = 0.5; - splcurve_generate(sd,jj); // regenerate all - tune_spc_moved[jj] = 0; - } - Fupdate++; - } - - if (strEqu(event,"load")) // load 5 saved curves v.11.02 - { - sdtemp.Nspc = 5; - sdtemp.drawarea = 0; - nn = splcurve_load(&sdtemp); - if (nn != 1) return 0; - - for (ii = 0; ii < 5; ii++) { - for (jj = 0; jj < sdtemp.nap[ii]; jj++) { - sd->apx[ii+1][jj] = sdtemp.apx[ii][jj]; - sd->apy[ii+1][jj] = sdtemp.apy[ii][jj]; - } - splcurve_generate(sd,ii+1); - tune_spc_moved[ii+1] = 1; - } - - ii = tune_spc; - sd->nap[0] = sd->nap[ii]; // copy active curve to curve 0 - for (jj = 0; jj < sd->nap[0]; jj++) { - sd->apx[0][jj] = sd->apx[ii][jj]; - sd->apy[0][jj] = sd->apy[ii][jj]; - } - Fupdate++; - } - - if (strEqu(event,"save")) // save 5 curves to file v.11.02 - { - sdtemp.Nspc = 5; - for (ii = 0; ii < 5; ii++) { - sdtemp.nap[ii] = sd->nap[ii+1]; - for (jj = 0; jj < sd->nap[ii+1]; jj++) { - sdtemp.apx[ii][jj] = sd->apx[ii+1][jj]; - sdtemp.apy[ii][jj] = sd->apy[ii+1][jj]; - } - } - splcurve_save(&sdtemp); - } - - if (Fupdate) // curve has changed - { - splcurve_generate(sd,0); // regenerate curve 0 - - ii = tune_spc; // active curve - sd->nap[ii] = sd->nap[0]; // copy curve 0 to active curve - for (jj = 0; jj < sd->nap[0]; jj++) { - sd->apx[ii][jj] = sd->apx[0][jj]; - sd->apy[ii][jj] = sd->apy[0][jj]; - } - for (jj = 0; jj < 1000; jj++) - sd->yval[ii][jj] = sd->yval[0][jj]; - - splcurve_draw(0,0,sd); // draw curve - tune_update_image(); // trigger image update - } - - return 1; -} - - -// this function is called when curve 0 is edited using mouse - -void tune_curve_update(int) -{ - int ii = tune_spc, jj; - spldat *sd = EFtune.curves; - - edit_takeover(EFtune); // set my edit function - - sd->nap[ii] = sd->nap[0]; // copy curve 0 to current curve - for (jj = 0; jj < sd->nap[0]; jj++) { - sd->apx[ii][jj] = sd->apx[0][jj]; - sd->apy[ii][jj] = sd->apy[0][jj]; - } - for (jj = 0; jj < 1000; jj++) - sd->yval[ii][jj] = sd->yval[0][jj]; - - tune_spc_moved[ii] = 1; - tune_update_image(); // update image - return; -} - - -// Update image based on latest settings of all dialog controls. - -void tune_update_image() // v.11.06 -{ - int px, py, ww, hh; - - if (Factivearea && sa_Npixel < 200000) // if relatively small area, - { // process in main() thread v.11.06 - for (py = sa_miny; py < sa_maxy; py++) - for (px = sa_minx; px < sa_maxx; px++) - tune_update_pixel(px,py); - - px = sa_minx; // direct window update - py = sa_miny; - ww = sa_maxx - sa_minx; - hh = sa_maxy - sa_miny; - mwpaint3(px,py,ww,hh); // speedup v.11.06 - CEF->Fmod = 1; - } - - else signal_thread(); // else use thread process - return; -} - - -// Update image based on latest settings of all dialog controls. - -void * tune_thread(void *) -{ - void * tune_wthread(void *arg); - - while (true) - { - thread_idle_loop(); // wait for work or exit request - - for (int ii = 0; ii < Nwt; ii++) // start worker threads - start_wthread(tune_wthread,&wtnx[ii]); - wait_wthreads(); // wait for completion - - CEF->Fmod = 1; - mwpaint2(); // update window - } - - return 0; // not executed, stop g++ warning -} - - -void * tune_wthread(void *arg) // worker thread function -{ - int px, py; - int index = *((int *) arg); - - for (py = index; py < E1hh; py += Nwt) - for (px = 0; px < E1ww; px++) - tune_update_pixel(px,py); - - exit_wthread(); - return 0; // not executed, avoid gcc warning -} - - -void tune_update_pixel(int px, int py) // process one pixel -{ - int ii, kk, dist = 0; - uint16 *pix1, *pix3; - double red1, green1, blue1, red3, green3, blue3; - double xval, brmax, brmean, brout, brightness; - spldat *sd = EFtune.curves; - - if (Factivearea) { // select area active - ii = py * Fww + px; - dist = sa_pixmap[ii]; // distance from edge - if (! dist) return; // pixel outside area - } - - pix1 = PXMpix(E1pxm16,px,py); // input pixel - pix3 = PXMpix(E3pxm16,px,py); // output pixel - - red1 = red3 = pix1[0]; // input and output RGB values - green1 = green3 = pix1[1]; - blue1 = blue3 = pix1[2]; - - brightness = 0.25 * red3 + 0.65 * green3 + 0.10 * blue3; // perceived brightness v.10.9 - xval = brightness / 65536.0; // curve x-value, 0 to 0.999 - -/* ------------------------------------------------------------------------ - - brightness adjustment - - brightness curve values: - 0 = dark - 0.5 = normal, unchanged - 1.0 = 200% brightness, clipped -*/ - - if (tune_spc_moved[1]) // curve has been edited - { - kk = 1000 * xval; // x-value speedup v.11.06 - if (kk > 999) kk = 999; - brout = sd->yval[1][kk]; // y-value, 0 to 1.0 - brout = 4 * brout - 2; // F-stops, -2 to +2 v.11.07 - brout = tune_pow[int(1000*brout+5000.5)]; // 0.25 to 4.0 - - brmax = red3; // brmax = brightest color - if (green3 > brmax) brmax = green3; - if (blue3 > brmax) brmax = blue3; - - red3 = red3 * brout; // apply to all colors - green3 = green3 * brout; // remove limit check v.10.9 - blue3 = blue3 * brout; // (result is better) - } - -/* ------------------------------------------------------------------------ - - color saturation curve values: - 0 = no color saturation (gray scale) - 0.5 = normal (initial unmodified RGB) - 1.0 = max. color saturation - - 0.5 >> 0: move all RGB values to their mean: (R+G+B)/3 - 0.5 >> 1.0: increase RGB spread to 2x original level -*/ - - if (tune_spc_moved[2]) // curve has been edited - { - kk = 1000 * xval; // speedup v.11.06 - if (kk > 999) kk = 999; - brout = sd->yval[2][kk]; // saturation factor, 0 - 1 - brout = 2.0 * brout - 1.0; // -1.0 .. +1.0 - brmean = 0.333 * (red3 + green3 + blue3); - red3 = red3 + brout * (red3 - brmean); // simplified v.10.9 - green3 = green3 + brout * (green3 - brmean); - blue3 = blue3 + brout * (blue3 - brmean); - if (red3 < 0) red3 = 0; - if (green3 < 0) green3 = 0; - if (blue3 < 0) blue3 = 0; - } - -/* ------------------------------------------------------------------------ - - color balance curve values: - 0 = 0.5 * original color - 0.5 = unmodified - 1.0 = 1.5 * original color, clipped -*/ - - if (tune_spc_moved[3]) { // curve has been edited - kk = 1000 * xval; // speedup v.11.06 - if (kk > 999) kk = 999; - brout = sd->yval[3][kk]; // 0 to 1.0 - brout = 4 * brout - 2; // F-stops, -2 to +2 v.11.07 - brout = tune_pow[int(1000*brout+5000.5)]; // 0.25 to 4.0 - red3 = red3 * brout; - } - - if (tune_spc_moved[4]) { - kk = 1000 * xval; - if (kk > 999) kk = 999; - brout = sd->yval[4][kk]; - brout = 4 * brout - 2; - brout = tune_pow[int(1000*brout+5000.5)]; - green3 = green3 * brout; - } - - if (tune_spc_moved[5]) { - kk = 1000 * xval; - if (kk > 999) kk = 999; - brout = sd->yval[5][kk]; - brout = 4 * brout - 2; - brout = tune_pow[int(1000*brout+5000.5)]; - blue3 = blue3 * brout; - } - -// if working within a select area, blend changes over distance from edge - - double dold, dnew; - - if (Factivearea && dist < sa_blend) { - dnew = 1.0 * dist / sa_blend; - dold = 1.0 - dnew; - red3 = dnew * red3 + dold * red1; - green3 = dnew * green3 + dold * green1; - blue3 = dnew * blue3 + dold * blue1; - } - -// prevent overflow and set output RGB values - - double cmax; - - cmax = red3; // detect overflow v.11.07 - if (green3 > cmax) cmax = green3; - if (blue3 > cmax) cmax = blue3; - - if (cmax > 65535) { // stop overflow - red3 = red3 * 65535 / cmax; - green3 = green3 * 65535 / cmax; - blue3 = blue3 * 65535 / cmax; - } - - pix3[0] = int(red3); - pix3[1] = int(green3); - pix3[2] = int(blue3); - - return; -} - - -/**************************************************************************/ - -// adjust image gamma using classic gamma curve - -editfunc EFgamma; -int gamma_spc; // current spline curve - -void m_gamma(GtkWidget *, cchar *) // new v.11.10 -{ - int gamma_dialog_event(zdialog* zd, cchar *event); - void gamma_curvedit(int spc); - void * gamma_thread(void *); - - zfuncs::F1_help_topic = "gamma_curve"; - - EFgamma.funcname = "gamma"; - EFgamma.Fprev = 1; // use preview - EFgamma.Farea = 2; // select area usable - EFgamma.Fpara = 1; // parallel edit OK - EFgamma.threadfunc = gamma_thread; - if (! edit_setup(EFgamma)) return; // setup edit - -/*** - _________________________________________ - | | // 5 curves are maintained: - | | // curve 0: current display curve - | | // 1: curve for all colors - | | // 2,3,4: red, green, blue - | curve edit area | - | | - | | - | | - |_________________________________________| - - (o) all (o) red (o) green (o) blue // colors: all, red, green, blue - Curve File: [Open] [Save] [histogram] - [Done] [Cancel] -***/ - - zdialog *zd = zdialog_new(ZTX("adjust image gamma"),mWin,Bdone,Bcancel,null); - EFgamma.zd = zd; - - zdialog_add_widget(zd,"frame","frame","dialog",0,"expand"); - zdialog_add_widget(zd,"hbox","hbrgb","dialog",0,"space=3"); - zdialog_add_widget(zd,"radio","all","hbrgb",Ball,"space=5"); - zdialog_add_widget(zd,"radio","red","hbrgb",Bred,"space=5"); - zdialog_add_widget(zd,"radio","green","hbrgb",Bgreen,"space=5"); - zdialog_add_widget(zd,"radio","blue","hbrgb",Bblue,"space=5"); - zdialog_add_widget(zd,"hbox","hbcf","dialog",0,"space=3"); - zdialog_add_widget(zd,"label","labcf","hbcf",Bcurvefile,"space=5"); - zdialog_add_widget(zd,"button","load","hbcf",Bopen); - zdialog_add_widget(zd,"button","save","hbcf",Bsave,"space=3"); - zdialog_add_widget(zd,"button","hist","hbcf",Bhistogram,"space=15"); - - - GtkWidget *frame = zdialog_widget(zd,"frame"); - spldat *sd = splcurve_init(frame,gamma_curvedit); - EFgamma.curves = sd; - - sd->Nscale = 1; // diagonal fixed line for neutral curve - sd->xscale[0][0] = 0.00; - sd->yscale[0][0] = 0.00; - sd->xscale[1][0] = 1.00; - sd->yscale[1][0] = 1.00; - - for (int ii = 0; ii < 5; ii++) // loop curves 0-4 - { - sd->nap[ii] = 3; // initial curves are flat - sd->vert[ii] = 0; - sd->apx[ii][0] = sd->apy[ii][0] = 0.01; - sd->apx[ii][1] = sd->apy[ii][1] = 0.50; - sd->apx[ii][2] = sd->apy[ii][2] = 0.99; - splcurve_generate(sd,ii); - } - - sd->Nspc = 1; // only curve 0 is shown - gamma_spc = 1; // current active curve: 1 (all) - - zdialog_stuff(zd,"all",1); // stuff default selection, all - - zdialog_resize(zd,260,300); - zdialog_help(zd,"gamma_curve"); // zdialog help topic - zdialog_run(zd,gamma_dialog_event,"save"); // run dialog - parallel - - return; -} - - -// dialog event and completion callback function - -int gamma_dialog_event(zdialog *zd, cchar *event) -{ - spldat *sd = EFgamma.curves; - int ii, jj, nn, Fupdate = 0; - spldat sdtemp; - - if (zd->zstat) // dialog complete - { - if (zd->zstat == 1) edit_done(EFgamma); - else edit_cancel(EFgamma); - return 1; - } - - edit_takeover(EFgamma); // set my edit function - - if (strEqu(event,"blendwidth")) signal_thread(); // adjust area edge blending - - if (strEqu(event,"hist")) m_histogram(0,0); // show brightness distribution - - if (strstr("all red green blue",event)) { // new choice of curve - zdialog_fetch(zd,event,ii); - if (! ii) return 0; // ignore button OFF events - - ii = strcmpv(event,"all","red","green","blue",null); - gamma_spc = ii; // 1, 2, 3, 4 - - sd->nap[0] = sd->nap[ii]; // copy active curve ii to curve 0 - for (jj = 0; jj < sd->nap[0]; jj++) { - sd->apx[0][jj] = sd->apx[ii][jj]; - sd->apy[0][jj] = sd->apy[ii][jj]; - } - - Fupdate++; - } - - if (strEqu(event,"load")) // load 4 saved curves from file - { - sdtemp.Nspc = 4; - sdtemp.drawarea = 0; - nn = splcurve_load(&sdtemp); - if (nn != 1) return 0; - - for (ii = 0; ii < 4; ii++) { // load curves 0-3 to curves 1-4 - sd->vert[ii+1] = sdtemp.vert[ii]; - sd->nap[ii+1] = sdtemp.nap[ii]; - for (jj = 0; jj < sdtemp.nap[ii]; jj++) { - sd->apx[ii+1][jj] = sdtemp.apx[ii][jj]; - sd->apy[ii+1][jj] = sdtemp.apy[ii][jj]; - } - splcurve_generate(sd,ii+1); - } - - ii = gamma_spc; // current active curve, 1-4 - - sd->nap[0] = sd->nap[ii]; // copy active curve to curve 0 - for (jj = 0; jj < sd->nap[0]; jj++) { - sd->apx[0][jj] = sd->apx[ii][jj]; - sd->apy[0][jj] = sd->apy[ii][jj]; - } - - Fupdate++; - } - - if (strEqu(event,"save")) // save 4 curves to a file - { - sdtemp.Nspc = 4; - for (ii = 0; ii < 4; ii++) { - sdtemp.vert[ii] = sd->vert[ii+1]; - sdtemp.nap[ii] = sd->nap[ii+1]; - for (jj = 0; jj < sd->nap[ii+1]; jj++) { - sdtemp.apx[ii][jj] = sd->apx[ii+1][jj]; - sdtemp.apy[ii][jj] = sd->apy[ii+1][jj]; - } - } - - splcurve_save(&sdtemp); - } - - if (Fupdate) // curve has changed - { - splcurve_generate(sd,0); // regenerate curve 0 - - ii = gamma_spc; // active curve 1-4 - - sd->nap[ii] = sd->nap[0]; // copy curve 0 to active curve - for (jj = 0; jj < sd->nap[0]; jj++) { - sd->apx[ii][jj] = sd->apx[0][jj]; - sd->apy[ii][jj] = sd->apy[0][jj]; - } - - for (jj = 0; jj < 1000; jj++) - sd->yval[ii][jj] = sd->yval[0][jj]; - - splcurve_draw(0,0,sd); // draw curve - - signal_thread(); // trigger image update - } - - return 1; -} - - -// this function is called when a curve is edited - -void gamma_curvedit(int spc) -{ - int ii = gamma_spc, jj; - spldat *sd = EFgamma.curves; // active curve, 1-4 - - edit_takeover(EFgamma); // set my edit function - - sd->nap[ii] = sd->nap[0]; // copy curve 0 to active curve - for (jj = 0; jj < sd->nap[0]; jj++) { - sd->apx[ii][jj] = sd->apx[0][jj]; - sd->apy[ii][jj] = sd->apy[0][jj]; - } - - for (jj = 0; jj < 1000; jj++) - sd->yval[ii][jj] = sd->yval[0][jj]; - - if (gamma_spc == 1) { // "all" curve (1) was edited - for (ii = 2; ii < 5; ii++) { // fix R/G/B curves (2-4) to match - sd->nap[ii] = sd->nap[1]; - for (jj = 0; jj < sd->nap[1]; jj++) { - sd->apx[ii][jj] = sd->apx[1][jj]; - sd->apy[ii][jj] = sd->apy[1][jj]; - } - - for (jj = 0; jj < 1000; jj++) - sd->yval[ii][jj] = sd->yval[1][jj]; - } - } - - signal_thread(); - return; -} - - -// gamma thread function - -void * gamma_thread(void *arg) -{ - void * gamma_wthread(void *); - - while (true) - { - thread_idle_loop(); // wait for work or exit request - - for (int ii = 0; ii < Nwt; ii++) // start worker threads - start_wthread(gamma_wthread,&wtnx[ii]); - wait_wthreads(); // wait for completion - - mwpaint2(); // update window - CEF->Fmod = 1; // image3 modified - } - - return 0; // not executed, stop g++ warning -} - - -void * gamma_wthread(void *arg) // worker thread function -{ - int index = *((int *) arg); - int ii, dist = 0, px3, py3; - uint16 *pix1, *pix3; - double red1, green1, blue1, maxrgb; - double red3, green3, blue3; - double coeff = 1000.0 / 65536.0; - double dold, dnew; - spldat *sd = EFgamma.curves; - - for (py3 = index; py3 < E3hh; py3 += Nwt) // loop output pixels - for (px3 = 0; px3 < E3ww; px3++) - { - if (Factivearea) { // select area active - ii = py3 * E3ww + px3; - dist = sa_pixmap[ii]; // distance from edge - if (! dist) continue; // pixel outside area - } - - pix1 = PXMpix(E1pxm16,px3,py3); // input pixel - pix3 = PXMpix(E3pxm16,px3,py3); // output pixel - - red1 = pix1[0]; // input RGB brightness, 0-65535 - green1 = pix1[1]; - blue1 = pix1[2]; - - ii = coeff * red1; // range 0-999 for gamma curve index - red3 = 65535.0 * sd->yval[2][ii]; // output RGB brightness, 0-65535 - ii = coeff * green1; - green3 = 65535.0 * sd->yval[3][ii]; - ii = coeff * blue1; - blue3 = 65535.0 * sd->yval[4][ii]; - - maxrgb = red3; - if (green3 > maxrgb) maxrgb = green3; - if (blue3 > maxrgb) maxrgb = blue3; - - if (maxrgb > 65535) { // stop overflow - red3 = red3 * 65535 / maxrgb; - green3 = green3 * 65535 / maxrgb; - blue3 = blue3 * 65535 / maxrgb; - } - - if (Factivearea && dist < sa_blend) { // blend changes over blendwidth - dnew = 1.0 * dist / sa_blend; - dold = 1.0 - dnew; - red3 = dnew * red3 + dold * red1; - green3 = dnew * green3 + dold * green1; - blue3 = dnew * blue3 + dold * blue1; - } - - pix3[0] = red3; - pix3[1] = green3; - pix3[2] = blue3; - } - - exit_wthread(); - return 0; // not executed, avoid gcc warning -} - - -/**************************************************************************/ - -// Clip pixels outside the given low/high range and expand the remaining -// brightness range back to the full range of 0 to 65535. - -double xbrangeD, xbrangeB; -editfunc EFxbrange; - -void m_xbrange(GtkWidget *, cchar *) // new v.10.1 -{ - int xbrange_dialog_event(zdialog *zd, cchar *event); - void * xbrange_thread(void *); - - cchar *title = ZTX("Expand Brightness Range"); - cchar *labD = ZTX("dark pixels"); - cchar *labB = ZTX("bright pixels"); - - zfuncs::F1_help_topic = "expand_brightness"; // v.10.8 - - EFxbrange.funcname = "bright-range"; - EFxbrange.Fprev = 1; // use preview - EFxbrange.Farea = 2; // select area usable - EFxbrange.Fpara = 1; // parallel edit OK - EFxbrange.threadfunc = xbrange_thread; // thread function - if (! edit_setup(EFxbrange)) return; // setup edit - - zdialog *zd = zdialog_new(title,mWin,Bdone,Bcancel,null); // revised v.11.01 - EFxbrange.zd = zd; - - zdialog_add_widget(zd,"hbox","hb1","dialog",0,"expand"); - zdialog_add_widget(zd,"vbox","vb1","hb1",0,"homog|space=5"); - zdialog_add_widget(zd,"vbox","vb2","hb1",0,"homog|expand"); - zdialog_add_widget(zd,"vbox","vb3","hb1",0,"homog|space=8"); - zdialog_add_widget(zd,"label","labD","vb1",labD); - zdialog_add_widget(zd,"label","labB","vb1",labB); - zdialog_add_widget(zd,"hscale","clipD","vb2","0|99|0.5|0"); - zdialog_add_widget(zd,"hscale","clipB","vb2","0|99|0.5|0"); - zdialog_add_widget(zd,"label","darkval","vb3"); - zdialog_add_widget(zd,"label","briteval","vb3"); - - zdialog_resize(zd,300,0); - zdialog_help(zd,"expand_brightness"); // zdialog help topic v.11.08 - zdialog_run(zd,xbrange_dialog_event,"save"); // run dialog - parallel v.11.07 - - m_histogram(0,0); // show brightness distribution v.11.02 - - xbrangeD = xbrangeB = 0; // initial clip = 0 - return; -} - - -// dialog event and completion callback function - -int xbrange_dialog_event(zdialog *zd, cchar *event) -{ - char text[8]; - - if (zd->zstat) // dialog complete - { - if (zd->zstat == 1) edit_done(EFxbrange); - else edit_cancel(EFxbrange); - histogram_destroy(); // v.11.02 - return 1; - } - - edit_takeover(EFxbrange); // set my edit function - - if (strEqu(event,"reset")) { // reset dialog controls v.11.08 - zdialog_stuff(zd,"clipD",0); - zdialog_stuff(zd,"clipB",0); - } - - if (strEqu(event,"blendwidth")) signal_thread(); // v.10.3 - - if (strEqu(event,"clipD")) { - zdialog_fetch(zd,"clipD",xbrangeD); - signal_thread(); - } - - if (strEqu(event,"clipB")) { - zdialog_fetch(zd,"clipB",xbrangeB); - signal_thread(); - } - - sprintf(text,"%.0f",xbrangeD); // numeric feedback v.11.07 - zdialog_stuff(zd,"darkval",text); - sprintf(text,"%.0f",xbrangeB); - zdialog_stuff(zd,"briteval",text); - - return 0; -} - - -// thread function - -void * xbrange_thread(void *) -{ - int ii, px, py, dist = 0; - double dark, bright, b1, b3, bf, f1, f2; - double red1, green1, blue1, red3, green3, blue3; - uint16 *pix1, *pix3; - - while (true) - { - thread_idle_loop(); // wait for work or exit request - - dark = 0.01 * xbrangeD * 65536; // clipping brightness levels - bright = (1.0 - 0.01 * xbrangeB) * 65536; - - for (py = 0; py < E3hh; py++) // loop all image pixels - for (px = 0; px < E3ww; px++) - { - ii = py * E3ww + px; - - if (Factivearea) { // select area active bugfix v.9.9 - dist = sa_pixmap[ii]; // distance from edge - if (! dist) continue; // pixel is outside area - } - - pix1 = PXMpix(E1pxm16,px,py); // input pixel - pix3 = PXMpix(E3pxm16,px,py); // output pixel - - b1 = pixbright(pix1); - - if (b1 < dark) // clip dark pixels - b3 = 0; - else if (b1 > bright) // clip bright pixels - b3 = bright; - else b3 = b1; - - if (b3 > dark) b3 = b3 - dark; // expand the rest - b3 = b3 * (65535.0 / (bright - dark)); - - bf = b3 / (b1 + 1); // brightness ratio - - red1 = pix1[0]; // input RGB v.11.08 - green1 = pix1[1]; - blue1 = pix1[2]; - - red3 = bf * red1; // output RGB - green3 = bf * green1; - blue3 = bf * blue1; - - if (red3 > 65535) red3 = 65535; - if (green3 > 65535) green3 = 65535; - if (blue3 > 65535) blue3 = 65535; - - if (Factivearea && dist < sa_blend) { // select area is active, - f1 = 1.0 * dist / sa_blend; // blend changes over sa_blend - f2 = 1.0 - f1; - red3 = f1 * red3 + f2 * red1; - green3 = f1 * green3 + f2 * green1; - blue3 = f1 * blue3 + f2 * blue1; - } - - pix3[0] = red3; - pix3[1] = green3; - pix3[2] = blue3; - } - - CEF->Fmod = 1; - mwpaint2(); - } - - return 0; // not executed, stop g++ warning -} - - -/**************************************************************************/ - -// flatten brightness distribution - -double flatten_value = 0; // flatten value, 0 - 100% -double flatten_brdist[65536]; - -void flatten_update_image(); -void flatten_distribution(); // compute brightness distribution -void flatten_pixel(int px, int py); // compute new pixel brightness - -editfunc EFflatten; - -void m_flatten(GtkWidget *, cchar *) -{ - int flatten_dialog_event(zdialog* zd, cchar *event); - void * flatten_thread(void *); - - cchar *title = ZTX("Flatten Brightness Distribution"); - zfuncs::F1_help_topic = "flatten"; - - EFflatten.funcname = "flatten"; - EFflatten.Fprev = 1; // preview - EFflatten.Farea = 2; // select area usable - EFflatten.Fpara = 1; // parallel edit OK - EFflatten.threadfunc = flatten_thread; - if (! edit_setup(EFflatten)) return; // setup edit - - zdialog *zd = zdialog_new(title,mWin,Bdone,Bcancel,null); - EFflatten.zd = zd; - - zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=15"); - zdialog_add_widget(zd,"label","labfd","hb1",ZTX("Flatten"),"space=5"); - zdialog_add_widget(zd,"hscale","flatten","hb1","0|100|1|0","expand"); - zdialog_add_widget(zd,"label","value","hb1",0,"space=5"); - - zdialog_help(zd,"flatten"); // v.11.08 - zdialog_resize(zd,300,0); - zdialog_run(zd,flatten_dialog_event,"save"); // run dialog - parallel v.11.07 - - flatten_value = 0; - return; -} - - -// dialog event and completion callback function - -int flatten_dialog_event(zdialog *zd, cchar *event) // flatten dialog event function -{ - char text[8]; - - if (zd->zstat) - { - if (zd->zstat == 1) edit_done(EFflatten); // done - else edit_cancel(EFflatten); // cancel or destroy - return 0; - } - - edit_takeover(EFflatten); // set my edit function - - if (strEqu(event,"blendwidth")) flatten_update_image(); // v.11.06 - - if (strEqu(event,"flatten")) { - zdialog_fetch(zd,"flatten",flatten_value); // get slider value - sprintf(text,"%.0f",flatten_value); // numeric feedback v.11.07 - zdialog_stuff(zd,"value",text); - flatten_update_image(); // trigger update thread - } - - return 1; -} - - -// Update image based on select area and dialog controls - -void flatten_update_image() // v.11.06 -{ - int px, py, ww, hh; - - if (Factivearea && sa_Npixel < 200000) // if relatively small area, - { // process in main() thread v.11.06 - flatten_distribution(); - - for (py = sa_miny; py < sa_maxy; py++) - for (px = sa_minx; px < sa_maxx; px++) - flatten_pixel(px,py); - - px = sa_minx; // direct window update - py = sa_miny; - ww = sa_maxx - sa_minx; - hh = sa_maxy - sa_miny; - mwpaint3(px,py,ww,hh); // speedup v.11.06 - CEF->Fmod = 1; - } - - else signal_thread(); // use thread process - return; -} - - -// thread function - use multiple working threads - -void * flatten_thread(void *) -{ - void * flatten_wthread(void *arg); - - while (true) - { - thread_idle_loop(); // wait for work or exit request - - flatten_distribution(); - - for (int ii = 0; ii < Nwt; ii++) // start worker threads - start_wthread(flatten_wthread,&wtnx[ii]); - wait_wthreads(); // wait for completion - - CEF->Fmod = 1; - mwpaint2(); // update window - } - - return 0; // not executed, stop g++ warning -} - - -void * flatten_wthread(void *arg) // worker thread function -{ - int index = *((int *) (arg)); - int px, py; - - for (py = index; py < E1hh; py += Nwt) // flatten brightness distribution - for (px = 0; px < E1ww; px++) - flatten_pixel(px,py); - - exit_wthread(); - return 0; // not executed, avoid gcc warning -} - - -// compute brightness distribution for image or selected area - -void flatten_distribution() -{ - int px, py, ii, npix; - int ww = E1ww, hh = E1hh; - double bright1; - uint16 *pix1; - - for (ii = 0; ii < 65536; ii++) // clear brightness distribution data - flatten_brdist[ii] = 0; - - if (Factivearea) // process selected area - { - for (ii = npix = 0; ii < ww * hh; ii++) - { - if (! sa_pixmap[ii]) continue; - py = ii / ww; - px = ii - py * ww; - pix1 = PXMpix(E1pxm16,px,py); - bright1 = pixbright(pix1); - flatten_brdist[int(bright1)]++; - npix++; - } - - for (ii = 1; ii < 65536; ii++) // cumulative brightness distribution - flatten_brdist[ii] += flatten_brdist[ii-1]; // 0 ... npix - - for (ii = 0; ii < 65536; ii++) - flatten_brdist[ii] = flatten_brdist[ii] // multiplier per brightness level - / npix * 65536.0 / (ii + 1); - } - - else // process whole image - { - for (py = 0; py < hh; py++) // compute brightness distribution - for (px = 0; px < ww; px++) - { - pix1 = PXMpix(E1pxm16,px,py); - bright1 = pixbright(pix1); - flatten_brdist[int(bright1)]++; - } - - for (ii = 1; ii < 65536; ii++) // cumulative brightness distribution - flatten_brdist[ii] += flatten_brdist[ii-1]; // 0 ... (ww * hh) - - for (ii = 0; ii < 65536; ii++) - flatten_brdist[ii] = flatten_brdist[ii] // multiplier per brightness level - / (ww * hh) * 65536.0 / (ii + 1); - } - - return; -} - - -// compute new brightness for one pixel - -void flatten_pixel(int px, int py) -{ - int ii, dist = 0; - uint16 *pix1, *pix3; - double fold, fnew, dold, dnew, cmax; - double red1, green1, blue1, red3, green3, blue3; - double bright1, bright2; - - if (Factivearea) { // select area active - ii = py * Fww + px; - dist = sa_pixmap[ii]; // distance from edge - if (! dist) return; // outside pixel - } - - pix1 = PXMpix(E1pxm16,px,py); // input pixel - pix3 = PXMpix(E3pxm16,px,py); // output pixel - - fnew = 0.01 * flatten_value; // 0.0 - 1.0 how much to flatten - fold = 1.0 - fnew; // 1.0 - 0.0 how much to retain - - red1 = pix1[0]; - green1 = pix1[1]; - blue1 = pix1[2]; - - bright1 = 0.25 * red1 + 0.65 * green1 + 0.10 * blue1; // input brightness - bright2 = flatten_brdist[int(bright1)]; // output brightness adjustment - - red3 = bright2 * red1; // flattened brightness - green3 = bright2 * green1; - blue3 = bright2 * blue1; - - red3 = fnew * red3 + fold * red1; // blend new and old brightness - green3 = fnew * green3 + fold * green1; - blue3 = fnew * blue3 + fold * blue1; - - if (Factivearea && dist < sa_blend) { // select area is active, - dnew = 1.0 * dist / sa_blend; // blend changes over sa_blend - dold = 1.0 - dnew; - red3 = dnew * red3 + dold * red1; - green3 = dnew * green3 + dold * green1; - blue3 = dnew * blue3 + dold * blue1; - } - - cmax = red3; // stop overflow, keep color balance - if (green3 > cmax) cmax = green3; - if (blue3 > cmax) cmax = blue3; - if (cmax > 65535) { - cmax = 65535 / cmax; - red3 = red3 * cmax; - green3 = green3 * cmax; - blue3 = blue3 * cmax; - } - - pix3[0] = red3; - pix3[1] = green3; - pix3[2] = blue3; - - return; -} - - -/**************************************************************************/ - -// ramp brightness across image, vertical and horizontal gradients - -editfunc EFbrramp; -int brramp_spc; // current spline curves (2 at a time) - -void m_brightramp(GtkWidget *, cchar *) // upgrade for 4 colors v.11.07 -{ - int brramp_dialog_event(zdialog* zd, cchar *event); - void brramp_curvedit(int spc); - void * brramp_thread(void *); - void brramp_init(); - - zfuncs::F1_help_topic = "brightness_ramp"; - - EFbrramp.funcname = "bright-ramp"; - EFbrramp.Fprev = 1; // use preview - EFbrramp.Farea = 2; // select area usable - EFbrramp.Fpara = 1; // parallel edit OK - EFbrramp.threadfunc = brramp_thread; - if (! edit_setup(EFbrramp)) return; // setup edit - -/*** - _________________________________________ - | | - | | - | curve edit area | - | | - | | - |_________________________________________| - - (o) all (o) red (o) green (o) blue // colors: all, red, green, blue - Curve File: [Open] [Save] // each has vert. and horiz. curve - [Done] [Cancel] - -***/ - - zdialog *zd = zdialog_new(ZTX("Ramp brightness across image"),mWin,Bdone,Bcancel,null); - EFbrramp.zd = zd; - - zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=5|expand"); - zdialog_add_widget(zd,"vbox","vb1","hb1"); - zdialog_add_widget(zd,"vbox","vb2","hb1",0,"expand"); - zdialog_add_widget(zd,"label","lmax","vb1","+","space=3"); - zdialog_add_widget(zd,"label","lspace","vb1",0,"expand"); - zdialog_add_widget(zd,"label","lmin","vb1","‒","space=3"); - zdialog_add_widget(zd,"label","lspace","vb1"); - zdialog_add_widget(zd,"frame","frame","vb2",0,"expand"); - - zdialog_add_widget(zd,"hbox","hb2","vb2"); - zdialog_add_widget(zd,"label","lmin","hb2","‒","space=3"); - zdialog_add_widget(zd,"label","lspace","hb2",0,"expand"); - zdialog_add_widget(zd,"label","lmax","hb2","+","space=3"); - zdialog_add_widget(zd,"hbox","hbrgb","dialog",0,"space=3"); - zdialog_add_widget(zd,"radio","all","hbrgb",Ball,"space=5"); - zdialog_add_widget(zd,"radio","red","hbrgb",Bred,"space=5"); - zdialog_add_widget(zd,"radio","green","hbrgb",Bgreen,"space=5"); - zdialog_add_widget(zd,"radio","blue","hbrgb",Bblue,"space=5"); - zdialog_add_widget(zd,"hbox","hbcf","dialog",0,"space=3"); - zdialog_add_widget(zd,"label","labcf","hbcf",Bcurvefile,"space=8"); - zdialog_add_widget(zd,"button","load","hbcf",Bopen,"space=5"); - zdialog_add_widget(zd,"button","save","hbcf",Bsave,"space=5"); - - GtkWidget *frame = zdialog_widget(zd,"frame"); - spldat *sd = splcurve_init(frame,brramp_curvedit); // v.11.01 - EFbrramp.curves = sd; - - brramp_init(); // set up initial flat curves - - sd->Nspc = 2; // only curves 0-1 are shown - brramp_spc = 2; // current curves: all (2-3) - - zdialog_stuff(zd,"all",1); // stuff default selection, all - - zdialog_resize(zd,260,350); - zdialog_help(zd,"brightness_ramp"); // zdialog help topic v.11.08 - zdialog_run(zd,brramp_dialog_event,"save"); // run dialog - parallel v.11.07 - return; -} - - -// initialize all curves to flat - -void brramp_init() -{ - spldat *sd = EFbrramp.curves; - - for (int ii = 0; ii < 10; ii++) // loop curves: current (0-1), all (2-3), - { // red (4-5), green (6-7), blue (8-9) - sd->nap[ii] = 2; // horizontal curve ii - sd->vert[ii] = 0; - sd->apx[ii][0] = 0.01; - sd->apx[ii][1] = 0.99; - sd->apy[ii][0] = sd->apy[ii][1] = 0.5; - splcurve_generate(sd,ii); - - ii++; - sd->nap[ii] = 2; // vertical curve ii+1 - sd->vert[ii] = 1; - sd->apx[ii][0] = 0.01; - sd->apx[ii][1] = 0.99; - sd->apy[ii][0] = sd->apy[ii][1] = 0.5; - splcurve_generate(sd,ii); - } - - return; -} - - -// dialog event and completion callback function - -int brramp_dialog_event(zdialog *zd, cchar *event) -{ - spldat *sd = EFbrramp.curves; - int ii, jj, nn, Fupdate = 0; - spldat sdtemp; - - if (zd->zstat) // dialog complete - { - if (zd->zstat == 1) edit_done(EFbrramp); - else edit_cancel(EFbrramp); - return 1; - } - - edit_takeover(EFbrramp); // set my edit function - - if (strEqu(event,"reset")) { // reset dialog controls v.11.08 - brramp_init(); - Fupdate++; - } - - if (strEqu(event,"blendwidth")) signal_thread(); - - if (strstr("all red green blue",event)) { // new choice of curve - zdialog_fetch(zd,event,ii); - if (! ii) return 0; // ignore button OFF events - - ii = strcmpv(event,"all","red","green","blue",null); - brramp_spc = ii = 2 * ii; // 2, 4, 6, 8 - - sd->nap[0] = sd->nap[ii]; // copy active curves ii/ii+1 to curves 0/1 - sd->nap[1] = sd->nap[ii+1]; - for (jj = 0; jj < sd->nap[0]; jj++) { - sd->apx[0][jj] = sd->apx[ii][jj]; - sd->apy[0][jj] = sd->apy[ii][jj]; - } - for (jj = 0; jj < sd->nap[1]; jj++) { - sd->apx[1][jj] = sd->apx[ii+1][jj]; - sd->apy[1][jj] = sd->apy[ii+1][jj]; - } - - Fupdate++; - } - - if (strEqu(event,"load")) // load 8 saved curves from file - { - sdtemp.Nspc = 8; - sdtemp.drawarea = 0; - nn = splcurve_load(&sdtemp); - if (nn != 1) return 0; - - for (ii = 0; ii < 8; ii++) { // load curves 0-7 to curves 2-9 - sd->vert[ii+2] = sdtemp.vert[ii]; - sd->nap[ii+2] = sdtemp.nap[ii]; - for (jj = 0; jj < sdtemp.nap[ii]; jj++) { - sd->apx[ii+2][jj] = sdtemp.apx[ii][jj]; - sd->apy[ii+2][jj] = sdtemp.apy[ii][jj]; - } - splcurve_generate(sd,ii+2); - } - - ii = brramp_spc; // current active curves: 2, 4, 6, 8 - - sd->nap[0] = sd->nap[ii]; // copy 2 active curves to curves 0-1 - for (jj = 0; jj < sd->nap[0]; jj++) { - sd->apx[0][jj] = sd->apx[ii][jj]; - sd->apy[0][jj] = sd->apy[ii][jj]; - } - - sd->nap[1] = sd->nap[ii+1]; - for (jj = 0; jj < sd->nap[1]; jj++) { - sd->apx[1][jj] = sd->apx[ii+1][jj]; - sd->apy[1][jj] = sd->apy[ii+1][jj]; - } - - Fupdate++; - } - - if (strEqu(event,"save")) // save 8 curves to file - { - sdtemp.Nspc = 8; - for (ii = 0; ii < 8; ii++) { - sdtemp.vert[ii] = sd->vert[ii+2]; - sdtemp.nap[ii] = sd->nap[ii+2]; - for (jj = 0; jj < sd->nap[ii+2]; jj++) { - sdtemp.apx[ii][jj] = sd->apx[ii+2][jj]; - sdtemp.apy[ii][jj] = sd->apy[ii+2][jj]; - } - } - - splcurve_save(&sdtemp); - } - - if (Fupdate) // curve has changed - { - splcurve_generate(sd,0); // regenerate curves 0-1 - splcurve_generate(sd,1); - - ii = brramp_spc; // active curves - - sd->nap[ii] = sd->nap[0]; // copy curves 0-1 to active curves - for (jj = 0; jj < sd->nap[0]; jj++) { - sd->apx[ii][jj] = sd->apx[0][jj]; - sd->apy[ii][jj] = sd->apy[0][jj]; - } - - sd->nap[ii+1] = sd->nap[1]; - for (jj = 0; jj < sd->nap[1]; jj++) { - sd->apx[ii+1][jj] = sd->apx[1][jj]; - sd->apy[ii+1][jj] = sd->apy[1][jj]; - } - - for (jj = 0; jj < 1000; jj++) - { - sd->yval[ii][jj] = sd->yval[0][jj]; - sd->yval[ii+1][jj] = sd->yval[1][jj]; - } - - splcurve_draw(0,0,sd); // draw curves - - signal_thread(); // trigger image update - } - - return 1; -} - - -// this function is called when a curve is edited - -void brramp_curvedit(int spc) -{ - int ii = brramp_spc, jj; - spldat *sd = EFbrramp.curves; // active curves: 2, 4, 6, 8 (and +1) - - edit_takeover(EFbrramp); // set my edit function - - sd->nap[ii] = sd->nap[0]; // copy curves 0-1 to active curves - for (jj = 0; jj < sd->nap[0]; jj++) { - sd->apx[ii][jj] = sd->apx[0][jj]; - sd->apy[ii][jj] = sd->apy[0][jj]; - } - - sd->nap[ii+1] = sd->nap[1]; - for (jj = 0; jj < sd->nap[1]; jj++) { - sd->apx[ii+1][jj] = sd->apx[1][jj]; - sd->apy[ii+1][jj] = sd->apy[1][jj]; - } - - for (jj = 0; jj < 1000; jj++) { - sd->yval[ii][jj] = sd->yval[0][jj]; - sd->yval[ii+1][jj] = sd->yval[1][jj]; - } - - if (brramp_spc == 2) { // "all" curve was edited - for (ii = 4; ii < 10; ii += 2) { // fix R/G/B curves to match - sd->nap[ii] = sd->nap[2]; - for (jj = 0; jj < sd->nap[2]; jj++) { - sd->apx[ii][jj] = sd->apx[2][jj]; - sd->apy[ii][jj] = sd->apy[2][jj]; - } - for (jj = 0; jj < 1000; jj++) - sd->yval[ii][jj] = sd->yval[2][jj]; - } - for (ii = 5; ii < 10; ii += 2) { - sd->nap[ii] = sd->nap[3]; - for (jj = 0; jj < sd->nap[3]; jj++) { - sd->apx[ii][jj] = sd->apx[3][jj]; - sd->apy[ii][jj] = sd->apy[3][jj]; - } - for (jj = 0; jj < 1000; jj++) - sd->yval[ii][jj] = sd->yval[3][jj]; - } - } - - signal_thread(); - return; -} - - -// brramp thread function - -void * brramp_thread(void *arg) -{ - void * brramp_wthread(void *); - - while (true) - { - thread_idle_loop(); // wait for work or exit request - - for (int ii = 0; ii < Nwt; ii++) // start worker threads - start_wthread(brramp_wthread,&wtnx[ii]); - wait_wthreads(); // wait for completion - - mwpaint2(); // update window - CEF->Fmod = 1; // image3 modified - } - - return 0; // not executed, stop g++ warning -} - - -void * brramp_wthread(void *arg) // worker thread function -{ - int index = *((int *) arg); - int ii, jj, kk, dist = 0, px3, py3; - uint16 *pix1, *pix3; - double red1, green1, blue1, maxrgb; - double red3, green3, blue3; - double dispx, dispy; - double hramp[3], vramp[3], tramp[3]; - double spanw, spanh, dold, dnew; - spldat *sd = EFbrramp.curves; - - if (Factivearea) { // if select area active, ramp - spanw = sa_maxx - sa_minx; // brightness over enclosing rectangle - spanh = sa_maxy - sa_miny; - } - else { - spanw = E3ww; // else over entire image - spanh = E3hh; - } - - for (py3 = index; py3 < E3hh; py3 += Nwt) // loop output pixels - for (px3 = 0; px3 < E3ww; px3++) - { - if (Factivearea) { // select area active v.10.1 - ii = py3 * E3ww + px3; - dist = sa_pixmap[ii]; // distance from edge - if (! dist) continue; // pixel outside area - dispx = (px3 - sa_minx) / spanw; - dispy = (py3 - sa_miny) / spanh; - } - else { - dispx = px3 / spanw; // left > right = 0 to 1 - dispy = py3 / spanh; // top > bottom = 0 to 1 - } - - kk = 1000 * dispx; // conv. dispx 0-1 to 0-1000 - if (kk > 999) kk = 999; - - for (ii = 0, jj = 4; ii < 3; ii++, jj+=2) // horz. curves for dispx and R/G/B - hramp[ii] = sd->yval[jj][kk] - 0.5; // scale to -0.5 to +0.5 - - kk = 1000 * dispy; // conv. dispy - if (kk > 999) kk = 999; - - for (ii = 0, jj = 5; ii < 3; ii++, jj+=2) // vert. curves - vramp[ii] = sd->yval[jj][kk] - 0.5; - - for (ii = 0; ii < 3; ii++) // total R/G/B change - tramp[ii] = 1.0 + hramp[ii] + vramp[ii]; // scale to 0.0 to 2.0 - - pix1 = PXMpix(E1pxm16,px3,py3); // input pixel - red1 = pix1[0]; - green1 = pix1[1]; - blue1 = pix1[2]; - - red3 = red1 * tramp[0]; // change R/G/B - green3 = green1 * tramp[1]; - blue3 = blue1 * tramp[2]; - - maxrgb = red3; - if (green3 > maxrgb) maxrgb = green3; - if (blue3 > maxrgb) maxrgb = blue3; - - if (maxrgb > 65535) { // stop overflow - red3 = red3 * 65535 / maxrgb; - green3 = green3 * 65535 / maxrgb; - blue3 = blue3 * 65535 / maxrgb; - } - - if (Factivearea && dist < sa_blend) { // blend changes over blendwidth v.10.1 - dnew = 1.0 * dist / sa_blend; - dold = 1.0 - dnew; - red3 = dnew * red3 + dold * red1; - green3 = dnew * green3 + dold * green1; - blue3 = dnew * blue3 + dold * blue1; - } - - pix3 = PXMpix(E3pxm16,px3,py3); // output pixel - pix3[0] = red3; - pix3[1] = green3; - pix3[2] = blue3; - } - - exit_wthread(); - return 0; // not executed, avoid gcc warning -} - - -/************************************************************************** - - Image Tone Mapping function - enhance local contrast as opposed to overall contrast - - methodology: - get brightness gradients for each pixel in 4 directions: SE SW NE NW - amplify gradients using the edit curve (x-axis range 0-max. gradient) - integrate 4 new brightness surfaces from the amplified gradients: - - pixel brightness = prior pixel brightness + amplified gradient - - the Amplify control varies amplification from zero to overamplified - new pixel brightness = average from 4 calculated brightness surfaces - -***************************************************************************/ - -float *Tmap_brmap1; -float *Tmap_brmap3[4]; -int Tmap_contrast99; -double Tmap_amplify; - -editfunc EFtonemap; - - -void m_tonemap(GtkWidget *, cchar *) // new v.9.8 -{ - int Tmap_dialog_event(zdialog *zd, cchar *event); - void Tmap_curvedit(int); - void * Tmap_thread(void *); - - zfuncs::F1_help_topic = "tone_mapping"; // v.10.8 - - int ii, cc, px, py; - uint16 *pix1; - cchar *title = ZTX("Tone Mapping"); - int jj, sum, limit, condist[100]; - - EFtonemap.funcname = "tonemap"; - EFtonemap.Farea = 2; // select area usable - EFtonemap.Fpara = 1; // parallel edit OK - EFtonemap.threadfunc = Tmap_thread; - if (! edit_setup(EFtonemap)) return; // setup: no preview, select area OK - -/*** - _____________________________ - | | - | | - | curve drawing area | - | | - |_____________________________| - low contrast high - - Amplify ========[]========= - - Curve File: [ Open ] [ Save ] -***/ - - zdialog *zd = zdialog_new(title,mWin,Bdone,Bcancel,null); - EFtonemap.zd = zd; - - zdialog_add_widget(zd,"frame","frame","dialog",0,"expand"); - zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=5"); - zdialog_add_widget(zd,"label","labcL","hb1",ZTX("low"),"space=4"); - zdialog_add_widget(zd,"label","labcM","hb1",ZTX("contrast"),"expand"); - zdialog_add_widget(zd,"label","labcH","hb1",ZTX("high"),"space=5"); - - zdialog_add_widget(zd,"hbox","hb2","dialog",0,"space=5"); - zdialog_add_widget(zd,"label","labcon","hb2",ZTX("Amplify"),"space=5"); - zdialog_add_widget(zd,"hscale","amplify","hb2","0|1|0.01|0","expand"); - zdialog_add_widget(zd,"label","ampval","hb2",0,"space=5"); - - zdialog_add_widget(zd,"hbox","hbcf","dialog",0,"space=8"); - zdialog_add_widget(zd,"label","labcf","hbcf",Bcurvefile,"space=5"); - zdialog_add_widget(zd,"button","load","hbcf",Bopen,"space=5"); - zdialog_add_widget(zd,"button","save","hbcf",Bsave,"space=5"); - - GtkWidget *frame = zdialog_widget(zd,"frame"); // set up curve edit - spldat *sd = splcurve_init(frame,Tmap_curvedit); // v.11.01 - EFtonemap.curves = sd; - - sd->Nspc = 1; - sd->vert[0] = 0; - sd->nap[0] = 3; // initial curve anchor points - sd->apx[0][0] = 0.01; - sd->apy[0][0] = 0.2; - sd->apx[0][1] = 0.50; - sd->apy[0][1] = 0.4; - sd->apx[0][2] = 0.99; - sd->apy[0][2] = 0.0; - - splcurve_generate(sd,0); // generate curve data - - cc = Fww * Fhh * sizeof(float); // allocate brightness map memory - Tmap_brmap1 = (float *) zmalloc(cc,"tonemap"); - for (ii = 0; ii < 4; ii++) - Tmap_brmap3[ii] = (float *) zmalloc(cc,"tonemap"); - - for (py = 0; py < Fhh; py++) // map initial image brightness - for (px = 0; px < Fww; px++) - { - ii = py * Fww + px; - pix1 = PXMpix(E1pxm16,px,py); - Tmap_brmap1[ii] = pixbright(pix1); - } - - for (ii = 0; ii < 100; ii++) - condist[ii] = 0; - - for (py = 1; py < Fhh; py++) // map contrast distribution - for (px = 1; px < Fww; px++) - { - ii = py * Fww + px; - jj = 0.00152 * fabsf(Tmap_brmap1[ii] - Tmap_brmap1[ii-1]); // contrast, ranged 0 - 99 - condist[jj]++; - jj = 0.00152 * fabsf(Tmap_brmap1[ii] - Tmap_brmap1[ii-Fww]); - condist[jj]++; - } - - sum = 0; - limit = 0.99 * 2 * (Fww-1) * (Fhh-1); // find 99th percentile contrast - - for (ii = 0; ii < 100; ii++) { - sum += condist[ii]; - if (sum > limit) break; - } - - Tmap_contrast99 = 65535.0 * ii / 100.0; // 0 to 65535 - if (Tmap_contrast99 < 1000) Tmap_contrast99 = 1000; // rescale low-contrast image v.10.9 - - zdialog_resize(zd,300,300); - zdialog_help(zd,"tone_mapping"); // zdialog help topic v.11.08 - zdialog_run(zd,Tmap_dialog_event,"save"); // run dialog - parallel v.11.07 - - Tmap_amplify = 0; - return; -} - - -// dialog event and completion callback function - -int Tmap_dialog_event(zdialog *zd, cchar *event) -{ - spldat *sd = EFtonemap.curves; - char text[8]; - - if (zd->zstat) // dialog complete - { - if (zd->zstat == 1) edit_done(EFtonemap); - else edit_cancel(EFtonemap); - zfree(Tmap_brmap1); // free memory - for (int ii = 0; ii < 4; ii++) - zfree(Tmap_brmap3[ii]); - return 1; - } - - edit_takeover(EFtonemap); // set my edit function - - if (strEqu(event,"reset")) // reset dialog controls v.11.08 - zdialog_stuff(zd,"amplify",0); - - if (strEqu(event,"blendwidth")) signal_thread(); // v.10.3 - - if (strEqu(event,"amplify")) { // slider value - zdialog_fetch(zd,"amplify",Tmap_amplify); - sprintf(text,"%.2f",Tmap_amplify); // numeric feedback v.11.07 - zdialog_stuff(zd,"ampval",text); - signal_thread(); // trigger update thread - } - - if (strEqu(event,"load")) { // load saved curve v.11.02 - splcurve_load(sd); - signal_thread(); - return 0; - } - - if (strEqu(event,"save")) { // save curve to file v.11.02 - splcurve_save(sd); - return 0; - } - - return 0; -} - - -// this function is called when the curve is edited - -void Tmap_curvedit(int) -{ - edit_takeover(EFtonemap); // set my edit function - signal_thread(); - return; -} - - -// thread function - -void * Tmap_thread(void *) -{ - void * Tmap_wthread1(void *arg); - void * Tmap_wthread2(void *arg); - - int ii; - - while (true) - { - thread_idle_loop(); // wait for work or exit request - - for (ii = 0; ii < 4; ii++) // start working threads1 (must be 4) - start_wthread(Tmap_wthread1,&wtnx[ii]); - wait_wthreads(); // wait for completion - - for (ii = 0; ii < Nwt; ii++) // start working threads2 - start_wthread(Tmap_wthread2,&wtnx[ii]); - wait_wthreads(); // wait for completion - - CEF->Fmod = 1; - mwpaint2(); - } - - return 0; // not executed, stop g++ warning -} - - -// working threads - -void * Tmap_wthread1(void *arg) // hardened v.9.9 -{ - int ii, kk, bii, pii, dist = 0; - int px, px1, px2, pxinc; - int py, py1, py2, pyinc; - float b1, b3, xval, yval, grad; - float amplify, contrast99; - spldat *sd = EFtonemap.curves; - - contrast99 = Tmap_contrast99; // 99th percentile contrast - contrast99 = 1.0 / contrast99; // inverted - - amplify = pow(Tmap_amplify,0.2); // get amplification, 0 to 1 v.11.02 - - bii = *((int *) arg); - - if (bii == 0) { // direction SE - px1 = 1; px2 = E3ww; pxinc = 1; - py1 = 1; py2 = E3hh; pyinc = 1; - pii = - 1 - E3ww; - } - - else if (bii == 1) { // direction SW - px1 = E3ww-2; px2 = 0; pxinc = -1; - py1 = 1; py2 = E3hh; pyinc = 1; - pii = + 1 - E3ww; - } - - else if (bii == 2) { // direction NE - px1 = 1; px2 = E3ww; pxinc = 1; - py1 = E3hh-2; py2 = 0; pyinc = -1; - pii = - 1 + E3ww; - } - - else { /* bii == 3 */ // direction NW - px1 = E3ww-2; px2 = 0; pxinc = -1; - py1 = E3hh-2; py2 = 0; pyinc = -1; - pii = + 1 + E3ww; - } - - for (ii = 0; ii < E3ww * E3hh; ii++) // initial brightness map - Tmap_brmap3[bii][ii] = Tmap_brmap1[ii]; - - for (py = py1; py != py2; py += pyinc) // loop all image pixels - for (px = px1; px != px2; px += pxinc) - { - ii = py * E3ww + px; - - if (Factivearea) { // select area active - dist = sa_pixmap[ii]; // distance from edge - if (! dist) continue; // outside pixel - } - - b1 = Tmap_brmap1[ii]; // this pixel brightness - grad = b1 - Tmap_brmap1[ii+pii]; // - prior pixel --> gradient - - xval = fabsf(grad) * contrast99; // gradient scaled 0 to 1+ - kk = 1000.0 * xval; - if (kk > 999) kk = 999; // speedup v.11.06 - yval = 1.0 + 5.0 * sd->yval[0][kk]; - - grad = grad * yval; // magnified gradient - - b3 = Tmap_brmap3[bii][ii+pii] + grad; // pixel brightness = prior + gradient - b3 = (1.0 - amplify) * b1 + amplify * b3; // constrain: push b3 toward b1 v.11.02 - - if (b3 > 65535) b3 = 65535; // constrain - if (b3 < 10) b3 = 10; - - Tmap_brmap3[bii][ii] = b3; // new pixel brightness - } - - exit_wthread(); - return 0; // not executed, avoid gcc warning -} - - -void * Tmap_wthread2(void *arg) // speedup v.10.2 -{ - uint16 *pix1, *pix3; - int index, ii, px, py, dist = 0; - float b1, b3, bf, f1, f2; - float red1, green1, blue1, red3, green3, blue3; - - index = *((int *) arg); - - for (py = index; py < E3hh; py += Nwt) // loop all image pixels - for (px = 0; px < E3ww; px++) - { - ii = py * E3ww + px; - - if (Factivearea) { // select area active bugfix v.9.9 - dist = sa_pixmap[ii]; // distance from edge - if (! dist) continue; // pixel is outside area - } - - pix1 = PXMpix(E1pxm16,px,py); // input pixel - pix3 = PXMpix(E3pxm16,px,py); // output pixel - - b1 = Tmap_brmap1[ii]; // initial pixel brightness - b3 = Tmap_brmap3[0][ii] + Tmap_brmap3[1][ii] // new brightness = average of four - + Tmap_brmap3[2][ii] + Tmap_brmap3[3][ii]; // calculated brightness surfaces - - bf = 0.25 * b3 / (b1 + 1); // brightness ratio - - red1 = pix1[0]; // input RGB - green1 = pix1[1]; - blue1 = pix1[2]; - - red3 = bf * red1; // output RGB - if (red3 > 65535) red3 = 65535; - green3 = bf * green1; - if (green3 > 65535) green3 = 65535; - blue3 = bf * blue1; - if (blue3 > 65535) blue3 = 65535; - - if (Factivearea && dist < sa_blend) { // select area is active, - f1 = 1.0 * dist / sa_blend; // blend changes over sa_blend - f2 = 1.0 - f1; - red3 = f1 * red3 + f2 * red1; - green3 = f1 * green3 + f2 * green1; - blue3 = f1 * blue3 + f2 * blue1; - } - - pix3[0] = red3; - pix3[1] = green3; - pix3[2] = blue3; - } - - exit_wthread(); - return 0; // not executed, stop g++ warning -} - - -/**************************************************************************/ - -// adjust white balance - -void whitebal_mousefunc(); - -double whitebal_red, whitebal_green, whitebal_blue; -editfunc EFwhitebal; - -void m_whitebal(GtkWidget *, cchar *) -{ - int whitebal_dialog_event(zdialog *zd, cchar *event); - void * whitebal_thread(void *); - - cchar *wbtitle = ZTX("Adjust White Balance"); - cchar *wbhelp = ZTX("Click white or gray image location"); - - zfuncs::F1_help_topic = "white_balance"; // v.10.8 - - EFwhitebal.funcname = "white-balance"; - EFwhitebal.Fprev = 1; // use preview - EFwhitebal.Farea = 2; // select area usable - EFwhitebal.Fpara = 1; // parallel edits OK - EFwhitebal.threadfunc = whitebal_thread; // thread function - EFwhitebal.mousefunc = whitebal_mousefunc; // mouse function - if (! edit_setup(EFwhitebal)) return; // setup edit: preview - - zdialog *zd = zdialog_new(wbtitle,mWin,Bdone,Bcancel,null); - EFwhitebal.zd = zd; - - zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=10"); - zdialog_add_widget(zd,"label","labwbh","hb1",wbhelp,"space=5"); - zdialog_add_widget(zd,"hbox","hb2","dialog",0,"space=5"); - zdialog_add_widget(zd,"label","labpix","hb2","pixel:"); - zdialog_add_widget(zd,"label","pixel","hb2","0000 0000"); - zdialog_add_widget(zd,"label","labrgb","hb2"," RGB:"); - zdialog_add_widget(zd,"label","rgb","hb2","000 000 000"); - zdialog_add_widget(zd,"check","mymouse","dialog",BmyMouse); - - zdialog_help(zd,"white_balance"); // zdialog help topic v.11.08 - zdialog_run(zd,whitebal_dialog_event,"save"); // run dialog - parallel v.11.07 - - whitebal_red = whitebal_green = whitebal_blue = 1.0; - - takeMouse(zd,whitebal_mousefunc,dragcursor); // connect mouse function v.11.03 - return; -} - - -// dialog event and completion callback function - -int whitebal_dialog_event(zdialog *zd, cchar *event) // dialog event function v.10.2 -{ - int mymouse; - - if (zd->zstat) - { - if (zd->zstat == 1) edit_done(EFwhitebal); // done - else edit_cancel(EFwhitebal); // cancel or destroy - return 0; - } - - edit_takeover(EFwhitebal); // set my edit function - - if (strEqu(event,"mymouse")) { // toggle mouse capture v.10.12 - zdialog_fetch(zd,"mymouse",mymouse); - if (mymouse) takeMouse(zd,whitebal_mousefunc,dragcursor); // connect mouse function - else freeMouse(); // disconnect mouse - } - - if (strEqu(event,"blendwidth")) signal_thread(); // v.10.3 - return 1; -} - - -void whitebal_mousefunc() // mouse function -{ - int px, py, dx, dy; - double red, green, blue, rgbmean; - char work[40]; - uint16 *ppix16; - zdialog *zd = EFwhitebal.zd; - - if (! LMclick) return; - - edit_takeover(EFwhitebal); // set my edit function - - LMclick = 0; - px = Mxclick; // mouse click position - py = Myclick; - - if (px < 2) px = 2; // pull back from edge - if (px > E3ww-3) px = E3ww-3; - if (py < 2) py = 2; - if (py > E3hh-3) py = E3hh-3; - - red = green = blue = 0; - - for (dy = -2; dy <= 2; dy++) // 5x5 block around mouse position - for (dx = -2; dx <= 2; dx++) - { - ppix16 = PXMpix(E1pxm16,px+dx,py+dy); // input image - red += ppix16[0]; - green += ppix16[1]; - blue += ppix16[2]; - } - - red = red / 25.0; // mean RGB levels - green = green / 25.0; - blue = blue / 25.0; - rgbmean = (red + green + blue) / 3.0; - - whitebal_red = rgbmean / red; - whitebal_green = rgbmean / green; - whitebal_blue = rgbmean / blue; - - signal_thread(); // trigger image update - - snprintf(work,40,"%d %d",px,py); - zdialog_stuff(zd,"pixel",work); - - snprintf(work,40,"%7.3f %7.3f %7.3f",red/256,green/256,blue/256); - zdialog_stuff(zd,"rgb",work); - - return; -} - - -// Update image based on neutral pixel that was clicked - -void * whitebal_thread(void *) -{ - void * whitebal_wthread(void *arg); - - while (true) - { - thread_idle_loop(); // wait for work or exit request - - for (int ii = 0; ii < Nwt; ii++) // start worker threads - start_wthread(whitebal_wthread,&wtnx[ii]); - wait_wthreads(); // wait for completion - - CEF->Fmod = 1; - mwpaint2(); // update window - } - - return 0; // not executed, stop g++ warning -} - - -void * whitebal_wthread(void *arg) // worker thread function -{ - int index = *((int *) arg); - int px, py, ii, dist = 0; - uint16 *pix1, *pix3; - double red1, green1, blue1; - double red3, green3, blue3; - double brmax, dold, dnew; - - for (py = index; py < E1hh; py += Nwt) - for (px = 0; px < E1ww; px++) - { - if (Factivearea) { // select area active - ii = py * Fww + px; - dist = sa_pixmap[ii]; // distance from edge - if (! dist) continue; // pixel outside area - } - - pix1 = PXMpix(E1pxm16,px,py); // input pixel - pix3 = PXMpix(E3pxm16,px,py); // output pixel - - red1 = pix1[0]; - green1 = pix1[1]; - blue1 = pix1[2]; - - red3 = whitebal_red * red1; // change color ratios - green3 = whitebal_green * green1; - blue3 = whitebal_blue * blue1; - - if (Factivearea && dist < sa_blend) { // select area is active, - dnew = 1.0 * dist / sa_blend; // blend changes over sa_blend - dold = 1.0 - dnew; - red3 = dnew * red3 + dold * red1; - green3 = dnew * green3 + dold * green1; - blue3 = dnew * blue3 + dold * blue1; - } - - brmax = red3; // brmax = brightest color - if (green3 > brmax) brmax = green3; - if (blue3 > brmax) brmax = blue3; - - if (brmax > 65535) { // if overflow, reduce - brmax = 65535 / brmax; - red3 = red3 * brmax; - green3 = green3 * brmax; - blue3 = blue3 * brmax; - } - - pix3[0] = red3; - pix3[1] = green3; - pix3[2] = blue3; - } - - exit_wthread(); - return 0; // not executed, stop gcc warning -} - - -/**************************************************************************/ - -// match_color edit function -// Adjust colors of image 2 to match the colors of image 1 -// using small selected areas in each image as the match standard. - -void * match_color_thread(void *); -void match_color_mousefunc(); - -int match_color_RGB1[3]; // image 1 base colors to match -int match_color_RGB2[3]; // image 2 target colors to match -int match_color_radius = 10; // mouse radius -int match_color_mode = 0; - -editfunc EFmatchcolor; - - -void m_match_color(GtkWidget *, const char *) // new v.11.07 -{ - int match_color_dialog_event(zdialog* zd, const char *event); - - cchar *title = ZTX("Color Match Images"); - - zfuncs::F1_help_topic = "match_colors"; - - if (is_syncbusy()) return; // must wait for file sync v.11.11 - if (! menulock(1)) return; // test menu lock - menulock(0); - -/* - Color Match Images - 1 [ 10 ] mouse radius for color sample - 2 [Open] image for source color - 3 click on image to get source color - 4 [Open] image for target color - 5 click on image to set target color - [done] [cancel] -*/ - - zdialog *zd = zdialog_new(title,mWin,Bdone,Bcancel,null); // match_color dialog - zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=2"); - zdialog_add_widget(zd,"vbox","vb1","hb1",0,"homog|space=3"); - zdialog_add_widget(zd,"vbox","vb2","hb1",0,"homog|space=3"); - zdialog_add_widget(zd,"label","labn1","vb1","1"); - zdialog_add_widget(zd,"label","labn2","vb1","2"); - zdialog_add_widget(zd,"label","labn3","vb1","3"); - zdialog_add_widget(zd,"label","labn4","vb1","4"); - zdialog_add_widget(zd,"label","labn5","vb1","5"); - zdialog_add_widget(zd,"hbox","hbrad","vb2"); - zdialog_add_widget(zd,"spin","radius","hbrad","1|20|1|10","space=5"); - zdialog_add_widget(zd,"label","labrad","hbrad",ZTX("mouse radius for color sample")); - zdialog_add_widget(zd,"hbox","hbop1","vb2"); - zdialog_add_widget(zd,"button","open1","hbop1",ZTX("Open"),"space=5"); - zdialog_add_widget(zd,"label","labop1","hbop1",ZTX("image for source color")); - zdialog_add_widget(zd,"hbox","hbclik1","vb2"); - zdialog_add_widget(zd,"label","labclik1","hbclik1",ZTX("click on image to get source color")); - zdialog_add_widget(zd,"hbox","hbop2","vb2"); - zdialog_add_widget(zd,"button","open2","hbop2",ZTX("Open"),"space=5"); - zdialog_add_widget(zd,"label","labop2","hbop2",ZTX("image to set matching color")); - zdialog_add_widget(zd,"hbox","hbclik2","vb2"); - zdialog_add_widget(zd,"label","labclik2","hbclik2",ZTX("click on image to set matching color")); - - zdialog_stuff(zd,"radius",match_color_radius); // remember last radius - zdialog_help(zd,"match_colors"); // zdialog help topic v.11.08 - zdialog_run(zd,match_color_dialog_event); // run dialog - parallel - - EFmatchcolor.funcname = "match-color"; - EFmatchcolor.Farea = 1; // select area ignored - EFmatchcolor.threadfunc = match_color_thread; - EFmatchcolor.mousefunc = match_color_mousefunc; - - match_color_mode = 0; - if (curr_file) { - match_color_mode = 1; // image 1 ready to click - takeMouse(zd,match_color_mousefunc,0); // connect mouse function - } - - return; -} - - -// match_color dialog event and completion function - -int match_color_dialog_event(zdialog *zd, const char *event) // match_color dialog event function -{ - int err; - - if (zd->zstat) // end dialog - { - if (match_color_mode == 4) { // edit was started - if (zd->zstat == 1) edit_done(EFmatchcolor); - else edit_cancel(EFmatchcolor); - } - freeMouse(); - zdialog_free(zd); - match_color_mode = 0; - return 1; - } - - if (match_color_mode == 4) // if prior edit, cancel it - edit_cancel(EFmatchcolor); - - if (strEqu(event,"radius")) // set new mouse radius - zdialog_fetch(zd,"radius",match_color_radius); - - if (strEqu(event,"open1")) // get image 1 for color source - { - match_color_mode = 0; - err = f_open(null,0,0); - if (! err) match_color_mode = 1; // image 1 ready to click - } - - if (strEqu(event,"open2")) // get image 2 to set matching color - { - if (match_color_mode < 2) { - zmessageACK(mWin,ZTX("select source image color first")); // check that RGB1 has been set - return 1; - } - match_color_mode = 2; - err = f_open(null,0,0); - if (err) return 1; - match_color_mode = 3; // image 2 ready to click - } - - takeMouse(zd,match_color_mousefunc,0); // reconnect mouse function - return 1; -} - - -// mouse function - click on image and get colors to match - -void match_color_mousefunc() -{ - void match_color_getRGB(int px, int py, int RGB[3]); - - int px, py; - zdialog *zd = EFmatchcolor.zd; - - if (match_color_mode < 1) return; // no image available yet - - toparcx = Mxposn - match_color_radius; // mouse outline circle - toparcy = Myposn - match_color_radius; - toparcw = toparch = 2 * match_color_radius; - Ftoparc = 1; - paint_toparc(3); - - if (LMclick) - { - LMclick = 0; - px = Mxclick; - py = Myclick; - - if (match_color_mode == 1 || match_color_mode == 2) // image 1 ready to click - { - match_color_getRGB(px,py,match_color_RGB1); // get RGB1 color - match_color_mode = 2; - return; - } - - if (match_color_mode == 3 || match_color_mode == 4) // image 2 ready to click - { - match_color_getRGB(px,py,match_color_RGB2); // get RGB2 color - - if (match_color_mode == 4) { - edit_cancel(EFmatchcolor); // if prior edit, cancel it - takeMouse(zd,match_color_mousefunc,0); // reconnect mouse function - match_color_mode = 3; - } - - if (! edit_setup(EFmatchcolor)) return; // setup edit - thread will launch - match_color_mode = 4; // edit waiting for cancel or done - signal_thread(); // update the target image - return; - } - } - - return; -} - - -// get the RGB averages for pixels within mouse radius - -void match_color_getRGB(int px, int py, int RGB[3]) -{ - int rad1 = match_color_radius; - int rad2 = rad1 * rad1; - int rad, npix, qx, qy; - int red, green, blue; - uint16 *pix1; - PXM *pxm; - - pxm = f_load(curr_file,16); - if (! pxm) return; - - npix = 0; - red = green = blue = 0; - - for (qy = py-rad1; qy <= py+rad1; qy++) - for (qx = px-rad1; qx <= px+rad1; qx++) - { - if (qx < 0 || qx > Fww-1) continue; - if (qy < 0 || qy > Fhh-1) continue; - rad = (qx-px) * (qx-px) + (qy-py) * (qy-py); - if (rad > rad2) continue; - pix1 = PXMpix(pxm,qx,qy); - red += pix1[0]; - green += pix1[1]; - blue += pix1[2]; - npix++; - } - - RGB[0] = red / npix; - RGB[1] = green / npix; - RGB[2] = blue / npix; - - PXM_free(pxm); - return; -} - - -// thread function - start multiple working threads - -void * match_color_thread(void *) -{ - void * match_color_wthread(void *arg); // worker thread - - while (true) - { - thread_idle_loop(); // wait for work or exit request - - for (int ii = 0; ii < Nwt; ii++) // start worker threads - start_wthread(match_color_wthread,&wtnx[ii]); - wait_wthreads(); // wait for completion - - CEF->Fmod = 1; - mwpaint2(); // update window - } - - return 0; // not executed, avoid warning -} - - -void * match_color_wthread(void *arg) // worker thread function -{ - int index = *((int *) (arg)); - int px, py; - uint16 *pix3; - double Rred, Rgreen, Rblue; - double red, green, blue, cmax; - - Rred = 1.0 * match_color_RGB1[0] / match_color_RGB2[0]; // color adjustment ratios - Rgreen = 1.0 * match_color_RGB1[1] / match_color_RGB2[1]; - Rblue = 1.0 * match_color_RGB1[2] / match_color_RGB2[2]; - - for (py = index; py < E3hh; py += Nwt) // loop all image pixels - for (px = 0; px < E3ww; px++) - { - pix3 = PXMpix(E3pxm16,px,py); - - red = pix3[0] * Rred; // adjust colors - green = pix3[1] * Rgreen; - blue = pix3[2] * Rblue; - - cmax = red; // check for overflow - if (green > cmax) cmax = green; - if (blue > cmax) cmax = blue; - - if (cmax > 65535) { // fix overflow - red = red * 65535 / cmax; - green = green * 65535 / cmax; - blue = blue * 65535 / cmax; - } - - pix3[0] = red; - pix3[1] = green; - pix3[2] = blue; - } - - exit_wthread(); - return 0; // not executed, avoid gcc warning -} - - -/**************************************************************************/ - -// DRGB menu function -// Adjust Density (Brightness) and RGB levels using 0.01 OD units - -editfunc EFdrgb; // edit function data -double DRGBinputs[8]; -int DRGBbias = 0; - -void m_DRGB(GtkWidget *, const char *) // new v.11.08 -{ - int DRGB_dialog_event(zdialog *zd, cchar *event); - void * DRGB_thread(void *); - - zfuncs::F1_help_topic = "DRGB"; - - EFdrgb.funcname = "DRGB"; // function name - EFdrgb.Fprev = 1; // use preview - EFdrgb.Farea = 2; // select area usable - EFdrgb.Fpara = 1; // parallel edit OK - EFdrgb.threadfunc = DRGB_thread; // thread function - if (! edit_setup(EFdrgb)) return; // setup edit - -/*** - ________________________________________________ - | | - | [reset] [x] Add standard bias | - | +Brightness -Density [__|v] Contrast [__|v] | - | +Red -Cyan [__|v] Red [__|v] | - | +Green -Magneta [__|v] Green [__|v] | - | +Blue -Yellow [__|v] Blue [__|x] | - |________________________________________________| - -***/ - - zdialog *zd = zdialog_new("DRGB",mWin,Bdone,Bcancel,null); // new dialog - zdialog_help(zd,"DRGB"); // add help topic to zdialog - EFdrgb.zd = zd; // add dialog to edit function - - zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=5"); - zdialog_add_widget(zd,"button","reset","hb1",Breset,"space=10"); - zdialog_add_widget(zd,"check","bias","hb1","Add standard bias","space=5"); - zdialog_add_widget(zd,"hbox","hb2","dialog"); - zdialog_add_widget(zd,"vbox","vb1","hb2",0,"homog|space=5"); - zdialog_add_widget(zd,"vbox","vb2","hb2",0,"homog|space=5"); - zdialog_add_widget(zd,"label","space","hb2",0,"space=8"); - zdialog_add_widget(zd,"vbox","vb3","hb2",0,"homog|space=5"); - zdialog_add_widget(zd,"vbox","vb4","hb2",0,"homog|space=5"); - zdialog_add_widget(zd,"button","buBriteDens","vb1","+Brightness -Density"); - zdialog_add_widget(zd,"button","buRedDens","vb1","+Red -Cyan"); - zdialog_add_widget(zd,"button","buGreenDens","vb1","+Green -Magneta"); - zdialog_add_widget(zd,"button","buBlueDens","vb1","+Blue -Yellow"); - zdialog_add_widget(zd,"spin","spBriteDens","vb2","-99|+99|1|0"); - zdialog_add_widget(zd,"spin","spRedDens","vb2","-99|+99|1|0"); - zdialog_add_widget(zd,"spin","spGreenDens","vb2","-99|+99|1|0"); - zdialog_add_widget(zd,"spin","spBlueDens","vb2","-99|+99|1|0"); - zdialog_add_widget(zd,"button","buContrast","vb3","Contrast"); - zdialog_add_widget(zd,"button","buRedCon","vb3","Red"); - zdialog_add_widget(zd,"button","buGreenCon","vb3","Green"); - zdialog_add_widget(zd,"button","buBlueCon","vb3","Blue"); - zdialog_add_widget(zd,"spin","spContrast","vb4","-99|+99|1|0"); - zdialog_add_widget(zd,"spin","spRedCon","vb4","-99|+99|1|0"); - zdialog_add_widget(zd,"spin","spGreenCon","vb4","-99|+99|1|0"); - zdialog_add_widget(zd,"spin","spBlueCon","vb4","-99|+99|1|0"); - - zdialog_run(zd,DRGB_dialog_event,"save"); // run dialog - parallel - return; -} - - -// DRGB dialog event and completion function - -int DRGB_dialog_event(zdialog *zd, cchar *event) // DRGB dialog event function -{ - int bias; - - if (zd->zstat) - { - if (zd->zstat == 1) edit_done(EFdrgb); // done - else edit_cancel(EFdrgb); // cancel or destroy - return 0; - } - - edit_takeover(EFdrgb); // set parallel edit function - - if (strEqu(event,"bias")) // bias was changed - { - zdialog_fetch(zd,"bias",bias); - if (bias != DRGBbias) - { - if (bias) { // off to on - DRGBinputs[0] += 72; - DRGBinputs[2] += 32; - DRGBinputs[3] += 32; - zdialog_set_limits(zd,"spBriteDens",-27,+171); - zdialog_set_limits(zd,"spGreenDens",-67,+131); - zdialog_set_limits(zd,"spBlueDens",-67,+131); - } - else { // on to off - DRGBinputs[0] -= 72; - DRGBinputs[2] -= 32; - DRGBinputs[3] -= 32; - zdialog_set_limits(zd,"spBriteDens",-99,+99); - zdialog_set_limits(zd,"spGreenDens",-99,+99); - zdialog_set_limits(zd,"spBlueDens",-99,+99); - } - zdialog_stuff(zd,"spBriteDens",DRGBinputs[0]); - zdialog_stuff(zd,"spGreenDens",DRGBinputs[2]); - zdialog_stuff(zd,"spBlueDens",DRGBinputs[3]); - } - DRGBbias = bias; - return 1; - } - - if (strEqu(event,"reset")) // reset dialog controls - { - DRGBinputs[0] = DRGBbias * 72; - DRGBinputs[1] = DRGBbias * 0; - DRGBinputs[2] = DRGBbias * 32; - DRGBinputs[3] = DRGBbias * 32; - DRGBinputs[4] = 0; - DRGBinputs[5] = 0; - DRGBinputs[6] = 0; - DRGBinputs[7] = 0; - zdialog_stuff(zd,"spBriteDens",DRGBinputs[0]); - zdialog_stuff(zd,"spRedDens",DRGBinputs[1]); - zdialog_stuff(zd,"spGreenDens",DRGBinputs[2]); - zdialog_stuff(zd,"spBlueDens",DRGBinputs[3]); - zdialog_stuff(zd,"spContrast",DRGBinputs[4]); - zdialog_stuff(zd,"spRedCon",DRGBinputs[5]); - zdialog_stuff(zd,"spGreenCon",DRGBinputs[6]); - zdialog_stuff(zd,"spBlueCon",DRGBinputs[7]); - } - - if (strEqu(event,"buBriteDens")) { - DRGBinputs[0] = DRGBbias * 72; - zdialog_stuff(zd,"spBriteDens",DRGBinputs[0]); - } - - if (strEqu(event,"buRedDens")) { - DRGBinputs[1] = 0; - zdialog_stuff(zd,"spRedDens",DRGBinputs[1]); - } - - if (strEqu(event,"buGreenDens")) { - DRGBinputs[2] = DRGBbias * 32; - zdialog_stuff(zd,"spGreenDens",DRGBinputs[2]); - } - - if (strEqu(event,"buBlueDens")) { - DRGBinputs[3] = DRGBbias * 32; - zdialog_stuff(zd,"spBlueDens",DRGBinputs[3]); - } - - if (strEqu(event,"buContrast")) { - DRGBinputs[4] = 0; - zdialog_stuff(zd,"spContrast",0); - } - - if (strEqu(event,"buRedCon")) { - DRGBinputs[5] = 0; - zdialog_stuff(zd,"spRedCon",0); - } - - if (strEqu(event,"buGreenCon")) { - DRGBinputs[6] = 0; - zdialog_stuff(zd,"spGreenCon",0); - } - - if (strEqu(event,"buBlueCon")) { - DRGBinputs[7] = 0; - zdialog_stuff(zd,"spBlueCon",0); - } - - zdialog_fetch(zd,"spBriteDens",DRGBinputs[0]); // get all inputs - zdialog_fetch(zd,"spRedDens",DRGBinputs[1]); - zdialog_fetch(zd,"spGreenDens",DRGBinputs[2]); - zdialog_fetch(zd,"spBlueDens",DRGBinputs[3]); - zdialog_fetch(zd,"spContrast",DRGBinputs[4]); - zdialog_fetch(zd,"spRedCon",DRGBinputs[5]); - zdialog_fetch(zd,"spGreenCon",DRGBinputs[6]); - zdialog_fetch(zd,"spBlueCon",DRGBinputs[7]); - - signal_thread(); // trigger update thread - wait_thread_idle(); // wait until done (optional) - return 1; -} - - -// thread function - multiple working threads to update image - -void * DRGB_thread(void *) -{ - void * DRGB_wthread(void *arg); // worker thread - - while (true) - { - thread_idle_loop(); // wait for work or exit request - - if (Factivearea) SB_goal = sa_Npixel; // set up progress monitor - else SB_goal = E3ww * E3hh; - SB_done = 0; - - for (int ii = 0; ii < Nwt; ii++) // start worker threads - start_wthread(DRGB_wthread,&wtnx[ii]); - wait_wthreads(); // wait for completion - - SB_goal = SB_done = 0; - CEF->Fmod = 1; // image modified - mwpaint2(); // update window - } - - return 0; // not executed, stop warning -} - - -void * DRGB_wthread(void *arg) // worker thread function -{ - double Du, Ru, Gu, Bu, Rd, Gd, Bd; - double con, conR, conG, conB; - double R1, G1, B1, R3, G3, B3; - - int index = *((int *) (arg)); - int px, py, ii, dist = 0; - uint16 *pix1, *pix3; - double cmax, F, f1, f2; - double c1 = 100.0 / 65536.0; - double c2 = 2.0 + log10(1.0/c1); - double c3 = 1.0 / 65536.0; - - #define ODfunc(rgb) (2.0 - log10(c1 * rgb)) // RGB units (1-65536) to OD units - #define RGBfunc(od) (pow(10,(c2 - od))) // OD units to RGB units - - Du = -0.01 * DRGBinputs[0]; // convert inputs from cc to OD units - Ru = -0.01 * DRGBinputs[1]; // range is -0.99 to +0.99 - Gu = -0.01 * DRGBinputs[2]; - Bu = -0.01 * DRGBinputs[3]; - - if (DRGBbias) { // remove bias - Du += 0.72; - Gu += 0.32; - Bu += 0.32; - } - - con = -0.01 * DRGBinputs[4]; - conR = -0.01 * DRGBinputs[5]; - conG = -0.01 * DRGBinputs[6]; - conB = -0.01 * DRGBinputs[7]; - - for (py = index; py < E3hh; py += Nwt) // loop all image pixels - for (px = 0; px < E3ww; px++) - { - if (Factivearea) { // select area active - ii = py * E3ww + px; - dist = sa_pixmap[ii]; // distance from edge - if (! dist) continue; // outside area - } - - pix1 = PXMpix(E1pxm16,px,py); // input pixel - pix3 = PXMpix(E3pxm16,px,py); // output pixel - - R1 = pix1[0] + 1; // input RGB values, 0-65535 - G1 = pix1[1] + 1; // (avoid 0) - B1 = pix1[2] + 1; - - Rd = ODfunc(R1); // convert to OD units - Gd = ODfunc(G1); - Bd = ODfunc(B1); - - Rd += Du + Ru; // add user OD increments - Gd += Du + Gu; - Bd += Du + Bu; - - if (con) { // overall contrast - Rd += con * c3 * (R1-32768); - Gd += con * c3 * (G1-32768); - Bd += con * c3 * (B1-32768); - } - - if (conR) // single color contrast - Rd += conR * c3 * (R1-32768); - if (conG) - Gd += conG * c3 * (G1-32768); - if (conB) - Bd += conB * c3 * (B1-32768); - - R3 = RGBfunc(Rd); // convert back to RGB units - G3 = RGBfunc(Gd); - B3 = RGBfunc(Bd); - - if (R3 < 0) R3 = 0; // stop underflow - if (G3 < 0) G3 = 0; - if (B3 < 0) B3 = 0; - - if (R3 > 65535 || G3 > 65535 || B3 > 65535) { // stop overflow - cmax = R3; - if (G3 > cmax) cmax = G3; - if (B3 > cmax) cmax = B3; - F = 65535 / cmax; - R3 *= F; - G3 *= F; - B3 *= F; - } - - if (Factivearea && dist < sa_blend) { // select area is active, - f1 = 1.0 * dist / sa_blend; // blend changes over sa_blend - f2 = 1.0 - f1; - R3 = f1 * R3 + f2 * R1; - G3 = f1 * G3 + f2 * G1; - B3 = f1 * B3 + f2 * B1; - } - - pix3[0] = R3; // output RGB values - pix3[1] = G3; - pix3[2] = B3; - } - - exit_wthread(); - return 0; // not executed, avoid gcc warning -} - - -/**************************************************************************/ - -// Show RGB values for 1-9 pixels selected with mouse-clicks. -// Revise RGB values for the selected points and then revise all other -// pixels to match, using a distance-weighted average of the selected pixels. - -void RGBR_dialog(); -void RGBR_mousefunc(); -void RGBR_stuff(); -void * RGBR_thread(void *); - -zdialog *RGBRzd; -int RGBRpixel[9][2]; // last 9 pixel locations clicked -double RGBRval1[9][3]; // original RGB values, 0 to 255.9 -double RGBRval3[9][3]; // revised RGB values, 0 to 255.9 -int RGBRmetric = 1; // 1/2/3 = /RGB/EV/OD -int RGBRdelta = 0; // flag, delta mode -int RGBRrestart; // flag, restart dialog -int RGBRnpix; // no. of selected pixels -double RGBRtime; // last click time -int RGBRblend; // blend factor, 10 to 1000 -editfunc EFrgbrevise; // edit function parameters - -#define RGB2EV(rgb) (log2(rgb)-7) // RGB 0.1 to 255.9 >> EV -10 to +1 -#define EV2RGB(ev) (pow(2,ev+7)) // inverse -#define RGB2OD(rgb) (2-log10(100*rgb/256)) // RGB 0.1 to 255.9 >> OD 3.4 to 0.000017 -#define OD2RGB(od) (pow(10,2.40824-od)) // inverse - - -void m_revise_RGB(GtkWidget *, cchar *menu) // new v.11.07 -{ - int RGBR_event(zdialog *zd, cchar *event); - - GtkWidget *widget; - cchar *limits; - zdialog *zd; - cchar *mess = ZTX("Click image to select pixels."); - - PangoFontDescription *widgetfont; - widgetfont = pango_font_description_from_string("Monospace 8"); // small monospace font for widgets - - zfuncs::F1_help_topic = "revise_RGB"; - - EFrgbrevise.funcname = "revise_RGB"; // setup edit function - EFrgbrevise.threadfunc = RGBR_thread; - EFrgbrevise.mousefunc = RGBR_mousefunc; - EFrgbrevise.Farea = 1; - if (! edit_setup(EFrgbrevise)) return; - - RGBRblend = 20; // default slider value - RGBRnpix = 0; // no pixels selected yet - -/*** - - Click image to select pixels. - [x] my mouse [x] delta - Metric: (o) RGB (o) EV (o) OD - Pixel Red Green Blue - A xxxx xxxx [xxxx|v] [xxxx|v] [xxxx|v] // spin buttons for RGB/EV/OD values - B xxxx xxxx [xxxx|v] [xxxx|v] [xxxx|v] - C xxxx xxxx [xxxx|v] [xxxx|v] [xxxx|v] - D xxxx xxxx [xxxx|v] [xxxx|v] [xxxx|v] - E xxxx xxxx [xxxx|v] [xxxx|v] [xxxx|v] - F xxxx xxxx [xxxx|v] [xxxx|v] [xxxx|v] - G xxxx xxxx [xxxx|v] [xxxx|v] [xxxx|v] - H xxxx xxxx [xxxx|v] [xxxx|v] [xxxx|v] - I xxxx xxxx [xxxx|v] [xxxx|v] [xxxx|v] - Blend ==============[]================ - - [reset] [done] [cancel] -***/ - -restart: - - zd = zdialog_new(ZTX("Revise RGB"),mWin,Breset,Bdone,Bcancel,null); - EFrgbrevise.zd = zd; - RGBRzd = zd; - - zdialog_add_widget(zd,"hbox","hbmess","dialog",0,"space=3"); - zdialog_add_widget(zd,"label","labmess","hbmess",mess,"space=5"); - - zdialog_add_widget(zd,"hbox","hbmym","dialog"); - zdialog_add_widget(zd,"check","mymouse","hbmym",BmyMouse,"space=5"); - zdialog_add_widget(zd,"check","delta","hbmym","delta","space=10"); - zdialog_stuff(zd,"mymouse",1); - zdialog_stuff(zd,"delta",RGBRdelta); - - zdialog_add_widget(zd,"hbox","hbmetr","dialog",0,"space=3"); - zdialog_add_widget(zd,"label","labmetr","hbmetr",ZTX("Metric:"),"space=5"); - zdialog_add_widget(zd,"radio","radRGB","hbmetr","RGB","space=3"); - zdialog_add_widget(zd,"radio","radEV","hbmetr","EV","space=3"); - zdialog_add_widget(zd,"radio","radOD","hbmetr","OD","space=3"); - - if (RGBRmetric == 1) zdialog_stuff(zd,"radRGB",1); // set current metric - if (RGBRmetric == 2) zdialog_stuff(zd,"radEV",1); - if (RGBRmetric == 3) zdialog_stuff(zd,"radOD",1); - - zdialog_add_widget(zd,"hbox","hbdata","dialog"); - zdialog_add_widget(zd,"vbox","vbpix","hbdata",0,"space=3|homog"); // vbox for pixel locations - zdialog_add_widget(zd,"hbox","hbpix","vbpix"); - zdialog_add_widget(zd,"label","labpix","hbpix","Pixel"); // header - - char hbpixx[8] = "hbpixx", pixx[8] = "pixx"; - - for (int ii = 1; ii < 10; ii++) { // add labels for pixel locations - hbpixx[5] = '0' + ii; - pixx[3] = '0' + ii; - zdialog_add_widget(zd,"hbox",hbpixx,"vbpix"); // add hbox "hbpix1" to "hbpix9" - zdialog_add_widget(zd,"label",pixx,hbpixx); // add label "pix1" to "pix9" - widget = zdialog_widget(zd,pixx); - gtk_widget_modify_font(widget,widgetfont); // use monofont - } - - if (RGBRmetric == 1) limits = "-255.9|255.9|0.1|0.0"; // metric = RGB - else if (RGBRmetric == 2) limits = "-8|8|0.01|0.0"; // EV - else limits = "-3|3|0.002|0.0"; // OD - - zdialog_add_widget(zd,"vbox","vbdat","hbdata",0,"space=3|homog"); // vbox for pixel RGB values - zdialog_add_widget(zd,"hbox","hbrgb","vbdat",0,"homog"); - zdialog_add_widget(zd,"label","labr","hbrgb",Bred); // v.11.08 - zdialog_add_widget(zd,"label","labg","hbrgb",Bgreen); - zdialog_add_widget(zd,"label","labb","hbrgb",Bblue); - - char hbdatx[8] = "hbdatx", redx[8] = "redx", greenx[8] = "greenx", bluex[8] = "bluex"; - - for (int ii = 1; ii < 10; ii++) { - hbdatx[5] = '0' + ii; - redx[3] = '0' + ii; - greenx[5] = '0' + ii; - bluex[4] = '0' + ii; - zdialog_add_widget(zd,"hbox",hbdatx,"vbdat"); // add hbox "hbdat1" to "hbdat9" - zdialog_add_widget(zd,"spin",redx,hbdatx,limits,"space=3"); // add spin buttons for "red1" to "red9" etc. - zdialog_add_widget(zd,"spin",greenx,hbdatx,limits,"space=3"); - zdialog_add_widget(zd,"spin",bluex,hbdatx,limits,"space=3"); - widget = zdialog_widget(zd,redx); - gtk_widget_modify_font(widget,widgetfont); // use monofont - widget = zdialog_widget(zd,greenx); - gtk_widget_modify_font(widget,widgetfont); - widget = zdialog_widget(zd,bluex); - gtk_widget_modify_font(widget,widgetfont); - } - - zdialog_add_widget(zd,"hbox","hbsoft","dialog","space=5"); - zdialog_add_widget(zd,"label","labsoft","hbsoft",ZTX("Blend"),"space=3"); - zdialog_add_widget(zd,"hscale","blend","hbsoft","0|100|1|20","space=5|expand"); - zdialog_add_widget(zd,"label","softval","hbsoft","20"); - - RGBR_stuff(); // stuff current pixels (if restart) - - takeMouse(zd,RGBR_mousefunc,dragcursor); // connect mouse function - zdialog_help(zd,"revise_RGB"); // zdialog help topic v.11.08 - zdialog_run(zd,RGBR_event,"save"); // run dialog - zdialog_wait(zd); // wait for completion - if (RGBRrestart) goto restart; // restart dialog - - return; -} - - -// dialog event function - -int RGBR_event(zdialog *zd, cchar *event) -{ - int mymouse, button; - int ii, jj; - char text[8]; - double val1, val3; - - if (zd->zstat) - { - if (zd->zstat == 1) { // Reset - zd->zstat = 0; // keep dialog active - RGBRnpix = 0; // no pixels selected yet - RGBR_stuff(); // clear dialog - edit_reset(); // reset edits v.11.08 - return 0; - } - else if (zd->zstat == 2) // Done - edit_done(EFrgbrevise); - else edit_cancel(EFrgbrevise); // Cancel or [x] - freeMouse(); // disconnect mouse function - zdialog_free(zd); // kill dialog - RGBRzd = 0; - RGBRrestart = 0; - erase_toptext(101); // erase pixel labels from image - return 1; - } - - if (strEqu(event,"mymouse")) { // toggle mouse capture - zdialog_fetch(zd,"mymouse",mymouse); - if (mymouse) takeMouse(zd,RGBR_mousefunc,dragcursor); // connect mouse function - else freeMouse(); // disconnect mouse - return 1; - } - - if (strEqu(event,"blend")) { // new blend factor - zdialog_fetch(zd,"blend",RGBRblend); - sprintf(text,"%d",RGBRblend); // numeric feedback - zdialog_stuff(zd,"softval",text); - signal_thread(); - return 1; - } - - if (strnEqu(event,"rad",3)) // metric was changed - { - if (strEqu(event,"radRGB")) { // RGB - zdialog_fetch(zd,event,button); - if (button) RGBRmetric = 1; - } - - if (strEqu(event,"radEV")) { // EV - zdialog_fetch(zd,event,button); - if (button) RGBRmetric = 2; - } - - if (strEqu(event,"radOD")) { // OD - zdialog_fetch(zd,event,button); - if (button) RGBRmetric = 3; - } - - if (button) { - freeMouse(); // restart dialog with new limits - zdialog_free(zd); - RGBRzd = 0; - RGBRrestart = 1; - } - - return 1; - } - - if (strEqu(event,"delta")) { // change absolute/delta mode - zdialog_fetch(zd,"delta",RGBRdelta); - freeMouse(); // restart dialog with new limits - zdialog_free(zd); - RGBRzd = 0; - RGBRrestart = 1; - return 1; - } - - ii = -1; // no RGB change yet - - if (strnEqu(event,"red",3)) { // red1 - red9 was changed - ii = event[3] - '1'; // pixel index 0-8 - jj = 0; // color = red - } - - if (strnEqu(event,"green",5)) { // green1 - green9 - ii = event[5] - '1'; - jj = 1; - } - - if (strnEqu(event,"blue",4)) { // blue1 - blue9 - ii = event[4] - '1'; - jj = 2; - } - - if (ii >= 0 && ii < 9) // RGB value was revised - { -/* - static int ignore = 0; - - if (ignore) { - ignore = 0; - return 1; - } - - ignore = 1; -*/ - - val1 = RGBRval1[ii][jj]; // original pixel RGB value - if (RGBRmetric == 2) val1 = RGB2EV(val1); // convert to EV or OD units - if (RGBRmetric == 3) val1 = RGB2OD(val1); - - zdialog_fetch(zd,event,val3); // revised RGB/EV/OD value from dialog - if (RGBRdelta) val3 += val1; // if delta mode, make absolute - - if (RGBRmetric == 2) val3 = EV2RGB(val3); // convert EV/OD to RGB value - if (RGBRmetric == 3) val3 = OD2RGB(val3); - - if (fabs(RGBRval3[ii][jj] - val3) < 0.001) return 1; // ignore re-entry after change - - if (val3 < 0.1) val3 = 0.1; // limit RGB within 0.1 to 255.9 - if (val3 > 255.9) val3 = 255.9; - - RGBRval3[ii][jj] = val3; // new RGB value for pixel - - if (RGBRmetric == 2) val3 = RGB2EV(val3); // convert RGB to EV/OD units - if (RGBRmetric == 3) val3 = RGB2OD(val3); - - if (RGBRdelta) val3 -= val1; // absolute back to relative - zdialog_stuff(zd,event,val3); // limited value back to dialog - - signal_thread(); // signal thread to update image - } - - return 1; -} - - -// mouse function - -void RGBR_mousefunc() // mouse function -{ - int ii; - uint16 *pix3; - - if (! LMclick) return; - LMclick = RMclick = 0; - - RGBRtime = get_seconds(); // mark time of pixel click - - if (RGBRnpix == 9) { // if table is full (9 entries) v.11.08 - for (ii = 1; ii < 9; ii++) { // move positions 1-8 up - RGBRpixel[ii-1][0] = RGBRpixel[ii][0]; // to fill positions 0-7 - RGBRpixel[ii-1][1] = RGBRpixel[ii][1]; - } - RGBRnpix = 8; // count is now 8 entries - } - - ii = RGBRnpix; // next table position to fill - RGBRpixel[ii][0] = Mxclick; // newest pixel - RGBRpixel[ii][1] = Myclick; - - pix3 = PXMpix(E3pxm16,Mxclick,Myclick); // get initial RGB values from - RGBRval1[ii][0] = RGBRval3[ii][0] = pix3[0] / 256.0; // modified image E3 - RGBRval1[ii][1] = RGBRval3[ii][1] = pix3[1] / 256.0; - RGBRval1[ii][2] = RGBRval3[ii][2] = pix3[2] / 256.0; - - RGBRnpix++; // up pixel count - RGBR_stuff(); // stuff pixels and values into dialog - return; -} - - -// stuff dialog with current pixels and their RGB/EV/OD values - -void RGBR_stuff() -{ - static char lab1[9][4] = { "A", "B", "C", "D", "E", "F", "G", "H", "I" }; - static char lab2[9][4] = { " A ", " B ", " C ", " D ", " E ", " F ", " G ", " H ", " I " }; - - int px, py; - double red1, green1, blue1, red3, green3, blue3; - char text[100], pixx[8] = "pixx"; - char redx[8] = "redx", greenx[8] = "greenx", bluex[8] = "bluex"; - zdialog *zd = RGBRzd; - - erase_toptext(101); // erase prior labels from image - - for (int ii = 0; ii < 9; ii++) // loop slots 0-8 - { - pixx[3] = '1' + ii; // widget names "pix1" ... "pix9" - redx[3] = '1' + ii; // widget names "red1" ... "red9" - greenx[5] = '1' + ii; - bluex[4] = '1' + ii; - - px = RGBRpixel[ii][0]; // next pixel to report - py = RGBRpixel[ii][1]; - if (ii >= RGBRnpix) { // > last pixel selected - zdialog_stuff(zd,pixx,""); - zdialog_stuff(zd,redx,0); // blank pixel and zero values - zdialog_stuff(zd,greenx,0); - zdialog_stuff(zd,bluex,0); - continue; - } - - sprintf(text,"%s %4d %4d",lab1[ii],px,py); // format pixel "A nnnn nnnn" - zdialog_stuff(zd,pixx,text); // pixel >> widget - - add_toptext(101,px,py,lab2[ii],"Sans 8"); // paint label on image at pixel - - red1 = RGBRval1[ii][0]; // original RGB values for pixel - green1 = RGBRval1[ii][1]; - blue1 = RGBRval1[ii][2]; - red3 = RGBRval3[ii][0]; // revised RGB values - green3 = RGBRval3[ii][1]; - blue3 = RGBRval3[ii][2]; - - if (RGBRmetric == 2) { // convert to EV units if needed - red1 = RGB2EV(red1); - green1 = RGB2EV(green1); - blue1 = RGB2EV(blue1); - red3 = RGB2EV(red3); - green3 = RGB2EV(green3); - blue3 = RGB2EV(blue3); - } - - if (RGBRmetric == 3) { // or OD units - red1 = RGB2OD(red1); - green1 = RGB2OD(green1); - blue1 = RGB2OD(blue1); - red3 = RGB2OD(red3); - green3 = RGB2OD(green3); - blue3 = RGB2OD(blue3); - } - - if (RGBRdelta) { // dialog is delta mode - red3 -= red1; - green3 -= green1; - blue3 -= blue1; - } - - zdialog_stuff(zd,redx,red3); - zdialog_stuff(zd,greenx,green3); - zdialog_stuff(zd,bluex,blue3); - } - - mwpaint2(); // refresh window - return; -} - - -// thread function - multiple working threads to update image - -void * RGBR_thread(void *) -{ - void * RGBR_wthread(void *arg); // worker thread - - while (true) - { - thread_idle_loop(); // wait for work or exit request - zsleep(0.3); // more time for dialog controls - - if (RGBRnpix < 1) continue; // must have 1+ pixels in table - - for (int ii = 0; ii < Nwt; ii++) // start worker threads - start_wthread(RGBR_wthread,&wtnx[ii]); - wait_wthreads(); // wait for completion - - CEF->Fmod = 1; // image modified - mwpaint2(); // update window - } - - return 0; // not executed, stop warning -} - - -void * RGBR_wthread(void *arg) // worker thread function -{ - int index = *((int *) (arg)); - int px1, py1, px2, py2, ii; - uint16 *pix1, *pix3; - double dist[9], weight[9], sumdist; - double blend, delta, red, green, blue, max; - - blend = Fww; - if (Fhh > Fww) blend = Fhh; - blend = blend * blend; - blend = 0.0001 * RGBRblend * RGBRblend * blend + 100; // 100 to (image size)**2 v.11.08 - - for (py1 = index; py1 < E3hh; py1 += Nwt) // loop all image pixels - for (px1 = 0; px1 < E3ww; px1++) - { - for (sumdist = ii = 0; ii < RGBRnpix; ii++) // compute weight of each revision point - { - px2 = RGBRpixel[ii][0]; - py2 = RGBRpixel[ii][1]; - dist[ii] = (px1-px2)*(px1-px2) + (py1-py2)*(py1-py2); // distance (px1,py1) to (px2,py2) - dist[ii] = 1.0 / (dist[ii] + blend); // blend reduces peaks at revision points - sumdist += dist[ii]; // sum inverse distances - } - - for (ii = 0; ii < RGBRnpix; ii++) // weight of each point - weight[ii] = dist[ii] / sumdist; - - pix1 = PXMpix(E1pxm16,px1,py1); // input pixel - pix3 = PXMpix(E3pxm16,px1,py1); // output pixel - - red = pix1[0]; - green = pix1[1]; - blue = pix1[2]; - - for (ii = 0; ii < RGBRnpix; ii++) { // apply weighted color changes - delta = RGBRval3[ii][0] - RGBRval1[ii][0]; // to each color - red += weight[ii] * 256 * delta; - delta = RGBRval3[ii][1] - RGBRval1[ii][1]; - green += weight[ii] * 256 * delta; - delta = RGBRval3[ii][2] - RGBRval1[ii][2]; - blue += weight[ii] * 256 * delta; - } - - max = red; - if (green > max) max = green; - if (blue > max) max = blue; - - if (max > 65535) { // stop overflow/underflow - red = red * 65535 / max; - green = green * 65535 / max; - blue = blue * 65535 / max; - } - - if (red < 0) red = 0; - if (green < 0) green = 0; - if (blue < 0) blue = 0; - - pix3[0] = red; - pix3[1] = green; - pix3[2] = blue; - } - - exit_wthread(); - return 0; // not executed, avoid gcc warning -} - - -/**************************************************************************/ - -// red eye removal function - -struct sredmem { // red-eye struct in memory - char type, space[3]; - int cx, cy, ww, hh, rad, clicks; - double thresh, tstep; -}; -sredmem redmem[100]; // store up to 100 red-eyes - -int Nredmem = 0, maxredmem = 100; -void redeye_mousefunc(); - -editfunc EFredeye; - - -void m_redeye(GtkWidget *, cchar *) -{ - int redeye_dialog_event(zdialog *zd, cchar *event); - - cchar *redeye_message = ZTX( - "Method 1:\n" - " Left-click on red-eye to darken.\n" - "Method 2:\n" - " Drag down and right to enclose red-eye.\n" - " Left-click on red-eye to darken.\n" - "Undo red-eye:\n" - " Right-click on red-eye."); - - zfuncs::F1_help_topic = "red_eye"; // v.10.8 - - EFredeye.funcname = "redeye"; - EFredeye.Farea = 1; // select area ignored - EFredeye.mousefunc = redeye_mousefunc; - if (! edit_setup(EFredeye)) return; // setup edit - - zdialog *zd = zdialog_new(ZTX("Red Eye Reduction"),mWin,Bdone,Bcancel,null); - EFredeye.zd = zd; - - zdialog_add_widget(zd,"label","lab1","dialog",redeye_message); - zdialog_add_widget(zd,"check","mymouse","dialog",BmyMouse); - zdialog_help(zd,"red_eye"); // zdialog help topic v.11.08 - zdialog_run(zd,redeye_dialog_event,"save"); // run dialog - parallel v.11.07 - - Nredmem = 0; - zdialog_stuff(zd,"mymouse",1); // v.11.03 - takeMouse(zd,redeye_mousefunc,dragcursor); // connect mouse function v.11.03 - return; -} - - -// dialog event and completion callback function - -int redeye_dialog_event(zdialog *zd, cchar *event) -{ - int mymouse; - - if (zd->zstat) { - if (Nredmem > 0) CEF->Fmod = 1; - Ftoparc = ptoparc = 0; - if (zd->zstat == 1) edit_done(EFredeye); - else edit_cancel(EFredeye); - return 0; - } - - if (strEqu(event,"mymouse")) { // toggle mouse capture v.10.12 - zdialog_fetch(zd,"mymouse",mymouse); - if (mymouse) takeMouse(zd,redeye_mousefunc,dragcursor); // connect mouse function - else freeMouse(); // disconnect mouse - } - - return 0; -} - - -// mouse functions to define, darken, and undo red-eyes - -int redeye_createF(int px, int py); // create 1-click red-eye (type F) -int redeye_createR(int px, int py, int ww, int hh); // create robust red-eye (type R) -void redeye_darken(int ii); // darken red-eye -void redeye_distr(int ii); // build pixel redness distribution -int redeye_find(int px, int py); // find red-eye at mouse position -void redeye_remove(int ii); // remove red-eye at mouse position -int redeye_radlim(int cx, int cy); // compute red-eye radius limit - - -void redeye_mousefunc() -{ - int ii, px, py, ww, hh; - - if (Nredmem == maxredmem) { - zmessageACK(mWin,"%d red-eye limit reached",maxredmem); // too many red-eyes - return; - } - - if (LMclick) // left mouse click - { - LMclick = 0; - - px = Mxclick; // click position - py = Myclick; - if (px < 0 || px > E3ww-1 || py < 0 || py > E3hh-1) return; // outside image area - - ii = redeye_find(px,py); // find existing red-eye - if (ii < 0) ii = redeye_createF(px,py); // or create new type F - redeye_darken(ii); // darken red-eye - } - - if (RMclick) // right mouse click - { - RMclick = 0; - px = Mxclick; // click position - py = Myclick; - ii = redeye_find(px,py); // find red-eye - if (ii >= 0) redeye_remove(ii); // if found, remove - } - - if (Mxdrag || Mydrag) // mouse drag underway - { - px = Mxdown; // initial position - py = Mydown; - ww = Mxdrag - Mxdown; // increment - hh = Mydrag - Mydown; - if (ww < 2 && hh < 2) return; - if (ww < 2) ww = 2; - if (hh < 2) hh = 2; - if (px < 1) px = 1; // keep within image area - if (py < 1) py = 1; - if (px + ww > E3ww-1) ww = E3ww-1 - px; - if (py + hh > E3hh-1) hh = E3hh-1 - py; - ii = redeye_find(px,py); // find existing red-eye - if (ii >= 0) redeye_remove(ii); // remove it - ii = redeye_createR(px,py,ww,hh); // create new red-eye type R - } - - mwpaint2(); - return; -} - - -// create type F redeye (1-click automatic) - -int redeye_createF(int cx, int cy) -{ - int cx0, cy0, cx1, cy1, px, py, rad, radlim; - int loops, ii; - int Tnpix, Rnpix, R2npix; - double rd, rcx, rcy, redpart; - double Tsum, Rsum, R2sum, Tavg, Ravg, R2avg; - double sumx, sumy, sumr; - uint16 *ppix; - - cx0 = cx; - cy0 = cy; - - for (loops = 0; loops < 8; loops++) - { - cx1 = cx; - cy1 = cy; - - radlim = redeye_radlim(cx,cy); // radius limit (image edge) - Tsum = Tavg = Ravg = Tnpix = 0; - - for (rad = 0; rad < radlim-2; rad++) // find red-eye radius from (cx,cy) - { - Rsum = Rnpix = 0; - R2sum = R2npix = 0; - - for (py = cy-rad-2; py <= cy+rad+2; py++) - for (px = cx-rad-2; px <= cx+rad+2; px++) - { - rd = sqrt((px-cx)*(px-cx) + (py-cy)*(py-cy)); - ppix = PXMpix(E3pxm16,px,py); - redpart = pixred(ppix); - - if (rd <= rad + 0.5 && rd > rad - 0.5) { // accum. redness at rad - Rsum += redpart; - Rnpix++; - } - else if (rd <= rad + 2.5 && rd > rad + 1.5) { // accum. redness at rad+2 - R2sum += redpart; - R2npix++; - } - } - - Tsum += Rsum; - Tnpix += Rnpix; - Tavg = Tsum / Tnpix; // avg. redness over 0-rad - Ravg = Rsum / Rnpix; // avg. redness at rad - R2avg = R2sum / R2npix; // avg. redness at rad+2 - if (R2avg > Ravg || Ravg > Tavg) continue; - if ((Ravg - R2avg) < 0.2 * (Tavg - Ravg)) break; // 0.1 --> 0.2 - } - - sumx = sumy = sumr = 0; - rad = int(1.2 * rad + 1); - if (rad > radlim) rad = radlim; - - for (py = cy-rad; py <= cy+rad; py++) // compute center of gravity for - for (px = cx-rad; px <= cx+rad; px++) // pixels within rad of (cx,cy) - { - rd = sqrt((px-cx)*(px-cx) + (py-cy)*(py-cy)); - if (rd > rad + 0.5) continue; - ppix = PXMpix(E3pxm16,px,py); - redpart = pixred(ppix); // weight by redness - sumx += redpart * (px - cx); - sumy += redpart * (py - cy); - sumr += redpart; - } - - rcx = cx + 1.0 * sumx / sumr; // new center of red-eye - rcy = cy + 1.0 * sumy / sumr; - if (fabs(cx0 - rcx) > 0.6 * rad) break; // give up if big movement - if (fabs(cy0 - rcy) > 0.6 * rad) break; - cx = int(rcx + 0.5); - cy = int(rcy + 0.5); - if (cx == cx1 && cy == cy1) break; // done if no change - } - - radlim = redeye_radlim(cx,cy); - if (rad > radlim) rad = radlim; - - ii = Nredmem++; // add red-eye to memory - redmem[ii].type = 'F'; - redmem[ii].cx = cx; - redmem[ii].cy = cy; - redmem[ii].rad = rad; - redmem[ii].clicks = 0; - redmem[ii].thresh = 0; - return ii; -} - - -// create type R red-eye (drag an ellipse over red-eye area) - -int redeye_createR(int cx, int cy, int ww, int hh) -{ - int rad, radlim; - - Ftoparc = 1; // paint ellipse over image - toparcx = cx - ww; - toparcy = cy - hh; - toparcw = 2 * ww; - toparch = 2 * hh; - - if (ww > hh) rad = ww; - else rad = hh; - radlim = redeye_radlim(cx,cy); - if (rad > radlim) rad = radlim; - - int ii = Nredmem++; // add red-eye to memory - redmem[ii].type = 'R'; - redmem[ii].cx = cx; - redmem[ii].cy = cy; - redmem[ii].ww = 2 * ww; - redmem[ii].hh = 2 * hh; - redmem[ii].rad = rad; - redmem[ii].clicks = 0; - redmem[ii].thresh = 0; - return ii; -} - - -// darken a red-eye and increase click count - -void redeye_darken(int ii) -{ - int cx, cy, ww, hh, px, py, rad, clicks; - double rd, thresh, tstep; - char type; - uint16 *ppix; - - type = redmem[ii].type; - cx = redmem[ii].cx; - cy = redmem[ii].cy; - ww = redmem[ii].ww; - hh = redmem[ii].hh; - rad = redmem[ii].rad; - thresh = redmem[ii].thresh; - tstep = redmem[ii].tstep; - clicks = redmem[ii].clicks++; - - if (thresh == 0) // 1st click - { - redeye_distr(ii); // get pixel redness distribution - thresh = redmem[ii].thresh; // initial redness threshhold - tstep = redmem[ii].tstep; // redness step size - Ftoparc = 0; - } - - tstep = (thresh - tstep) / thresh; // convert to reduction factor - thresh = thresh * pow(tstep,clicks); // reduce threshhold by total clicks - - for (py = cy-rad; py <= cy+rad; py++) // darken pixels over threshhold - for (px = cx-rad; px <= cx+rad; px++) - { - if (type == 'R') { - if (px < cx - ww/2) continue; - if (px > cx + ww/2) continue; - if (py < cy - hh/2) continue; - if (py > cy + hh/2) continue; - } - rd = sqrt((px-cx)*(px-cx) + (py-cy)*(py-cy)); - if (rd > rad + 0.5) continue; - ppix = PXMpix(E3pxm16,px,py); // set redness = threshhold - if (pixred(ppix) > thresh) - ppix[0] = int(thresh * (0.65 * ppix[1] + 0.10 * ppix[2] + 1) / (25 - 0.25 * thresh)); - } - - return; -} - - -// Build a distribution of redness for a red-eye. Use this information -// to set initial threshhold and step size for stepwise darkening. - -void redeye_distr(int ii) -{ - int cx, cy, ww, hh, rad, px, py; - int bin, npix, dbins[20], bsum, blim; - double rd, maxred, minred, redpart, dbase, dstep; - char type; - uint16 *ppix; - - type = redmem[ii].type; - cx = redmem[ii].cx; - cy = redmem[ii].cy; - ww = redmem[ii].ww; - hh = redmem[ii].hh; - rad = redmem[ii].rad; - - maxred = 0; - minred = 100; - - for (py = cy-rad; py <= cy+rad; py++) - for (px = cx-rad; px <= cx+rad; px++) - { - if (type == 'R') { - if (px < cx - ww/2) continue; - if (px > cx + ww/2) continue; - if (py < cy - hh/2) continue; - if (py > cy + hh/2) continue; - } - rd = sqrt((px-cx)*(px-cx) + (py-cy)*(py-cy)); - if (rd > rad + 0.5) continue; - ppix = PXMpix(E3pxm16,px,py); - redpart = pixred(ppix); - if (redpart > maxred) maxred = redpart; - if (redpart < minred) minred = redpart; - } - - dbase = minred; - dstep = (maxred - minred) / 19.99; - - for (bin = 0; bin < 20; bin++) dbins[bin] = 0; - npix = 0; - - for (py = cy-rad; py <= cy+rad; py++) - for (px = cx-rad; px <= cx+rad; px++) - { - if (type == 'R') { - if (px < cx - ww/2) continue; - if (px > cx + ww/2) continue; - if (py < cy - hh/2) continue; - if (py > cy + hh/2) continue; - } - rd = sqrt((px-cx)*(px-cx) + (py-cy)*(py-cy)); - if (rd > rad + 0.5) continue; - ppix = PXMpix(E3pxm16,px,py); - redpart = pixred(ppix); - bin = int((redpart - dbase) / dstep); - ++dbins[bin]; - ++npix; - } - - bsum = 0; - blim = int(0.5 * npix); - - for (bin = 0; bin < 20; bin++) // find redness level for 50% of - { // pixels within red-eye radius - bsum += dbins[bin]; - if (bsum > blim) break; - } - - redmem[ii].thresh = dbase + dstep * bin; // initial redness threshhold - redmem[ii].tstep = dstep; // redness step (5% of range) - - return; -} - - -// find a red-eye (nearly) overlapping the mouse click position - -int redeye_find(int cx, int cy) -{ - for (int ii = 0; ii < Nredmem; ii++) - { - if (cx > redmem[ii].cx - 2 * redmem[ii].rad && - cx < redmem[ii].cx + 2 * redmem[ii].rad && - cy > redmem[ii].cy - 2 * redmem[ii].rad && - cy < redmem[ii].cy + 2 * redmem[ii].rad) - return ii; // found - } - return -1; // not found -} - - -// remove a red-eye from memory - -void redeye_remove(int ii) -{ - int cx, cy, rad, px, py; - uint16 *pix1, *pix3; - - cx = redmem[ii].cx; - cy = redmem[ii].cy; - rad = redmem[ii].rad; - - for (px = cx-rad; px <= cx+rad; px++) - for (py = cy-rad; py <= cy+rad; py++) - { - pix1 = PXMpix(E1pxm16,px,py); - pix3 = PXMpix(E3pxm16,px,py); - pix3[0] = pix1[0]; - pix3[1] = pix1[1]; - pix3[2] = pix1[2]; - } - - for (ii++; ii < Nredmem; ii++) - redmem[ii-1] = redmem[ii]; - Nredmem--; - - Ftoparc = 0; - return; -} - - -// compute red-eye radius limit: smaller of 100 and nearest image edge - -int redeye_radlim(int cx, int cy) -{ - int radlim = 100; - if (cx < 100) radlim = cx; - if (E3ww-1 - cx < 100) radlim = E3ww-1 - cx; - if (cy < 100) radlim = cy; - if (E3hh-1 - cy < 100) radlim = E3hh-1 - cy; - return radlim; -} - - -/**************************************************************************/ - -// image blur function // radius steps of 0.5 v.9.2 - -double blur_radius; -double blur_weight[101][101]; // up to blur radius = 99 v.9.2 -int blur_Npixels, blur_pixdone; -int blur_cancel; - -editfunc EFblur; - - -void m_blur(GtkWidget *, cchar *) -{ - int blur_dialog_event(zdialog *zd, cchar *event); - void * blur_thread(void *); - - zfuncs::F1_help_topic = "blur"; // v.10.8 - - EFblur.funcname = "blur"; - EFblur.Farea = 2; // select area usable - EFblur.threadfunc = blur_thread; // thread function - if (! edit_setup(EFblur)) return; // setup edit - - blur_radius = 0.5; - blur_cancel = 0; - - zdialog *zd = zdialog_new(ZTX("Set Blur Radius"),mWin,Bdone,Bcancel,null); - EFblur.zd = zd; - - zdialog_add_widget(zd,"hbox","hb2","dialog",0,"space=10"); - zdialog_add_widget(zd,"label","labrad","hb2",Bradius,"space=5"); - zdialog_add_widget(zd,"spin","radius","hb2","0|99|0.5|0.5","space=5"); - zdialog_add_widget(zd,"button","apply","hb2",Bapply,"space=5"); - - zdialog_help(zd,"blur"); // zdialog help topic v.11.08 - zdialog_run(zd,blur_dialog_event,"save"); // run dialog - parallel v.11.07 - - return; -} - - -// dialog event and completion callback function - -int blur_dialog_event(zdialog * zd, cchar *event) -{ - if (zd->zstat) - { - if (zd->zstat == 1) edit_done(EFblur); // done - else { - blur_cancel = 1; // v.11.09 - edit_cancel(EFblur); // cancel or destroy - } - return 1; - } - - if (strEqu(event,"blendwidth")) signal_thread(); // v.10.3 - - if (strEqu(event,"apply")) { - zdialog_fetch(zd,"radius",blur_radius); // get blur radius - if (blur_radius == 0) edit_reset(); - else signal_thread(); // trigger working thread - } - - return 1; -} - - -// image blur thread function - -void * blur_thread(void *) -{ - void * blur_wthread(void *arg); - - int dx, dy; - double rad, rad2; - double m, d, w, sum; - - while (true) - { - thread_idle_loop(); // wait for work or exit request - - rad = blur_radius - 0.2; // v.9.2 - rad2 = rad * rad; - - for (dx = 0; dx <= rad+1; dx++) // clear weights array - for (dy = 0; dy <= rad+1; dy++) - blur_weight[dx][dy] = 0; - - for (dx = -rad-1; dx <= rad+1; dx++) // blur_weight[dx][dy] = no. of pixels - for (dy = -rad-1; dy <= rad+1; dy++) // at distance (dx,dy) from center - ++blur_weight[abs(dx)][abs(dy)]; - - m = sqrt(rad2 + rad2); // corner pixel distance from center - sum = 0; - - for (dx = 0; dx <= rad+1; dx++) // compute weight of pixel - for (dy = 0; dy <= rad+1; dy++) // at distance dx, dy - { - d = sqrt(dx*dx + dy*dy); - w = (m + 1.2 - d) / m; // v.9.2 - w = w * w; - sum += blur_weight[dx][dy] * w; - blur_weight[dx][dy] = w; - } - - for (dx = 0; dx <= rad+1; dx++) // make weights add up to 1.0 - for (dy = 0; dy <= rad+1; dy++) - blur_weight[dx][dy] = blur_weight[dx][dy] / sum; - - if (Factivearea) SB_goal = sa_Npixel; - else SB_goal = E3ww * E3hh; - SB_done = 0; // v.11.06 - - for (int ii = 0; ii < Nwt; ii++) // start worker threads - start_wthread(blur_wthread,&wtnx[ii]); - wait_wthreads(); // wait for completion - - SB_goal = 0; - CEF->Fmod = 1; - mwpaint2(); // update window - } - - return 0; // not executed, stop g++ warning -} - - -void * blur_wthread(void *arg) // worker thread function -{ - int index = *((int *) arg); - int px, py, ii, dist = 0; - int jj, dx, dy, adx, ady, rad; - double red, green, blue; - double weight1, weight2, f1, f2; - uint16 *pix1, *pix3, *pixN; - - for (py = index; py < E3hh-1; py += Nwt) // loop all image pixels - for (px = 0; px < E3ww-1; px++) - { - if (blur_cancel) exit_wthread(); // v.11.09 - - if (Factivearea) { // select area active - ii = py * Fww + px; - dist = sa_pixmap[ii]; // distance from edge - if (! dist) continue; // outside pixel - } - - pix1 = PXMpix(E1pxm16,px,py); // source pixel - pix3 = PXMpix(E3pxm16,px,py); // target pixel - - rad = blur_radius; - red = green = blue = 0; - weight2 = 0.0; - - if (Factivearea) // select area active - { - for (dy = -rad-1; dy <= rad+1; dy++) // loop neighbor pixels within radius - for (dx = -rad-1; dx <= rad+1; dx++) - { - if (px+dx < 0 || px+dx > E3ww-1) continue; // omit pixels off edge - if (py+dy < 0 || py+dy > E3hh-1) continue; - jj = (py+dy) * E3ww + (px+dx); - if (! sa_pixmap[jj]) continue; // omit pixels outside area - adx = abs(dx); - ady = abs(dy); - pixN = pix1 + (dy * E3ww + dx) * 3; - weight1 = blur_weight[adx][ady]; // weight at distance (dx,dy) - weight2 += weight1; - red += pixN[0] * weight1; // accumulate contributions - green += pixN[1] * weight1; - blue += pixN[2] * weight1; - } - - red = red / weight2; // weighted average - green = green / weight2; - blue = blue / weight2; - - if (dist < sa_blend) { // select area is active, - f1 = 1.0 * dist / sa_blend; // blend changes over sa_blend - f2 = 1.0 - f1; - red = f1 * red + f2 * pix1[0]; - green = f1 * green + f2 * pix1[1]; - blue = f1 * blue + f2 * pix1[2]; - } - - pix3[0] = int(red); - pix3[1] = int(green); - pix3[2] = int(blue); - } - - else - { - for (dy = -rad-1; dy <= rad+1; dy++) // loop neighbor pixels within radius - for (dx = -rad-1; dx <= rad+1; dx++) - { - if (px+dx < 0 || px+dx > E3ww-1) continue; // omit pixels off edge - if (py+dy < 0 || py+dy > E3hh-1) continue; - adx = abs(dx); - ady = abs(dy); - pixN = pix1 + (dy * E3ww + dx) * 3; - weight1 = blur_weight[adx][ady]; // weight at distance (dx,dy) - weight2 += weight1; - red += pixN[0] * weight1; // accumulate contributions - green += pixN[1] * weight1; - blue += pixN[2] * weight1; - } - - red = red / weight2; // weighted average - green = green / weight2; - blue = blue / weight2; - - pix3[0] = red; - pix3[1] = green; - pix3[2] = blue; - } - - SB_done++; // track progress v.10.6 - } - - exit_wthread(); - return 0; // not executed, avoid gcc warning -} - - -/**************************************************************************/ - -// image sharpening function - -int sharp_ED_cycles; -int sharp_ED_reduce; -int sharp_ED_thresh; -int sharp_UM_radius; -int sharp_UM_amount; -int sharp_UM_thresh; -int sharp_UM_Fcalc; -int sharp_GR_amount; -int sharp_GR_thresh; -char sharp_function[4]; - -editfunc EFsharp; - - -void m_sharpen(GtkWidget *, cchar *) -{ - int sharp_dialog_event(zdialog *zd, cchar *event); - void * sharp_thread(void *); - - zfuncs::F1_help_topic = "sharpen"; // v.10.8 - - EFsharp.funcname = "sharpen"; - EFsharp.Farea = 2; // select area usable - EFsharp.threadfunc = sharp_thread; // thread function - if (! edit_setup(EFsharp)) return; // setup edit - - zdialog *zd = zdialog_new(ZTX("Sharpen Image"),mWin,Bdone,Bcancel,null); - EFsharp.zd = zd; - - zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=5"); - zdialog_add_widget(zd,"vbox","vb11","hb1",0,"space=5"); - zdialog_add_widget(zd,"vbox","vb12","hb1",0,"homog|space=5"); - zdialog_add_widget(zd,"vbox","vb13","hb1",0,"homog|space=5"); - zdialog_add_widget(zd,"button","ED","vb11",ZTX("edge detection"),"space=5"); - zdialog_add_widget(zd,"label","lab11","vb12",ZTX("cycles")); - zdialog_add_widget(zd,"label","lab12","vb12",ZTX("reduce")); - zdialog_add_widget(zd,"label","lab13","vb12",Bthresh); - zdialog_add_widget(zd,"spin","cyclesED","vb13","1|30|1|10"); - zdialog_add_widget(zd,"spin","reduceED","vb13","50|95|1|80"); - zdialog_add_widget(zd,"spin","threshED","vb13","1|99|1|1"); - - zdialog_add_widget(zd,"hsep","sep2","dialog"); - zdialog_add_widget(zd,"hbox","hb2","dialog",0,"space=5"); - zdialog_add_widget(zd,"vbox","vb21","hb2",0,"space=5"); - zdialog_add_widget(zd,"vbox","vb22","hb2",0,"homog|space=5"); - zdialog_add_widget(zd,"vbox","vb23","hb2",0,"homog|space=5"); - zdialog_add_widget(zd,"button","UM","vb21",ZTX("unsharp mask"),"space=5"); - zdialog_add_widget(zd,"label","lab21","vb22",Bradius); - zdialog_add_widget(zd,"label","lab22","vb22",Bamount); - zdialog_add_widget(zd,"label","lab23","vb22",Bthresh); - zdialog_add_widget(zd,"spin","radiusUM","vb23","1|20|1|2"); - zdialog_add_widget(zd,"spin","amountUM","vb23","0|200|1|100"); - zdialog_add_widget(zd,"spin","threshUM","vb23","0|100|1|0"); - - zdialog_add_widget(zd,"hsep","sep3","dialog"); - zdialog_add_widget(zd,"hbox","hb3","dialog",0,"space=5"); - zdialog_add_widget(zd,"vbox","vb31","hb3",0,"space=5"); - zdialog_add_widget(zd,"vbox","vb32","hb3",0,"homog|space=5"); - zdialog_add_widget(zd,"vbox","vb33","hb3",0,"homog|space=5"); - zdialog_add_widget(zd,"button","GR","vb31",ZTX("brightness gradient"),"space=5"); - zdialog_add_widget(zd,"label","lab32","vb32",Bamount); - zdialog_add_widget(zd,"label","lab33","vb32",Bthresh); - zdialog_add_widget(zd,"spin","amountGR","vb33","0|400|1|100"); - zdialog_add_widget(zd,"spin","threshGR","vb33","0|100|1|0"); - - zdialog_help(zd,"sharpen"); // zdialog help topic v.11.08 - zdialog_run(zd,sharp_dialog_event,"save"); // run dialog - parallel v.11.07 - - *sharp_function = 0; - sharp_UM_Fcalc = 1; - return; -} - - -// dialog event and completion callback function - -int sharp_dialog_event(zdialog *zd, cchar *event) -{ - if (zd->zstat) - { - if (zd->zstat == 1) edit_done(EFsharp); - else edit_cancel(EFsharp); - return 0; - } - - if (strEqu(event,"blendwidth")) signal_thread(); // v.10.3 - if (strEqu(event,"radiusUM")) sharp_UM_Fcalc = 1; // must recalculate - - if (strcmpv(event,"ED","UM","GR",null)) - { - edit_reset(); // restore original image - - zdialog_fetch(zd,"cyclesED",sharp_ED_cycles); // get all input values - zdialog_fetch(zd,"reduceED",sharp_ED_reduce); - zdialog_fetch(zd,"threshED",sharp_ED_thresh); - zdialog_fetch(zd,"radiusUM",sharp_UM_radius); - zdialog_fetch(zd,"amountUM",sharp_UM_amount); - zdialog_fetch(zd,"threshUM",sharp_UM_thresh); - zdialog_fetch(zd,"amountGR",sharp_GR_amount); - zdialog_fetch(zd,"threshGR",sharp_GR_thresh); - - strcpy(sharp_function,event); // pass to working thread - signal_thread(); - } - - return 0; -} - - -// sharpen image thread function - -void * sharp_thread(void *) -{ - int sharp_ED(); - int sharp_UM(); - int sharp_GR(); - - while (true) - { - thread_idle_loop(); // wait for work or exit request - - if (strEqu(sharp_function,"ED")) sharp_ED(); // do requested function - if (strEqu(sharp_function,"UM")) sharp_UM(); - if (strEqu(sharp_function,"GR")) sharp_GR(); - - CEF->Fmod = 1; - mwpaint2(); - } - - return 0; // not executed, stop g++ warning -} - - -// image sharpen function by edge detection and compression - -int sharp_ED() -{ - void sharp_pixel_ED(int px, int py, int thresh); - - int sharp_thresh1 = 100; // initial threshold - double sharp_thresh2 = 0.01 * sharp_ED_reduce; // decline rate - int px, py, thresh, cycles; - - thresh = sharp_thresh1; - - if (Factivearea) SB_goal = sa_Npixel; // v.9.6 - else SB_goal = E3ww * E3hh; - SB_goal *= sharp_ED_cycles; - SB_done = 0; // v.11.06 - - for (cycles = 0; cycles < sharp_ED_cycles; cycles++) - { - if (cycles > 0) thresh = int(thresh * sharp_thresh2); - - for (py = 2; py < E3hh-2; py++) - for (px = 2; px < E3ww-2; px++) // loop all pixels - { - sharp_pixel_ED(px,py,thresh); - SB_done++; // track progress v.10.6 - } - } - - SB_goal = 0; - return 1; -} - - -void sharp_pixel_ED(int px, int py, int thresh) -{ - uint16 *pix1, *pix1u, *pix1d; - uint16 *pix3, *pix3u, *pix3d, *pix3uu, *pix3dd; - int ii, dist = 0; - int dd, rgb, pthresh; - int dx[4] = { -1, 0, 1, 1 }; // 4 directions: NW N NE E - int dy[4] = { -1, -1, -1, 0 }; - int pv2, pv2u, pv2d, pv2uu, pv2dd, pvdiff; - double f1, f2; - - if (Factivearea) { // select area active - ii = py * Fww + px; - dist = sa_pixmap[ii]; // distance from edge - if (! dist) return; // outside pixel - } - - pthresh = sharp_ED_thresh; // pthresh = larger - if (thresh > pthresh) pthresh = thresh; - - pix1 = PXMpix(E1pxm16,px,py); // input pixel - pix3 = PXMpix(E3pxm16,px,py); // output pixel - - for (dd = 0; dd < 4; dd++) // 4 directions - { - pix3u = pix3 + (dy[dd] * E3ww + dx[dd]) * 3; // upstream pixel - pix3d = pix3 - (dy[dd] * E3ww - dx[dd]) * 3; // downstream pixel - - for (rgb = 0; rgb < 3; rgb++) // loop 3 RGB colors - { - pv2 = pix3[rgb]; - pv2u = pix3u[rgb]; // brightness difference - pv2d = pix3d[rgb]; // across target pixel - - pvdiff = pv2d - pv2u; - if (pvdiff < 0) pvdiff = -pvdiff; - if (pvdiff < 256 * pthresh) continue; // brightness slope < threshold - - if (pv2u < pv2 && pv2 < pv2d) // slope up, monotone - { - pix3uu = pix3u + (dy[dd] * E3ww + dx[dd]) * 3; // upstream of upstream pixel - pix3dd = pix3d - (dy[dd] * E3ww - dx[dd]) * 3; // downstream of downstream - pv2uu = pix3uu[rgb]; - pv2dd = pix3dd[rgb]; - - if (pv2uu >= pv2u) { // shift focus of changes to - pix3u = pix3; // avoid up/down/up jaggies - pv2u = pv2; - } - - if (pv2dd <= pv2d) { - pix3d = pix3; - pv2d = pv2; - } - - if (pv2u > 256) pv2u -= 256; - if (pv2d < 65279) pv2d += 256; - } - - else if (pv2u > pv2 && pv2 > pv2d) // slope down, monotone - { - pix3uu = pix3u + (dy[dd] * E3ww + dx[dd]) * 3; - pix3dd = pix3d - (dy[dd] * E3ww - dx[dd]) * 3; - pv2uu = pix3uu[rgb]; - pv2dd = pix3dd[rgb]; - - if (pv2uu <= pv2u) { - pix3u = pix3; - pv2u = pv2; - } - - if (pv2dd >= pv2d) { - pix3d = pix3; - pv2d = pv2; - } - - if (pv2d > 256) pv2d -= 256; - if (pv2u < 65279) pv2u += 256; - } - - else continue; // slope too small - - if (Factivearea && dist < sa_blend) { // select area is active, - f1 = 1.0 * dist / sa_blend; // blend changes over sa_blend - f2 = 1.0 - f1; - pix1u = pix1 + (dy[dd] * E1ww + dx[dd]) * 3; // upstream input pixel - pix1d = pix1 - (dy[dd] * E1ww - dx[dd]) * 3; // downstream input pixel - pv2u = int(f1 * pv2u + f2 * pix1u[rgb]); - pv2d = int(f1 * pv2d + f2 * pix1d[rgb]); - } - - pix3u[rgb] = pv2u; // modified brightness values - pix3d[rgb] = pv2d; // >> image3 pixel - } - } - - return; -} - - -// image sharpen function using unsharp mask - -int sharp_UM() -{ - void * sharp_UM_wthread(void *arg); - - int ii; - - if (sharp_UM_Fcalc) { // speedup v.9.6 - sharp_UM_Fcalc = 0; - brhood_calc(sharp_UM_radius,'f'); - } - - if (Factivearea) SB_goal = sa_Npixel; // v.9.6 - else SB_goal = E3ww * E3hh; - SB_done = 0; // v.11.06 - - for (ii = 0; ii < Nwt; ii++) // start worker threads - start_wthread(sharp_UM_wthread,&wtnx[ii]); - wait_wthreads(); // wait for completion - - SB_goal = 0; - return 1; -} - - -void * sharp_UM_wthread(void *arg) // worker thread function -{ - void sharp_pixel_UM(int px, int py, int index); - - int index = *((int *) arg); - int px, py; - - for (py = index; py < E3hh; py += Nwt) // loop all image3 pixels - for (px = 0; px < E3ww; px++) - sharp_pixel_UM(px,py,index); - - exit_wthread(); - return 0; // not executed, avoid gcc warning -} - - -void sharp_pixel_UM(int px, int py, int index) // process one pixel -{ // revised v.9.6 - int ii, dist = 0; - double amount, thresh, bright; - double mean, incr, ratio, f1, f2; - double red1, green1, blue1, red3, green3, blue3; - uint16 *pix1, *pix3; - - if (Factivearea) { // select area active - ii = py * Fww + px; - dist = sa_pixmap[ii]; // distance from edge - if (! dist) return; // outside pixel - } - - amount = 0.01 * sharp_UM_amount; // 0.0 to 2.0 - thresh = 100 * sharp_UM_thresh; // 0 to 10K (64K max. possible) - - pix1 = PXMpix(E1pxm16,px,py); // input pixel - pix3 = PXMpix(E3pxm16,px,py); // output pixel - - bright = pixbright(pix1); - if (bright < 100) return; // effectively black - mean = get_brhood(px,py); - incr = (bright - mean); - if (fabs(incr) < thresh) return; // omit low-contrast pixels - - incr = incr * amount; // 0.0 to 2.0 - if (bright + incr > 65535) incr = 65535 - bright; - ratio = (bright + incr) / bright; - if (ratio < 0) ratio = 0; // v.11.08 - - red1 = pix1[0]; // input RGB - green1 = pix1[1]; - blue1 = pix1[2]; - - red3 = ratio * red1; // output RGB - if (red3 > 65535) red3 = 65535; - green3 = ratio * green1; - if (green3 > 65535) green3 = 65535; - blue3 = ratio * blue1; - if (blue3 > 65535) blue3 = 65535; - - if (Factivearea && dist < sa_blend) { // select area is active, - f1 = 1.0 * dist / sa_blend; // blend changes over sa_blend - f2 = 1.0 - f1; - red3 = f1 * red3 + f2 * red1; - green3 = f1 * green3 + f2 * green1; - blue3 = f1 * blue3 + f2 * blue1; - } - - pix3[0] = red3; - pix3[1] = green3; - pix3[2] = blue3; - - SB_done++; // track progress v.10.6 - return; -} - - -// sharpen image by increasing brightness gradient // new v.9.8 - -int sharp_GR() -{ - uint16 *pix1, *pix3; - int ii, px, py, dist = 0; - double amount, thresh; - double b1, b1x, b1y, b3x, b3y, b3, bf, f1, f2; - double red1, green1, blue1, red3, green3, blue3; - - amount = 1 + 0.01 * sharp_GR_amount; // 1.0 - 5.0 - thresh = 655.35 * sharp_GR_thresh; // 0 - 64K - - if (Factivearea) SB_goal = sa_Npixel; - else SB_goal = E3ww * E3hh; - SB_done = 0; // v.11.06 - - for (py = 1; py < E1hh; py++) // loop all image pixels - for (px = 1; px < E1ww; px++) - { - if (Factivearea) { // select area active - ii = py * Fww + px; - dist = sa_pixmap[ii]; // distance from edge - if (! dist) continue; // pixel is outside area - } - - pix1 = PXMpix(E1pxm16,px,py); // input pixel - pix3 = PXMpix(E3pxm16,px,py); // output pixel - - b1 = pixbright(pix1); // pixel brightness, 0 - 64K - b1x = b1 - pixbright(pix1 - 3); // brightness gradient (x,y) - b1y = b1 - pixbright(pix1 - 3 * E1ww); - - if (abs(b1x + b1y) < thresh) // moderate brightness change for - f1 = abs(b1x + b1y) / thresh; // pixels below threshold gradient - else f1 = 1.0; // v.10.9 - f2 = 1.0 - f1; - - b1x = b1x * amount; // amplified gradient - b1y = b1y * amount; - - b3x = pixbright(pix1 - 3) + b1x; // + prior pixel brightness - b3y = pixbright(pix1 - 3 * E3ww) + b1y; // = new brightness - b3 = 0.5 * (b3x + b3y); - - b3 = f1 * b3 + f2 * b1; // possibly moderated v.10.9 - - bf = b3 / b1; // ratio of brightness change - if (bf < 0) bf = 0; - if (bf > 4) bf = 4; - - red1 = pix1[0]; // input RGB - green1 = pix1[1]; - blue1 = pix1[2]; - - red3 = bf * red1; // output RGB - if (red3 > 65535) red3 = 65535; - green3 = bf * green1; - if (green3 > 65535) green3 = 65535; - blue3 = bf * blue1; - if (blue3 > 65535) blue3 = 65535; - - if (Factivearea && dist < sa_blend) { // select area is active, - f1 = 1.0 * dist / sa_blend; // blend changes over sa_blend - f2 = 1.0 - f1; - red3 = f1 * red3 + f2 * red1; - green3 = f1 * green3 + f2 * green1; - blue3 = f1 * blue3 + f2 * blue1; - } - - pix3[0] = red3; - pix3[1] = green3; - pix3[2] = blue3; - - SB_done++; // track progress v.10.6 - } - - SB_goal = 0; - return 1; -} - - -/**************************************************************************/ - -// image noise reduction - -int denoise_method = 5; // default algorithm -int denoise_radius = 4; - -editfunc EFdenoise; - - -void m_denoise(GtkWidget *, cchar *) -{ - int denoise_dialog_event(zdialog *zd, cchar *event); // dialog event function - void * denoise_thread(void *); - - cchar *denoise_message = ZTX(" Press the reduce button to \n" - " reduce noise in small steps. \n" - " Use undo to start over."); - - zfuncs::F1_help_topic = "reduce_noise"; // v.10.8 - - EFdenoise.funcname = "denoise"; - EFdenoise.Farea = 2; // select area usable - EFdenoise.threadfunc = denoise_thread; // thread function - if (! edit_setup(EFdenoise)) return; // setup edit - - zdialog *zd = zdialog_new(ZTX("Noise Reduction"),mWin,Bdone,Bcancel,null); - EFdenoise.zd = zd; - - zdialog_add_widget(zd,"label","lab1","dialog",denoise_message,"space=5"); - zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=5"); - zdialog_add_widget(zd,"label","labalg","hb1",ZTX("algorithm"),"space=5"); - zdialog_add_widget(zd,"combo","method","hb1",0,"space=5|expand"); - zdialog_add_widget(zd,"hbox","hb2","dialog",0,"space=5"); - zdialog_add_widget(zd,"label","labrad","hb2",Bradius,"space=5"); - zdialog_add_widget(zd,"spin","radius","hb2","1|9|1|4","space=5"); - zdialog_add_widget(zd,"button","reduce","hb2",Breduce,"space=5"); - - zdialog_cb_app(zd,"method",ZTX("flatten outliers by color (1)")); - zdialog_cb_app(zd,"method",ZTX("flatten outliers by color (2)")); - zdialog_cb_app(zd,"method",ZTX("set median brightness by color")); - zdialog_cb_app(zd,"method",ZTX("top hat filter by color")); - zdialog_stuff(zd,"method",ZTX("top hat filter by color")); // default - - zdialog_help(zd,"reduce_noise"); // zdialog help topic v.11.08 - zdialog_run(zd,denoise_dialog_event,"save"); // run dialog - parallel v.11.07 - return; -} - - -// dialog event and completion callback function - -int denoise_dialog_event(zdialog * zd, cchar *event) -{ - char method[40]; - - if (zd->zstat) - { - if (zd->zstat == 1) edit_done(EFdenoise); - else edit_cancel(EFdenoise); - return 0; - } - - if (strEqu(event,"blendwidth")) signal_thread(); // trigger update thread - - if (strEqu(event,"radius")) - zdialog_fetch(zd,"radius",denoise_radius); - - if (strEqu(event,"method")) - { - zdialog_fetch(zd,"method",method,39); - - if (strEqu(method,"flatten outliers by color (1)")) { - denoise_method = 1; - denoise_radius = 1; - } - - if (strEqu(method,"flatten outliers by color (2)")) { - denoise_method = 2; - denoise_radius = 3; - } - - if (strEqu(method,"set median brightness by color")) { - denoise_method = 4; - denoise_radius = 2; - } - - if (strEqu(method,"top hat filter by color")) { - denoise_method = 5; - denoise_radius = 4; - } - - zdialog_stuff(zd,"radius",denoise_radius); - } - - if (strEqu(event,"reduce")) signal_thread(); // trigger update thread - - return 1; -} - - -// image noise reduction thread - -void * denoise_thread(void *) -{ - void * denoise_wthread(void *arg); - - int ii; - - while (true) - { - thread_idle_loop(); // wait for work or exit request - - E9pxm16 = PXM_copy(E3pxm16); // image3 is reference source - // image9 will be modified - if (Factivearea) SB_goal = sa_Npixel; - else SB_goal = E3ww * E3hh; - SB_done = 0; // v.11.06 - - for (ii = 0; ii < Nwt; ii++) // start worker threads - start_wthread(denoise_wthread,&wtnx[ii]); - wait_wthreads(); // wait for completion - - SB_goal = 0; - - mutex_lock(&Fpixmap_lock); - PXM_free(E3pxm16); // image9 >> image3 - E3pxm16 = E9pxm16; - E9pxm16 = 0; - mutex_unlock(&Fpixmap_lock); - - CEF->Fmod = 1; - mwpaint2(); // update window - } - - return 0; // not executed, stop g++ warning -} - - -void * denoise_wthread(void *arg) // worker thread function -{ - void denoise_func1(uint16 *pix3, uint16 *pix9); - void denoise_func2(uint16 *pix3, uint16 *pix9); - void denoise_func4(uint16 *pix3, uint16 *pix9); - void denoise_func5(uint16 *pix3, uint16 *pix9); - - int index = *((int *) arg); - int ii, px, py, rad, dist = 0; - double f1, f2; - uint16 *pix1, *pix3, *pix9; - - rad = denoise_radius; - - for (py = index+rad; py < E3hh-rad; py += Nwt) // loop all image3 pixels - for (px = rad; px < E3ww-rad; px++) - { - if (Factivearea) { // select area active - ii = py * Fww + px; - dist = sa_pixmap[ii]; // distance from edge - if (! dist) continue; // outside pixel - } - - pix3 = PXMpix(E3pxm16,px,py); // source pixel - pix9 = PXMpix(E9pxm16,px,py); // target pixel - - if (denoise_method == 1) denoise_func1(pix3,pix9); - if (denoise_method == 2) denoise_func2(pix3,pix9); - if (denoise_method == 4) denoise_func4(pix3,pix9); - if (denoise_method == 5) denoise_func5(pix3,pix9); - - if (Factivearea && dist < sa_blend) { // select area is active, - f1 = 1.0 * dist / sa_blend; // blend changes over sa_blend - f2 = 1.0 - f1; - pix1 = PXMpix(E1pxm16,px,py); // source pixel - pix9[0] = int(f1 * pix9[0] + f2 * pix1[0]); - pix9[1] = int(f1 * pix9[1] + f2 * pix1[1]); - pix9[2] = int(f1 * pix9[2] + f2 * pix1[2]); - } - - SB_done++; // track progress v.10.6 - } - - exit_wthread(); - return 0; // not executed, avoid gcc warning -} - - -// flatten outliers within radius, by color -// an outlier is the max or min value within a radius - -void denoise_func1(uint16 *pix3, uint16 *pix9) -{ - int dy, dx, rad; - int min0, min1, min2, max0, max1, max2; - uint16 *pixN; - - min0 = min1 = min2 = 65535; - max0 = max1 = max2 = 0; - rad = denoise_radius; - - for (dy = -rad; dy <= rad; dy++) // loop surrounding pixels - for (dx = -rad; dx <= rad; dx++) - { - if (dy == 0 && dx == 0) continue; // skip self - - pixN = pix3 + (dy * E3ww + dx) * 3; - if (pixN[0] < min0) min0 = pixN[0]; // find min and max per color - if (pixN[0] > max0) max0 = pixN[0]; - if (pixN[1] < min1) min1 = pixN[1]; - if (pixN[1] > max1) max1 = pixN[1]; - if (pixN[2] < min2) min2 = pixN[2]; - if (pixN[2] > max2) max2 = pixN[2]; - } - - if (pix3[0] <= min0 && min0 < 65279) pix9[0] = min0 + 256; // if outlier, flatten a little - if (pix3[0] >= max0 && max0 > 256) pix9[0] = max0 - 256; - if (pix3[1] <= min1 && min1 < 65279) pix9[1] = min1 + 256; - if (pix3[1] >= max1 && max1 > 256) pix9[1] = max1 - 256; - if (pix3[2] <= min2 && min2 < 65279) pix9[2] = min2 + 256; - if (pix3[2] >= max2 && max2 > 256) pix9[2] = max2 - 256; - - return; -} - - -// flatten outliers -// An outlier pixel has an RGB value outside one sigma of -// the mean for all pixels within a given radius of the pixel. - -void denoise_func2(uint16 *pix3, uint16 *pix9) -{ - int rgb, dy, dx, rad, nn; - double nn1, val, sum, sum2, mean, variance, sigma; - uint16 *pixN; - - rad = denoise_radius; - nn = (rad * 2 + 1); - nn = nn * nn - 1; - nn1 = 1.0 / nn; - - for (rgb = 0; rgb < 3; rgb++) // loop RGB color - { - sum = sum2 = 0; - - for (dy = -rad; dy <= rad; dy++) // loop surrounding pixels - for (dx = -rad; dx <= rad; dx++) - { - if (dy == 0 && dx == 0) continue; // skip self - pixN = pix3 + (dy * E3ww + dx) * 3; - val = pixN[rgb]; - sum += val; - sum2 += val * val; - } - - mean = nn1 * sum; - variance = nn1 * (sum2 - 2.0 * mean * sum) + mean * mean; - sigma = sqrt(variance); - - val = pix3[rgb]; - if (val > mean + sigma) { // move value to mean +/- sigma - val = mean + sigma; - pix9[rgb] = val; - } - else if (val < mean - sigma) { - val = mean - sigma; - pix9[rgb] = val; - } - } - - return; -} - - -// use median brightness for pixels within radius - -void denoise_func4(uint16 *pix3, uint16 *pix9) -{ - int dy, dx, rad; - int ns, rgb, bsortN[400]; - uint16 *pixN; - - rad = denoise_radius; - - for (rgb = 0; rgb < 3; rgb++) // loop all RGB colors - { - ns = 0; - - for (dy = -rad; dy <= rad; dy++) // loop surrounding pixels - for (dx = -rad; dx <= rad; dx++) // get brightness values - { - pixN = pix3 + (dy * E3ww + dx) * 3; - bsortN[ns] = pixN[rgb]; - ns++; - } - - HeapSort(bsortN,ns); - pix9[rgb] = bsortN[ns/2]; // median brightness of ns pixels - } - - return; -} - - -// modified top hat filter: execute with increasing radius from 1 to limit -// detect outlier by comparing with pixels in outer radius - -void denoise_func5(uint16 *pix3, uint16 *pix9) -{ - int dy, dx, rad; - int min0, min1, min2, max0, max1, max2; - uint16 *pixN; - - for (rad = 1; rad <= denoise_radius; rad++) - for (int loops = 0; loops < 2; loops++) - { - min0 = min1 = min2 = 65535; - max0 = max1 = max2 = 0; - - for (dy = -rad; dy <= rad; dy++) // loop all pixels within rad - for (dx = -rad; dx <= rad; dx++) - { - if (dx > -rad && dx < rad) continue; // skip inner pixels - if (dy > -rad && dy < rad) continue; - - pixN = pix3 + (dy * E3ww + dx) * 3; - if (pixN[0] < min0) min0 = pixN[0]; // find min and max per color - if (pixN[0] > max0) max0 = pixN[0]; // among outermost pixels - if (pixN[1] < min1) min1 = pixN[1]; - if (pixN[1] > max1) max1 = pixN[1]; - if (pixN[2] < min2) min2 = pixN[2]; - if (pixN[2] > max2) max2 = pixN[2]; - } - - if (pix3[0] < min0 && pix9[0] < 65279) pix9[0] += 256; // if central pixel is outlier, - if (pix3[0] > max0 && pix9[0] > 256) pix9[0] -= 256; // moderate its values - if (pix3[1] < min1 && pix9[1] < 65279) pix9[1] += 256; - if (pix3[1] > max1 && pix9[1] > 256) pix9[1] -= 256; - if (pix3[2] < min2 && pix9[2] < 65279) pix9[2] += 256; - if (pix3[2] > max2 && pix9[2] > 256) pix9[2] -= 256; - } - - return; -} - - -/**************************************************************************/ - -// Smart Erase menu function - Replace pixels inside a select area -// with a reflection of pixels outside the area. - -editfunc EFerase; - -void m_smart_erase(GtkWidget *, const char *) // overhauled v.11.04 -{ - int smart_erase_dialog_event(zdialog* zd, const char *event); - - int cc; - cchar *erase_message = ZTX("1. Drag mouse to select. \n" - "2. Erase. 3. Repeat. "); - - zfuncs::F1_help_topic = "smart_erase"; - - EFerase.funcname = "smart-erase"; - EFerase.Farea = 0; // select area deleted - EFerase.mousefunc = sa_radius_mousefunc; // mouse function (use select area) v.11.08 - if (! edit_setup(EFerase)) return; // setup edit - -/* ______________________________ - | | - | 1. Drag mouse to select. | - | 2. Erase. 3. Repeat. | - | | - | [x] my mouse | - | Radius [10|v] Blur [0.5|v] | - | [New Area] [Erase] [Undo] | - | | - | [Done] | - |______________________________| -*/ - - zdialog *zd = zdialog_new(ZTX("Smart Erase"),mWin,Bdone,null); - EFerase.zd = zd; - EFerase.mousefunc = sa_radius_mousefunc; - - zdialog_add_widget(zd,"label","lab1","dialog",erase_message,"space=8"); - zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=5"); - zdialog_add_widget(zd,"check","mymouse","hb1",BmyMouse,"space=5"); - zdialog_add_widget(zd,"hbox","hb2","dialog",0,"space=5"); - zdialog_add_widget(zd,"label","labr","hb2",ZTX("Radius"),"space=5"); - zdialog_add_widget(zd,"spin","radius","hb2","1|20|1|5"); - zdialog_add_widget(zd,"label","labb","hb2",ZTX("Blur"),"space=5"); - zdialog_add_widget(zd,"spin","blur","hb2","0|9|0.5|0.5"); - zdialog_add_widget(zd,"hbox","hb3","dialog",0,"space=5"); - zdialog_add_widget(zd,"button","newarea","hb3",ZTX("New Area"),"space=10"); - zdialog_add_widget(zd,"button","erase","hb3",Berase,"space=10"); - zdialog_add_widget(zd,"button","undo1","hb3",Bundo,"space=5"); - - zdialog_stuff(zd,"mymouse",0); - zdialog_help(zd,"smart_erase"); // zdialog help topic v.11.08 - zdialog_run(zd,smart_erase_dialog_event,"save"); // run dialog - parallel v.11.07 - - sa_unselect(); // unselect area if any v.11.06.1 - cc = Fww * Fhh * sizeof(uint16); // create new area - sa_pixmap = (uint16 *) zmalloc(cc,"smart_erase"); - memset(sa_pixmap,0,cc); - sa_mode = 6; // mode = select by mouse - sa_stat = 1; // status = active edit - sa_fww = Fww; // v.11.08 - sa_fhh = Fhh; - sa_show(1); - - sa_mouseradius = 5; // initial mouse select radius - return; -} - - -// dialog event and completion function - -int smart_erase_dialog_event(zdialog *zd, const char *event) // overhauled v.11.04 -{ - void smart_erase_func(int mode); - void smart_erase_blur(double radius); - - double radius; - int mymouse, cc; - - if (zd->zstat) { - sa_unselect(); - if (zd->zstat == 1) edit_done(EFerase); - else edit_cancel(EFerase); - return 0; - } - - if (strEqu(event,"mymouse")) { // toggle mouse capture - zdialog_fetch(zd,"mymouse",mymouse); - if (mymouse) { - sa_stat = 1; // status = active edit - takeMouse(zd,sa_radius_mousefunc,0); // use select area by mouse function - sa_show(1); - } - else { - sa_stat = 2; // pause edit - freeMouse(); // disconnect mouse - } - } - - if (strEqu(event,"newarea")) { - sa_unselect(); - cc = Fww * Fhh * sizeof(uint16); // create new area - sa_pixmap = (uint16 *) zmalloc(cc,"smart_erase"); - memset(sa_pixmap,0,cc); - sa_mode = 6; // mode = select by mouse - sa_stat = 1; // status = active edit - sa_fww = Fww; // v.11.08 - sa_fhh = Fhh; - sa_show(1); - } - - if (strEqu(event,"radius")) - zdialog_fetch(zd,"radius",sa_mouseradius); - - if (strEqu(event,"erase")) { // do smart erase - sa_finish_auto(); // finish the area - smart_erase_func(1); - zdialog_fetch(zd,"blur",radius); // add optional blur - if (radius > 0) smart_erase_blur(radius); - sa_show(0); - freeMouse(); // disconnect mouse - } - - if (strEqu(event,"undo1")) // dialog undo, undo last erase - smart_erase_func(2); - - return 0; -} - - -// erase the area or restore last erased area - -void smart_erase_func(int mode) -{ - int px, py, npx, npy; - int qx, qy, sx, sy, tx, ty; - int ii, rad, inc, cc; - int dist2, mindist2; - double slope; - char *pmap; - uint16 *pix1, *pix3; - - if (! Factivearea) return; // nothing selected v.11.05 - - for (py = sa_miny; py < sa_maxy; py++) // loop all pixels in area - for (px = sa_minx; px < sa_maxx; px++) - { - ii = py * Fww + px; - if (! sa_pixmap[ii]) continue; // pixel not selected - - pix1 = PXMpix(E1pxm16,px,py); // input pixel - pix3 = PXMpix(E3pxm16,px,py); // output pixel - - pix3[0] = pix1[0]; // restore pixels inside area - pix3[1] = pix1[1]; - pix3[2] = pix1[2]; - } - - mwpaint2(); // update window - - if (mode == 2) return; // mode = undo, done - - cc = Fww * Fhh; // allocate pixel done map - pmap = (char *) zmalloc(cc,"smart_erase"); - memset(pmap,0,cc); - - for (py = sa_miny; py < sa_maxy; py++) // loop all pixels in area - for (px = sa_minx; px < sa_maxx; px++) - { - ii = py * Fww + px; - if (! sa_pixmap[ii]) continue; // pixel not selected - if (pmap[ii]) continue; // pixel already done - - mindist2 = 999999; // find nearest edge - npx = npy = 0; - - for (rad = 1; rad < 50; rad++) // 50 pixel limit v.11.05 - { - for (qx = px-rad; qx <= px+rad; qx++) // search within rad v.11.05 - for (qy = py-rad; qy <= py+rad; qy++) - { - if (qx < 0 || qx >= Fww) continue; // off image edge modified v.11.09 - if (qy < 0 || qy >= Fhh) continue; - ii = qy * Fww + qx; - if (sa_pixmap[ii]) continue; // within selected area - - dist2 = (px-qx) * (px-qx) + (py-qy) * (py-qy); // distance**2 to edge pixel - if (dist2 < mindist2) { - mindist2 = dist2; - npx = qx; // save nearest edge pixel found - npy = qy; - } - } - - if (rad * rad >= mindist2) break; // can quit now - } - - if (! npx && ! npy) continue; // edge not found, should not happen - - qx = npx; // nearest edge pixel - qy = npy; - - if (abs(qy - py) > abs(qx - px)) { // qx/qy = near edge from px/py - slope = 1.0 * (qx - px) / (qy - py); - if (qy > py) inc = 1; - else inc = -1; - for (sy = py; sy != qy; sy += inc) // line from px/py to qx/qy v.11.06 - { - sx = px + slope * (sy - py); - ii = sy * Fww + sx; - if (pmap[ii]) continue; // v.11.06 - pmap[ii] = 1; - tx = qx + (qx - sx); // tx/ty = parallel line from qx/qy - ty = qy + (qy - sy); // modified v.11.09 - if (tx < 0) tx = 0; - if (tx > Fww-1) tx = Fww-1; - if (ty < 0) ty = 0; - if (ty > Fhh-1) ty = Fhh-1; - pix1 = PXMpix(E3pxm16,tx,ty); // copy pixel from tx/ty to sx/sy - pix3 = PXMpix(E3pxm16,sx,sy); - pix3[0] = pix1[0]; - pix3[1] = pix1[1]; - pix3[2] = pix1[2]; - } - } - - else { - slope = 1.0 * (qy - py) / (qx - px); - if (qx > px) inc = 1; - else inc = -1; - for (sx = px; sx != qx; sx += inc) - { - sy = py + slope * (sx - px); - ii = sy * Fww + sx; - if (pmap[ii]) continue; - pmap[ii] = 1; - tx = qx + (qx - sx); - ty = qy + (qy - sy); - if (tx < 0) tx = 0; - if (tx > Fww-1) tx = Fww-1; - if (ty < 0) ty = 0; - if (ty > Fhh-1) ty = Fhh-1; - pix1 = PXMpix(E3pxm16,tx,ty); - pix3 = PXMpix(E3pxm16,sx,sy); - pix3[0] = pix1[0]; - pix3[1] = pix1[1]; - pix3[2] = pix1[2]; - } - } - } - - zfree(pmap); // free memory - CEF->Fmod = 1; - mwpaint2(); // update window - return; -} - - -// add blur to the erased area to help mask the side-effects - -int smart_erase_blur(double radius) -{ - int ii, px, py, dx, dy, adx, ady; - double blur_weight[10][10]; // up to blur radius = 9 - double rad, rad2; - double m, d, w, sum; - double red, green, blue; - double weight1, weight2; - uint16 *pix9, *pix3, *pixN; - - if (! Factivearea) return 0; - - rad = radius - 0.2; - rad2 = rad * rad; - - for (dx = 0; dx <= rad+1; dx++) // clear weights array - for (dy = 0; dy <= rad+1; dy++) - blur_weight[dx][dy] = 0; - - for (dx = -rad-1; dx <= rad+1; dx++) // blur_weight[dx][dy] = no. of pixels - for (dy = -rad-1; dy <= rad+1; dy++) // at distance (dx,dy) from center - ++blur_weight[abs(dx)][abs(dy)]; - - m = sqrt(rad2 + rad2); // corner pixel distance from center - sum = 0; - - for (dx = 0; dx <= rad+1; dx++) // compute weight of pixel - for (dy = 0; dy <= rad+1; dy++) // at distance dx, dy - { - d = sqrt(dx*dx + dy*dy); - w = (m + 1.2 - d) / m; - w = w * w; - sum += blur_weight[dx][dy] * w; - blur_weight[dx][dy] = w; - } - - for (dx = 0; dx <= rad+1; dx++) // make weights add up to 1.0 - for (dy = 0; dy <= rad+1; dy++) - blur_weight[dx][dy] = blur_weight[dx][dy] / sum; - - E9pxm16 = PXM_copy(E3pxm16); // copy edited image - - for (py = sa_miny; py < sa_maxy; py++) // loop all pixels in area - for (px = sa_minx; px < sa_maxx; px++) - { - ii = py * Fww + px; - if (! sa_pixmap[ii]) continue; // pixel not in area - - pix9 = PXMpix(E9pxm16,px,py); // source pixel - pix3 = PXMpix(E3pxm16,px,py); // target pixel - - rad = radius; - red = green = blue = 0; - weight2 = 0.0; - - for (dy = -rad-1; dy <= rad+1; dy++) // loop neighbor pixels within radius - for (dx = -rad-1; dx <= rad+1; dx++) - { - if (px+dx < 0 || px+dx >= E3ww) continue; // omit pixels off edge - if (py+dy < 0 || py+dy >= E3hh) continue; - adx = abs(dx); - ady = abs(dy); - pixN = pix9 + (dy * E3ww + dx) * 3; - weight1 = blur_weight[adx][ady]; // weight at distance (dx,dy) - weight2 += weight1; - red += pixN[0] * weight1; // accumulate contributions - green += pixN[1] * weight1; - blue += pixN[2] * weight1; - } - - red = red / weight2; // weighted average - green = green / weight2; - blue = blue / weight2; - - pix3[0] = int(red); - pix3[1] = int(green); - pix3[2] = int(blue); - } - - PXM_free(E9pxm16); - - CEF->Fmod = 1; - mwpaint2(); // update window - return 0; -} - - -/**************************************************************************/ - -// find and remove "dust" from an image (e.g. from a scanned dusty slide) -// dust is defined as small dark areas surrounded by brighter areas -// image 1 original with prior edits -// image 3 accumulated dust removals that have been comitted -// image 9 comitted dust removals + pending removal (work in process) - -namespace dust_names -{ - editfunc EFdust; - - int spotspann; // max. dustspot spann, pixels - int spotspann2; // spotspann **2 - double brightness; // brightness limit, 0 to 1 = white - double contrast; // min. contrast, 0 to 1 = black/white - int *pixgroup; // maps (px,py) to pixel group no. - int Fred; // red pixels are on - - int Nstack; - - struct spixstack { - uint16 px, py; // pixel group search stack - uint16 direc; - } *pixstack; - - #define maxgroups 1000000 - int Ngroups; - int groupcount[maxgroups]; // count of pixels in each group - double groupbright[maxgroups]; // - int edgecount[maxgroups]; // group edge pixel count - double edgebright[maxgroups]; // group edge pixel brightness sum - - typedef struct { - uint16 px1, py1, px2, py2; // pixel group extreme pixels - int spann2; // spann from px1/py1 to px2/py2 - } sgroupspann; - - sgroupspann groupspann[maxgroups]; -} - - -void m_dust(GtkWidget *, const char *) // new v.11.05 -{ - using namespace dust_names; - - int dust_dialog_event(zdialog *zd, cchar *event); - void * dust_thread(void *); - - zfuncs::F1_help_topic = "remove_dust"; // v.11.05.1 - - EFdust.funcname = "dust"; - EFdust.Farea = 2; // select area usable - EFdust.threadfunc = dust_thread; // thread function - if (! edit_setup(EFdust)) return; // setup edit - - E9pxm16 = PXM_copy(E3pxm16); // image 9 = copy of image3 - Fred = 0; - - int cc = Fww * Fhh * sizeof(int); - pixgroup = (int *) zmalloc(cc,"erase_dust"); // maps pixels to assigned groups - - cc = Fww * Fhh * sizeof(spixstack); - pixstack = (spixstack *) zmalloc(cc,"erase_dust"); // pixel group search stack - -/*** - Remove Dust - - spot size limit =========[]=========== - max. brightness =============[]======= - min. contrast ========[]============ - [erase] [red] [undo last] [apply] - - [Done] [Cancel] -***/ - - zdialog *zd = zdialog_new(ZTX("Remove Dust"),mWin,Bdone,Bcancel,null); - EFdust.zd = zd; - - zdialog_add_widget(zd,"hbox","hbssl","dialog",0,"space=1"); - zdialog_add_widget(zd,"label","labssl","hbssl",ZTX("spot size limit"),"space=5"); - zdialog_add_widget(zd,"hscale","spotspann","hbssl","1|50|1|20","space=5|expand"); - zdialog_add_widget(zd,"hbox","hbmb","dialog",0,"space=1"); - zdialog_add_widget(zd,"label","labmb","hbmb",ZTX("max. brightness"),"space=5"); - zdialog_add_widget(zd,"hscale","brightness","hbmb","1|999|1|700","space=5|expand"); - zdialog_add_widget(zd,"hbox","hbmc","dialog",0,"space=1"); - zdialog_add_widget(zd,"label","labmb","hbmc",ZTX("min. contrast"),"space=5"); - zdialog_add_widget(zd,"hscale","contrast","hbmc","1|500|1|50","space=5|expand"); - zdialog_add_widget(zd,"hbox","hbbutts","dialog",0,"space=5"); - zdialog_add_widget(zd,"button","erase","hbbutts",Berase,"space=5"); - zdialog_add_widget(zd,"button","red","hbbutts",Bred,"space=5"); - zdialog_add_widget(zd,"button","undo1","hbbutts",Bundolast,"space=5"); - zdialog_add_widget(zd,"button","apply","hbbutts",Bapply,"space=5"); - - zdialog_fetch(zd,"spotspann",spotspann); // max. dustspot spann (pixels) - spotspann2 = spotspann * spotspann; - - zdialog_fetch(zd,"brightness",brightness); // max. dustspot brightness - brightness = 0.001 * brightness; // scale 0 to 1 = white - - zdialog_fetch(zd,"contrast",contrast); // min. dustspot contrast - contrast = 0.001 * contrast; // scale 0 to 1 = black/white - - zdialog_resize(zd,300,0); - zdialog_help(zd,"remove_dust"); // zdialog help topic v.11.08 - zdialog_run(zd,dust_dialog_event,"save"); // run dialog - parallel v.11.07 - - signal_thread(); - return; -} - - -// dialog event and completion callback function - -int dust_dialog_event(zdialog *zd, cchar *event) -{ - using namespace dust_names; - - void dust_erase(); - - if (zd->zstat) // dialog complete - { - if (zd->zstat == 1) { // done, use committed changes - mutex_lock(&Fpixmap_lock); - PXM_free(E3pxm16); - E3pxm16 = E9pxm16; // image 3 = image 9 - E9pxm16 = 0; - mutex_unlock(&Fpixmap_lock); - edit_done(EFdust); - } - else { // cancel, discard changes - PXM_free(E9pxm16); - edit_cancel(EFdust); - } - - zfree(pixgroup); // free memory - zfree(pixstack); - return 0; - } - - if (strEqu(event,"spotspann") || strEqu(event,"brightness") - || strEqu(event,"contrast") || strEqu(event,"red")) - { - zdialog_fetch(zd,"spotspann",spotspann); // max. dustspot spann (pixels) - spotspann2 = spotspann * spotspann; - - zdialog_fetch(zd,"brightness",brightness); // max. dustspot brightness - brightness = 0.001 * brightness; // scale 0 to 1 = white - - zdialog_fetch(zd,"contrast",contrast); // min. dustspot contrast - contrast = 0.001 * contrast; // scale 0 to 1 = black/white - - signal_thread(); // do the work - } - - if (strEqu(event,"erase")) dust_erase(); - if (strEqu(event,"blendwidth")) dust_erase(); - - if (strEqu(event,"undo1")) { - mutex_lock(&Fpixmap_lock); // image 3 = copy of image 9 - PXM_free(E3pxm16); - E3pxm16 = PXM_copy(E9pxm16); - mutex_unlock(&Fpixmap_lock); - Fred = 0; - mwpaint2(); - } - - if (strEqu(event,"apply")) { - if (Fred) dust_erase(); - PXM_free(E9pxm16); // image 9 = copy of image 3 - E9pxm16 = PXM_copy(E3pxm16); - CEF->Fmod = 1; - } - - return 0; -} - - -// dust find thread function - find the dust particles and mark them - -void * dust_thread(void *) -{ - using namespace dust_names; - - int xspann, yspann, spann2; - int group, cc, ii, kk, Nremoved; - int px, py, dx, dy, ppx, ppy, npx, npy; - double gbright, pbright, pcontrast; - double ff = 1.0 / 65536.0; - uint16 direc, *pix3; - - while (true) - { - thread_idle_loop(); // wait for work or exit request - - mutex_lock(&Fpixmap_lock); // image 3 = copy of image 9 - PXM_free(E3pxm16); - E3pxm16 = PXM_copy(E9pxm16); - mutex_unlock(&Fpixmap_lock); - mwpaint2(); - - cc = Fww * Fhh * sizeof(int); // clear group arrays - memset(pixgroup,0,cc); - cc = maxgroups * sizeof(int); - memset(groupcount,0,cc); - memset(edgecount,0,cc); - cc = maxgroups * sizeof(double); - memset(groupbright,0,cc); - memset(edgebright,0,cc); - cc = maxgroups * sizeof(sgroupspann); - memset(groupspann,0,cc); - - group = 0; - - for (py = 0; py < Fhh; py++) // loop all pixels - for (px = 0; px < Fww; px++) - { - ii = py * Fww + px; - if (Factivearea && ! sa_pixmap[ii]) continue; // not in active area - if (pixgroup[ii]) continue; // already assigned to a group - - pix3 = PXMpix(E3pxm16,px,py); // get pixel brightness - gbright = ff * pixbright(pix3); // 0 to 1.0 = white - if (gbright > brightness) continue; // ignore bright pixel - - if (group == maxgroups-1) break; // too many groups, make no more - - pixgroup[ii] = ++group; // assign next group - groupcount[group] = 1; - groupbright[group] = gbright; - - pixstack[0].px = px; // put pixel into stack with - pixstack[0].py = py; // direction = ahead - pixstack[0].direc = 0; - Nstack = 1; - - while (Nstack) - { - kk = Nstack - 1; // get last pixel in stack - px = pixstack[kk].px; - py = pixstack[kk].py; - direc = pixstack[kk].direc; // next search direction - - if (direc == 'x') { - Nstack--; // none left - continue; - } - - if (Nstack > 1) { - ii = Nstack - 2; // get prior pixel in stack - ppx = pixstack[ii].px; - ppy = pixstack[ii].py; - } - else { - ppx = px - 1; // if only one, assume prior = left - ppy = py; - } - - dx = px - ppx; // vector from prior to this pixel - dy = py - ppy; - - switch (direc) - { - case 0: - npx = px + dx; - npy = py + dy; - pixstack[kk].direc = 1; - break; - - case 1: - npx = px + dy; - npy = py + dx; - pixstack[kk].direc = 3; - break; - - case 2: - npx = px - dx; // back to prior pixel - npy = py - dy; // (this path never taken) - zappcrash("stack search bug"); - break; - - case 3: - npx = px - dy; - npy = py - dx; - pixstack[kk].direc = 4; - break; - - case 4: - npx = px - dx; - npy = py + dy; - pixstack[kk].direc = 5; - break; - - case 5: - npx = px - dy; - npy = py + dx; - pixstack[kk].direc = 6; - break; - - case 6: - npx = px + dx; - npy = py - dy; - pixstack[kk].direc = 7; - break; - - case 7: - npx = px + dy; - npy = py - dx; - pixstack[kk].direc = 'x'; - break; - - default: - npx = npy = 0; - zappcrash("stack search bug"); - } - - if (npx < 0 || npx > Fww-1) continue; // pixel off the edge - if (npy < 0 || npy > Fhh-1) continue; - - ii = npy * Fww + npx; - if (pixgroup[ii]) continue; // pixel already assigned - if (Factivearea && ! sa_pixmap[ii]) continue; // pixel outside area - - pix3 = PXMpix(E3pxm16,npx,npy); // pixel brightness - pbright = ff * pixbright(pix3); - if (pbright > brightness) continue; // brighter than limit - - pixgroup[ii] = group; // assign pixel to group - ++groupcount[group]; // count pixels in group - groupbright[group] += pbright; // sum brightness for group - - kk = Nstack++; // put pixel into stack - pixstack[kk].px = npx; - pixstack[kk].py = npy; - pixstack[kk].direc = 0; // search direction - } - } - - Ngroups = group; // group numbers are 1-Ngroups - Nremoved = 0; - - for (py = 0; py < Fhh; py++) // loop all pixels - for (px = 0; px < Fww; px++) - { - ii = py * Fww + px; - group = pixgroup[ii]; - if (! group) continue; - if (groupspann[group].px1 == 0) { // first pixel found in this group - groupspann[group].px1 = px; // group px1/py1 = this pixel - groupspann[group].py1 = py; - continue; - } - xspann = groupspann[group].px1 - px; // spann from group px1/py1 to this pixel - yspann = groupspann[group].py1 - py; - spann2 = xspann * xspann + yspann * yspann; - if (spann2 > groupspann[group].spann2) { - groupspann[group].spann2 = spann2; // if greater, group px2/py2 = this pixel - groupspann[group].px2 = px; - groupspann[group].py2 = py; - } - } - - for (py = 0; py < Fhh; py++) // loop all pixels - for (px = 0; px < Fww; px++) - { - ii = py * Fww + px; - group = pixgroup[ii]; - if (! group) continue; - if (groupspann[group].spann2 > spotspann2) continue; - xspann = groupspann[group].px2 - px; // spann from this pixel to group px2/py2 - yspann = groupspann[group].py2 - py; - spann2 = xspann * xspann + yspann * yspann; - if (spann2 > groupspann[group].spann2) { - groupspann[group].spann2 = spann2; // if greater, group px1/py1 = this pixel - groupspann[group].px1 = px; - groupspann[group].py1 = py; - } - } - - for (py = 0; py < Fhh; py++) // loop all pixels - for (px = 0; px < Fww; px++) - { - ii = py * Fww + px; // eliminate group if spann > limit - group = pixgroup[ii]; - if (! group) continue; - if (! groupcount[group]) pixgroup[ii] = 0; - else if (groupspann[group].spann2 > spotspann2) { - pixgroup[ii] = 0; - groupcount[group] = 0; - Nremoved++; - } - } - - for (py = 1; py < Fhh-1; py++) // loop all pixels except image edges - for (px = 1; px < Fww-1; px++) - { - ii = py * Fww + px; - group = pixgroup[ii]; - if (group) continue; // find pixels bordering group pixels - pix3 = PXMpix(E3pxm16,px,py); - pbright = ff * pixbright(pix3); - - group = pixgroup[ii-Fww-1]; - if (group) { - ++edgecount[group]; // accumulate pixel count and - edgebright[group] += pbright; // bordering the groups - } - - group = pixgroup[ii-Fww]; - if (group) { - ++edgecount[group]; - edgebright[group] += pbright; - } - - group = pixgroup[ii-Fww+1]; - if (group) { - ++edgecount[group]; - edgebright[group] += pbright; - } - - group = pixgroup[ii-1]; - if (group) { - ++edgecount[group]; - edgebright[group] += pbright; - } - - group = pixgroup[ii+1]; - if (group) { - ++edgecount[group]; - edgebright[group] += pbright; - } - - group = pixgroup[ii+Fww-1]; - if (group) { - ++edgecount[group]; - edgebright[group] += pbright; - } - - group = pixgroup[ii+Fww]; - if (group) { - ++edgecount[group]; - edgebright[group] += pbright; - } - - group = pixgroup[ii+Fww+1]; - if (group) { - ++edgecount[group]; - edgebright[group] += pbright; - } - } - - for (group = 1; group <= Ngroups; group++) // compute group pixel and edge pixel - { // mean brightness - if (groupcount[group] && edgecount[group]) { - edgebright[group] = edgebright[group] / edgecount[group]; - groupbright[group] = groupbright[group] / groupcount[group]; - pcontrast = edgebright[group] - groupbright[group]; // edge - group contrast - if (pcontrast < contrast) { - groupcount[group] = 0; - Nremoved++; - } - } - } - - for (py = 0; py < Fhh; py++) // loop all pixels - for (px = 0; px < Fww; px++) - { - ii = py * Fww + px; // eliminate group if low contrast - group = pixgroup[ii]; - if (! group) continue; - if (! groupcount[group]) pixgroup[ii] = 0; - } - - for (py = 0; py < Fhh; py++) // loop all pixels - for (px = 0; px < Fww; px++) - { - ii = py * Fww + px; - if (! pixgroup[ii]) continue; // not a dust pixel - pix3 = PXMpix(E3pxm16,px,py); // paint it red - pix3[0] = 65535; - pix3[1] = pix3[2] = 0; - } - - Fred = 1; - mwpaint2(); // update window - } - - return 0; // not executed, stop g++ warning -} - - -// erase the selected dust areas - -void dust_erase() -{ - using namespace dust_names; - - int cc, ii, px, py, inc; - int qx, qy, npx, npy; - int sx, sy, tx, ty; - int rad, dist, dist2, mindist2; - double slope, f1, f2; - uint16 *pix1, *pix3; - char *pmap; - - Ffuncbusy++; - - mutex_lock(&Fpixmap_lock); // image 3 = copy of image 9 - PXM_free(E3pxm16); - E3pxm16 = PXM_copy(E9pxm16); - mutex_unlock(&Fpixmap_lock); - - cc = Fww * Fhh; // allocate pixel done map - pmap = (char *) zmalloc(cc,"erase_dust"); - memset(pmap,0,cc); - - for (py = 0; py < Fhh; py++) // loop all pixels - for (px = 0; px < Fww; px++) - { - ii = py * Fww + px; - if (! pixgroup[ii]) continue; // not a dust pixel - if (pmap[ii]) continue; // skip pixels already done - - mindist2 = 999999; - npx = npy = 0; - - for (rad = 1; rad < 10; rad++) // find nearest edge (10 pixel limit) - { - for (qx = px-rad; qx <= px+rad; qx++) // search within rad - for (qy = py-rad; qy <= py+rad; qy++) - { - if (qx < 0 || qx >= Fww) continue; // off image edge modified v.11.09 - if (qy < 0 || qy >= Fhh) continue; - ii = qy * Fww + qx; - if (pixgroup[ii]) continue; // within dust area - - dist2 = (px-qx) * (px-qx) + (py-qy) * (py-qy); // distance**2 to edge pixel - if (dist2 < mindist2) { - mindist2 = dist2; - npx = qx; // save nearest pixel found - npy = qy; - } - } - - if (rad * rad >= mindist2) break; // can quit now - } - - if (! npx && ! npy) continue; // should not happen - - qx = npx; // nearest edge pixel - qy = npy; - - if (abs(qy - py) > abs(qx - px)) { // qx/qy = near edge from px/py - slope = 1.0 * (qx - px) / (qy - py); - if (qy > py) inc = 1; - else inc = -1; - for (sy = py; sy != qy+inc; sy += inc) // line from px/py to qx/qy - { - sx = px + slope * (sy - py); - ii = sy * Fww + sx; - if (pmap[ii]) continue; // v.11.06 - pmap[ii] = 1; - tx = qx + (qx - sx); // tx/ty = parallel line from qx/qy - ty = qy + (qy - sy); // modified v.11.09 - if (tx < 0) tx = 0; - if (tx > Fww-1) tx = Fww-1; - if (ty < 0) ty = 0; - if (ty > Fhh-1) ty = Fhh-1; - pix1 = PXMpix(E3pxm16,tx,ty); // copy pixel from tx/ty to sx/sy - pix3 = PXMpix(E3pxm16,sx,sy); - pix3[0] = pix1[0]; - pix3[1] = pix1[1]; - pix3[2] = pix1[2]; - } - } - - else { - slope = 1.0 * (qy - py) / (qx - px); - if (qx > px) inc = 1; - else inc = -1; - for (sx = px; sx != qx+inc; sx += inc) - { - sy = py + slope * (sx - px); - ii = sy * Fww + sx; - if (pmap[ii]) continue; - pmap[ii] = 1; - tx = qx + (qx - sx); - ty = qy + (qy - sy); - if (tx < 0) tx = 0; - if (tx > Fww-1) tx = Fww-1; - if (ty < 0) ty = 0; - if (ty > Fhh-1) ty = Fhh-1; - pix1 = PXMpix(E3pxm16,tx,ty); - pix3 = PXMpix(E3pxm16,sx,sy); - pix3[0] = pix1[0]; - pix3[1] = pix1[1]; - pix3[2] = pix1[2]; - } - } - } - - zfree(pmap); - - if (Factivearea) // area edge blending - { - for (ii = 0; ii < Fww * Fhh; ii++) // find pixels in select area - { - dist = sa_pixmap[ii]; - if (! dist || dist >= sa_blend) continue; - - py = ii / Fww; - px = ii - py * Fww; - pix1 = PXMpix(E1pxm16,px,py); // input pixel, unchanged image - pix3 = PXMpix(E3pxm16,px,py); // output pixel, changed image - - f2 = 1.0 * dist / sa_blend; // changes over distance sa_blend - f1 = 1.0 - f2; - - pix3[0] = f1 * pix1[0] + f2 * pix3[0]; // blend the pixels - pix3[1] = f1 * pix1[1] + f2 * pix3[1]; - pix3[2] = f1 * pix1[2] + f2 * pix3[2]; - } - } - - Fred = 0; - Ffuncbusy--; - mwpaint2(); // update window - return; -} - - -/**************************************************************************/ - -// pixel edit function - edit individual pixels - -#define pixed_undomaxmem (1000 * mega) // pixel edit max. memory v.11.04 -#define pixed_undomaxpix (mega) // pixel edit max. pixel blocks - -void pixed_mousefunc(); -void pixed_dopixels(int px, int py); -void pixed_undo1(); -void pixed_freeundo(); - -int pixed_RGB[3]; -int pixed_mode; -int pixed_radius; -double pixed_kernel[200][200]; // radius <= 99 - -int pixed_undototpix = 0; // total undo pixel blocks -int pixed_undototmem = 0; // total undo memory allocated -int pixed_undoseq = 0; // undo sequence no. -char pixed_undomemmessage[100]; // translated undo memory message - -typedef struct { // pixel block before edit - int seq; // undo sequence no. - uint16 npix; // no. pixels in this block - uint16 px, py; // center pixel (radius org.) - uint16 radius; // radius of pixel block - uint16 pixel[][3]; // array of pixel[npix][3] -} pixed_savepix; - -pixed_savepix **pixed_undopixmem = 0; // array of *pixed_savepix - -editfunc EFpixed; - - -void m_pixedit(GtkWidget *, cchar *) -{ - int pixed_dialog_event(zdialog* zd, cchar *event); - - char undomemmessage[100]; - - zfuncs::F1_help_topic = "edit_pixels"; // v.10.8 - - EFpixed.funcname = "pixel-edit"; - EFpixed.Farea = 1; // select area ignored - EFpixed.Fpara = 1; // parallel edit OK - EFpixed.mousefunc = pixed_mousefunc; // mouse function - if (! edit_setup(EFpixed)) return; // setup edit - - strncpy0(pixed_undomemmessage,ZTX("Undo Memory %d%c"),99); // translate undo memory message - - zdialog *zd = zdialog_new(ZTX("Edit Pixels"),mWin,Bdone,Bcancel,null); - EFpixed.zd = zd; - - zdialog_add_widget(zd,"hbox","hbc","dialog",0,"space=5"); - zdialog_add_widget(zd,"label","labc","hbc",ZTX("color"),"space=8"); - zdialog_add_widget(zd,"colorbutt","color","hbc","100|100|100"); - zdialog_add_widget(zd,"label","space","hbc",0,"space=10"); - zdialog_add_widget(zd,"radio","radio1","hbc",ZTX("pick"),"space=3"); - zdialog_add_widget(zd,"radio","radio2","hbc",ZTX("paint"),"space=3"); - zdialog_add_widget(zd,"radio","radio3","hbc",ZTX("erase"),"space=3"); - zdialog_add_widget(zd,"hbox","hbbri","dialog",0,"space=5"); - zdialog_add_widget(zd,"vbox","vbbr1","hbbri",0,"homog|space=5"); - zdialog_add_widget(zd,"vbox","vbbr2","hbbri",0,"homog|space=5"); - zdialog_add_widget(zd,"label","space","hbbri",0,"space=10"); - zdialog_add_widget(zd,"vbox","vbbr3","hbbri",0,"homog|space=3"); - zdialog_add_widget(zd,"hbox","hbrad","vbbr1",0,"space=3"); - zdialog_add_widget(zd,"label","space","hbrad",0,"expand"); - zdialog_add_widget(zd,"label","labbr","hbrad",ZTX("paintbrush radius")); - zdialog_add_widget(zd,"label","labtc","vbbr1",ZTX("transparency center")); - zdialog_add_widget(zd,"label","labte","vbbr1",ZTX("transparency edge")); - zdialog_add_widget(zd,"spin","radius","vbbr2","1|99|1|5"); - zdialog_add_widget(zd,"spin","trcent","vbbr2","0|100|0.1|95"); // smaller steps v.11.10 - zdialog_add_widget(zd,"spin","tredge","vbbr2","0|100|0.1|100"); - zdialog_add_widget(zd,"button","undlast","vbbr3",Bundolast); - zdialog_add_widget(zd,"button","undall","vbbr3",Bundoall); - zdialog_add_widget(zd,"hbox","hb4","dialog"); - zdialog_add_widget(zd,"check","mymouse","hb4",BmyMouse,"space=20"); - zdialog_add_widget(zd,"label","labmem","hb4"); - - zdialog_help(zd,"edit_pixels"); // zdialog help topic v.11.08 - zdialog_run(zd,pixed_dialog_event,"save"); // run dialog, parallel v.11.07 - - zdialog_send_event(zd,"radius"); // get kernel initialized - - snprintf(undomemmessage,99,pixed_undomemmessage,0,'%'); // stuff undo memory status - zdialog_stuff(zd,"labmem",undomemmessage); - - pixed_RGB[0] = pixed_RGB[1] = pixed_RGB[2] = 100; // initialize color - - pixed_mode = 1; // mode = pick color - - pixed_undopixmem = 0; // no undo data - pixed_undototpix = 0; - pixed_undototmem = 0; - pixed_undoseq = 0; - - takeMouse(zd,pixed_mousefunc,drawcursor); // connect mouse function v.11.03 - return; -} - - -// dialog event and completion callback function - -int pixed_dialog_event(zdialog *zd, cchar *event) // pixedit dialog event function -{ - char color[20]; - cchar *pp; - int radius, dx, dy, brad, mymouse; - double rad, kern, trcent, tredge; - - if (zd->zstat) - { - if (zd->zstat == 1) edit_done(EFpixed); // done - else edit_cancel(EFpixed); // cancel or destroy - pixed_freeundo(); // free undo memory - return 0; - } - - edit_takeover(EFpixed); // set my edit function - - paint_toparc(2); // v.11.04 - - if (strEqu(event,"mymouse")) { // toggle mouse capture v.10.12 - zdialog_fetch(zd,"mymouse",mymouse); - if (mymouse) // connect mouse function v.11.03 - takeMouse(zd,pixed_mousefunc,drawcursor); - else freeMouse(); // disconnect mouse - } - - zdialog_fetch(zd,"radio1",brad); // pick - if (brad) pixed_mode = 1; - zdialog_fetch(zd,"radio2",brad); // paint - if (brad) pixed_mode = 2; - zdialog_fetch(zd,"radio3",brad); // erase - if (brad) pixed_mode = 3; - - if (strEqu(event,"color")) - { - zdialog_fetch(zd,"color",color,19); // get color from color wheel - pp = strField(color,"|",1); - if (pp) pixed_RGB[0] = atoi(pp); - pp = strField(color,"|",2); - if (pp) pixed_RGB[1] = atoi(pp); - pp = strField(color,"|",3); - if (pp) pixed_RGB[2] = atoi(pp); - } - - if (strstr("radius trcent tredge",event)) // get new brush attributes - { - zdialog_fetch(zd,"radius",radius); // radius - zdialog_fetch(zd,"trcent",trcent); // center transparency - zdialog_fetch(zd,"tredge",tredge); // edge transparency - - pixed_radius = radius; - trcent = 0.01 * trcent; // scale 0 ... 1 - tredge = 0.01 * tredge; - tredge = (1 - trcent) * (1 - tredge); - tredge = 1 - tredge; - trcent = sqrt(trcent); // speed up the curve - tredge = sqrt(tredge); - - for (dy = -radius; dy <= radius; dy++) // build kernel - for (dx = -radius; dx <= radius; dx++) - { - rad = sqrt(dx*dx + dy*dy); - kern = (radius - rad) / radius; // 1 ... 0 - kern = kern * (trcent - tredge) + tredge; // trcent ... tredge - if (rad > radius) kern = 1; - if (kern < 0) kern = 0; - if (kern > 1) kern = 1; - pixed_kernel[dx+radius][dy+radius] = kern; - } - } - - if (strEqu(event,"undlast")) // undo last edit (click or drag) - pixed_undo1(); - - if (strEqu(event,"undall")) { // undo all edits - edit_reset(); // v.10.3 - pixed_freeundo(); - } - - return 1; -} - - -// pixel edit mouse function - -void pixed_mousefunc() -{ - static int pmxdown = 0, pmydown = 0; - int px, py; - char color[20]; - uint16 *ppix3; - zdialog *zd = EFpixed.zd; - - edit_takeover(EFpixed); // set my edit function - - if (LMclick) // left mouse click - { - LMclick = 0; - px = Mxclick; - py = Myclick; - - if (pixed_mode == 1) // pick new color from image - { - ppix3 = PXMpix(E3pxm16,px,py); - pixed_RGB[0] = ppix3[0] / 256; - pixed_RGB[1] = ppix3[1] / 256; - pixed_RGB[2] = ppix3[2] / 256; - snprintf(color,19,"%d|%d|%d",pixed_RGB[0],pixed_RGB[1],pixed_RGB[2]); - if (zd) zdialog_stuff(zd,"color",color); - } - else { // paint or erase - pixed_undoseq++; // new undo seq. no. - paint_toparc(2); - pixed_dopixels(px,py); // do 1 block of pixels - } - } - - if (RMclick) - { - RMclick = 0; - paint_toparc(2); - pixed_undo1(); // undo last paint v.10.11 - } - - if (Mxdrag || Mydrag) // drag in progress - { - px = Mxdrag; - py = Mydrag; - Mxdrag = Mydrag = 0; - - if (Mxdown != pmxdown || Mydown != pmydown) { // new drag - pixed_undoseq++; // new undo seq. no. - pmxdown = Mxdown; - pmydown = Mydown; - } - paint_toparc(2); - pixed_dopixels(px,py); // do 1 block of pixels - } - - toparcx = Mxposn - pixed_radius; // define brush outline circle - toparcy = Myposn - pixed_radius; - toparcw = toparch = 2 * pixed_radius; - - if (pixed_mode == 1) Ftoparc = 0; - else Ftoparc = 1; - if (Ftoparc) paint_toparc(3); - - return; -} - - -// paint or erase 1 block of pixels within radius of px, py - -void pixed_dopixels(int px, int py) -{ - void pixed_saveundo(int px, int py); - - uint16 *ppix1, *ppix3; - int radius, dx, dy, qx, qy, ii, ww, dist; - int red, green, blue; - double kern; - - edit_zapredo(); // delete redo copy v.10.3 - - pixed_saveundo(px,py); // save pixels for poss. undo v.10.12.1 - - red = 256 * pixed_RGB[0]; - green = 256 * pixed_RGB[1]; - blue = 256 * pixed_RGB[2]; - - radius = pixed_radius; - - for (dy = -radius; dy <= radius; dy++) // loop surrounding block of pixels - for (dx = -radius; dx <= radius; dx++) - { - qx = px + dx; - qy = py + dy; - - if (qx < 0 || qx > E3ww-1) continue; - if (qy < 0 || qy > E3hh-1) continue; - - if (Factivearea) { // select area active v.10.11 - ii = qy * E3ww + qx; - dist = sa_pixmap[ii]; - if (! dist) continue; // pixel is outside area - } - - kern = pixed_kernel[dx+radius][dy+radius]; - ppix1 = PXMpix(E1pxm16,qx,qy); // original image pixel - ppix3 = PXMpix(E3pxm16,qx,qy); // edited image pixel - - if (pixed_mode == 2) // color pixels transparently - { - ppix3[0] = (1.0 - kern) * red + kern * ppix3[0]; - ppix3[1] = (1.0 - kern) * green + kern * ppix3[1]; - ppix3[2] = (1.0 - kern) * blue + kern * ppix3[2]; - CEF->Fmod = 1; - } - - if (pixed_mode == 3) // restore org. pixels transparently - { - ppix3[0] = (1.0 - kern) * ppix1[0] + kern * ppix3[0]; - ppix3[1] = (1.0 - kern) * ppix1[1] + kern * ppix3[1]; - ppix3[2] = (1.0 - kern) * ppix1[2] + kern * ppix3[2]; - } - } - - px = px - radius - 1; - py = py - radius - 1; - ww = 2 * radius + 3; - mwpaint3(px,py,ww,ww); // v.10.11 - return; -} - - -// save 1 block of pixels for possible undo - -void pixed_saveundo(int px, int py) -{ - int npix, radius, dx, dy; - uint16 *ppix3; - pixed_savepix *ppixsave1; - char undomemmessage[100]; - int mempercent; - static int ppercent = 0; - zdialog *zd = EFpixed.zd; - - if (! pixed_undopixmem) // first call - { - pixed_undopixmem = (pixed_savepix **) zmalloc(pixed_undomaxpix * sizeof(void *),"pixed"); - pixed_undototpix = 0; - pixed_undototmem = 0; - } - - if (pixed_undototmem > pixed_undomaxmem) - { - zmessageACK(mWin,ZTX("Undo memory limit has been reached. \n" - "Save work with [done], then resume editing.")); - Mdrag = 0; - return; - } - - radius = pixed_radius; - npix = 0; - - for (dy = -radius; dy <= radius; dy++) // count pixels in block - for (dx = -radius; dx <= radius; dx++) - { - if (px + dx < 0 || px + dx > E3ww-1) continue; - if (py + dy < 0 || py + dy > E3hh-1) continue; - npix++; - } - - ppixsave1 = (pixed_savepix *) zmalloc(npix*6+12,"pixed"); // allocate memory for block - pixed_undopixmem[pixed_undototpix] = ppixsave1; - pixed_undototpix += 1; - pixed_undototmem += npix * 6 + 12; - - ppixsave1->seq = pixed_undoseq; // save pixel block poop - ppixsave1->npix = npix; - ppixsave1->px = px; - ppixsave1->py = py; - ppixsave1->radius = radius; - - npix = 0; - - for (dy = -radius; dy <= radius; dy++) // save pixels in block - for (dx = -radius; dx <= radius; dx++) - { - if (px + dx < 0 || px + dx > E3ww-1) continue; - if (py + dy < 0 || py + dy > E3hh-1) continue; - ppix3 = PXMpix(E3pxm16,(px+dx),(py+dy)); // edited image pixel - ppixsave1->pixel[npix][0] = ppix3[0]; - ppixsave1->pixel[npix][1] = ppix3[1]; - ppixsave1->pixel[npix][2] = ppix3[2]; - npix++; - } - - mempercent = int(100.0 * pixed_undototmem / pixed_undomaxmem); // update undo memory status - if (mempercent != ppercent) { - ppercent = mempercent; - snprintf(undomemmessage,99,pixed_undomemmessage,mempercent,'%'); - zdialog_stuff(zd,"labmem",undomemmessage); - } - - return; -} - - -// undo last undo sequence number - -void pixed_undo1() -{ - int pindex, npix, radius, mempercent; - int ww, px, py, dx, dy; - uint16 *ppix3; - pixed_savepix *ppixsave1; - char undomemmessage[100]; - zdialog *zd = EFpixed.zd; - - pindex = pixed_undototpix; - - while (pindex > 0) - { - --pindex; - ppixsave1 = pixed_undopixmem[pindex]; - if (ppixsave1->seq != pixed_undoseq) break; - px = ppixsave1->px; - py = ppixsave1->py; - radius = ppixsave1->radius; - - npix = 0; - for (dy = -radius; dy <= radius; dy++) - for (dx = -radius; dx <= radius; dx++) - { - if (px + dx < 0 || px + dx > E3ww-1) continue; - if (py + dy < 0 || py + dy > E3hh-1) continue; - ppix3 = PXMpix(E3pxm16,(px+dx),(py+dy)); - ppix3[0] = ppixsave1->pixel[npix][0]; - ppix3[1] = ppixsave1->pixel[npix][1]; - ppix3[2] = ppixsave1->pixel[npix][2]; - npix++; - } - - px = px - radius - 1; // v.10.12 - py = py - radius - 1; - ww = 2 * radius + 3; - mwpaint3(px,py,ww,ww); - - npix = ppixsave1->npix; - zfree(ppixsave1); - pixed_undopixmem[pindex] = 0; - pixed_undototmem -= (npix * 6 + 12); - --pixed_undototpix; - } - - if (pixed_undoseq > 0) --pixed_undoseq; - - mempercent = int(100.0 * pixed_undototmem / pixed_undomaxmem); // update undo memory status - snprintf(undomemmessage,99,pixed_undomemmessage,mempercent,'%'); - zdialog_stuff(zd,"labmem",undomemmessage); - - return; -} - - -// free all undo memory - -void pixed_freeundo() -{ - int pindex; - pixed_savepix *ppixsave1; - char undomemmessage[100]; - zdialog *zd = EFpixed.zd; - - pindex = pixed_undototpix; - - while (pindex > 0) - { - --pindex; - ppixsave1 = pixed_undopixmem[pindex]; - zfree(ppixsave1); - } - - if (pixed_undopixmem) zfree(pixed_undopixmem); - pixed_undopixmem = 0; - - pixed_undoseq = 0; - pixed_undototpix = 0; - pixed_undototmem = 0; - - if (zd) { - snprintf(undomemmessage,99,pixed_undomemmessage,0,'%'); // undo memory = 0% - zdialog_stuff(zd,"labmem",undomemmessage); - } - - return; -} - - - diff -Nru fotoxx-11.11.1/fotoxx_tools.cc fotoxx-12.01.2/fotoxx_tools.cc --- fotoxx-11.11.1/fotoxx_tools.cc 2011-11-05 05:30:36.000000000 +0000 +++ fotoxx-12.01.2/fotoxx_tools.cc 1970-01-01 00:00:00.000000000 +0000 @@ -1,3447 +0,0 @@ -/************************************************************************** - - Fotoxx edit photos and manage collections - - Copyright 2007 2008 2009 2010 2011 Michael Cornelison - Source URL: http://kornelix.squarespace.com/fotoxx - Contact: kornelix2@googlemail.com - - 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 http://www.gnu.org/licenses/. - -***************************************************************************/ - -#define EX extern // enable extern declarations -#include "fotoxx.h" - - -/************************************************************************** - - Fotoxx image edit - Tools menu functions - -***************************************************************************/ - - -// Manage Collections - -void m_manage_collections(GtkWidget *, cchar *) // v.11.11 -{ - int manage_coll_dialog_event(zdialog *zd, cchar *event); // manage collectiond dialog event func - - zdialog *zd; - cchar *helptext = ZTX("When editing a collection, right-click \n" - "an image or thumbnail to add or remove."); - - zfuncs::F1_help_topic = "manage_collections"; - - if (mod_keep()) return; // unsaved edits - -/*** - __________________________________________ - | | - | Manage Collections | - | | - | When editing a collection, right-click | - | an image or thumbnail to add or remove. | - | | - | [New] Start a new collection | - | [Edit] Edit a collection | - | [View] View a collection | - | [Delete] Delete a collection | - | | - | Editing: | - | Action: xxxxxxxxxxxxxx | - | | - | [Done] | - |__________________________________________| - -***/ - - zd = zdialog_new(ZTX("Manage Collections"),0,Bdone,null); - zd_edit_coll = zd; - - zdialog_add_widget(zd,"label","labhelp","dialog",helptext,"space=5"); - - zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=3"); - zdialog_add_widget(zd,"vbox","vb1","hb1",0,"homog|space=5"); - zdialog_add_widget(zd,"vbox","vb2","hb1",0,"homog|space=5"); - - zdialog_add_widget(zd,"button","new","vb1",Bnew); - zdialog_add_widget(zd,"button","edit","vb1",Bedit); - zdialog_add_widget(zd,"button","view","vb1",Bview); - zdialog_add_widget(zd,"button","delete","vb1",Bdelete); - - zdialog_add_widget(zd,"hbox","hbnew","vb2"); - zdialog_add_widget(zd,"label","labnew","hbnew",ZTX("Start new collection")); - zdialog_add_widget(zd,"hbox","hbedit","vb2"); - zdialog_add_widget(zd,"label","labedit","hbedit",ZTX("Edit a collection")); - zdialog_add_widget(zd,"hbox","hbview","vb2"); - zdialog_add_widget(zd,"label","labview","hbview",ZTX("View a collection")); - zdialog_add_widget(zd,"hbox","hbdel","vb2"); - zdialog_add_widget(zd,"label","labdel","hbdel",ZTX("Delete a collection")); - - zdialog_add_widget(zd,"hsep","sep","dialog",0,"space=3"); - zdialog_add_widget(zd,"hbox","hbedit","dialog"); - zdialog_add_widget(zd,"label","labedit","hbedit",ZTX("Editing:"),"space=3"); - zdialog_add_widget(zd,"label","editcoll","hbedit",0,"space=3"); - - zdialog_add_widget(zd,"hbox","hbact","dialog",0,"space=3"); - zdialog_add_widget(zd,"label","labact","hbact",ZTX("Action:"),"space=3"); - zdialog_add_widget(zd,"label","lastact","hbact",0,"space=3"); - - zdialog_help(zd,"manage_collections"); - zdialog_resize(zd,300,0); - zdialog_run(zd,manage_coll_dialog_event); - zdialog_wait(zd); - zdialog_free(zd); - zd_edit_coll = 0; - - if (edit_coll_name) zfree(edit_coll_name); // no collection for editing - edit_coll_name = 0; - - return; -} - - -// manage collections dialog event and completion function - -int manage_coll_dialog_event(zdialog *zd, cchar *event) // v.11.11 -{ - int err; - FILE *fid; - char *pp; - struct stat statb; - - if (strEqu(event,"new")) // start a new collection for editing - { - if (edit_coll_name) { // no current collection - zfree(edit_coll_name); - edit_coll_name = 0; - } - - if (edit_coll_file) zfree(edit_coll_file); - edit_coll_file = zgetfile1(ZTX("New Collection"),"save",collections_dirk); - if (! edit_coll_file) return 0; - - fid = fopen(edit_coll_file,"w"); // open collection file - if (! fid) return 0; - fprintf(fid,"Fotoxx Collection \n"); // write one record - fclose(fid); - - pp = strrchr(edit_coll_file,'/'); // file name = collection name - edit_coll_name = strdupz(pp+1); // set current edit collection - - zdialog_stuff(zd,"editcoll",edit_coll_name); - return 0; - } - - if (strEqu(event,"edit")) // choose a collection for editing - { - if (edit_coll_name) { // no current collection - zfree(edit_coll_name); - edit_coll_name = 0; - } - - if (edit_coll_file) zfree(edit_coll_file); - edit_coll_file = zgetfile1(ZTX("Edit Collection"),"open",collections_dirk); - if (! edit_coll_file) return 0; - - err = stat(edit_coll_file,&statb); - if (err) return 0; - - pp = strrchr(edit_coll_file,'/'); // file name = collection name - edit_coll_name = strdupz(pp+1); // set current edit collection - - zdialog_stuff(zd,"editcoll",edit_coll_name); - return 0; - } - - if (strEqu(event,"view")) // choose a collection for viewing - { - if (edit_coll_file) zfree(edit_coll_file); - edit_coll_file = zgetfile1(ZTX("View Collection"),"open",collections_dirk); - if (! edit_coll_file) return 0; - - err = stat(edit_coll_file,&statb); - if (err) return 0; - - image_gallery(edit_coll_file,"initF",0,m_gallery2,mWin); // generate gallery of files in coll. - - if (edit_coll_memberfile) zfree(edit_coll_memberfile); - edit_coll_memberfile = image_gallery(0,"find",0); // top of list - if (! edit_coll_memberfile) return 0; - f_open(edit_coll_memberfile,1); // open first file - zmainloop(); - - image_gallery(0,"paint1"); // show new image gallery window - return 0; - } - - if (strEqu(event,"delete")) // choose collection to delete - { - if (edit_coll_file) zfree(edit_coll_file); - edit_coll_file = zgetfile1(ZTX("Delete Collection"),"open",collections_dirk); - if (! edit_coll_file) return 0; - - if (! zmessageYN(mWin,ZTX("delete %s ?"),edit_coll_file)) return 0; - - remove(edit_coll_file); // delete it - return 0; - } - - return 0; -} - - -// Popup menu for editing a collection. -// This function is called when a thumbnail is right-clicked. - -void edit_coll_popmenu(GtkWidget *, char *file) -{ - void edit_coll_popfunc(GtkWidget *, cchar *menu); - - GtkWidget *popmenu; - static char addmenuitem[200]; - - if (! edit_coll_name) return; // no edit in progress, do nothing - - if (edit_coll_memberfile) zfree(edit_coll_memberfile); // save clicked thumbnail file - edit_coll_memberfile = strdupz(file,0,"edit_coll"); - - popmenu = create_popmenu(); // create popup menu - - snprintf(addmenuitem,200,ZTX("add image to collection: %s"),edit_coll_name); - add_popmenu_item(popmenu,addmenuitem,edit_coll_popfunc); - add_popmenu_item(popmenu,ZTX("remove image from collection"),edit_coll_popfunc); - add_popmenu_item(popmenu,ZTX("remove and save image"),edit_coll_popfunc); - add_popmenu_item(popmenu,ZTX("insert saved images here"),edit_coll_popfunc); - - popup_menu(popmenu); - return; -} - - -// Response function for the edit collections popup menu - -void edit_coll_popfunc(GtkWidget *, cchar *menu) -{ - int ii, found = 0; - FILE *fidr, *fidw; - char collfile[maxfcc], buff[maxfcc]; - char *filename, tempfile[200]; - - static char *saved_files[100]; - static int Nsaved = 0; - - if (! edit_coll_name) return; // no edit in progress, do nothing - if (! edit_coll_memberfile) return; // no member file for action - if (! zd_edit_coll) return; - - strcpy(collfile,collections_dirk); // edit collection full path - strcat(collfile,edit_coll_name); - - strcpy(tempfile,collections_dirk); // temp file for copying - strcat(tempfile,"tempfile"); - - if (strnEqu(menu,ZTX("add image to collection"),23)) - { - fidw = fopen(collfile,"a"); // append new file at end of list - if (! fidw) return; - fprintf(fidw,"%s\n",edit_coll_memberfile); - fclose(fidw); - - filename = strrchr(edit_coll_memberfile,'/') + 1; // notify in dialog window - sprintf(buff,"Add: %s",filename); - zdialog_stuff(zd_edit_coll,"lastact",buff); - - return; - } - - if (strEqu(menu,ZTX("remove image from collection")) || - strEqu(menu,ZTX("remove and save image"))) - { - fidr = fopen(collfile,"r"); // copy collection file and omit - if (! fidr) return; // the image file being removed - fidw =fopen(tempfile,"w"); - if (! fidw) return; - - while (true) - { - filename = fgets_trim(buff,maxfcc,fidr); - if (! filename) break; - if (strEqu(filename,edit_coll_memberfile)) { - found = 1; - continue; - } - fprintf(fidw,"%s\n",filename); - } - - fclose(fidr); - fclose(fidw); - rename(tempfile,collfile); - - filename = strrchr(edit_coll_memberfile,'/') + 1; // notify in dialog window - if (found) sprintf(buff,"Removed: %s",filename); - else sprintf(buff,"Not found: %s",filename); - zdialog_stuff(zd_edit_coll,"lastact",buff); - - if (found && strEqu(menu,ZTX("remove and save image"))) // add file to list of saved files - { - if (Nsaved > 99) { - zmessageACK(mWin,ZTX("too many saved files")); - return; - } - saved_files[Nsaved] = strdupz(edit_coll_memberfile,0,"edit_coll"); - Nsaved++; - } - - if (strEqu(collfile,image_navi::galleryname)) { - image_gallery(collfile,"initF",0,m_gallery2,mWin); // update gallery window - image_gallery(0,"paint2",-1); - } - - return; - } - - if (strEqu(menu,ZTX("insert saved images here"))) - { - if (! Nsaved) return; - if (strNeq(collfile,image_navi::galleryname)) return; // gallery not the edit collection - - fidr = fopen(collfile,"r"); // copy collection file and insert - if (! fidr) return; // the saved image files - fidw =fopen(tempfile,"w"); - if (! fidw) return; - - while (true) - { - filename = fgets_trim(buff,maxfcc,fidr); - if (! filename) break; - fprintf(fidw,"%s\n",filename); - if (strNeq(filename,edit_coll_memberfile)) continue; - for (ii = 0; ii < Nsaved; ii++) { - fprintf(fidw,"%s\n",saved_files[ii]); - zfree(saved_files[ii]); - } - } - - fclose(fidr); - fclose(fidw); - rename(tempfile,collfile); - - sprintf(buff,"inserted %d files",Nsaved); - zdialog_stuff(zd_edit_coll,"lastact",buff); - Nsaved = 0; - - image_gallery(collfile,"initF",0,m_gallery2,mWin); // update gallery window - image_gallery(0,"paint2",-1); - - return; - } -} - - -/**************************************************************************/ - -// Change the top directory for all image collections. -// This facilitates changing the Fotoxx top image directory -// without having to re-create all collections. - -void m_move_collections(GtkWidget *, cchar *) -{ - zdialog *zd; - char *pp, oldtop[200], newtop[200]; - char command[200], buffr[maxfcc], buffw[maxfcc]; - char collfile[200], tempfile[200]; - int zstat, contx = 0, err; - FILE *fidr, *fidw; - - zfuncs::F1_help_topic = "move_collections"; - - if (mod_keep()) return; // unsaved edits - - zd = zdialog_new(ZTX("Move Collections"),0,Bapply,Bcancel,null); - zdialog_add_widget(zd,"hbox","hbold","dialog",0,"space=5"); - zdialog_add_widget(zd,"label","labold","hbold",ZTX("old top directory"),"space=5"); - zdialog_add_widget(zd,"entry","oldtop","hbold",0,"scc=30"); - zdialog_add_widget(zd,"hbox","hbnew","dialog",0,"space=5"); - zdialog_add_widget(zd,"label","labnew","hbnew",ZTX("new top directory"),"space=5"); - zdialog_add_widget(zd,"entry","newtop","hbnew",0,"scc=30"); - - zdialog_stuff(zd,"oldtop",topdirk); - zdialog_stuff(zd,"newtop",topdirk); - - zdialog_help(zd,"move_collections"); - zdialog_run(zd); - - zstat = zdialog_wait(zd); - if (zstat != 1) { - zdialog_free(zd); - return; - } - - zdialog_fetch(zd,"oldtop",oldtop,200); // old and new top directory paths - zdialog_fetch(zd,"newtop",newtop,200); - zdialog_free(zd); - - snprintf(tempfile,200,"%s/move-collection",get_zuserdir()); - - snprintf(command,200,"find -L %s -type f",collections_dirk); // find all collections - printf("%s \n",command); - - while ((pp = command_output(contx,command,null))) // loop all collections - { - printf("%s \n",pp); - strncpy0(collfile,pp,200); - zfree(pp); - - fidr = fopen(collfile,"r"); // open collection and temp files - if (! fidr) break; - - fidw = fopen(tempfile,"w"); - if (! fidw) break; - - while ((pp = fgets(buffr,maxfcc,fidr))) // loop collection recs - { - repl_1str(buffr,buffw,oldtop,newtop); // replace top directory path - err = fputs(buffw,fidw); - if (err < 0) break; - } - - err = fclose(fidr); - err = fclose(fidw); - if (err) break; - - err = rename(tempfile,collfile); // replace collection with temp file - if (err) break; - } - - if (err) { - err = errno; - printf("%s \n %s \n",collfile,strerror(err)); - zmessageACK(mWin,"%s \n %s",collfile,strerror(err)); - } - else zmessageACK(mWin,ZTX("completed")); - - return; -} - - -/**************************************************************************/ - -// monitor test function - -void m_moncheck(GtkWidget *, cchar *) -{ - uint8 *pixel; - int red, green, blue; - int row, col, row1, row2; - int ww = 800, hh = 500; - zdialog *zd; - - cchar *message = ZTX("Brightness should show a gradual ramp \n" - "extending all the way to the edges."); - - zfuncs::F1_help_topic = "check_monitor"; - - if (mod_keep()) return; // unsaved edits - if (! menulock(1)) return; - mutex_lock(&Fpixmap_lock); - - PXM_free(Fpxm8); - Fpxm8 = PXM_make(ww,hh,8); - Fww = ww; - Fhh = hh; - curr_file_bpc = 8; - curr_file_size = 0; - - for (red = 0; red <= 1; red++) // 8 RGB combinations - for (green = 0; green <= 1; green++) - for (blue = 0; blue <= 1; blue++) - { - row1 = 4 * red + 2 * green + blue; // row 0 to 7 - row1 = row1 * hh / 8; // stripe, 1/8 of image - row2 = row1 + hh / 8; - - for (row = row1; row < row2; row++) - for (col = 0; col < ww; col++) - { - pixel = PXMpix8(Fpxm8,col,row); - pixel[0] = red * 256 * col / ww; - pixel[1] = green * 256 * col / ww; - pixel[2] = blue * 256 * col / ww; - } - } - - Fzoom = 0; // scale to window - gtk_window_set_title(MWIN,"monitor check"); - mutex_unlock(&Fpixmap_lock); - mwpaint2(); // repaint window - curr_image_time = get_seconds(); // mark time of image change v.11.07 - - zd = zdialog_new(ZTX("Monitor Check"),mWin,Bdone,null); // start user dialog v.11.04 - zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=5"); - zdialog_add_widget(zd,"label","lab1","hb1",message,"space=5"); - - zdialog_resize(zd,200,0); - zdialog_help(zd,"check_monitor"); // zdialog help topic v.11.08 - zdialog_run(zd); - zdialog_wait(zd); // wait for dialog complete - zdialog_free(zd); - - f_open(curr_file,0); // back to current file v.11.04 - menulock(0); - return; -} - - -/**************************************************************************/ - -// adjust monitor gamma - -void m_mongamma(GtkWidget *, cchar *) // revised v.11.04 -{ - int mongamma_event(zdialog *zd, cchar *event); - char gammachart[200]; - - zdialog *zd; - cchar *permit = "Chart image courtesy of Norman Koren"; - cchar *website1 = "http://www.normankoren.com"; - cchar *website2 = "http://www.imatest.org"; - PXM *pxmtemp; - - zfuncs::F1_help_topic = "monitor_gamma"; - - if (mod_keep()) return; // unsaved edits - if (! menulock(1)) return; - - snprintf(gammachart,200,"%s/images/gammachart.png",get_zdocdir()); // gamma chart .png file - pxmtemp = PXBread(gammachart); - if (! pxmtemp) { - zmessageACK(mWin,"gamma chart is missing"); - menulock(0); - return; - } - - mutex_lock(&Fpixmap_lock); // curr. image = gamma chart - PXM_free(Fpxm8); - Fpxm8 = pxmtemp; - Fww = Fpxm8->ww; - Fhh = Fpxm8->hh; - curr_file_bpc = 8; - curr_file_size = 0; - - Fzoom = 1; // scale 100% (required) - gtk_window_set_title(MWIN,"adjust gamma chart"); - mutex_unlock(&Fpixmap_lock); - mwpaint2(); // repaint window - curr_image_time = get_seconds(); // mark time of image change v.11.07 - - zd = zdialog_new(ZTX("Monitor Gamma"),mWin,Bdone,null); // start user dialog - zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=8"); - zdialog_add_widget(zd,"label","labgamma","hb1","gamma","space=5"); - zdialog_add_widget(zd,"hscale","gamma","hb1","0.6|1.4|0.02|1.0","expand"); - zdialog_add_widget(zd,"hbox","hb2","dialog"); - zdialog_add_widget(zd,"label","permit","hb2",permit,"space=5"); - zdialog_add_widget(zd,"hbox","hb3","dialog"); - zdialog_add_widget(zd,"link","web1","hb3",website1); - zdialog_add_widget(zd,"hbox","hb4","dialog"); - zdialog_add_widget(zd,"link","web2","hb4",website2); - - zdialog_resize(zd,200,0); - zdialog_help(zd,"monitor_gamma"); // zdialog help topic v.11.08 - zdialog_run(zd,mongamma_event); - zdialog_wait(zd); // wait for dialog complete - zdialog_free(zd); - - f_open(curr_file,0); // back to current file v.11.04 - menulock(0); - return; -} - - -// dialog event function - -int mongamma_event(zdialog *zd, cchar *event) -{ - int err; - double gamma; - - if (strEqu(event,"gamma")) { - zdialog_fetch(zd,"gamma",gamma); - sprintf(command,"xgamma -quiet -gamma %.2f",gamma); - err = system(command); - if (err) zmessageACK(mWin,"error: %s",wstrerror(err)); - } - - return 0; -} - - -/**************************************************************************/ - -// create or update brightness histogram graph - -GtkWidget *winhisto = 0; // brightness histogram window -GtkWidget *winhistoH = 0; // histogram drawing area -GtkWidget *winhistoB = 0; // brightness band underneath - - -void m_histogram(GtkWidget *, cchar *menu) // menu function -{ - if (menu) zfuncs::F1_help_topic = "brightness_graph"; - - if (! Dpxm8) return; - - if (winhisto) { // window already present - histogram_paint(); - return; - } - - winhisto = gtk_window_new(GTK_WINDOW_TOPLEVEL); // create histogram window - gtk_window_set_title(GTK_WINDOW(winhisto),ZTX("Brightness Distribution")); - gtk_window_set_transient_for(GTK_WINDOW(winhisto),MWIN); - gtk_window_set_default_size(GTK_WINDOW(winhisto),300,200); - GtkWidget * vbox = gtk_vbox_new(0,3); - gtk_container_add(GTK_CONTAINER(winhisto),vbox); - - winhistoH = gtk_drawing_area_new(); // histogram drawing area - gtk_box_pack_start(GTK_BOX(vbox),winhistoH,1,1,3); - - winhistoB = gtk_drawing_area_new(); // brightness scale under histogram - gtk_box_pack_start(GTK_BOX(vbox),winhistoB,0,0,0); // (progresses from black to white) - gtk_widget_set_size_request(winhistoB,300,12); // v.9.3 - - G_SIGNAL(winhisto,"destroy",histogram_destroy,0) - G_SIGNAL(winhistoH,"expose-event",histogram_paint,0) - G_SIGNAL(winhistoB,"expose-event",histogram_paint,0) - - gtk_widget_show_all(winhisto); - - return; -} - - -void histogram_paint() // paint graph window -{ - GdkGC *gdkgc = 0; // GDK graphics context - GdkColor color; - GdkColormap *colormap = 0; - - int brdist[40], bin, nbins = 40; // increased v.9.3 - int dist_maxbin = 0; - int winww, winhh; - int px, py, ww, hh, orgx, orgy; - uint8 *pix8; - uint16 *pix16; - double bright; - - if (! winhisto) return; - if (! Dpxm8) return; - - gdkgc = gdk_gc_new(winhistoH->window); // use separate graphics context - colormap = gtk_widget_get_colormap(winhistoH); - - for (bin = 0; bin < nbins; bin++) // clear brightness distribution - brdist[bin] = 0; - - mutex_lock(&Fpixmap_lock); - - if (Factivearea && E3pxm16) // compute brightness distribution - { // for selected area being edited - for (int ii = 0; ii < Fww * Fhh; ii++) - { - if (! sa_pixmap[ii]) continue; - py = ii / Fww; - px = ii - Fww * py; - pix16 = PXMpix(E3pxm16,px,py); - bright = 0.003906 * pixbright(pix16); // 0 to 255 - brdist[int(bright / 256 * nbins)]++; // 0 to nbins - } - } - - else - { - for (py = 0; py < dhh; py++) // compute brightness distribution - for (px = 0; px < dww; px++) // for image in visible window - { - pix8 = (uint8 *) Dpxm8->bmp + (py * dww + px) * 3; - bright = pixbright(pix8); // 0 to 255 - brdist[int(bright / 256 * nbins)]++; // 0 to nbins - } - } - - for (bin = 0; bin < nbins; bin++) // find max. bin - if (brdist[bin] > dist_maxbin) dist_maxbin = brdist[bin]; - - mutex_unlock(&Fpixmap_lock); - - gdk_window_clear(winhistoH->window); - - winww = winhistoH->allocation.width; // drawing window size - winhh = winhistoH->allocation.height; - ww = winww / nbins; // bin width - bin = -1; - - color.red = 10000; // a pleasing color - color.green = 25000; - color.blue = 40000; - gdk_rgb_find_color(colormap,&color); - gdk_gc_set_foreground(gdkgc,&color); - - for (px = 0; px < winww; px++) // draw each bin - { - if (px * nbins / winww > bin) { - bin++; - hh = 0.9 * winhh * brdist[bin] / dist_maxbin; - orgx = px; - orgy = winhh - hh; - gdk_draw_rectangle(winhistoH->window,gdkgc,1,orgx,orgy,ww+1,hh); - } - } - - hh = winhistoB->allocation.height; - - for (px = 0; px < winww; px++) // draw brightness scale underneath - { // v.9.3 - color.red = color.green = color.blue = 65536 * px / winww; - gdk_rgb_find_color(colormap,&color); - gdk_gc_set_foreground(gdkgc,&color); - gdk_draw_line(winhistoB->window,gdkgc,px,0,px,hh-1); - } - - return; -} - - -void histogram_destroy() // delete window -{ - if (winhisto) gtk_widget_destroy(winhisto); - winhisto = 0; - return; -} - - -/**************************************************************************/ - -// enter or leave slideshow mode - -int ss_interval = 3; // slide show interval -int ss_timer = 0; // slide show timer -int ss_latest = 0; // show only latest revision files -char *ss_oldfile, *ss_newfile; // image files for transition -PXM *ss_pxmold, *ss_pxmnew, *ss_pxmmix; // pixmap images: old, new, mixed -int ss_ww, ss_hh; // full screen window size -int ss_busy = 0; // transition underway -int ss_escape = 0; // user pressed Escape key -int ss_paused = 0; // user pressed P key (pause/resume) - -void ss_instant(); // transition functions -void ss_fadein(); -void ss_rollright(); -void ss_rolldown(); -void ss_shiftleft(); -void ss_venetian(); -void ss_grate(); -void ss_rectangle(); -void ss_ellipse(); -void ss_radar(); -void ss_jaws(); -char * ss_prev(int posn); -char * ss_next(int posn); -char * ss_prev_latest(int posn); -char * ss_next_latest(int posn); -char * ss_basename(char *file); - - -struct ss_table_t { - cchar *name; - cchar *vbox; - void (*func)(); -}; - -ss_table_t ss_table[SSNF] = // image transition types -{ - { "arrow keys", "vb41", null }, // name, zdialog parent, function - { "instant", "vb41", ss_instant }, - { "fade-in", "vb41", ss_fadein }, - { "roll-right", "vb41", ss_rollright }, - { "roll-down", "vb42", ss_rolldown }, - { "shift-left", "vb42", ss_shiftleft }, - { "venetian", "vb42", ss_venetian }, - { "grate", "vb42", ss_grate }, - { "rectangle", "vb43", ss_rectangle }, - { "ellipse", "vb43", ss_ellipse }, - { "radar", "vb43", ss_radar }, - { "jaws", "vb43", ss_jaws } -}; - - -void m_slideshow(GtkWidget *, cchar *) -{ - int slideshow_dialog_event(zdialog *zd, cchar *event); - - zdialog *zd; - int zstat, secs, err, ii; - cchar *esc_message = ZTX("Press ESC to exit slide show"); - cchar *latest_message = ZTX("show only latest file versions"); - - zfuncs::F1_help_topic = "slide_show"; // v.10.8 - - ss_table[0].name = ZTX("arrow keys"); // use translated names - ss_table[1].name = ZTX("instant"); - ss_table[2].name = ZTX("fade-in"); - ss_table[3].name = ZTX("roll-right"); - ss_table[4].name = ZTX("roll-down"); - ss_table[5].name = ZTX("shift-left"); - ss_table[6].name = ZTX("venetian"); - ss_table[7].name = ZTX("grate"); - ss_table[8].name = ZTX("rectangle"); - ss_table[9].name = ZTX("ellipse"); - ss_table[10].name = ZTX("radar"); - ss_table[11].name = ZTX("jaws"); - - if (! Fslideshow) // start slide show - { - if (! curr_file) return; - if (! menulock(1)) return; - - zd = zdialog_new(ZTX("Slide Show"),mWin,Bproceed,Bcancel,null); // user dialog - zdialog_add_widget(zd,"hbox","hbesc","dialog",0,"space=3"); - zdialog_add_widget(zd,"label","labesc","hbesc",esc_message,"space=3"); - zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=3"); - zdialog_add_widget(zd,"label","labsecs","hb1",ZTX("seconds"),"space=3"); - zdialog_add_widget(zd,"entry","secs","hb1","3","scc=5"); - zdialog_add_widget(zd,"check","latest","hb1",latest_message,"space=8"); - zdialog_add_widget(zd,"hbox","hb2","dialog",0,"space=3"); - zdialog_add_widget(zd,"label","lab21","hb2",ZTX("music file"),"space=3"); - zdialog_add_widget(zd,"entry","musicfile","hb2",0,"scc=30|space=5"); - zdialog_add_widget(zd,"button","browse","hb2",Bbrowse,"space=5"); - zdialog_add_widget(zd,"hbox","hb3","dialog",0,"space=3"); - zdialog_add_widget(zd,"label","lab3","hb3",ZTX("transitions"),"space=3"); - zdialog_add_widget(zd,"hbox","hb4","dialog"); - zdialog_add_widget(zd,"vbox","vb41","hb4",0,"space=8"); - zdialog_add_widget(zd,"vbox","vb42","hb4",0,"space=8"); - zdialog_add_widget(zd,"vbox","vb43","hb4",0,"space=8"); - - for (ii = 0; ii < SSNF; ii++) { // add transition check boxes - zdialog_add_widget(zd,"check",ss_table[ii].name, - ss_table[ii].vbox,ss_table[ii].name); - if (ss_funcs[ii]) zdialog_stuff(zd,ss_table[ii].name,1); // restore user preferences - } - - if (ss_interval < 9999) - zdialog_stuff(zd,"secs",ss_interval); // stuff last time interval - zdialog_stuff(zd,"musicfile",ss_musicfile); // stuff last music file - - zdialog_help(zd,"slide_show"); // zdialog help topic v.11.08 - zdialog_run(zd,slideshow_dialog_event); // run dialog - zstat = zdialog_wait(zd); // wait for completion - - if (zstat != 1) { // cancel - zdialog_free(zd); - menulock(0); - return; - } - - zdialog_fetch(zd,"secs",secs); // get interval, seconds - zdialog_fetch(zd,"latest",ss_latest); // get "latest files only" option - - for (ii = 0; ii < SSNF; ii++) // get selected transition types - zdialog_fetch(zd,ss_table[ii].name,ss_funcs[ii]); // v.11.08 - - for (ii = 1; ii < SSNF; ii++) // check selections - if (ss_funcs[ii]) break; - if (ii < SSNF) ss_funcs[0] = 0; // if some, remove arrow keys - else ss_funcs[0] = 1; // if none, default arrow keys - - char *pp = zmalloc(500,"musicfile"); - zdialog_fetch(zd,"musicfile",pp,499); // get music file - ss_musicfile = pp; - - zdialog_free(zd); - - ss_interval = secs; // interval between slides - if (ss_funcs[0]) ss_interval = 9999; // if manual transition, huge interval - ss_paused = 0; // not paused v.11.10 - - if (ss_musicfile && *ss_musicfile && strNeq(ss_musicfile,"undefined")) - { // if music file present, start it up - sprintf(command,"xdg-open \"%s\" ",ss_musicfile); // v.11.04 - printf("command: %s \n",command); - err = system(command); - if (err) printf("error: %s \n",wstrerror(err)); - } - - gtk_widget_hide_all(GTK_WIDGET(mMbar)); // enter slide show mode - gtk_widget_hide_all(GTK_WIDGET(mTbar)); // (full screen, no extras) - gtk_widget_hide_all(GTK_WIDGET(STbar)); - - gdk_window_set_background(drWin->window,&black); // black background v.11.10 - - gtk_window_maximize(MWIN); // avoid gtk_window_fullscreen() - zmainloop(); // must wait for update v.11.10 - gtk_window_get_size(MWIN,&ss_ww,&ss_hh); - - ss_pxmold = PXM_make(ss_ww,ss_hh,8); // make 3 screen-size pixmaps - ss_pxmnew = PXM_make(ss_ww,ss_hh,8); - ss_pxmmix = PXM_make(ss_ww,ss_hh,8); - - ss_newfile = strdupz(curr_file); // start with current image - ss_oldfile = 0; - - ss_timer = get_seconds() + ss_interval; // set timer for first call to - Fslideshow = 1; // ss_slideshow_next() - } - - else // leave slide show mode - { - if (ss_busy) { - ss_escape = 1; // wait for transition done - return; - } - - ss_escape = 0; - Fslideshow = 0; - - gdk_window_set_background(drWin->window,&lgray); // restore background v.11.10 - - gtk_window_unmaximize(MWIN); // restore old window size v.11.10 - gtk_widget_show_all(GTK_WIDGET(mMbar)); - gtk_widget_show_all(GTK_WIDGET(mTbar)); - gtk_widget_show_all(GTK_WIDGET(STbar)); - - if (ss_newfile) zfree(ss_newfile); // free memory - if (ss_oldfile) zfree(ss_oldfile); - ss_newfile = ss_oldfile = 0; - PXM_free(ss_pxmold); - PXM_free(ss_pxmnew); - PXM_free(ss_pxmmix); - - menulock(0); - } - - Fblowup = Fslideshow; - Fzoom = 0; // fit image to window - mwpaint2(); - return; -} - - -// dialog event function - file chooser for music file - -int slideshow_dialog_event(zdialog *zd, cchar *event) // v.11.04 -{ - char *pp; - - if (! strEqu(event,"browse")) return 0; - pp = zgetfile1(ZTX("Select music file or playlist"),"open",ss_musicfile); - if (! pp) return 0; - zdialog_stuff(zd,"musicfile",pp); - zfree(pp); - return 0; -} - - -// Show next slide if time is up or user navigates with arrow keys. -// Called by timer function and by keyboard function if Fslideshow is set. - -void slideshow_next(cchar *mode) // new v.11.01 -{ - void ss_loadimage(char *file, PXM *pxmout); - - double secs; - char *pp = 0; - int Fkey = 0, cp, ii; - static int last_transition = 0; - - if (strEqu(mode,"pause")) // toggle slide show paused status - ss_paused = 1 - ss_paused; // (spacebar) v.11.10 - - if (ss_busy) return; // come back later - - if (ss_escape) { // user pressed escape key - m_slideshow(0,0); // exit slide show - return; - } - - if (strEqu(mode,"timer")) { // timer trigger - if (ss_paused) return; - secs = get_seconds(); - if (secs < ss_timer) return; - mode = "next"; // time for next image - Fkey = 0; - } - else Fkey = 1; // keyboard trigger - - cp = curr_file_posn; - - if (ss_latest) { // get prev/next image file, - if (strEqu(mode,"prev")) // latest version v.11.10 - pp = ss_prev_latest(cp); - if (strEqu(mode,"next")) - pp = ss_next_latest(cp); - } - else { // get prev or next image file - if (strEqu(mode,"prev")) - pp = ss_prev(cp); - if (strEqu(mode,"next")) - pp = ss_next(cp); - } - - if (! pp) return; // there is none - - ss_busy++; - - if (ss_oldfile) zfree(ss_oldfile); - ss_oldfile = ss_newfile; - ss_newfile = pp; - - ss_loadimage(ss_oldfile,ss_pxmold); - ss_loadimage(ss_newfile,ss_pxmnew); - - mutex_lock(&Fpixmap_lock); // block other window updates - - if (Fkey) ss_instant(); // KB input, do instant transition - - else // use next selected transition type - { // v.11.08 - ii = last_transition; // start with last transition type + 1 - if (++ii > SSNF-1) ii = 1; // 1st is omitted (arrow keys) - - while (! ss_funcs[ii]) // infinite loop if none selected - if (++ii > SSNF-1) ii = 1; // bugfix v.11.09.1 - - last_transition = ii; // next transition - if (ii > 0) ss_table[ii].func(); // do image transition - } - - mutex_unlock(&Fpixmap_lock); - - zmainloop(); // catch-up anynch window updates? - - f_open(ss_newfile,0); // sync all image data /////// - - if (zdeditcctext) m_edit_cctext(0,0); // edit caption and comments dialog - - secs = get_seconds(); // set time for next image - ss_timer = secs + ss_interval + 0.5; - ss_busy = 0; - return; -} - - -// get previous file before current file - -char * ss_prev(int cp) -{ - char *pp; - int ii; - - for (ii = cp-1; ii >= 0; ii--) - { - pp = image_gallery(0,"find",ii); - if (pp) return pp; - } - - return 0; -} - - -// get next file after current file - -char * ss_next(int cp) -{ - char *pp; - int ii; - int nfiles = image_navi::nfiles; - - for (ii = cp+1; ii < nfiles; ii++) - { - pp = image_gallery(0,"find",ii); - if (pp) return pp; - } - - return 0; -} - - -// get previous file, latest version, before current file - -char * ss_prev_latest(int cp) // new v.11.10 -{ - char *pp, *name1, *name2; - int ii; - - pp = image_gallery(0,"find",cp); - if (! pp) return 0; - - name1 = ss_basename(pp); - zfree(pp); - - for (ii = cp-1; ii >= 0; ii--) - { - pp = image_gallery(0,"find",ii); - if (! pp) { - zfree(name1); - return 0; - } - name2 = ss_basename(pp); - if (strEqu(name1,name2)) { - zfree(name2); - zfree(pp); - } - else { - zfree(name1); - zfree(name2); - return pp; - } - } - return 0; -} - - -// get next file, latest version, after current file - -char * ss_next_latest(int cp) // new v.11.10 -{ - char *pp1, *pp2, *name1, *name2; - int ii; - int nfiles = image_navi::nfiles; - - pp1 = image_gallery(0,"find",cp+1); - if (! pp1) return 0; - - name1 = ss_basename(pp1); - - for (ii = cp+2; ii < nfiles; ii++) - { - pp2 = image_gallery(0,"find",ii); - if (! pp2) { - zfree(name1); - return pp1; - } - name2 = ss_basename(pp2); - if (strEqu(name1,name2)) { - zfree(pp1); - zfree(name2); - pp1 = pp2; - } - else { - zfree(pp2); - zfree(name1); - zfree(name2); - return pp1; - } - } - return 0; -} - - -// extract base name from image file name -// base name is file name without directory, version, extension - -char * ss_basename(char *file) // v.11.10 -{ - char *pp1, *pp2, *pp3; - - pp1 = strrchr(file,'/'); // skip over directory if present - if (pp1) file = pp1 + 1; - pp1 = strdupz(file,0,"ss.basename"); - pp2 = strrchr(pp1,'.'); // look for .ext - if (! pp2) return pp1; - *pp2 = 0; // strip it off - pp3 = pp2 - 4; - if (! strnEqu(pp3,".v",2)) return pp1; // look for version .v00 to .v99 - if (pp3[2] < '0' || pp3[2] > '9') return pp1; - if (pp3[3] < '0' || pp3[3] > '9') return pp1; - *pp3 = 0; // strip it off - return pp1; -} - - -// load image and rescale to fit in given pixmap = window size - -void ss_loadimage(char *file, PXM *pxmout) // new v.11.01 -{ - int cc, fww, fhh, px, py, orgx, orgy; - PXM *pxmtemp1, *pxmtemp2; - double wscale, hscale, scale; - uint8 *pix1, *pix2; - - cc = ss_ww * ss_hh * 3; // clear output pixmap black v.11.10 - memset(pxmout->bmp,0,cc); - - pxmtemp1 = f_load(file,8); // load image file into 1x pixmap - if (! pxmtemp1) return; - - fww = pxmtemp1->ww; // image size - fhh = pxmtemp1->hh; - - wscale = 1.0 * ss_ww / fww; // find scale to fit in window - hscale = 1.0 * ss_hh / fhh; - if (wscale < hscale) scale = wscale; // use greatest ww/hh ratio - else scale = hscale; - fww = fww * scale; - fhh = fhh * scale; - - pxmtemp2 = PXM_rescale(pxmtemp1,fww,fhh); // rescale image to fit window - - orgx = 0.5 * (ss_ww - fww); // origin of image in window - orgy = 0.5 * (ss_hh - fhh); - - for (py = 0; py < fhh; py++) - for (px = 0; px < fww; px++) - { - pix1 = PXMpix8(pxmtemp2,px,py); - pix2 = PXMpix8(pxmout,px+orgx,py+orgy); - pix2[0] = pix1[0]; - pix2[1] = pix1[1]; - pix2[2] = pix1[2]; - } - - PXM_free(pxmtemp1); - PXM_free(pxmtemp2); - - return; -} - - -// instant transition (for use with keyboard arrow keys) - -void ss_instant() // new v.11.01 -{ - uint8 *pix3; - - pix3 = PXMpix8(ss_pxmnew,0,0); - gdk_draw_rgb_image(drWin->window, gdkgc, 0, 0, ss_ww, ss_hh, NODITHER, pix3, ss_ww*3); - return; -} - - -// fade-out / fade-in transition - -void ss_fadein() // new v.11.01 -{ - int ii, jj, kk, px, py; - double newpart, oldpart; - uint8 *pix1, *pix2, *pix3; - - PXM_free(ss_pxmmix); - ss_pxmmix = PXM_copy(ss_pxmold); - - for (ii = 0; ii <= 100; ii += 10) - { - newpart = 0.01 * ii; - oldpart = 1.0 - newpart; - - for (jj = 0; jj < 2; jj++) // four passes, each modifies 25% - for (kk = 0; kk < 2; kk++) // of the pixels (visually smoother) - { - for (py = jj; py < ss_hh; py += 2) - for (px = kk; px < ss_ww; px += 2) - { - pix1 = PXMpix8(ss_pxmold,px,py); - pix2 = PXMpix8(ss_pxmnew,px,py); - pix3 = PXMpix8(ss_pxmmix,px,py); - pix3[0] = newpart * pix2[0] + oldpart * pix1[0]; - pix3[1] = newpart * pix2[1] + oldpart * pix1[1]; - pix3[2] = newpart * pix2[2] + oldpart * pix1[2]; - } - - pix3 = PXMpix8(ss_pxmmix,0,0); - gdk_draw_rgb_image(drWin->window, gdkgc, 0, 0, ss_ww, ss_hh, NODITHER, pix3, ss_ww*3); - } - } - - pix3 = PXMpix8(ss_pxmnew,0,0); - gdk_draw_rgb_image(drWin->window, gdkgc, 0, 0, ss_ww, ss_hh, NODITHER, pix3, ss_ww*3); - return; -} - - -// new image rolls over prior image from left to right - -void ss_rollright() // new v.11.01 -{ - int px, py; - uint8 *pix1, *pix3; - double delay = 0.5 / ss_ww; // v.11.04 - - PXM_free(ss_pxmmix); - ss_pxmmix = PXM_copy(ss_pxmold); - - for (px = 0; px < ss_ww; px++) - { - pix1 = PXMpix8(ss_pxmnew,px,0); - pix3 = PXMpix8(ss_pxmmix,px,0); - - for (py = 0; py < ss_hh; py++) - { - memmove(pix3,pix1,3); - pix1 += ss_ww * 3; - pix3 += ss_ww * 3; - } - - pix3 = PXMpix8(ss_pxmmix,px,0); - gdk_draw_rgb_image(drWin->window, gdkgc, px, 0, 1, ss_hh, NODITHER, pix3, ss_ww*3); - zsleep(delay); - } - - pix3 = PXMpix8(ss_pxmnew,0,0); - gdk_draw_rgb_image(drWin->window, gdkgc, 0, 0, ss_ww, ss_hh, NODITHER, pix3, ss_ww*3); - return; -} - - -// new image rolls over prior image from top down - -void ss_rolldown() // new v.11.01 -{ - int py; - uint8 *pix3; - double delay = 0.5 / ss_hh; - - for (py = 0; py < ss_hh; py++) - { - pix3 = PXMpix8(ss_pxmnew,0,py); - gdk_draw_rgb_image(drWin->window, gdkgc, 0, py, ss_ww, 1, NODITHER, pix3, ss_ww*3); - zsleep(delay); - } - - pix3 = PXMpix8(ss_pxmnew,0,0); - gdk_draw_rgb_image(drWin->window, gdkgc, 0, 0, ss_ww, ss_hh, NODITHER, pix3, ss_ww*3); - return; -} - - -// shift prior image to the left as next image shifts-in from the right -// (this one flickers annoingly and cannot be fixed) - -void ss_shiftleft() // new v.11.01 -{ - int px, Nsteps = 50; - uint8 *pix1, *pix3; - - for (px = 0; px < ss_ww; px += ss_ww / Nsteps) - { - pix1 = PXMpix8(ss_pxmold,px,0); - pix3 = PXMpix8(ss_pxmnew,0,0); - gdk_draw_rgb_image(drWin->window, gdkgc, 0, 0, ss_ww - px, ss_hh, NODITHER, pix1, ss_ww * 3); - gdk_draw_rgb_image(drWin->window, gdkgc, ss_ww - px, 0, px, ss_hh, NODITHER, pix3, ss_ww * 3); - zsleep(0.01); - } - - pix3 = PXMpix8(ss_pxmnew,0,0); - gdk_draw_rgb_image(drWin->window, gdkgc, 0, 0, ss_ww, ss_hh, NODITHER, pix3, ss_ww * 3); - return; -} - - -// new image opens up in horizontal rows like venetian blinds - -void ss_venetian() // new v.11.01 -{ - int py1, py2; - uint8 *pix3; - int louver, Nlouvers = 20; - int louversize = ss_hh / Nlouvers; - double delay = 1.0 / louversize; - - for (py1 = 0; py1 < louversize; py1++) // y-row within each louver - { - for (louver = 0; louver < Nlouvers; louver++) // louver, first to last - { - py2 = py1 + louver * louversize; - if (py2 >= ss_hh) break; - pix3 = PXMpix8(ss_pxmnew,0,py2); - gdk_draw_rgb_image(drWin->window, gdkgc, 0, py2, ss_ww, 1, NODITHER, pix3, ss_ww*3); - } - - zsleep(delay); - } - - pix3 = PXMpix8(ss_pxmnew,0,0); - gdk_draw_rgb_image(drWin->window, gdkgc, 0, 0, ss_ww, ss_hh, NODITHER, pix3, ss_ww * 3); - return; -} - - -// a grate opens up to show new image - -void ss_grate() // new v.11.01 -{ - int px1, px2, py1, py2; - uint8 *pix3; - int row, col, Nrow, Ncol; // rows and columns - int boxww, boxhh; - double delay; - - Ncol = 20; // 20 columns - boxww = boxhh = ss_ww / Ncol; // square boxes - Nrow = ss_hh / boxhh; // corresp. rows - Ncol++; // round up - Nrow++; - delay = 1.0 / boxhh; - - for (py1 = 0; py1 < boxhh; py1++) - { - for (row = 0; row < Nrow; row++) - { - py2 = py1 + row * boxhh; - if (py2 >= ss_hh) break; - pix3 = PXMpix8(ss_pxmnew,0,py2); - gdk_draw_rgb_image(drWin->window, gdkgc, 0, py2, ss_ww, 1, NODITHER, pix3, ss_ww*3); - } - - px1 = py1; - - for (col = 0; col < Ncol; col++) - { - px2 = px1 + col * boxww; - if (px2 >= ss_ww) break; - pix3 = PXMpix8(ss_pxmnew,px2,0); - gdk_draw_rgb_image(drWin->window, gdkgc, px2, 0, 1, ss_hh, NODITHER, pix3, ss_ww*3); - } - - zsleep(delay); - } - - pix3 = PXMpix8(ss_pxmnew,0,0); - gdk_draw_rgb_image(drWin->window, gdkgc, 0, 0, ss_ww, ss_hh, NODITHER, pix3, ss_ww * 3); - return; -} - - -// A hole opens up from the center and expands outward - -void ss_rectangle() // new v.11.01 -{ - int px1, py1, px2, py2, px3, py3; - int ww1, hh1, ww2, hh2; - uint8 *pix3; - int step, Nsteps = 100; - double delay = 1.0 / Nsteps; - - for (step = 1; step < Nsteps; step++) - { - ww1 = ss_ww * step / Nsteps; - hh1 = ww1 * ss_hh / ss_ww; - ww2 = ss_ww / Nsteps / 2; - hh2 = ss_hh / Nsteps / 2; - - px1 = (ss_ww - ww1) / 2; - py1 = (ss_hh - hh1) / 2; - px2 = px1 + ww1 - ww2; - py2 = py1; - px3 = px1; - py3 = py1 + hh1 - hh2; - - pix3 = PXMpix8(ss_pxmnew,px1,py1); - gdk_draw_rgb_image(drWin->window, gdkgc, px1, py1, ww1+1, hh2+1, NODITHER, pix3, ss_ww*3); - - pix3 = PXMpix8(ss_pxmnew,px2,py2); - gdk_draw_rgb_image(drWin->window, gdkgc, px2, py2, ww2+1, hh1+1, NODITHER, pix3, ss_ww*3); - - pix3 = PXMpix8(ss_pxmnew,px3,py3); - gdk_draw_rgb_image(drWin->window, gdkgc, px3, py3, ww1+1, hh2+1, NODITHER, pix3, ss_ww*3); - - pix3 = PXMpix8(ss_pxmnew,px1,py1); - gdk_draw_rgb_image(drWin->window, gdkgc, px1, py1, ww2+1, hh1+1, NODITHER, pix3, ss_ww*3); - - zmainloop(); - zsleep(delay); - } - - pix3 = PXMpix8(ss_pxmnew,0,0); - gdk_draw_rgb_image(drWin->window, gdkgc, 0, 0, ss_ww, ss_hh, NODITHER, pix3, ss_ww * 3); - return; -} - - -// An ellipse opens up from the center and expands outward - -void ss_ellipse() // new v.11.03 -{ - uint8 *pix3; - int step, Nsteps = 100; - int px1, py1, ww; - double delay = 1.0 / Nsteps; - double a, b, a2, b2, px, py, px2, py2; - double ww2 = ss_ww / 2, hh2 = ss_hh / 2; - - for (step = 1; step < 1.3 * Nsteps; step++) - { - a = ww2 * step / Nsteps; // ellipse a and b constants - b = a * ss_hh / ss_ww; // from tiny to >> image size - a2 = a * a; - b2 = b * b; - - for (py = -b; py <= +b; py += 3) // py from top of ellipse to bottom - { - while (py < -(hh2-2)) py += 3; - if (py > hh2-2) break; - py2 = py * py; - px2 = a2 * (1.0 - py2 / b2); // corresponding px value, - px = sqrt(px2); // (+/- from center of ellipse) - if (px > ww2) px = ww2; - ww = 2 * px; // length of line thru ellipse - px1 = ww2 - px; // relocate origin - py1 = py + hh2; - pix3 = PXMpix8(ss_pxmnew,px1,py1); - gdk_draw_rgb_image(drWin->window, gdkgc, px1, py1, ww, 3, NODITHER, pix3, ss_ww*3); - } - - zmainloop(); - zsleep(delay); - } - - pix3 = PXMpix8(ss_pxmnew,0,0); - gdk_draw_rgb_image(drWin->window, gdkgc, 0, 0, ss_ww, ss_hh, NODITHER, pix3, ss_ww * 3); - return; -} - - -// New image sweeps into view like a circular radar image - -void ss_radar() // new v.11.08 -{ - int px = 0, py = 0, Npx, Npy, Np = 12; // smaller values make compiz jerky *** - double R, Rmax, T, Tmax, dT, delay; - double cosT, sinT; - double ww2 = ss_ww / 2, hh2 = ss_hh / 2; - uint8 *pix3; - - Rmax = sqrt(ww2 * ww2 + hh2 * hh2); - Tmax = pi; - dT = 0.6 * asin(Np / Rmax); - delay = dT / Tmax; // 1 sec. + CPU time - if (delay < 0.001) delay = 0.001; - - for (T = 0; T < Tmax; T += dT) - { - cosT = cos(T); - sinT = sin(T); - - for (R = -Rmax; R < Rmax; R += Np) // v.11.09 - { - px = ww2 + R * cosT; - py = hh2 - R * sinT; - if (px < -Np) continue; - if (py < -Np) continue; - if (px > ss_ww-1) continue; - if (py > ss_hh-1) continue; - Npx = Npy = Np; // do the last piece too v.11.10 - if (px < 0) px = 0; - if (py < 0) py = 0; - if (px + Npx > ss_ww-1) Npx = ss_ww-1 - px; - if (py + Npy > ss_hh-1) Npy = ss_hh-1 - py; - pix3 = PXMpix8(ss_pxmnew,px,py); - gdk_draw_rgb_image(drWin->window, gdkgc, px, py, Npx, Npy, NODITHER, pix3, ss_ww*3); - } - - zsleep(delay); - } - - pix3 = PXMpix8(ss_pxmnew,0,0); - gdk_draw_rgb_image(drWin->window, gdkgc, 0, 0, ss_ww, ss_hh, NODITHER, pix3, ss_ww * 3); - return; -} - - -// New image closes in from top and bottom with jagged teeth - -void ss_jaws() // new v.11.08 -{ - int nteeth = 20, Np = 6; - int tbase1, tbase2, twidth, tlength, tooth, tpos; - int ii, px, py, ww, ww2; - double delay = 2.0 * Np / ss_hh; // 1 sec. + CPU time - uint8 *pix3; - - twidth = ss_ww / nteeth; - tlength = twidth; - - for (ii = 0; ii < ss_hh/2 - tlength/2; ii += Np) - { - tbase1 = ii; // tooth base from top to middle - tbase2 = ss_hh - tbase1 - 1; // tooth base from bottom to middle - - for (tooth = 0; tooth <= nteeth; tooth++) // tooth first to last + 1 - { - for (tpos = 0; tpos < tlength; tpos += Np) // tooth position from base to point - { - ww = twidth * (tlength - tpos) / tlength; // tooth width at scan line - if (ww < 2) break; - - py = tbase1 + tpos; // top teeth scan line y - px = twidth / 2 + tooth * twidth - ww / 2; // scan line x to x + ww - if (px < ss_ww) { - pix3 = PXMpix8(ss_pxmnew,px,py); - ww2 = ww; - if (px + ww2 > ss_ww) ww2 = ss_ww - px; - gdk_draw_rgb_image(drWin->window, gdkgc, px, py, ww2, Np, NODITHER, pix3, ss_ww*3); - } - - py = tbase2 - tpos; // bottom teeth scan line y - px = tooth * twidth - ww / 2; // scan line x to x + ww - if (tooth == 0) { - px = 0; // leftmost tooth is half - ww = ww / 2; - } - if (px < ss_ww) { - pix3 = PXMpix8(ss_pxmnew,px,py); - ww2 = ww; - if (px + ww2 > ss_ww) ww2 = ss_ww - px; - gdk_draw_rgb_image(drWin->window, gdkgc, px, py, ww2, Np, NODITHER, pix3, ss_ww*3); - } - } - } - - zmainloop(); - zsleep(delay); - } - - pix3 = PXMpix8(ss_pxmnew,0,0); - gdk_draw_rgb_image(drWin->window, gdkgc, 0, 0, ss_ww, ss_hh, NODITHER, pix3, ss_ww * 3); - return; -} - - -/**************************************************************************/ - -// Show RGB values for 1-5 pixels selected with mouse-clicks. - -void show_RGB_mousefunc(); -int show_RGB_timefunc(void *); - -zdialog *RGBSzd; -int RGBSpixel[5][2]; // last 0-5 pixels clicked -int RGBSnpix; // count of pixels -double RGBStime; // last click time -int RGBSmetric = 1; // 1/2/3 = /RGB/EV/OD -int RGBSdelta = 0; // abs/delta mode -int RGBSlabels = 0; // pixel labels on/off - - -void m_show_RGB(GtkWidget *, cchar *menu) // rewritten v.11.07 -{ - int show_RGB_event(zdialog *zd, cchar *event); - - PangoFontDescription *pfontdesc; - GtkWidget *widget; - cchar *mess = ZTX("Click image to select pixels."); - cchar *header = " Pixel Red Green Blue"; - - zfuncs::F1_help_topic = "show_RGB"; - - if (! Fpxm8) return; // no image file - RGBSnpix = 0; // no pixels yet - pfontdesc = pango_font_description_from_string("Monospace 9"); // monospace font - -/*** - - Click image to select pixels. - [x] my mouse [x] delta [x] labels - Metric: (o) RGB (o) EV (o) OD - Pixel Red Green Blue - A xxxx xxxx xxxxx xxxxx xxxxx - B xxxx xxxx xxxxx xxxxx xxxxx - C xxxx xxxx xxxxx xxxxx xxxxx - D xxxx xxxx xxxxx xxxxx xxxxx - E xxxx xxxx xxxxx xxxxx xxxxx - - [done] -***/ - - if (RGBSzd) zdialog_free(RGBSzd); // delete previous if any - zdialog *zd = zdialog_new(ZTX("Show RGB"),mWin,Bdone,null); - RGBSzd = zd; - - zdialog_add_widget(zd,"hbox","hbmess","dialog",0,"space=3"); - zdialog_add_widget(zd,"label","labmess","hbmess",mess,"space=5"); - - zdialog_add_widget(zd,"hbox","hbmym","dialog"); - zdialog_add_widget(zd,"check","mymouse","hbmym",BmyMouse,"space=8"); - zdialog_add_widget(zd,"check","delta","hbmym","delta","space=8"); - zdialog_add_widget(zd,"check","labels","hbmym","labels","space=8"); - - if (RGBSdelta) zdialog_stuff(zd,"delta",1); // abs/delta mode v.11.08 - - zdialog_add_widget(zd,"hbox","hbmetr","dialog",0,"space=3"); - zdialog_add_widget(zd,"label","labmetr","hbmetr","Metric:","space=5"); - zdialog_add_widget(zd,"radio","radRGB","hbmetr","RGB","space=3"); - zdialog_add_widget(zd,"radio","radEV","hbmetr","EV","space=3"); - zdialog_add_widget(zd,"radio","radOD","hbmetr","OD","space=3"); - - if (RGBSmetric == 1) zdialog_stuff(zd,"radRGB",1); // get which metric to use - if (RGBSmetric == 2) zdialog_stuff(zd,"radEV",1); - if (RGBSmetric == 3) zdialog_stuff(zd,"radOD",1); - - zdialog_add_widget(zd,"vbox","vbdat","dialog"); // vbox for current pixel values - zdialog_add_widget(zd,"hbox","hbpix","vbdat"); - zdialog_add_widget(zd,"label","labheader","hbpix",header); // Pixel Red Green Blue - - zdialog_add_widget(zd,"hbox","hb1","vbdat"); - zdialog_add_widget(zd,"label","pix1","hb1"); // A xxxx yyyy rrr.r ggg.g bbb.b - zdialog_add_widget(zd,"hbox","hb2","vbdat"); - zdialog_add_widget(zd,"label","pix2","hb2"); - zdialog_add_widget(zd,"hbox","hb3","vbdat"); - zdialog_add_widget(zd,"label","pix3","hb3"); - zdialog_add_widget(zd,"hbox","hb4","vbdat"); - zdialog_add_widget(zd,"label","pix4","hb4"); - zdialog_add_widget(zd,"hbox","hb5","vbdat"); - zdialog_add_widget(zd,"label","pix5","hb5"); - - widget = zdialog_widget(zd,"labheader"); - gtk_widget_modify_font(widget,pfontdesc); // use monospace font - widget = zdialog_widget(zd,"pix1"); - gtk_widget_modify_font(widget,pfontdesc); - widget = zdialog_widget(zd,"pix2"); - gtk_widget_modify_font(widget,pfontdesc); - widget = zdialog_widget(zd,"pix3"); - gtk_widget_modify_font(widget,pfontdesc); - widget = zdialog_widget(zd,"pix4"); - gtk_widget_modify_font(widget,pfontdesc); - widget = zdialog_widget(zd,"pix5"); - gtk_widget_modify_font(widget,pfontdesc); - - zdialog_help(zd,"show_RGB"); // zdialog help topic v.11.08 - zdialog_run(zd,show_RGB_event,"save"); // run dialog - takeMouse(zd,show_RGB_mousefunc,dragcursor); // connect mouse function - g_timeout_add(300,show_RGB_timefunc,0); // start timer function, 300 ms - - return; -} - - -// dialog event function - -int show_RGB_event(zdialog *zd, cchar *event) -{ - int mymouse, button, ii, px, py; - static char label[5][4] = { " A ", " B ", " C ", " D ", " E " }; - - if (zd->zstat) { - freeMouse(); // disconnect mouse function - zdialog_free(RGBSzd); // kill dialog - RGBSzd = 0; - erase_toptext(102); - mwpaint2(); - } - - if (strEqu(event,"mymouse")) { // toggle mouse capture - zdialog_fetch(zd,"mymouse",mymouse); - if (mymouse) takeMouse(zd,show_RGB_mousefunc,dragcursor); // connect mouse function - else freeMouse(); // disconnect mouse - } - - if (strEqu(event,"delta")) { // set absolute/delta mode - zdialog_fetch(zd,"delta",RGBSdelta); - if (RGBSdelta && ! E3pxm16) { - RGBSdelta = 0; // block delta mode if no edit underway - zdialog_stuff(zd,"delta",0); // v.11.09 - } - } - - if (strEqu(event,"labels")) { // get labels on/off v.11.09 - zdialog_fetch(zd,"labels",RGBSlabels); - - erase_toptext(102); - - if (RGBSlabels) { // labels off to labels on - for (ii = 0; ii < RGBSnpix; ii++) // show pixel labels on image - { // v.11.08 - px = RGBSpixel[ii][0]; - py = RGBSpixel[ii][1]; - add_toptext(102,px,py,label[ii],"Sans 8"); - } - } - - mwpaint2(); - } - - if (strEqu(event,"radRGB")) { // metric = RGB - zdialog_fetch(zd,event,button); - if (button) RGBSmetric = 1; - } - - if (strEqu(event,"radEV")) { // metric = EV - zdialog_fetch(zd,event,button); - if (button) RGBSmetric = 2; - } - - if (strEqu(event,"radOD")) { // metric = OD - zdialog_fetch(zd,event,button); - if (button) RGBSmetric = 3; - } - - return 0; -} - - -// mouse function - -void show_RGB_mousefunc() // mouse function -{ - int ii, px, py; - static char label[5][4] = { " A ", " B ", " C ", " D ", " E " }; - - if (! LMclick) return; - - LMclick = 0; - RGBStime = get_seconds(); // mark time of pixel click - - if (RGBSnpix == 5) { // if all 5 positions filled, - for (ii = 1; ii < 5; ii++) { // remove first (oldest) and - RGBSpixel[ii-1][0] = RGBSpixel[ii][0]; // push the rest back - RGBSpixel[ii-1][1] = RGBSpixel[ii][1]; - } - RGBSnpix = 4; // position for newest - } - - ii = RGBSnpix; // next position to fill - RGBSpixel[ii][0] = Mxclick; // save newest pixel - RGBSpixel[ii][1] = Myclick; - RGBSnpix++; - - erase_toptext(102); - - if (RGBSlabels) { // v.11.09 - for (ii = 0; ii < RGBSnpix; ii++) // show pixel labels on image - { // v.11.08 - px = RGBSpixel[ii][0]; - py = RGBSpixel[ii][1]; - add_toptext(102,px,py,label[ii],"Sans 8"); - } - } - - mwpaint2(); - return; -} - - -// timer function - continuously display RGB values for selected pixels - -int show_RGB_timefunc(void *arg) // up to 5 pixels, live update -{ - int ii, px, py, delta; - double red1, green1, blue1; - double red3, green3, blue3; - char text[100], pixx[8] = "pixx"; - uint8 *ppix8; - uint16 *ppix16a, *ppix16b; - double c1 = 100.0 / 256.0; - - #define ODfunc(rgb) (2.0 - log10(c1 * rgb)) // RGB units (1-256) to OD units - #define EVfunc(rgb) (log2(rgb) - 7) // RGB units to EV (128 == 0 EV) - - if (! RGBSzd) return 1; // user quit, stop timer - if (! RGBSnpix) return 1; // no pixels clicked yet - - if (RGBSdelta && E3pxm16) delta = 1; // delta mode only if edit underway - else delta = 0; // v.11.08 - - red1 = green1 = blue1 = 0; - - if (curr_image_time > RGBStime) { // image time later than click time - RGBSnpix = 0; // data is no longer valid - erase_toptext(102); - mwpaint2(); - } - - for (ii = 0; ii < 5; ii++) // loop positons 0 to 4 - { - pixx[3] = '1' + ii; // widget names "pix1" ... "pix5" - - px = RGBSpixel[ii][0]; // next pixel to report - py = RGBSpixel[ii][1]; - if (ii >= RGBSnpix) { // no pixel there yet - zdialog_stuff(RGBSzd,pixx,""); // blank report line - continue; - } - - if (E3pxm16) { // use current image being edited - if (px < 0 || px > E3ww-1 || // outside image area - py < 0 || py > E3hh-1) return 1; - ppix16a = PXMpix(E3pxm16,px,py); - red3 = ppix16a[0] / 256.0; // "after" image E3 - green3 = ppix16a[1] / 256.0; - blue3 = ppix16a[2] / 256.0; - - if (delta) { // delta RGB for ongoing edited image - ppix16b = PXMpix(E1pxm16,px,py); // "before" image E1 - red1 = ppix16b[0] / 256.0; // v.11.08 - green1 = ppix16b[1] / 256.0; - blue1 = ppix16b[2] / 256.0; - } - } - - else if (Fpxm16) { // use finished edited image - if (px < 0 || px > Fww-1 || - py < 0 || py > Fhh-1) return 1; - ppix16a = PXMpix(Fpxm16,px,py); - red3 = ppix16a[0] / 256.0; - green3 = ppix16a[1] / 256.0; - blue3 = ppix16a[2] / 256.0; - } - - else { // use 8 bpc image - if (px < 0 || px > Fww-1 || - py < 0 || py > Fhh-1) return 1; - ppix8 = (uint8 *) Fpxm8->bmp + (py * Fww + px) * 3; - red3 = ppix8[0]; - green3 = ppix8[1]; - blue3 = ppix8[2]; - } - - sprintf(text," %c %4d %4d ",'A'+ii,px,py); // format pixel " A xxxx yyyy" - - if (RGBSmetric == 1) { // output RGB values - if (delta) { - red3 -= red1; // delta RGB - green3 -= green1; - blue3 -= blue1; - } - sprintf(text+12," %6.2f %6.2f %6.2f ",red3,green3,blue3); // xxx.xx - } - - if (RGBSmetric == 2) { // output EV values v.11.08 - red3 = EVfunc(red3); - green3 = EVfunc(green3); - blue3 = EVfunc(blue3); - if (delta) { - red3 -= EVfunc(red1); // delta EV - green3 -= EVfunc(green1); - blue3 -= EVfunc(blue1); - } - sprintf(text+12," %6.3f %6.3f %6.3f ",red3,green3,blue3); // x.xxx - } - - if (RGBSmetric == 3) { // output OD values v.11.08 - red3 = ODfunc(red3); - green3 = ODfunc(green3); - blue3 = ODfunc(blue3); - if (delta) { - red3 -= ODfunc(red1); // delta OD - green3 -= ODfunc(green1); - blue3 -= ODfunc(blue1); - } - sprintf(text+12," %6.3f %6.3f %6.3f ",red3,green3,blue3); // x.xxx - } - - zdialog_stuff(RGBSzd,pixx,text); // pixel and RGB values >> label - } - - return 1; -} - - -/**************************************************************************/ - -// setup x and y grid lines - count/spacing, enable/disable, offsets - -void m_gridlines(GtkWidget *, cchar *) -{ - int gridlines_dialog_event(zdialog *zd, cchar *event); - - zdialog *zd; - - zfuncs::F1_help_topic = "grid_lines"; // v.10.8 - - zd = zdialog_new(ZTX("Grid Lines"),mWin,Bdone,Bcancel,null); - - zdialog_add_widget(zd,"hbox","hb0","dialog",0,"space=10"); - zdialog_add_widget(zd,"vbox","vb1","hb0",0,"homog|space=5"); - zdialog_add_widget(zd,"vbox","vb2","hb0",0,"homog|space=5"); - zdialog_add_widget(zd,"vbox","vbspace","hb0",0,"homog|space=5"); - zdialog_add_widget(zd,"vbox","vb3","hb0",0,"homog|space=5"); - zdialog_add_widget(zd,"vbox","vb4","hb0",0,"homog|space=5"); - - zdialog_add_widget(zd,"label","lab1x","vb1",ZTX("x-spacing")); - zdialog_add_widget(zd,"label","lab2x","vb1",ZTX("x-count")); - zdialog_add_widget(zd,"label","lab4x","vb1",ZTX("x-enable")); - - zdialog_add_widget(zd,"spin","spacex","vb2","10|200|1|50"); - zdialog_add_widget(zd,"spin","countx","vb2","0|100|1|0"); - zdialog_add_widget(zd,"check","enablex","vb2",0); - - zdialog_add_widget(zd,"label","lab1y","vb3",ZTX("y-spacing")); - zdialog_add_widget(zd,"label","lab2y","vb3",ZTX("y-count")); - zdialog_add_widget(zd,"label","lab4y","vb3",ZTX("y-enable")); - - zdialog_add_widget(zd,"spin","spacey","vb4","10|200|1|50"); - zdialog_add_widget(zd,"spin","county","vb4","0|100|1|0"); - zdialog_add_widget(zd,"check","enabley","vb4",0); - - zdialog_add_widget(zd,"hbox","hboffx","dialog"); - zdialog_add_widget(zd,"label","lab3x","hboffx",ZTX("x-offset"),"space=7"); - zdialog_add_widget(zd,"hscale","offsetx","hboffx","-100|100|1|0","expand"); - - zdialog_add_widget(zd,"hbox","hboffy","dialog"); - zdialog_add_widget(zd,"label","lab3y","hboffy",ZTX("y-offset"),"space=7"); - zdialog_add_widget(zd,"hscale","offsety","hboffy","-100|100|1|0","expand"); - - zdialog_stuff(zd,"spacex",gridspace[0]); - zdialog_stuff(zd,"spacey",gridspace[1]); - zdialog_stuff(zd,"countx",gridcount[0]); - zdialog_stuff(zd,"county",gridcount[1]); - zdialog_stuff(zd,"offsetx",gridoffset[0]); - zdialog_stuff(zd,"offsety",gridoffset[1]); - zdialog_stuff(zd,"enablex",gridon[0]); - zdialog_stuff(zd,"enabley",gridon[1]); - - if (gridon[0] || gridon[1]) Fgrid = 1; - mwpaint2(); - - zdialog_help(zd,"grid_lines"); // zdialog help topic v.11.08 - zdialog_run(zd,gridlines_dialog_event); - zdialog_wait(zd); - return; -} - - -// dialog event function - -int gridlines_dialog_event(zdialog *zd, cchar *event) -{ - int zstat; - - if (zd->zstat) { - zstat = zd->zstat; - if (zstat != 1) Fgrid = gridon[0] = gridon[1] = 0; // cancel, grid lines off v.11.11 - zdialog_free(zd); - mwpaint2(); - return 0; - } - - if (strEqu(event,"enablex")) // x/y grid enable or disable - zdialog_fetch(zd,"enablex",gridon[0]); - - if (strEqu(event,"enabley")) - zdialog_fetch(zd,"enabley",gridon[1]); - - if (strEqu(event,"spacex")) // x/y grid spacing (if counts == 0) - zdialog_fetch(zd,"spacex",gridspace[0]); - - if (strEqu(event,"spacey")) - zdialog_fetch(zd,"spacey",gridspace[1]); - - if (strEqu(event,"countx")) // x/y grid line counts - zdialog_fetch(zd,"countx",gridcount[0]); - - if (strEqu(event,"county")) - zdialog_fetch(zd,"county",gridcount[1]); - - if (strEqu(event,"offsetx")) // x/y grid starting offsets - zdialog_fetch(zd,"offsetx",gridoffset[0]); - - if (strEqu(event,"offsety")) - zdialog_fetch(zd,"offsety",gridoffset[1]); - - if (gridon[0] || gridon[1]) Fgrid = 1; // if either grid enabled, show grid - else Fgrid = 0; - - mwpaint2(); - return 0; -} - - -// load or save grid settings from or to external int array - -void load_grid(int *griddata) // v.11.11 -{ - Fgrid = griddata[0]; - gridon[0] = griddata[1]; - gridon[1] = griddata[2]; - gridspace[0] = griddata[3]; - gridspace[1] = griddata[4]; - gridcount[0] = griddata[5]; - gridcount[1] = griddata[6]; - if (! gridcount[0] && ! gridspace[0]) gridcount[0] = 5; // if never set, use 5 lines - if (! gridcount[1] && ! gridspace[1]) gridcount[1] = 5; - mwpaint2(); - return; -} - -void save_grid(int *griddata) -{ - griddata[0] = Fgrid; - griddata[1] = gridon[0]; - griddata[2] = gridon[1]; - griddata[3] = gridspace[0]; - griddata[4] = gridspace[1]; - griddata[5] = gridcount[0]; - griddata[6] = gridcount[1]; - return; -} - - -// toggle grid lines on or off -// action: 0 = off, 1 = on, 2 = toggle: on > off, off > on - -void toggle_grid(int action) // v.11.11 -{ - if (action == 0) Fgrid = 0; // grid off - if (action == 1) Fgrid = 1; // grid on - if (action == 2) Fgrid = 1 - Fgrid; // toggle grid - - if (Fgrid && ! gridon[0] && ! gridon[1]) // if grid on and x/y both off, - gridon[0] = gridon[1] = 1; // set both grids on - - mwpaint2(); - return; -} - - -/**************************************************************************/ - -// choose or set lens parameters for panoramas - -void m_lensparms(GtkWidget *, cchar *) -{ - int ii, zstat, radb; - char text[20]; - zdialog *zd; - - zfuncs::F1_help_topic = "lens_parms"; // v.10.8 - - if (! lens4_name[0] || strEqu(lens4_name[0],"undefined")) { - lens4_name[0] = strdupz("lens_1",0,"lensname"); // default lens parameters - lens4_name[1] = strdupz("lens_2",0,"lensname"); - lens4_name[2] = strdupz("lens_3",0,"lensname"); - lens4_name[3] = strdupz("lens_4",0,"lensname"); - lens4_mm[0] = 30; - lens4_mm[1] = 40; - lens4_mm[2] = 50; - lens4_mm[3] = 60; - lens4_bow[0] = 0; - lens4_bow[1] = 0; - lens4_bow[2] = 0; - lens4_bow[3] = 0; - curr_lens = 1; // default 40 mm lens - } - - zd = zdialog_new(ZTX("Lens Parameters"),mWin,Bdone,Bcancel,null); - zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=5"); - zdialog_add_widget(zd,"vbox","vb1","hb1",0,"space=5|homog"); // Lens mm bow - zdialog_add_widget(zd,"vbox","vb2","hb1",0,"space=5|homog"); // (o) name1 30 0.33 - zdialog_add_widget(zd,"vbox","vb3","hb1",0,"space=5|homog"); // (x) name2 40 0.22 - zdialog_add_widget(zd,"vbox","vb4","hb1",0,"space=5|homog"); // (o) name3 45 0.28 - zdialog_add_widget(zd,"label","space","vb1"); // (o) name4 50 0.44 - zdialog_add_widget(zd,"radio","radb0","vb1",0); // - zdialog_add_widget(zd,"radio","radb1","vb1",0); // [done] [cancel] - zdialog_add_widget(zd,"radio","radb2","vb1",0); - zdialog_add_widget(zd,"radio","radb3","vb1",0); - zdialog_add_widget(zd,"label","lname","vb2",ZTX("lens name")); - zdialog_add_widget(zd,"entry","name0","vb2","scc=10"); - zdialog_add_widget(zd,"entry","name1","vb2","scc=10"); - zdialog_add_widget(zd,"entry","name2","vb2","scc=10"); - zdialog_add_widget(zd,"entry","name3","vb2","scc=10"); - zdialog_add_widget(zd,"label","lmm","vb3",ZTX("lens mm")); - zdialog_add_widget(zd,"entry","mm0","vb3","0","scc=5"); - zdialog_add_widget(zd,"entry","mm1","vb3","0","scc=5"); - zdialog_add_widget(zd,"entry","mm2","vb3","0","scc=5"); - zdialog_add_widget(zd,"entry","mm3","vb3","0","scc=5"); - zdialog_add_widget(zd,"label","lbow","vb4",ZTX("lens bow")); - zdialog_add_widget(zd,"entry","bow0","vb4","0.0","scc=6"); - zdialog_add_widget(zd,"entry","bow1","vb4","0.0","scc=6"); - zdialog_add_widget(zd,"entry","bow2","vb4","0.0","scc=6"); - zdialog_add_widget(zd,"entry","bow3","vb4","0.0","scc=6"); - - for (ii = 0; ii < 4; ii++) // stuff lens data into dialog - { - snprintf(text,20,"name%d",ii); - zdialog_stuff(zd,text,lens4_name[ii]); - snprintf(text,20,"mm%d",ii); - zdialog_stuff(zd,text,lens4_mm[ii]); - snprintf(text,20,"bow%d",ii); - zdialog_stuff(zd,text,lens4_bow[ii]); - } - - snprintf(text,20,"radb%d",curr_lens); // current lens = selected - zdialog_stuff(zd,text,1); - - zdialog_help(zd,"lens_parms"); // zdialog help topic v.11.08 - zdialog_run(zd,0); // run dialog, get inputs - zstat = zdialog_wait(zd); - - if (zstat != 1) { - zdialog_free(zd); // canceled - return; - } - - for (ii = 0; ii < 4; ii++) // fetch lens data (revisions) - { - snprintf(text,20,"name%d",ii); - zdialog_fetch(zd,text,lensname,39); - repl_1str(lensname,lensname," ","_"); // replace blanks with _ - if (lens4_name[ii]) zfree(lens4_name[ii]); - lens4_name[ii] = strdupz(lensname,0,"lensname"); // bugfix v.11.03.1 - snprintf(text,20,"mm%d",ii); - zdialog_fetch(zd,text,lens4_mm[ii]); - snprintf(text,20,"bow%d",ii); - zdialog_fetch(zd,text,lens4_bow[ii]); - snprintf(text,20,"radb%d",ii); // detect which is selected - zdialog_fetch(zd,text,radb); - if (radb) curr_lens = ii; - } - - zdialog_free(zd); - return; -} - - -/**************************************************************************/ - -// set GUI language - -void m_lang(GtkWidget *, cchar *) // overhauled v.10.1 -{ - zdialog *zd; - int ii, cc, err, val, zstat; - char lang1[8], *pp; - - cchar *langs[12] = { "en English", "de German", "es Spanish", // english first - "fr French", "gl Galacian", "it Italian", - "nl Dutch", "pt Portuguese", "ru_RU Russian", - "sv Swedish", "zh_CN Chinese", null }; - - cchar *title = ZTX("Available Translations"); - - zfuncs::F1_help_topic = "language"; // v.10.8 - - zd = zdialog_new(ZTX("Set Language"),mWin,Bdone,Bcancel,null); - zdialog_add_widget(zd,"label","title","dialog",title,"space=10"); - zdialog_add_widget(zd,"hbox","hb1","dialog"); - zdialog_add_widget(zd,"vbox","vb1","hb1"); - - for (ii = 0; langs[ii]; ii++) // make radio button per language - zdialog_add_widget(zd,"radio",langs[ii],"vb1",langs[ii]); - - cc = strlen(zfuncs::zlanguage); // current language - for (ii = 0; langs[ii]; ii++) // match on lc_RC - if (strnEqu(zfuncs::zlanguage,langs[ii],cc)) break; - if (! langs[ii]) - for (ii = 0; langs[ii]; ii++) // failed, match on lc alone - if (strnEqu(zfuncs::zlanguage,langs[ii],2)) break; - if (! langs[ii]) ii = 0; // failed, default english - zdialog_stuff(zd,langs[ii],1); - - zdialog_resize(zd,200,0); - zdialog_help(zd,"language"); // zdialog help topic v.11.08 - zdialog_run(zd); // run dialog - zstat = zdialog_wait(zd); - - for (ii = 0; langs[ii]; ii++) { // get active radio button - zdialog_fetch(zd,langs[ii],val); - if (val) break; - } - - zdialog_free(zd); // kill dialog - - if (zstat != 1) return; // user cancel - if (! val) return; // no selection - - strncpy0(lang1,langs[ii],8); - pp = strchr(lang1,' '); // isolate lc_RC part - *pp = 0; - - sprintf(command,"fotoxx -l %s -p &",lang1); // start new fotoxx with language - err = system(command); - if (err) printf("error: %s \n",wstrerror(err)); - - m_quit(0,0); // exit - return; -} - - -/**************************************************************************/ - -// edit translations while running the application interactively - -void m_translate(GtkWidget *, cchar *) // new v.11.06 -{ - zfuncs::F1_help_topic = "translate"; - ZTX_translation_start(); - return; -} - - -/**************************************************************************/ - -// create desktop icon / launcher - -void m_menu_launcher(GtkWidget *, cchar *) // v.11.08 -{ - char *command; - - zfuncs::F1_help_topic = "menu_launcher"; - command = zdialog_text(mWin,ZTX("Make Launcher"),"fotoxx -recent"); - if (! command || ! *command) return; // bugfix v.11.09 - zmake_menu_launcher(command,"Graphics","Image Editor"); - return; -} - - -/**************************************************************************/ - -// open a single RAW file or convert multiple RAW files to tiff - -void m_conv_raw(GtkWidget *, cchar *menu) // simplified v.11.08 -{ - char **raw_files; - char *rawfile, *outfile, *pp; - int ii, err, filecount; - - zfuncs::F1_help_topic = "convert_RAW"; - - if (! Fufraw) { - zmessageACK(mWin,ZTX("Program ufraw-batch is required")); - return; - } - - if (is_syncbusy()) return; // must wait for file sync v.11.11 - if (mod_keep()) return; // unsaved edits - if (! menulock(1)) return; - - if (strEqu(menu,"Open RAW File")) // convert one file v.11.08 - { - rawfile = zgetfile1(ZTX("Open RAW File"),"open",curr_dirk); - if (! rawfile) { - menulock(0); - return; - } - raw_files = (char **) zmalloc(2 * sizeof(char *),"conv-RAW"); - raw_files[0] = rawfile; - raw_files[1] = 0; - } - else // convert multiple files - { - raw_files = zgetfileN(ZTX("Select RAW files to convert"),"openN",curr_dirk); - if (! raw_files) { - menulock(0); - return; - } - } - - for (ii = 0; raw_files[ii]; ii++); // count selected files - filecount = ii; - - write_popup_text("open","Converting RAW files",500,200,mWin); // status monitor popup window - write_popup_text("write","converting ..."); - - for (ii = 0; ii < filecount; ii++) - { - rawfile = raw_files[ii]; - outfile = strdupz(rawfile,5,"raw_out"); - pp = strrchr(rawfile,'.'); - pp = outfile + (pp - rawfile); - strcpy(pp,".tiff"); - - write_popup_text("write",rawfile); // write output to log window - - snprintf(command,ccc,"ufraw-batch --wb=camera --out-type=tiff --out-depth=16" - " --overwrite --output=\"%s\" \"%s\" ",outfile, rawfile); - err = system(command); - - if (err) { - write_popup_text("write",wstrerror(err)); - zfree(outfile); - continue; - } - - f_open(outfile,0); // open converted file in main window - zfree(outfile); - zmainloop(); - } - - write_popup_text("write","COMPLETED"); - write_popup_text("close",0); - - image_gallery(curr_file,"init"); // update gallery file list - image_gallery(0,"paint2",curr_file_posn); // refresh gallery window if active - - for (ii = 0; raw_files[ii]; ii++) // free memory - zfree(raw_files[ii]); - zfree(raw_files); - - menulock(0); - return; -} - - -/**************************************************************************/ - -// burn images to CD/DVD - -void m_burn(GtkWidget *, cchar *) -{ - int ii, cc, err; - char **filelist, *imagefile, *bcommand; - - if (is_syncbusy()) return; // must wait for file sync v.11.11 - if (mod_keep()) return; // unsaved edits - if (! menulock(1)) return; // lock menus - - zfuncs::F1_help_topic = "burn"; // v.10.8 - - filelist = image_gallery_getfiles(0,mWin); // get list of files to burn v.10.9 - if (! filelist) { - menulock(0); - return; - } - - cc = 0; - for (ii = 0; filelist[ii]; ii++) // get memory for brasero command line - cc += strlen(filelist[ii]) + 4; - - bcommand = zmalloc(cc+20,"brasero"); - strcpy(bcommand,"brasero"); - cc = strlen(bcommand); - - for (ii = 0; filelist[ii]; ii++) // copy files to command line - { - imagefile = filelist[ii]; - strcpy(bcommand+cc," \""); - cc += 2; - strcpy(bcommand+cc,imagefile); - cc += strlen(imagefile); - strcpy(bcommand+cc,"\""); - cc += 1; - zfree(imagefile); - } - - zfree(filelist); - - strcat(bcommand," &"); // brasero command in background - err = system(bcommand); - if (err) zmessageACK(mWin,"error: %s",wstrerror(err)); - zfree(bcommand); - - menulock(0); - return; -} - - -/**************************************************************************/ - -// menu function -// resize selected images and send to preferred e-mail program - -void m_email(GtkWidget *, cchar *) // new v.10.10 -{ - int email_dialog_event(zdialog *zd, cchar *event); - - zdialog *zd; // email dialog - - zfuncs::F1_help_topic = "e-mail"; - - if (is_syncbusy()) return; // must wait for file sync v.11.11 - if (mod_keep()) return; // unsaved edits - if (! menulock(1)) return; // lock menus - - // [select files] N files selected - // max. width [____] - // max. height [____] - // - // [proceed] [cancel] - - zd = zdialog_new(ZTX("E-mail Images"),mWin,Bproceed,Bcancel,null); - zdialog_add_widget(zd,"hbox","hbf","dialog",0,"space=5"); - zdialog_add_widget(zd,"button","files","hbf",Bselectfiles,"space=5"); - zdialog_add_widget(zd,"label","fcount","hbf",ZTX("0 files selected"),"space=10"); - zdialog_add_widget(zd,"hbox","hbwh","dialog","space=10"); - zdialog_add_widget(zd,"vbox","vbwh1","hbwh",0,"homog|space=5"); - zdialog_add_widget(zd,"vbox","vbwh2","hbwh",0,"homog|space=5"); - zdialog_add_widget(zd,"label","labw","vbwh1",ZTX("max. width")); - zdialog_add_widget(zd,"label","labh","vbwh1",ZTX("max. height")); - zdialog_add_widget(zd,"entry","maxw","vbwh2","1000","scc=5"); - zdialog_add_widget(zd,"entry","maxh","vbwh2","700","scc=5"); - - zdialog_stuff(zd,"maxw",emailsize[0]); - zdialog_stuff(zd,"maxh",emailsize[1]); - - zdialog_help(zd,"e-mail"); // zdialog help topic v.11.08 - zdialog_run(zd,email_dialog_event); // run dialog - zdialog_wait(zd); // wait for completion - - menulock(0); - return; -} - - -// dialog event and completion callback function - -int email_dialog_event(zdialog *zd, cchar *event) -{ - static char **flist = 0; - char countmess[50], tempdir[100], sequence[8]; - int maxw, maxh, err, fcc, ww, hh; - int ii, jj, kk; - char *pfile, *pext, *oldfile, *newfile; - double scale, wscale, hscale; - PXM *pxmin, *pxmout; - - if (strEqu(event,"files")) // select images to resize - { - if (flist) { // free prior list - for (ii = 0; flist[ii]; ii++) - zfree(flist[ii]); - zfree(flist); - } - - flist = image_gallery_getfiles(0,mWin); // get list of files to resize v.10.9 - - if (flist) // count files selected - for (ii = 0; flist[ii]; ii++); - else ii = 0; - - snprintf(countmess,50,ZTX("%d files selected"),ii); // update dialog - zdialog_stuff(zd,"fcount",countmess); - } - - if (! zd->zstat) return 0; // dialog still busy - - if (zd->zstat != 1) goto cleanup; // dialog canceled - - if (! flist) { // no files selected - zd->zstat = 0; // keep dialog active - return 0; - } - - zdialog_fetch(zd,"maxw",maxw); // new max width - zdialog_fetch(zd,"maxh",maxh); // new max height - - if (maxw < 20 || maxh < 20) { - zmessageACK(mWin,ZTX("max. size %d x %d is not reasonable"),maxw,maxh); - zd->zstat = 0; - return 0; - } - - *tempdir = 0; // temp dirk: /tmp//fotoxx/email - strncatv(tempdir,99,"/tmp/",getenv("USER"),"/fotoxx/email",null); // v.11.09 - - sprintf(command,"mkdir -p %s",tempdir); // (re)create directory - err = system(command); - if (err) { - zmessageACK(mWin,"%s",strerror(err)); - goto cleanup; - } - - sprintf(command,"rm -f %s/*.jpg",tempdir); // purge prior file list - err = system(command); - - write_popup_text("open","preparing files",500,200,mWin); // status monitor popup window - - strcpy(command,"xdg-email"); // e-mail command: xdg-email - - for (ii = 0; flist[ii]; ii++) // loop selected files - { - oldfile = flist[ii]; - pfile = strrchr(oldfile,'/'); // /filename.ext - if (! pfile) continue; - - fcc = strlen(pfile); - newfile = strdupz(tempdir,fcc+10,"email"); // add extra space for .nn and .ext - strcat(newfile,pfile); // /tmp//fotoxx/filename.ext - pfile = strrchr(newfile,'/'); - - for (jj = kk = 1; pfile[jj]; jj++, kk++) // remove special characters - { // (xdg-email substitutes %nn - pfile[kk] = pfile[jj]; // and thunderbird falls over) - if (pfile[jj] < 0) continue; // UTF-8 multibyte characters OK - if (pfile[jj] == '.') continue; // periods OK - if (pfile[jj] >= 'a' && pfile[jj] <= 'z') continue; // keep a-z, A-Z, 0-9 - if (pfile[jj] >= 'A' && pfile[jj] <= 'Z') continue; - if (pfile[jj] >= '0' && pfile[jj] <= '9') continue; - kk--; // omit others - } - - pfile[kk] = 0; - - pext = strrchr(pfile,'.'); // find .ext if there is one - if (! pext) pext = pfile + strlen(pfile); - if (strlen(pext) > 5) pext = pext + strlen(pext); - - sprintf(sequence,"-%d",ii+1); // replace with sequence number - strcpy(pext,sequence); // filename-nn - - pext = pext + strlen(pext); // add .jpg extension - strcpy(pext,".jpg"); // filename-nn.jpg - - write_popup_text("write",newfile); // log progress - zmainloop(); - - pxmin = f_load(oldfile,8); // load image as PXM-8 pixmap - if (! pxmin) { - printf("f_load error: %s \n",oldfile); - continue; - } - - ww = pxmin->ww; - hh = pxmin->hh; - - wscale = hscale = 1.0; - if (ww > maxw) wscale = 1.0 * maxw / ww; // compute new size - if (hh > maxh) hscale = 1.0 * maxh / hh; - if (wscale < hscale) scale = wscale; - else scale = hscale; - ww = ww * scale; - hh = hh * scale; - pxmout = PXM_rescale(pxmin,ww,hh); // rescale file - - PXBwrite(pxmout,newfile); // write to new file - - PXM_free(pxmin); - PXM_free(pxmout); - - err = strncatv(command,1990," --attach ","\"",newfile,"\"",null); // --attach /tmp//fotoxx/file.jpg - zfree(newfile); - - if (err) { - zmessageACK(mWin,ZTX("too many files")); - goto cleanup; - } - } - - write_popup_text("write","COMPLETED"); - write_popup_text("close",0); - - emailsize[0] = maxw; // save preferred size - emailsize[1] = maxh; - - strcat(command," &"); // wait for email completion - printf("system: %s \n",command); - err = system(command); - -cleanup: - - if (flist) { // free memory - for (ii = 0; flist[ii]; ii++) - zfree(flist[ii]); - zfree(flist); - flist = 0; - } - - zdialog_free(zd); // kill dialog - return 0; -} - - -/**************************************************************************/ - -// menu function, start synchronize files process manually - -void m_syncfiles(GtkWidget *, cchar *) // v.11.11 -{ - int err, syncfd; - - if (mod_keep()) return; // unsaved edits - if (! menulock(1)) return; // edit function busy - - syncfd = global_lock(fsync_lock); // check if sync files running - if (syncfd >= 0) global_unlock(syncfd); - else { - zmessageACK(mWin,ZTX("Sync Files is already running")); // yes, do nothing - menulock(0); - return; - } - - printf("spawn sync files subprocess \n"); - err = system("fotoxx -syncfiles manual &"); // spawn file sync process - if (err) zmessageACK(mWin,"error: %s \n",wstrerror(err)); - - menulock(0); - return; -} - - -/**************************************************************************/ - -// Synchronize files when fotoxx is installed for the first time or -// when new image files have been created or moved outside fotoxx. -// This is a spawned process running parallel to the user GUI process. -// The main window with menus and toolbar is not available. - -struct tag_index_rec { - char *file; // image filespec - char *tags; // image tags - char *comms; // image comments - char *capt; // image caption - char imagedate[12], filedate[16]; // image date, file date - char stars; // image rating, '0' to '5' - char update; // flag, update is needed -}; -tag_index_rec *xrec_old, *xrec_new; - - -int syncfiles_func(void *) // v.11.11 -{ - int syncfiles_dialog_event(zdialog *zd, cchar *event); - char * syncfiles_find(char *imagedirk, int &Finit); - int syncfiles_index_compare(cchar *rec1, cchar *rec2); - int filesync_thumbfile(char *imagefile); - - int contx, syncfd, dosync, err; - cchar *Fsyncreason, *ppc; - char *pp, text[100]; - char *filespec, *thumbfile, *subdirk; - char imagefile[maxfcc], logrec[200]; - zdialog *zd; - int zstat, fcount, flag; - int fcc, dcc, Finit; - FILE *fid; - struct stat statb; - - cchar *sync_message = ZTX("Run Tools > Synchronize Files so that gallery windows \n" - "will be fast and Search Images will work correctly. \n" - "You can view (not edit) images while synchronize runs."); - - cchar *exifkeys[5] = { exif_date_key, iptc_tags_key, iptc_rating_key, - exif_comment_key, iptc_caption_key }; - - zfuncs::F1_help_topic = "sync_files"; - - printf("enter sync files process %d %d \n",Fautosync,Fmansync); - - syncfd = global_lock(fsync_lock); // obtain sync files lock - if (syncfd < 0) { - zmessage_post(0,5,"Sync Files is already running"); - gtk_main_quit(); - return 0; - } - - err = system("which exiftool > /dev/null"); - if (err) { // exiftool is required - zmessageACK(0,Bexiftoolmissing); - gtk_main_quit(); - return 0; - } - - dosync = 0; - Fsyncreason = "none"; - - if (! topdirk || *topdirk != '/') { // reasons for sync files - Fsyncreason = ZTX("no top image directory is defined"); - dosync = 2; - } - else { - printf("top image directory: %s \n",topdirk); - err = stat(topdirk,&statb); - if (err) Fsyncreason = ZTX("top image directory is invalid"); - if (err) dosync = 2; - } - - err = stat(search_index_file,&statb); - if (err) Fsyncreason = ZTX("no search index file is present"); - if (err) dosync = 2; - - if (! dosync) // check for new image files v.11.11 - { // since last session or sync - sprintf(command,"find -L \"%s\" -type d -newermt \"%s\" ", - topdirk,last_session); // use directory mod time v.11.11.1 - printf("%s \n",command); - contx = 0; - while ((pp = command_output(contx,command,null))) { - newfiles++; // add to possible prior session count - zfree(pp); - } - if (newfiles) { - strncpy0(text,ZTX("new/modified files are present"),99); // v.11.11.1 - Fsyncreason = text; - dosync = 1; - } - } - - if (dosync) printf("%s \n",Fsyncreason); - else printf("%s \n",ZTX("no new files found")); - - if (! dosync && Fautosync) { // no need to sync and not manual req. - gtk_main_quit(); - return 0; - } - - if (dosync < 2 && ! Fmansync) // dialog not required, not manual req. - goto start_sync; // do auto sync - - -// user dialog to request sync files and supply top image directory - -sync_dialog: - - zd = zdialog_new(ZTX("Synchronize Files"),mWin,Bproceed,Bcancel,null); - zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=3"); - zdialog_add_widget(zd,"label","lab1","hb1",ZTX("Top Image Directory:")); - zdialog_add_widget(zd,"hbox","hb2","dialog",0,"space=3"); - zdialog_add_widget(zd,"entry","topdirk","hb2","??","scc=40|space=5"); - zdialog_add_widget(zd,"button","browse","hb2",Bbrowse,"space=5"); - - if (strNeq(Fsyncreason,"none")) { // show reason for file sync - zdialog_add_widget(zd,"label","labwhy1","dialog",Fsyncreason,"space=3"); - zdialog_add_widget(zd,"label","labwhy2","dialog",sync_message,"space=3"); - } - - zdialog_stuff(zd,"topdirk",topdirk); - zdialog_help(zd,"sync_files"); - - zdialog_run(zd,syncfiles_dialog_event); - zstat = zdialog_wait(zd); - - if (zstat != 1) { // dialog canceled - zdialog_free(zd); - if (dosync < 2) { // file sync is optional - gtk_main_quit(); - return 0; - } - zmessageACK(0,ZTX("file sync is mandatory")); - goto sync_dialog; - } - - pp = zmalloc(200); - zdialog_fetch(zd,"topdirk",pp,200); // get top directory - zdialog_free(zd); - - err = stat(pp,&statb); // check for validity - if (err || ! S_ISDIR(statb.st_mode)) { - zmessageACK(mWin,ZTX("top directory is invalid")); - zfree(pp); - goto sync_dialog; - } - - if (topdirk) zfree(topdirk); - topdirk = strdupz(pp,0,"topdirk"); - zfree(pp); - - fid = fopen(topdirk_file,"w"); // write top directory file - if (fid) { - fprintf(fid,"%s\n",topdirk); - fclose(fid); - } - - -start_sync: - -// look for orphan thumbnail files and delete them - - write_popup_text("open","Synchronize Files",500,300); // popup window for log data - write_popup_text("write","deleting orphan thumbnails"); - - snprintf(command,ccc,"%s*.thumbnails/*.png",topdirk); // find all /topdirk/.thumbnails/*.png - fcount = 0; - flag = 1; - - while ((thumbfile = (char *) SearchWild(command,flag))) // next thumbnail file - { - pp = strrchr(thumbfile,'/'); - if (strnNeq(pp-12,"/.thumbnails/",13)) continue; - fcc = strlen(pp) - 4; - if (strNeq(pp+fcc,".png")) continue; - - strncpy0(imagefile,thumbfile,maxfcc); // construct matching image file - dcc = pp - 12 - thumbfile; - if (dcc + fcc >= maxfcc) continue; - memmove(imagefile+dcc,pp,fcc); - imagefile[dcc+fcc] = 0; - - err = stat(imagefile,&statb); // look for image file - if (! err) continue; // found, keep thumbnail - - *pp = '/'; - remove(thumbfile); // not found, delete thumbnail - fcount++; // count thumbnails deleted - - snprintf(logrec,199,"delete thumbnail: %s",thumbfile); - write_popup_text("write",logrec); - } - - snprintf(logrec,199,"deleted %d orphan thumbnails",fcount); - write_popup_text("write",logrec); - -// look for image files without thumbnails and create the thumbnails - - snprintf(logrec,199,"creating missing and update stale thumbnails"); - write_popup_text("write",logrec); - - snprintf(command,ccc,"find \"%s\" -type d",topdirk); // find directories under top directory - contx = 0; - fcount = 0; - - while ((subdirk = command_output(contx,command))) - { - pp = strrchr(subdirk,'/'); - if (pp && strEqu(pp,"/.thumbnails")) { // /.../.thumbnails/ directory - zfree(subdirk); - continue; // skip - } - - Finit = 1; - filespec = syncfiles_find(subdirk,Finit); // get first image file - - while (filespec) // loop all image files - { - if (image_file_type(filespec) == 2) - { - if (filesync_thumbfile(filespec)) { - snprintf(logrec,199,"create thumbnail: %s",filespec); - write_popup_text("write",logrec); - fcount++; // count thumbnails created v.11.11 - } - } - - zfree(filespec); - filespec = syncfiles_find(subdirk,Finit); // next image file - } - - zfree(subdirk); - } - - snprintf(logrec,199,"created %d thumbnails",fcount); - write_popup_text("write",logrec); - - // Rebuild search index file. - // Process all image files within given top-level directory. - // Works incrementally and is very fast after the first run. - - snprintf(logrec,199,"rebuild search index"); - write_popup_text("write",logrec); - - char **ppv, tagsbuff[tagrecl]; - char *imagedate, *imagetags, *imagestars, *imagecomms, *imagecapt; - int Nold, Nnew, orec, nrec, comp; - struct tm bdt; - - fcount += 100000; // space for huge increase - - xrec_old = (tag_index_rec *) zmalloc(fcount * sizeof(tag_index_rec),"sync"); - xrec_new = (tag_index_rec *) zmalloc(fcount * sizeof(tag_index_rec),"sync"); - - // read current search index file and build "old list" of tags - - orec = Nold = 0; - fid = 0; - - fid = fopen(search_index_file,"r"); - - if (fid) - { - while (true) // read current search index records - { - pp = fgets_trim(tagsbuff,tagrecl,fid); // next record - if (! pp) break; - - if (strnEqu(pp,"file: ",6)) // start new file entry - { - if (++Nold == fcount) zappcrash("too many image files"); - orec = Nold - 1; - xrec_old[orec].file = strdupz(pp+6,0,"xrec_old.file"); - xrec_old[orec].imagedate[0] = 0; - xrec_old[orec].filedate[0] = 0; - xrec_old[orec].tags = 0; - xrec_old[orec].stars = '0'; - xrec_old[orec].comms = 0; - xrec_old[orec].capt = 0; - xrec_old[orec].update = '0'; - } - - if (strnEqu(pp,"date: ",6)) - { - ppc = strField(pp,' ',2); - if (ppc) strncpy0(xrec_old[orec].imagedate,ppc,12); - ppc = strField(pp,' ',3); - if (ppc) strncpy0(xrec_old[orec].filedate,ppc,16); - } - - if (strnEqu(pp,"tags: ",6)) - xrec_old[orec].tags = strdupz(pp+6,0,"sync"); - - if (strnEqu(pp,"stars: ",7)) - xrec_old[orec].stars = *(pp+7); - - if (strnEqu(pp,"comms: ",7)) - xrec_old[orec].comms = strdupz(pp+7,0,"sync"); - - if (strnEqu(pp,"capt: ",6)) - xrec_old[orec].capt = strdupz(pp+6,0,"sync"); // v.10.12 - } - - fclose(fid); - } - - snprintf(logrec,199,"%d current index records found",Nold); - write_popup_text("write",logrec); - - // find all image files and create "new list" with no tags - - snprintf(logrec,199,"find all image files and build index records"); - write_popup_text("write",logrec); - - snprintf(command,ccc,"find \"%s\" -type d",topdirk); // find directories under top directory - contx = 0; - Nnew = nrec = 0; - - while ((subdirk = command_output(contx,command))) - { - pp = strrchr(subdirk,'/'); - if (pp && strEqu(pp,"/.thumbnails")) // skip ./thumbnails directories - { - zfree(subdirk); - continue; - } - - Finit = 1; - filespec = syncfiles_find(subdirk,Finit); // get first image file - - while (filespec) // loop all image files - { - if (image_file_type(filespec) == 2) // construct new tag record - { - err = stat(filespec,&statb); - if (err) continue; - if (++Nnew == fcount) zappcrash("too many image files"); - nrec = Nnew - 1; - xrec_new[nrec].file = strdupz(filespec,0,"sync"); // image filespec - xrec_new[nrec].imagedate[0] = 0; // image date = empty - gmtime_r(&statb.st_mtime,&bdt); // file date = yyyymmddhhmmss - snprintf(xrec_new[nrec].filedate,16,"%04d%02d%02d%02d%02d%02d", - bdt.tm_year + 1900, bdt.tm_mon + 1, bdt.tm_mday, - bdt.tm_hour, bdt.tm_min, bdt.tm_sec); - xrec_new[nrec].tags = 0; // tags = empty - xrec_new[nrec].stars = '0'; // stars = '0' - xrec_new[nrec].comms = 0; // comments = empty - xrec_new[nrec].capt = 0; // caption = empty v.10.12 - } - - zfree(filespec); - filespec = syncfiles_find(subdirk,Finit); // next image file - } - - zfree(subdirk); - } - - snprintf(logrec,199,"found %d image files",Nnew); - write_popup_text("write",logrec); - - // merge and compare lists - // if filespecs match and have the same date, then old tags are OK - - snprintf(logrec,199,"merging old and new index records"); - write_popup_text("write",logrec); - - HeapSort((char *) xrec_old,sizeof(tag_index_rec),Nold,syncfiles_index_compare); - HeapSort((char *) xrec_new,sizeof(tag_index_rec),Nnew,syncfiles_index_compare); - - for (orec = nrec = 0; nrec < Nnew; ) - { - xrec_new[nrec].update = '1'; // assume update is needed - - if (orec == Nold) comp = +1; - else comp = strcmp(xrec_old[orec].file, xrec_new[nrec].file); // compare filespecs - - if (comp > 0) nrec++; - else if (comp < 0) orec++; - else // matching filespecs - { - if (strEqu(xrec_new[nrec].filedate, xrec_old[orec].filedate)) // and matching file dates - { // copy data from old to new - strncpy0(xrec_new[nrec].imagedate,xrec_old[orec].imagedate,12); - xrec_new[nrec].tags = xrec_old[orec].tags; - xrec_old[orec].tags = 0; - xrec_new[nrec].stars = xrec_old[orec].stars; - xrec_new[nrec].comms = xrec_old[orec].comms; - xrec_old[orec].comms = 0; - xrec_new[nrec].capt = xrec_old[orec].capt; - xrec_old[orec].capt = 0; - xrec_new[nrec].update = '0'; // update is not needed - } - nrec++; - orec++; - } - } - - for (orec = 0; orec < Nold; orec++) // release old list memory - { - zfree(xrec_old[orec].file); - if (xrec_old[orec].tags) zfree(xrec_old[orec].tags); - if (xrec_old[orec].capt) zfree(xrec_old[orec].capt); // memory leak v.11.09 - if (xrec_old[orec].comms) zfree(xrec_old[orec].comms); - } - - zfree(xrec_old); - xrec_old = 0; - - // process entries needing update in new index list - // get updated tags from image file EXIF/IPTC data - - snprintf(logrec,199,"updating index records"); - write_popup_text("write",logrec); - - for (fcount = nrec = 0; nrec < Nnew; nrec++) - { - if (xrec_new[nrec].update == '0') continue; // no update needed - fcount++; // running count of updates - - // ================================================================== - - char ** syncfiles_info_get_exiv2(cchar *file); // new v.11.10 - static int exiv2err = 1; // try exiv2, much faster *** not yet *** - - if (! exiv2err) { - ppv = syncfiles_info_get_exiv2(xrec_new[nrec].file); - if (! ppv) { - printf("exiv2 failed, switching to exiftool \n"); - exiv2err = 1; - } - } - - if (exiv2err) - ppv = info_get(xrec_new[nrec].file,exifkeys,5); // get exif/iptc data - - // ================================================================== - - imagedate = ppv[0]; - imagetags = ppv[1]; - imagestars = ppv[2]; - imagecomms = ppv[3]; - imagecapt = ppv[4]; - - if (imagedate && strlen(imagedate) > 3) { // image date v.11.10 - if (strlen(imagedate) > 9) imagedate[10] = 0; // truncate to yyyy:mm:dd - strcpy(xrec_new[nrec].imagedate,imagedate); - } - else strcpy(xrec_new[nrec].imagedate,"null"); - - if (imagetags && strlen(imagetags)) // image tags - xrec_new[nrec].tags = strdupz(imagetags,0,"sync"); - else xrec_new[nrec].tags = strdupz("null"tagdelim2,0,"sync"); // v.11.02 - - if (imagestars && strlen(imagestars)) // image rating - xrec_new[nrec].stars = *imagestars; - - if (imagecomms && strlen(imagecomms)) // image comments - xrec_new[nrec].comms = strdupz(imagecomms,0,"sync"); - else xrec_new[nrec].comms = strdupz("null",0,"sync"); - - if (imagecapt && strlen(imagecapt)) // image caption v.10.12 - xrec_new[nrec].capt = strdupz(imagecapt,0,"sync"); - else xrec_new[nrec].capt = strdupz("null",0,"sync"); - - if (imagedate) zfree(imagedate); - if (imagetags) zfree(imagetags); - if (imagestars) zfree(imagestars); - if (imagecomms) zfree(imagecomms); - if (imagecapt) zfree(imagecapt); - - snprintf(logrec,199,"update index: %s",xrec_new[nrec].file); - write_popup_text("write",logrec); - } - - fid = fopen(search_index_file,"w"); // write new search index file - if (! fid) zappcrash("cannot write tags file"); // with merged data - - for (nrec = 0; nrec < Nnew; nrec++) - { - fprintf(fid,"file: %s""\n",xrec_new[nrec].file); - fprintf(fid,"date: %s %s""\n",xrec_new[nrec].imagedate, xrec_new[nrec].filedate); - fprintf(fid,"tags: %s""\n",xrec_new[nrec].tags); - fprintf(fid,"stars: %c""\n",xrec_new[nrec].stars); - fprintf(fid,"comms: %s""\n",xrec_new[nrec].comms); - fprintf(fid,"capt: %s""\n",xrec_new[nrec].capt); - fprintf(fid,"\n"); - } - - fclose(fid); - - for (nrec = 0; nrec < Nnew; nrec++) // release new list memory - { - zfree(xrec_new[nrec].file); - if (xrec_new[nrec].tags) zfree(xrec_new[nrec].tags); - if (xrec_new[nrec].capt) zfree(xrec_new[nrec].capt); // memory leak v.11.09 - if (xrec_new[nrec].comms) zfree(xrec_new[nrec].comms); - } - - zfree(xrec_new); - xrec_new = 0; - - snprintf(logrec,199,"%d image files updated",fcount); - write_popup_text("write",logrec); - - write_popup_text("write","COMPLETED"); - printf("sync files subprocess completed \n"); - - global_unlock(syncfd); // release file sync lock - - while (zfuncs::open_popup_windows) { // wait for popup window to be closed - zmainloop(); - zsleep(0.1); - } - - gtk_main_quit(); // gone forever - return 0; -} - - -// dialog event function - file chooser for top image directory - -int syncfiles_dialog_event(zdialog *zd, cchar *event) -{ - char *pp; - - if (! strEqu(event,"browse")) return 0; - pp = zgetfile1(ZTX("Select top image directory"),"folder",topdirk); // get topmost directory - if (! pp) return 0; - zdialog_stuff(zd,"topdirk",pp); - zfree(pp); - return 0; -} - - -// find image files in a directory, return one per call // v.11.11 - -char * syncfiles_find(char *imagedirk, int &Finit) -{ - char *file; - cchar *findcommand = "find \"%s\" -maxdepth 1 -type f"; - static int contx, ftyp; - - if (Finit) { - Finit = 0; - contx = 0; - } - - while ((file = command_output(contx,findcommand,imagedirk))) // find next file in directory - { - if (! file) return 0; // EOL - ftyp = image_file_type(file); - if (ftyp == 2) return file; // supported image file type - zfree(file); - continue; - } - - return 0; -} - - -// Find the thumbnail file for the given image file. -// If missing or stale, add or update in /.thumbnails directory. -// Returns 0 if thumbnail file was OK, 1 if it was created. - -int filesync_thumbfile(char *imagefile) // v.11.11 -{ - GdkPixbuf *thumbpxb; - GError *gerror = 0; - char *pfile, *bfile, *thumbfile; - int err, sizew, sizeh; - struct stat statf, statb; - - err = stat(imagefile,&statf); // stat the image file - if (err) return 0; - pfile = strrchr(imagefile,'/'); // get .../filename.xxx - if (! pfile) return 0; - thumbfile = strdupz(imagefile,20,"image_thumbfile"); // construct thumbnail file - bfile = thumbfile + (pfile - imagefile); // .../.thumbnails/filename.xxx.png - strcpy(bfile,"/.thumbnails"); - bfile += 12; - strcpy(bfile,pfile); - strcat(bfile,".png"); - - err = stat(thumbfile,&statb); // stat the thumbnail file - if (! err && statb.st_mtime >= statf.st_mtime) return 0; // found and up to date - - *bfile = 0; - err = stat(thumbfile,&statb); - if (err) err = mkdir(thumbfile,0751); // create .thumbnails directory - if (err) return 0; - - *bfile = *pfile; - sizew = sizeh = image_navi::thumbfilesize; // create thumbnail pixbuf - thumbpxb = gdk_pixbuf_new_from_file_at_size(imagefile,sizew,sizeh,&gerror); - if (! thumbpxb) { - printf("gdk_pixbuf_new error: %s \n",gerror->message); // diagnose error v.3.3 - return 0; - } - gdk_pixbuf_save(thumbpxb,thumbfile,"png",&gerror,null); // save in /.thumbnails/ directory - g_object_unref(thumbpxb); - - return 1; -} - - -// sort compare function - compare tag record filespecs and return -// <0 | 0 | >0 for file1 < | == | > file2 - -int syncfiles_index_compare(cchar *rec1, cchar *rec2) -{ - char * file1 = ((tag_index_rec *) rec1)->file; - char * file2 = ((tag_index_rec *) rec2)->file; - return strcmp(file1,file2); -} - - -// Get EXIF/IPTC metadata for fotoxx index file, using exiv2. -// Returns array of pointers to corresponding key values. -// If a key is missing, corresponding pointer is null. -// -// command: -// exiv2 -Pkv -g keyname1 -g keyname2 ... "file" -// command output: -// keyname1 keyvalue1 -// keyname2 keyvalue2 -// ... -// -// The overhead is about 0.01 seconds elapsed on a 7200 RPM disk. - -char ** syncfiles_info_get_exiv2(cchar *file) // new v.11.10 -{ - cchar *keynames[5] = { "Exif.Photo.DateTimeOriginal", - "Iptc.Application2.Keywords", - "Xmp.xmp.Rating", - "Exif.Photo.UserComment", - "Iptc.Application2.Caption" }; - - static char *keyvalues[5]; - - char *pp1, *pp2; - int contx = 0, err, ii, jj; - uint cc; - - strcpy(command,"exiv2 -Pkv"); // build command line - - for (ii = 0; ii < 5; ii++) - { - keyvalues[ii] = null; - strncatv(command,ccc," -g ",keynames[ii],null); - } - - strncatv(command,ccc," \"",file,"\"",null); - - while (true) - { - pp1 = command_output(contx,command); - if (! pp1) break; - - for (ii = 0; ii < 5; ii++) - { - cc = strlen(keynames[ii]); - if (strncasecmp(pp1,keynames[ii],cc) == 0) { // match keyname, ignore case - pp2 = pp1 + cc; // skip to keyvalue - while (*pp2 == ' ') pp2++; // and intervening blanks - if (strnEqu(pp2,"charset=",8)) { // skip charset="Ascii" or "Unicode" - pp2 += 10; - for (jj = 0; jj < 10; jj++) - if (pp2[jj] == '"') break; - if (jj < 10) pp2 += jj + 1; - while (*pp2 && *pp2 <= ' ') pp2++; - } - if (strnEqu(pp2,"(Binary value suppressed)",25)) continue; // ignore (Binary value suppressed) - cc = strlen(pp2); - if (! cc) continue; // ignore blank output - if (cc > 999) pp2[999] = 0; // truncate to 999 chars. max. - keyvalues[ii] = strdupz(pp2,0,"index.data"); // return keyvalue - } - } - - zfree(pp1); - } - - err = command_status(contx); - if (err) printf(" syncfiles_info_get_exiv2: %s \n %d %s \n",file,err,wstrerror(err)); - if (err && err != 253) return 0; - - return keyvalues; -} - - -/**************************************************************************/ - -// customize toolbar style: icons, text, or both - -void m_tbar_style(GtkWidget *, cchar *) // new function v.11.06 -{ - int tbar_style_event(zdialog *zd, cchar *event); - zdialog *zd; - - zfuncs::F1_help_topic = "toolbar_style"; - - zd = zdialog_new(ZTX("Toolbar Style"),mWin,Bdone,null); - zdialog_add_widget(zd,"hbox","hbs","dialog",0,"space=5"); - zdialog_add_widget(zd,"radio","icons","hbs",ZTX("icons"),"space=5"); - zdialog_add_widget(zd,"radio","text","hbs",ZTX("text"),"space=5"); - zdialog_add_widget(zd,"radio","both","hbs",ZTX("both"),"space=5"); - - zdialog_stuff(zd,"icons",0); - zdialog_stuff(zd,"text",0); - zdialog_stuff(zd,"both",0); - zdialog_stuff(zd,tbar_style,1); - - zdialog_run(zd,tbar_style_event); // v.11.07 - zdialog_wait(zd); - zdialog_free(zd); - return; -} - - -// process dialog event - -int tbar_style_event(zdialog *zd, cchar *event) -{ - if (zd->zstat) return 0; - tbar_style_set(event); - return 0; -} - - -// set toolbar style - also called at startup initialization - -void tbar_style_set(cchar *style) -{ - if (! style) { - if (strEqu(tbar_style,"undefined")) - tbar_style = "both"; - style = tbar_style; - } - - if (strEqu(style,"icons")) { - gtk_toolbar_set_style(GTK_TOOLBAR(mTbar),GTK_TOOLBAR_ICONS); - tbar_style = "icons"; - } - - if (strEqu(style,"text")) { - gtk_toolbar_set_style(GTK_TOOLBAR(mTbar),GTK_TOOLBAR_TEXT); - tbar_style = "text"; - } - - if (strEqu(style,"both")) { - gtk_toolbar_set_style(GTK_TOOLBAR(mTbar),GTK_TOOLBAR_BOTH); - tbar_style = "both"; - } - - return; -} - - -/**************************************************************************/ - -// dump memory usage by category to STDOUT - -void m_memory_usage(GtkWidget *, cchar *) -{ - zfuncs::F1_help_topic = "memory_usage"; - zmalloc_report(); - return; -} - - - - - diff -Nru fotoxx-11.11.1/fotoxx_transform.cc fotoxx-12.01.2/fotoxx_transform.cc --- fotoxx-11.11.1/fotoxx_transform.cc 2011-11-05 05:30:36.000000000 +0000 +++ fotoxx-12.01.2/fotoxx_transform.cc 1970-01-01 00:00:00.000000000 +0000 @@ -1,4090 +0,0 @@ -/************************************************************************** - - Fotoxx edit photos and manage collections - - Copyright 2007 2008 2009 2010 2011 Michael Cornelison - Source URL: http://kornelix.squarespace.com/fotoxx - Contact: kornelix2@googlemail.com - - 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 http://www.gnu.org/licenses/. - -***************************************************************************/ - -#define EX extern // enable extern declarations -#include "fotoxx.h" - - -/************************************************************************** - - Fotoxx image edit - transform functions - -***************************************************************************/ - - -// rotate image through any arbitrary angle - -double rotate_angle = 0; // E3 rotatation vs. F -double rotate_delta = 0; -int rotate_trim = 0; - -editfunc EFrotate; - - -void m_rotate(GtkWidget *, cchar *menu) // menu function -{ - int rotate_dialog_event(zdialog *zd, cchar *event); - void * rotate_thread(void *); - void rotate_mousefunc(); - - cchar *rotmess = ZTX("Use buttons or drag right edge with mouse"); - - zfuncs::F1_help_topic = "rotate"; // v.10.8 - - EFrotate.funcname = "rotate"; - EFrotate.Fprev = 1; // use preview - EFrotate.threadfunc = rotate_thread; // thread function - EFrotate.mousefunc = rotate_mousefunc; // mouse function - if (! edit_setup(EFrotate)) return; // setup edit - - zdialog *zd = zdialog_new(ZTX("Rotate Image"),mWin,Bdone,Bcancel,null); - EFrotate.zd = zd; - - zdialog_add_widget(zd,"label","labrot","dialog",ZTX(rotmess),"space=5"); - zdialog_add_widget(zd,"label","labdeg","dialog",ZTX("degrees"),"space=5"); - zdialog_add_widget(zd,"hbox","hb1","dialog",0,"homog|space=5"); - zdialog_add_widget(zd,"vbox","vb1","hb1",0,"space=5"); - zdialog_add_widget(zd,"vbox","vb2","hb1",0,"space=5"); - zdialog_add_widget(zd,"vbox","vb3","hb1",0,"space=5"); - zdialog_add_widget(zd,"vbox","vb4","hb1",0,"space=5"); - zdialog_add_widget(zd,"button"," +0.1 ","vb1"," + 0.1 "); // button name is increment to use - zdialog_add_widget(zd,"button"," -0.1 ","vb1"," - 0.1 "); - zdialog_add_widget(zd,"button"," +1.0 ","vb2"," + 1 "); - zdialog_add_widget(zd,"button"," -1.0 ","vb2"," - 1 "); - zdialog_add_widget(zd,"button"," +10.0 ","vb3"," + 10 "); - zdialog_add_widget(zd,"button"," -10.0 ","vb3"," - 10 "); - zdialog_add_widget(zd,"button"," +90.0 ","vb4"," + 90 "); - zdialog_add_widget(zd,"button"," -90.0 ","vb4"," - 90 "); - zdialog_add_widget(zd,"hbox","hb2","dialog",0,"space=10"); - zdialog_add_widget(zd,"label","space","hb2",0,"expand"); - zdialog_add_widget(zd,"button","trim","hb2",ZTX("Trim"),"space=10"); - zdialog_add_widget(zd,"button","grid","hb2",ZTX("Grid"),"space=10"); - - zdialog_help(zd,"rotate"); // zdialog help topic v.11.08 - zdialog_run(zd,rotate_dialog_event,"save"); // run dialog, parallel v.11.07 - - takeMouse(zd,rotate_mousefunc,dragcursor); // connect mouse function v.11.03 - rotate_angle = rotate_delta = rotate_trim = 0; - - load_grid(rotate_grid); // load grid preferences v.11.11 - - return; -} - - -// dialog event and completion callback function - -int rotate_dialog_event(zdialog *zd, cchar * event) -{ - int err, trim = 0; - double incr; - char text[40]; - - if (zd->zstat) // dialog complete - { - if (zd->zstat == 1) { - rotate_delta = rotate_angle; // rotate main image - rotate_angle = 0; - edit_done(EFrotate); - } - else edit_cancel(EFrotate); // canceled - - rotate_angle = rotate_delta = rotate_trim = 0; - - save_grid(rotate_grid); // save grid preferences v.11.11 - Fgrid = 0; // grid off - - mwpaint2(); - return 0; - } - - if (strEqu(event,"trim")) { - rotate_trim = 1 - rotate_trim; // toggle trim button - if (rotate_trim) zdialog_stuff(zd,"trim",ZTX("Undo Trim")); - else zdialog_stuff(zd,"trim",ZTX("Trim")); - trim = 1; // v.10.3 - } - - if (strpbrk(event,"+-")) { - err = convSD(event,incr); // button name is increment to use - if (err) return 0; - rotate_delta += incr; - } - - if (rotate_delta || trim) { - trim = 0; - zdialog_stuff(zd,"labdeg","computing"); - signal_thread(); // do rotate in thread - wait_thread_idle(); - snprintf(text,40,ZTX("degrees: %.1f"),rotate_angle); // update dialog angle display v.11.08 - zdialog_stuff(zd,"labdeg",text); - } - - if (strEqu(event,"grid")) m_gridlines(0,0); // grid dialog v.11.11 - - if (strstr("KB G KB g",event)) // G key, toggle grid v.11.11 - toggle_grid(2); - - return 1; -} - - -// rotate mouse function - drag right edge of image up/down for rotation - -void rotate_mousefunc() -{ - static int mpx0 = 0, mpy0 = 0; - static int mpy1, mpy2, dist; - zdialog *zd = EFrotate.zd; - - if (! Mxdrag && ! Mydrag) return; // no drag underway - if (Mxdrag < 0.8 * E3ww) return; // not right edge of image - - if (Mxdown != mpx0 || Mydown != mpy0) { - mpx0 = Mxdown; // new drag started - mpy0 = mpy1 = Mydown; - } - - mpy2 = Mydrag; - dist = mpy2 - mpy1; // drag distance - mpy1 = mpy2; // reset origin for next time - if (! dist) return; - - rotate_delta = 30.0 * dist / E3ww; // convert to angle - rotate_dialog_event(zd,"mouse"); - return; -} - - -// rotate thread function - -void * rotate_thread(void *) -{ - int px3, py3, px9, py9; - int wwcut, hhcut, ww, hh; - double trim_angle, radians; - uint16 *pix3, *pix9; - - while (true) - { - thread_idle_loop(); // wait for work or exit request - - mutex_lock(&Fpixmap_lock); - - rotate_angle += rotate_delta; // accum. net rotation - rotate_delta = 0; // from dialog widget - - if (rotate_angle >= 360) rotate_angle -=360; - if (rotate_angle <= -360) rotate_angle +=360; - if (fabs(rotate_angle) < 0.01) rotate_angle = 0; - - if (! rotate_angle) { - PXM_free(E3pxm16); // E1 >> E3 - E3pxm16 = PXM_copy(E1pxm16); - E3ww = E1ww; - E3hh = E1hh; - CEF->Fmod = 0; - } - - if (rotate_angle) { - PXM_free(E3pxm16); - E3pxm16 = PXM_rotate(E1pxm16,rotate_angle); // E3 is rotated E1 - E3ww = E3pxm16->ww; - E3hh = E3pxm16->hh; - CEF->Fmod = 1; - } - - if (rotate_trim) - { // auto trim - trim_angle = fabs(rotate_angle); - while (trim_angle > 45) trim_angle -= 90; - radians = fabs(trim_angle / 57.296); - wwcut = int(E3pxm16->hh * sin(radians) + 1); // amount to trim - hhcut = int(E3pxm16->ww * sin(radians) + 1); - ww = E3pxm16->ww - 2 * wwcut; - hh = E3pxm16->hh - 2 * hhcut; - if (ww > 0 && hh > 0) { - E9pxm16 = PXM_make(ww,hh,16); - - for (py3 = hhcut; py3 < E3hh-hhcut; py3++) // E9 = trimmed E3 - for (px3 = wwcut; px3 < E3ww-wwcut; px3++) - { - px9 = px3 - wwcut; - py9 = py3 - hhcut; - pix3 = PXMpix(E3pxm16,px3,py3); - pix9 = PXMpix(E9pxm16,px9,py9); - pix9[0] = pix3[0]; - pix9[1] = pix3[1]; - pix9[2] = pix3[2]; - } - - PXM_free(E3pxm16); // E3 = E9 - E3pxm16 = E9pxm16; - E9pxm16 = 0; - E3ww = ww; - E3hh = hh; - } - } - - mutex_unlock(&Fpixmap_lock); - mwpaint2(); // update window - } - - return 0; // not executed, stop g++ warning -} - - -/**************************************************************************/ - -// trim image - use mouse to select image region to retain - -int trimx1, trimy1, trimx2, trimy2; // current trim rectangle -int trimpx1, trimpy1, trimpx2, trimpy2; // prior trim rectangle -double trimR; // trim ratio, width/height - -void trim_mousefunc(); // edit trim margins with mouse -void trim_dialog(); -void trim_trim(int mode); // show trim area, trim image - -editfunc EFtrim; - - -void m_trim(GtkWidget *, cchar *) -{ - zfuncs::F1_help_topic = "trim_image"; // v.10.8 - - EFtrim.funcname = "trim"; - EFtrim.mousefunc = trim_mousefunc; - if (! edit_setup(EFtrim)) return; // setup edit - - if (! trimbuttons[0] || strEqu(trimbuttons[0],"undefined")) { - trimbuttons[0] = strdupz("1:1",8); // default trim buttons v.10.10.2 - trimbuttons[1] = strdupz("2:1",8); - trimbuttons[2] = strdupz("3:2",8); - trimbuttons[3] = strdupz("4:3",8); - trimbuttons[4] = strdupz("16:9",8); - trimbuttons[5] = strdupz(ZTX("gold"),8); - - trimratios[0] = strdupz("1:1",8); // default trim ratios v.10.10.2 - trimratios[1] = strdupz("2:1",8); - trimratios[2] = strdupz("3:2",8); - trimratios[3] = strdupz("4:3",8); - trimratios[4] = strdupz("16:9",8); - trimratios[5] = strdupz("1.618:1",8); // fix inverted ratio v.10.10.3 - } - - if (trimsize[0] < 0.95 * iww && trimsize[1] < 0.95 * ihh) { // use last trim size if within limits - trimx1 = Iorgx + 0.5 * (iww - trimsize[0]); - trimx2 = trimx1 + trimsize[0]; - trimy1 = Iorgy + 0.5 * (ihh - trimsize[1]); - trimy2 = trimy1 + trimsize[1]; - } - else { // else use 90% current dimensions - trimx1 = Iorgx + 0.05 * iww; - trimx2 = Iorgx + 0.95 * iww; - trimy1 = Iorgy + 0.05 * ihh; - trimy2 = Iorgy + 0.95 * ihh; - } - - trimpx1 = Iorgx; // prior trim rectangle - trimpx2 = Iorgx + iww; // = 100% of image - trimpy1 = Iorgy; - trimpy2 = Iorgy + ihh; - - trimsize[0] = (trimx2 - trimx1); - trimsize[1] = (trimy2 - trimy1); - trimR = 1.0 * trimsize[0] / trimsize[1]; - - trim_trim(0); // show trim area in image - takeMouse(0,trim_mousefunc,dragcursor); // connect mouse function v.11.03 - trim_dialog(); // start dialog - - return; -} - - -// dialog function is called from two places - -void trim_dialog() -{ - int trim_dialog_event(zdialog *zd, cchar *event); - - cchar *trim_message = ZTX("Drag middle to move, drag corners to resize."); - char text[20]; - int ii; - -/** - Drag middle to move, drag corners to resize - - width [___] height [___] ratio [___] // width/height inputs v.11.05 - [1:1] [2:1] [3:2] [4:3] [16:9] [gold] [invert] - [x] Lock Ratio [x] my mouse - - [customize] [Done] [Cancel] -**/ - - zdialog *zd = zdialog_new(ZTX("Trim Image"),mWin,ZTX("customize"),Bdone,Bcancel,null); - EFtrim.zd = zd; - - zdialog_add_widget(zd,"label","lab1","dialog",trim_message,"space=8"); - zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=4"); - zdialog_add_widget(zd,"label","labW","hb1",ZTX("width"),"space=3"); - zdialog_add_widget(zd,"spin","width","hb1","20|9999|1|1000"); - zdialog_add_widget(zd,"label","space","hb1",0,"space=5"); - zdialog_add_widget(zd,"label","labH","hb1",ZTX("height"),"space=3"); - zdialog_add_widget(zd,"spin","height","hb1","20|9999|1|600"); - zdialog_add_widget(zd,"label","space","hb1",0,"space=5"); - zdialog_add_widget(zd,"label","labR","hb1",ZTX("ratio"),"space=3"); - zdialog_add_widget(zd,"label","ratio","hb1","1.67 "); - zdialog_add_widget(zd,"hbox","hb2","dialog",0,"space=4"); // ratio buttons - zdialog_add_widget(zd,"hbox","hb3","dialog",0,"space=4"); - zdialog_add_widget(zd,"check","lock","hb3",ZTX("Lock Ratio"),"space=3"); - zdialog_add_widget(zd,"check","mymouse","hb3",BmyMouse,"space=8"); - - for (ii = 0; ii < 6; ii++) // 6 custom buttons v.10.10.2 - zdialog_add_widget(zd,"button",trimbuttons[ii],"hb2",trimbuttons[ii]); - - zdialog_add_widget(zd,"button","invert","hb2",ZTX("invert")); // [invert] button - - zdialog_stuff(zd,"width",trimsize[0]); // stuff width, height, ratio v.11.05 - zdialog_stuff(zd,"height",trimsize[1]); - sprintf(text,"%.2f ",trimR); - zdialog_stuff(zd,"ratio",text); - zdialog_stuff(zd,"mymouse",1); // v.11.05 - - zdialog_help(zd,"trim_image"); // zdialog help topic v.11.08 - zdialog_run(zd,trim_dialog_event,"save"); // run dialog - parallel v.11.07 - return; -} - - -// dialog event and completion callback function - -int trim_dialog_event(zdialog *zd, cchar *event) // overhauled v.11.05 -{ - void trim_customize(); - - static int flip = 0; - int width, height, delta; - int ii, rlock, mymouse; - double r1, r2, ratio = 0; - char text[20]; - cchar *pp; - - if (zd->zstat) // dialog complete - { - paint_toplines(2); // erase rectangle outline v.11.05 - - if (zd->zstat == 1) { // customize buttons - zdialog_free(zd); // kill trim dialog - trim_customize(); // do customize dialog - trim_trim(0); // show trim area in image v.11.05 - takeMouse(0,trim_mousefunc,dragcursor); // connect mouse function v.11.05 - trim_dialog(); // restart dialog - return 0; - } - - if (zd->zstat != 2) { // cancel - edit_cancel(EFtrim); - return 0; - } - - trimsize[0] = trimx2 - trimx1; // apply - trimsize[1] = trimy2 - trimy1; - - trim_trim(1); // do trim on image - Fzoom = 0; // v.11.01 - edit_done(EFtrim); - return 0; - } - - if (strEqu(event,"mymouse")) { // my mouse toggle v.11.05 - zdialog_fetch(zd,"mymouse",mymouse); - if (mymouse) - takeMouse(0,trim_mousefunc,dragcursor); // connect mouse function - else freeMouse(); // disconnect mouse - return 0; - } - - if (strstr("width height",event)) // get direct width/height inputs - { // v.11.05 - zdialog_fetch(zd,"width",width); - zdialog_fetch(zd,"height",height); - zdialog_fetch(zd,"lock",rlock); // lock ratio on/off - - - if (strEqu(event,"width")) { // v.11.05 - if (width > iww) width = iww; - if (rlock) { // ratio locked - height = width / trimR + 0.5; // try to keep ratio - if (height > ihh) height = ihh; - zdialog_stuff(zd,"height",height); - } - } - - if (strEqu(event,"height")) { - if (height > ihh) height = ihh; - if (rlock) { - width = height * trimR + 0.5; - if (width > iww) width = iww; - zdialog_stuff(zd,"width",width); - } - } - - flip = 1 - flip; // alternates 0, 1, 0, 1 ... - - delta = width - trimsize[0]; - - if (delta > 0) { // increase width - trimx1 = trimx1 - delta / 2; // left and right sides equally - trimx2 = trimx2 + delta / 2; - if (delta % 2) { // if increase is odd - trimx1 = trimx1 - flip; // add 1 alternatively to each side - trimx2 = trimx2 + 1 - flip; - } - } - - if (delta < 0) { // decrease width - trimx1 = trimx1 - delta / 2; - trimx2 = trimx2 + delta / 2; - if (delta % 2) { - trimx1 = trimx1 + flip; - trimx2 = trimx2 - 1 + flip; - } - } - - delta = height - trimsize[1]; - - if (delta > 0) { // increase width - trimy1 = trimy1 - delta / 2; // left and right sides equally - trimy2 = trimy2 + delta / 2; - if (delta % 2) { // if increase is odd - trimy1 = trimy1 - flip; // add 1 alternatively to each side - trimy2 = trimy2 + 1 - flip; - } - } - - if (delta < 0) { // decrease width - trimy1 = trimy1 - delta / 2; - trimy2 = trimy2 + delta / 2; - if (delta % 2) { - trimy1 = trimy1 + flip; - trimy2 = trimy2 - 1 + flip; - } - } - - if (trimx1 < Iorgx) trimx1 = Iorgx; - if (trimx2 > Iorgx + iww) trimx2 = Iorgx + iww; - if (trimy1 < Iorgy) trimy1 = Iorgy; - if (trimy2 > Iorgy + ihh) trimy2 = Iorgy + ihh; - - width = trimx2 - trimx1; // new width and height - height = trimy2 - trimy1; - - zdialog_stuff(zd,"width",width); // update dialog values - zdialog_stuff(zd,"height",height); - - trimsize[0] = width; // new rectangle dimensions - trimsize[1] = height; - - if (! rlock) // set new ratio if not locked - trimR = 1.0 * trimsize[0] / trimsize[1]; - - sprintf(text,"%.2f ",trimR); // stuff new ratio - zdialog_stuff(zd,"ratio",text); - - trim_trim(0); // show trim area in image - return 0; - } - - for (ii = 0; ii < 6; ii++) // trim ratio buttons - if (strEqu(event,trimbuttons[ii])) break; - if (ii < 6) { - r1 = r2 = ratio = 0; - pp = strField(trimratios[ii],':',1); - if (pp) r1 = atof(pp); - pp = strField(trimratios[ii],':',2); - if (pp) r2 = atof(pp); - if (r1 > 0 && r2 > 0) ratio = r1/r2; - if (ratio < 0.1 || ratio > 10) ratio = 1.0; - if (! ratio) return 0; - zdialog_stuff(zd,"lock",1); // assume lock is wanted - trimR = ratio; - } - - if (strEqu(event,"invert")) // invert ratio button - if (trimR) ratio = 1.0 / trimR; - - if (ratio) // ratio was changed - { - trimR = ratio; - - if (trimx2 - trimx1 > trimy2 - trimy1) - trimy2 = trimy1 + (trimx2 - trimx1) / trimR; // adjust smaller dimension - else - trimx2 = trimx1 + (trimy2 - trimy1) * trimR; - - if (trimx2 > Iorgx + iww) { // if off the right edge, - trimx2 = Iorgx + iww; // adjust height - trimy2 = trimy1 + (trimx2 - trimx1) / trimR; - } - - if (trimy2 > Iorgy + ihh) { // if off the bottom edge, - trimy2 = Iorgy + ihh; // adjust width - trimx2 = trimx1 + (trimy2 - trimy1) * trimR; - } - - trimsize[0] = trimx2 - trimx1; // new rectangle dimensions - trimsize[1] = trimy2 - trimy1; - - zdialog_stuff(zd,"width",trimsize[0]); // stuff width, height, ratio v.11.05 - zdialog_stuff(zd,"height",trimsize[1]); - sprintf(text,"%.2f ",trimR); - zdialog_stuff(zd,"ratio",text); - - trim_trim(0); // show trim area in image - return 0; - } - - return 0; -} - - -// trim mouse function - -void trim_mousefunc() -{ - int mpx, mpy, xdrag, ydrag, rlock; - int corner, chop, moveall = 0; - int dx, dy, dd, d1, d2, d3, d4; - char text[20]; - double drr; - zdialog *zd = EFtrim.zd; - - if (LMclick || Mxdrag || Mydrag) // mouse click or drag - { - if (LMclick) { - mpx = Mxclick; // click - mpy = Myclick; - xdrag = ydrag = 0; - LMclick = 0; - } - else { - mpx = Mxdrag; // drag - mpy = Mydrag; - xdrag = Mxdrag - Mxdown; - ydrag = Mydrag - Mydown; - Mxdown = Mxdrag; // reset drag origin - Mydown = Mydrag; - } - - if (Mxdrag || Mydrag) { - moveall = 1; - dd = 0.1 * (trimx2 - trimx1); // test if mouse is in the broad - if (mpx < trimx1 + dd) moveall = 0; // middle of the rectangle - if (mpx > trimx2 - dd) moveall = 0; - dd = 0.1 * (trimy2 - trimy1); - if (mpy < trimy1 + dd) moveall = 0; - if (mpy > trimy2 - dd) moveall = 0; - } - - if (moveall) { // yes, move the whole rectangle - trimx1 += xdrag; - trimx2 += xdrag; - trimy1 += ydrag; - trimy2 += ydrag; - corner = 0; - } - - else { // no, find closest corner - dx = mpx - trimx1; - dy = mpy - trimy1; - d1 = sqrt(dx*dx + dy*dy); // distance from NW corner - - dx = mpx - trimx2; - dy = mpy - trimy1; - d2 = sqrt(dx*dx + dy*dy); - - dx = mpx - trimx2; - dy = mpy - trimy2; - d3 = sqrt(dx*dx + dy*dy); - - dx = mpx - trimx1; - dy = mpy - trimy2; - d4 = sqrt(dx*dx + dy*dy); - - corner = 1; // NW - dd = d1; - if (d2 < dd) { corner = 2; dd = d2; } // NE - if (d3 < dd) { corner = 3; dd = d3; } // SE - if (d4 < dd) { corner = 4; dd = d4; } // SW - - if (corner == 1) { trimx1 = mpx; trimy1 = mpy; } // move this corner to mouse - if (corner == 2) { trimx2 = mpx; trimy1 = mpy; } - if (corner == 3) { trimx2 = mpx; trimy2 = mpy; } - if (corner == 4) { trimx1 = mpx; trimy2 = mpy; } - } - - if (trimx1 < Iorgx) trimx1 = Iorgx; // keep within visible area v.11.05 - if (trimx2 > Iorgx + iww) trimx2 = Iorgx + iww; - if (trimy1 < Iorgy) trimy1 = Iorgy; - if (trimy2 > Iorgy + ihh) trimy2 = Iorgy + ihh; - - if (trimx1 > trimx2-10) trimx1 = trimx2-10; // sanity limits - if (trimy1 > trimy2-10) trimy1 = trimy2-10; - - zdialog_fetch(zd,"lock",rlock); // w/h ratio locked - if (rlock && corner) { - if (corner < 3) // bugfix v.10.3.1 - trimy2 = trimy1 + 1.0 * (trimx2 - trimx1) / trimR; - else - trimy1 = trimy2 - 1.0 * (trimx2 - trimx1) / trimR; - } - - chop = 0; - if (trimx1 < Iorgx) { // look for off the edge v.10.1 - trimx1 = Iorgx; - chop = 1; - } - - if (trimx2 > Iorgx + iww) { // after corner move v.10.3.1 - trimx2 = Iorgx + iww; - chop = 2; - } - - if (trimy1 < Iorgy) { - trimy1 = Iorgy; - chop = 3; - } - - if (trimy2 > Iorgy + ihh) { - trimy2 = Iorgy + ihh; - chop = 4; - } - - if (rlock && chop) { // keep ratio if off edge v.10.1 - if (chop < 3) - trimy2 = trimy1 + 1.0 * (trimx2 - trimx1) / trimR; - else - trimx2 = trimx1 + 1.0 * (trimy2 - trimy1) * trimR; - } - - if (trimx1 > trimx2-10) trimx1 = trimx2-10; // sanity limits - if (trimy1 > trimy2-10) trimy1 = trimy2-10; - - if (trimx1 < Iorgx) trimx1 = Iorgx; // keep within visible area v.11.05 - if (trimx2 > Iorgx + iww) trimx2 = Iorgx + iww; - if (trimy1 < Iorgy) trimy1 = Iorgy; - if (trimy2 > Iorgy + ihh) trimy2 = Iorgy + ihh; - - trimsize[0] = trimx2 - trimx1; // new rectangle dimensions - trimsize[1] = trimy2 - trimy1; - - drr = 1.0 * trimsize[0] / trimsize[1]; // new w/h ratio - if (! rlock) trimR = drr; - - zdialog_stuff(zd,"width",trimsize[0]); // stuff width, height, ratio v.11.05 - zdialog_stuff(zd,"height",trimsize[1]); - sprintf(text,"%.2f ",trimR); - zdialog_stuff(zd,"ratio",text); - - trim_trim(0); // show trim area in image - } - - return; -} - - -// darken image pixels outside of current trim margins -// messy logic: update pixmaps only for changed pixels to increase speed - -void trim_trim(int mode) -{ - int ox1, oy1, ox2, oy2; // outer trim rectangle - int nx1, ny1, nx2, ny2; // inner trim rectangle - int px, py, px1, py1, px2, py2; - uint16 *pix1, *pix3; - - if (mode == 1) // do the final trim - { - mutex_lock(&Fpixmap_lock); - PXM_free(E3pxm16); - E3pxm16 = PXM_make(trimsize[0],trimsize[1],16); // new pixmap with requested size - E3ww = trimsize[0]; - E3hh = trimsize[1]; - - for (py1 = trimy1; py1 < trimy2; py1++) // copy pixels - for (px1 = trimx1; px1 < trimx2; px1++) - { - px2 = px1 - trimx1; - py2 = py1 - trimy1; - pix1 = PXMpix(E1pxm16,px1,py1); - pix3 = PXMpix(E3pxm16,px2,py2); - pix3[0] = pix1[0]; - pix3[1] = pix1[1]; - pix3[2] = pix1[2]; - } - - CEF->Fmod = 1; - mutex_unlock(&Fpixmap_lock); - mwpaint2(); // update window - return; - } - - if (trimx1 < Iorgx) trimx1 = Iorgx; // keep within visible area v.11.05 - if (trimx2 > Iorgx + iww) trimx2 = Iorgx + iww; - if (trimy1 < Iorgy) trimy1 = Iorgy; - if (trimy2 > Iorgy + ihh) trimy2 = Iorgy + ihh; - - if (trimpx1 < trimx1) ox1 = trimpx1; // outer rectangle - else ox1 = trimx1; - if (trimpx2 > trimx2) ox2 = trimpx2; - else ox2 = trimx2; - if (trimpy1 < trimy1) oy1 = trimpy1; - else oy1 = trimy1; - if (trimpy2 > trimy2) oy2 = trimpy2; - else oy2 = trimy2; - - if (trimpx1 > trimx1) nx1 = trimpx1; // inner rectangle - else nx1 = trimx1; - if (trimpx2 < trimx2) nx2 = trimpx2; - else nx2 = trimx2; - if (trimpy1 > trimy1) ny1 = trimpy1; - else ny1 = trimy1; - if (trimpy2 < trimy2) ny2 = trimpy2; - else ny2 = trimy2; - - trimpx1 = trimx1; // set prior trim rectangle - trimpx2 = trimx2; // from current trim rectangle - trimpy1 = trimy1; - trimpy2 = trimy2; - - if (ox1 > 0) ox1--; - if (ox2 < E3ww-1) ox2++; - if (oy1 > 0) oy1--; - if (oy2 < E3hh-1) oy2++; - - for (py = oy1; py < ny1; py++) // top band of pixels - for (px = ox1; px < ox2; px++) - { - pix1 = PXMpix(E1pxm16,px,py); - pix3 = PXMpix(E3pxm16,px,py); - if (px < trimx1 || px > trimx2 || py < trimy1 || py > trimy2) { - pix3[0] = pix1[0] / 2; // outside trim margins - pix3[1] = pix1[1] / 2; // 50% brightness - pix3[2] = pix1[2] / 2; - } - else { - pix3[0] = pix1[0]; // inside trim margins - pix3[1] = pix1[1]; // 100% brightness - pix3[2] = pix1[2]; - } - } - - for (py = oy1; py < oy2; py++) // right band - for (px = nx2; px < ox2; px++) - { - pix1 = PXMpix(E1pxm16,px,py); - pix3 = PXMpix(E3pxm16,px,py); - if (px < trimx1 || px > trimx2 || py < trimy1 || py > trimy2) { - pix3[0] = pix1[0] / 2; - pix3[1] = pix1[1] / 2; - pix3[2] = pix1[2] / 2; - } - else { - pix3[0] = pix1[0]; - pix3[1] = pix1[1]; - pix3[2] = pix1[2]; - } - } - - for (py = ny2; py < oy2; py++) // bottom band - for (px = ox1; px < ox2; px++) - { - pix1 = PXMpix(E1pxm16,px,py); - pix3 = PXMpix(E3pxm16,px,py); - if (px < trimx1 || px > trimx2 || py < trimy1 || py > trimy2) { - pix3[0] = pix1[0] / 2; - pix3[1] = pix1[1] / 2; - pix3[2] = pix1[2] / 2; - } - else { - pix3[0] = pix1[0]; - pix3[1] = pix1[1]; - pix3[2] = pix1[2]; - } - } - - for (py = oy1; py < oy2; py++) // left band - for (px = ox1; px < nx1; px++) - { - pix1 = PXMpix(E1pxm16,px,py); - pix3 = PXMpix(E3pxm16,px,py); - if (px < trimx1 || px > trimx2 || py < trimy1 || py > trimy2) { - pix3[0] = pix1[0] / 2; - pix3[1] = pix1[1] / 2; - pix3[2] = pix1[2] / 2; - } - else { - pix3[0] = pix1[0]; - pix3[1] = pix1[1]; - pix3[2] = pix1[2]; - } - } - - mwpaint3(ox1,oy1,ox2-ox1+1,ny1-oy1+1); // 4 updated rectangles - mwpaint3(nx2,oy1,ox2-nx2+1,oy2-oy1+1); // ww+1, hh+1 v.11.05 - mwpaint3(ox1,ny2,ox2-ox1+1,oy2-ny2+1); - mwpaint3(ox1,oy1,nx1-ox1+1,oy2-oy1+1); - - Ntoplines = 4; // outline trim rectangle v.11.05 - toplinex1[0] = trimx1; - topliney1[0] = trimy1; - toplinex2[0] = trimx2; - topliney2[0] = trimy1; - toplinex1[1] = trimx2; - topliney1[1] = trimy1; - toplinex2[1] = trimx2; - topliney2[1] = trimy2; - toplinex1[2] = trimx2; - topliney1[2] = trimy2; - toplinex2[2] = trimx1; - topliney2[2] = trimy2; - toplinex1[3] = trimx1; - topliney1[3] = trimy2; - toplinex2[3] = trimx1; - topliney2[3] = trimy1; - paint_toplines(1); - - return; -} - - -// dialog to get custom trim button names and corresponding ratios - -void trim_customize() -{ - char text[20], blab[8], rlab[8]; - double r1, r2, ratio; - cchar *pp; - int ii, zstat; - - zdialog *zd = zdialog_new(ZTX("Trim Buttons"),mWin,Bdone,Bcancel,null); // start dialog - zdialog_add_widget(zd,"hbox","hbb","dialog",0,"homog|space=5"); - zdialog_add_widget(zd,"hbox","hbr","dialog",0,"homog|space=5"); - - strcpy(blab,"butt-0"); - strcpy(rlab,"ratio-0"); - - for (ii = 0; ii < 6; ii++) - { - blab[5] = '0' + ii; - rlab[6] = '0' + ii; - zdialog_add_widget(zd,"entry",blab,"hbb",trimbuttons[ii],"scc=6"); - zdialog_add_widget(zd,"entry",rlab,"hbr",trimratios[ii],"scc=6"); - } - - zdialog_run(zd,0,"mouse"); // run dialog v.11.07 - zstat = zdialog_wait(zd); - - if (zstat == 1) // apply - { - for (ii = 0; ii < 6; ii++) // get custom button names - { - blab[5] = '0' + ii; - zdialog_fetch(zd,blab,text,12); - strTrim2(text); - if (! *text) continue; - zfree(trimbuttons[ii]); - trimbuttons[ii] = strdupz(text,0,"trim"); - } - - for (ii = 0; ii < 6; ii++) // get custom ratios - { - rlab[6] = '0' + ii; - zdialog_fetch(zd,rlab,text,12); - strTrim2(text); - r1 = r2 = ratio = 0; - pp = strField(text,':',1); - if (! pp) continue; - r1 = atof(pp); - pp = strField(text,':',2); - if (! pp) continue; - r2 = atof(pp); - if (r1 > 0 && r2 > 0) ratio = r1/r2; - if (ratio < 0.1 || ratio > 10) continue; - zfree(trimratios[ii]); - trimratios[ii] = strdupz(text,0,"trim"); - } - } - - zdialog_free(zd); // kill dialog - return; -} - - -/**************************************************************************/ - -// Resize (rescale) image -// -// Output pixels are composites of input pixels, e.g. 2/3 size means -// that 3x3 input pixels are mapped into 2x2 output pixels, and an -// image size of 1000 x 600 becomes 667 x 400. - -int resize_ww0, resize_hh0; // original size -int resize_ww1, resize_hh1; // new size - -editfunc EFresize; - -void m_resize(GtkWidget *, cchar *) -{ - int resize_dialog_event(zdialog *zd, cchar *event); - void * resize_thread(void *); - - cchar *lockmess = ZTX("Lock aspect ratio"); - - zfuncs::F1_help_topic = "resize"; // v.10.8 - - EFresize.funcname = "resize"; - EFresize.threadfunc = resize_thread; // thread function - if (! edit_setup(EFresize)) return; // setup edit - - zdialog *zd = zdialog_new(ZTX("Resize Image"),mWin,Bdone,Bcancel,null); - EFresize.zd = zd; - - zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=10"); - zdialog_add_widget(zd,"vbox","vb11","hb1",0,"homog|space=5"); - zdialog_add_widget(zd,"vbox","vb12","hb1",0,"homog|space=5"); - zdialog_add_widget(zd,"vbox","vb13","hb1",0,"homog|space=5"); - zdialog_add_widget(zd,"label","placeholder","vb11",0); // pixels percent - zdialog_add_widget(zd,"label","labw","vb11",Bwidth); // width [______] [______] - zdialog_add_widget(zd,"label","labh","vb11",Bheight); // height [______] [______] - zdialog_add_widget(zd,"label","labpix","vb12","pixels"); // - zdialog_add_widget(zd,"spin","wpix","vb12","20|9999|1|20"); // presets [2/3] [1/2] [1/3] [1/4] [Prev] - zdialog_add_widget(zd,"spin","hpix","vb12","20|9999|1|20"); // - zdialog_add_widget(zd,"label","labpct","vb13",Bpercent); // [_] lock aspect ratio - zdialog_add_widget(zd,"spin","wpct","vb13","1|500|0.1|100"); // - zdialog_add_widget(zd,"spin","hpct","vb13","1|500|0.1|100"); // [done] [cancel] - zdialog_add_widget(zd,"hbox","hb2","dialog",0,"space=5"); - zdialog_add_widget(zd,"label","preset","hb2",Bpresets,"space=5"); - zdialog_add_widget(zd,"button","b 3/4","hb2","3/4"); - zdialog_add_widget(zd,"button","b 2/3","hb2","2/3"); - zdialog_add_widget(zd,"button","b 1/2","hb2","1/2"); - zdialog_add_widget(zd,"button","b 1/3","hb2","1/3"); - zdialog_add_widget(zd,"button","b 1/4","hb2","1/4"); - zdialog_add_widget(zd,"button","prev","hb2",ZTX("Prev")); - zdialog_add_widget(zd,"hbox","hb3","dialog",0,"space=5"); - zdialog_add_widget(zd,"check","lock","hb3",lockmess,"space=5"); - - resize_ww0 = Fpxm16->ww; // original width, height - resize_hh0 = Fpxm16->hh; - - zdialog_stuff(zd,"wpix",resize_ww0); - zdialog_stuff(zd,"hpix",resize_hh0); - zdialog_stuff(zd,"lock",1); - - zdialog_help(zd,"resize"); // zdialog help topic v.11.08 - zdialog_run(zd,resize_dialog_event,"save"); // run dialog v.11.07 - zdialog_wait(zd); // wait for completion - return; -} - - -// dialog event and completion callback function - -int resize_dialog_event(zdialog *zd, cchar * event) -{ - int lock; - double wpct1, hpct1; - - if (zd->zstat) // dialog complete - { - if (zd->zstat != 1) { // user cancel - edit_cancel(EFresize); - return 0; - } - - editresize[0] = resize_ww1; // remember size used v.10.10 - editresize[1] = resize_hh1; - - Fzoom = 0; // v.11.01 - edit_done(EFresize); - return 0; - } - - if (strnEqu(event,"KB",2)) return 0; // ignore KB inputs v.11.11 - - zdialog_fetch(zd,"wpix",resize_ww1); // get all widget values - zdialog_fetch(zd,"hpix",resize_hh1); - zdialog_fetch(zd,"wpct",wpct1); - zdialog_fetch(zd,"hpct",hpct1); - zdialog_fetch(zd,"lock",lock); - - if (strEqu(event,"b 3/4")) { - resize_ww1 = (3 * resize_ww0 + 3) / 4; - resize_hh1 = (3 * resize_hh0 + 3) / 4; - } - - if (strEqu(event,"b 2/3")) { - resize_ww1 = (2 * resize_ww0 + 2) / 3; - resize_hh1 = (2 * resize_hh0 + 2) / 3; - } - - if (strEqu(event,"b 1/2")) { - resize_ww1 = (resize_ww0 + 1) / 2; - resize_hh1 = (resize_hh0 + 1) / 2; - } - - if (strEqu(event,"b 1/3")) { - resize_ww1 = (resize_ww0 + 2) / 3; - resize_hh1 = (resize_hh0 + 2) / 3; - } - - if (strEqu(event,"b 1/4")) { - resize_ww1 = (resize_ww0 + 3) / 4; - resize_hh1 = (resize_hh0 + 3) / 4; - } - - if (strEqu(event,"prev")) { // use previous resize values v.10.10 - resize_ww1 = editresize[0]; - resize_hh1 = editresize[1]; - } - - if (strEqu(event,"wpct")) // width % - set pixel width - resize_ww1 = int(wpct1 / 100.0 * resize_ww0 + 0.5); - - if (strEqu(event,"hpct")) // height % - set pixel height - resize_hh1 = int(hpct1 / 100.0 * resize_hh0 + 0.5); - - if (lock && event[0] == 'w') // preserve width/height ratio - resize_hh1 = int(resize_ww1 * (1.0 * resize_hh0 / resize_ww0) + 0.5); - if (lock && event[0] == 'h') - resize_ww1 = int(resize_hh1 * (1.0 * resize_ww0 / resize_hh0) + 0.5); - - hpct1 = 100.0 * resize_hh1 / resize_hh0; // set percents to match pixels - wpct1 = 100.0 * resize_ww1 / resize_ww0; - - zdialog_stuff(zd,"wpix",resize_ww1); // index all widget values - zdialog_stuff(zd,"hpix",resize_hh1); - zdialog_stuff(zd,"wpct",wpct1); - zdialog_stuff(zd,"hpct",hpct1); - - signal_thread(); // do the update, don't wait for idle - return 1; -} - - -// do the resize job - -void * resize_thread(void *) // v.10.12 -{ - CEF->Fmod = 0; - - while (true) - { - thread_idle_loop(); // wait for signal - - mutex_lock(&Fpixmap_lock); - PXM_free(E3pxm16); - E3pxm16 = PXM_rescale(Fpxm16,resize_ww1,resize_hh1); // rescale the edit image - E3ww = resize_ww1; - E3hh = resize_hh1; - CEF->Fmod = 1; - mutex_unlock(&Fpixmap_lock); - mwpaint2(); - } - - return 0; -} - - -/**************************************************************************/ - -// menu function - batch resize - resize many files at once -// resized files are .jpg files - -void m_batchresize(GtkWidget *, cchar *) // new v.10.8 -{ - int batchresize_dialog_event(zdialog *zd, cchar *event); - - zfuncs::F1_help_topic = "batch_resize"; // v.10.8 - - if (is_syncbusy()) return; // must wait for file sync v.11.11 - if (mod_keep()) return; // unsaved edits - if (! menulock(1)) return; // lock menus - - // [select files] N files selected - // new max. width [____] - // new max. height [____] - // (o) replace originals - // (o) export to location [browse] [x] copy EXIF - // [___________________________________________] - // - // [resize] [cancel] - - zdialog *zd = zdialog_new(ZTX("Batch Resize"),mWin,Bproceed,Bcancel,null); - - zdialog_add_widget(zd,"hbox","hbf","dialog",0,"space=5"); - zdialog_add_widget(zd,"button","files","hbf",Bselectfiles,"space=5"); - zdialog_add_widget(zd,"label","fcount","hbf","0 files selected","space=10"); - zdialog_add_widget(zd,"hbox","hbwh","dialog","space=10"); - zdialog_add_widget(zd,"vbox","vbwh1","hbwh",0,"homog|space=5"); - zdialog_add_widget(zd,"vbox","vbwh2","hbwh",0,"homog|space=5"); - zdialog_add_widget(zd,"label","labw","vbwh1",ZTX("new max. width")); - zdialog_add_widget(zd,"label","labh","vbwh1",ZTX("new max. height")); - zdialog_add_widget(zd,"entry","maxw","vbwh2","1000","scc=5"); - zdialog_add_widget(zd,"entry","maxh","vbwh2","700","scc=5"); - zdialog_add_widget(zd,"hbox","hbsep","dialog",0,"space=5"); - zdialog_add_widget(zd,"hbox","hbloc","dialog"); - zdialog_add_widget(zd,"vbox","vbloc1","hbloc",0,"homog"); - zdialog_add_widget(zd,"vbox","vbloc2","hbloc",0,"homog"); - zdialog_add_widget(zd,"radio","replace","vbloc1",ZTX("replace originals")); - zdialog_add_widget(zd,"radio","export","vbloc1",ZTX("export to location")); - zdialog_add_widget(zd,"label","space","vbloc2"); - zdialog_add_widget(zd,"hbox","hbloc2","vbloc2","space=5"); - zdialog_add_widget(zd,"button","browse","hbloc2",Bbrowse,"space=5"); - zdialog_add_widget(zd,"check","copyexif","hbloc2",ZTX("copy EXIF"),"space=5"); - zdialog_add_widget(zd,"hbox","hbloc3","dialog",0,"expand"); - zdialog_add_widget(zd,"entry","location","hbloc3",0,"expand|space=5"); - - zdialog_stuff(zd,"replace",0); // defaults: export, no EXIF - zdialog_stuff(zd,"export",1); - zdialog_stuff(zd,"copyexif",0); - zdialog_stuff(zd,"maxw",batchresize[0]); // v.10.9 - zdialog_stuff(zd,"maxh",batchresize[1]); - - zdialog_help(zd,"batch_resize"); // zdialog help topic v.11.08 - zdialog_run(zd,batchresize_dialog_event,"parent"); // run dialog v.11.07 - zdialog_wait(zd); // wait for completion - - menulock(0); - return; -} - - -// dialog event and completion callback function - -int batchresize_dialog_event(zdialog *zd, cchar *event) -{ - static char **flist = 0; - char countmess[50]; - int Freplace, maxw, maxh, Fcopyexif, yn; - int ii, err, lcc, fcc, ww, hh; - char location[maxfcc], *ploc, *pfile, *pext; - char *oldfile, *newfile, *tempfile; - double scale, wscale, hscale; - PXM *pxmout; - struct stat statb; - - if (strEqu(event,"files")) // select images to resize - { - if (flist) { // free prior list - for (ii = 0; flist[ii]; ii++) - zfree(flist[ii]); - zfree(flist); - } - - flist = image_gallery_getfiles(0,mWin); // get list of files to resize v.10.9 - - if (flist) // count files selected - for (ii = 0; flist[ii]; ii++); - else ii = 0; - - snprintf(countmess,50,ZTX("%d files selected"),ii); // update dialog - zdialog_stuff(zd,"fcount",countmess); - } - - if (strEqu(event,"browse")) - { - ploc = zgetfile1(ZTX("Select directory"),"folder",curr_dirk); // get directory v.10.9 - if (! ploc) return 0; - zdialog_stuff(zd,"location",ploc); - zfree(ploc); - zdialog_stuff(zd,"export",1); - } - - if (! zd->zstat) return 0; // dialog still busy - - if (zd->zstat != 1) goto cleanup; // dialog canceled - - if (! flist) { // no files selected - zd->zstat = 0; // keep dialog active - return 0; - } - - zdialog_fetch(zd,"maxw",maxw); // new max width - zdialog_fetch(zd,"maxh",maxh); // new max height - zdialog_fetch(zd,"replace",Freplace); // replace originals y/n - zdialog_fetch(zd,"copyexif",Fcopyexif); // copy EXIF/IPTC y/n - zdialog_fetch(zd,"location",location,maxfcc); // output location (Freplace = 0) - strTrim2(location,location); // trim leading and trailing blanks - - if (Freplace) { - yn = zmessageYN(mWin,ZTX("replace original files? (max. %d x %d)"),maxw,maxh); - if (! yn) { - zd->zstat = 0; - return 0; - } - } - else { - yn = zmessageYN(mWin,ZTX("copy files? (max. %d x %d) \n" - " to location %s"),maxw,maxh,location); - if (! yn) { - zd->zstat = 0; - return 0; - } - } - - if (! Freplace) { - err = stat(location,&statb); - if (err || ! S_ISDIR(statb.st_mode)) { - zmessageACK(mWin,ZTX("location is not a valid directory")); - zd->zstat = 0; - return 0; - } - } - - if (maxw < 20 || maxh < 20) { - zmessageACK(mWin,ZTX("max. size %d x %d is not reasonable"),maxw,maxh); - zd->zstat = 0; - return 0; - } - - write_popup_text("open","Resizing files",500,200,mWin); // status monitor popup window - - lcc = strlen(location); - if (! Freplace && location[lcc-1] == '/') lcc--; // remove trailing '/' - - for (ii = 0; flist[ii]; ii++) // loop selected files - { - oldfile = flist[ii]; - - if (Freplace) - newfile = strdupz(oldfile,8,"batchresize"); // new file = old file - else { - pfile = strrchr(oldfile,'/'); - if (! pfile) continue; - fcc = strlen(pfile); - newfile = strdupz(location,fcc+9,"batchresize"); - strcpy(newfile+lcc,pfile); // new file at location - } - - pfile = strrchr(newfile,'/'); // force .jpg extension v.10.9 - pext = strrchr(pfile,'.'); - if (! pext) pext = pfile + strlen(pfile); - if (strlen(pext) > 5) pext = pext + strlen(pext); - strcpy(pext,".jpg"); - - write_popup_text("write",newfile); // report progress - zmainloop(); - - if (! Freplace) { - err = stat(newfile,&statb); // if export, check if file exists - if (! err) { - snprintf(command,ccc,"%s", ZTX("new file already exists")); - write_popup_text("write",command); - zfree(newfile); - continue; - } - } - - tempfile = strdupz(newfile,12,"batchresize"); // temp file needed for EXIF/IPTC copy - strcat(tempfile,"-temp.jpg"); // v.10.9 - - f_open(oldfile,0); // read old file - - wscale = hscale = 1.0; - if (Fww > maxw) wscale = 1.0 * maxw / Fww; // compute new size - if (Fhh > maxh) hscale = 1.0 * maxh / Fhh; - if (wscale < hscale) scale = wscale; - else scale = hscale; - ww = Fww * scale; - hh = Fhh * scale; - pxmout = PXM_rescale(Fpxm8,ww,hh); // rescale file - - PXBwrite(pxmout,tempfile); // write to temp file - - if (Freplace || Fcopyexif) // copy EXIF/IPTC if files replaced - info_copy(oldfile,tempfile,0,0,0); // or if requested for export - - snprintf(command,ccc,"cp -p \"%s\" \"%s\" ",tempfile,newfile); // copy tempfile to newfile - err = system(command); - if (err) write_popup_text("write",wstrerror(err)); - - remove(tempfile); // remove tempfile - - if (Freplace && ! err && strNeq(oldfile,newfile)) // remove oldfile if not - remove(oldfile); // already replaced - - zfree(newfile); - zfree(tempfile); - PXM_free(pxmout); - } - - write_popup_text("write","COMPLETED"); - write_popup_text("close",0); - - batchresize[0] = maxw; // save preferred size v.10.9 - batchresize[1] = maxh; - -cleanup: - - if (flist) { // free memory - for (ii = 0; flist[ii]; ii++) - zfree(flist[ii]); - zfree(flist); - flist = 0; - } - - zdialog_free(zd); // kill dialog - return 0; -} - - -/**************************************************************************/ - -// edit image annotation - write text on the image itself - -char annotate_file[1000] = ""; // file for annotation data -int annotate_mode = 0; // 0/1/2 = 1st write / re-write / erase -int annotate_px, annotate_py; // text position on image -PXM *annotate_pxm = 0; // buffer for rendered annotation text -PXM *annotate_pxm_transp = 0; // buffer for transparency data - -void annotate_dialog_stuff(zdialog *zd); // stuff dialog widgets from memory data -int annotate_dialog_event(zdialog *zd, cchar *event); // dialog event function -void annotate_mousefunc(); // mouse event function -void annotate_gettext(); // render text into graphic image -void annotate_write(); // write text on image -void annotate_load(); // load annotation data from file -void annotate_save(); // save annotation data to file - -editfunc EFannotate; - - -void m_annotate(GtkWidget *, cchar *menu) // overhauled v.10.11 -{ - char *pp; - cchar *intro = ZTX("Enter text, click/drag on image.\n" - "Right click to remove"); - - zfuncs::F1_help_topic = "annotate"; // user guide topic - - EFannotate.funcname = "annotate"; - EFannotate.Farea = 1; // select area ignored - if (! edit_setup(EFannotate)) return; // setup edit - - if (! annotate_text) - annotate_text = strdupz("enter text",0,"annotate"); - - if (! annotate_font || strEqu(annotate_font,"undefined")) - annotate_font = strdupz("FreeMono Bold Italic 44",4,"annotate"); // default font and size - else annotate_font = strdupz(annotate_font,4,"annotate"); // add extra space bugfix v.11.02 - - - if (! annotate_color[0] || strEqu(annotate_color[0],"undefined")) { // default colors - annotate_color[0] = strdupz("255|0|0",0,"annotate"); // text - annotate_color[1] = strdupz("0|0|255",0,"annotate"); // background - annotate_color[2] = strdupz("0|255|0",0,"annotate"); // text outline - annotate_outline = 6; // outline width - } - - pp = annotate_color[0]; // insure at least 20 bytes - annotate_color[0] = strdupz(pp,20,"annotate"); - zfree(pp); - pp = annotate_color[1]; - annotate_color[1] = strdupz(pp,20,"annotate"); - zfree(pp); - pp = annotate_color[2]; - annotate_color[2] = strdupz(pp,20,"annotate"); - zfree(pp); - -// Annotate Image -// -// Text [__________________________________] // dialog -// -// [font] size [___|v] angle [___|v] -// -// text backing outline // v.11.04 -// Color [color] [color] [color] -// Transparency [___|v] [___|v] [___|v] -// Width [___|v] -// -// [x] my mouse Annotation File: [Open] [Save] -// [Done] [Cancel] - - zdialog *zd = zdialog_new(ZTX("Annotate Image"),mWin,Bdone,Bcancel,null); - EFannotate.zd = zd; - EFannotate.mousefunc = annotate_mousefunc; - - zdialog_add_widget(zd,"label","intro","dialog",intro,"space=3"); - zdialog_add_widget(zd,"hbox","hbtext","dialog",0,"space=3"); - zdialog_add_widget(zd,"label","labtext","hbtext",ZTX("Text"),"space=5"); - zdialog_add_widget(zd,"frame","frtext","hbtext",0,"expand"); - zdialog_add_widget(zd,"edit","text","frtext",0,"expand"); - - zdialog_add_widget(zd,"hbox","hbfont","dialog",0,"space=8"); - zdialog_add_widget(zd,"button","font","hbfont",Bfont,"space=5"); - zdialog_add_widget(zd,"label","space","hbfont","","space=5"); - zdialog_add_widget(zd,"label","labsize","hbfont",ZTX("Size"),"space=3"); - zdialog_add_widget(zd,"spin","size","hbfont","6|99|1|20","space=3"); - zdialog_add_widget(zd,"label","space","hbfont","","space=5"); - zdialog_add_widget(zd,"label","labangle","hbfont",ZTX("Angle"),"space=3"); - zdialog_add_widget(zd,"spin","angle","hbfont","-180|180|0.2|0","space=3"); - - zdialog_add_widget(zd,"hsep","hs1","dialog",0,"space=3"); - zdialog_add_widget(zd,"hbox","hbcol","dialog",0,"space=3"); - zdialog_add_widget(zd,"vbox","vbcol1","hbcol",0,"homog|space=5"); - zdialog_add_widget(zd,"vbox","vbcol2","hbcol",0,"homog|space=5"); - zdialog_add_widget(zd,"vbox","vbcol3","hbcol",0,"homog|space=5"); - zdialog_add_widget(zd,"vbox","vbcol4","hbcol",0,"homog|space=5"); - - zdialog_add_widget(zd,"label","space","vbcol1"); - zdialog_add_widget(zd,"label","labcol","vbcol1",ZTX("Color")); - zdialog_add_widget(zd,"label","labcol","vbcol1",ZTX("Transparency")); - zdialog_add_widget(zd,"label","space","vbcol1"); - - zdialog_add_widget(zd,"label","labtext","vbcol2",ZTX("text")); - zdialog_add_widget(zd,"colorbutt","fgcolor","vbcol2","0|0|0"); - zdialog_add_widget(zd,"spin","fgtrans","vbcol2","0|100|1|0"); - zdialog_add_widget(zd,"label","space","vbcol2"); - - zdialog_add_widget(zd,"label","labback","vbcol3",ZTX("backing")); - zdialog_add_widget(zd,"colorbutt","bgcolor","vbcol3","255|255|255"); - zdialog_add_widget(zd,"spin","bgtrans","vbcol3","0|100|1|0"); - zdialog_add_widget(zd,"label","labw","vbcol3",ZTX("Outline\n Width")); - - zdialog_add_widget(zd,"label","laboutln","vbcol4",ZTX("outline")); - zdialog_add_widget(zd,"colorbutt","tocolor","vbcol4","255|0|0"); - zdialog_add_widget(zd,"spin","totrans","vbcol4","0|100|1|0"); - zdialog_add_widget(zd,"spin","outline","vbcol4","0|9|1|0"); - - zdialog_add_widget(zd,"hsep","hs1","dialog",0,"space=3"); - zdialog_add_widget(zd,"hbox","hbaf","dialog",0,"space=8"); - zdialog_add_widget(zd,"check","mymouse","hbaf",BmyMouse,"space=3"); - zdialog_add_widget(zd,"label","space","hbaf",0,"space=12"); - zdialog_add_widget(zd,"label","labbg","hbaf",ZTX("Annotation File:")); - zdialog_add_widget(zd,"button","load","hbaf",Bopen,"space=8"); - zdialog_add_widget(zd,"button","save","hbaf",Bsave,"space=5"); - - annotate_dialog_stuff(zd); // stuff dialog widgets from memory data - - zdialog_help(zd,"annotate"); // zdialog help topic v.11.08 - zdialog_run(zd,annotate_dialog_event,"save"); // run dialog, parallel v.11.07 - - zdialog_stuff(zd,"mymouse",1); - takeMouse(zd,annotate_mousefunc,dragcursor); // connect mouse function v.10.12 - - annotate_mode = 0; // no write on image (yet) - annotate_px = annotate_py = -1; // no location on image (yet) - return; -} - - -// stuff all dialog widgets from annotation data in memory - -void annotate_dialog_stuff(zdialog *zd) -{ - int size; - char *pp; - - zdialog_stuff(zd,"text",annotate_text); - zdialog_stuff(zd,"angle",annotate_angle); - zdialog_stuff(zd,"fgtrans",annotate_trans[0]); - zdialog_stuff(zd,"bgtrans",annotate_trans[1]); - zdialog_stuff(zd,"totrans",annotate_trans[2]); - zdialog_stuff(zd,"fgcolor",annotate_color[0]); - zdialog_stuff(zd,"bgcolor",annotate_color[1]); - zdialog_stuff(zd,"tocolor",annotate_color[2]); - zdialog_stuff(zd,"outline",annotate_outline); - - pp = annotate_font + strlen(annotate_font); - while (*pp != ' ') pp--; - if (pp > annotate_font) { - size = atoi(pp); - if (size >= 6 && size <= 99) - zdialog_stuff(zd,"size",size); - } - - annotate_gettext(); // build text buffer from annotation data - - return; -} - - -// dialog event and completion callback function - -int annotate_dialog_event(zdialog *zd, cchar *event) -{ - GtkWidget *font_dialog; - int size, mymouse; - char *pp, text[1000]; - - if (zd->zstat) - { - if (zd->zstat == 1 && CEF->Fmod) edit_done(EFannotate); // Done, complete pending edit - else edit_cancel(EFannotate); // Cancel or kill - return 0; - } - - if (strEqu(event,"mymouse")) { // toggle mouse capture v.10.12 - zdialog_fetch(zd,"mymouse",mymouse); - if (mymouse) takeMouse(zd,annotate_mousefunc,dragcursor); // connect mouse function v.11.03 - else freeMouse(); // disconnect mouse - } - - if (strEqu(event,"text")) { - zdialog_fetch(zd,"text",text,999); // get text from dialog - if (annotate_text) zfree(annotate_text); - annotate_text = 0; - if (*text) annotate_text = strdupz(text,0,"annotate"); - } - - if (strEqu(event,"font")) { // new font - font_dialog = gtk_font_selection_dialog_new(ZTX("select font")); - gtk_font_selection_dialog_set_font_name(GTK_FONT_SELECTION_DIALOG(font_dialog),annotate_font); - gtk_dialog_run(GTK_DIALOG(font_dialog)); - pp = gtk_font_selection_dialog_get_font_name(GTK_FONT_SELECTION_DIALOG(font_dialog)); - gtk_widget_destroy(GTK_WIDGET(font_dialog)); - - if (pp) { - zfree(annotate_font); - annotate_font = strdupz(pp,6,"annotate"); // update font and size - g_free(pp); - pp = annotate_font + strlen(annotate_font); - while (*pp != ' ') pp--; - if (pp > annotate_font) { - size = atoi(pp); - if (size >= 6 && size <= 99) zdialog_stuff(zd,"size",size); - } - } - } - - if (strEqu(event,"load")) { // load annotate data from file - annotate_load(); - annotate_dialog_stuff(zd); - return 1; - } - - if (strEqu(event,"save")) { // save annotate data to file - annotate_save(); - return 1; - } - - if (strEqu(event,"size")) { // new font size - zdialog_fetch(zd,"size",size); - pp = annotate_font + strlen(annotate_font); // "fontname NN" - while (*pp != ' ') pp--; // back-up to " NN" - if (pp > annotate_font) sprintf(pp," %d",size); // replace NN with new size - } - - if (strEqu(event,"angle")) - zdialog_fetch(zd,"angle",annotate_angle); - - if (strEqu(event,"fgcolor")) // foreground (text) color - zdialog_fetch(zd,"fgcolor",annotate_color[0],20); - - if (strEqu(event,"bgcolor")) // background color - zdialog_fetch(zd,"bgcolor",annotate_color[1],20); - - if (strEqu(event,"tocolor")) // text outline color - zdialog_fetch(zd,"tocolor",annotate_color[2],20); - - if (strEqu(event,"fgtrans")) // foreground transparency - zdialog_fetch(zd,"fgtrans",annotate_trans[0]); - - if (strEqu(event,"bgtrans")) // background transparency - zdialog_fetch(zd,"bgtrans",annotate_trans[1]); - - if (strEqu(event,"totrans")) // text outline transparency - zdialog_fetch(zd,"totrans",annotate_trans[2]); - - if (strEqu(event,"outline")) // text outline width - zdialog_fetch(zd,"outline",annotate_outline); - - annotate_gettext(); // rebuild text buffer - annotate_write(); // write on image - zmainloop(); - - return 1; -} - - -// mouse function, set position for annotation text on image - -void annotate_mousefunc() -{ - static int dragging = 0; - - if (LMclick) { // left mouse click - LMclick = 0; - annotate_px = Mxclick; // new text position on image - annotate_py = Myclick; - annotate_write(); // write text on image - } - - if (RMclick) { // right mouse click - RMclick = 0; - annotate_mode = 2; // erase text on image - annotate_write(); - annotate_px = annotate_py = -1; // no location on image - } - - if (Mxdrag || Mydrag) // mouse dragged - { - if (! dragging && annotate_mode) dragging = 1; - - if (dragging) { - annotate_px = Mxdrag; // new text position on image - annotate_py = Mydrag; - annotate_write(); // write text on image - } - } - else dragging = 0; // no drag underway - - return; -} - - -// write annotation text on image at designated place, if wanted -// annotate_mode: 0/1/2 = 1st write / re-write / erase - -void annotate_write() -{ - uint8 *pix1, *pix2; - uint16 *pix3, *pix31, *pix33; - int px1, py1, px3, py3; - double e3part, f256 = 1.0 / 256.0; - - static int orgx1 = 0, orgy1 = 0, ww1 = 0, hh1 = 0; // old text image overlap rectangle - int orgx2, orgy2, ww2, hh2; // new overlap rectangle - - if (annotate_mode) // re-write or erase - { - for (py3 = orgy1; py3 < orgy1 + hh1; py3++) // erase prior text image - for (px3 = orgx1; px3 < orgx1 + ww1; px3++) // replace E3 pixels with E1 pixels - { // in prior overlap rectangle - if (px3 < 0 || px3 >= E3ww) continue; - if (py3 < 0 || py3 >= E3hh) continue; - pix31 = PXMpix(E1pxm16,px3,py3); - pix33 = PXMpix(E3pxm16,px3,py3); - pix33[0] = pix31[0]; - pix33[1] = pix31[1]; - pix33[2] = pix31[2]; - } - - CEF->Fmod = 0; - } - - if (annotate_mode == 2) { // erase only - annotate_mode = 0; // next time is a 1st write - mwpaint3(orgx1,orgy1,ww1,hh1); // update window - return; - } - - if (! annotate_text) { // no text to write - annotate_mode = 0; // next time is a 1st write - mwpaint3(orgx1,orgy1,ww1,hh1); // update window - return; - } - - if (annotate_px < 0 || annotate_py < 0) { // no image position to write - annotate_mode = 0; // next time is a 1st write - mwpaint3(orgx1,orgy1,ww1,hh1); // update window - return; - } - - annotate_mode = 1; // next time is a re-write - - ww2 = annotate_pxm->ww; // text image buffer - hh2 = annotate_pxm->hh; - - orgx2 = annotate_px - ww2/2; // copy-to image3 location - orgy2 = annotate_py - hh2/2; - - for (py1 = 0; py1 < hh2; py1++) // loop all pixels in text image - for (px1 = 0; px1 < ww2; px1++) - { - px3 = orgx2 + px1; // copy-to image3 pixel - py3 = orgy2 + py1; - - if (px3 < 0 || px3 >= E3ww) continue; // omit parts beyond edges - if (py3 < 0 || py3 >= E3hh) continue; - - pix1 = PXMpix8(annotate_pxm,px1,py1); // copy-from text pixel - pix2 = PXMpix8(annotate_pxm_transp,px1,py1); // copy-from transparency - pix3 = PXMpix(E3pxm16,px3,py3); // copy-to image pixel - - e3part = pix2[0] * f256; // image part visible through text - - pix3[0] = (pix1[0] << 8) + e3part * pix3[0]; // combine text part + image part - pix3[1] = (pix1[1] << 8) + e3part * pix3[1]; - pix3[2] = (pix1[2] << 8) + e3part * pix3[2]; - } - - mwpaint3(orgx1,orgy1,ww1,hh1); // restore prior overlap rectangle - mwpaint3(orgx2,orgy2,ww2,hh2); // update new overlap rectangle - - CEF->Fmod = 1; - - orgx1 = orgx2; // remember overlap rectangle - orgy1 = orgy2; // for next call - - ww1 = ww2; - hh1 = hh2; - return; -} - - -// Create a graphic image with text, white on black, any font, any angle. - -void annotate_gettext() // revised v.10.12 -{ - PXM * annotate_addoutline(PXM *); - - PangoFontDescription *pfont; - static GdkColormap *colormap = 0; - static GdkColor black, white; - PangoLayout *playout; - GdkPixmap *pixmap; - GdkGC *gdkgc; - GdkPixbuf *pixbuf; - - char *text = annotate_text; - double angle = annotate_angle; - PXM *pxm_temp1, *pxm_temp2, *pxm_temp3; - uint8 *pix1, *pix2, *pix3, *ppix; - int px, py, ww, hh, rs, fontsize; - char *pp, font[100]; - cchar *ppc; - int fgred, fggreen, fgblue; - int bgred, bggreen, bgblue; - int tored, togreen, toblue; - int red, green, blue; - double fgtrans, bgtrans, totrans, fgpart, bgpart; - double f256 = 1.0 / 256.0; - - if (! annotate_text || ! *annotate_text) return; // no annotation text - - strncpy0(font,annotate_font,99); - pp = font + strlen(font); // save current font size - while (*pp != ' ') pp--; - fontsize = atoi(pp); - if (fontsize < 6 || fontsize > 99) fontsize = 20; - - strcpy(pp+1,"99"); // use large size for text generation - - if (! colormap) { - colormap = gtk_widget_get_colormap(drWin); - black.red = black.green = black.blue = 0; - white.red = white.green = white.blue = 0xffff; - gdk_rgb_find_color(colormap,&black); - gdk_rgb_find_color(colormap,&white); - } - - pfont = pango_font_description_from_string(font); // make layout with text - playout = gtk_widget_create_pango_layout(drWin,null); - pango_layout_set_font_description(playout,pfont); - pango_layout_set_text(playout,text,-1); - pango_layout_get_pixel_size(playout,&ww,&hh); - - ww += 10; // sometimes it is a little too small - hh += 2; - pixmap = gdk_pixmap_new(drWin->window,ww,hh,-1); // then make pixmap - gdkgc = gdk_gc_new(pixmap); - gdk_draw_rectangle(pixmap,gdkgc,1,0,0,ww,hh); - gdk_draw_layout_with_colors(pixmap,gdkgc,0,0,playout,&white,&black); - - pixbuf = gdk_pixbuf_get_from_drawable(null,pixmap,0,0,0,0,0,ww,hh); // then make pixbuf - - ww = gdk_pixbuf_get_width(pixbuf); // pixbuf dimensions - hh = gdk_pixbuf_get_height(pixbuf); - rs = gdk_pixbuf_get_rowstride(pixbuf); - ppix = gdk_pixbuf_get_pixels(pixbuf); - - pxm_temp1 = PXM_make(ww,hh,8); - - for (py = 0; py < hh; py++) // copy pixbuf to PXM - for (px = 0; px < ww; px++) - { // text color is gray/white - pix1 = ppix + rs * py + 3 * px; // can erase all but one color - pix2 = PXMpix8(pxm_temp1,px,py); - pix2[0] = pix1[0]; - pix2[1] = pix2[2] = 0; - } - - g_object_unref(playout); - g_object_unref(pixmap); - g_object_unref(gdkgc); - g_object_unref(pixbuf); - - pxm_temp2 = annotate_addoutline(pxm_temp1); // add text outline color if any - if (pxm_temp2) { - PXM_free(pxm_temp1); - pxm_temp1 = pxm_temp2; - } - - if (fabs(angle) > 0.1) { // rotate text if wanted - pxm_temp2 = PXM_rotate(pxm_temp1,angle); - PXM_free(pxm_temp1); - pxm_temp1 = pxm_temp2; - } - - fgred = fggreen = fgblue = 0; - bgred = bggreen = bgblue = 255; - tored = togreen = toblue = 0; - - ppc = strField(annotate_color[0],'|',1); // get text foreground color - if (ppc) fgred = atoi(ppc); // 0 - 255 per RGB color - ppc = strField(annotate_color[0],'|',2); - if (ppc) fggreen = atoi(ppc); - ppc = strField(annotate_color[0],'|',3); - if (ppc) fgblue = atoi(ppc); - - ppc = strField(annotate_color[1],'|',1); // get text background color - if (ppc) bgred = atoi(ppc); - ppc = strField(annotate_color[1],'|',2); - if (ppc) bggreen = atoi(ppc); - ppc = strField(annotate_color[1],'|',3); - if (ppc) bgblue = atoi(ppc); - - ppc = strField(annotate_color[2],'|',1); // get text outline color - if (ppc) tored = atoi(ppc); - ppc = strField(annotate_color[2],'|',2); - if (ppc) togreen = atoi(ppc); - ppc = strField(annotate_color[2],'|',3); - if (ppc) toblue = atoi(ppc); - - fgtrans = 0.01 * annotate_trans[0]; // get transparencies - bgtrans = 0.01 * annotate_trans[1]; // text, background, text outline - totrans = 0.01 * annotate_trans[2]; - - ww = pxm_temp1->ww; // text image input pixmap - hh = pxm_temp1->hh; - - pxm_temp2 = PXM_make(ww,hh,8); // text image output pixmap - pxm_temp3 = PXM_make(ww,hh,8); // output transparency map - - for (py = 0; py < hh; py++) // loop all pixels in text image - for (px = 0; px < ww; px++) - { - pix1 = PXMpix8(pxm_temp1,px,py); // copy-from pixel - pix2 = PXMpix8(pxm_temp2,px,py); // copy-to pixel - pix3 = PXMpix8(pxm_temp3,px,py); // copy-to transparency - - fgpart = pix1[0] * f256; // white part = text foreground, 0 - 1 - bgpart = 1.0 - fgpart; // rest = text background part, 1 - 0 - - if (pix1[1]) // use text outline color - { - fgpart = fgpart * (1.0 - totrans); // reduce for transparencies - bgpart = bgpart * (1.0 - bgtrans); - red = tored * fgpart + bgred * bgpart; // red part for text outline + background - green = togreen * fgpart + bggreen * bgpart; // same for green - blue = toblue * fgpart + bgblue * bgpart; // same for blue - } - - else // use text foreground color - { - fgpart = fgpart * (1.0 - fgtrans); // reduce for transparencies - bgpart = bgpart * (1.0 - bgtrans); - red = fgred * fgpart + bgred * bgpart; // red part for text + text background - green = fggreen * fgpart + bggreen * bgpart; // same for green - blue = fgblue * fgpart + bgblue * bgpart; // same for blue - } - - pix2[0] = red; // output total red, green blue - pix2[1] = green; - pix2[2] = blue; - - pix3[0] = 255 * (1.0 - fgpart - bgpart); // image part visible through text - } - - ww = ww * fontsize / 99.0 + 0.5; // resize from size 99 font - hh = hh * fontsize / 99.0 + 0.5; // to requested font size - PXM_free(pxm_temp1); - pxm_temp1 = PXM_rescale(pxm_temp2,ww,hh); - PXM_free(pxm_temp2); - PXM_free(annotate_pxm); - annotate_pxm = pxm_temp1; - - pxm_temp1 = PXM_rescale(pxm_temp3,ww,hh); // resize transparency map - PXM_free(pxm_temp3); - PXM_free(annotate_pxm_transp); - annotate_pxm_transp = pxm_temp1; - - return; -} - - -// add an outline color to the text character edges - -PXM * annotate_addoutline(PXM *pxm1) // new v.10.12 -{ - PXM *pxm2; - int toww, toww2; - int ww1, hh1, ww2, hh2; - int px1, py1, px2, py2, ii, diff; - uint8 *pix1, *pix2; - - toww = annotate_outline; // text outline color width - if (toww == 0) return 0; // zero - toww2 = 2 * toww; - - ww1 = pxm1->ww; // input PXM dimensions - hh1 = pxm1->hh; - - ww2 = ww1 + toww2; // output PXM with added margins - hh2 = hh1 + toww2; - pxm2 = PXM_make(ww2,hh2,8); - - memset(pxm2->bmp,0,ww2*hh2*3); // clear output to black - - for (py1 = 0; py1 < hh1; py1++) // copy input to output, - for (px1 = 0; px1 < ww1; px1++) // displaced for margins - { - pix1 = PXMpix8(pxm1,px1,py1); - pix2 = PXMpix8(pxm2,px1+toww,py1+toww); - pix2[0] = pix1[0]; - pix2[1] = pix1[1]; - pix2[2] = pix1[2]; - } - - for (py1 = 0; py1 < hh1; py1++) - for (px1 = 0; px1 < ww1-toww-2; px1++) // horizontal forward scan - { - pix1 = PXMpix8(pxm1,px1,py1); - diff = (pix1+6)[0] - pix1[0]; - if (diff < 200) continue; - - px2 = px1 + toww; - py2 = py1 + toww; - pix2 = PXMpix8(pxm2,px2-toww/2,py2); - - for (ii = 0; ii < toww + 1; ii++) - { - pix2[0] = pix1[0]; - pix2[1] = 1; - pix1 += 3; - pix2 += 3; - } - } - - for (py1 = 0; py1 < hh1; py1++) - for (px1 = ww1-1; px1 > toww+2; px1--) // horizontal reverse scan - { - pix1 = PXMpix8(pxm1,px1,py1); - diff = (pix1-6)[0] - pix1[0]; - if (diff < 200) continue; - - px2 = px1 + toww; - py2 = py1 + toww; - pix2 = PXMpix8(pxm2,px2+toww/2,py2); - - for (ii = 0; ii < toww + 1; ii++) - { - pix2[0] = pix1[0]; - pix2[1] = 1; - pix1 -= 3; - pix2 -= 3; - } - } - - for (px1 = 0; px1 < ww1; px1++) - for (py1 = 0; py1 < hh1-toww-2; py1++) // vertical forward scan - { - pix1 = PXMpix8(pxm1,px1,py1); - diff = (pix1+6*ww1)[0] - pix1[0]; - if (diff < 200) continue; - - px2 = px1 + toww; - py2 = py1 + toww; - pix2 = PXMpix8(pxm2,px2,py2-toww/2); - - for (ii = 0; ii < toww + 1; ii++) - { - if (pix2[0] < pix1[0]) pix2[0] = pix1[0]; - pix2[1] = 1; - pix1 += 3*ww1; - pix2 += 3*ww2; - } - } - - for (px1 = 0; px1 < ww1; px1++) - for (py1 = hh1-1; py1 > toww+2; py1--) // vertical reverse scan - { - pix1 = PXMpix8(pxm1,px1,py1); - diff = (pix1-6*ww1)[0] - pix1[0]; - if (diff < 200) continue; - - px2 = px1 + toww; - py2 = py1 + toww; - pix2 = PXMpix8(pxm2,px2,py2+toww/2); - - for (ii = 0; ii < toww + 1; ii++) - { - if (pix2[0] < pix1[0]) pix2[0] = pix1[0]; - pix2[1] = 1; - pix1 -= 3*ww1; - pix2 -= 3*ww2; - } - } - - return pxm2; -} - - -// load annotation data from a file - -void annotate_load() // v.10.11 -{ - FILE *fid; - int cc, err; - char *pp, *file, buff[1200]; - cchar *dialogtitle = "load annotation data from a file"; - - file = zgetfile1(dialogtitle,"open",annotations_dirk); // get input file from user - if (! file) return; - - fid = fopen(file,"r"); // open for read - if (! fid) { - zmessageACK(mWin,"%s",strerror(errno)); - zfree(file); - return; - } - - while (true) - { - pp = fgets_trim(buff,1200,fid,1); - if (! pp) break; - - if (strnEqu(pp,"annotate_text ",15)) { - if (annotate_text) zfree(annotate_text); - cc = strlen(pp+15) + 100; - annotate_text = zmalloc(cc,"annotate"); - repl_1str(pp+15,annotate_text,"\\n","\n"); // replace "\n" with real newline char. - } - - if (strnEqu(pp,"annotate_font ",15)) - strcpy(annotate_font,pp+15); - - if (strnEqu(pp,"annotate_angle ",16)) - convSD(pp+16,annotate_angle,-180,+180); - - if (strnEqu(pp,"annotate_fgcolor ",18)) - strcpy(annotate_color[0],pp+18); - - if (strnEqu(pp,"annotate_bgcolor ",18)) - strcpy(annotate_color[1],pp+18); - - if (strnEqu(pp,"annotate_tocolor ",18)) - strcpy(annotate_color[2],pp+18); - - if (strnEqu(pp,"annotate_fgtrans ",18)) - convSI(pp+18,annotate_trans[0],0,100); - - if (strnEqu(pp,"annotate_bgtrans ",18)) - convSI(pp+18,annotate_trans[1],0,100); - - if (strnEqu(pp,"annotate_totrans ",18)) - convSI(pp+18,annotate_trans[2],0,100); - - if (strnEqu(pp,"annotate_outline ",18)) - convSI(pp+18,annotate_outline,0,9); - } - - err = fclose(fid); - if (err) { - zmessageACK(mWin,"%s",strerror(errno)); - zfree(file); - return; - } - - strcpy(annotate_file,file); // update current file - zfree(file); - - return; -} - - -// save annotation data to a file - -void annotate_save() // v.10.11 -{ - FILE *fid; - char *file, text[1100]; - cchar *dialogtitle = "save annotation data to a file"; - int err; - - file = zgetfile1(dialogtitle,"save",annotations_dirk); // get output file from user - if (! file) return; - - fid = fopen(file,"w"); // open for write - if (! fid) { - zmessageACK(mWin,"%s",strerror(errno)); - zfree(file); - return; - } - - repl_1str(annotate_text,text,"\n","\\n"); // replace newlines with "\n" - - fprintf(fid,"annotate_text %s \n", text); - fprintf(fid,"annotate_font %s \n", annotate_font); - fprintf(fid,"annotate_angle %.1f \n", annotate_angle); - fprintf(fid,"annotate_fgcolor %s \n", annotate_color[0]); - fprintf(fid,"annotate_bgcolor %s \n", annotate_color[1]); - fprintf(fid,"annotate_tocolor %s \n", annotate_color[2]); - fprintf(fid,"annotate_fgtrans %d \n", annotate_trans[0]); - fprintf(fid,"annotate_bgtrans %d \n", annotate_trans[1]); - fprintf(fid,"annotate_totrans %d \n", annotate_trans[2]); - fprintf(fid,"annotate_outline %d \n", annotate_outline); - - fprintf(fid,"\n"); - - err = fclose(fid); - if (err) { - zmessageACK(mWin,"file I/O error %s",file); - zfree(file); - return; - } - - strcpy(annotate_file,file); // update current file - zfree(file); - - return; -} - - -/**************************************************************************/ - -// flip an image horizontally or vertically - -editfunc EFflip; - -void m_flip(GtkWidget *, cchar *) -{ - int flip_dialog_event(zdialog *zd, cchar *event); - - zfuncs::F1_help_topic = "flip_image"; // v.10.8 - - EFflip.funcname = "flip"; - if (! edit_setup(EFflip)) return; // setup edit - - zdialog *zd = zdialog_new(ZTX("Flip Image"),mWin,Bdone,Bcancel,null); - EFflip.zd = zd; - - zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=10"); - zdialog_add_widget(zd,"button","horz","hb1",ZTX("horizontal"),"space=5"); - zdialog_add_widget(zd,"button","vert","hb1",ZTX("vertical"),"space=5"); - - zdialog_help(zd,"flip_image"); // zdialog help topic v.11.08 - zdialog_run(zd,flip_dialog_event,"save"); // run dialog, parallel v.11.07 - return; -} - - -// dialog event and completion callback function - -int flip_dialog_event(zdialog *zd, cchar *event) -{ - int flip_horz(); - int flip_vert(); - - if (zd->zstat) // dialog complete - { - if (zd->zstat == 1) edit_done(EFflip); - else edit_cancel(EFflip); - return 0; - } - - if (strEqu(event,"horz")) flip_horz(); - if (strEqu(event,"vert")) flip_vert(); - return 0; -} - - -int flip_horz() -{ - int px, py; - uint16 *pix3, *pix9; - - edit_zapredo(); // delete redo copy v.10.3 - - E9pxm16 = PXM_copy(E3pxm16); - - for (py = 0; py < E3hh; py++) - for (px = 0; px < E3ww; px++) - { - pix3 = PXMpix(E3pxm16,px,py); // image9 = flipped image3 - pix9 = PXMpix(E9pxm16,E3ww-1-px,py); - pix9[0] = pix3[0]; - pix9[1] = pix3[1]; - pix9[2] = pix3[2]; - } - - mutex_lock(&Fpixmap_lock); - PXM_free(E3pxm16); // image9 >> image3 - E3pxm16 = E9pxm16; - E9pxm16 = 0; - mutex_unlock(&Fpixmap_lock); - - CEF->Fmod = 1; - mwpaint2(); - return 0; -} - - -int flip_vert() -{ - int px, py; - uint16 *pix3, *pix9; - - edit_zapredo(); // delete redo copy v.10.3 - - E9pxm16 = PXM_copy(E3pxm16); - - for (py = 0; py < E3hh; py++) - for (px = 0; px < E3ww; px++) - { - pix3 = PXMpix(E3pxm16,px,py); // image9 = flipped image3 - pix9 = PXMpix(E9pxm16,px,E3hh-1-py); - pix9[0] = pix3[0]; - pix9[1] = pix3[1]; - pix9[2] = pix3[2]; - } - - mutex_lock(&Fpixmap_lock); - PXM_free(E3pxm16); // image9 >> image3 - E3pxm16 = E9pxm16; - E9pxm16 = 0; - mutex_unlock(&Fpixmap_lock); - - CEF->Fmod = 1; - mwpaint2(); - return 0; -} - - -/**************************************************************************/ - -// make a black & white or color negative image - -editfunc EFnegate; - -void m_negate(GtkWidget *, cchar *) // v.10.9 -{ - int negate_dialog_event(zdialog *zd, cchar *event); - - zfuncs::F1_help_topic = "make_negative"; - - EFnegate.funcname = "negate"; - if (! edit_setup(EFnegate)) return; // setup edit: no preview - - zdialog *zd = zdialog_new(ZTX("Make Negative"),mWin,Bdone,Bcancel,null); - EFnegate.zd = zd; - - zdialog_add_widget(zd,"radio","b&wpos","dialog",ZTX("black/white positive")); - zdialog_add_widget(zd,"radio","b&wneg","dialog",ZTX("black/white negative")); - zdialog_add_widget(zd,"radio","colpos","dialog",ZTX("color positive")); - zdialog_add_widget(zd,"radio","colneg","dialog",ZTX("color negative")); - - zdialog_stuff(zd,"colpos",1); - - zdialog_resize(zd,200,0); - zdialog_help(zd,"make_negative"); // zdialog help topic v.11.08 - zdialog_run(zd,negate_dialog_event,"save"); // run dialog - parallel v.11.07 - return; -} - - -// dialog event and completion callback function - -int negate_dialog_event(zdialog *zd, cchar *event) -{ - int mode, px, py; - int red, green, blue; - uint16 *pix1, *pix3; - - if (zd->zstat) // dialog complete - { - if (zd->zstat == 1) edit_done(EFnegate); - else edit_cancel(EFnegate); - return 0; - } - - if (strEqu(event,"b&wpos")) mode = 1; - if (strEqu(event,"b&wneg")) mode = 2; - if (strEqu(event,"colpos")) mode = 3; - if (strEqu(event,"colneg")) mode = 4; - - edit_zapredo(); // delete redo copy - - for (py = 0; py < E3hh; py++) - for (px = 0; px < E3ww; px++) - { - pix1 = PXMpix(E1pxm16,px,py); - - red = pix1[0]; - green = pix1[1]; - blue = pix1[2]; - - if (mode == 1) // black and white positive - red = green = blue = (red + green + blue) / 3; - - else if (mode == 2) // black and white negative - red = green = blue = 65535 - (red + green + blue) / 3; - - if (mode == 3) { /** do nothing **/ } // color positive - - if (mode == 4) { // color negative - red = 65535 - red; - green = 65535 - green; - blue = 65535 - blue; - } - - pix3 = PXMpix(E3pxm16,px,py); - - pix3[0] = red; - pix3[1] = green; - pix3[2] = blue; - } - - CEF->Fmod = 1; - mwpaint2(); - - return 0; -} - - -/**************************************************************************/ - -// unbend an image -// straighten curvature added by pano or improve perspective - -double unbend_lin_horz, unbend_lin_vert; // unbend values from dialog -double unbend_cur_horz, unbend_cur_vert; -double unbend_x1, unbend_x2, unbend_y1, unbend_y2; // unbend axes scaled 0 to 1 -int unbend_hx1, unbend_hy1, unbend_hx2, unbend_hy2; -int unbend_vx1, unbend_vy1, unbend_vx2, unbend_vy2; - -editfunc EFunbend; - - -void m_unbend(GtkWidget *, cchar *) // overhauled v.11.04 -{ - int unbend_dialog_event(zdialog* zd, cchar *event); - void * unbend_thread(void *); - void unbend_mousefunc(); - - zfuncs::F1_help_topic = "unbend"; - - EFunbend.funcname = "unbend"; - EFunbend.Fprev = 1; // use preview - EFunbend.threadfunc = unbend_thread; // thread function - EFunbend.mousefunc = unbend_mousefunc; // mouse function - if (! edit_setup(EFunbend)) return; // setup edit - -/*** ___________________________________ - | | - | Unbend Image | - | | - | linear curved | - | vertical [__|v] [__|v] | - | horizontal [__|v] [__|v] | - | | - | [grid] | - | [done] [cancel] | - |___________________________________| -***/ - - zdialog *zd = zdialog_new(ZTX("Unbend Image"),mWin,Bdone,Bcancel,null); - EFunbend.zd = zd; - - zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=8"); - zdialog_add_widget(zd,"vbox","vb1","hb1",0,"homog|space=5"); - zdialog_add_widget(zd,"vbox","vb2","hb1",0,"homog|space=5"); - zdialog_add_widget(zd,"vbox","vb3","hb1",0,"homog|space=5"); - zdialog_add_widget(zd,"label","labspace","vb1",""); - zdialog_add_widget(zd,"label","labvert","vb1",ZTX("vertical")); - zdialog_add_widget(zd,"label","labhorz","vb1",ZTX("horizontal")); - zdialog_add_widget(zd,"label","lablin","vb2",ZTX("linear")); - zdialog_add_widget(zd,"spin","splinvert","vb2","-99|99|1|0"); - zdialog_add_widget(zd,"spin","splinhorz","vb2","-99|99|1|0"); - zdialog_add_widget(zd,"label","labhorz","vb3",ZTX("curved")); - zdialog_add_widget(zd,"spin","spcurvert","vb3","-99|99|1|0"); - zdialog_add_widget(zd,"spin","spcurhorz","vb3","-99|99|1|0"); - zdialog_add_widget(zd,"hbox","hb2","dialog",0,"space=5"); - zdialog_add_widget(zd,"button","grid","hb2",ZTX("Grid"),"space=10"); - - zdialog_help(zd,"unbend"); // zdialog help topic v.11.08 - zdialog_run(zd,unbend_dialog_event,"save"); // run dialog, parallel v.11.07 - - unbend_x1 = unbend_x2 = unbend_y1 = unbend_y2 = 0.5; // initial axes thru image middle - unbend_lin_horz = unbend_lin_vert = 0; - unbend_cur_horz = unbend_cur_vert = 0; - - load_grid(unbend_grid); // load grid preferences v.11.11 - - takeMouse(zd,unbend_mousefunc,dragcursor); // connect mouse function v.11.03 - signal_thread(); - return; -} - - -// dialog event and completion callback function - -int unbend_dialog_event(zdialog *zd, cchar *event) -{ - if (zd->zstat) // dialog complete - { - paint_toplines(2); // erase axes-lines - - save_grid(unbend_grid); // save grid preferences v.11.11 - Fgrid = 0; // grid off - - if (zd->zstat != 1) { - edit_cancel(EFunbend); // canceled - return 0; - } - - if (unbend_cur_vert || unbend_cur_horz || // image3 modified - unbend_lin_vert || unbend_lin_horz) CEF->Fmod = 1; - else CEF->Fmod = 0; - - edit_done(EFunbend); // commit changes to image3 - return 1; - } - - if (strstr(event,"splinvert")) { // get new unbend value - zdialog_fetch(zd,"splinvert",unbend_lin_vert); - signal_thread(); // trigger thread - } - - if (strstr(event,"splinhorz")) { - zdialog_fetch(zd,"splinhorz",unbend_lin_horz); - signal_thread(); - } - - if (strstr(event,"spcurvert")) { - zdialog_fetch(zd,"spcurvert",unbend_cur_vert); - signal_thread(); - } - - if (strstr(event,"spcurhorz")) { - zdialog_fetch(zd,"spcurhorz",unbend_cur_horz); - signal_thread(); - } - - if (strEqu(event,"grid")) m_gridlines(0,0); // grid dialog v.11.11 - - if (strstr("KB G KB g",event)) // G key, toggle grid v.11.11 - toggle_grid(2); - - - return 1; -} - - -// unbend mouse function // adjustable axes - -void unbend_mousefunc() -{ - cchar *close; - double dist1, dist2; - double mpx = 0, mpy = 0; - - if (LMclick) { // left mouse click - LMclick = 0; - mpx = Mxclick; - mpy = Myclick; - } - - if (Mxdrag || Mydrag) { // mouse dragged - mpx = Mxdrag; - mpy = Mydrag; - } - - if (! mpx && ! mpy) return; - - mpx = 1.0 * mpx / E3ww; // scale mouse position 0 to 1 - mpy = 1.0 * mpy / E3hh; - - if (mpx < 0.2 || mpx > 0.8 ) { // check reasonable position - if (mpy < 0.1 || mpy > 0.9) return; - } - else if (mpy < 0.2 || mpy > 0.8) { - if (mpx < 0.1 || mpx > 0.9) return; - } - else return; - - close = "?"; // find closest axis end-point - dist1 = 2; - - dist2 = mpx * mpx + (mpy-unbend_y1) * (mpy-unbend_y1); - if (dist2 < dist1) { - dist1 = dist2; - close = "left"; - } - - dist2 = (1-mpx) * (1-mpx) + (mpy-unbend_y2) * (mpy-unbend_y2); - if (dist2 < dist1) { - dist1 = dist2; - close = "right"; - } - - dist2 = (mpx-unbend_x1) * (mpx-unbend_x1) + mpy * mpy; - if (dist2 < dist1) { - dist1 = dist2; - close = "top"; - } - - dist2 = (mpx-unbend_x2) * (mpx-unbend_x2) + (1-mpy) * (1-mpy); - if (dist2 < dist1) { - dist1 = dist2; - close = "bottom"; - } - - if (strEqu(close,"left")) unbend_y1 = mpy; // set new axis end-point - if (strEqu(close,"right")) unbend_y2 = mpy; - if (strEqu(close,"top")) unbend_x1 = mpx; - if (strEqu(close,"bottom")) unbend_x2 = mpx; - - signal_thread(); // trigger thread - - return; -} - - -// unbend thread function - -void * unbend_thread(void *arg) -{ - void * unbend_wthread(void *); - - while (true) - { - thread_idle_loop(); // wait for work or exit request - - unbend_hx1 = 0; // scale axes to E3ww/hh - unbend_hy1 = unbend_y1 * E3hh; - unbend_hx2 = E3ww; - unbend_hy2 = unbend_y2 * E3hh; - - unbend_vx1 = unbend_x1 * E3ww; - unbend_vy1 = 0; - unbend_vx2 = unbend_x2 * E3ww; - unbend_vy2 = E3hh; - - if (Fpreview) { // omit for final unbend - Ntoplines = 2; - toplinex1[0] = unbend_hx1; // lines on window - topliney1[0] = unbend_hy1; - toplinex2[0] = unbend_hx2; - topliney2[0] = unbend_hy2; - toplinex1[1] = unbend_vx1; - topliney1[1] = unbend_vy1; - toplinex2[1] = unbend_vx2; - topliney2[1] = unbend_vy2; - } - - for (int ii = 0; ii < Nwt; ii++) // start worker threads - start_wthread(unbend_wthread,&wtnx[ii]); - wait_wthreads(); // wait for completion - - mwpaint2(); // update window - } - - return 0; // not executed, stop g++ warning -} - - -void * unbend_wthread(void *arg) // worker thread function -{ - int index = *((int *) arg); - int vstat, px3, py3, cx3, cy3; - double dispx, dispy, dispx2, dispy2; - double px1, py1, vx1, vx2, hy1, hy2; - double curvert, curhorz, linvert, linhorz; - uint16 vpix[3], *pix3; - - curvert = int(unbend_cur_vert * 0.01 * E3hh); // -0.99 to +0.99 - curhorz = int(unbend_cur_horz * 0.01 * E3ww); - linvert = int(unbend_lin_vert * 0.0013 * E3hh); // -0.13 to +0.13 - linhorz = int(unbend_lin_horz * 0.0013 * E3ww); - - vx1 = unbend_vx1; - vx2 = unbend_vx2; - hy1 = unbend_hy1; - hy2 = unbend_hy2; - - for (py3 = index; py3 < E3hh; py3 += Nwt) // step through F3 pixels - for (px3 = 0; px3 < E3ww; px3++) - { - cx3 = vx1 + (vx2 - vx1) * py3 / E3hh; // center of unbend - cy3 = hy1 + (hy2 - hy1) * px3 / E3ww; - dispx = 2.0 * (px3 - cx3) / E3ww; // -1.0 .. 0.0 .. +1.0 (roughly) - dispy = 2.0 * (py3 - cy3) / E3hh; // -1.0 .. 0.0 .. +1.0 - dispx2 = -cos(0.8 * dispx) + 1; // curved v.11.03 - dispy2 = -cos(0.8 * dispy) + 1; // v.11.04 - - pix3 = PXMpix(E3pxm16,px3,py3); // output pixel - px1 = px3; // input pixel = output - py1 = py3; - - px1 += dispx * dispy * linhorz; // move input pixel - py1 += dispy * dispx * linvert; - px1 += dispx * dispy2 * curhorz; - py1 += dispy * dispx2 * curvert; - - vstat = vpixel(E1pxm16,px1,py1,vpix); - if (vstat) { - pix3[0] = vpix[0]; // input pixel >> output pixel - pix3[1] = vpix[1]; - pix3[2] = vpix[2]; - } - else pix3[0] = pix3[1] = pix3[2] = 0; - } - - exit_wthread(); - return 0; // not executed, avoid gcc warning -} - - -/**************************************************************************/ - -// Convert a selected tetragon area into a rectangle, converting the -// rest of the image to match and keeping straight lines straight. - -int KST_pixel[4][2]; // last 0-4 pixels clicked -int KST_npix; // count of pixels -char KST_pixlab[4][4] = { " A ", " B ", " C ", " D " }; - -editfunc EFkeystone; - -int KST_dialog_event(zdialog *zd, cchar *event); -void KST_mousefunc(void); -void KST_warpfunc(void); - - -void m_keystone(GtkWidget *, cchar *) // new v.11.10 -{ - cchar *KST_message = ZTX( - " Click the four corners of a tetragon area. Press [apply]. \n" - " The image is warped to make the tetragon into a rectangle."); - - zfuncs::F1_help_topic = "keystone"; - - EFkeystone.funcname = "keystone"; - EFkeystone.Fprev = 0; // no preview - EFkeystone.mousefunc = KST_mousefunc; // mouse function - if (! edit_setup(EFkeystone)) return; // setup edit - - KST_npix = 0; // no pixels yet - - zdialog *zd = zdialog_new(ZTX("Keystone Correction"),mWin,Bapply,Breset,Bdone,null); - zdialog_add_widget(zd,"label","lab1","dialog",KST_message,"space=5"); - zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=5"); - zdialog_add_widget(zd,"check","mymouse","hb1",BmyMouse,"space=5"); - zdialog_help(zd,"keystone"); // zdialog help topic - - EFkeystone.zd = zd; - zdialog_run(zd,KST_dialog_event,"save"); // run dialog, parallel - - takeMouse(zd,KST_mousefunc,dragcursor); // connect mouse function - return; -} - - -// dialog completion callback function - -int KST_dialog_event(zdialog *zd, cchar *event) -{ - int ii, px, py, mymouse; - - if (strEqu(event,"mymouse")) { // toggle mouse capture - zdialog_fetch(zd,"mymouse",mymouse); - if (mymouse) // connect mouse function - takeMouse(zd,KST_mousefunc,dragcursor); - else freeMouse(); // disconnect mouse - } - - if (! zd->zstat) return 1; // wait for completion - - if (zd->zstat == 1) // apply - { - erase_toptext(102); // erase points - KST_warpfunc(); // do the warp - zd->zstat = 0; // keep dialog active - } - - else if (zd->zstat == 2) // reset - { - edit_reset(); - zd->zstat = 0; - - for (ii = 0; ii < KST_npix; ii++) // show pixel labels on image - { - px = KST_pixel[ii][0]; - py = KST_pixel[ii][1]; - add_toptext(102,px,py,KST_pixlab[ii],"Sans 8"); - } - mwpaint2(); - } - - else if (zd->zstat == 3) // done - { - erase_toptext(102); // erase points - edit_done(EFkeystone); - } - - else { // cancel - erase_toptext(102); // erase points - edit_cancel(EFkeystone); - } - - return 0; -} - - -// mouse function - click on 4 corners of tetragon - -void KST_mousefunc(void) -{ - int ii, minii, jj, px, py; - double dist, distx, disty, mindist; - - if (LMclick) // left click - { - LMclick = 0; - - for (ii = 0; ii < KST_npix; ii++) // check if very near a previous corner - { - if (abs(KST_pixel[ii][0] - Mxclick) < 0.07 * E3ww - && abs(KST_pixel[ii][1] - Myclick) < 0.07 * E3hh) - { - KST_pixel[ii][0] = Mxclick; // yes, set new corner position - KST_pixel[ii][1] = Myclick; - goto showcorners; - } - } - - if (KST_npix < 4) // if < 4 corners, add a new one - { - ii = KST_npix; // next corner to fill - KST_pixel[ii][0] = Mxclick; // save newest corner position - KST_pixel[ii][1] = Myclick; - KST_npix++; - goto showcorners; - } - - mindist = 99999; // all 4 corners already specified - minii = -1; - - for (ii = 0; ii < 4; ii++) // find closest corner to click position - { - distx = (Mxclick - KST_pixel[ii][0]); - disty = (Myclick - KST_pixel[ii][1]); - dist = sqrt(distx*distx + disty*disty); - if (dist < mindist) { - mindist = dist; - minii = ii; - } - } - - if (minii >= 0) { // set new corner position - ii = minii; - KST_pixel[ii][0] = Mxclick; - KST_pixel[ii][1] = Myclick; - goto showcorners; - } - } - - else if (RMclick) // right click - { - RMclick = 0; - mindist = 99999; - minii = -1; - - for (ii = 0; ii < KST_npix; ii++) // find closest corner to click position - { - distx = (Mxclick - KST_pixel[ii][0]); - disty = (Myclick - KST_pixel[ii][1]); - dist = sqrt(distx*distx + disty*disty); - if (dist < mindist) { - mindist = dist; - minii = ii; - } - } - - if (minii >= 0) { // replace deleted corner with - ii = minii; // last corner - jj = KST_npix - 1; - KST_pixel[ii][0] = KST_pixel[jj][0]; - KST_pixel[ii][1] = KST_pixel[jj][1]; - --KST_npix; // reduce corner count - goto showcorners; - } - } - -showcorners: - // show corner labels on image - erase_toptext(102); - - for (ii = 0; ii < KST_npix; ii++) - { - px = KST_pixel[ii][0]; - py = KST_pixel[ii][1]; - add_toptext(102,px,py,KST_pixlab[ii],"Sans 8"); - } - - mwpaint2(); - return; -} - - -// keystone warp function - make input tetragon into a rectangle - -void KST_warpfunc(void) -{ - int ii, jj, tempx, tempy, vstat; - double px3, py3, trpx[4], trpy[4]; - double sqpx0, sqpy0, sqpx1, sqpy1, sqpx2, sqpy2, sqpx3, sqpy3; - double cdx0, cdy0, cdx1, cdy1, cdx2, cdy2, cdx3, cdy3; - double px1, py1, dispx, dispy, sqww, sqhh; - double f0, f1, f2, f3; - uint16 vpix1[3], *pix3; - - if (KST_npix != 4) { - zmessageACK(mWin,ZTX("must have 4 corners")); - return; - } - - for (ii = 0; ii < 4; ii++) { // get 4 selected tetragon points - trpx[ii] = KST_pixel[ii][0]; - trpy[ii] = KST_pixel[ii][1]; - } - - // sort 4 points in clockwise order NW, NE, SE, SW - - for (ii = 0; ii < 4; ii++) { // sort top to bottom (y order) - for (jj = ii; jj < 4; jj++) { - if (trpy[jj] < trpy[ii]) { - tempx = trpx[ii]; - tempy = trpy[ii]; - trpx[ii] = trpx[jj]; - trpy[ii] = trpy[jj]; - trpx[jj] = tempx; - trpy[jj] = tempy; - } - } - } - - if (trpx[1] < trpx[0]) { // sort upper two left, right - tempx = trpx[0]; - tempy = trpy[0]; - trpx[0] = trpx[1]; - trpy[0] = trpy[1]; - trpx[1] = tempx; - trpy[1] = tempy; - } - - if (trpx[2] < trpx[3]) { // sort lower two right, left - tempx = trpx[2]; - tempy = trpy[2]; - trpx[2] = trpx[3]; - trpy[2] = trpy[3]; - trpx[3] = tempx; - trpy[3] = tempy; - } - - if (trpx[0] < trpx[3]) sqpx0 = sqpx3 = trpx[0]; // rectangle enclosing tetragon - else sqpx0 = sqpx3 = trpx[3]; - if (trpx[1] > trpx[2]) sqpx1 = sqpx2 = trpx[1]; - else sqpx1 = sqpx2 = trpx[2]; - if (trpy[0] < trpy[1]) sqpy0 = sqpy1 = trpy[0]; - else sqpy0 = sqpy1 = trpy[1]; - if (trpy[2] > trpy[3]) sqpy2 = sqpy3 = trpy[2]; - else sqpy2 = sqpy3 = trpy[3]; - -/*** - sqpx0 = sqpx3 = 0.5 * (trpx[0] + trpx[3]); // rectangle bisecting tetragon sides - sqpx1 = sqpx2 = 0.5 * (trpx[1] + trpx[2]); - sqpy0 = sqpy1 = 0.5 * (trpy[0] + trpy[1]); - sqpy2 = sqpy3 = 0.5 * (trpy[2] + trpy[3]); -***/ - - cdx0 = sqpx0 - trpx[0]; // displavement of tetragon corner - cdy0 = sqpy0 - trpy[0]; // to corresponding rectangle corner - cdx1 = sqpx1 - trpx[1]; - cdy1 = sqpy1 - trpy[1]; - cdx2 = sqpx2 - trpx[2]; - cdy2 = sqpy2 - trpy[2]; - cdx3 = sqpx3 - trpx[3]; - cdy3 = sqpy3 - trpy[3]; - - sqww = 1.0 / (sqpx1 - sqpx0); // rectangle width and height - sqhh = 1.0 / (sqpy3 - sqpy0); - - for (py3 = 0; py3 < E3hh; py3++) // loop all output pixels - for (px3 = 0; px3 < E3ww; px3++) - { - f0 = (1.0 - (px3 - sqpx0) * sqww) * (1.0 - (py3 - sqpy0) * sqhh); - f1 = (px3 - sqpx0) * sqww * (1.0 - (py3 - sqpy0) * sqhh); - f2 = (px3 - sqpx0) * sqww * (py3 - sqpy0) * sqhh; - f3 = (1.0 - (px3 - sqpx0) * sqww) * (py3 - sqpy0) * sqhh; - - dispx = cdx0 * f0 + cdx1 * f1 + cdx2 * f2 + cdx3 * f3; - dispy = cdy0 * f0 + cdy1 * f1 + cdy2 * f2 + cdy3 * f3; - - px1 = px3 - dispx; // input virtual pixel for px3/py3 - py1 = py3 - dispy; - - pix3 = PXMpix(E3pxm16,int(px3),int(py3)); // output pixel - - vstat = vpixel(E1pxm16,px1,py1,vpix1); // output pixel = input virtual pixel - if (vstat) { - pix3[0] = vpix1[0]; - pix3[1] = vpix1[1]; - pix3[2] = vpix1[2]; - } - else pix3[0] = pix3[1] = pix3[2] = 0; - } - - CEF->Fmod = 1; // image is modified - mwpaint2(); // update window - return; -} - - -/**************************************************************************/ - -// warp/distort area - select image area and pull with mouse - -float *WarpAx, *WarpAy; // memory of all displaced pixels -float WarpAmem[4][100]; // undo memory, last 100 warps -int NWarpA; // WarpA mem count -int WarpA_started; - -editfunc EFwarpA; - -void WarpA_warpfunc(float wdx, float wdy, float wdw, float wdh, int acc); -void WarpA_mousefunc(void); - - -void m_warp_area(GtkWidget *, cchar *) -{ - int WarpA_dialog_event(zdialog *zd, cchar *event); - - cchar *WarpA_message = ZTX( - " Select an area to warp using select area function. \n" - " Press [start warp] and pull area with mouse. \n" - " Make multiple mouse pulls until satisfied. \n" - " When finished, select another area or press [done]."); - - int px, py, ii; - - zfuncs::F1_help_topic = "warp_area"; - - EFwarpA.funcname = "warp-area"; - EFwarpA.Farea = 2; // select area usable - EFwarpA.mousefunc = WarpA_mousefunc; // mouse function - if (! edit_setup(EFwarpA)) return; // setup edit - - zdialog *zd = zdialog_new(ZTX("Warp Image (area)"),mWin,Bdone,Bcancel,null); - EFwarpA.zd = zd; - - zdialog_add_widget(zd,"label","lab1","dialog",WarpA_message,"space=5"); - zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=5"); - zdialog_add_widget(zd,"button","swarp","hb1",ZTX("start warp"),"space=5"); - zdialog_add_widget(zd,"button","undlast","hb1",Bundolast,"space=5"); - zdialog_add_widget(zd,"button","undall","hb1",Bundoall,"space=5"); - zdialog_add_widget(zd,"hbox","hb2","dialog",0,"space=5"); - zdialog_add_widget(zd,"check","mymouse","hb2",BmyMouse,"space=5"); - - zdialog_help(zd,"warp_area"); // zdialog help topic v.11.08 - zdialog_run(zd,WarpA_dialog_event,"save"); // run dialog, parallel v.11.07 - - WarpAx = (float *) zmalloc(E3ww * E3hh * sizeof(float),"warpA"); // get memory for pixel displacements - WarpAy = (float *) zmalloc(E3ww * E3hh * sizeof(float),"warpA"); - - NWarpA = 0; // no warp data - WarpA_started = 0; - - for (py = 0; py < E3hh; py++) // no pixel displacements - for (px = 0; px < E3ww; px++) - { - ii = py * E3ww + px; - WarpAx[ii] = WarpAy[ii] = 0.0; - } - - return; -} - - -// dialog event and completion callback function - -int WarpA_dialog_event(zdialog * zd, cchar *event) -{ - int px, py, ii, mymouse; - float wdx, wdy, wdw, wdh; - - if (zd->zstat) // dialog complete - { - if (NWarpA) CEF->Fmod = 1; - else CEF->Fmod = 0; - - if (zd->zstat == 1) edit_done(EFwarpA); - else edit_cancel(EFwarpA); - - zfree(WarpAx); // release undo memory - zfree(WarpAy); - return 0; - } - - if (strEqu(event,"swarp")) // start warp - { - if (! Factivearea || sa_mode == 7) { // no select area active v.11.01 - zmessageACK(mWin,ZTX("Select area first")); - return 0; - } - sa_edgecalc(); // calculate area edge distances - takeMouse(zd,WarpA_mousefunc,dragcursor); // connect mouse function v.11.03 - WarpA_started = 1; - } - - if (! WarpA_started) { - zdialog_stuff(zd,"mymouse",0); - return 0; - } - - if (strEqu(event,"mymouse")) { // toggle mouse capture v.10.12 - zdialog_fetch(zd,"mymouse",mymouse); - if (mymouse) // connect mouse function v.11.03 - takeMouse(zd,WarpA_mousefunc,dragcursor); - else freeMouse(); // disconnect mouse - } - - if (strEqu(event,"undlast")) { - if (NWarpA) { // undo most recent warp - ii = --NWarpA; - wdx = WarpAmem[0][ii]; - wdy = WarpAmem[1][ii]; - wdw = WarpAmem[2][ii]; - wdh = WarpAmem[3][ii]; - WarpA_warpfunc(wdx,wdy,-wdw,-wdh,0); // unwarp image - WarpA_warpfunc(wdx,wdy,-wdw,-wdh,1); // unwarp memory - } - } - - if (strEqu(event,"undall")) // undo all warps - { - edit_reset(); // v.10.3 - - for (py = 0; py < E3hh; py++) // reset pixel displacements - for (px = 0; px < E3ww; px++) - { - ii = py * E3ww + px; - WarpAx[ii] = WarpAy[ii] = 0.0; - } - - NWarpA = 0; // erase undo memory - mwpaint2(); - } - - return 1; -} - - -// warp mouse function - -void WarpA_mousefunc(void) -{ - static float wdx, wdy, wdw, wdh; - static int ii, warped = 0; - - if (Mxdrag || Mydrag) // mouse drag underway - { - wdx = Mxdown; // drag origin, image coordinates - wdy = Mydown; - wdw = Mxdrag - Mxdown; // drag increment - wdh = Mydrag - Mydown; - WarpA_warpfunc(wdx,wdy,wdw,wdh,0); // warp image - warped = 1; - return; - } - - else if (warped) - { - warped = 0; - WarpA_warpfunc(wdx,wdy,wdw,wdh,1); // drag done, add to warp memory - - if (NWarpA == 100) // if full, throw away oldest - { - NWarpA = 99; - for (ii = 0; ii < NWarpA; ii++) - { - WarpAmem[0][ii] = WarpAmem[0][ii+1]; - WarpAmem[1][ii] = WarpAmem[1][ii+1]; - WarpAmem[2][ii] = WarpAmem[2][ii+1]; - WarpAmem[3][ii] = WarpAmem[3][ii+1]; - } - } - - ii = NWarpA; - WarpAmem[0][ii] = wdx; // save warp for undo - WarpAmem[1][ii] = wdy; - WarpAmem[2][ii] = wdw; - WarpAmem[3][ii] = wdh; - NWarpA++; - } - - return; -} - - -// warp image and accumulate warp memory - -void WarpA_warpfunc(float wdx, float wdy, float wdw, float wdh, int acc) -{ - int ii, px, py, ww, hh, vstat; - double ddx, ddy, dpe, dpm, mag, dispx, dispy; - uint16 vpix[3], *pix3; - - edit_zapredo(); // delete redo copy v.10.3 - - if (! Factivearea) return; // area erased v.11.06.1 - - for (py = sa_miny; py < sa_maxy; py++) // loop all pixels in area v.10.11 - for (px = sa_minx; px < sa_maxx; px++) - { - ii = py * Fww + px; - dpe = sa_pixmap[ii]; // distance from area edge - if (! dpe) continue; - - ddx = (px - wdx); - ddy = (py - wdy); - dpm = sqrt(ddx*ddx + ddy*ddy); // distance from drag origin - - mag = dpe / (dpm + dpe); // relative pixel movement, 0 to 1 v.11.08 - - dispx = -wdw * mag; // pixel movement from drag movement - dispy = -wdh * mag; - - if (acc) { // mouse drag done, - WarpAx[ii] += dispx; // accumulate warp memory - WarpAy[ii] += dispy; - continue; - } - - dispx += WarpAx[ii]; // add this warp to prior - dispy += WarpAy[ii]; - - vstat = vpixel(E1pxm16,px+dispx,py+dispy,vpix); // input virtual pixel - if (vstat) { - pix3 = PXMpix(E3pxm16,px,py); // output pixel - pix3[0] = vpix[0]; - pix3[1] = vpix[1]; - pix3[2] = vpix[2]; - } - } - - ww = sa_maxx - sa_minx; // update window v.10.11 - hh = sa_maxy - sa_miny; - mwpaint3(sa_minx,sa_miny,ww,hh); - - CEF->Fmod = 1; // v.10.2 - return; -} - - -/**************************************************************************/ - -// warp/distort whole image with a curved transform -// fix perspective problems (e.g. curved walls, leaning buildings) - -float *WarpCx, *WarpCy; // memory of all dragged pixels -float WarpCmem[4][100]; // undo memory, last 100 drags -int NWarpC; // WarpCmem count -int WarpCdrag; -int WarpCww, WarpChh; - -editfunc EFwarpC; - -void WarpC_warpfunc(float wdx, float wdy, float wdw, float wdh, int acc); -void WarpC_mousefunc(void); - - -void m_warp_curved(GtkWidget *, cchar *) -{ - int WarpC_dialog_event(zdialog *zd, cchar *event); - - cchar *WarpC_message = ZTX( - " Pull an image position using the mouse. \n" - " Make multiple mouse pulls until satisfied. \n" - " When finished, press [done]."); - - int px, py, ii; - - zfuncs::F1_help_topic = "warp_curved"; - - EFwarpC.funcname = "warp-curved"; - EFwarpC.Fprev = 1; // use preview - EFwarpC.mousefunc = WarpC_mousefunc; // mouse function - if (! edit_setup(EFwarpC)) return; // setup edit - - zdialog *zd = zdialog_new(ZTX("Warp Image (curved)"),mWin,Bdone,Bcancel,null); - EFwarpC.zd = zd; - - zdialog_add_widget(zd,"label","lab1","dialog",WarpC_message,"space=5"); - zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=10"); - zdialog_add_widget(zd,"button","undlast","hb1",Bundolast,"space=5"); - zdialog_add_widget(zd,"button","undall","hb1",Bundoall,"space=5"); - zdialog_add_widget(zd,"hbox","hb2","dialog",0,"space=10"); - zdialog_add_widget(zd,"button","grid","hb2",ZTX("Grid"),"space=10"); - - load_grid(warpC_grid); // load grid preferences v.11.11 - - zdialog_help(zd,"warp_curved"); // zdialog help topic - zdialog_run(zd,WarpC_dialog_event,"save"); // run dialog, parallel v.11.07 - - NWarpC = WarpCdrag = 0; // no drag data - - WarpCx = (float *) zmalloc(E3ww * E3hh * sizeof(float),"warpC"); // get memory for pixel displacements - WarpCy = (float *) zmalloc(E3ww * E3hh * sizeof(float),"warpC"); - - for (py = 0; py < E3hh; py++) // no pixel displacements - for (px = 0; px < E3ww; px++) - { - ii = py * E3ww + px; - WarpCx[ii] = WarpCy[ii] = 0.0; - } - - WarpCww = E3ww; // preview dimensions - WarpChh = E3hh; - - takeMouse(zd,WarpC_mousefunc,dragcursor); // connect mouse function v.11.03 - return; -} - - -// dialog event and completion callback function - -int WarpC_dialog_event(zdialog * zd, cchar *event) -{ - int px, py, ii; - float wdx, wdy, wdw, wdh; - int fpx, fpy, epx, epy, vstat; - double scale, dispx, dispy; - uint16 vpix[3], *pix3; - - if (zd->zstat) goto complete; - - if (strEqu(event,"undlast")) - { - if (NWarpC == 1) event = "undall"; - else if (NWarpC) { // undo most recent drag - ii = --NWarpC; - wdx = WarpCmem[0][ii]; - wdy = WarpCmem[1][ii]; - wdw = WarpCmem[2][ii]; - wdh = WarpCmem[3][ii]; - WarpC_warpfunc(wdx,wdy,-wdw,-wdh,0); // undrag image - WarpC_warpfunc(wdx,wdy,-wdw,-wdh,1); // undrag memory - } - } - - if (strEqu(event,"undall")) // undo all drags - { - NWarpC = 0; // erase undo memory - - for (py = 0; py < E3hh; py++) // reset pixel displacements - for (px = 0; px < E3ww; px++) - { - ii = py * E3ww + px; - WarpCx[ii] = WarpCy[ii] = 0.0; - } - edit_reset(); // restore image 1 v.10.3 - } - - if (strEqu(event,"grid")) m_gridlines(0,0); // grid dialog v.11.11 - - if (strstr("KB G KB g",event)) // G key, toggle grid v.11.11 - toggle_grid(2); - - return 1; - -complete: - - save_grid(warpC_grid); // save grid preferences v.11.11 - Fgrid = 0; // grid off - - if (zd->zstat != 1) edit_cancel(EFwarpC); - else if (NWarpC == 0) edit_cancel(EFwarpC); - else - { - edit_fullsize(); // get full-size E1/E3 - - scale = 1.0 * (E3ww + E3hh) / (WarpCww + WarpChh); - - for (fpy = 0; fpy < E3hh; fpy++) // scale net pixel displacements - for (fpx = 0; fpx < E3ww; fpx++) // to full image size - { - epx = WarpCww * fpx / E3ww; - epy = WarpChh * fpy / E3hh; - ii = epy * WarpCww + epx; - dispx = WarpCx[ii] * scale; - dispy = WarpCy[ii] * scale; - - vstat = vpixel(E1pxm16,fpx+dispx,fpy+dispy,vpix); // input virtual pixel - pix3 = PXMpix(E3pxm16,fpx,fpy); // output pixel - if (vstat) { - pix3[0] = vpix[0]; - pix3[1] = vpix[1]; - pix3[2] = vpix[2]; - } - else pix3[0] = pix3[1] = pix3[2] = 0; - } - - edit_done(EFwarpC); - } - - zfree(WarpCx); // release memory - zfree(WarpCy); - return 0; -} - - -// WarpC mouse function - -void WarpC_mousefunc(void) -{ - static float wdx, wdy, wdw, wdh; - int ii; - - if (Mxdrag || Mydrag) // mouse drag underway - { - wdx = Mxdown; // drag origin, window coordinates - wdy = Mydown; - wdw = Mxdrag - Mxdown; // drag increment - wdh = Mydrag - Mydown; - WarpC_warpfunc(wdx,wdy,wdw,wdh,0); // drag image - WarpCdrag = 1; - return; - } - - else if (WarpCdrag) - { - WarpCdrag = 0; - WarpC_warpfunc(wdx,wdy,wdw,wdh,1); // drag done, add to memory - - if (NWarpC == 100) // if full, throw away oldest - { - NWarpC = 99; - for (ii = 0; ii < NWarpC; ii++) - { - WarpCmem[0][ii] = WarpCmem[0][ii+1]; - WarpCmem[1][ii] = WarpCmem[1][ii+1]; - WarpCmem[2][ii] = WarpCmem[2][ii+1]; - WarpCmem[3][ii] = WarpCmem[3][ii+1]; - } - } - - ii = NWarpC; - WarpCmem[0][ii] = wdx; // save drag for undo - WarpCmem[1][ii] = wdy; - WarpCmem[2][ii] = wdw; - WarpCmem[3][ii] = wdh; - NWarpC++; - } - - return; -} - - -// warp image and accumulate warp memory -// mouse at (mx,my) is moved (mw,mh) pixels - -void WarpC_warpfunc(float mx, float my, float mw, float mh, int acc) -{ - int ii, px, py, vstat; - double mag, dispx, dispy; - double d1, d2, d3, d4; - uint16 vpix[3], *pix3; - - edit_zapredo(); // delete redo copy v.10.3 - - d1 = (mx-0) * (mx-0) + (my-0) * (my-0); // distance, mouse to 4 corners - d2 = (E3ww-mx) * (E3ww-mx) + (my-0) * (my-0); - d3 = (E3ww-mx) * (E3ww-mx) + (E3hh-my) * (E3hh-my); - d4 = (mx-0) * (mx-0) + (E3hh-my) * (E3hh-my); - - if (d2 > d1) d1 = d2; // d1 = greatest v.10.11 - if (d3 > d1) d1 = d3; - if (d4 > d1) d1 = d4; - - for (py = 0; py < E3hh; py++) // process all pixels - for (px = 0; px < E3ww; px++) - { - d2 = (px-mx)*(px-mx) + (py-my)*(py-my); - mag = (1.0 - d2 / d1); - mag = mag * mag; // faster than pow(mag,16); - mag = mag * mag; - - dispx = -mw * mag; // displacement = drag * mag - dispy = -mh * mag; - - ii = py * E3ww + px; - - if (acc) { // drag done, accumulate drag sum - WarpCx[ii] += dispx; - WarpCy[ii] += dispy; - continue; - } - - dispx += WarpCx[ii]; // add this drag to prior sum - dispy += WarpCy[ii]; - - vstat = vpixel(E1pxm16,px+dispx,py+dispy,vpix); // input virtual pixel - pix3 = PXMpix(E3pxm16,px,py); // output pixel - if (vstat) { - pix3[0] = vpix[0]; - pix3[1] = vpix[1]; - pix3[2] = vpix[2]; - } - else pix3[0] = pix3[1] = pix3[2] = 0; - } - - CEF->Fmod = 1; - mwpaint2(); // update window - return; -} - - -/**************************************************************************/ - -// warp/distort whole image with a linear transform -// fix perspective problems (e.g. curved walls, leaning buildings) - -float *WarpLx, *WarpLy; // memory of all dragged pixels -float WarpLmem[4][100]; // undo memory, last 100 drags -int NWarpL; // WarpLmem count -int WarpLdrag; -int WarpLww, WarpLhh; - -editfunc EFwarpL; - -void WarpL_warpfunc(float wdx, float wdy, float wdw, float wdh, int acc); -void WarpL_mousefunc(void); - - -void m_warp_linear(GtkWidget *, cchar *) // new v.10.11 -{ - int WarpL_dialog_event(zdialog *zd, cchar *event); - - cchar *WarpL_message = ZTX( - " Pull an image position using the mouse. \n" - " Make multiple mouse pulls until satisfied. \n" - " When finished, press [done]."); - - int px, py, ii; - - zfuncs::F1_help_topic = "warp_linear"; - - EFwarpL.funcname = "warp-linear"; - EFwarpL.Fprev = 1; // use preview - EFwarpL.mousefunc = WarpL_mousefunc; // mouse function - if (! edit_setup(EFwarpL)) return; // setup edit - - zdialog *zd = zdialog_new(ZTX("Warp Image (linear)"),mWin,Bdone,Bcancel,null); - EFwarpL.zd = zd; - - zdialog_add_widget(zd,"label","lab1","dialog",WarpL_message,"space=5"); - zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=10"); - zdialog_add_widget(zd,"button","undlast","hb1",Bundolast,"space=5"); - zdialog_add_widget(zd,"button","undall","hb1",Bundoall,"space=5"); - zdialog_add_widget(zd,"hbox","hb2","dialog",0,"space=10"); - zdialog_add_widget(zd,"button","grid","hb2",ZTX("Grid"),"space=10"); - - load_grid(warpL_grid); // load grid preferences v.11.11 - - zdialog_help(zd,"warp_linear"); // zdialog help topic v.11.08 - zdialog_run(zd,WarpL_dialog_event,"save"); // run dialog, parallel v.11.07 - - NWarpL = WarpLdrag = 0; // no drag data - - WarpLx = (float *) zmalloc(E3ww * E3hh * sizeof(float),"warpL"); // get memory for pixel displacements - WarpLy = (float *) zmalloc(E3ww * E3hh * sizeof(float),"warpL"); - - for (py = 0; py < E3hh; py++) // no pixel displacements - for (px = 0; px < E3ww; px++) - { - ii = py * E3ww + px; - WarpLx[ii] = WarpLy[ii] = 0.0; - } - - WarpLww = E3ww; // preview dimensions - WarpLhh = E3hh; - - takeMouse(zd,WarpL_mousefunc,dragcursor); // connect mouse function v.11.03 - return; -} - - -// dialog event and completion callback function - -int WarpL_dialog_event(zdialog * zd, cchar *event) -{ - int px, py, ii; - float wdx, wdy, wdw, wdh; - int fpx, fpy, epx, epy, vstat; - double scale, dispx, dispy; - uint16 vpix[3], *pix3; - - if (zd->zstat) goto complete; - - if (strEqu(event,"undlast")) - { - if (NWarpL == 1) event = "undall"; - else if (NWarpL) { // undo most recent drag - ii = --NWarpL; - wdx = WarpLmem[0][ii]; - wdy = WarpLmem[1][ii]; - wdw = WarpLmem[2][ii]; - wdh = WarpLmem[3][ii]; - WarpL_warpfunc(wdx,wdy,-wdw,-wdh,0); // undrag image - WarpL_warpfunc(wdx,wdy,-wdw,-wdh,1); // undrag memory - } - } - - if (strEqu(event,"undall")) // undo all drags - { - NWarpL = 0; // erase undo memory - - for (py = 0; py < E3hh; py++) // reset pixel displacements - for (px = 0; px < E3ww; px++) - { - ii = py * E3ww + px; - WarpLx[ii] = WarpLy[ii] = 0.0; - } - edit_reset(); // restore image 1 v.10.3 - } - - if (strEqu(event,"grid")) m_gridlines(0,0); // grid dialog v.11.11 - - if (strstr("KB G KB g",event)) // G key, toggle grid v.11.11 - toggle_grid(2); - - return 1; - -complete: - - save_grid(warpL_grid); // save grid preferences v.11.11 - Fgrid = 0; // grid off - - if (zd->zstat != 1) edit_cancel(EFwarpL); - else if (NWarpL == 0) edit_cancel(EFwarpL); - else - { - edit_fullsize(); // get full-size E1/E3 - - scale = 1.0 * (E3ww + E3hh) / (WarpLww + WarpLhh); - - for (fpy = 0; fpy < E3hh; fpy++) // scale net pixel displacements - for (fpx = 0; fpx < E3ww; fpx++) // to full image size - { - epx = WarpLww * fpx / E3ww; - epy = WarpLhh * fpy / E3hh; - ii = epy * WarpLww + epx; - dispx = WarpLx[ii] * scale; - dispy = WarpLy[ii] * scale; - - vstat = vpixel(E1pxm16,fpx+dispx,fpy+dispy,vpix); // input virtual pixel - pix3 = PXMpix(E3pxm16,fpx,fpy); // output pixel - if (vstat) { - pix3[0] = vpix[0]; - pix3[1] = vpix[1]; - pix3[2] = vpix[2]; - } - else pix3[0] = pix3[1] = pix3[2] = 0; - } - - edit_done(EFwarpL); - } - - zfree(WarpLx); // release memory - zfree(WarpLy); - return 0; -} - - -// WarpL mouse function - -void WarpL_mousefunc(void) -{ - static float wdx, wdy, wdw, wdh; - int ii; - - if (Mxdrag || Mydrag) // mouse drag underway - { - wdx = Mxdown; // drag origin, window coordinates - wdy = Mydown; - wdw = Mxdrag - Mxdown; // drag increment - wdh = Mydrag - Mydown; - WarpL_warpfunc(wdx,wdy,wdw,wdh,0); // drag image - WarpLdrag = 1; - return; - } - - else if (WarpLdrag) - { - WarpLdrag = 0; - WarpL_warpfunc(wdx,wdy,wdw,wdh,1); // drag done, add to memory - - if (NWarpL == 100) // if full, throw away oldest - { - NWarpL = 99; - for (ii = 0; ii < NWarpL; ii++) - { - WarpLmem[0][ii] = WarpLmem[0][ii+1]; - WarpLmem[1][ii] = WarpLmem[1][ii+1]; - WarpLmem[2][ii] = WarpLmem[2][ii+1]; - WarpLmem[3][ii] = WarpLmem[3][ii+1]; - } - } - - ii = NWarpL; - WarpLmem[0][ii] = wdx; // save drag for undo - WarpLmem[1][ii] = wdy; - WarpLmem[2][ii] = wdw; - WarpLmem[3][ii] = wdh; - NWarpL++; - } - - return; -} - - -// warp image and accumulate warp memory -// mouse at (mx,my) is moved (mw,mh) pixels - -void WarpL_warpfunc(float mx, float my, float mw, float mh, int acc) -{ - int ii, px, py, vstat; - double mag, dispx, dispy; - double d1, d2, d3, d4; - uint16 vpix[3], *pix3; - - edit_zapredo(); // delete redo copy v.10.3 - - d1 = (mx-0) * (mx-0) + (my-0) * (my-0); // distance, mouse to 4 corners - d2 = (E3ww-mx) * (E3ww-mx) + (my-0) * (my-0); - d3 = (E3ww-mx) * (E3ww-mx) + (E3hh-my) * (E3hh-my); - d4 = (mx-0) * (mx-0) + (E3hh-my) * (E3hh-my); - - if (d2 > d1) d1 = d2; // d1 = greatest v.10.11 - if (d3 > d1) d1 = d3; - if (d4 > d1) d1 = d4; - - d1 = sqrt(d1); - - for (py = 0; py < E3hh; py++) // process all pixels - for (px = 0; px < E3ww; px++) - { - d2 = (px-mx)*(px-mx) + (py-my)*(py-my); - d2 = sqrt(d2); - mag = (1.0 - d2 / d1); - - dispx = -mw * mag; // displacement = drag * mag - dispy = -mh * mag; - - ii = py * E3ww + px; - - if (acc) { // drag done, accumulate drag sum - WarpLx[ii] += dispx; - WarpLy[ii] += dispy; - continue; - } - - dispx += WarpLx[ii]; // add this drag to prior sum - dispy += WarpLy[ii]; - - vstat = vpixel(E1pxm16,px+dispx,py+dispy,vpix); // input virtual pixel - pix3 = PXMpix(E3pxm16,px,py); // output pixel - if (vstat) { - pix3[0] = vpix[0]; - pix3[1] = vpix[1]; - pix3[2] = vpix[2]; - } - else pix3[0] = pix3[1] = pix3[2] = 0; - } - - CEF->Fmod = 1; - mwpaint2(); // update window - return; -} - - -/**************************************************************************/ - -// warp/distort whole image using affine transform -// (straight lines remain straight) - -double WarpF_old[3][2]; // 3 original image points -double WarpF_new[3][2]; // corresponding warped points -double WarpF_coeff[6]; // transform coefficients -double WarpF_Icoeff[6]; // inverse transform coefficients -int WarpF_ftf; // first time flag - -editfunc EFwarpF; - -void WarpF_warpfunc(); // image warp function -void WarpF_mousefunc(void); -void WarpF_affine(double po[3][2], double pn[3][2], double coeff[6]); // compute affine transform coefficients -void WarpF_invert(double coeff[6], double Icoeff[6]); // compute reverse transform coefficients - - -void m_warp_affine(GtkWidget *, cchar *) -{ - int WarpF_dialog_event(zdialog *zd, cchar *event); - - cchar *WarpF_message = ZTX( - " Pull on an image corner using the mouse. \n" - " Make multiple mouse pulls until satisfied. \n" - " When finished, press [done]."); - - zfuncs::F1_help_topic = "warp_affine"; - - EFwarpF.funcname = "warp-affine"; - EFwarpF.Fprev = 1; // use preview - EFwarpF.mousefunc = WarpF_mousefunc; // mouse function - if (! edit_setup(EFwarpF)) return; // setup edit - - zdialog *zd = zdialog_new(ZTX("Warp Image (affine)"),mWin,Bdone,Bcancel,null); - EFwarpF.zd = zd; - - zdialog_add_widget(zd,"label","lab1","dialog",WarpF_message,"space=5"); - zdialog_add_widget(zd,"hbox","hb2","dialog",0,"space=10"); - zdialog_add_widget(zd,"button","grid","hb2",ZTX("Grid"),"space=10"); - - load_grid(warpF_grid); // load grid preferences v.11.11 - - zdialog_help(zd,"warp_affine"); // zdialog help topic v.11.08 - zdialog_run(zd,WarpF_dialog_event,"save"); // run dialog, parallel v.11.07 - - WarpF_ftf = 1; // 1st warp flag - - takeMouse(zd,WarpF_mousefunc,dragcursor); // connect mouse function v.11.03 - return; -} - - -// dialog event and completion callback function - -int WarpF_dialog_event(zdialog *zd, cchar *event) -{ - double scale; - int ww, hh; - - if (strEqu(event,"grid")) m_gridlines(0,0); // grid dialog v.11.11 - - if (strstr("KB G KB g",event)) // G key, toggle grid v.11.11 - toggle_grid(2); - - if (! zd->zstat) return 1; // wait for completion - - save_grid(warpF_grid); // save grid preferences v.11.11 - Fgrid = 0; // grid off - - if (zd->zstat != 1 || ! CEF->Fmod) { - edit_cancel(EFwarpF); // bugfix v.11.11 - return 0; - } - - ww = E3ww; // preview image dimensions - hh = E3hh; - - edit_fullsize(); // get full-size images - - scale = 1.0 * (E3ww + E3hh) / (ww + hh); // preview to full-size scale factor - - WarpF_old[0][0] = WarpF_old[0][0] * scale; // re-scale new and old points - WarpF_old[0][1] = WarpF_old[0][1] * scale; - WarpF_old[1][0] = WarpF_old[1][0] * scale; - WarpF_old[1][1] = WarpF_old[1][1] * scale; - WarpF_old[2][0] = WarpF_old[2][0] * scale; - WarpF_old[2][1] = WarpF_old[2][1] * scale; - - WarpF_new[0][0] = WarpF_new[0][0] * scale; - WarpF_new[0][1] = WarpF_new[0][1] * scale; - WarpF_new[1][0] = WarpF_new[1][0] * scale; - WarpF_new[1][1] = WarpF_new[1][1] * scale; - WarpF_new[2][0] = WarpF_new[2][0] * scale; - WarpF_new[2][1] = WarpF_new[2][1] * scale; - - WarpF_warpfunc(); // warp full-size image - edit_done(EFwarpF); - - return 0; -} - - -// WarpF mouse function - -void WarpF_mousefunc(void) -{ - int mdx1, mdy1, mdx2, mdy2; - double x1o, y1o, x2o, y2o, x3o, y3o; - double x1n, y1n, x2n, y2n, x3n, y3n; - double a, b, c, d, e, f; - - if (Mxdrag + Mydrag == 0) return; - - mdx1 = Mxdown; // mouse drag origin - mdy1 = Mydown; - mdx2 = Mxdrag; // mouse drag position - mdy2 = Mydrag; - - Mxdown = Mxdrag; // reset origin for next time - Mydown = Mydrag; - - x1n = mdx1; // point 1 = drag origin - y1n = mdy1; - x2n = E3ww - x1n; // point 2 = mirror of point1 - y2n = E3hh - y1n; - x3n = E3ww * (y2n / E3hh); - y3n = E3hh * (1.0 - (x2n / E3ww)); - - if (WarpF_ftf) // first warp - { - WarpF_ftf = 0; - x1o = x1n; // old = current positions - y1o = y1n; - x2o = x2n; - y2o = y2n; - x3o = x3n; - y3o = y3n; - } - else - { - WarpF_invert(WarpF_coeff,WarpF_Icoeff); // get inverse coefficients - a = WarpF_Icoeff[0]; - b = WarpF_Icoeff[1]; - c = WarpF_Icoeff[2]; - d = WarpF_Icoeff[3]; - e = WarpF_Icoeff[4]; - f = WarpF_Icoeff[5]; - - x1o = a * x1n + b * y1n + c; // compute old from current positions - y1o = d * x1n + e * y1n + f; - x2o = a * x2n + b * y2n + c; - y2o = d * x2n + e * y2n + f; - x3o = a * x3n + b * y3n + c; - y3o = d * x3n + e * y3n + f; - } - - WarpF_old[0][0] = x1o; // set up 3 old points and corresponding - WarpF_old[0][1] = y1o; // new points for affine translation - WarpF_old[1][0] = x2o; - WarpF_old[1][1] = y2o; - WarpF_old[2][0] = x3o; - WarpF_old[2][1] = y3o; - - x1n = mdx2; // point 1 new position = drag position - y1n = mdy2; - x2n = E3ww - x1n; // point 2 new = mirror of point1 new - y2n = E3hh - y1n; - - WarpF_new[0][0] = x1n; // 3 new points - WarpF_new[0][1] = y1n; - WarpF_new[1][0] = x2n; - WarpF_new[1][1] = y2n; - WarpF_new[2][0] = x3n; - WarpF_new[2][1] = y3n; - - WarpF_warpfunc(); // do the warp - - return; -} - - -// warp image and accumulate warp memory - -void WarpF_warpfunc() -{ - double a, b, c, d, e, f; - int px3, py3, vstat; - double px1, py1; - uint16 vpix1[3], *pix3; - - edit_zapredo(); // delete redo copy v.10.3 - - WarpF_affine(WarpF_old, WarpF_new, WarpF_coeff); // get coefficients for forward transform - WarpF_invert(WarpF_coeff, WarpF_Icoeff); // get coefficients for reverse transform - - a = WarpF_Icoeff[0]; // coefficients to map output pixels - b = WarpF_Icoeff[1]; // to corresponding input pixels - c = WarpF_Icoeff[2]; - d = WarpF_Icoeff[3]; - e = WarpF_Icoeff[4]; - f = WarpF_Icoeff[5]; - - for (py3 = 0; py3 < E3hh; py3++) // loop all output pixels - for (px3 = 0; px3 < E3ww; px3++) - { - px1 = a * px3 + b * py3 + c; // corresponding input pixel - py1 = d * px3 + e * py3 + f; - - vstat = vpixel(E1pxm16,px1,py1,vpix1); // input virtual pixel - pix3 = PXMpix(E3pxm16,px3,py3); // output pixel - - if (vstat) { - pix3[0] = vpix1[0]; - pix3[1] = vpix1[1]; - pix3[2] = vpix1[2]; - } - else pix3[0] = pix3[1] = pix3[2] = 0; - } - - CEF->Fmod = 1; - mwpaint2(); // update window - return; -} - - -/************************************************************************** - - Compute affine transformation of an image (warp image). - - Given 3 new (warped) positions for 3 image points, derive the - coefficients of the translation function to warp the entire image. - - Inputs: - pold[3][2] (x,y) coordinates for 3 points in original image - pnew[3][2] (x,y) coordinates for same points in warped image - - Output: - coeff[6] coefficients of translation function which can be used - to convert all image points to their warped positions - - If coeff[6] = (a, b, c, d, e, f) then the following formula - can be used to convert an image point to its warped position: - - Xnew = a * Xold + b * Yold + c - Ynew = d * Xold + e * Yold + f - -***************************************************************************/ - -void WarpF_affine(double pold[3][2], double pnew[3][2], double coeff[6]) -{ - double x11, y11, x12, y12, x13, y13; // original points - double x21, y21, x22, y22, x23, y23; // moved points - double a, b, c, d, e, f; // coefficients - double A1, A2, B1, B2, C1, C2; - - x11 = pold[0][0]; - y11 = pold[0][1]; - x12 = pold[1][0]; - y12 = pold[1][1]; - x13 = pold[2][0]; - y13 = pold[2][1]; - - x21 = pnew[0][0]; - y21 = pnew[0][1]; - x22 = pnew[1][0]; - y22 = pnew[1][1]; - x23 = pnew[2][0]; - y23 = pnew[2][1]; - - A1 = x11 - x12; - A2 = x12 - x13; - B1 = y11 - y12; - B2 = y12 - y13; - C1 = x21 - x22; - C2 = x22 - x23; - - a = (B1 * C2 - B2 * C1) / (A2 * B1 - A1 * B2); - b = (A1 * C2 - A2 * C1) / (A1 * B2 - A2 * B1); - c = x23 - a * x13 - b * y13; - - C1 = y21 - y22; - C2 = y22 - y23; - - d = (B1 * C2 - B2 * C1) / (A2 * B1 - A1 * B2); - e = (A1 * C2 - A2 * C1) / (A1 * B2 - A2 * B1); - f = y23 - d * x13 - e * y13; - - coeff[0] = a; - coeff[1] = b; - coeff[2] = c; - coeff[3] = d; - coeff[4] = e; - coeff[5] = f; - - return; -} - - -/************************************************************************** - - Invert affine transform - - Input: - coeff[6] coefficients of translation function to convert - image points to their warped positions - Output: - Icoeff[6] coefficients of translation function to convert - warped image points to their original positions - - If Icoeff[6] = (a, b, c, d, e, f) then the following formula can be - used to translate a warped image point to its original position: - - Xold = a * Xnew + b * Ynew + c - Yold = d * Xnew + e * Ynew + f - -***************************************************************************/ - -void WarpF_invert(double coeff[6], double Icoeff[6]) -{ - double a, b, c, d, e, f, Z; - - a = coeff[0]; - b = coeff[1]; - c = coeff[2]; - d = coeff[3]; - e = coeff[4]; - f = coeff[5]; - - Z = 1.0 / (a * e - b * d); - - Icoeff[0] = e * Z; - Icoeff[1] = - b * Z; - Icoeff[2] = Z * (b * f - c * e); - Icoeff[3] = - d * Z; - Icoeff[4] = a * Z; - Icoeff[5] = Z * (c * d - a * f); - - return; -} - - - diff -Nru fotoxx-11.11.1/f.retouch.cc fotoxx-12.01.2/f.retouch.cc --- fotoxx-11.11.1/f.retouch.cc 1970-01-01 00:00:00.000000000 +0000 +++ fotoxx-12.01.2/f.retouch.cc 2012-01-04 08:47:11.000000000 +0000 @@ -0,0 +1,7116 @@ +/************************************************************************** + + Fotoxx edit photos and manage collections + + Copyright 2007 2008 2009 2010 2011 2012 Michael Cornelison + Source URL: http://kornelix.squarespace.com/fotoxx + Contact: kornelix2@googlemail.com + + 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 http://www.gnu.org/licenses/. + +***************************************************************************/ + +#define EX extern // enable extern declarations +#include "fotoxx.h" + + +/************************************************************************** + + Fotoxx image edit - retouch functions + +***************************************************************************/ + + +// brightness / color / contrast adjustment + +void tune_curve_update(int spc); // curve update callback function +void tune_update_image(); // process all pixels +void tune_update_pixel(int px, int py); // process one pixel +void *tune_thread(void *); // thread process for all pixels + +int tune_spc; // current spline curve 1-5 +int tune_spc_moved[6]; // tracks which curves changed + +double tune_pow[10000]; // pow(2,x) for x = -5.0 to +5.0 +int tune_ftf = 1; + +editfunc EFtune; + + +void m_tune(GtkWidget *, cchar *) // menu function +{ + int tune_dialog_event(zdialog *zd, cchar *event); + + cchar *title = ZTX("Adjust Brightness and Color"); + zfuncs::F1_help_topic = "tune"; // v.10.8 + + EFtune.funcname = "bright-color"; + EFtune.Fprev = 1; // use preview + EFtune.Farea = 2; // select area usable + EFtune.Fpara = 1; // parallel edit OK + EFtune.threadfunc = tune_thread; + if (! edit_setup(EFtune)) return; // setup edit + + if (tune_ftf) { + tune_ftf = 0; // pre-compute pow(2,x) + for (int ii = 0; ii < 10000; ii++) // for x = -5.0 to +4.999 + tune_pow[ii] = pow(2,(ii/1000.0 - 5.0)); + } + +/*** + Adjust Brightness and Color + ____________________________________________ + | | + | | + | curve drawing area | + | | + | | + |____________________________________________| + darker areas lighter areas + + [+++] [---] [+ -] [- +] [+-+] [-+-] + [x] small-steps Curve File: [ Open ] [ Save ] + (o) brightness [reset 1] [reset all] + (o) color saturation [histogram] + (o) red + (o) green + (o) blue + [done] [cancel] +***/ + + zdialog *zd = zdialog_new(title,mWin,Bdone,Bcancel,null); + EFtune.zd = zd; + + zdialog_add_widget(zd,"frame","fr1","dialog",0,"expand"); + zdialog_add_widget(zd,"hbox","hba","dialog"); + zdialog_add_widget(zd,"label","labda","hba",Bdarker,"space=5"); + zdialog_add_widget(zd,"label","space","hba",0,"expand"); + zdialog_add_widget(zd,"label","labba","hba",Blighter,"space=5"); + + zdialog_add_widget(zd,"hbox","hbb","dialog",0,"space=5"); + zdialog_add_widget(zd,"button","b +++","hbb","+++"); + zdialog_add_widget(zd,"button","b ---","hbb","‒ ‒ ‒"); + zdialog_add_widget(zd,"button","b +-", "hbb"," + ‒ "); + zdialog_add_widget(zd,"button","b -+", "hbb"," ‒ + "); + zdialog_add_widget(zd,"button","b +-+","hbb","+ ‒ +"); + zdialog_add_widget(zd,"button","b -+-","hbb","‒ + ‒"); + + zdialog_add_widget(zd,"hbox","hbcf","dialog",0,"space=5"); + zdialog_add_widget(zd,"check","smallstep","hbcf",ZTX("small-steps")); + zdialog_add_widget(zd,"label","labcf","hbcf",Bcurvefile,"space=5"); + zdialog_add_widget(zd,"button","load","hbcf",Bopen); + zdialog_add_widget(zd,"button","save","hbcf",Bsave,"space=5"); + + zdialog_add_widget(zd,"hbox","hb2","dialog"); + zdialog_add_widget(zd,"vbox","vb21","hb2"); + zdialog_add_widget(zd,"vbox","vb22","hb2"); + zdialog_add_widget(zd,"radio","radbri","vb21",Bbrightness); + zdialog_add_widget(zd,"radio","radsat","vb21",ZTX("color saturation")); + zdialog_add_widget(zd,"radio","radR","vb21",Bred); + zdialog_add_widget(zd,"radio","radG","vb21",Bgreen); + zdialog_add_widget(zd,"radio","radB","vb21",Bblue); + + zdialog_add_widget(zd,"hbox","hbrs","vb22",0,"space=5"); + zdialog_add_widget(zd,"label","space","hbrs",0,"space=10"); + zdialog_add_widget(zd,"button","reset1","hbrs",ZTX(" reset 1 ")); + zdialog_add_widget(zd,"button","resetA","hbrs",ZTX("reset all")); + zdialog_add_widget(zd,"hbox","hbhist","vb22",0,"space=6"); + zdialog_add_widget(zd,"label","space","hbhist",0,"space=10"); + zdialog_add_widget(zd,"button","histo","hbhist",Bhistogram); + + GtkWidget *frame = zdialog_widget(zd,"fr1"); // setup for curve editing + spldat *sd = splcurve_init(frame,tune_curve_update); // v.11.01 + EFtune.curves = sd; + + sd->Nscale = 3; // y-scale lines at 1.0 EV intervals + sd->xscale[0][0] = 0.00; // x and y values v.11.10 + sd->yscale[0][0] = 0.25; + sd->xscale[1][0] = 1.00; + sd->yscale[1][0] = 0.25; + sd->xscale[0][1] = 0.00; + sd->yscale[0][1] = 0.50; + sd->xscale[1][1] = 1.00; + sd->yscale[1][1] = 0.50; + sd->xscale[0][2] = 0.00; + sd->yscale[0][2] = 0.75; + sd->xscale[1][2] = 1.00; + sd->yscale[1][2] = 0.75; + + for (int spc = 0; spc < 6; spc++) // setup 6 spline curves + { // no. 0 is active curve + sd->vert[spc] = 0; // all curves are horizontal + sd->nap[spc] = 3; // curves 1-6 are copied to 0 when active + sd->apx[spc][0] = 0.01; + sd->apy[spc][0] = 0.5; + sd->apx[spc][1] = 0.5; + sd->apy[spc][1] = 0.5; + sd->apx[spc][2] = 0.99; + sd->apy[spc][2] = 0.5; + splcurve_generate(sd,spc); + tune_spc_moved[spc] = 0; + } + + sd->Nspc = 1; // only one at a time is active + tune_spc = 1; // default curve = brightness + + zdialog_stuff(zd,"radbri",1); // stuff default selection + + zdialog_resize(zd,0,500); + zdialog_help(zd,"tune"); // zdialog help topic v.11.08 + zdialog_run(zd,tune_dialog_event,"save"); // run dialog - parallel v.11.07 + return; +} + + +// dialog event and completion callback function + +int tune_dialog_event(zdialog *zd, cchar *event) +{ + int Fupdate = 0; + int ii, jj, nn; + static int smallstep = 0; + double step, step2, step4; + double px, py; + spldat *sd = EFtune.curves; + spldat sdtemp; + + if (zd->zstat) + { + if (zd->zstat == 1) edit_done(EFtune); // done + else edit_cancel(EFtune); // cancel or destroy + return 0; + } + + edit_takeover(EFtune); // set my edit function + + if (strEqu(event,"reset")) // reset dialog controls v.11.08 + event = "resetA"; + + if (strEqu(event,"blendwidth")) tune_update_image(); // v.10.3 + if (strEqu(event,"histo")) m_histogram(0,0); // popup brightness histogram + + if (strnEqu(event,"rad",3)) { // new choice of curve + ii = strcmpv(event,"radbri","radsat","radR","radG","radB",null); + tune_spc = ii; + sd->nap[0] = sd->nap[ii]; // copy active curve to curve 0 + for (jj = 0; jj < sd->nap[0]; jj++) { + sd->apx[0][jj] = sd->apx[ii][jj]; + sd->apy[0][jj] = sd->apy[ii][jj]; + } + Fupdate++; + } + + if (strEqu(event,"smallstep")) // toggle [+++] etc. step size + zdialog_fetch(zd,"smallstep",smallstep); + + ii = tune_spc; // current active curve + + if (strnEqu(event,"b ",2)) { // button [+++] etc. - move entire curve + for (jj = 0; jj < sd->nap[ii]; jj++) { + px = sd->apx[0][jj]; + py = sd->apy[0][jj]; + + step = 0.025; // 1/40 + if (smallstep) step = step * 0.3333; + step2 = 2 * step; + step4 = 4 * step; + + if (strEqu(event,"b +++")) py += step; // range is 40 steps v.11.07 + if (strEqu(event,"b ---")) py -= step; // = -2.0 to +2.0 EV + if (strEqu(event,"b +-")) py += step - step2 * px; // normal steps are 0.1 EV or 0.03 OD + if (strEqu(event,"b -+")) py -= step - step2 * px; // small steps are 1/3 as big + if (strEqu(event,"b +-+")) py -= step - step4 * fabs(px-0.5); + if (strEqu(event,"b -+-")) py += step - step4 * fabs(px-0.5); + if (py > 1) py = 1; + if (py < 0) py = 0; + sd->apy[0][jj] = py; + } + tune_spc_moved[ii] = 1; + Fupdate++; + } + + if (strEqu(event,"reset1")) { // reset current curve + sd->nap[0] = 3; + sd->apx[0][0] = 0.01; // 3 anchor points, flatline + sd->apy[0][0] = 0.5; + sd->apx[0][1] = 0.5; + sd->apy[0][1] = 0.5; + sd->apx[0][2] = 0.99; + sd->apy[0][2] = 0.5; + Fupdate++; + tune_spc_moved[ii] = 0; + } + + if (strEqu(event,"resetA")) + { + for (jj = 0; jj < 6; jj++) { // reset all curves + sd->nap[jj] = 3; + sd->apx[jj][0] = 0.01; + sd->apy[jj][0] = 0.5; + sd->apx[jj][1] = 0.5; + sd->apy[jj][1] = 0.5; + sd->apx[jj][2] = 0.99; + sd->apy[jj][2] = 0.5; + splcurve_generate(sd,jj); // regenerate all + tune_spc_moved[jj] = 0; + } + Fupdate++; + } + + if (strEqu(event,"load")) // load 5 saved curves v.11.02 + { + sdtemp.Nspc = 5; + sdtemp.drawarea = 0; + nn = splcurve_load(&sdtemp); + if (nn != 1) return 0; + + for (ii = 0; ii < 5; ii++) { + for (jj = 0; jj < sdtemp.nap[ii]; jj++) { + sd->apx[ii+1][jj] = sdtemp.apx[ii][jj]; + sd->apy[ii+1][jj] = sdtemp.apy[ii][jj]; + } + splcurve_generate(sd,ii+1); + tune_spc_moved[ii+1] = 1; + } + + ii = tune_spc; + sd->nap[0] = sd->nap[ii]; // copy active curve to curve 0 + for (jj = 0; jj < sd->nap[0]; jj++) { + sd->apx[0][jj] = sd->apx[ii][jj]; + sd->apy[0][jj] = sd->apy[ii][jj]; + } + Fupdate++; + } + + if (strEqu(event,"save")) // save 5 curves to file v.11.02 + { + sdtemp.Nspc = 5; + for (ii = 0; ii < 5; ii++) { + sdtemp.nap[ii] = sd->nap[ii+1]; + for (jj = 0; jj < sd->nap[ii+1]; jj++) { + sdtemp.apx[ii][jj] = sd->apx[ii+1][jj]; + sdtemp.apy[ii][jj] = sd->apy[ii+1][jj]; + } + } + splcurve_save(&sdtemp); + } + + if (Fupdate) // curve has changed + { + splcurve_generate(sd,0); // regenerate curve 0 + + ii = tune_spc; // active curve + sd->nap[ii] = sd->nap[0]; // copy curve 0 to active curve + for (jj = 0; jj < sd->nap[0]; jj++) { + sd->apx[ii][jj] = sd->apx[0][jj]; + sd->apy[ii][jj] = sd->apy[0][jj]; + } + for (jj = 0; jj < 1000; jj++) + sd->yval[ii][jj] = sd->yval[0][jj]; + + splcurve_draw(0,0,sd); // draw curve + tune_update_image(); // trigger image update + } + + return 1; +} + + +// this function is called when curve 0 is edited using mouse + +void tune_curve_update(int) +{ + int ii = tune_spc, jj; + spldat *sd = EFtune.curves; + + edit_takeover(EFtune); // set my edit function + + sd->nap[ii] = sd->nap[0]; // copy curve 0 to current curve + for (jj = 0; jj < sd->nap[0]; jj++) { + sd->apx[ii][jj] = sd->apx[0][jj]; + sd->apy[ii][jj] = sd->apy[0][jj]; + } + for (jj = 0; jj < 1000; jj++) + sd->yval[ii][jj] = sd->yval[0][jj]; + + tune_spc_moved[ii] = 1; + tune_update_image(); // update image + return; +} + + +// Update image based on latest settings of all dialog controls. + +void tune_update_image() // v.11.06 +{ + int px, py, ww, hh; + + if (Factivearea && sa_Npixel < 200000) // if relatively small area, + { // process in main() thread v.11.06 + for (py = sa_miny; py < sa_maxy; py++) + for (px = sa_minx; px < sa_maxx; px++) + tune_update_pixel(px,py); + + px = sa_minx; // direct window update + py = sa_miny; + ww = sa_maxx - sa_minx; + hh = sa_maxy - sa_miny; + mwpaint3(px,py,ww,hh); // speedup v.11.06 + CEF->Fmod = 1; + } + + else signal_thread(); // else use thread process + return; +} + + +// Update image based on latest settings of all dialog controls. + +void * tune_thread(void *) +{ + void * tune_wthread(void *arg); + + while (true) + { + thread_idle_loop(); // wait for work or exit request + + for (int ii = 0; ii < Nwt; ii++) // start worker threads + start_wthread(tune_wthread,&wtnx[ii]); + wait_wthreads(); // wait for completion + + CEF->Fmod = 1; + mwpaint2(); // update window + } + + return 0; // not executed, stop g++ warning +} + + +void * tune_wthread(void *arg) // worker thread function +{ + int px, py; + int index = *((int *) arg); + + for (py = index; py < E1hh; py += Nwt) + for (px = 0; px < E1ww; px++) + tune_update_pixel(px,py); + + exit_wthread(); + return 0; // not executed, avoid gcc warning +} + + +void tune_update_pixel(int px, int py) // process one pixel +{ + int ii, kk, dist = 0; + uint16 *pix1, *pix3; + double red1, green1, blue1, red3, green3, blue3; + double xval, brmax, brmean, brout, brightness; + spldat *sd = EFtune.curves; + + if (Factivearea) { // select area active + ii = py * Fww + px; + dist = sa_pixmap[ii]; // distance from edge + if (! dist) return; // pixel outside area + } + + pix1 = PXMpix(E1pxm16,px,py); // input pixel + pix3 = PXMpix(E3pxm16,px,py); // output pixel + + red1 = red3 = pix1[0]; // input and output RGB values + green1 = green3 = pix1[1]; + blue1 = blue3 = pix1[2]; + + brightness = 0.25 * red3 + 0.65 * green3 + 0.10 * blue3; // perceived brightness v.10.9 + xval = brightness / 65536.0; // curve x-value, 0 to 0.999 + +/* ------------------------------------------------------------------------ + + brightness adjustment + + brightness curve values: + 0 = dark + 0.5 = normal, unchanged + 1.0 = 200% brightness, clipped +*/ + + if (tune_spc_moved[1]) // curve has been edited + { + kk = 1000 * xval; // x-value speedup v.11.06 + if (kk > 999) kk = 999; + brout = sd->yval[1][kk]; // y-value, 0 to 1.0 + brout = 4 * brout - 2; // F-stops, -2 to +2 v.11.07 + brout = tune_pow[int(1000*brout+5000.5)]; // 0.25 to 4.0 + + brmax = red3; // brmax = brightest color + if (green3 > brmax) brmax = green3; + if (blue3 > brmax) brmax = blue3; + + red3 = red3 * brout; // apply to all colors + green3 = green3 * brout; // remove limit check v.10.9 + blue3 = blue3 * brout; // (result is better) + } + +/* ------------------------------------------------------------------------ + + color saturation curve values: + 0 = no color saturation (gray scale) + 0.5 = normal (initial unmodified RGB) + 1.0 = max. color saturation + + 0.5 >> 0: move all RGB values to their mean: (R+G+B)/3 + 0.5 >> 1.0: increase RGB spread to 2x original level +*/ + + if (tune_spc_moved[2]) // curve has been edited + { + kk = 1000 * xval; // speedup v.11.06 + if (kk > 999) kk = 999; + brout = sd->yval[2][kk]; // saturation factor, 0 - 1 + brout = 2.0 * brout - 1.0; // -1.0 .. +1.0 + brmean = 0.333 * (red3 + green3 + blue3); + red3 = red3 + brout * (red3 - brmean); // simplified v.10.9 + green3 = green3 + brout * (green3 - brmean); + blue3 = blue3 + brout * (blue3 - brmean); + if (red3 < 0) red3 = 0; + if (green3 < 0) green3 = 0; + if (blue3 < 0) blue3 = 0; + } + +/* ------------------------------------------------------------------------ + + color balance curve values: + 0 = 0.5 * original color + 0.5 = unmodified + 1.0 = 1.5 * original color, clipped +*/ + + if (tune_spc_moved[3]) { // curve has been edited + kk = 1000 * xval; // speedup v.11.06 + if (kk > 999) kk = 999; + brout = sd->yval[3][kk]; // 0 to 1.0 + brout = 4 * brout - 2; // F-stops, -2 to +2 v.11.07 + brout = tune_pow[int(1000*brout+5000.5)]; // 0.25 to 4.0 + red3 = red3 * brout; + } + + if (tune_spc_moved[4]) { + kk = 1000 * xval; + if (kk > 999) kk = 999; + brout = sd->yval[4][kk]; + brout = 4 * brout - 2; + brout = tune_pow[int(1000*brout+5000.5)]; + green3 = green3 * brout; + } + + if (tune_spc_moved[5]) { + kk = 1000 * xval; + if (kk > 999) kk = 999; + brout = sd->yval[5][kk]; + brout = 4 * brout - 2; + brout = tune_pow[int(1000*brout+5000.5)]; + blue3 = blue3 * brout; + } + +// if working within a select area, blend changes over distance from edge + + double dold, dnew; + + if (Factivearea && dist < sa_blend) { + dnew = 1.0 * dist / sa_blend; + dold = 1.0 - dnew; + red3 = dnew * red3 + dold * red1; + green3 = dnew * green3 + dold * green1; + blue3 = dnew * blue3 + dold * blue1; + } + +// prevent overflow and set output RGB values + + double cmax; + + cmax = red3; // detect overflow v.11.07 + if (green3 > cmax) cmax = green3; + if (blue3 > cmax) cmax = blue3; + + if (cmax > 65535) { // stop overflow + red3 = red3 * 65535 / cmax; + green3 = green3 * 65535 / cmax; + blue3 = blue3 * 65535 / cmax; + } + + pix3[0] = int(red3); + pix3[1] = int(green3); + pix3[2] = int(blue3); + + return; +} + + +/**************************************************************************/ + +// adjust image gamma using classic gamma curve + +editfunc EFgamma; +int gamma_spc; // current spline curve + +void m_gamma(GtkWidget *, cchar *) // new v.11.10 +{ + int gamma_dialog_event(zdialog* zd, cchar *event); + void gamma_curvedit(int spc); + void * gamma_thread(void *); + + zfuncs::F1_help_topic = "gamma_curve"; + + EFgamma.funcname = "gamma"; + EFgamma.Fprev = 1; // use preview + EFgamma.Farea = 2; // select area usable + EFgamma.Fpara = 1; // parallel edit OK + EFgamma.threadfunc = gamma_thread; + if (! edit_setup(EFgamma)) return; // setup edit + +/*** + _________________________________________ + | | // 5 curves are maintained: + | | // curve 0: current display curve + | | // 1: curve for all colors + | | // 2,3,4: red, green, blue + | curve edit area | + | | + | | + | | + |_________________________________________| + + (o) all (o) red (o) green (o) blue // colors: all, red, green, blue + Curve File: [Open] [Save] [histogram] + [Done] [Cancel] +***/ + + zdialog *zd = zdialog_new(ZTX("adjust image gamma"),mWin,Bdone,Bcancel,null); + EFgamma.zd = zd; + + zdialog_add_widget(zd,"frame","frame","dialog",0,"expand"); + zdialog_add_widget(zd,"hbox","hbrgb","dialog",0,"space=3"); + zdialog_add_widget(zd,"radio","all","hbrgb",Ball,"space=5"); + zdialog_add_widget(zd,"radio","red","hbrgb",Bred,"space=5"); + zdialog_add_widget(zd,"radio","green","hbrgb",Bgreen,"space=5"); + zdialog_add_widget(zd,"radio","blue","hbrgb",Bblue,"space=5"); + zdialog_add_widget(zd,"hbox","hbcf","dialog",0,"space=3"); + zdialog_add_widget(zd,"label","labcf","hbcf",Bcurvefile,"space=5"); + zdialog_add_widget(zd,"button","load","hbcf",Bopen); + zdialog_add_widget(zd,"button","save","hbcf",Bsave,"space=3"); + zdialog_add_widget(zd,"button","hist","hbcf",Bhistogram,"space=15"); + + + GtkWidget *frame = zdialog_widget(zd,"frame"); + spldat *sd = splcurve_init(frame,gamma_curvedit); + EFgamma.curves = sd; + + sd->Nscale = 1; // diagonal fixed line for neutral curve + sd->xscale[0][0] = 0.00; + sd->yscale[0][0] = 0.00; + sd->xscale[1][0] = 1.00; + sd->yscale[1][0] = 1.00; + + for (int ii = 0; ii < 5; ii++) // loop curves 0-4 + { + sd->nap[ii] = 3; // initial curves are flat + sd->vert[ii] = 0; + sd->apx[ii][0] = sd->apy[ii][0] = 0.01; + sd->apx[ii][1] = sd->apy[ii][1] = 0.50; + sd->apx[ii][2] = sd->apy[ii][2] = 0.99; + splcurve_generate(sd,ii); + } + + sd->Nspc = 1; // only curve 0 is shown + gamma_spc = 1; // current active curve: 1 (all) + + zdialog_stuff(zd,"all",1); // stuff default selection, all + + zdialog_resize(zd,260,300); + zdialog_help(zd,"gamma_curve"); // zdialog help topic + zdialog_run(zd,gamma_dialog_event,"save"); // run dialog - parallel + + return; +} + + +// dialog event and completion callback function + +int gamma_dialog_event(zdialog *zd, cchar *event) +{ + spldat *sd = EFgamma.curves; + int ii, jj, nn, Fupdate = 0; + spldat sdtemp; + + if (zd->zstat) // dialog complete + { + if (zd->zstat == 1) edit_done(EFgamma); + else edit_cancel(EFgamma); + return 1; + } + + edit_takeover(EFgamma); // set my edit function + + if (strEqu(event,"blendwidth")) signal_thread(); // adjust area edge blending + + if (strEqu(event,"hist")) m_histogram(0,0); // show brightness distribution + + if (strstr("all red green blue",event)) { // new choice of curve + zdialog_fetch(zd,event,ii); + if (! ii) return 0; // ignore button OFF events + + ii = strcmpv(event,"all","red","green","blue",null); + gamma_spc = ii; // 1, 2, 3, 4 + + sd->nap[0] = sd->nap[ii]; // copy active curve ii to curve 0 + for (jj = 0; jj < sd->nap[0]; jj++) { + sd->apx[0][jj] = sd->apx[ii][jj]; + sd->apy[0][jj] = sd->apy[ii][jj]; + } + + Fupdate++; + } + + if (strEqu(event,"load")) // load 4 saved curves from file + { + sdtemp.Nspc = 4; + sdtemp.drawarea = 0; + nn = splcurve_load(&sdtemp); + if (nn != 1) return 0; + + for (ii = 0; ii < 4; ii++) { // load curves 0-3 to curves 1-4 + sd->vert[ii+1] = sdtemp.vert[ii]; + sd->nap[ii+1] = sdtemp.nap[ii]; + for (jj = 0; jj < sdtemp.nap[ii]; jj++) { + sd->apx[ii+1][jj] = sdtemp.apx[ii][jj]; + sd->apy[ii+1][jj] = sdtemp.apy[ii][jj]; + } + splcurve_generate(sd,ii+1); + } + + ii = gamma_spc; // current active curve, 1-4 + + sd->nap[0] = sd->nap[ii]; // copy active curve to curve 0 + for (jj = 0; jj < sd->nap[0]; jj++) { + sd->apx[0][jj] = sd->apx[ii][jj]; + sd->apy[0][jj] = sd->apy[ii][jj]; + } + + Fupdate++; + } + + if (strEqu(event,"save")) // save 4 curves to a file + { + sdtemp.Nspc = 4; + for (ii = 0; ii < 4; ii++) { + sdtemp.vert[ii] = sd->vert[ii+1]; + sdtemp.nap[ii] = sd->nap[ii+1]; + for (jj = 0; jj < sd->nap[ii+1]; jj++) { + sdtemp.apx[ii][jj] = sd->apx[ii+1][jj]; + sdtemp.apy[ii][jj] = sd->apy[ii+1][jj]; + } + } + + splcurve_save(&sdtemp); + } + + if (Fupdate) // curve has changed + { + splcurve_generate(sd,0); // regenerate curve 0 + + ii = gamma_spc; // active curve 1-4 + + sd->nap[ii] = sd->nap[0]; // copy curve 0 to active curve + for (jj = 0; jj < sd->nap[0]; jj++) { + sd->apx[ii][jj] = sd->apx[0][jj]; + sd->apy[ii][jj] = sd->apy[0][jj]; + } + + for (jj = 0; jj < 1000; jj++) + sd->yval[ii][jj] = sd->yval[0][jj]; + + splcurve_draw(0,0,sd); // draw curve + + signal_thread(); // trigger image update + } + + return 1; +} + + +// this function is called when a curve is edited + +void gamma_curvedit(int spc) +{ + int ii = gamma_spc, jj; + spldat *sd = EFgamma.curves; // active curve, 1-4 + + edit_takeover(EFgamma); // set my edit function + + sd->nap[ii] = sd->nap[0]; // copy curve 0 to active curve + for (jj = 0; jj < sd->nap[0]; jj++) { + sd->apx[ii][jj] = sd->apx[0][jj]; + sd->apy[ii][jj] = sd->apy[0][jj]; + } + + for (jj = 0; jj < 1000; jj++) + sd->yval[ii][jj] = sd->yval[0][jj]; + + if (gamma_spc == 1) { // "all" curve (1) was edited + for (ii = 2; ii < 5; ii++) { // fix R/G/B curves (2-4) to match + sd->nap[ii] = sd->nap[1]; + for (jj = 0; jj < sd->nap[1]; jj++) { + sd->apx[ii][jj] = sd->apx[1][jj]; + sd->apy[ii][jj] = sd->apy[1][jj]; + } + + for (jj = 0; jj < 1000; jj++) + sd->yval[ii][jj] = sd->yval[1][jj]; + } + } + + signal_thread(); + return; +} + + +// gamma thread function + +void * gamma_thread(void *arg) +{ + void * gamma_wthread(void *); + + while (true) + { + thread_idle_loop(); // wait for work or exit request + + for (int ii = 0; ii < Nwt; ii++) // start worker threads + start_wthread(gamma_wthread,&wtnx[ii]); + wait_wthreads(); // wait for completion + + mwpaint2(); // update window + CEF->Fmod = 1; // image3 modified + } + + return 0; // not executed, stop g++ warning +} + + +void * gamma_wthread(void *arg) // worker thread function +{ + int index = *((int *) arg); + int ii, dist = 0, px3, py3; + uint16 *pix1, *pix3; + double red1, green1, blue1, maxrgb; + double red3, green3, blue3; + double coeff = 1000.0 / 65536.0; + double dold, dnew; + spldat *sd = EFgamma.curves; + + for (py3 = index; py3 < E3hh; py3 += Nwt) // loop output pixels + for (px3 = 0; px3 < E3ww; px3++) + { + if (Factivearea) { // select area active + ii = py3 * E3ww + px3; + dist = sa_pixmap[ii]; // distance from edge + if (! dist) continue; // pixel outside area + } + + pix1 = PXMpix(E1pxm16,px3,py3); // input pixel + pix3 = PXMpix(E3pxm16,px3,py3); // output pixel + + red1 = pix1[0]; // input RGB brightness, 0-65535 + green1 = pix1[1]; + blue1 = pix1[2]; + + ii = coeff * red1; // range 0-999 for gamma curve index + red3 = 65535.0 * sd->yval[2][ii]; // output RGB brightness, 0-65535 + ii = coeff * green1; + green3 = 65535.0 * sd->yval[3][ii]; + ii = coeff * blue1; + blue3 = 65535.0 * sd->yval[4][ii]; + + maxrgb = red3; + if (green3 > maxrgb) maxrgb = green3; + if (blue3 > maxrgb) maxrgb = blue3; + + if (maxrgb > 65535) { // stop overflow + red3 = red3 * 65535 / maxrgb; + green3 = green3 * 65535 / maxrgb; + blue3 = blue3 * 65535 / maxrgb; + } + + if (Factivearea && dist < sa_blend) { // blend changes over blendwidth + dnew = 1.0 * dist / sa_blend; + dold = 1.0 - dnew; + red3 = dnew * red3 + dold * red1; + green3 = dnew * green3 + dold * green1; + blue3 = dnew * blue3 + dold * blue1; + } + + pix3[0] = red3; + pix3[1] = green3; + pix3[2] = blue3; + } + + exit_wthread(); + return 0; // not executed, avoid gcc warning +} + + +/**************************************************************************/ + +// Clip pixels outside the given low/high range and expand the remaining +// brightness range back to the full range of 0 to 65535. + +double xbrangeD, xbrangeB; +editfunc EFxbrange; + +void m_xbrange(GtkWidget *, cchar *) // new v.10.1 +{ + int xbrange_dialog_event(zdialog *zd, cchar *event); + void * xbrange_thread(void *); + + cchar *title = ZTX("Expand Brightness Range"); + cchar *labD = ZTX("dark pixels"); + cchar *labB = ZTX("bright pixels"); + + zfuncs::F1_help_topic = "expand_brightness"; // v.10.8 + + EFxbrange.funcname = "bright-range"; + EFxbrange.Fprev = 1; // use preview + EFxbrange.Farea = 2; // select area usable + EFxbrange.Fpara = 1; // parallel edit OK + EFxbrange.threadfunc = xbrange_thread; // thread function + if (! edit_setup(EFxbrange)) return; // setup edit + + zdialog *zd = zdialog_new(title,mWin,Bdone,Bcancel,null); // revised v.11.01 + EFxbrange.zd = zd; + + zdialog_add_widget(zd,"hbox","hb1","dialog",0,"expand"); + zdialog_add_widget(zd,"vbox","vb1","hb1",0,"homog|space=5"); + zdialog_add_widget(zd,"vbox","vb2","hb1",0,"homog|expand"); + zdialog_add_widget(zd,"vbox","vb3","hb1",0,"homog|space=8"); + zdialog_add_widget(zd,"label","labD","vb1",labD); + zdialog_add_widget(zd,"label","labB","vb1",labB); + zdialog_add_widget(zd,"hscale","clipD","vb2","0|99|0.5|0"); + zdialog_add_widget(zd,"hscale","clipB","vb2","0|99|0.5|0"); + zdialog_add_widget(zd,"label","darkval","vb3"); + zdialog_add_widget(zd,"label","briteval","vb3"); + + zdialog_resize(zd,300,0); + zdialog_help(zd,"expand_brightness"); // zdialog help topic v.11.08 + zdialog_run(zd,xbrange_dialog_event,"save"); // run dialog - parallel v.11.07 + + m_histogram(0,0); // show brightness distribution v.11.02 + + xbrangeD = xbrangeB = 0; // initial clip = 0 + return; +} + + +// dialog event and completion callback function + +int xbrange_dialog_event(zdialog *zd, cchar *event) +{ + char text[8]; + + if (zd->zstat) // dialog complete + { + if (zd->zstat == 1) edit_done(EFxbrange); + else edit_cancel(EFxbrange); + histogram_destroy(); // v.11.02 + return 1; + } + + edit_takeover(EFxbrange); // set my edit function + + if (strEqu(event,"reset")) { // reset dialog controls v.11.08 + zdialog_stuff(zd,"clipD",0); + zdialog_stuff(zd,"clipB",0); + } + + if (strEqu(event,"blendwidth")) signal_thread(); // v.10.3 + + if (strEqu(event,"clipD")) { + zdialog_fetch(zd,"clipD",xbrangeD); + signal_thread(); + } + + if (strEqu(event,"clipB")) { + zdialog_fetch(zd,"clipB",xbrangeB); + signal_thread(); + } + + sprintf(text,"%.0f",xbrangeD); // numeric feedback v.11.07 + zdialog_stuff(zd,"darkval",text); + sprintf(text,"%.0f",xbrangeB); + zdialog_stuff(zd,"briteval",text); + + return 0; +} + + +// thread function + +void * xbrange_thread(void *) +{ + int ii, px, py, dist = 0; + double dark, bright, b1, b3, bf, f1, f2; + double red1, green1, blue1, red3, green3, blue3; + uint16 *pix1, *pix3; + + while (true) + { + thread_idle_loop(); // wait for work or exit request + + dark = 0.01 * xbrangeD * 65536; // clipping brightness levels + bright = (1.0 - 0.01 * xbrangeB) * 65536; + + for (py = 0; py < E3hh; py++) // loop all image pixels + for (px = 0; px < E3ww; px++) + { + ii = py * E3ww + px; + + if (Factivearea) { // select area active bugfix v.9.9 + dist = sa_pixmap[ii]; // distance from edge + if (! dist) continue; // pixel is outside area + } + + pix1 = PXMpix(E1pxm16,px,py); // input pixel + pix3 = PXMpix(E3pxm16,px,py); // output pixel + + b1 = pixbright(pix1); + + if (b1 < dark) // clip dark pixels + b3 = 0; + else if (b1 > bright) // clip bright pixels + b3 = bright; + else b3 = b1; + + if (b3 > dark) b3 = b3 - dark; // expand the rest + b3 = b3 * (65535.0 / (bright - dark)); + + bf = b3 / (b1 + 1); // brightness ratio + + red1 = pix1[0]; // input RGB v.11.08 + green1 = pix1[1]; + blue1 = pix1[2]; + + red3 = bf * red1; // output RGB + green3 = bf * green1; + blue3 = bf * blue1; + + if (red3 > 65535) red3 = 65535; + if (green3 > 65535) green3 = 65535; + if (blue3 > 65535) blue3 = 65535; + + if (Factivearea && dist < sa_blend) { // select area is active, + f1 = 1.0 * dist / sa_blend; // blend changes over sa_blend + f2 = 1.0 - f1; + red3 = f1 * red3 + f2 * red1; + green3 = f1 * green3 + f2 * green1; + blue3 = f1 * blue3 + f2 * blue1; + } + + pix3[0] = red3; + pix3[1] = green3; + pix3[2] = blue3; + } + + CEF->Fmod = 1; + mwpaint2(); + } + + return 0; // not executed, stop g++ warning +} + + +/**************************************************************************/ + +// flatten brightness distribution + +double flatten_value = 0; // flatten value, 0 - 100% +double flatten_brdist[65536]; + +void flatten_update_image(); +void flatten_distribution(); // compute brightness distribution +void flatten_pixel(int px, int py); // compute new pixel brightness + +editfunc EFflatten; + +void m_flatten(GtkWidget *, cchar *) +{ + int flatten_dialog_event(zdialog* zd, cchar *event); + void * flatten_thread(void *); + + cchar *title = ZTX("Flatten Brightness Distribution"); + zfuncs::F1_help_topic = "flatten"; + + EFflatten.funcname = "flatten"; + EFflatten.Fprev = 1; // preview + EFflatten.Farea = 2; // select area usable + EFflatten.Fpara = 1; // parallel edit OK + EFflatten.threadfunc = flatten_thread; + if (! edit_setup(EFflatten)) return; // setup edit + + zdialog *zd = zdialog_new(title,mWin,Bdone,Bcancel,null); + EFflatten.zd = zd; + + zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=15"); + zdialog_add_widget(zd,"label","labfd","hb1",ZTX("Flatten"),"space=5"); + zdialog_add_widget(zd,"hscale","flatten","hb1","0|100|1|0","expand"); + zdialog_add_widget(zd,"label","value","hb1",0,"space=5"); + + zdialog_help(zd,"flatten"); // v.11.08 + zdialog_resize(zd,300,0); + zdialog_run(zd,flatten_dialog_event,"save"); // run dialog - parallel v.11.07 + + flatten_value = 0; + return; +} + + +// dialog event and completion callback function + +int flatten_dialog_event(zdialog *zd, cchar *event) // flatten dialog event function +{ + char text[8]; + + if (zd->zstat) + { + if (zd->zstat == 1) edit_done(EFflatten); // done + else edit_cancel(EFflatten); // cancel or destroy + return 0; + } + + edit_takeover(EFflatten); // set my edit function + + if (strEqu(event,"blendwidth")) flatten_update_image(); // v.11.06 + + if (strEqu(event,"flatten")) { + zdialog_fetch(zd,"flatten",flatten_value); // get slider value + sprintf(text,"%.0f",flatten_value); // numeric feedback v.11.07 + zdialog_stuff(zd,"value",text); + flatten_update_image(); // trigger update thread + } + + return 1; +} + + +// Update image based on select area and dialog controls + +void flatten_update_image() // v.11.06 +{ + int px, py, ww, hh; + + if (Factivearea && sa_Npixel < 200000) // if relatively small area, + { // process in main() thread v.11.06 + flatten_distribution(); + + for (py = sa_miny; py < sa_maxy; py++) + for (px = sa_minx; px < sa_maxx; px++) + flatten_pixel(px,py); + + px = sa_minx; // direct window update + py = sa_miny; + ww = sa_maxx - sa_minx; + hh = sa_maxy - sa_miny; + mwpaint3(px,py,ww,hh); // speedup v.11.06 + CEF->Fmod = 1; + } + + else signal_thread(); // use thread process + return; +} + + +// thread function - use multiple working threads + +void * flatten_thread(void *) +{ + void * flatten_wthread(void *arg); + + while (true) + { + thread_idle_loop(); // wait for work or exit request + + flatten_distribution(); + + for (int ii = 0; ii < Nwt; ii++) // start worker threads + start_wthread(flatten_wthread,&wtnx[ii]); + wait_wthreads(); // wait for completion + + CEF->Fmod = 1; + mwpaint2(); // update window + } + + return 0; // not executed, stop g++ warning +} + + +void * flatten_wthread(void *arg) // worker thread function +{ + int index = *((int *) (arg)); + int px, py; + + for (py = index; py < E1hh; py += Nwt) // flatten brightness distribution + for (px = 0; px < E1ww; px++) + flatten_pixel(px,py); + + exit_wthread(); + return 0; // not executed, avoid gcc warning +} + + +// compute brightness distribution for image or selected area + +void flatten_distribution() +{ + int px, py, ii, npix; + int ww = E1ww, hh = E1hh; + double bright1; + uint16 *pix1; + + for (ii = 0; ii < 65536; ii++) // clear brightness distribution data + flatten_brdist[ii] = 0; + + if (Factivearea) // process selected area + { + for (ii = npix = 0; ii < ww * hh; ii++) + { + if (! sa_pixmap[ii]) continue; + py = ii / ww; + px = ii - py * ww; + pix1 = PXMpix(E1pxm16,px,py); + bright1 = pixbright(pix1); + flatten_brdist[int(bright1)]++; + npix++; + } + + for (ii = 1; ii < 65536; ii++) // cumulative brightness distribution + flatten_brdist[ii] += flatten_brdist[ii-1]; // 0 ... npix + + for (ii = 0; ii < 65536; ii++) + flatten_brdist[ii] = flatten_brdist[ii] // multiplier per brightness level + / npix * 65536.0 / (ii + 1); + } + + else // process whole image + { + for (py = 0; py < hh; py++) // compute brightness distribution + for (px = 0; px < ww; px++) + { + pix1 = PXMpix(E1pxm16,px,py); + bright1 = pixbright(pix1); + flatten_brdist[int(bright1)]++; + } + + for (ii = 1; ii < 65536; ii++) // cumulative brightness distribution + flatten_brdist[ii] += flatten_brdist[ii-1]; // 0 ... (ww * hh) + + for (ii = 0; ii < 65536; ii++) + flatten_brdist[ii] = flatten_brdist[ii] // multiplier per brightness level + / (ww * hh) * 65536.0 / (ii + 1); + } + + return; +} + + +// compute new brightness for one pixel + +void flatten_pixel(int px, int py) +{ + int ii, dist = 0; + uint16 *pix1, *pix3; + double fold, fnew, dold, dnew, cmax; + double red1, green1, blue1, red3, green3, blue3; + double bright1, bright2; + + if (Factivearea) { // select area active + ii = py * Fww + px; + dist = sa_pixmap[ii]; // distance from edge + if (! dist) return; // outside pixel + } + + pix1 = PXMpix(E1pxm16,px,py); // input pixel + pix3 = PXMpix(E3pxm16,px,py); // output pixel + + fnew = 0.01 * flatten_value; // 0.0 - 1.0 how much to flatten + fold = 1.0 - fnew; // 1.0 - 0.0 how much to retain + + red1 = pix1[0]; + green1 = pix1[1]; + blue1 = pix1[2]; + + bright1 = 0.25 * red1 + 0.65 * green1 + 0.10 * blue1; // input brightness + bright2 = flatten_brdist[int(bright1)]; // output brightness adjustment + + red3 = bright2 * red1; // flattened brightness + green3 = bright2 * green1; + blue3 = bright2 * blue1; + + red3 = fnew * red3 + fold * red1; // blend new and old brightness + green3 = fnew * green3 + fold * green1; + blue3 = fnew * blue3 + fold * blue1; + + if (Factivearea && dist < sa_blend) { // select area is active, + dnew = 1.0 * dist / sa_blend; // blend changes over sa_blend + dold = 1.0 - dnew; + red3 = dnew * red3 + dold * red1; + green3 = dnew * green3 + dold * green1; + blue3 = dnew * blue3 + dold * blue1; + } + + cmax = red3; // stop overflow, keep color balance + if (green3 > cmax) cmax = green3; + if (blue3 > cmax) cmax = blue3; + if (cmax > 65535) { + cmax = 65535 / cmax; + red3 = red3 * cmax; + green3 = green3 * cmax; + blue3 = blue3 * cmax; + } + + pix3[0] = red3; + pix3[1] = green3; + pix3[2] = blue3; + + return; +} + + +/**************************************************************************/ + +// ramp brightness across image, vertical and horizontal gradients + +editfunc EFbrramp; +int brramp_spc; // current spline curves (2 at a time) + +void m_brightramp(GtkWidget *, cchar *) // upgrade for 4 colors v.11.07 +{ + int brramp_dialog_event(zdialog* zd, cchar *event); + void brramp_curvedit(int spc); + void * brramp_thread(void *); + void brramp_init(); + + zfuncs::F1_help_topic = "brightness_ramp"; + + EFbrramp.funcname = "bright-ramp"; + EFbrramp.Fprev = 1; // use preview + EFbrramp.Farea = 2; // select area usable + EFbrramp.Fpara = 1; // parallel edit OK + EFbrramp.threadfunc = brramp_thread; + if (! edit_setup(EFbrramp)) return; // setup edit + +/*** + _________________________________________ + | | + | | + | curve edit area | + | | + | | + |_________________________________________| + + (o) all (o) red (o) green (o) blue // colors: all, red, green, blue + Curve File: [Open] [Save] // each has vert. and horiz. curve + [Done] [Cancel] + +***/ + + zdialog *zd = zdialog_new(ZTX("Ramp brightness across image"),mWin,Bdone,Bcancel,null); + EFbrramp.zd = zd; + + zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=5|expand"); + zdialog_add_widget(zd,"vbox","vb1","hb1"); + zdialog_add_widget(zd,"vbox","vb2","hb1",0,"expand"); + zdialog_add_widget(zd,"label","lmax","vb1","+","space=3"); + zdialog_add_widget(zd,"label","lspace","vb1",0,"expand"); + zdialog_add_widget(zd,"label","lmin","vb1","‒","space=3"); + zdialog_add_widget(zd,"label","lspace","vb1"); + zdialog_add_widget(zd,"frame","frame","vb2",0,"expand"); + + zdialog_add_widget(zd,"hbox","hb2","vb2"); + zdialog_add_widget(zd,"label","lmin","hb2","‒","space=3"); + zdialog_add_widget(zd,"label","lspace","hb2",0,"expand"); + zdialog_add_widget(zd,"label","lmax","hb2","+","space=3"); + zdialog_add_widget(zd,"hbox","hbrgb","dialog",0,"space=3"); + zdialog_add_widget(zd,"radio","all","hbrgb",Ball,"space=5"); + zdialog_add_widget(zd,"radio","red","hbrgb",Bred,"space=5"); + zdialog_add_widget(zd,"radio","green","hbrgb",Bgreen,"space=5"); + zdialog_add_widget(zd,"radio","blue","hbrgb",Bblue,"space=5"); + zdialog_add_widget(zd,"hbox","hbcf","dialog",0,"space=3"); + zdialog_add_widget(zd,"label","labcf","hbcf",Bcurvefile,"space=8"); + zdialog_add_widget(zd,"button","load","hbcf",Bopen,"space=5"); + zdialog_add_widget(zd,"button","save","hbcf",Bsave,"space=5"); + + GtkWidget *frame = zdialog_widget(zd,"frame"); + spldat *sd = splcurve_init(frame,brramp_curvedit); // v.11.01 + EFbrramp.curves = sd; + + brramp_init(); // set up initial flat curves + + sd->Nspc = 2; // only curves 0-1 are shown + brramp_spc = 2; // current curves: all (2-3) + + zdialog_stuff(zd,"all",1); // stuff default selection, all + + zdialog_resize(zd,260,350); + zdialog_help(zd,"brightness_ramp"); // zdialog help topic v.11.08 + zdialog_run(zd,brramp_dialog_event,"save"); // run dialog - parallel v.11.07 + return; +} + + +// initialize all curves to flat + +void brramp_init() +{ + spldat *sd = EFbrramp.curves; + + for (int ii = 0; ii < 10; ii++) // loop curves: current (0-1), all (2-3), + { // red (4-5), green (6-7), blue (8-9) + sd->nap[ii] = 2; // horizontal curve ii + sd->vert[ii] = 0; + sd->apx[ii][0] = 0.01; + sd->apx[ii][1] = 0.99; + sd->apy[ii][0] = sd->apy[ii][1] = 0.5; + splcurve_generate(sd,ii); + + ii++; + sd->nap[ii] = 2; // vertical curve ii+1 + sd->vert[ii] = 1; + sd->apx[ii][0] = 0.01; + sd->apx[ii][1] = 0.99; + sd->apy[ii][0] = sd->apy[ii][1] = 0.5; + splcurve_generate(sd,ii); + } + + return; +} + + +// dialog event and completion callback function + +int brramp_dialog_event(zdialog *zd, cchar *event) +{ + spldat *sd = EFbrramp.curves; + int ii, jj, nn, Fupdate = 0; + spldat sdtemp; + + if (zd->zstat) // dialog complete + { + if (zd->zstat == 1) edit_done(EFbrramp); + else edit_cancel(EFbrramp); + return 1; + } + + edit_takeover(EFbrramp); // set my edit function + + if (strEqu(event,"reset")) { // reset dialog controls v.11.08 + brramp_init(); + Fupdate++; + } + + if (strEqu(event,"blendwidth")) signal_thread(); + + if (strstr("all red green blue",event)) { // new choice of curve + zdialog_fetch(zd,event,ii); + if (! ii) return 0; // ignore button OFF events + + ii = strcmpv(event,"all","red","green","blue",null); + brramp_spc = ii = 2 * ii; // 2, 4, 6, 8 + + sd->nap[0] = sd->nap[ii]; // copy active curves ii/ii+1 to curves 0/1 + sd->nap[1] = sd->nap[ii+1]; + for (jj = 0; jj < sd->nap[0]; jj++) { + sd->apx[0][jj] = sd->apx[ii][jj]; + sd->apy[0][jj] = sd->apy[ii][jj]; + } + for (jj = 0; jj < sd->nap[1]; jj++) { + sd->apx[1][jj] = sd->apx[ii+1][jj]; + sd->apy[1][jj] = sd->apy[ii+1][jj]; + } + + Fupdate++; + } + + if (strEqu(event,"load")) // load 8 saved curves from file + { + sdtemp.Nspc = 8; + sdtemp.drawarea = 0; + nn = splcurve_load(&sdtemp); + if (nn != 1) return 0; + + for (ii = 0; ii < 8; ii++) { // load curves 0-7 to curves 2-9 + sd->vert[ii+2] = sdtemp.vert[ii]; + sd->nap[ii+2] = sdtemp.nap[ii]; + for (jj = 0; jj < sdtemp.nap[ii]; jj++) { + sd->apx[ii+2][jj] = sdtemp.apx[ii][jj]; + sd->apy[ii+2][jj] = sdtemp.apy[ii][jj]; + } + splcurve_generate(sd,ii+2); + } + + ii = brramp_spc; // current active curves: 2, 4, 6, 8 + + sd->nap[0] = sd->nap[ii]; // copy 2 active curves to curves 0-1 + for (jj = 0; jj < sd->nap[0]; jj++) { + sd->apx[0][jj] = sd->apx[ii][jj]; + sd->apy[0][jj] = sd->apy[ii][jj]; + } + + sd->nap[1] = sd->nap[ii+1]; + for (jj = 0; jj < sd->nap[1]; jj++) { + sd->apx[1][jj] = sd->apx[ii+1][jj]; + sd->apy[1][jj] = sd->apy[ii+1][jj]; + } + + Fupdate++; + } + + if (strEqu(event,"save")) // save 8 curves to file + { + sdtemp.Nspc = 8; + for (ii = 0; ii < 8; ii++) { + sdtemp.vert[ii] = sd->vert[ii+2]; + sdtemp.nap[ii] = sd->nap[ii+2]; + for (jj = 0; jj < sd->nap[ii+2]; jj++) { + sdtemp.apx[ii][jj] = sd->apx[ii+2][jj]; + sdtemp.apy[ii][jj] = sd->apy[ii+2][jj]; + } + } + + splcurve_save(&sdtemp); + } + + if (Fupdate) // curve has changed + { + splcurve_generate(sd,0); // regenerate curves 0-1 + splcurve_generate(sd,1); + + ii = brramp_spc; // active curves + + sd->nap[ii] = sd->nap[0]; // copy curves 0-1 to active curves + for (jj = 0; jj < sd->nap[0]; jj++) { + sd->apx[ii][jj] = sd->apx[0][jj]; + sd->apy[ii][jj] = sd->apy[0][jj]; + } + + sd->nap[ii+1] = sd->nap[1]; + for (jj = 0; jj < sd->nap[1]; jj++) { + sd->apx[ii+1][jj] = sd->apx[1][jj]; + sd->apy[ii+1][jj] = sd->apy[1][jj]; + } + + for (jj = 0; jj < 1000; jj++) + { + sd->yval[ii][jj] = sd->yval[0][jj]; + sd->yval[ii+1][jj] = sd->yval[1][jj]; + } + + splcurve_draw(0,0,sd); // draw curves + + signal_thread(); // trigger image update + } + + return 1; +} + + +// this function is called when a curve is edited + +void brramp_curvedit(int spc) +{ + int ii = brramp_spc, jj; + spldat *sd = EFbrramp.curves; // active curves: 2, 4, 6, 8 (and +1) + + edit_takeover(EFbrramp); // set my edit function + + sd->nap[ii] = sd->nap[0]; // copy curves 0-1 to active curves + for (jj = 0; jj < sd->nap[0]; jj++) { + sd->apx[ii][jj] = sd->apx[0][jj]; + sd->apy[ii][jj] = sd->apy[0][jj]; + } + + sd->nap[ii+1] = sd->nap[1]; + for (jj = 0; jj < sd->nap[1]; jj++) { + sd->apx[ii+1][jj] = sd->apx[1][jj]; + sd->apy[ii+1][jj] = sd->apy[1][jj]; + } + + for (jj = 0; jj < 1000; jj++) { + sd->yval[ii][jj] = sd->yval[0][jj]; + sd->yval[ii+1][jj] = sd->yval[1][jj]; + } + + if (brramp_spc == 2) { // "all" curve was edited + for (ii = 4; ii < 10; ii += 2) { // fix R/G/B curves to match + sd->nap[ii] = sd->nap[2]; + for (jj = 0; jj < sd->nap[2]; jj++) { + sd->apx[ii][jj] = sd->apx[2][jj]; + sd->apy[ii][jj] = sd->apy[2][jj]; + } + for (jj = 0; jj < 1000; jj++) + sd->yval[ii][jj] = sd->yval[2][jj]; + } + for (ii = 5; ii < 10; ii += 2) { + sd->nap[ii] = sd->nap[3]; + for (jj = 0; jj < sd->nap[3]; jj++) { + sd->apx[ii][jj] = sd->apx[3][jj]; + sd->apy[ii][jj] = sd->apy[3][jj]; + } + for (jj = 0; jj < 1000; jj++) + sd->yval[ii][jj] = sd->yval[3][jj]; + } + } + + signal_thread(); + return; +} + + +// brramp thread function + +void * brramp_thread(void *arg) +{ + void * brramp_wthread(void *); + + while (true) + { + thread_idle_loop(); // wait for work or exit request + + for (int ii = 0; ii < Nwt; ii++) // start worker threads + start_wthread(brramp_wthread,&wtnx[ii]); + wait_wthreads(); // wait for completion + + mwpaint2(); // update window + CEF->Fmod = 1; // image3 modified + } + + return 0; // not executed, stop g++ warning +} + + +void * brramp_wthread(void *arg) // worker thread function +{ + int index = *((int *) arg); + int ii, jj, kk, dist = 0, px3, py3; + uint16 *pix1, *pix3; + double red1, green1, blue1, maxrgb; + double red3, green3, blue3; + double dispx, dispy; + double hramp[3], vramp[3], tramp[3]; + double spanw, spanh, dold, dnew; + spldat *sd = EFbrramp.curves; + + if (Factivearea) { // if select area active, ramp + spanw = sa_maxx - sa_minx; // brightness over enclosing rectangle + spanh = sa_maxy - sa_miny; + } + else { + spanw = E3ww; // else over entire image + spanh = E3hh; + } + + for (py3 = index; py3 < E3hh; py3 += Nwt) // loop output pixels + for (px3 = 0; px3 < E3ww; px3++) + { + if (Factivearea) { // select area active v.10.1 + ii = py3 * E3ww + px3; + dist = sa_pixmap[ii]; // distance from edge + if (! dist) continue; // pixel outside area + dispx = (px3 - sa_minx) / spanw; + dispy = (py3 - sa_miny) / spanh; + } + else { + dispx = px3 / spanw; // left > right = 0 to 1 + dispy = py3 / spanh; // top > bottom = 0 to 1 + } + + kk = 1000 * dispx; // conv. dispx 0-1 to 0-1000 + if (kk > 999) kk = 999; + + for (ii = 0, jj = 4; ii < 3; ii++, jj+=2) // horz. curves for dispx and R/G/B + hramp[ii] = sd->yval[jj][kk] - 0.5; // scale to -0.5 to +0.5 + + kk = 1000 * dispy; // conv. dispy + if (kk > 999) kk = 999; + + for (ii = 0, jj = 5; ii < 3; ii++, jj+=2) // vert. curves + vramp[ii] = sd->yval[jj][kk] - 0.5; + + for (ii = 0; ii < 3; ii++) // total R/G/B change + tramp[ii] = 1.0 + hramp[ii] + vramp[ii]; // scale to 0.0 to 2.0 + + pix1 = PXMpix(E1pxm16,px3,py3); // input pixel + red1 = pix1[0]; + green1 = pix1[1]; + blue1 = pix1[2]; + + red3 = red1 * tramp[0]; // change R/G/B + green3 = green1 * tramp[1]; + blue3 = blue1 * tramp[2]; + + maxrgb = red3; + if (green3 > maxrgb) maxrgb = green3; + if (blue3 > maxrgb) maxrgb = blue3; + + if (maxrgb > 65535) { // stop overflow + red3 = red3 * 65535 / maxrgb; + green3 = green3 * 65535 / maxrgb; + blue3 = blue3 * 65535 / maxrgb; + } + + if (Factivearea && dist < sa_blend) { // blend changes over blendwidth v.10.1 + dnew = 1.0 * dist / sa_blend; + dold = 1.0 - dnew; + red3 = dnew * red3 + dold * red1; + green3 = dnew * green3 + dold * green1; + blue3 = dnew * blue3 + dold * blue1; + } + + pix3 = PXMpix(E3pxm16,px3,py3); // output pixel + pix3[0] = red3; + pix3[1] = green3; + pix3[2] = blue3; + } + + exit_wthread(); + return 0; // not executed, avoid gcc warning +} + + +/************************************************************************** + + Image Tone Mapping function + enhance local contrast as opposed to overall contrast + + methodology: + get brightness gradients for each pixel in 4 directions: SE SW NE NW + amplify gradients using the edit curve (x-axis range 0-max. gradient) + integrate 4 new brightness surfaces from the amplified gradients: + - pixel brightness = prior pixel brightness + amplified gradient + - the Amplify control varies amplification from zero to overamplified + new pixel brightness = average from 4 calculated brightness surfaces + +***************************************************************************/ + +float *Tmap_brmap1; +float *Tmap_brmap3[4]; +int Tmap_contrast99; +double Tmap_amplify; + +editfunc EFtonemap; + + +void m_tonemap(GtkWidget *, cchar *) // new v.9.8 +{ + int Tmap_dialog_event(zdialog *zd, cchar *event); + void Tmap_curvedit(int); + void * Tmap_thread(void *); + + zfuncs::F1_help_topic = "tone_mapping"; // v.10.8 + + int ii, cc, px, py; + uint16 *pix1; + cchar *title = ZTX("Tone Mapping"); + int jj, sum, limit, condist[100]; + + EFtonemap.funcname = "tonemap"; + EFtonemap.Farea = 2; // select area usable + EFtonemap.Fpara = 1; // parallel edit OK + EFtonemap.threadfunc = Tmap_thread; + if (! edit_setup(EFtonemap)) return; // setup: no preview, select area OK + +/*** + _____________________________ + | | + | | + | curve drawing area | + | | + |_____________________________| + low contrast high + + Amplify ========[]========= + + Curve File: [ Open ] [ Save ] +***/ + + zdialog *zd = zdialog_new(title,mWin,Bdone,Bcancel,null); + EFtonemap.zd = zd; + + zdialog_add_widget(zd,"frame","frame","dialog",0,"expand"); + zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=5"); + zdialog_add_widget(zd,"label","labcL","hb1",ZTX("low"),"space=4"); + zdialog_add_widget(zd,"label","labcM","hb1",ZTX("contrast"),"expand"); + zdialog_add_widget(zd,"label","labcH","hb1",ZTX("high"),"space=5"); + + zdialog_add_widget(zd,"hbox","hb2","dialog",0,"space=5"); + zdialog_add_widget(zd,"label","labcon","hb2",ZTX("Amplify"),"space=5"); + zdialog_add_widget(zd,"hscale","amplify","hb2","0|1|0.01|0","expand"); + zdialog_add_widget(zd,"label","ampval","hb2",0,"space=5"); + + zdialog_add_widget(zd,"hbox","hbcf","dialog",0,"space=8"); + zdialog_add_widget(zd,"label","labcf","hbcf",Bcurvefile,"space=5"); + zdialog_add_widget(zd,"button","load","hbcf",Bopen,"space=5"); + zdialog_add_widget(zd,"button","save","hbcf",Bsave,"space=5"); + + GtkWidget *frame = zdialog_widget(zd,"frame"); // set up curve edit + spldat *sd = splcurve_init(frame,Tmap_curvedit); // v.11.01 + EFtonemap.curves = sd; + + sd->Nspc = 1; + sd->vert[0] = 0; + sd->nap[0] = 3; // initial curve anchor points + sd->apx[0][0] = 0.01; + sd->apy[0][0] = 0.2; + sd->apx[0][1] = 0.50; + sd->apy[0][1] = 0.4; + sd->apx[0][2] = 0.99; + sd->apy[0][2] = 0.0; + + splcurve_generate(sd,0); // generate curve data + + cc = Fww * Fhh * sizeof(float); // allocate brightness map memory + Tmap_brmap1 = (float *) zmalloc(cc,"tonemap"); + for (ii = 0; ii < 4; ii++) + Tmap_brmap3[ii] = (float *) zmalloc(cc,"tonemap"); + + for (py = 0; py < Fhh; py++) // map initial image brightness + for (px = 0; px < Fww; px++) + { + ii = py * Fww + px; + pix1 = PXMpix(E1pxm16,px,py); + Tmap_brmap1[ii] = pixbright(pix1); + } + + for (ii = 0; ii < 100; ii++) + condist[ii] = 0; + + for (py = 1; py < Fhh; py++) // map contrast distribution + for (px = 1; px < Fww; px++) + { + ii = py * Fww + px; + jj = 0.00152 * fabsf(Tmap_brmap1[ii] - Tmap_brmap1[ii-1]); // contrast, ranged 0 - 99 + condist[jj]++; + jj = 0.00152 * fabsf(Tmap_brmap1[ii] - Tmap_brmap1[ii-Fww]); + condist[jj]++; + } + + sum = 0; + limit = 0.99 * 2 * (Fww-1) * (Fhh-1); // find 99th percentile contrast + + for (ii = 0; ii < 100; ii++) { + sum += condist[ii]; + if (sum > limit) break; + } + + Tmap_contrast99 = 65535.0 * ii / 100.0; // 0 to 65535 + if (Tmap_contrast99 < 1000) Tmap_contrast99 = 1000; // rescale low-contrast image v.10.9 + + zdialog_resize(zd,300,300); + zdialog_help(zd,"tone_mapping"); // zdialog help topic v.11.08 + zdialog_run(zd,Tmap_dialog_event,"save"); // run dialog - parallel v.11.07 + + Tmap_amplify = 0; + return; +} + + +// dialog event and completion callback function + +int Tmap_dialog_event(zdialog *zd, cchar *event) +{ + spldat *sd = EFtonemap.curves; + char text[8]; + + if (zd->zstat) // dialog complete + { + if (zd->zstat == 1) edit_done(EFtonemap); + else edit_cancel(EFtonemap); + zfree(Tmap_brmap1); // free memory + for (int ii = 0; ii < 4; ii++) + zfree(Tmap_brmap3[ii]); + return 1; + } + + edit_takeover(EFtonemap); // set my edit function + + if (strEqu(event,"reset")) // reset dialog controls v.11.08 + zdialog_stuff(zd,"amplify",0); + + if (strEqu(event,"blendwidth")) signal_thread(); // v.10.3 + + if (strEqu(event,"amplify")) { // slider value + zdialog_fetch(zd,"amplify",Tmap_amplify); + sprintf(text,"%.2f",Tmap_amplify); // numeric feedback v.11.07 + zdialog_stuff(zd,"ampval",text); + signal_thread(); // trigger update thread + } + + if (strEqu(event,"load")) { // load saved curve v.11.02 + splcurve_load(sd); + signal_thread(); + return 0; + } + + if (strEqu(event,"save")) { // save curve to file v.11.02 + splcurve_save(sd); + return 0; + } + + return 0; +} + + +// this function is called when the curve is edited + +void Tmap_curvedit(int) +{ + edit_takeover(EFtonemap); // set my edit function + signal_thread(); + return; +} + + +// thread function + +void * Tmap_thread(void *) +{ + void * Tmap_wthread1(void *arg); + void * Tmap_wthread2(void *arg); + + int ii; + + while (true) + { + thread_idle_loop(); // wait for work or exit request + + for (ii = 0; ii < 4; ii++) // start working threads1 (must be 4) + start_wthread(Tmap_wthread1,&wtnx[ii]); + wait_wthreads(); // wait for completion + + for (ii = 0; ii < Nwt; ii++) // start working threads2 + start_wthread(Tmap_wthread2,&wtnx[ii]); + wait_wthreads(); // wait for completion + + CEF->Fmod = 1; + mwpaint2(); + } + + return 0; // not executed, stop g++ warning +} + + +// working threads + +void * Tmap_wthread1(void *arg) // hardened v.9.9 +{ + int ii, kk, bii, pii, dist = 0; + int px, px1, px2, pxinc; + int py, py1, py2, pyinc; + float b1, b3, xval, yval, grad; + float amplify, contrast99; + spldat *sd = EFtonemap.curves; + + contrast99 = Tmap_contrast99; // 99th percentile contrast + contrast99 = 1.0 / contrast99; // inverted + + amplify = pow(Tmap_amplify,0.2); // get amplification, 0 to 1 v.11.02 + + bii = *((int *) arg); + + if (bii == 0) { // direction SE + px1 = 1; px2 = E3ww; pxinc = 1; + py1 = 1; py2 = E3hh; pyinc = 1; + pii = - 1 - E3ww; + } + + else if (bii == 1) { // direction SW + px1 = E3ww-2; px2 = 0; pxinc = -1; + py1 = 1; py2 = E3hh; pyinc = 1; + pii = + 1 - E3ww; + } + + else if (bii == 2) { // direction NE + px1 = 1; px2 = E3ww; pxinc = 1; + py1 = E3hh-2; py2 = 0; pyinc = -1; + pii = - 1 + E3ww; + } + + else { /* bii == 3 */ // direction NW + px1 = E3ww-2; px2 = 0; pxinc = -1; + py1 = E3hh-2; py2 = 0; pyinc = -1; + pii = + 1 + E3ww; + } + + for (ii = 0; ii < E3ww * E3hh; ii++) // initial brightness map + Tmap_brmap3[bii][ii] = Tmap_brmap1[ii]; + + for (py = py1; py != py2; py += pyinc) // loop all image pixels + for (px = px1; px != px2; px += pxinc) + { + ii = py * E3ww + px; + + if (Factivearea) { // select area active + dist = sa_pixmap[ii]; // distance from edge + if (! dist) continue; // outside pixel + } + + b1 = Tmap_brmap1[ii]; // this pixel brightness + grad = b1 - Tmap_brmap1[ii+pii]; // - prior pixel --> gradient + + xval = fabsf(grad) * contrast99; // gradient scaled 0 to 1+ + kk = 1000.0 * xval; + if (kk > 999) kk = 999; // speedup v.11.06 + yval = 1.0 + 5.0 * sd->yval[0][kk]; + + grad = grad * yval; // magnified gradient + + b3 = Tmap_brmap3[bii][ii+pii] + grad; // pixel brightness = prior + gradient + b3 = (1.0 - amplify) * b1 + amplify * b3; // constrain: push b3 toward b1 v.11.02 + + if (b3 > 65535) b3 = 65535; // constrain + if (b3 < 10) b3 = 10; + + Tmap_brmap3[bii][ii] = b3; // new pixel brightness + } + + exit_wthread(); + return 0; // not executed, avoid gcc warning +} + + +void * Tmap_wthread2(void *arg) // speedup v.10.2 +{ + uint16 *pix1, *pix3; + int index, ii, px, py, dist = 0; + float b1, b3, bf, f1, f2; + float red1, green1, blue1, red3, green3, blue3; + + index = *((int *) arg); + + for (py = index; py < E3hh; py += Nwt) // loop all image pixels + for (px = 0; px < E3ww; px++) + { + ii = py * E3ww + px; + + if (Factivearea) { // select area active bugfix v.9.9 + dist = sa_pixmap[ii]; // distance from edge + if (! dist) continue; // pixel is outside area + } + + pix1 = PXMpix(E1pxm16,px,py); // input pixel + pix3 = PXMpix(E3pxm16,px,py); // output pixel + + b1 = Tmap_brmap1[ii]; // initial pixel brightness + b3 = Tmap_brmap3[0][ii] + Tmap_brmap3[1][ii] // new brightness = average of four + + Tmap_brmap3[2][ii] + Tmap_brmap3[3][ii]; // calculated brightness surfaces + + bf = 0.25 * b3 / (b1 + 1); // brightness ratio + + red1 = pix1[0]; // input RGB + green1 = pix1[1]; + blue1 = pix1[2]; + + red3 = bf * red1; // output RGB + if (red3 > 65535) red3 = 65535; + green3 = bf * green1; + if (green3 > 65535) green3 = 65535; + blue3 = bf * blue1; + if (blue3 > 65535) blue3 = 65535; + + if (Factivearea && dist < sa_blend) { // select area is active, + f1 = 1.0 * dist / sa_blend; // blend changes over sa_blend + f2 = 1.0 - f1; + red3 = f1 * red3 + f2 * red1; + green3 = f1 * green3 + f2 * green1; + blue3 = f1 * blue3 + f2 * blue1; + } + + pix3[0] = red3; + pix3[1] = green3; + pix3[2] = blue3; + } + + exit_wthread(); + return 0; // not executed, stop g++ warning +} + + +/**************************************************************************/ + +// adjust white balance + +void whitebal_mousefunc(); + +double whitebal_red, whitebal_green, whitebal_blue; +editfunc EFwhitebal; + +void m_whitebal(GtkWidget *, cchar *) +{ + int whitebal_dialog_event(zdialog *zd, cchar *event); + void * whitebal_thread(void *); + + cchar *wbtitle = ZTX("Adjust White Balance"); + cchar *wbhelp = ZTX("Click white or gray image location"); + + zfuncs::F1_help_topic = "white_balance"; // v.10.8 + + EFwhitebal.funcname = "white-balance"; + EFwhitebal.Fprev = 1; // use preview + EFwhitebal.Farea = 2; // select area usable + EFwhitebal.Fpara = 1; // parallel edits OK + EFwhitebal.threadfunc = whitebal_thread; // thread function + EFwhitebal.mousefunc = whitebal_mousefunc; // mouse function + if (! edit_setup(EFwhitebal)) return; // setup edit: preview + + zdialog *zd = zdialog_new(wbtitle,mWin,Bdone,Bcancel,null); + EFwhitebal.zd = zd; + + zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=10"); + zdialog_add_widget(zd,"label","labwbh","hb1",wbhelp,"space=5"); + zdialog_add_widget(zd,"hbox","hb2","dialog",0,"space=5"); + zdialog_add_widget(zd,"label","labpix","hb2","pixel:"); + zdialog_add_widget(zd,"label","pixel","hb2","0000 0000"); + zdialog_add_widget(zd,"label","labrgb","hb2"," RGB:"); + zdialog_add_widget(zd,"label","rgb","hb2","000 000 000"); + + zdialog_help(zd,"white_balance"); // zdialog help topic v.11.08 + zdialog_run(zd,whitebal_dialog_event,"save"); // run dialog - parallel v.11.07 + + whitebal_red = whitebal_green = whitebal_blue = 1.0; + + takeMouse(zd,whitebal_mousefunc,dragcursor); // connect mouse function v.11.03 + return; +} + + +// dialog event and completion callback function + +int whitebal_dialog_event(zdialog *zd, cchar *event) // dialog event function v.10.2 +{ + if (zd->zstat) + { + if (zd->zstat == 1) edit_done(EFwhitebal); // done + else edit_cancel(EFwhitebal); // cancel or destroy + return 0; + } + + edit_takeover(EFwhitebal); // set my edit function + + if (strEqu(event,"focus")) // toggle mouse capture v.12.01 + takeMouse(zd,whitebal_mousefunc,dragcursor); // connect mouse function + + if (strEqu(event,"blendwidth")) signal_thread(); // v.10.3 + return 1; +} + + +void whitebal_mousefunc() // mouse function +{ + int px, py, dx, dy; + double red, green, blue, rgbmean; + char work[40]; + uint16 *ppix16; + zdialog *zd = EFwhitebal.zd; + + if (! LMclick) return; + + edit_takeover(EFwhitebal); // set my edit function + + LMclick = 0; + px = Mxclick; // mouse click position + py = Myclick; + + if (px < 2) px = 2; // pull back from edge + if (px > E3ww-3) px = E3ww-3; + if (py < 2) py = 2; + if (py > E3hh-3) py = E3hh-3; + + red = green = blue = 0; + + for (dy = -2; dy <= 2; dy++) // 5x5 block around mouse position + for (dx = -2; dx <= 2; dx++) + { + ppix16 = PXMpix(E1pxm16,px+dx,py+dy); // input image + red += ppix16[0]; + green += ppix16[1]; + blue += ppix16[2]; + } + + red = red / 25.0; // mean RGB levels + green = green / 25.0; + blue = blue / 25.0; + rgbmean = (red + green + blue) / 3.0; + + whitebal_red = rgbmean / red; + whitebal_green = rgbmean / green; + whitebal_blue = rgbmean / blue; + + signal_thread(); // trigger image update + + snprintf(work,40,"%d %d",px,py); + zdialog_stuff(zd,"pixel",work); + + snprintf(work,40,"%7.3f %7.3f %7.3f",red/256,green/256,blue/256); + zdialog_stuff(zd,"rgb",work); + + return; +} + + +// Update image based on neutral pixel that was clicked + +void * whitebal_thread(void *) +{ + void * whitebal_wthread(void *arg); + + while (true) + { + thread_idle_loop(); // wait for work or exit request + + for (int ii = 0; ii < Nwt; ii++) // start worker threads + start_wthread(whitebal_wthread,&wtnx[ii]); + wait_wthreads(); // wait for completion + + CEF->Fmod = 1; + mwpaint2(); // update window + } + + return 0; // not executed, stop g++ warning +} + + +void * whitebal_wthread(void *arg) // worker thread function +{ + int index = *((int *) arg); + int px, py, ii, dist = 0; + uint16 *pix1, *pix3; + double red1, green1, blue1; + double red3, green3, blue3; + double brmax, dold, dnew; + + for (py = index; py < E1hh; py += Nwt) + for (px = 0; px < E1ww; px++) + { + if (Factivearea) { // select area active + ii = py * Fww + px; + dist = sa_pixmap[ii]; // distance from edge + if (! dist) continue; // pixel outside area + } + + pix1 = PXMpix(E1pxm16,px,py); // input pixel + pix3 = PXMpix(E3pxm16,px,py); // output pixel + + red1 = pix1[0]; + green1 = pix1[1]; + blue1 = pix1[2]; + + red3 = whitebal_red * red1; // change color ratios + green3 = whitebal_green * green1; + blue3 = whitebal_blue * blue1; + + if (Factivearea && dist < sa_blend) { // select area is active, + dnew = 1.0 * dist / sa_blend; // blend changes over sa_blend + dold = 1.0 - dnew; + red3 = dnew * red3 + dold * red1; + green3 = dnew * green3 + dold * green1; + blue3 = dnew * blue3 + dold * blue1; + } + + brmax = red3; // brmax = brightest color + if (green3 > brmax) brmax = green3; + if (blue3 > brmax) brmax = blue3; + + if (brmax > 65535) { // if overflow, reduce + brmax = 65535 / brmax; + red3 = red3 * brmax; + green3 = green3 * brmax; + blue3 = blue3 * brmax; + } + + pix3[0] = red3; + pix3[1] = green3; + pix3[2] = blue3; + } + + exit_wthread(); + return 0; // not executed, stop gcc warning +} + + +/**************************************************************************/ + +// match_color edit function +// Adjust colors of image 2 to match the colors of image 1 +// using small selected areas in each image as the match standard. + +void * match_color_thread(void *); +void match_color_mousefunc(); + +int match_color_RGB1[3]; // image 1 base colors to match +int match_color_RGB2[3]; // image 2 target colors to match +int match_color_radius = 10; // mouse radius +int match_color_mode = 0; + +editfunc EFmatchcolor; + + +void m_match_color(GtkWidget *, const char *) // new v.11.07 +{ + int match_color_dialog_event(zdialog* zd, const char *event); + + cchar *title = ZTX("Color Match Images"); + + zfuncs::F1_help_topic = "match_colors"; + + if (is_syncbusy()) return; // must wait for file sync v.11.11 + if (! menulock(1)) return; // test menu lock + menulock(0); + +/* + Color Match Images + 1 [ 10 ] mouse radius for color sample + 2 [Open] image for source color + 3 click on image to get source color + 4 [Open] image for target color + 5 click on image to set target color + [done] [cancel] +*/ + + zdialog *zd = zdialog_new(title,mWin,Bdone,Bcancel,null); // match_color dialog + zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=2"); + zdialog_add_widget(zd,"vbox","vb1","hb1",0,"homog|space=3"); + zdialog_add_widget(zd,"vbox","vb2","hb1",0,"homog|space=3"); + zdialog_add_widget(zd,"label","labn1","vb1","1"); + zdialog_add_widget(zd,"label","labn2","vb1","2"); + zdialog_add_widget(zd,"label","labn3","vb1","3"); + zdialog_add_widget(zd,"label","labn4","vb1","4"); + zdialog_add_widget(zd,"label","labn5","vb1","5"); + zdialog_add_widget(zd,"hbox","hbrad","vb2"); + zdialog_add_widget(zd,"spin","radius","hbrad","1|20|1|10","space=5"); + zdialog_add_widget(zd,"label","labrad","hbrad",ZTX("mouse radius for color sample")); + zdialog_add_widget(zd,"hbox","hbop1","vb2"); + zdialog_add_widget(zd,"button","open1","hbop1",ZTX("Open"),"space=5"); + zdialog_add_widget(zd,"label","labop1","hbop1",ZTX("image for source color")); + zdialog_add_widget(zd,"hbox","hbclik1","vb2"); + zdialog_add_widget(zd,"label","labclik1","hbclik1",ZTX("click on image to get source color")); + zdialog_add_widget(zd,"hbox","hbop2","vb2"); + zdialog_add_widget(zd,"button","open2","hbop2",ZTX("Open"),"space=5"); + zdialog_add_widget(zd,"label","labop2","hbop2",ZTX("image to set matching color")); + zdialog_add_widget(zd,"hbox","hbclik2","vb2"); + zdialog_add_widget(zd,"label","labclik2","hbclik2",ZTX("click on image to set matching color")); + + zdialog_stuff(zd,"radius",match_color_radius); // remember last radius + zdialog_help(zd,"match_colors"); // zdialog help topic v.11.08 + zdialog_run(zd,match_color_dialog_event); // run dialog - parallel + + EFmatchcolor.funcname = "match-color"; + EFmatchcolor.Farea = 1; // select area ignored + EFmatchcolor.threadfunc = match_color_thread; + EFmatchcolor.mousefunc = match_color_mousefunc; + + match_color_mode = 0; + if (curr_file) { + match_color_mode = 1; // image 1 ready to click + takeMouse(zd,match_color_mousefunc,0); // connect mouse function + } + + return; +} + + +// match_color dialog event and completion function + +int match_color_dialog_event(zdialog *zd, const char *event) // match_color dialog event function +{ + int err; + + if (zd->zstat) // end dialog + { + if (match_color_mode == 4) { // edit was started + if (zd->zstat == 1) edit_done(EFmatchcolor); + else edit_cancel(EFmatchcolor); + } + freeMouse(); + zdialog_free(zd); + match_color_mode = 0; + return 1; + } + + if (match_color_mode == 4) // if prior edit, cancel it + edit_cancel(EFmatchcolor); + + if (strEqu(event,"radius")) // set new mouse radius + zdialog_fetch(zd,"radius",match_color_radius); + + if (strEqu(event,"open1")) // get image 1 for color source + { + match_color_mode = 0; + err = f_open(null,0,0); + if (! err) match_color_mode = 1; // image 1 ready to click + } + + if (strEqu(event,"open2")) // get image 2 to set matching color + { + if (match_color_mode < 2) { + zmessageACK(mWin,ZTX("select source image color first")); // check that RGB1 has been set + return 1; + } + match_color_mode = 2; + err = f_open(null,0,0); + if (err) return 1; + match_color_mode = 3; // image 2 ready to click + } + + takeMouse(zd,match_color_mousefunc,0); // reconnect mouse function + return 1; +} + + +// mouse function - click on image and get colors to match + +void match_color_mousefunc() +{ + void match_color_getRGB(int px, int py, int RGB[3]); + + int px, py; + zdialog *zd = EFmatchcolor.zd; + + if (match_color_mode < 1) return; // no image available yet + + toparcx = Mxposn - match_color_radius; // mouse outline circle + toparcy = Myposn - match_color_radius; + toparcw = toparch = 2 * match_color_radius; + Ftoparc = 1; + paint_toparc(3); + + if (LMclick) + { + LMclick = 0; + px = Mxclick; + py = Myclick; + + if (match_color_mode == 1 || match_color_mode == 2) // image 1 ready to click + { + match_color_getRGB(px,py,match_color_RGB1); // get RGB1 color + match_color_mode = 2; + return; + } + + if (match_color_mode == 3 || match_color_mode == 4) // image 2 ready to click + { + match_color_getRGB(px,py,match_color_RGB2); // get RGB2 color + + if (match_color_mode == 4) { + edit_cancel(EFmatchcolor); // if prior edit, cancel it + takeMouse(zd,match_color_mousefunc,0); // reconnect mouse function + match_color_mode = 3; + } + + if (! edit_setup(EFmatchcolor)) return; // setup edit - thread will launch + match_color_mode = 4; // edit waiting for cancel or done + signal_thread(); // update the target image + return; + } + } + + return; +} + + +// get the RGB averages for pixels within mouse radius + +void match_color_getRGB(int px, int py, int RGB[3]) +{ + int rad1 = match_color_radius; + int rad2 = rad1 * rad1; + int rad, npix, qx, qy; + int red, green, blue; + uint16 *pix1; + PXM *pxm; + + pxm = f_load(curr_file,16); + if (! pxm) return; + + npix = 0; + red = green = blue = 0; + + for (qy = py-rad1; qy <= py+rad1; qy++) + for (qx = px-rad1; qx <= px+rad1; qx++) + { + if (qx < 0 || qx > Fww-1) continue; + if (qy < 0 || qy > Fhh-1) continue; + rad = (qx-px) * (qx-px) + (qy-py) * (qy-py); + if (rad > rad2) continue; + pix1 = PXMpix(pxm,qx,qy); + red += pix1[0]; + green += pix1[1]; + blue += pix1[2]; + npix++; + } + + RGB[0] = red / npix; + RGB[1] = green / npix; + RGB[2] = blue / npix; + + PXM_free(pxm); + return; +} + + +// thread function - start multiple working threads + +void * match_color_thread(void *) +{ + void * match_color_wthread(void *arg); // worker thread + + while (true) + { + thread_idle_loop(); // wait for work or exit request + + for (int ii = 0; ii < Nwt; ii++) // start worker threads + start_wthread(match_color_wthread,&wtnx[ii]); + wait_wthreads(); // wait for completion + + CEF->Fmod = 1; + mwpaint2(); // update window + } + + return 0; // not executed, avoid warning +} + + +void * match_color_wthread(void *arg) // worker thread function +{ + int index = *((int *) (arg)); + int px, py; + uint16 *pix3; + double Rred, Rgreen, Rblue; + double red, green, blue, cmax; + + Rred = 1.0 * match_color_RGB1[0] / match_color_RGB2[0]; // color adjustment ratios + Rgreen = 1.0 * match_color_RGB1[1] / match_color_RGB2[1]; + Rblue = 1.0 * match_color_RGB1[2] / match_color_RGB2[2]; + + for (py = index; py < E3hh; py += Nwt) // loop all image pixels + for (px = 0; px < E3ww; px++) + { + pix3 = PXMpix(E3pxm16,px,py); + + red = pix3[0] * Rred; // adjust colors + green = pix3[1] * Rgreen; + blue = pix3[2] * Rblue; + + cmax = red; // check for overflow + if (green > cmax) cmax = green; + if (blue > cmax) cmax = blue; + + if (cmax > 65535) { // fix overflow + red = red * 65535 / cmax; + green = green * 65535 / cmax; + blue = blue * 65535 / cmax; + } + + pix3[0] = red; + pix3[1] = green; + pix3[2] = blue; + } + + exit_wthread(); + return 0; // not executed, avoid gcc warning +} + + +/**************************************************************************/ + +// DRGB menu function +// Adjust Density (Brightness) and RGB levels using 0.01 OD units + +editfunc EFdrgb; // edit function data +int DRGBinputs[8]; +int DRGBbias = 0; +char *DRGB_file = 0; + +void m_DRGB(GtkWidget *, const char *) // new v.11.08 +{ + int DRGB_dialog_event(zdialog *zd, cchar *event); + void * DRGB_thread(void *); + + zfuncs::F1_help_topic = "DRGB"; + + EFdrgb.funcname = "DRGB"; // function name + EFdrgb.Fprev = 1; // use preview + EFdrgb.Farea = 2; // select area usable + EFdrgb.Fpara = 1; // parallel edit OK + EFdrgb.threadfunc = DRGB_thread; // thread function + if (! edit_setup(EFdrgb)) return; // setup edit + +/*** + _________________________________________________ + | | + | [reset] [x] Add standard bias | + | +Brightness -Density [__|v] Contrast [__|v] | + | +Red -Cyan [__|v] Red [__|v] | + | +Green -Magenta [__|v] Green [__|v] | + | +Blue -Yellow [__|v] Blue [__|x] | + | | + | [open] [save] [done] [cancel] | + |_________________________________________________| + +***/ + + zdialog *zd = zdialog_new("DRGB",mWin,Bopen,Bsave,Bdone,Bcancel,null); // new dialog + zdialog_help(zd,"DRGB"); // add help topic to zdialog + EFdrgb.zd = zd; // add dialog to edit function + + zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=5"); + zdialog_add_widget(zd,"button","reset","hb1",Breset,"space=10"); + zdialog_add_widget(zd,"check","bias","hb1",ZTX("Add standard bias"),"space=5"); + zdialog_add_widget(zd,"hbox","hb2","dialog"); + zdialog_add_widget(zd,"vbox","vb1","hb2",0,"homog|space=5"); + zdialog_add_widget(zd,"vbox","vb2","hb2",0,"homog|space=5"); + zdialog_add_widget(zd,"label","space","hb2",0,"space=8"); + zdialog_add_widget(zd,"vbox","vb3","hb2",0,"homog|space=5"); + zdialog_add_widget(zd,"vbox","vb4","hb2",0,"homog|space=5"); + zdialog_add_widget(zd,"button","buBriteDens","vb1",ZTX("+Brightness -Density")); + zdialog_add_widget(zd,"button","buRedDens","vb1",ZTX("+Red -Cyan")); + zdialog_add_widget(zd,"button","buGreenDens","vb1",ZTX("+Green -Magenta")); + zdialog_add_widget(zd,"button","buBlueDens","vb1",ZTX("+Blue -Yellow")); + zdialog_add_widget(zd,"spin","spBriteDens","vb2","-99|+99|1|0"); + zdialog_add_widget(zd,"spin","spRedDens","vb2","-99|+99|1|0"); + zdialog_add_widget(zd,"spin","spGreenDens","vb2","-99|+99|1|0"); + zdialog_add_widget(zd,"spin","spBlueDens","vb2","-99|+99|1|0"); + zdialog_add_widget(zd,"button","buContrast","vb3",ZTX("Contrast")); + zdialog_add_widget(zd,"button","buRedCon","vb3",ZTX("Red")); + zdialog_add_widget(zd,"button","buGreenCon","vb3",ZTX("Green")); + zdialog_add_widget(zd,"button","buBlueCon","vb3",ZTX("Blue")); + zdialog_add_widget(zd,"spin","spContrast","vb4","-99|+99|1|0"); + zdialog_add_widget(zd,"spin","spRedCon","vb4","-99|+99|1|0"); + zdialog_add_widget(zd,"spin","spGreenCon","vb4","-99|+99|1|0"); + zdialog_add_widget(zd,"spin","spBlueCon","vb4","-99|+99|1|0"); + + if (! DRGB_file) { // default file + DRGB_file = zmalloc(200); // /home//.fotoxx/DRGB_parameters + snprintf(DRGB_file,200,"%s/DRGB_parameters",get_zuserdir()); + } + + zdialog_run(zd,DRGB_dialog_event,"save"); // run dialog - parallel + return; +} + + +// DRGB dialog event and completion function + +int DRGB_dialog_event(zdialog *zd, cchar *event) // DRGB dialog event function +{ + void DRGB_open(); + void DRGB_save(); + + int bias; + + if (zd->zstat) + { + if (zd->zstat == 1) { // open file + zd->zstat = 0; // keep dialog active + DRGB_open(); // read file + + zdialog_stuff(zd,"bias",DRGBbias); // set all data + zdialog_stuff(zd,"spBriteDens",DRGBinputs[0]); + zdialog_stuff(zd,"spRedDens",DRGBinputs[1]); + zdialog_stuff(zd,"spGreenDens",DRGBinputs[2]); + zdialog_stuff(zd,"spBlueDens",DRGBinputs[3]); + zdialog_stuff(zd,"spContrast",DRGBinputs[4]); + zdialog_stuff(zd,"spRedCon",DRGBinputs[5]); + zdialog_stuff(zd,"spGreenCon",DRGBinputs[6]); + zdialog_stuff(zd,"spBlueCon",DRGBinputs[7]); + } + + else if (zd->zstat == 2) { // save file + zd->zstat = 0; // keep dialog active + DRGB_save(); // write file + } + + else if (zd->zstat == 3) edit_done(EFdrgb); // done + + else edit_cancel(EFdrgb); // cancel or destroy + + return 0; + } + + edit_takeover(EFdrgb); // set parallel edit function + + if (strEqu(event,"bias")) // bias was changed + { + zdialog_fetch(zd,"bias",bias); + if (bias != DRGBbias) + { + if (bias) { // off to on + DRGBinputs[0] += 72; + DRGBinputs[2] += 32; + DRGBinputs[3] += 32; + zdialog_set_limits(zd,"spBriteDens",-27,+171); + zdialog_set_limits(zd,"spGreenDens",-67,+131); + zdialog_set_limits(zd,"spBlueDens",-67,+131); + } + else { // on to off + DRGBinputs[0] -= 72; + DRGBinputs[2] -= 32; + DRGBinputs[3] -= 32; + zdialog_set_limits(zd,"spBriteDens",-99,+99); + zdialog_set_limits(zd,"spGreenDens",-99,+99); + zdialog_set_limits(zd,"spBlueDens",-99,+99); + } + zdialog_stuff(zd,"spBriteDens",DRGBinputs[0]); + zdialog_stuff(zd,"spGreenDens",DRGBinputs[2]); + zdialog_stuff(zd,"spBlueDens",DRGBinputs[3]); + } + DRGBbias = bias; + return 1; + } + + if (strEqu(event,"reset")) // reset dialog controls + { + DRGBinputs[0] = DRGBbias * 72; + DRGBinputs[1] = DRGBbias * 0; + DRGBinputs[2] = DRGBbias * 32; + DRGBinputs[3] = DRGBbias * 32; + DRGBinputs[4] = 0; + DRGBinputs[5] = 0; + DRGBinputs[6] = 0; + DRGBinputs[7] = 0; + zdialog_stuff(zd,"spBriteDens",DRGBinputs[0]); + zdialog_stuff(zd,"spRedDens",DRGBinputs[1]); + zdialog_stuff(zd,"spGreenDens",DRGBinputs[2]); + zdialog_stuff(zd,"spBlueDens",DRGBinputs[3]); + zdialog_stuff(zd,"spContrast",DRGBinputs[4]); + zdialog_stuff(zd,"spRedCon",DRGBinputs[5]); + zdialog_stuff(zd,"spGreenCon",DRGBinputs[6]); + zdialog_stuff(zd,"spBlueCon",DRGBinputs[7]); + } + + zdialog_fetch(zd,"spBriteDens",DRGBinputs[0]); // get all inputs + zdialog_fetch(zd,"spRedDens",DRGBinputs[1]); + zdialog_fetch(zd,"spGreenDens",DRGBinputs[2]); + zdialog_fetch(zd,"spBlueDens",DRGBinputs[3]); + zdialog_fetch(zd,"spContrast",DRGBinputs[4]); + zdialog_fetch(zd,"spRedCon",DRGBinputs[5]); + zdialog_fetch(zd,"spGreenCon",DRGBinputs[6]); + zdialog_fetch(zd,"spBlueCon",DRGBinputs[7]); + + signal_thread(); // trigger update thread + wait_thread_idle(); // wait until done (optional) + return 1; +} + + +// load DRGB parameters from a previously saved file + +void DRGB_open() +{ + int DRGB_open_dialog_event(zdialog *zd, cchar *event); + + zdialog *zd; + + zd = zdialog_new(ZTX("Load DRGB parameters"),mWin,Bopen,Bcancel,null); + zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=3"); + zdialog_add_widget(zd,"label","lab1","hb1",ZTX("File:"),"space=3"); + zdialog_add_widget(zd,"entry","file","hb1",0,"expand|scc=40"); + zdialog_add_widget(zd,"button","browse","hb1",Bbrowse,"space=5"); + + zdialog_stuff(zd,"file",DRGB_file); + + zdialog_run(zd,DRGB_open_dialog_event); + zdialog_wait(zd); + return; +} + + +int DRGB_open_dialog_event(zdialog *zd, cchar *event) +{ + char *pp, file[200]; + FILE *fid = 0; + int zstat, nn; + + if (strEqu(event,"browse")) { + pp = zgetfile1(ZTX("DRGB parameters file"),"open",DRGB_file); + if (! pp) return 0; + zdialog_stuff(zd,"file",pp); + zfree(pp); + } + + zstat = zd->zstat; // completion button + + if (zstat) + { + if (zstat == 1) // open + { + zdialog_fetch(zd,"file",file,200); // get file from dialog + if (DRGB_file) zfree(DRGB_file); + DRGB_file = strdupz(file); + + fid = fopen(file,"r"); // open file + if (! fid) { + zmessageACK(mWin,ZTX("file not found")); + return 1; + } + + nn = fscanf(fid,"DRGB parameters"); // read header + + nn = fscanf(fid,"%4d %4d %4d %4d %4d %4d %4d %4d %4d", // read data + &DRGBbias, + &DRGBinputs[0], &DRGBinputs[1], &DRGBinputs[2], + &DRGBinputs[3], &DRGBinputs[4], &DRGBinputs[5], + &DRGBinputs[6], &DRGBinputs[7]); + + if (nn != 9) zmessageACK(mWin,"file format error"); + + fclose(fid); + zdialog_free(zd); + } + + else zdialog_free(zd); // cancel or [x] + } + + return 1; +} + + +// save DRGB parameters to a file + +void DRGB_save() +{ + int DRGB_save_dialog_event(zdialog *zd, cchar *event); + + zdialog *zd; + + zd = zdialog_new(ZTX("Save DRGB parameters"),mWin,Bsave,Bcancel,null); + zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=3"); + zdialog_add_widget(zd,"label","lab1","hb1",ZTX("File:"),"space=3"); + zdialog_add_widget(zd,"entry","file","hb1",0,"expand|scc=40"); + zdialog_add_widget(zd,"button","browse","hb1",Bbrowse,"space=5"); + + zdialog_stuff(zd,"file",DRGB_file); + + zdialog_run(zd,DRGB_save_dialog_event); + zdialog_wait(zd); + + return; +} + + +int DRGB_save_dialog_event(zdialog *zd, cchar *event) +{ + char *pp, file[200]; + FILE *fid = 0; + int zstat; + + if (strEqu(event,"browse")) { + pp = zgetfile1(ZTX("DRGB parameters file"),"save",DRGB_file); + if (! pp) return 0; + zdialog_stuff(zd,"file",pp); + zfree(pp); + } + + zstat = zd->zstat; // completion button + + if (zstat) + { + if (zstat == 1) // save + { + zdialog_fetch(zd,"file",file,200); // get file from dialog + if (DRGB_file) zfree(DRGB_file); + DRGB_file = strdupz(file); + + fid = fopen(file,"w"); // open file + if (! fid) { + zmessageACK(mWin,strerror(errno)); + return 1; + } + + fprintf(fid,"DRGB parameters \n"); // write headers + + fprintf(fid,"%4d %4d %4d %4d %4d %4d %4d %4d %4d ", // write data + DRGBbias, + DRGBinputs[0], DRGBinputs[1], DRGBinputs[2], + DRGBinputs[3], DRGBinputs[4], DRGBinputs[5], + DRGBinputs[6], DRGBinputs[7]); + fprintf(fid,"\n"); + fclose(fid); + zdialog_free(zd); + } + + else zdialog_free(zd); // cancel or [x] + } + + return 1; +} + + +// thread function - multiple working threads to update image + +void * DRGB_thread(void *) +{ + void * DRGB_wthread(void *arg); // worker thread + + while (true) + { + thread_idle_loop(); // wait for work or exit request + + if (Factivearea) SB_goal = sa_Npixel; // set up progress monitor + else SB_goal = E3ww * E3hh; + SB_done = 0; + + for (int ii = 0; ii < Nwt; ii++) // start worker threads + start_wthread(DRGB_wthread,&wtnx[ii]); + wait_wthreads(); // wait for completion + + SB_goal = SB_done = 0; + CEF->Fmod = 1; // image modified + mwpaint2(); // update window + } + + return 0; // not executed, stop warning +} + + +void * DRGB_wthread(void *arg) // worker thread function +{ + double Du, Ru, Gu, Bu, Rd, Gd, Bd; + double con, conR, conG, conB; + double R1, G1, B1, R3, G3, B3; + + int index = *((int *) (arg)); + int px, py, ii, dist = 0; + uint16 *pix1, *pix3; + double cmax, F, f1, f2; + double c1 = 100.0 / 65536.0; + double c2 = 2.0 + log10(1.0/c1); + double c3 = 1.0 / 65536.0; + + #define ODfunc(rgb) (2.0 - log10(c1 * rgb)) // RGB units (1-65536) to OD units + #define RGBfunc(od) (pow(10,(c2 - od))) // OD units to RGB units + + Du = -0.01 * DRGBinputs[0]; // convert inputs from cc to OD units + Ru = -0.01 * DRGBinputs[1]; // range is -0.99 to +0.99 + Gu = -0.01 * DRGBinputs[2]; + Bu = -0.01 * DRGBinputs[3]; + + if (DRGBbias) { // remove bias + Du += 0.72; + Gu += 0.32; + Bu += 0.32; + } + + con = -0.01 * DRGBinputs[4]; + conR = -0.01 * DRGBinputs[5]; + conG = -0.01 * DRGBinputs[6]; + conB = -0.01 * DRGBinputs[7]; + + for (py = index; py < E3hh; py += Nwt) // loop all image pixels + for (px = 0; px < E3ww; px++) + { + if (Factivearea) { // select area active + ii = py * E3ww + px; + dist = sa_pixmap[ii]; // distance from edge + if (! dist) continue; // outside area + } + + pix1 = PXMpix(E1pxm16,px,py); // input pixel + pix3 = PXMpix(E3pxm16,px,py); // output pixel + + R1 = pix1[0] + 1; // input RGB values, 0-65535 + G1 = pix1[1] + 1; // (avoid 0) + B1 = pix1[2] + 1; + + Rd = ODfunc(R1); // convert to OD units + Gd = ODfunc(G1); + Bd = ODfunc(B1); + + Rd += Du + Ru; // add user OD increments + Gd += Du + Gu; + Bd += Du + Bu; + + if (con) { // overall contrast + Rd += con * c3 * (R1-32768); + Gd += con * c3 * (G1-32768); + Bd += con * c3 * (B1-32768); + } + + if (conR) // single color contrast + Rd += conR * c3 * (R1-32768); + if (conG) + Gd += conG * c3 * (G1-32768); + if (conB) + Bd += conB * c3 * (B1-32768); + + R3 = RGBfunc(Rd); // convert back to RGB units + G3 = RGBfunc(Gd); + B3 = RGBfunc(Bd); + + if (R3 < 0) R3 = 0; // stop underflow + if (G3 < 0) G3 = 0; + if (B3 < 0) B3 = 0; + + if (R3 > 65535 || G3 > 65535 || B3 > 65535) { // stop overflow + cmax = R3; + if (G3 > cmax) cmax = G3; + if (B3 > cmax) cmax = B3; + F = 65535 / cmax; + R3 *= F; + G3 *= F; + B3 *= F; + } + + if (Factivearea && dist < sa_blend) { // select area is active, + f1 = 1.0 * dist / sa_blend; // blend changes over sa_blend + f2 = 1.0 - f1; + R3 = f1 * R3 + f2 * R1; + G3 = f1 * G3 + f2 * G1; + B3 = f1 * B3 + f2 * B1; + } + + pix3[0] = R3; // output RGB values + pix3[1] = G3; + pix3[2] = B3; + } + + exit_wthread(); + return 0; // not executed, avoid gcc warning +} + + +/**************************************************************************/ + +// Show RGB values for 1-9 pixels selected with mouse-clicks. +// Revise RGB values for the selected points and then revise all other +// pixels to match, using a distance-weighted average of the selected pixels. + +void RGBR_dialog(); +void RGBR_mousefunc(); +void RGBR_stuff(); +void * RGBR_thread(void *); + +zdialog *RGBRzd; +int RGBRpixel[9][2]; // last 9 pixel locations clicked +double RGBRval1[9][3]; // original RGB values, 0 to 255.9 +double RGBRval3[9][3]; // revised RGB values, 0 to 255.9 +int RGBRmetric = 1; // 1/2/3 = /RGB/EV/OD +int RGBRdelta = 0; // flag, delta mode +int RGBRrestart; // flag, restart dialog +int RGBRnpix; // no. of selected pixels +double RGBRtime; // last click time +int RGBRblend; // blend factor, 10 to 1000 +editfunc EFrgbrevise; // edit function parameters + +#define RGB2EV(rgb) (log2(rgb)-7) // RGB 0.1 to 255.9 >> EV -10 to +1 +#define EV2RGB(ev) (pow(2,ev+7)) // inverse +#define RGB2OD(rgb) (2-log10(100*rgb/256)) // RGB 0.1 to 255.9 >> OD 3.4 to 0.000017 +#define OD2RGB(od) (pow(10,2.40824-od)) // inverse + + +void m_revise_RGB(GtkWidget *, cchar *menu) // new v.11.07 +{ + int RGBR_event(zdialog *zd, cchar *event); + + GtkWidget *widget; + cchar *limits; + zdialog *zd; + cchar *mess = ZTX("Click image to select pixels."); + + PangoFontDescription *widgetfont; + widgetfont = pango_font_description_from_string("Monospace 8"); // small monospace font for widgets + + zfuncs::F1_help_topic = "revise_RGB"; + + EFrgbrevise.funcname = "revise_RGB"; // setup edit function + EFrgbrevise.threadfunc = RGBR_thread; + EFrgbrevise.mousefunc = RGBR_mousefunc; + EFrgbrevise.Farea = 1; + if (! edit_setup(EFrgbrevise)) return; + + RGBRblend = 20; // default slider value + RGBRnpix = 0; // no pixels selected yet + +/*** + + Click image to select pixels. + [x] delta + Metric: (o) RGB (o) EV (o) OD + Pixel Red Green Blue + A xxxx xxxx [xxxx|v] [xxxx|v] [xxxx|v] // spin buttons for RGB/EV/OD values + B xxxx xxxx [xxxx|v] [xxxx|v] [xxxx|v] + C xxxx xxxx [xxxx|v] [xxxx|v] [xxxx|v] + D xxxx xxxx [xxxx|v] [xxxx|v] [xxxx|v] + E xxxx xxxx [xxxx|v] [xxxx|v] [xxxx|v] + F xxxx xxxx [xxxx|v] [xxxx|v] [xxxx|v] + G xxxx xxxx [xxxx|v] [xxxx|v] [xxxx|v] + H xxxx xxxx [xxxx|v] [xxxx|v] [xxxx|v] + I xxxx xxxx [xxxx|v] [xxxx|v] [xxxx|v] + Blend ==============[]================ + + [reset] [done] [cancel] +***/ + +restart: + + zd = zdialog_new(ZTX("Revise RGB"),mWin,Breset,Bdone,Bcancel,null); + EFrgbrevise.zd = zd; + RGBRzd = zd; + + zdialog_add_widget(zd,"hbox","hbmess","dialog",0,"space=3"); + zdialog_add_widget(zd,"label","labmess","hbmess",mess,"space=5"); + + zdialog_add_widget(zd,"hbox","hbmym","dialog"); + zdialog_add_widget(zd,"check","delta","hbmym","delta","space=5"); + zdialog_stuff(zd,"delta",RGBRdelta); + + zdialog_add_widget(zd,"hbox","hbmetr","dialog",0,"space=3"); + zdialog_add_widget(zd,"label","labmetr","hbmetr",ZTX("Metric:"),"space=5"); + zdialog_add_widget(zd,"radio","radRGB","hbmetr","RGB","space=3"); + zdialog_add_widget(zd,"radio","radEV","hbmetr","EV","space=3"); + zdialog_add_widget(zd,"radio","radOD","hbmetr","OD","space=3"); + + if (RGBRmetric == 1) zdialog_stuff(zd,"radRGB",1); // set current metric + if (RGBRmetric == 2) zdialog_stuff(zd,"radEV",1); + if (RGBRmetric == 3) zdialog_stuff(zd,"radOD",1); + + zdialog_add_widget(zd,"hbox","hbdata","dialog"); + zdialog_add_widget(zd,"vbox","vbpix","hbdata",0,"space=3|homog"); // vbox for pixel locations + zdialog_add_widget(zd,"hbox","hbpix","vbpix"); + zdialog_add_widget(zd,"label","labpix","hbpix","Pixel"); // header + + char hbpixx[8] = "hbpixx", pixx[8] = "pixx"; + + for (int ii = 1; ii < 10; ii++) { // add labels for pixel locations + hbpixx[5] = '0' + ii; + pixx[3] = '0' + ii; + zdialog_add_widget(zd,"hbox",hbpixx,"vbpix"); // add hbox "hbpix1" to "hbpix9" + zdialog_add_widget(zd,"label",pixx,hbpixx); // add label "pix1" to "pix9" + widget = zdialog_widget(zd,pixx); + gtk_widget_modify_font(widget,widgetfont); // use monofont + } + + if (RGBRmetric == 1) limits = "-255.9|255.9|0.1|0.0"; // metric = RGB + else if (RGBRmetric == 2) limits = "-8|8|0.01|0.0"; // EV + else limits = "-3|3|0.002|0.0"; // OD + + zdialog_add_widget(zd,"vbox","vbdat","hbdata",0,"space=3|homog"); // vbox for pixel RGB values + zdialog_add_widget(zd,"hbox","hbrgb","vbdat",0,"homog"); + zdialog_add_widget(zd,"label","labr","hbrgb",Bred); // v.11.08 + zdialog_add_widget(zd,"label","labg","hbrgb",Bgreen); + zdialog_add_widget(zd,"label","labb","hbrgb",Bblue); + + char hbdatx[8] = "hbdatx", redx[8] = "redx", greenx[8] = "greenx", bluex[8] = "bluex"; + + for (int ii = 1; ii < 10; ii++) { + hbdatx[5] = '0' + ii; + redx[3] = '0' + ii; + greenx[5] = '0' + ii; + bluex[4] = '0' + ii; + zdialog_add_widget(zd,"hbox",hbdatx,"vbdat"); // add hbox "hbdat1" to "hbdat9" + zdialog_add_widget(zd,"spin",redx,hbdatx,limits,"space=3"); // add spin buttons for "red1" to "red9" etc. + zdialog_add_widget(zd,"spin",greenx,hbdatx,limits,"space=3"); + zdialog_add_widget(zd,"spin",bluex,hbdatx,limits,"space=3"); + widget = zdialog_widget(zd,redx); + gtk_widget_modify_font(widget,widgetfont); // use monofont + widget = zdialog_widget(zd,greenx); + gtk_widget_modify_font(widget,widgetfont); + widget = zdialog_widget(zd,bluex); + gtk_widget_modify_font(widget,widgetfont); + } + + zdialog_add_widget(zd,"hbox","hbsoft","dialog","space=5"); + zdialog_add_widget(zd,"label","labsoft","hbsoft",ZTX("Blend"),"space=3"); + zdialog_add_widget(zd,"hscale","blend","hbsoft","0|100|1|20","space=5|expand"); + zdialog_add_widget(zd,"label","softval","hbsoft","20"); + + RGBR_stuff(); // stuff current pixels (if restart) + + takeMouse(zd,RGBR_mousefunc,dragcursor); // connect mouse function + zdialog_help(zd,"revise_RGB"); // zdialog help topic v.11.08 + zdialog_run(zd,RGBR_event,"save"); // run dialog + zdialog_wait(zd); // wait for completion + if (RGBRrestart) goto restart; // restart dialog + + return; +} + + +// dialog event function + +int RGBR_event(zdialog *zd, cchar *event) +{ + int button; + int ii, jj; + char text[8]; + double val1, val3; + + if (zd->zstat) + { + if (zd->zstat == 1) { // Reset + zd->zstat = 0; // keep dialog active + RGBRnpix = 0; // no pixels selected yet + RGBR_stuff(); // clear dialog + edit_reset(); // reset edits v.11.08 + return 0; + } + else if (zd->zstat == 2) // Done + edit_done(EFrgbrevise); + else edit_cancel(EFrgbrevise); // Cancel or [x] + freeMouse(); // disconnect mouse function + zdialog_free(zd); // kill dialog + RGBRzd = 0; + RGBRrestart = 0; + erase_toptext(101); // erase pixel labels from image + return 1; + } + + if (strEqu(event,"focus")) // toggle mouse capture + takeMouse(zd,RGBR_mousefunc,dragcursor); // connect mouse function + + if (strEqu(event,"blend")) { // new blend factor + zdialog_fetch(zd,"blend",RGBRblend); + sprintf(text,"%d",RGBRblend); // numeric feedback + zdialog_stuff(zd,"softval",text); + signal_thread(); + return 1; + } + + if (strnEqu(event,"rad",3)) // metric was changed + { + if (strEqu(event,"radRGB")) { // RGB + zdialog_fetch(zd,event,button); + if (button) RGBRmetric = 1; + } + + if (strEqu(event,"radEV")) { // EV + zdialog_fetch(zd,event,button); + if (button) RGBRmetric = 2; + } + + if (strEqu(event,"radOD")) { // OD + zdialog_fetch(zd,event,button); + if (button) RGBRmetric = 3; + } + + if (button) { + freeMouse(); // restart dialog with new limits + zdialog_free(zd); + RGBRzd = 0; + RGBRrestart = 1; + } + + return 1; + } + + if (strEqu(event,"delta")) { // change absolute/delta mode + zdialog_fetch(zd,"delta",RGBRdelta); + freeMouse(); // restart dialog with new limits + zdialog_free(zd); + RGBRzd = 0; + RGBRrestart = 1; + return 1; + } + + ii = -1; // no RGB change yet + + if (strnEqu(event,"red",3)) { // red1 - red9 was changed + ii = event[3] - '1'; // pixel index 0-8 + jj = 0; // color = red + } + + if (strnEqu(event,"green",5)) { // green1 - green9 + ii = event[5] - '1'; + jj = 1; + } + + if (strnEqu(event,"blue",4)) { // blue1 - blue9 + ii = event[4] - '1'; + jj = 2; + } + + if (ii >= 0 && ii < 9) // RGB value was revised + { +/* + static int ignore = 0; + + if (ignore) { + ignore = 0; + return 1; + } + + ignore = 1; +*/ + + val1 = RGBRval1[ii][jj]; // original pixel RGB value + if (RGBRmetric == 2) val1 = RGB2EV(val1); // convert to EV or OD units + if (RGBRmetric == 3) val1 = RGB2OD(val1); + + zdialog_fetch(zd,event,val3); // revised RGB/EV/OD value from dialog + if (RGBRdelta) val3 += val1; // if delta mode, make absolute + + if (RGBRmetric == 2) val3 = EV2RGB(val3); // convert EV/OD to RGB value + if (RGBRmetric == 3) val3 = OD2RGB(val3); + + if (fabs(RGBRval3[ii][jj] - val3) < 0.001) return 1; // ignore re-entry after change + + if (val3 < 0.1) val3 = 0.1; // limit RGB within 0.1 to 255.9 + if (val3 > 255.9) val3 = 255.9; + + RGBRval3[ii][jj] = val3; // new RGB value for pixel + + if (RGBRmetric == 2) val3 = RGB2EV(val3); // convert RGB to EV/OD units + if (RGBRmetric == 3) val3 = RGB2OD(val3); + + if (RGBRdelta) val3 -= val1; // absolute back to relative + zdialog_stuff(zd,event,val3); // limited value back to dialog + + signal_thread(); // signal thread to update image + } + + return 1; +} + + +// mouse function + +void RGBR_mousefunc() // mouse function +{ + int ii; + uint16 *pix3; + + if (! LMclick) return; + LMclick = RMclick = 0; + + RGBRtime = get_seconds(); // mark time of pixel click + + if (RGBRnpix == 9) { // if table is full (9 entries) v.11.08 + for (ii = 1; ii < 9; ii++) { // move positions 1-8 up + RGBRpixel[ii-1][0] = RGBRpixel[ii][0]; // to fill positions 0-7 + RGBRpixel[ii-1][1] = RGBRpixel[ii][1]; + } + RGBRnpix = 8; // count is now 8 entries + } + + ii = RGBRnpix; // next table position to fill + RGBRpixel[ii][0] = Mxclick; // newest pixel + RGBRpixel[ii][1] = Myclick; + + pix3 = PXMpix(E3pxm16,Mxclick,Myclick); // get initial RGB values from + RGBRval1[ii][0] = RGBRval3[ii][0] = pix3[0] / 256.0; // modified image E3 + RGBRval1[ii][1] = RGBRval3[ii][1] = pix3[1] / 256.0; + RGBRval1[ii][2] = RGBRval3[ii][2] = pix3[2] / 256.0; + + RGBRnpix++; // up pixel count + RGBR_stuff(); // stuff pixels and values into dialog + return; +} + + +// stuff dialog with current pixels and their RGB/EV/OD values + +void RGBR_stuff() +{ + static char lab1[9][4] = { "A", "B", "C", "D", "E", "F", "G", "H", "I" }; + static char lab2[9][4] = { " A ", " B ", " C ", " D ", " E ", " F ", " G ", " H ", " I " }; + + int px, py; + double red1, green1, blue1, red3, green3, blue3; + char text[100], pixx[8] = "pixx"; + char redx[8] = "redx", greenx[8] = "greenx", bluex[8] = "bluex"; + zdialog *zd = RGBRzd; + + erase_toptext(101); // erase prior labels from image + + for (int ii = 0; ii < 9; ii++) // loop slots 0-8 + { + pixx[3] = '1' + ii; // widget names "pix1" ... "pix9" + redx[3] = '1' + ii; // widget names "red1" ... "red9" + greenx[5] = '1' + ii; + bluex[4] = '1' + ii; + + px = RGBRpixel[ii][0]; // next pixel to report + py = RGBRpixel[ii][1]; + if (ii >= RGBRnpix) { // > last pixel selected + zdialog_stuff(zd,pixx,""); + zdialog_stuff(zd,redx,0); // blank pixel and zero values + zdialog_stuff(zd,greenx,0); + zdialog_stuff(zd,bluex,0); + continue; + } + + sprintf(text,"%s %4d %4d",lab1[ii],px,py); // format pixel "A nnnn nnnn" + zdialog_stuff(zd,pixx,text); // pixel >> widget + + add_toptext(101,px,py,lab2[ii],"Sans 8"); // paint label on image at pixel + + red1 = RGBRval1[ii][0]; // original RGB values for pixel + green1 = RGBRval1[ii][1]; + blue1 = RGBRval1[ii][2]; + red3 = RGBRval3[ii][0]; // revised RGB values + green3 = RGBRval3[ii][1]; + blue3 = RGBRval3[ii][2]; + + if (RGBRmetric == 2) { // convert to EV units if needed + red1 = RGB2EV(red1); + green1 = RGB2EV(green1); + blue1 = RGB2EV(blue1); + red3 = RGB2EV(red3); + green3 = RGB2EV(green3); + blue3 = RGB2EV(blue3); + } + + if (RGBRmetric == 3) { // or OD units + red1 = RGB2OD(red1); + green1 = RGB2OD(green1); + blue1 = RGB2OD(blue1); + red3 = RGB2OD(red3); + green3 = RGB2OD(green3); + blue3 = RGB2OD(blue3); + } + + if (RGBRdelta) { // dialog is delta mode + red3 -= red1; + green3 -= green1; + blue3 -= blue1; + } + + zdialog_stuff(zd,redx,red3); + zdialog_stuff(zd,greenx,green3); + zdialog_stuff(zd,bluex,blue3); + } + + mwpaint2(); // refresh window + return; +} + + +// thread function - multiple working threads to update image + +void * RGBR_thread(void *) +{ + void * RGBR_wthread(void *arg); // worker thread + + while (true) + { + thread_idle_loop(); // wait for work or exit request + zsleep(0.3); // more time for dialog controls + + if (RGBRnpix < 1) continue; // must have 1+ pixels in table + + for (int ii = 0; ii < Nwt; ii++) // start worker threads + start_wthread(RGBR_wthread,&wtnx[ii]); + wait_wthreads(); // wait for completion + + CEF->Fmod = 1; // image modified + mwpaint2(); // update window + } + + return 0; // not executed, stop warning +} + + +void * RGBR_wthread(void *arg) // worker thread function +{ + int index = *((int *) (arg)); + int px1, py1, px2, py2, ii; + uint16 *pix1, *pix3; + double dist[9], weight[9], sumdist; + double blend, delta, red, green, blue, max; + + blend = Fww; + if (Fhh > Fww) blend = Fhh; + blend = blend * blend; + blend = 0.0001 * RGBRblend * RGBRblend * blend + 100; // 100 to (image size)**2 v.11.08 + + for (py1 = index; py1 < E3hh; py1 += Nwt) // loop all image pixels + for (px1 = 0; px1 < E3ww; px1++) + { + for (sumdist = ii = 0; ii < RGBRnpix; ii++) // compute weight of each revision point + { + px2 = RGBRpixel[ii][0]; + py2 = RGBRpixel[ii][1]; + dist[ii] = (px1-px2)*(px1-px2) + (py1-py2)*(py1-py2); // distance (px1,py1) to (px2,py2) + dist[ii] = 1.0 / (dist[ii] + blend); // blend reduces peaks at revision points + sumdist += dist[ii]; // sum inverse distances + } + + for (ii = 0; ii < RGBRnpix; ii++) // weight of each point + weight[ii] = dist[ii] / sumdist; + + pix1 = PXMpix(E1pxm16,px1,py1); // input pixel + pix3 = PXMpix(E3pxm16,px1,py1); // output pixel + + red = pix1[0]; + green = pix1[1]; + blue = pix1[2]; + + for (ii = 0; ii < RGBRnpix; ii++) { // apply weighted color changes + delta = RGBRval3[ii][0] - RGBRval1[ii][0]; // to each color + red += weight[ii] * 256 * delta; + delta = RGBRval3[ii][1] - RGBRval1[ii][1]; + green += weight[ii] * 256 * delta; + delta = RGBRval3[ii][2] - RGBRval1[ii][2]; + blue += weight[ii] * 256 * delta; + } + + max = red; + if (green > max) max = green; + if (blue > max) max = blue; + + if (max > 65535) { // stop overflow/underflow + red = red * 65535 / max; + green = green * 65535 / max; + blue = blue * 65535 / max; + } + + if (red < 0) red = 0; + if (green < 0) green = 0; + if (blue < 0) blue = 0; + + pix3[0] = red; + pix3[1] = green; + pix3[2] = blue; + } + + exit_wthread(); + return 0; // not executed, avoid gcc warning +} + + +/**************************************************************************/ + +// red eye removal function + +struct sredmem { // red-eye struct in memory + char type, space[3]; + int cx, cy, ww, hh, rad, clicks; + double thresh, tstep; +}; +sredmem redmem[100]; // store up to 100 red-eyes + +int Nredmem = 0, maxredmem = 100; +void redeye_mousefunc(); + +editfunc EFredeye; + + +void m_redeye(GtkWidget *, cchar *) +{ + int redeye_dialog_event(zdialog *zd, cchar *event); + + cchar *redeye_message = ZTX( + "Method 1:\n" + " Left-click on red-eye to darken.\n" + "Method 2:\n" + " Drag down and right to enclose red-eye.\n" + " Left-click on red-eye to darken.\n" + "Undo red-eye:\n" + " Right-click on red-eye."); + + zfuncs::F1_help_topic = "red_eye"; // v.10.8 + + EFredeye.funcname = "redeye"; + EFredeye.Farea = 1; // select area ignored + EFredeye.mousefunc = redeye_mousefunc; + if (! edit_setup(EFredeye)) return; // setup edit + + zdialog *zd = zdialog_new(ZTX("Red Eye Reduction"),mWin,Bdone,Bcancel,null); + EFredeye.zd = zd; + + zdialog_add_widget(zd,"label","lab1","dialog",redeye_message); + zdialog_help(zd,"red_eye"); // zdialog help topic v.11.08 + zdialog_run(zd,redeye_dialog_event,"save"); // run dialog - parallel v.11.07 + + Nredmem = 0; + takeMouse(zd,redeye_mousefunc,dragcursor); // connect mouse function v.11.03 + return; +} + + +// dialog event and completion callback function + +int redeye_dialog_event(zdialog *zd, cchar *event) +{ + if (zd->zstat) { + if (Nredmem > 0) CEF->Fmod = 1; + Ftoparc = ptoparc = 0; + if (zd->zstat == 1) edit_done(EFredeye); + else edit_cancel(EFredeye); + return 0; + } + + if (strEqu(event,"focus")) // toggle mouse capture v.10.12 + takeMouse(zd,redeye_mousefunc,dragcursor); // connect mouse function + + return 0; +} + + +// mouse functions to define, darken, and undo red-eyes + +int redeye_createF(int px, int py); // create 1-click red-eye (type F) +int redeye_createR(int px, int py, int ww, int hh); // create robust red-eye (type R) +void redeye_darken(int ii); // darken red-eye +void redeye_distr(int ii); // build pixel redness distribution +int redeye_find(int px, int py); // find red-eye at mouse position +void redeye_remove(int ii); // remove red-eye at mouse position +int redeye_radlim(int cx, int cy); // compute red-eye radius limit + + +void redeye_mousefunc() +{ + int ii, px, py, ww, hh; + + if (Nredmem == maxredmem) { + zmessageACK(mWin,"%d red-eye limit reached",maxredmem); // too many red-eyes + return; + } + + if (LMclick) // left mouse click + { + LMclick = 0; + + px = Mxclick; // click position + py = Myclick; + if (px < 0 || px > E3ww-1 || py < 0 || py > E3hh-1) return; // outside image area + + ii = redeye_find(px,py); // find existing red-eye + if (ii < 0) ii = redeye_createF(px,py); // or create new type F + redeye_darken(ii); // darken red-eye + } + + if (RMclick) // right mouse click + { + RMclick = 0; + px = Mxclick; // click position + py = Myclick; + ii = redeye_find(px,py); // find red-eye + if (ii >= 0) redeye_remove(ii); // if found, remove + } + + if (Mxdrag || Mydrag) // mouse drag underway + { + px = Mxdown; // initial position + py = Mydown; + ww = Mxdrag - Mxdown; // increment + hh = Mydrag - Mydown; + if (ww < 2 && hh < 2) return; + if (ww < 2) ww = 2; + if (hh < 2) hh = 2; + if (px < 1) px = 1; // keep within image area + if (py < 1) py = 1; + if (px + ww > E3ww-1) ww = E3ww-1 - px; + if (py + hh > E3hh-1) hh = E3hh-1 - py; + ii = redeye_find(px,py); // find existing red-eye + if (ii >= 0) redeye_remove(ii); // remove it + ii = redeye_createR(px,py,ww,hh); // create new red-eye type R + } + + mwpaint2(); + return; +} + + +// create type F redeye (1-click automatic) + +int redeye_createF(int cx, int cy) +{ + int cx0, cy0, cx1, cy1, px, py, rad, radlim; + int loops, ii; + int Tnpix, Rnpix, R2npix; + double rd, rcx, rcy, redpart; + double Tsum, Rsum, R2sum, Tavg, Ravg, R2avg; + double sumx, sumy, sumr; + uint16 *ppix; + + cx0 = cx; + cy0 = cy; + + for (loops = 0; loops < 8; loops++) + { + cx1 = cx; + cy1 = cy; + + radlim = redeye_radlim(cx,cy); // radius limit (image edge) + Tsum = Tavg = Ravg = Tnpix = 0; + + for (rad = 0; rad < radlim-2; rad++) // find red-eye radius from (cx,cy) + { + Rsum = Rnpix = 0; + R2sum = R2npix = 0; + + for (py = cy-rad-2; py <= cy+rad+2; py++) + for (px = cx-rad-2; px <= cx+rad+2; px++) + { + rd = sqrt((px-cx)*(px-cx) + (py-cy)*(py-cy)); + ppix = PXMpix(E3pxm16,px,py); + redpart = pixred(ppix); + + if (rd <= rad + 0.5 && rd > rad - 0.5) { // accum. redness at rad + Rsum += redpart; + Rnpix++; + } + else if (rd <= rad + 2.5 && rd > rad + 1.5) { // accum. redness at rad+2 + R2sum += redpart; + R2npix++; + } + } + + Tsum += Rsum; + Tnpix += Rnpix; + Tavg = Tsum / Tnpix; // avg. redness over 0-rad + Ravg = Rsum / Rnpix; // avg. redness at rad + R2avg = R2sum / R2npix; // avg. redness at rad+2 + if (R2avg > Ravg || Ravg > Tavg) continue; + if ((Ravg - R2avg) < 0.2 * (Tavg - Ravg)) break; // 0.1 --> 0.2 + } + + sumx = sumy = sumr = 0; + rad = int(1.2 * rad + 1); + if (rad > radlim) rad = radlim; + + for (py = cy-rad; py <= cy+rad; py++) // compute center of gravity for + for (px = cx-rad; px <= cx+rad; px++) // pixels within rad of (cx,cy) + { + rd = sqrt((px-cx)*(px-cx) + (py-cy)*(py-cy)); + if (rd > rad + 0.5) continue; + ppix = PXMpix(E3pxm16,px,py); + redpart = pixred(ppix); // weight by redness + sumx += redpart * (px - cx); + sumy += redpart * (py - cy); + sumr += redpart; + } + + rcx = cx + 1.0 * sumx / sumr; // new center of red-eye + rcy = cy + 1.0 * sumy / sumr; + if (fabs(cx0 - rcx) > 0.6 * rad) break; // give up if big movement + if (fabs(cy0 - rcy) > 0.6 * rad) break; + cx = int(rcx + 0.5); + cy = int(rcy + 0.5); + if (cx == cx1 && cy == cy1) break; // done if no change + } + + radlim = redeye_radlim(cx,cy); + if (rad > radlim) rad = radlim; + + ii = Nredmem++; // add red-eye to memory + redmem[ii].type = 'F'; + redmem[ii].cx = cx; + redmem[ii].cy = cy; + redmem[ii].rad = rad; + redmem[ii].clicks = 0; + redmem[ii].thresh = 0; + return ii; +} + + +// create type R red-eye (drag an ellipse over red-eye area) + +int redeye_createR(int cx, int cy, int ww, int hh) +{ + int rad, radlim; + + Ftoparc = 1; // paint ellipse over image + toparcx = cx - ww; + toparcy = cy - hh; + toparcw = 2 * ww; + toparch = 2 * hh; + + if (ww > hh) rad = ww; + else rad = hh; + radlim = redeye_radlim(cx,cy); + if (rad > radlim) rad = radlim; + + int ii = Nredmem++; // add red-eye to memory + redmem[ii].type = 'R'; + redmem[ii].cx = cx; + redmem[ii].cy = cy; + redmem[ii].ww = 2 * ww; + redmem[ii].hh = 2 * hh; + redmem[ii].rad = rad; + redmem[ii].clicks = 0; + redmem[ii].thresh = 0; + return ii; +} + + +// darken a red-eye and increase click count + +void redeye_darken(int ii) +{ + int cx, cy, ww, hh, px, py, rad, clicks; + double rd, thresh, tstep; + char type; + uint16 *ppix; + + type = redmem[ii].type; + cx = redmem[ii].cx; + cy = redmem[ii].cy; + ww = redmem[ii].ww; + hh = redmem[ii].hh; + rad = redmem[ii].rad; + thresh = redmem[ii].thresh; + tstep = redmem[ii].tstep; + clicks = redmem[ii].clicks++; + + if (thresh == 0) // 1st click + { + redeye_distr(ii); // get pixel redness distribution + thresh = redmem[ii].thresh; // initial redness threshhold + tstep = redmem[ii].tstep; // redness step size + Ftoparc = 0; + } + + tstep = (thresh - tstep) / thresh; // convert to reduction factor + thresh = thresh * pow(tstep,clicks); // reduce threshhold by total clicks + + for (py = cy-rad; py <= cy+rad; py++) // darken pixels over threshhold + for (px = cx-rad; px <= cx+rad; px++) + { + if (type == 'R') { + if (px < cx - ww/2) continue; + if (px > cx + ww/2) continue; + if (py < cy - hh/2) continue; + if (py > cy + hh/2) continue; + } + rd = sqrt((px-cx)*(px-cx) + (py-cy)*(py-cy)); + if (rd > rad + 0.5) continue; + ppix = PXMpix(E3pxm16,px,py); // set redness = threshhold + if (pixred(ppix) > thresh) + ppix[0] = int(thresh * (0.65 * ppix[1] + 0.10 * ppix[2] + 1) / (25 - 0.25 * thresh)); + } + + return; +} + + +// Build a distribution of redness for a red-eye. Use this information +// to set initial threshhold and step size for stepwise darkening. + +void redeye_distr(int ii) +{ + int cx, cy, ww, hh, rad, px, py; + int bin, npix, dbins[20], bsum, blim; + double rd, maxred, minred, redpart, dbase, dstep; + char type; + uint16 *ppix; + + type = redmem[ii].type; + cx = redmem[ii].cx; + cy = redmem[ii].cy; + ww = redmem[ii].ww; + hh = redmem[ii].hh; + rad = redmem[ii].rad; + + maxred = 0; + minred = 100; + + for (py = cy-rad; py <= cy+rad; py++) + for (px = cx-rad; px <= cx+rad; px++) + { + if (type == 'R') { + if (px < cx - ww/2) continue; + if (px > cx + ww/2) continue; + if (py < cy - hh/2) continue; + if (py > cy + hh/2) continue; + } + rd = sqrt((px-cx)*(px-cx) + (py-cy)*(py-cy)); + if (rd > rad + 0.5) continue; + ppix = PXMpix(E3pxm16,px,py); + redpart = pixred(ppix); + if (redpart > maxred) maxred = redpart; + if (redpart < minred) minred = redpart; + } + + dbase = minred; + dstep = (maxred - minred) / 19.99; + + for (bin = 0; bin < 20; bin++) dbins[bin] = 0; + npix = 0; + + for (py = cy-rad; py <= cy+rad; py++) + for (px = cx-rad; px <= cx+rad; px++) + { + if (type == 'R') { + if (px < cx - ww/2) continue; + if (px > cx + ww/2) continue; + if (py < cy - hh/2) continue; + if (py > cy + hh/2) continue; + } + rd = sqrt((px-cx)*(px-cx) + (py-cy)*(py-cy)); + if (rd > rad + 0.5) continue; + ppix = PXMpix(E3pxm16,px,py); + redpart = pixred(ppix); + bin = int((redpart - dbase) / dstep); + ++dbins[bin]; + ++npix; + } + + bsum = 0; + blim = int(0.5 * npix); + + for (bin = 0; bin < 20; bin++) // find redness level for 50% of + { // pixels within red-eye radius + bsum += dbins[bin]; + if (bsum > blim) break; + } + + redmem[ii].thresh = dbase + dstep * bin; // initial redness threshhold + redmem[ii].tstep = dstep; // redness step (5% of range) + + return; +} + + +// find a red-eye (nearly) overlapping the mouse click position + +int redeye_find(int cx, int cy) +{ + for (int ii = 0; ii < Nredmem; ii++) + { + if (cx > redmem[ii].cx - 2 * redmem[ii].rad && + cx < redmem[ii].cx + 2 * redmem[ii].rad && + cy > redmem[ii].cy - 2 * redmem[ii].rad && + cy < redmem[ii].cy + 2 * redmem[ii].rad) + return ii; // found + } + return -1; // not found +} + + +// remove a red-eye from memory + +void redeye_remove(int ii) +{ + int cx, cy, rad, px, py; + uint16 *pix1, *pix3; + + cx = redmem[ii].cx; + cy = redmem[ii].cy; + rad = redmem[ii].rad; + + for (px = cx-rad; px <= cx+rad; px++) + for (py = cy-rad; py <= cy+rad; py++) + { + pix1 = PXMpix(E1pxm16,px,py); + pix3 = PXMpix(E3pxm16,px,py); + pix3[0] = pix1[0]; + pix3[1] = pix1[1]; + pix3[2] = pix1[2]; + } + + for (ii++; ii < Nredmem; ii++) + redmem[ii-1] = redmem[ii]; + Nredmem--; + + Ftoparc = 0; + return; +} + + +// compute red-eye radius limit: smaller of 100 and nearest image edge + +int redeye_radlim(int cx, int cy) +{ + int radlim = 100; + if (cx < 100) radlim = cx; + if (E3ww-1 - cx < 100) radlim = E3ww-1 - cx; + if (cy < 100) radlim = cy; + if (E3hh-1 - cy < 100) radlim = E3hh-1 - cy; + return radlim; +} + + +/**************************************************************************/ + +// image blur function // radius steps of 0.5 v.9.2 + +double blur_radius; +double blur_weight[101][101]; // up to blur radius = 99 v.9.2 +int blur_Npixels, blur_pixdone; +int blur_cancel; + +editfunc EFblur; + + +void m_blur(GtkWidget *, cchar *) +{ + int blur_dialog_event(zdialog *zd, cchar *event); + void * blur_thread(void *); + + zfuncs::F1_help_topic = "blur"; // v.10.8 + + EFblur.funcname = "blur"; + EFblur.Farea = 2; // select area usable + EFblur.threadfunc = blur_thread; // thread function + if (! edit_setup(EFblur)) return; // setup edit + + blur_radius = 0.5; + blur_cancel = 0; + + zdialog *zd = zdialog_new(ZTX("Set Blur Radius"),mWin,Bdone,Bcancel,null); + EFblur.zd = zd; + + zdialog_add_widget(zd,"hbox","hb2","dialog",0,"space=10"); + zdialog_add_widget(zd,"label","labrad","hb2",Bradius,"space=5"); + zdialog_add_widget(zd,"spin","radius","hb2","0|99|0.5|0.5","space=5"); + zdialog_add_widget(zd,"button","apply","hb2",Bapply,"space=5"); + + zdialog_help(zd,"blur"); // zdialog help topic v.11.08 + zdialog_run(zd,blur_dialog_event,"save"); // run dialog - parallel v.11.07 + + return; +} + + +// dialog event and completion callback function + +int blur_dialog_event(zdialog * zd, cchar *event) +{ + if (zd->zstat) + { + if (zd->zstat == 1) edit_done(EFblur); // done + else { + blur_cancel = 1; // v.11.09 + edit_cancel(EFblur); // cancel or destroy + } + return 1; + } + + if (strEqu(event,"blendwidth")) signal_thread(); // v.10.3 + + if (strEqu(event,"apply")) { + zdialog_fetch(zd,"radius",blur_radius); // get blur radius + if (blur_radius == 0) edit_reset(); + else signal_thread(); // trigger working thread + } + + return 1; +} + + +// image blur thread function + +void * blur_thread(void *) +{ + void * blur_wthread(void *arg); + + int dx, dy; + double rad, rad2; + double m, d, w, sum; + + while (true) + { + thread_idle_loop(); // wait for work or exit request + + rad = blur_radius - 0.2; // v.9.2 + rad2 = rad * rad; + + for (dx = 0; dx <= rad+1; dx++) // clear weights array + for (dy = 0; dy <= rad+1; dy++) + blur_weight[dx][dy] = 0; + + for (dx = -rad-1; dx <= rad+1; dx++) // blur_weight[dx][dy] = no. of pixels + for (dy = -rad-1; dy <= rad+1; dy++) // at distance (dx,dy) from center + ++blur_weight[abs(dx)][abs(dy)]; + + m = sqrt(rad2 + rad2); // corner pixel distance from center + sum = 0; + + for (dx = 0; dx <= rad+1; dx++) // compute weight of pixel + for (dy = 0; dy <= rad+1; dy++) // at distance dx, dy + { + d = sqrt(dx*dx + dy*dy); + w = (m + 1.2 - d) / m; // v.9.2 + w = w * w; + sum += blur_weight[dx][dy] * w; + blur_weight[dx][dy] = w; + } + + for (dx = 0; dx <= rad+1; dx++) // make weights add up to 1.0 + for (dy = 0; dy <= rad+1; dy++) + blur_weight[dx][dy] = blur_weight[dx][dy] / sum; + + if (Factivearea) SB_goal = sa_Npixel; + else SB_goal = E3ww * E3hh; + SB_done = 0; // v.11.06 + + for (int ii = 0; ii < Nwt; ii++) // start worker threads + start_wthread(blur_wthread,&wtnx[ii]); + wait_wthreads(); // wait for completion + + SB_goal = 0; + CEF->Fmod = 1; + mwpaint2(); // update window + } + + return 0; // not executed, stop g++ warning +} + + +void * blur_wthread(void *arg) // worker thread function +{ + int index = *((int *) arg); + int px, py, ii, dist = 0; + int jj, dx, dy, adx, ady, rad; + double red, green, blue; + double weight1, weight2, f1, f2; + uint16 *pix1, *pix3, *pixN; + + for (py = index; py < E3hh-1; py += Nwt) // loop all image pixels + for (px = 0; px < E3ww-1; px++) + { + if (blur_cancel) exit_wthread(); // v.11.09 + + if (Factivearea) { // select area active + ii = py * Fww + px; + dist = sa_pixmap[ii]; // distance from edge + if (! dist) continue; // outside pixel + } + + pix1 = PXMpix(E1pxm16,px,py); // source pixel + pix3 = PXMpix(E3pxm16,px,py); // target pixel + + rad = blur_radius; + red = green = blue = 0; + weight2 = 0.0; + + if (Factivearea) // select area active + { + for (dy = -rad-1; dy <= rad+1; dy++) // loop neighbor pixels within radius + for (dx = -rad-1; dx <= rad+1; dx++) + { + if (px+dx < 0 || px+dx > E3ww-1) continue; // omit pixels off edge + if (py+dy < 0 || py+dy > E3hh-1) continue; + jj = (py+dy) * E3ww + (px+dx); + if (! sa_pixmap[jj]) continue; // omit pixels outside area + adx = abs(dx); + ady = abs(dy); + pixN = pix1 + (dy * E3ww + dx) * 3; + weight1 = blur_weight[adx][ady]; // weight at distance (dx,dy) + weight2 += weight1; + red += pixN[0] * weight1; // accumulate contributions + green += pixN[1] * weight1; + blue += pixN[2] * weight1; + } + + red = red / weight2; // weighted average + green = green / weight2; + blue = blue / weight2; + + if (dist < sa_blend) { // select area is active, + f1 = 1.0 * dist / sa_blend; // blend changes over sa_blend + f2 = 1.0 - f1; + red = f1 * red + f2 * pix1[0]; + green = f1 * green + f2 * pix1[1]; + blue = f1 * blue + f2 * pix1[2]; + } + + pix3[0] = int(red); + pix3[1] = int(green); + pix3[2] = int(blue); + } + + else + { + for (dy = -rad-1; dy <= rad+1; dy++) // loop neighbor pixels within radius + for (dx = -rad-1; dx <= rad+1; dx++) + { + if (px+dx < 0 || px+dx > E3ww-1) continue; // omit pixels off edge + if (py+dy < 0 || py+dy > E3hh-1) continue; + adx = abs(dx); + ady = abs(dy); + pixN = pix1 + (dy * E3ww + dx) * 3; + weight1 = blur_weight[adx][ady]; // weight at distance (dx,dy) + weight2 += weight1; + red += pixN[0] * weight1; // accumulate contributions + green += pixN[1] * weight1; + blue += pixN[2] * weight1; + } + + red = red / weight2; // weighted average + green = green / weight2; + blue = blue / weight2; + + pix3[0] = red; + pix3[1] = green; + pix3[2] = blue; + } + + SB_done++; // track progress v.10.6 + } + + exit_wthread(); + return 0; // not executed, avoid gcc warning +} + + +/**************************************************************************/ + +// image sharpening function + +int sharp_ED_cycles; +int sharp_ED_reduce; +int sharp_ED_thresh; +int sharp_UM_radius; +int sharp_UM_amount; +int sharp_UM_thresh; +int sharp_UM_Fcalc; +int sharp_GR_amount; +int sharp_GR_thresh; +char sharp_function[4]; + +editfunc EFsharp; + + +void m_sharpen(GtkWidget *, cchar *) +{ + int sharp_dialog_event(zdialog *zd, cchar *event); + void * sharp_thread(void *); + + zfuncs::F1_help_topic = "sharpen"; // v.10.8 + + EFsharp.funcname = "sharpen"; + EFsharp.Farea = 2; // select area usable + EFsharp.threadfunc = sharp_thread; // thread function + if (! edit_setup(EFsharp)) return; // setup edit + + zdialog *zd = zdialog_new(ZTX("Sharpen Image"),mWin,Bdone,Bcancel,null); + EFsharp.zd = zd; + + zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=5"); + zdialog_add_widget(zd,"vbox","vb11","hb1",0,"space=5"); + zdialog_add_widget(zd,"vbox","vb12","hb1",0,"homog|space=5"); + zdialog_add_widget(zd,"vbox","vb13","hb1",0,"homog|space=5"); + zdialog_add_widget(zd,"button","ED","vb11",ZTX("edge detection"),"space=5"); + zdialog_add_widget(zd,"label","lab11","vb12",ZTX("cycles")); + zdialog_add_widget(zd,"label","lab12","vb12",ZTX("reduce")); + zdialog_add_widget(zd,"label","lab13","vb12",Bthresh); + zdialog_add_widget(zd,"spin","cyclesED","vb13","1|30|1|10"); + zdialog_add_widget(zd,"spin","reduceED","vb13","50|95|1|80"); + zdialog_add_widget(zd,"spin","threshED","vb13","1|99|1|1"); + + zdialog_add_widget(zd,"hsep","sep2","dialog"); + zdialog_add_widget(zd,"hbox","hb2","dialog",0,"space=5"); + zdialog_add_widget(zd,"vbox","vb21","hb2",0,"space=5"); + zdialog_add_widget(zd,"vbox","vb22","hb2",0,"homog|space=5"); + zdialog_add_widget(zd,"vbox","vb23","hb2",0,"homog|space=5"); + zdialog_add_widget(zd,"button","UM","vb21",ZTX("unsharp mask"),"space=5"); + zdialog_add_widget(zd,"label","lab21","vb22",Bradius); + zdialog_add_widget(zd,"label","lab22","vb22",Bamount); + zdialog_add_widget(zd,"label","lab23","vb22",Bthresh); + zdialog_add_widget(zd,"spin","radiusUM","vb23","1|20|1|2"); + zdialog_add_widget(zd,"spin","amountUM","vb23","0|200|1|100"); + zdialog_add_widget(zd,"spin","threshUM","vb23","0|100|1|0"); + + zdialog_add_widget(zd,"hsep","sep3","dialog"); + zdialog_add_widget(zd,"hbox","hb3","dialog",0,"space=5"); + zdialog_add_widget(zd,"vbox","vb31","hb3",0,"space=5"); + zdialog_add_widget(zd,"vbox","vb32","hb3",0,"homog|space=5"); + zdialog_add_widget(zd,"vbox","vb33","hb3",0,"homog|space=5"); + zdialog_add_widget(zd,"button","GR","vb31",ZTX("brightness gradient"),"space=5"); + zdialog_add_widget(zd,"label","lab32","vb32",Bamount); + zdialog_add_widget(zd,"label","lab33","vb32",Bthresh); + zdialog_add_widget(zd,"spin","amountGR","vb33","0|400|1|100"); + zdialog_add_widget(zd,"spin","threshGR","vb33","0|100|1|0"); + + zdialog_help(zd,"sharpen"); // zdialog help topic v.11.08 + zdialog_run(zd,sharp_dialog_event,"save"); // run dialog - parallel v.11.07 + + *sharp_function = 0; + sharp_UM_Fcalc = 1; + return; +} + + +// dialog event and completion callback function + +int sharp_dialog_event(zdialog *zd, cchar *event) +{ + if (zd->zstat) + { + if (zd->zstat == 1) edit_done(EFsharp); + else edit_cancel(EFsharp); + return 0; + } + + if (strEqu(event,"blendwidth")) signal_thread(); // v.10.3 + if (strEqu(event,"radiusUM")) sharp_UM_Fcalc = 1; // must recalculate + + if (strcmpv(event,"ED","UM","GR",null)) + { + edit_reset(); // restore original image + + zdialog_fetch(zd,"cyclesED",sharp_ED_cycles); // get all input values + zdialog_fetch(zd,"reduceED",sharp_ED_reduce); + zdialog_fetch(zd,"threshED",sharp_ED_thresh); + zdialog_fetch(zd,"radiusUM",sharp_UM_radius); + zdialog_fetch(zd,"amountUM",sharp_UM_amount); + zdialog_fetch(zd,"threshUM",sharp_UM_thresh); + zdialog_fetch(zd,"amountGR",sharp_GR_amount); + zdialog_fetch(zd,"threshGR",sharp_GR_thresh); + + strcpy(sharp_function,event); // pass to working thread + signal_thread(); + } + + return 0; +} + + +// sharpen image thread function + +void * sharp_thread(void *) +{ + int sharp_ED(); + int sharp_UM(); + int sharp_GR(); + + while (true) + { + thread_idle_loop(); // wait for work or exit request + + if (strEqu(sharp_function,"ED")) sharp_ED(); // do requested function + if (strEqu(sharp_function,"UM")) sharp_UM(); + if (strEqu(sharp_function,"GR")) sharp_GR(); + + CEF->Fmod = 1; + mwpaint2(); + } + + return 0; // not executed, stop g++ warning +} + + +// image sharpen function by edge detection and compression + +int sharp_ED() +{ + void sharp_pixel_ED(int px, int py, int thresh); + + int sharp_thresh1 = 100; // initial threshold + double sharp_thresh2 = 0.01 * sharp_ED_reduce; // decline rate + int px, py, thresh, cycles; + + thresh = sharp_thresh1; + + if (Factivearea) SB_goal = sa_Npixel; // v.9.6 + else SB_goal = E3ww * E3hh; + SB_goal *= sharp_ED_cycles; + SB_done = 0; // v.11.06 + + for (cycles = 0; cycles < sharp_ED_cycles; cycles++) + { + if (cycles > 0) thresh = int(thresh * sharp_thresh2); + + for (py = 2; py < E3hh-2; py++) + for (px = 2; px < E3ww-2; px++) // loop all pixels + { + sharp_pixel_ED(px,py,thresh); + SB_done++; // track progress v.10.6 + } + } + + SB_goal = 0; + return 1; +} + + +void sharp_pixel_ED(int px, int py, int thresh) +{ + uint16 *pix1, *pix1u, *pix1d; + uint16 *pix3, *pix3u, *pix3d, *pix3uu, *pix3dd; + int ii, dist = 0; + int dd, rgb, pthresh; + int dx[4] = { -1, 0, 1, 1 }; // 4 directions: NW N NE E + int dy[4] = { -1, -1, -1, 0 }; + int pv2, pv2u, pv2d, pv2uu, pv2dd, pvdiff; + double f1, f2; + + if (Factivearea) { // select area active + ii = py * Fww + px; + dist = sa_pixmap[ii]; // distance from edge + if (! dist) return; // outside pixel + } + + pthresh = sharp_ED_thresh; // pthresh = larger + if (thresh > pthresh) pthresh = thresh; + + pix1 = PXMpix(E1pxm16,px,py); // input pixel + pix3 = PXMpix(E3pxm16,px,py); // output pixel + + for (dd = 0; dd < 4; dd++) // 4 directions + { + pix3u = pix3 + (dy[dd] * E3ww + dx[dd]) * 3; // upstream pixel + pix3d = pix3 - (dy[dd] * E3ww - dx[dd]) * 3; // downstream pixel + + for (rgb = 0; rgb < 3; rgb++) // loop 3 RGB colors + { + pv2 = pix3[rgb]; + pv2u = pix3u[rgb]; // brightness difference + pv2d = pix3d[rgb]; // across target pixel + + pvdiff = pv2d - pv2u; + if (pvdiff < 0) pvdiff = -pvdiff; + if (pvdiff < 256 * pthresh) continue; // brightness slope < threshold + + if (pv2u < pv2 && pv2 < pv2d) // slope up, monotone + { + pix3uu = pix3u + (dy[dd] * E3ww + dx[dd]) * 3; // upstream of upstream pixel + pix3dd = pix3d - (dy[dd] * E3ww - dx[dd]) * 3; // downstream of downstream + pv2uu = pix3uu[rgb]; + pv2dd = pix3dd[rgb]; + + if (pv2uu >= pv2u) { // shift focus of changes to + pix3u = pix3; // avoid up/down/up jaggies + pv2u = pv2; + } + + if (pv2dd <= pv2d) { + pix3d = pix3; + pv2d = pv2; + } + + if (pv2u > 256) pv2u -= 256; + if (pv2d < 65279) pv2d += 256; + } + + else if (pv2u > pv2 && pv2 > pv2d) // slope down, monotone + { + pix3uu = pix3u + (dy[dd] * E3ww + dx[dd]) * 3; + pix3dd = pix3d - (dy[dd] * E3ww - dx[dd]) * 3; + pv2uu = pix3uu[rgb]; + pv2dd = pix3dd[rgb]; + + if (pv2uu <= pv2u) { + pix3u = pix3; + pv2u = pv2; + } + + if (pv2dd >= pv2d) { + pix3d = pix3; + pv2d = pv2; + } + + if (pv2d > 256) pv2d -= 256; + if (pv2u < 65279) pv2u += 256; + } + + else continue; // slope too small + + if (Factivearea && dist < sa_blend) { // select area is active, + f1 = 1.0 * dist / sa_blend; // blend changes over sa_blend + f2 = 1.0 - f1; + pix1u = pix1 + (dy[dd] * E1ww + dx[dd]) * 3; // upstream input pixel + pix1d = pix1 - (dy[dd] * E1ww - dx[dd]) * 3; // downstream input pixel + pv2u = int(f1 * pv2u + f2 * pix1u[rgb]); + pv2d = int(f1 * pv2d + f2 * pix1d[rgb]); + } + + pix3u[rgb] = pv2u; // modified brightness values + pix3d[rgb] = pv2d; // >> image3 pixel + } + } + + return; +} + + +// image sharpen function using unsharp mask + +int sharp_UM() +{ + void * sharp_UM_wthread(void *arg); + + int ii; + + if (sharp_UM_Fcalc) { // speedup v.9.6 + sharp_UM_Fcalc = 0; + brhood_calc(sharp_UM_radius,'f'); + } + + if (Factivearea) SB_goal = sa_Npixel; // v.9.6 + else SB_goal = E3ww * E3hh; + SB_done = 0; // v.11.06 + + for (ii = 0; ii < Nwt; ii++) // start worker threads + start_wthread(sharp_UM_wthread,&wtnx[ii]); + wait_wthreads(); // wait for completion + + SB_goal = 0; + return 1; +} + + +void * sharp_UM_wthread(void *arg) // worker thread function +{ + void sharp_pixel_UM(int px, int py, int index); + + int index = *((int *) arg); + int px, py; + + for (py = index; py < E3hh; py += Nwt) // loop all image3 pixels + for (px = 0; px < E3ww; px++) + sharp_pixel_UM(px,py,index); + + exit_wthread(); + return 0; // not executed, avoid gcc warning +} + + +void sharp_pixel_UM(int px, int py, int index) // process one pixel +{ // revised v.9.6 + int ii, dist = 0; + double amount, thresh, bright; + double mean, incr, ratio, f1, f2; + double red1, green1, blue1, red3, green3, blue3; + uint16 *pix1, *pix3; + + if (Factivearea) { // select area active + ii = py * Fww + px; + dist = sa_pixmap[ii]; // distance from edge + if (! dist) return; // outside pixel + } + + amount = 0.01 * sharp_UM_amount; // 0.0 to 2.0 + thresh = 100 * sharp_UM_thresh; // 0 to 10K (64K max. possible) + + pix1 = PXMpix(E1pxm16,px,py); // input pixel + pix3 = PXMpix(E3pxm16,px,py); // output pixel + + bright = pixbright(pix1); + if (bright < 100) return; // effectively black + mean = get_brhood(px,py); + incr = (bright - mean); + if (fabs(incr) < thresh) return; // omit low-contrast pixels + + incr = incr * amount; // 0.0 to 2.0 + if (bright + incr > 65535) incr = 65535 - bright; + ratio = (bright + incr) / bright; + if (ratio < 0) ratio = 0; // v.11.08 + + red1 = pix1[0]; // input RGB + green1 = pix1[1]; + blue1 = pix1[2]; + + red3 = ratio * red1; // output RGB + if (red3 > 65535) red3 = 65535; + green3 = ratio * green1; + if (green3 > 65535) green3 = 65535; + blue3 = ratio * blue1; + if (blue3 > 65535) blue3 = 65535; + + if (Factivearea && dist < sa_blend) { // select area is active, + f1 = 1.0 * dist / sa_blend; // blend changes over sa_blend + f2 = 1.0 - f1; + red3 = f1 * red3 + f2 * red1; + green3 = f1 * green3 + f2 * green1; + blue3 = f1 * blue3 + f2 * blue1; + } + + pix3[0] = red3; + pix3[1] = green3; + pix3[2] = blue3; + + SB_done++; // track progress v.10.6 + return; +} + + +// sharpen image by increasing brightness gradient // new v.9.8 + +int sharp_GR() +{ + uint16 *pix1, *pix3; + int ii, px, py, dist = 0; + double amount, thresh; + double b1, b1x, b1y, b3x, b3y, b3, bf, f1, f2; + double red1, green1, blue1, red3, green3, blue3; + + amount = 1 + 0.01 * sharp_GR_amount; // 1.0 - 5.0 + thresh = 655.35 * sharp_GR_thresh; // 0 - 64K + + if (Factivearea) SB_goal = sa_Npixel; + else SB_goal = E3ww * E3hh; + SB_done = 0; // v.11.06 + + for (py = 1; py < E1hh; py++) // loop all image pixels + for (px = 1; px < E1ww; px++) + { + if (Factivearea) { // select area active + ii = py * Fww + px; + dist = sa_pixmap[ii]; // distance from edge + if (! dist) continue; // pixel is outside area + } + + pix1 = PXMpix(E1pxm16,px,py); // input pixel + pix3 = PXMpix(E3pxm16,px,py); // output pixel + + b1 = pixbright(pix1); // pixel brightness, 0 - 64K + b1x = b1 - pixbright(pix1 - 3); // brightness gradient (x,y) + b1y = b1 - pixbright(pix1 - 3 * E1ww); + + if (abs(b1x + b1y) < thresh) // moderate brightness change for + f1 = abs(b1x + b1y) / thresh; // pixels below threshold gradient + else f1 = 1.0; // v.10.9 + f2 = 1.0 - f1; + + b1x = b1x * amount; // amplified gradient + b1y = b1y * amount; + + b3x = pixbright(pix1 - 3) + b1x; // + prior pixel brightness + b3y = pixbright(pix1 - 3 * E3ww) + b1y; // = new brightness + b3 = 0.5 * (b3x + b3y); + + b3 = f1 * b3 + f2 * b1; // possibly moderated v.10.9 + + bf = b3 / b1; // ratio of brightness change + if (bf < 0) bf = 0; + if (bf > 4) bf = 4; + + red1 = pix1[0]; // input RGB + green1 = pix1[1]; + blue1 = pix1[2]; + + red3 = bf * red1; // output RGB + if (red3 > 65535) red3 = 65535; + green3 = bf * green1; + if (green3 > 65535) green3 = 65535; + blue3 = bf * blue1; + if (blue3 > 65535) blue3 = 65535; + + if (Factivearea && dist < sa_blend) { // select area is active, + f1 = 1.0 * dist / sa_blend; // blend changes over sa_blend + f2 = 1.0 - f1; + red3 = f1 * red3 + f2 * red1; + green3 = f1 * green3 + f2 * green1; + blue3 = f1 * blue3 + f2 * blue1; + } + + pix3[0] = red3; + pix3[1] = green3; + pix3[2] = blue3; + + SB_done++; // track progress v.10.6 + } + + SB_goal = 0; + return 1; +} + + +/**************************************************************************/ + +// image noise reduction + +int denoise_method = 5; // default algorithm +int denoise_radius = 4; + +editfunc EFdenoise; + + +void m_denoise(GtkWidget *, cchar *) +{ + int denoise_dialog_event(zdialog *zd, cchar *event); // dialog event function + void * denoise_thread(void *); + + cchar *denoise_message = ZTX(" Press the reduce button to \n" + " reduce noise in small steps. \n" + " Use undo to start over."); + + zfuncs::F1_help_topic = "reduce_noise"; // v.10.8 + + EFdenoise.funcname = "denoise"; + EFdenoise.Farea = 2; // select area usable + EFdenoise.threadfunc = denoise_thread; // thread function + if (! edit_setup(EFdenoise)) return; // setup edit + + zdialog *zd = zdialog_new(ZTX("Noise Reduction"),mWin,Bdone,Bcancel,null); + EFdenoise.zd = zd; + + zdialog_add_widget(zd,"label","lab1","dialog",denoise_message,"space=5"); + zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=5"); + zdialog_add_widget(zd,"label","labalg","hb1",ZTX("algorithm"),"space=5"); + zdialog_add_widget(zd,"combo","method","hb1",0,"space=5|expand"); + zdialog_add_widget(zd,"hbox","hb2","dialog",0,"space=5"); + zdialog_add_widget(zd,"label","labrad","hb2",Bradius,"space=5"); + zdialog_add_widget(zd,"spin","radius","hb2","1|9|1|4","space=5"); + zdialog_add_widget(zd,"button","reduce","hb2",Breduce,"space=5"); + + zdialog_cb_app(zd,"method",ZTX("flatten outliers by color (1)")); + zdialog_cb_app(zd,"method",ZTX("flatten outliers by color (2)")); + zdialog_cb_app(zd,"method",ZTX("set median brightness by color")); + zdialog_cb_app(zd,"method",ZTX("top hat filter by color")); + zdialog_stuff(zd,"method",ZTX("top hat filter by color")); // default + + zdialog_help(zd,"reduce_noise"); // zdialog help topic v.11.08 + zdialog_run(zd,denoise_dialog_event,"save"); // run dialog - parallel v.11.07 + return; +} + + +// dialog event and completion callback function + +int denoise_dialog_event(zdialog * zd, cchar *event) +{ + char method[40]; + + if (zd->zstat) + { + if (zd->zstat == 1) edit_done(EFdenoise); + else edit_cancel(EFdenoise); + return 0; + } + + if (strEqu(event,"blendwidth")) signal_thread(); // trigger update thread + + if (strEqu(event,"radius")) + zdialog_fetch(zd,"radius",denoise_radius); + + if (strEqu(event,"method")) + { + zdialog_fetch(zd,"method",method,39); + + if (strEqu(method,"flatten outliers by color (1)")) { + denoise_method = 1; + denoise_radius = 1; + } + + if (strEqu(method,"flatten outliers by color (2)")) { + denoise_method = 2; + denoise_radius = 3; + } + + if (strEqu(method,"set median brightness by color")) { + denoise_method = 4; + denoise_radius = 2; + } + + if (strEqu(method,"top hat filter by color")) { + denoise_method = 5; + denoise_radius = 4; + } + + zdialog_stuff(zd,"radius",denoise_radius); + } + + if (strEqu(event,"reduce")) signal_thread(); // trigger update thread + + return 1; +} + + +// image noise reduction thread + +void * denoise_thread(void *) +{ + void * denoise_wthread(void *arg); + + int ii; + + while (true) + { + thread_idle_loop(); // wait for work or exit request + + E9pxm16 = PXM_copy(E3pxm16); // image3 is reference source + // image9 will be modified + if (Factivearea) SB_goal = sa_Npixel; + else SB_goal = E3ww * E3hh; + SB_done = 0; // v.11.06 + + for (ii = 0; ii < Nwt; ii++) // start worker threads + start_wthread(denoise_wthread,&wtnx[ii]); + wait_wthreads(); // wait for completion + + SB_goal = 0; + + mutex_lock(&Fpixmap_lock); + PXM_free(E3pxm16); // image9 >> image3 + E3pxm16 = E9pxm16; + E9pxm16 = 0; + mutex_unlock(&Fpixmap_lock); + + CEF->Fmod = 1; + mwpaint2(); // update window + } + + return 0; // not executed, stop g++ warning +} + + +void * denoise_wthread(void *arg) // worker thread function +{ + void denoise_func1(uint16 *pix3, uint16 *pix9); + void denoise_func2(uint16 *pix3, uint16 *pix9); + void denoise_func4(uint16 *pix3, uint16 *pix9); + void denoise_func5(uint16 *pix3, uint16 *pix9); + + int index = *((int *) arg); + int ii, px, py, rad, dist = 0; + double f1, f2; + uint16 *pix1, *pix3, *pix9; + + rad = denoise_radius; + + for (py = index+rad; py < E3hh-rad; py += Nwt) // loop all image3 pixels + for (px = rad; px < E3ww-rad; px++) + { + if (Factivearea) { // select area active + ii = py * Fww + px; + dist = sa_pixmap[ii]; // distance from edge + if (! dist) continue; // outside pixel + } + + pix3 = PXMpix(E3pxm16,px,py); // source pixel + pix9 = PXMpix(E9pxm16,px,py); // target pixel + + if (denoise_method == 1) denoise_func1(pix3,pix9); + if (denoise_method == 2) denoise_func2(pix3,pix9); + if (denoise_method == 4) denoise_func4(pix3,pix9); + if (denoise_method == 5) denoise_func5(pix3,pix9); + + if (Factivearea && dist < sa_blend) { // select area is active, + f1 = 1.0 * dist / sa_blend; // blend changes over sa_blend + f2 = 1.0 - f1; + pix1 = PXMpix(E1pxm16,px,py); // source pixel + pix9[0] = int(f1 * pix9[0] + f2 * pix1[0]); + pix9[1] = int(f1 * pix9[1] + f2 * pix1[1]); + pix9[2] = int(f1 * pix9[2] + f2 * pix1[2]); + } + + SB_done++; // track progress v.10.6 + } + + exit_wthread(); + return 0; // not executed, avoid gcc warning +} + + +// flatten outliers within radius, by color +// an outlier is the max or min value within a radius + +void denoise_func1(uint16 *pix3, uint16 *pix9) +{ + int dy, dx, rad; + int min0, min1, min2, max0, max1, max2; + uint16 *pixN; + + min0 = min1 = min2 = 65535; + max0 = max1 = max2 = 0; + rad = denoise_radius; + + for (dy = -rad; dy <= rad; dy++) // loop surrounding pixels + for (dx = -rad; dx <= rad; dx++) + { + if (dy == 0 && dx == 0) continue; // skip self + + pixN = pix3 + (dy * E3ww + dx) * 3; + if (pixN[0] < min0) min0 = pixN[0]; // find min and max per color + if (pixN[0] > max0) max0 = pixN[0]; + if (pixN[1] < min1) min1 = pixN[1]; + if (pixN[1] > max1) max1 = pixN[1]; + if (pixN[2] < min2) min2 = pixN[2]; + if (pixN[2] > max2) max2 = pixN[2]; + } + + if (pix3[0] <= min0 && min0 < 65279) pix9[0] = min0 + 256; // if outlier, flatten a little + if (pix3[0] >= max0 && max0 > 256) pix9[0] = max0 - 256; + if (pix3[1] <= min1 && min1 < 65279) pix9[1] = min1 + 256; + if (pix3[1] >= max1 && max1 > 256) pix9[1] = max1 - 256; + if (pix3[2] <= min2 && min2 < 65279) pix9[2] = min2 + 256; + if (pix3[2] >= max2 && max2 > 256) pix9[2] = max2 - 256; + + return; +} + + +// flatten outliers +// An outlier pixel has an RGB value outside one sigma of +// the mean for all pixels within a given radius of the pixel. + +void denoise_func2(uint16 *pix3, uint16 *pix9) +{ + int rgb, dy, dx, rad, nn; + double nn1, val, sum, sum2, mean, variance, sigma; + uint16 *pixN; + + rad = denoise_radius; + nn = (rad * 2 + 1); + nn = nn * nn - 1; + nn1 = 1.0 / nn; + + for (rgb = 0; rgb < 3; rgb++) // loop RGB color + { + sum = sum2 = 0; + + for (dy = -rad; dy <= rad; dy++) // loop surrounding pixels + for (dx = -rad; dx <= rad; dx++) + { + if (dy == 0 && dx == 0) continue; // skip self + pixN = pix3 + (dy * E3ww + dx) * 3; + val = pixN[rgb]; + sum += val; + sum2 += val * val; + } + + mean = nn1 * sum; + variance = nn1 * (sum2 - 2.0 * mean * sum) + mean * mean; + sigma = sqrt(variance); + + val = pix3[rgb]; + if (val > mean + sigma) { // move value to mean +/- sigma + val = mean + sigma; + pix9[rgb] = val; + } + else if (val < mean - sigma) { + val = mean - sigma; + pix9[rgb] = val; + } + } + + return; +} + + +// use median brightness for pixels within radius + +void denoise_func4(uint16 *pix3, uint16 *pix9) +{ + int dy, dx, rad; + int ns, rgb, bsortN[400]; + uint16 *pixN; + + rad = denoise_radius; + + for (rgb = 0; rgb < 3; rgb++) // loop all RGB colors + { + ns = 0; + + for (dy = -rad; dy <= rad; dy++) // loop surrounding pixels + for (dx = -rad; dx <= rad; dx++) // get brightness values + { + pixN = pix3 + (dy * E3ww + dx) * 3; + bsortN[ns] = pixN[rgb]; + ns++; + } + + HeapSort(bsortN,ns); + pix9[rgb] = bsortN[ns/2]; // median brightness of ns pixels + } + + return; +} + + +// modified top hat filter: execute with increasing radius from 1 to limit +// detect outlier by comparing with pixels in outer radius + +void denoise_func5(uint16 *pix3, uint16 *pix9) +{ + int dy, dx, rad; + int min0, min1, min2, max0, max1, max2; + uint16 *pixN; + + for (rad = 1; rad <= denoise_radius; rad++) + for (int loops = 0; loops < 2; loops++) + { + min0 = min1 = min2 = 65535; + max0 = max1 = max2 = 0; + + for (dy = -rad; dy <= rad; dy++) // loop all pixels within rad + for (dx = -rad; dx <= rad; dx++) + { + if (dx > -rad && dx < rad) continue; // skip inner pixels + if (dy > -rad && dy < rad) continue; + + pixN = pix3 + (dy * E3ww + dx) * 3; + if (pixN[0] < min0) min0 = pixN[0]; // find min and max per color + if (pixN[0] > max0) max0 = pixN[0]; // among outermost pixels + if (pixN[1] < min1) min1 = pixN[1]; + if (pixN[1] > max1) max1 = pixN[1]; + if (pixN[2] < min2) min2 = pixN[2]; + if (pixN[2] > max2) max2 = pixN[2]; + } + + if (pix3[0] < min0 && pix9[0] < 65279) pix9[0] += 256; // if central pixel is outlier, + if (pix3[0] > max0 && pix9[0] > 256) pix9[0] -= 256; // moderate its values + if (pix3[1] < min1 && pix9[1] < 65279) pix9[1] += 256; + if (pix3[1] > max1 && pix9[1] > 256) pix9[1] -= 256; + if (pix3[2] < min2 && pix9[2] < 65279) pix9[2] += 256; + if (pix3[2] > max2 && pix9[2] > 256) pix9[2] -= 256; + } + + return; +} + + +/**************************************************************************/ + +// Smart Erase menu function - Replace pixels inside a select area +// with a reflection of pixels outside the area. + +editfunc EFerase; + +void m_smart_erase(GtkWidget *, const char *) // overhauled v.11.04 +{ + int smart_erase_dialog_event(zdialog* zd, const char *event); + + int cc; + cchar *erase_message = ZTX("1. Drag mouse to select. \n" + "2. Erase. 3. Repeat. "); + + zfuncs::F1_help_topic = "smart_erase"; + + EFerase.funcname = "smart-erase"; + EFerase.Farea = 0; // select area deleted + EFerase.mousefunc = sa_mouse_mousefunc; // mouse function (use select area) v.11.12 + if (! edit_setup(EFerase)) return; // setup edit + +/* ______________________________ + | | + | 1. Drag mouse to select. | + | 2. Erase. 3. Repeat. | + | | + | Radius [10|v] Blur [0.5|v] | + | [New Area] [Erase] [Undo] | + | | + | [Done] | + |______________________________| +*/ + + zdialog *zd = zdialog_new(ZTX("Smart Erase"),mWin,Bdone,null); + EFerase.zd = zd; + + zdialog_add_widget(zd,"label","lab1","dialog",erase_message,"space=8"); + zdialog_add_widget(zd,"hbox","hb2","dialog",0,"space=5"); + zdialog_add_widget(zd,"label","labr","hb2",ZTX("Radius"),"space=5"); + zdialog_add_widget(zd,"spin","radius","hb2","1|20|1|5"); + zdialog_add_widget(zd,"label","labb","hb2",ZTX("Blur"),"space=5"); + zdialog_add_widget(zd,"spin","blur","hb2","0|9|0.5|0.5"); + zdialog_add_widget(zd,"hbox","hb3","dialog",0,"space=5"); + zdialog_add_widget(zd,"button","newarea","hb3",ZTX("New Area"),"space=10"); + zdialog_add_widget(zd,"button","erase","hb3",Berase,"space=10"); + zdialog_add_widget(zd,"button","undo1","hb3",Bundo,"space=5"); + + zdialog_help(zd,"smart_erase"); // zdialog help topic v.11.08 + zdialog_run(zd,smart_erase_dialog_event,"save"); // run dialog - parallel v.11.07 + + sa_unselect(); // unselect area if any v.11.06.1 + cc = Fww * Fhh * sizeof(uint16); // create new area + sa_pixmap = (uint16 *) zmalloc(cc,"smart_erase"); + memset(sa_pixmap,0,cc); + sa_mode = 5; // mode = select by mouse + sa_stat = 1; // status = active edit + sa_fww = Fww; // v.11.08 + sa_fhh = Fhh; + sa_matchcolor = 0; // no color matching v.11.12 + sa_searchrange = 1; // search within mouse radius v.11.12 + sa_show(1); + + sa_mouseradius = 5; // initial mouse select radius + return; +} + + +// dialog event and completion function + +int smart_erase_dialog_event(zdialog *zd, const char *event) // overhauled v.11.04 +{ + void smart_erase_func(int mode); + void smart_erase_blur(double radius); + + double radius; + int cc; + + if (zd->zstat) { + sa_unselect(); + if (zd->zstat == 1) edit_done(EFerase); + else edit_cancel(EFerase); + return 0; + } + + if (strEqu(event,"focus")) { // toggle mouse capture + sa_stat = 1; // status = active edit + takeMouse(zd,sa_mouse_mousefunc,0); // use select area by mouse function + sa_show(1); + } + + if (strEqu(event,"newarea")) { + sa_unselect(); + cc = Fww * Fhh * sizeof(uint16); // create new area + sa_pixmap = (uint16 *) zmalloc(cc,"smart_erase"); + memset(sa_pixmap,0,cc); + sa_mode = 5; // mode = select by mouse + sa_stat = 1; // status = active edit + sa_fww = Fww; // v.11.08 + sa_fhh = Fhh; + sa_show(1); + } + + if (strEqu(event,"radius")) + zdialog_fetch(zd,"radius",sa_mouseradius); + + if (strEqu(event,"erase")) { // do smart erase + sa_finish_auto(); // finish the area + smart_erase_func(1); + zdialog_fetch(zd,"blur",radius); // add optional blur + if (radius > 0) smart_erase_blur(radius); + sa_show(0); + freeMouse(); // disconnect mouse + } + + if (strEqu(event,"undo1")) // dialog undo, undo last erase + smart_erase_func(2); + + return 0; +} + + +// erase the area or restore last erased area + +void smart_erase_func(int mode) +{ + int px, py, npx, npy; + int qx, qy, sx, sy, tx, ty; + int ii, rad, inc, cc; + int dist2, mindist2; + double slope; + char *pmap; + uint16 *pix1, *pix3; + + if (! Factivearea) return; // nothing selected v.11.05 + + for (py = sa_miny; py < sa_maxy; py++) // loop all pixels in area + for (px = sa_minx; px < sa_maxx; px++) + { + ii = py * Fww + px; + if (! sa_pixmap[ii]) continue; // pixel not selected + + pix1 = PXMpix(E1pxm16,px,py); // input pixel + pix3 = PXMpix(E3pxm16,px,py); // output pixel + + pix3[0] = pix1[0]; // restore pixels inside area + pix3[1] = pix1[1]; + pix3[2] = pix1[2]; + } + + mwpaint2(); // update window + + if (mode == 2) return; // mode = undo, done + + cc = Fww * Fhh; // allocate pixel done map + pmap = (char *) zmalloc(cc,"smart_erase"); + memset(pmap,0,cc); + + for (py = sa_miny; py < sa_maxy; py++) // loop all pixels in area + for (px = sa_minx; px < sa_maxx; px++) + { + ii = py * Fww + px; + if (! sa_pixmap[ii]) continue; // pixel not selected + if (pmap[ii]) continue; // pixel already done + + mindist2 = 999999; // find nearest edge + npx = npy = 0; + + for (rad = 1; rad < 50; rad++) // 50 pixel limit v.11.05 + { + for (qx = px-rad; qx <= px+rad; qx++) // search within rad v.11.05 + for (qy = py-rad; qy <= py+rad; qy++) + { + if (qx < 0 || qx >= Fww) continue; // off image edge modified v.11.09 + if (qy < 0 || qy >= Fhh) continue; + ii = qy * Fww + qx; + if (sa_pixmap[ii]) continue; // within selected area + + dist2 = (px-qx) * (px-qx) + (py-qy) * (py-qy); // distance**2 to edge pixel + if (dist2 < mindist2) { + mindist2 = dist2; + npx = qx; // save nearest edge pixel found + npy = qy; + } + } + + if (rad * rad >= mindist2) break; // can quit now + } + + if (! npx && ! npy) continue; // edge not found, should not happen + + qx = npx; // nearest edge pixel + qy = npy; + + if (abs(qy - py) > abs(qx - px)) { // qx/qy = near edge from px/py + slope = 1.0 * (qx - px) / (qy - py); + if (qy > py) inc = 1; + else inc = -1; + for (sy = py; sy != qy; sy += inc) // line from px/py to qx/qy v.11.06 + { + sx = px + slope * (sy - py); + ii = sy * Fww + sx; + if (pmap[ii]) continue; // v.11.06 + pmap[ii] = 1; + tx = qx + (qx - sx); // tx/ty = parallel line from qx/qy + ty = qy + (qy - sy); // modified v.11.09 + if (tx < 0) tx = 0; + if (tx > Fww-1) tx = Fww-1; + if (ty < 0) ty = 0; + if (ty > Fhh-1) ty = Fhh-1; + pix1 = PXMpix(E3pxm16,tx,ty); // copy pixel from tx/ty to sx/sy + pix3 = PXMpix(E3pxm16,sx,sy); + pix3[0] = pix1[0]; + pix3[1] = pix1[1]; + pix3[2] = pix1[2]; + } + } + + else { + slope = 1.0 * (qy - py) / (qx - px); + if (qx > px) inc = 1; + else inc = -1; + for (sx = px; sx != qx; sx += inc) + { + sy = py + slope * (sx - px); + ii = sy * Fww + sx; + if (pmap[ii]) continue; + pmap[ii] = 1; + tx = qx + (qx - sx); + ty = qy + (qy - sy); + if (tx < 0) tx = 0; + if (tx > Fww-1) tx = Fww-1; + if (ty < 0) ty = 0; + if (ty > Fhh-1) ty = Fhh-1; + pix1 = PXMpix(E3pxm16,tx,ty); + pix3 = PXMpix(E3pxm16,sx,sy); + pix3[0] = pix1[0]; + pix3[1] = pix1[1]; + pix3[2] = pix1[2]; + } + } + } + + zfree(pmap); // free memory + CEF->Fmod = 1; + mwpaint2(); // update window + return; +} + + +// add blur to the erased area to help mask the side-effects + +int smart_erase_blur(double radius) +{ + int ii, px, py, dx, dy, adx, ady; + double blur_weight[10][10]; // up to blur radius = 9 + double rad, rad2; + double m, d, w, sum; + double red, green, blue; + double weight1, weight2; + uint16 *pix9, *pix3, *pixN; + + if (! Factivearea) return 0; + + rad = radius - 0.2; + rad2 = rad * rad; + + for (dx = 0; dx <= rad+1; dx++) // clear weights array + for (dy = 0; dy <= rad+1; dy++) + blur_weight[dx][dy] = 0; + + for (dx = -rad-1; dx <= rad+1; dx++) // blur_weight[dx][dy] = no. of pixels + for (dy = -rad-1; dy <= rad+1; dy++) // at distance (dx,dy) from center + ++blur_weight[abs(dx)][abs(dy)]; + + m = sqrt(rad2 + rad2); // corner pixel distance from center + sum = 0; + + for (dx = 0; dx <= rad+1; dx++) // compute weight of pixel + for (dy = 0; dy <= rad+1; dy++) // at distance dx, dy + { + d = sqrt(dx*dx + dy*dy); + w = (m + 1.2 - d) / m; + w = w * w; + sum += blur_weight[dx][dy] * w; + blur_weight[dx][dy] = w; + } + + for (dx = 0; dx <= rad+1; dx++) // make weights add up to 1.0 + for (dy = 0; dy <= rad+1; dy++) + blur_weight[dx][dy] = blur_weight[dx][dy] / sum; + + E9pxm16 = PXM_copy(E3pxm16); // copy edited image + + for (py = sa_miny; py < sa_maxy; py++) // loop all pixels in area + for (px = sa_minx; px < sa_maxx; px++) + { + ii = py * Fww + px; + if (! sa_pixmap[ii]) continue; // pixel not in area + + pix9 = PXMpix(E9pxm16,px,py); // source pixel + pix3 = PXMpix(E3pxm16,px,py); // target pixel + + rad = radius; + red = green = blue = 0; + weight2 = 0.0; + + for (dy = -rad-1; dy <= rad+1; dy++) // loop neighbor pixels within radius + for (dx = -rad-1; dx <= rad+1; dx++) + { + if (px+dx < 0 || px+dx >= E3ww) continue; // omit pixels off edge + if (py+dy < 0 || py+dy >= E3hh) continue; + adx = abs(dx); + ady = abs(dy); + pixN = pix9 + (dy * E3ww + dx) * 3; + weight1 = blur_weight[adx][ady]; // weight at distance (dx,dy) + weight2 += weight1; + red += pixN[0] * weight1; // accumulate contributions + green += pixN[1] * weight1; + blue += pixN[2] * weight1; + } + + red = red / weight2; // weighted average + green = green / weight2; + blue = blue / weight2; + + pix3[0] = int(red); + pix3[1] = int(green); + pix3[2] = int(blue); + } + + PXM_free(E9pxm16); + + CEF->Fmod = 1; + mwpaint2(); // update window + return 0; +} + + +/**************************************************************************/ + +// find and remove "dust" from an image (e.g. from a scanned dusty slide) +// dust is defined as small dark areas surrounded by brighter areas +// image 1 original with prior edits +// image 3 accumulated dust removals that have been comitted +// image 9 comitted dust removals + pending removal (work in process) + +namespace dust_names +{ + editfunc EFdust; + + int spotspann; // max. dustspot spann, pixels + int spotspann2; // spotspann **2 + double brightness; // brightness limit, 0 to 1 = white + double contrast; // min. contrast, 0 to 1 = black/white + int *pixgroup; // maps (px,py) to pixel group no. + int Fred; // red pixels are on + + int Nstack; + + struct spixstack { + uint16 px, py; // pixel group search stack + uint16 direc; + } *pixstack; + + #define maxgroups 1000000 + int Ngroups; + int groupcount[maxgroups]; // count of pixels in each group + double groupbright[maxgroups]; // + int edgecount[maxgroups]; // group edge pixel count + double edgebright[maxgroups]; // group edge pixel brightness sum + + typedef struct { + uint16 px1, py1, px2, py2; // pixel group extreme pixels + int spann2; // spann from px1/py1 to px2/py2 + } sgroupspann; + + sgroupspann groupspann[maxgroups]; +} + + +void m_dust(GtkWidget *, const char *) // new v.11.05 +{ + using namespace dust_names; + + int dust_dialog_event(zdialog *zd, cchar *event); + void * dust_thread(void *); + + zfuncs::F1_help_topic = "remove_dust"; // v.11.05.1 + + EFdust.funcname = "dust"; + EFdust.Farea = 2; // select area usable + EFdust.threadfunc = dust_thread; // thread function + if (! edit_setup(EFdust)) return; // setup edit + + E9pxm16 = PXM_copy(E3pxm16); // image 9 = copy of image3 + Fred = 0; + + int cc = Fww * Fhh * sizeof(int); + pixgroup = (int *) zmalloc(cc,"erase_dust"); // maps pixels to assigned groups + + cc = Fww * Fhh * sizeof(spixstack); + pixstack = (spixstack *) zmalloc(cc,"erase_dust"); // pixel group search stack + +/*** + Remove Dust + + spot size limit =========[]=========== + max. brightness =============[]======= + min. contrast ========[]============ + [erase] [red] [undo last] [apply] + + [Done] [Cancel] +***/ + + zdialog *zd = zdialog_new(ZTX("Remove Dust"),mWin,Bdone,Bcancel,null); + EFdust.zd = zd; + + zdialog_add_widget(zd,"hbox","hbssl","dialog",0,"space=1"); + zdialog_add_widget(zd,"label","labssl","hbssl",ZTX("spot size limit"),"space=5"); + zdialog_add_widget(zd,"hscale","spotspann","hbssl","1|50|1|20","space=5|expand"); + zdialog_add_widget(zd,"hbox","hbmb","dialog",0,"space=1"); + zdialog_add_widget(zd,"label","labmb","hbmb",ZTX("max. brightness"),"space=5"); + zdialog_add_widget(zd,"hscale","brightness","hbmb","1|999|1|700","space=5|expand"); + zdialog_add_widget(zd,"hbox","hbmc","dialog",0,"space=1"); + zdialog_add_widget(zd,"label","labmb","hbmc",ZTX("min. contrast"),"space=5"); + zdialog_add_widget(zd,"hscale","contrast","hbmc","1|500|1|50","space=5|expand"); + zdialog_add_widget(zd,"hbox","hbbutts","dialog",0,"space=5"); + zdialog_add_widget(zd,"button","erase","hbbutts",Berase,"space=5"); + zdialog_add_widget(zd,"button","red","hbbutts",Bred,"space=5"); + zdialog_add_widget(zd,"button","undo1","hbbutts",Bundolast,"space=5"); + zdialog_add_widget(zd,"button","apply","hbbutts",Bapply,"space=5"); + + zdialog_fetch(zd,"spotspann",spotspann); // max. dustspot spann (pixels) + spotspann2 = spotspann * spotspann; + + zdialog_fetch(zd,"brightness",brightness); // max. dustspot brightness + brightness = 0.001 * brightness; // scale 0 to 1 = white + + zdialog_fetch(zd,"contrast",contrast); // min. dustspot contrast + contrast = 0.001 * contrast; // scale 0 to 1 = black/white + + zdialog_resize(zd,300,0); + zdialog_help(zd,"remove_dust"); // zdialog help topic v.11.08 + zdialog_run(zd,dust_dialog_event,"save"); // run dialog - parallel v.11.07 + + signal_thread(); + return; +} + + +// dialog event and completion callback function + +int dust_dialog_event(zdialog *zd, cchar *event) +{ + using namespace dust_names; + + void dust_erase(); + + if (zd->zstat) // dialog complete + { + if (zd->zstat == 1) { // done, use committed changes + mutex_lock(&Fpixmap_lock); + PXM_free(E3pxm16); + E3pxm16 = E9pxm16; // image 3 = image 9 + E9pxm16 = 0; + mutex_unlock(&Fpixmap_lock); + edit_done(EFdust); + } + else { // cancel, discard changes + PXM_free(E9pxm16); + edit_cancel(EFdust); + } + + zfree(pixgroup); // free memory + zfree(pixstack); + return 0; + } + + if (strEqu(event,"spotspann") || strEqu(event,"brightness") + || strEqu(event,"contrast") || strEqu(event,"red")) + { + zdialog_fetch(zd,"spotspann",spotspann); // max. dustspot spann (pixels) + spotspann2 = spotspann * spotspann; + + zdialog_fetch(zd,"brightness",brightness); // max. dustspot brightness + brightness = 0.001 * brightness; // scale 0 to 1 = white + + zdialog_fetch(zd,"contrast",contrast); // min. dustspot contrast + contrast = 0.001 * contrast; // scale 0 to 1 = black/white + + signal_thread(); // do the work + } + + if (strEqu(event,"erase")) dust_erase(); + if (strEqu(event,"blendwidth")) dust_erase(); + + if (strEqu(event,"undo1")) { + mutex_lock(&Fpixmap_lock); // image 3 = copy of image 9 + PXM_free(E3pxm16); + E3pxm16 = PXM_copy(E9pxm16); + mutex_unlock(&Fpixmap_lock); + Fred = 0; + mwpaint2(); + } + + if (strEqu(event,"apply")) { + if (Fred) dust_erase(); + PXM_free(E9pxm16); // image 9 = copy of image 3 + E9pxm16 = PXM_copy(E3pxm16); + CEF->Fmod = 1; + } + + return 0; +} + + +// dust find thread function - find the dust particles and mark them + +void * dust_thread(void *) +{ + using namespace dust_names; + + int xspann, yspann, spann2; + int group, cc, ii, kk, Nremoved; + int px, py, dx, dy, ppx, ppy, npx, npy; + double gbright, pbright, pcontrast; + double ff = 1.0 / 65536.0; + uint16 direc, *pix3; + + while (true) + { + thread_idle_loop(); // wait for work or exit request + + mutex_lock(&Fpixmap_lock); // image 3 = copy of image 9 + PXM_free(E3pxm16); + E3pxm16 = PXM_copy(E9pxm16); + mutex_unlock(&Fpixmap_lock); + mwpaint2(); + + cc = Fww * Fhh * sizeof(int); // clear group arrays + memset(pixgroup,0,cc); + cc = maxgroups * sizeof(int); + memset(groupcount,0,cc); + memset(edgecount,0,cc); + cc = maxgroups * sizeof(double); + memset(groupbright,0,cc); + memset(edgebright,0,cc); + cc = maxgroups * sizeof(sgroupspann); + memset(groupspann,0,cc); + + group = 0; + + for (py = 0; py < Fhh; py++) // loop all pixels + for (px = 0; px < Fww; px++) + { + ii = py * Fww + px; + if (Factivearea && ! sa_pixmap[ii]) continue; // not in active area + if (pixgroup[ii]) continue; // already assigned to a group + + pix3 = PXMpix(E3pxm16,px,py); // get pixel brightness + gbright = ff * pixbright(pix3); // 0 to 1.0 = white + if (gbright > brightness) continue; // ignore bright pixel + + if (group == maxgroups-1) break; // too many groups, make no more + + pixgroup[ii] = ++group; // assign next group + groupcount[group] = 1; + groupbright[group] = gbright; + + pixstack[0].px = px; // put pixel into stack with + pixstack[0].py = py; // direction = ahead + pixstack[0].direc = 0; + Nstack = 1; + + while (Nstack) + { + kk = Nstack - 1; // get last pixel in stack + px = pixstack[kk].px; + py = pixstack[kk].py; + direc = pixstack[kk].direc; // next search direction + + if (direc == 'x') { + Nstack--; // none left + continue; + } + + if (Nstack > 1) { + ii = Nstack - 2; // get prior pixel in stack + ppx = pixstack[ii].px; + ppy = pixstack[ii].py; + } + else { + ppx = px - 1; // if only one, assume prior = left + ppy = py; + } + + dx = px - ppx; // vector from prior to this pixel + dy = py - ppy; + + switch (direc) + { + case 0: + npx = px + dx; + npy = py + dy; + pixstack[kk].direc = 1; + break; + + case 1: + npx = px + dy; + npy = py + dx; + pixstack[kk].direc = 3; + break; + + case 2: + npx = px - dx; // back to prior pixel + npy = py - dy; // (this path never taken) + zappcrash("stack search bug"); + break; + + case 3: + npx = px - dy; + npy = py - dx; + pixstack[kk].direc = 4; + break; + + case 4: + npx = px - dx; + npy = py + dy; + pixstack[kk].direc = 5; + break; + + case 5: + npx = px - dy; + npy = py + dx; + pixstack[kk].direc = 6; + break; + + case 6: + npx = px + dx; + npy = py - dy; + pixstack[kk].direc = 7; + break; + + case 7: + npx = px + dy; + npy = py - dx; + pixstack[kk].direc = 'x'; + break; + + default: + npx = npy = 0; + zappcrash("stack search bug"); + } + + if (npx < 0 || npx > Fww-1) continue; // pixel off the edge + if (npy < 0 || npy > Fhh-1) continue; + + ii = npy * Fww + npx; + if (pixgroup[ii]) continue; // pixel already assigned + if (Factivearea && ! sa_pixmap[ii]) continue; // pixel outside area + + pix3 = PXMpix(E3pxm16,npx,npy); // pixel brightness + pbright = ff * pixbright(pix3); + if (pbright > brightness) continue; // brighter than limit + + pixgroup[ii] = group; // assign pixel to group + ++groupcount[group]; // count pixels in group + groupbright[group] += pbright; // sum brightness for group + + kk = Nstack++; // put pixel into stack + pixstack[kk].px = npx; + pixstack[kk].py = npy; + pixstack[kk].direc = 0; // search direction + } + } + + Ngroups = group; // group numbers are 1-Ngroups + Nremoved = 0; + + for (py = 0; py < Fhh; py++) // loop all pixels + for (px = 0; px < Fww; px++) + { + ii = py * Fww + px; + group = pixgroup[ii]; + if (! group) continue; + if (groupspann[group].px1 == 0) { // first pixel found in this group + groupspann[group].px1 = px; // group px1/py1 = this pixel + groupspann[group].py1 = py; + continue; + } + xspann = groupspann[group].px1 - px; // spann from group px1/py1 to this pixel + yspann = groupspann[group].py1 - py; + spann2 = xspann * xspann + yspann * yspann; + if (spann2 > groupspann[group].spann2) { + groupspann[group].spann2 = spann2; // if greater, group px2/py2 = this pixel + groupspann[group].px2 = px; + groupspann[group].py2 = py; + } + } + + for (py = 0; py < Fhh; py++) // loop all pixels + for (px = 0; px < Fww; px++) + { + ii = py * Fww + px; + group = pixgroup[ii]; + if (! group) continue; + if (groupspann[group].spann2 > spotspann2) continue; + xspann = groupspann[group].px2 - px; // spann from this pixel to group px2/py2 + yspann = groupspann[group].py2 - py; + spann2 = xspann * xspann + yspann * yspann; + if (spann2 > groupspann[group].spann2) { + groupspann[group].spann2 = spann2; // if greater, group px1/py1 = this pixel + groupspann[group].px1 = px; + groupspann[group].py1 = py; + } + } + + for (py = 0; py < Fhh; py++) // loop all pixels + for (px = 0; px < Fww; px++) + { + ii = py * Fww + px; // eliminate group if spann > limit + group = pixgroup[ii]; + if (! group) continue; + if (! groupcount[group]) pixgroup[ii] = 0; + else if (groupspann[group].spann2 > spotspann2) { + pixgroup[ii] = 0; + groupcount[group] = 0; + Nremoved++; + } + } + + for (py = 1; py < Fhh-1; py++) // loop all pixels except image edges + for (px = 1; px < Fww-1; px++) + { + ii = py * Fww + px; + group = pixgroup[ii]; + if (group) continue; // find pixels bordering group pixels + pix3 = PXMpix(E3pxm16,px,py); + pbright = ff * pixbright(pix3); + + group = pixgroup[ii-Fww-1]; + if (group) { + ++edgecount[group]; // accumulate pixel count and + edgebright[group] += pbright; // bordering the groups + } + + group = pixgroup[ii-Fww]; + if (group) { + ++edgecount[group]; + edgebright[group] += pbright; + } + + group = pixgroup[ii-Fww+1]; + if (group) { + ++edgecount[group]; + edgebright[group] += pbright; + } + + group = pixgroup[ii-1]; + if (group) { + ++edgecount[group]; + edgebright[group] += pbright; + } + + group = pixgroup[ii+1]; + if (group) { + ++edgecount[group]; + edgebright[group] += pbright; + } + + group = pixgroup[ii+Fww-1]; + if (group) { + ++edgecount[group]; + edgebright[group] += pbright; + } + + group = pixgroup[ii+Fww]; + if (group) { + ++edgecount[group]; + edgebright[group] += pbright; + } + + group = pixgroup[ii+Fww+1]; + if (group) { + ++edgecount[group]; + edgebright[group] += pbright; + } + } + + for (group = 1; group <= Ngroups; group++) // compute group pixel and edge pixel + { // mean brightness + if (groupcount[group] && edgecount[group]) { + edgebright[group] = edgebright[group] / edgecount[group]; + groupbright[group] = groupbright[group] / groupcount[group]; + pcontrast = edgebright[group] - groupbright[group]; // edge - group contrast + if (pcontrast < contrast) { + groupcount[group] = 0; + Nremoved++; + } + } + } + + for (py = 0; py < Fhh; py++) // loop all pixels + for (px = 0; px < Fww; px++) + { + ii = py * Fww + px; // eliminate group if low contrast + group = pixgroup[ii]; + if (! group) continue; + if (! groupcount[group]) pixgroup[ii] = 0; + } + + for (py = 0; py < Fhh; py++) // loop all pixels + for (px = 0; px < Fww; px++) + { + ii = py * Fww + px; + if (! pixgroup[ii]) continue; // not a dust pixel + pix3 = PXMpix(E3pxm16,px,py); // paint it red + pix3[0] = 65535; + pix3[1] = pix3[2] = 0; + } + + Fred = 1; + mwpaint2(); // update window + } + + return 0; // not executed, stop g++ warning +} + + +// erase the selected dust areas + +void dust_erase() +{ + using namespace dust_names; + + int cc, ii, px, py, inc; + int qx, qy, npx, npy; + int sx, sy, tx, ty; + int rad, dist, dist2, mindist2; + double slope, f1, f2; + uint16 *pix1, *pix3; + char *pmap; + + Ffuncbusy++; + + mutex_lock(&Fpixmap_lock); // image 3 = copy of image 9 + PXM_free(E3pxm16); + E3pxm16 = PXM_copy(E9pxm16); + mutex_unlock(&Fpixmap_lock); + + cc = Fww * Fhh; // allocate pixel done map + pmap = (char *) zmalloc(cc,"erase_dust"); + memset(pmap,0,cc); + + for (py = 0; py < Fhh; py++) // loop all pixels + for (px = 0; px < Fww; px++) + { + ii = py * Fww + px; + if (! pixgroup[ii]) continue; // not a dust pixel + if (pmap[ii]) continue; // skip pixels already done + + mindist2 = 999999; + npx = npy = 0; + + for (rad = 1; rad < 10; rad++) // find nearest edge (10 pixel limit) + { + for (qx = px-rad; qx <= px+rad; qx++) // search within rad + for (qy = py-rad; qy <= py+rad; qy++) + { + if (qx < 0 || qx >= Fww) continue; // off image edge modified v.11.09 + if (qy < 0 || qy >= Fhh) continue; + ii = qy * Fww + qx; + if (pixgroup[ii]) continue; // within dust area + + dist2 = (px-qx) * (px-qx) + (py-qy) * (py-qy); // distance**2 to edge pixel + if (dist2 < mindist2) { + mindist2 = dist2; + npx = qx; // save nearest pixel found + npy = qy; + } + } + + if (rad * rad >= mindist2) break; // can quit now + } + + if (! npx && ! npy) continue; // should not happen + + qx = npx; // nearest edge pixel + qy = npy; + + if (abs(qy - py) > abs(qx - px)) { // qx/qy = near edge from px/py + slope = 1.0 * (qx - px) / (qy - py); + if (qy > py) inc = 1; + else inc = -1; + for (sy = py; sy != qy+inc; sy += inc) // line from px/py to qx/qy + { + sx = px + slope * (sy - py); + ii = sy * Fww + sx; + if (pmap[ii]) continue; // v.11.06 + pmap[ii] = 1; + tx = qx + (qx - sx); // tx/ty = parallel line from qx/qy + ty = qy + (qy - sy); // modified v.11.09 + if (tx < 0) tx = 0; + if (tx > Fww-1) tx = Fww-1; + if (ty < 0) ty = 0; + if (ty > Fhh-1) ty = Fhh-1; + pix1 = PXMpix(E3pxm16,tx,ty); // copy pixel from tx/ty to sx/sy + pix3 = PXMpix(E3pxm16,sx,sy); + pix3[0] = pix1[0]; + pix3[1] = pix1[1]; + pix3[2] = pix1[2]; + } + } + + else { + slope = 1.0 * (qy - py) / (qx - px); + if (qx > px) inc = 1; + else inc = -1; + for (sx = px; sx != qx+inc; sx += inc) + { + sy = py + slope * (sx - px); + ii = sy * Fww + sx; + if (pmap[ii]) continue; + pmap[ii] = 1; + tx = qx + (qx - sx); + ty = qy + (qy - sy); + if (tx < 0) tx = 0; + if (tx > Fww-1) tx = Fww-1; + if (ty < 0) ty = 0; + if (ty > Fhh-1) ty = Fhh-1; + pix1 = PXMpix(E3pxm16,tx,ty); + pix3 = PXMpix(E3pxm16,sx,sy); + pix3[0] = pix1[0]; + pix3[1] = pix1[1]; + pix3[2] = pix1[2]; + } + } + } + + zfree(pmap); + + if (Factivearea) // area edge blending + { + for (ii = 0; ii < Fww * Fhh; ii++) // find pixels in select area + { + dist = sa_pixmap[ii]; + if (! dist || dist >= sa_blend) continue; + + py = ii / Fww; + px = ii - py * Fww; + pix1 = PXMpix(E1pxm16,px,py); // input pixel, unchanged image + pix3 = PXMpix(E3pxm16,px,py); // output pixel, changed image + + f2 = 1.0 * dist / sa_blend; // changes over distance sa_blend + f1 = 1.0 - f2; + + pix3[0] = f1 * pix1[0] + f2 * pix3[0]; // blend the pixels + pix3[1] = f1 * pix1[1] + f2 * pix3[1]; + pix3[2] = f1 * pix1[2] + f2 * pix3[2]; + } + } + + Fred = 0; + Ffuncbusy--; + mwpaint2(); // update window + return; +} + + +/**************************************************************************/ + +// Find and fix stuck pixels (always bright or dark) from camera sensor defects. + +namespace stuckpix +{ + editfunc EFstuckpix; + int stuckpix_1x1, stuckpix_2x2, stuckpix_3x3; // pixel blocks to search + int stuckpix_color; // 1/2/3 = white/black/red circles + cchar *stuckpix_mode; // find or fix + double stuckpix_threshcon; // min. contrast threshold + char *stuckpix_file = 0; // file for saved bad pixels + + struct badpix_t { // memory for bad pixels + int px, py; // location (NW corner of block) + int size; // size: 1/2/3 = 1x1/2x2/3x3 block + double pcon; // contrast with surrounding pixels + int rgb[3]; // surrounding pixel mean RGB + }; + badpix_t badpix[50]; + int maxbad = 50, Nbad; +} + + +void m_stuckpix(GtkWidget *, cchar *menu) // new v.11.12 +{ + using namespace stuckpix; + + int stuckpix_dialog_event(zdialog *zd, cchar *event); + void * stuckpix_thread(void *); + + zdialog *zd; + + zfuncs::F1_help_topic = "stuck_pixels"; + + EFstuckpix.funcname = "stuckpix"; // function name + EFstuckpix.threadfunc = stuckpix_thread; // thread function + + if (! edit_setup(EFstuckpix)) return; // setup edit + +/*** + + pixel group [x] 1x1 [x] 2x2 [x] 3x3 + circle color (o) white (o) black (o) red + contrast =========[]==================== + + [open] [save] [apply] [cancel] +***/ + + zd = zdialog_new(ZTX("Fix Stuck Pixels"),mWin,Bopen,Bsave,Bapply,Bcancel,null); + EFstuckpix.zd = zd; + + zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=5"); + zdialog_add_widget(zd,"vbox","vb1","hb1",0,"space=5|homog"); + zdialog_add_widget(zd,"vbox","vb2","hb1",0,"space=5|expand|homog"); + zdialog_add_widget(zd,"label","labgroup","vb1",ZTX("pixel group")); + zdialog_add_widget(zd,"label","labcolor","vb1",ZTX("circle color")); + zdialog_add_widget(zd,"label","labcont","vb1",ZTX("contrast")); + zdialog_add_widget(zd,"hbox","hbgroup","vb2"); + zdialog_add_widget(zd,"check","1x1","hbgroup","1x1","space=3"); + zdialog_add_widget(zd,"check","2x2","hbgroup","2x2","space=3"); + zdialog_add_widget(zd,"check","3x3","hbgroup","3x3","space=3"); + zdialog_add_widget(zd,"hbox","hbcolor","vb2"); + zdialog_add_widget(zd,"radio","white","hbcolor",Bwhite,"space=5"); + zdialog_add_widget(zd,"radio","black","hbcolor",Bblack,"space=5"); + zdialog_add_widget(zd,"radio","red","hbcolor",Bred,"space=5"); + zdialog_add_widget(zd,"hscale","contrast","vb2","0.1|1.0|0.001|0.5","expand"); + + zdialog_stuff(zd,"1x1",1); // initz. dialog controls + zdialog_stuff(zd,"2x2",1); + zdialog_stuff(zd,"3x3",1); + zdialog_stuff(zd,"white",0); + zdialog_stuff(zd,"black",0); + zdialog_stuff(zd,"red",1); + + stuckpix_1x1 = stuckpix_2x2 = stuckpix_3x3 = 1; // corresp. data values + stuckpix_color = 3; + stuckpix_threshcon = 0.5; + + if (! stuckpix_file) { // default file + stuckpix_file = zmalloc(200); // /home//.fotoxx/stuck-pixels + snprintf(stuckpix_file,200,"%s/stuck-pixels",get_zuserdir()); + } + + zdialog_help(zd,"stuck_pixels"); + zdialog_run(zd,stuckpix_dialog_event,"save"); // run dialog + + stuckpix_mode = "find"; + signal_thread(); // find and show the bad pixels + wait_thread_idle(); + + return; +} + + +// dialog event function + +int stuckpix_dialog_event(zdialog *zd, cchar *event) +{ + using namespace stuckpix; + + void stuckpix_open(); + void stuckpix_save(); + + int color; + + if (zd->zstat) // completion button + { + if (zd->zstat == 1) { // open file + zd->zstat = 0; // keep dialog active + stuckpix_open(); + } + + else if (zd->zstat == 2) { // save file + zd->zstat = 0; // keep dialog active + stuckpix_save(); + } + + else if (zd->zstat == 3) { // apply + stuckpix_mode = "apply"; + signal_thread(); // fix the bad pixels + wait_thread_idle(); + edit_done(EFstuckpix); + erase_topcircles(); + } + + else { // cancel + edit_cancel(EFstuckpix); + erase_topcircles(); + } + + mwpaint2(); // update main window + return 0; + } + + zdialog_fetch(zd,"1x1",stuckpix_1x1); // get dialog inputs + zdialog_fetch(zd,"2x2",stuckpix_2x2); + zdialog_fetch(zd,"3x3",stuckpix_3x3); + + zdialog_fetch(zd,"white",color); + if (color) stuckpix_color = 1; + zdialog_fetch(zd,"black",color); + if (color) stuckpix_color = 2; + zdialog_fetch(zd,"red",color); + if (color) stuckpix_color = 3; + + zdialog_fetch(zd,"contrast",stuckpix_threshcon); + + stuckpix_mode = "find"; + signal_thread(); // find and show bad pixels + wait_thread_idle(); + + return 0; +} + + +// load bad pixel list from a previously saved file + +void stuckpix_open() +{ + using namespace stuckpix; + + int stuckpix_open_dialog_event(zdialog *zd, cchar *event); + + zdialog *zd; + + zd = zdialog_new(ZTX("Load Stuck Pixels"),mWin,Bopen,Bcancel,null); + zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=3"); + zdialog_add_widget(zd,"label","lab1","hb1",ZTX("File:"),"space=3"); + zdialog_add_widget(zd,"entry","file","hb1",0,"expand|scc=40"); + zdialog_add_widget(zd,"button","browse","hb1",Bbrowse,"space=5"); + + zdialog_stuff(zd,"file",stuckpix_file); + + zdialog_run(zd,stuckpix_open_dialog_event); + zdialog_wait(zd); + + return; +} + + +int stuckpix_open_dialog_event(zdialog *zd, cchar *event) +{ + using namespace stuckpix; + + char *pp, file[200]; + FILE *fid = 0; + int zstat, nn, ii, px, py, size; + + if (strEqu(event,"browse")) { + pp = zgetfile1(ZTX("Stuck Pixels file"),"open",stuckpix_file); + if (! pp) return 0; + zdialog_stuff(zd,"file",pp); + zfree(pp); + } + + zstat = zd->zstat; // completion button + + if (zstat) + { + if (zstat == 1) // open + { + zdialog_fetch(zd,"file",file,200); // get file from dialog + if (stuckpix_file) zfree(stuckpix_file); + stuckpix_file = strdupz(file); + + fid = fopen(file,"r"); // open file + if (! fid) { + zmessageACK(mWin,ZTX("file not found")); + return 1; + } + + nn = fscanf(fid,"stuck pixels px py size"); // read headers + + for (ii = 0; ii < maxbad; ii++) + { + nn = fscanf(fid," %5d %5d %5d ",&px,&py,&size); // read bad pixels data + if (nn == EOF) break; + if (nn != 3) break; + badpix[ii].px = px; + badpix[ii].py = py; + badpix[ii].size = size; + badpix[ii].pcon = 0; + } + + Nbad = ii; + fclose(fid); + zdialog_free(zd); + + if (! Nbad || nn != EOF) + zmessageACK(mWin,ZTX("file format error")); + + stuckpix_mode = "file"; // process pixels + signal_thread(); + wait_thread_idle(); + } + + else { // cancel or [x] + zdialog_free(zd); + return 1; + } + } + + return 1; +} + + +// save bad pixel list to a file or add them to a previous file + +void stuckpix_save() +{ + using namespace stuckpix; + + int stuckpix_save_dialog_event(zdialog *zd, cchar *event); + + zdialog *zd; + + if (Nbad == 0) { + zmessageACK(mWin,ZTX("there are zero stuck pixels")); + return; + } + + zd = zdialog_new(ZTX("Save Stuck Pixels"),mWin,Bsave,Bcancel,null); + zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=3"); + zdialog_add_widget(zd,"label","lab1","hb1",ZTX("File:"),"space=3"); + zdialog_add_widget(zd,"entry","file","hb1",0,"expand|scc=40"); + zdialog_add_widget(zd,"button","browse","hb1",Bbrowse,"space=5"); + + zdialog_stuff(zd,"file",stuckpix_file); + + zdialog_run(zd,stuckpix_save_dialog_event); + zdialog_wait(zd); + + return; +} + + +int stuckpix_save_dialog_event(zdialog *zd, cchar *event) +{ + using namespace stuckpix; + + char *pp, file[200]; + FILE *fid = 0; + int zstat, ii, px, py, size; + + if (strEqu(event,"browse")) { + pp = zgetfile1(ZTX("Stuck Pixels file"),"save",stuckpix_file); + if (! pp) return 0; + zdialog_stuff(zd,"file",pp); + zfree(pp); + } + + zstat = zd->zstat; // completion button + + if (zstat) + { + if (zstat == 1) // save + { + zdialog_fetch(zd,"file",file,200); // get file from dialog + if (stuckpix_file) zfree(stuckpix_file); + stuckpix_file = strdupz(file); + + fid = fopen(file,"w"); // open file + if (! fid) { + zmessageACK(mWin,strerror(errno)); + return 1; + } + + fprintf(fid,"stuck pixels \n"); // write headers + fprintf(fid," px py size \n"); + + for (ii = 0; ii < Nbad; ii++) // write bad pixel data + { + px = badpix[ii].px; + py = badpix[ii].py; + size = badpix[ii].size; + fprintf(fid," %5d %5d %5d \n",px,py,size); + } + + fclose(fid); + zdialog_free(zd); + } + + else { // cancel or [x] + zdialog_free(zd); + return 1; + } + } + + return 1; +} + + +// perform the fix function +// find pixel groups with contrast exceeding the limit +// replace these pixels with surrounding ones + +void * stuckpix_thread(void *) +{ + using namespace stuckpix; + + void stuckpix_pixelblock(int px, int py, int size, int rgb[3]); + void stuckpix_surroundings(int px, int py, int size, int rgb[3]); + double stuckpix_getcon(int rgbA[3], int rgbB[3]); + void stuckpix_insert(int px, int py, int size, double pcon, int rgb[3]); + void stuckpix_show(); + + int px, py, qx, qy, ii, size; + int rgbA[3], rgbB[3]; + double threshcon, pcon; + uint16 *ppix; + + while (true) + { + thread_idle_loop(); + + if (strEqu(stuckpix_mode,"find")) // find bad pixels in image + { + threshcon = stuckpix_threshcon; // threshold contrast, 0.1 to 1.0 + Nbad = 0; // count bad pixels found + + if (stuckpix_3x3) // find 3x3 pixel groups FIRST + { + for (py = 2; py < E3hh-5; py++) + for (px = 2; px < E3ww-5; px++) + { + stuckpix_pixelblock(px,py,3,rgbA); // get mean RGB for 3x3 pixel block + stuckpix_surroundings(px,py,3,rgbB); // get surrounding pixels mean RGB + pcon = stuckpix_getcon(rgbA,rgbB); // contrast with surrounding + if (pcon > threshcon) + stuckpix_insert(px,py,3,pcon,rgbB); // if > threshold, add to table + if (Nbad == maxbad) goto findquit; + } + } + + if (stuckpix_2x2) // find 2x2 pixel groups + { + for (py = 2; py < E3hh-4; py++) + for (px = 2; px < E3ww-4; px++) + { + stuckpix_pixelblock(px,py,2,rgbA); // get mean RGB for 2x2 pixel block + stuckpix_surroundings(px,py,2,rgbB); // get surrounding pixels mean RGB + pcon = stuckpix_getcon(rgbA,rgbB); // contrast with surrounding + if (pcon > threshcon) + stuckpix_insert(px,py,2,pcon,rgbB); // if > threshold, add to table + if (Nbad == maxbad) goto findquit; + } + } + + if (stuckpix_1x1) // find 1x1 pixel groups LAST + { + for (py = 2; py < E3hh-3; py++) + for (px = 2; px < E3ww-3; px++) + { + stuckpix_pixelblock(px,py,1,rgbA); // get mean RGB for 1x1 pixel block + stuckpix_surroundings(px,py,1,rgbB); // get surrounding pixels mean RGB + pcon = stuckpix_getcon(rgbA,rgbB); // contrast with surrounding + if (pcon > threshcon) + stuckpix_insert(px,py,1,pcon,rgbB); // if > threshold, add to table + if (Nbad == maxbad) goto findquit; + } + } + + findquit: + stuckpix_show(); // show the bad pixels found + } + + if (strEqu(stuckpix_mode,"file")) // process bad pixels read from a file + { + for (ii = 0; ii < Nbad; ii++) + { + px = badpix[ii].px; + py = badpix[ii].py; + size = badpix[ii].size; + + stuckpix_pixelblock(px,py,size,rgbA); + stuckpix_surroundings(px,py,size,rgbB); + pcon = stuckpix_getcon(rgbA,rgbB); + + badpix[ii].pcon = pcon; + badpix[ii].rgb[0] = rgbB[0]; + badpix[ii].rgb[1] = rgbB[1]; + badpix[ii].rgb[2] = rgbB[2]; + } + + stuckpix_show(); // show the bad pixels read + } + + if (strEqu(stuckpix_mode,"apply")) // replace the bad pixels + { + for (ii = 0; ii < Nbad; ii++) // loop pixel groups found + { + px = badpix[ii].px; + py = badpix[ii].py; + size = badpix[ii].size; + if (! size) continue; + + if (size == 1) // 1x1 pixel group + { + ppix = PXMpix(E3pxm16,px,py); // replace pixel group + ppix[0] = badpix[ii].rgb[0]; + ppix[1] = badpix[ii].rgb[1]; + ppix[2] = badpix[ii].rgb[2]; + } + + if (size == 2) // 2x2 pixel group + { + for (qy = py; qy < py+2; qy++) // replace pixel group + for (qx = px; qx < px+2; qx++) + { + ppix = PXMpix(E3pxm16,qx,qy); + ppix[0] = badpix[ii].rgb[0]; + ppix[1] = badpix[ii].rgb[1]; + ppix[2] = badpix[ii].rgb[2]; + } + } + + if (size == 3) // 3x3 pixel group + { + for (qy = py; qy < py+3; qy++) // replace pixel group + for (qx = px; qx < px+3; qx++) + { + ppix = PXMpix(E3pxm16,qx,qy); + ppix[0] = badpix[ii].rgb[0]; + ppix[1] = badpix[ii].rgb[1]; + ppix[2] = badpix[ii].rgb[2]; + } + } + } + + EFstuckpix.Fmod++; // image modified + mwpaint2(); // update window + } + } + + return 0; +} + + +// get the mean RGB values for a block of (defective) pixels + +void stuckpix_pixelblock(int px, int py, int size, int rgb[3]) +{ + uint16 *ppix; + + ppix = PXMpix(E3pxm16,px,py); // block of pixels + + if (size == 1) // 1x1 block, 1 pixel + { + rgb[0] = ppix[0]; + rgb[1] = ppix[1]; + rgb[2] = ppix[2]; + } + + if (size == 2) // 2x2 block, 4 pixels + { + rgb[0] = (ppix[0] + ppix[3] + ppix[E3ww*3] + ppix[E3ww*3+3]) / 4; + rgb[1] = (ppix[1] + ppix[4] + ppix[E3ww*3+1] + ppix[E3ww*3+4]) / 4; + rgb[2] = (ppix[2] + ppix[5] + ppix[E3ww*3+2] + ppix[E3ww*3+5]) / 4; + } + + if (size == 3) // 3x3 block, 9 pixels + { + rgb[0] = (ppix[0] + ppix[3] + ppix[6] + + ppix[E3ww*3] + ppix[E3ww*3+3] + ppix[E3ww*3+6] + + ppix[E3ww*6] + ppix[E3ww*6+3] + ppix[E3ww*6+6]) / 9; + + rgb[1] = (ppix[1] + ppix[4] + ppix[7] + + ppix[E3ww*3+1] + ppix[E3ww*3+4] + ppix[E3ww*3+7] + + ppix[E3ww*6+1] + ppix[E3ww*6+4] + ppix[E3ww*6+7]) / 9; + + rgb[2] = (ppix[2] + ppix[5] + ppix[8] + + ppix[E3ww*3+2] + ppix[E3ww*3+5] + ppix[E3ww*3+8] + + ppix[E3ww*6+2] + ppix[E3ww*6+5] + ppix[E3ww*6+8]) / 9; + } + + return; +} + + +// get the mean RGB values for pixels surrounding a given pixel block + +void stuckpix_surroundings(int px, int py, int size, int rgb[3]) +{ + int qx, qy, ii; + int red, green, blue; + uint16 *ppix; + + int n8x[8] = { -1, 0, 1,-1, 1,-1, 0, 1 }; // 8 neighbors of 1x1 group at [0,0] + int n8y[8] = { -1,-1,-1, 0, 0, 1, 1, 1 }; + + int n12x[12] = { -1, 0, 1, 2,-1, 2,-1, 2,-1, 0, 1, 2 }; // 12 neighbors of 2x2 group at [0,0] + int n12y[12] = { -1,-1,-1,-1, 0, 0, 1, 1, 2, 2, 2, 2 }; + + int n16x[16] = { -1, 0, 1, 2, 3,-1, 3,-1, 3,-1, 3,-1, 0, 1, 2, 3 }; // 16 neighbors of 3x3 group at [0,0] + int n16y[16] = { -1,-1,-1,-1,-1, 0, 0, 1, 1, 2, 2, 3, 3, 3, 3, 3 }; + + red = green = blue = 0; + + if (size == 1) + { + for (ii = 0; ii < 8; ii++) // surrounding 8 pixels + { + qx = px + n8x[ii]; + qy = py + n8y[ii]; + ppix = PXMpix(E3pxm16,qx,qy); + red += ppix[0]; + green += ppix[1]; + blue += ppix[2]; + } + + red = red / 8; // average surrounding pixels + green = green / 8; + blue = blue / 8; + } + + if (size == 2) + { + for (ii = 0; ii < 12; ii++) // surrounding 12 pixels + { + qx = px + n12x[ii]; + qy = py + n12y[ii]; + ppix = PXMpix(E3pxm16,qx,qy); + red += ppix[0]; + green += ppix[1]; + blue += ppix[2]; + } + + red = red / 12; // average surrounding pixels + green = green / 12; + blue = blue / 12; + } + + if (size == 3) + { + for (ii = 0; ii < 16; ii++) // surrounding 16 pixels + { + qx = px + n16x[ii]; + qy = py + n16y[ii]; + ppix = PXMpix(E3pxm16,qx,qy); + red += ppix[0]; + green += ppix[1]; + blue += ppix[2]; + } + + red = red / 16; // average surrounding pixels + green = green / 16; + blue = blue / 16; + } + + rgb[0] = red; + rgb[1] = green; + rgb[2] = blue; + + return; +} + + +// draw circles around the bad pixels + +void stuckpix_show() +{ + using namespace stuckpix; + + int ii, px, py, size, rad; + + erase_topcircles(); // erase prior circles + + for (ii = 0; ii < Nbad; ii++) // write circles around bad pixels + { + px = badpix[ii].px; + py = badpix[ii].py; + size = badpix[ii].size; + if (! size) continue; + rad = 8 + 2 * size; + px += size / 2; + py += size / 2; + add_topcircle(px,py,rad,stuckpix_color); + } + + mwpaint2(); // update window + return; +} + + +// compare two pixels and return contrast +// 0 = no contrast, 1 = max. contrast (black:white) + +double stuckpix_getcon(int rgbA[3], int rgbB[3]) +{ + double ff = 1.0 / 65536.0; + double Rdiff, Gdiff, Bdiff, match; + + Rdiff = ff * abs(rgbA[0] - rgbB[0]); // 0 = perfect match + Gdiff = ff * abs(rgbA[1] - rgbB[1]); // 1 = total mismatch + Bdiff = ff * abs(rgbA[2] - rgbB[2]); + + match = (1.0 - Rdiff) * (1.0 - Gdiff) * (1.0 - Bdiff); // 1 = perfect match + return (1.0 - match); +} + + +// Insert a new bad pixel block into the bad pixel table. +// If the new entry touches on a previous entry, +// then remove the entry with lesser contrast. + +void stuckpix_insert(int px, int py, int size, double pcon, int rgb[3]) +{ + using namespace stuckpix; + + int ii, px1, py1, px2, py2, px3, py3, px4, py4; + + px1 = px - 1; // "touch" periphery + py1 = py - 1; + px2 = px + size + 1; + py2 = py + size + 1; + + for (ii = 0; ii < Nbad; ii++) // loop badpix table + { + if (badpix[ii].size == 0) continue; // skip deleted entry + + px3 = badpix[ii].px; + py3 = badpix[ii].py; + px4 = px3 + badpix[ii].size - 1; + py4 = py3 + badpix[ii].size - 1; + + if ((px1 >= px3 && px1 <= px4 && py1 >= py3 && py1 <= py4) || // test if old entry touches new + (px2 >= px3 && px2 <= px4 && py2 >= py3 && py2 <= py4) || + (px1 >= px3 && px1 <= px4 && py2 >= py3 && py2 <= py4) || + (px2 >= px3 && px2 <= px4 && py1 >= py3 && py1 <= py4) || + (px3 >= px1 && px3 <= px2 && py3 >= py1 && py3 <= py2) || + (px4 >= px1 && px4 <= px2 && py4 >= py1 && py4 <= py2) || + (px3 >= px1 && px3 <= px2 && py4 >= py1 && py4 <= py2) || + (px4 >= px1 && px4 <= px2 && py3 >= py1 && py3 <= py2)) + { + if (size < badpix[ii].size && // if new touches a larger block, + pcon < 2.0 * badpix[ii].pcon) return; // keep only if contrast much greater + + if (pcon < 1.0 * badpix[ii].pcon) return; // keep only if contrast is greater + + badpix[ii].size = 0; // delete old entry + } + } + + for (ii = 0; ii < Nbad; ii++) // loop badpix table + if (badpix[ii].size == 0) break; // find first empty slot or last + 1 + if (ii == maxbad) return; // table full + + badpix[ii].px = px; // replace overlapping entry + badpix[ii].py = py; // or add to end of table + badpix[ii].size = size; + badpix[ii].pcon = pcon; + badpix[ii].rgb[0] = rgb[0]; + badpix[ii].rgb[1] = rgb[1]; + badpix[ii].rgb[2] = rgb[2]; + + if (ii == Nbad) Nbad++; // incr. count if added to end + if (Nbad == maxbad) printf("exceed %d bad pixels \n",maxbad); // report one time only + + return; +} + + +/**************************************************************************/ + +// pixel edit function - edit individual pixels + +#define pixed_undomaxmem (1000 * mega) // pixel edit max. memory v.11.04 +#define pixed_undomaxpix (mega) // pixel edit max. pixel blocks + +void pixed_mousefunc(); +void pixed_dopixels(int px, int py); +void pixed_undo1(); +void pixed_freeundo(); + +int pixed_RGB[3]; +int pixed_mode; +int pixed_radius; +double pixed_kernel[200][200]; // radius <= 99 + +int pixed_undototpix = 0; // total undo pixel blocks +int pixed_undototmem = 0; // total undo memory allocated +int pixed_undoseq = 0; // undo sequence no. +char pixed_undomemmessage[100]; // translated undo memory message + +typedef struct { // pixel block before edit + int seq; // undo sequence no. + uint16 npix; // no. pixels in this block + uint16 px, py; // center pixel (radius org.) + uint16 radius; // radius of pixel block + uint16 pixel[][3]; // array of pixel[npix][3] +} pixed_savepix; + +pixed_savepix **pixed_undopixmem = 0; // array of *pixed_savepix + +editfunc EFpixed; + + +void m_pixedit(GtkWidget *, cchar *) +{ + int pixed_dialog_event(zdialog* zd, cchar *event); + + char undomemmessage[100]; + + zfuncs::F1_help_topic = "edit_pixels"; // v.10.8 + + EFpixed.funcname = "pixel-edit"; + EFpixed.Farea = 1; // select area ignored + EFpixed.Fpara = 1; // parallel edit OK + EFpixed.mousefunc = pixed_mousefunc; // mouse function + if (! edit_setup(EFpixed)) return; // setup edit + + strncpy0(pixed_undomemmessage,ZTX("Undo Memory %d%c"),99); // translate undo memory message + + zdialog *zd = zdialog_new(ZTX("Edit Pixels"),mWin,Bdone,Bcancel,null); + EFpixed.zd = zd; + + zdialog_add_widget(zd,"hbox","hbc","dialog",0,"space=5"); + zdialog_add_widget(zd,"label","labc","hbc",ZTX("color"),"space=8"); + zdialog_add_widget(zd,"colorbutt","color","hbc","100|100|100"); + zdialog_add_widget(zd,"label","space","hbc",0,"space=10"); + zdialog_add_widget(zd,"radio","radio1","hbc",ZTX("pick"),"space=3"); + zdialog_add_widget(zd,"radio","radio2","hbc",ZTX("paint"),"space=3"); + zdialog_add_widget(zd,"radio","radio3","hbc",ZTX("erase"),"space=3"); + zdialog_add_widget(zd,"hbox","hbbri","dialog",0,"space=5"); + zdialog_add_widget(zd,"vbox","vbbr1","hbbri",0,"homog|space=5"); + zdialog_add_widget(zd,"vbox","vbbr2","hbbri",0,"homog|space=5"); + zdialog_add_widget(zd,"label","space","hbbri",0,"space=10"); + zdialog_add_widget(zd,"vbox","vbbr3","hbbri",0,"homog|space=3"); + zdialog_add_widget(zd,"hbox","hbrad","vbbr1",0,"space=3"); + zdialog_add_widget(zd,"label","space","hbrad",0,"expand"); + zdialog_add_widget(zd,"label","labbr","hbrad",ZTX("paintbrush radius")); + zdialog_add_widget(zd,"label","labtc","vbbr1",ZTX("transparency center")); + zdialog_add_widget(zd,"label","labte","vbbr1",ZTX("transparency edge")); + zdialog_add_widget(zd,"spin","radius","vbbr2","1|99|1|5"); + zdialog_add_widget(zd,"spin","trcent","vbbr2","0|100|0.1|95"); // smaller steps v.11.10 + zdialog_add_widget(zd,"spin","tredge","vbbr2","0|100|0.1|100"); + zdialog_add_widget(zd,"button","undlast","vbbr3",Bundolast); + zdialog_add_widget(zd,"button","undall","vbbr3",Bundoall); + zdialog_add_widget(zd,"hbox","hb4","dialog"); + zdialog_add_widget(zd,"label","labmem","hb4"); + + zdialog_help(zd,"edit_pixels"); // zdialog help topic v.11.08 + zdialog_run(zd,pixed_dialog_event,"save"); // run dialog, parallel v.11.07 + + zdialog_send_event(zd,"radius"); // get kernel initialized + + snprintf(undomemmessage,99,pixed_undomemmessage,0,'%'); // stuff undo memory status + zdialog_stuff(zd,"labmem",undomemmessage); + + pixed_RGB[0] = pixed_RGB[1] = pixed_RGB[2] = 100; // initialize color + + pixed_mode = 1; // mode = pick color + + pixed_undopixmem = 0; // no undo data + pixed_undototpix = 0; + pixed_undototmem = 0; + pixed_undoseq = 0; + + takeMouse(zd,pixed_mousefunc,drawcursor); // connect mouse function v.11.03 + return; +} + + +// dialog event and completion callback function + +int pixed_dialog_event(zdialog *zd, cchar *event) // pixedit dialog event function +{ + char color[20]; + cchar *pp; + int radius, dx, dy, brad; + double rad, kern, trcent, tredge; + + if (zd->zstat) + { + if (zd->zstat == 1) edit_done(EFpixed); // done + else edit_cancel(EFpixed); // cancel or destroy + pixed_freeundo(); // free undo memory + return 0; + } + + edit_takeover(EFpixed); // set my edit function + + paint_toparc(2); // v.11.04 + + if (strEqu(event,"focus")) // toggle mouse capture v.12.01 + takeMouse(zd,pixed_mousefunc,drawcursor); + + zdialog_fetch(zd,"radio1",brad); // pick + if (brad) pixed_mode = 1; + zdialog_fetch(zd,"radio2",brad); // paint + if (brad) pixed_mode = 2; + zdialog_fetch(zd,"radio3",brad); // erase + if (brad) pixed_mode = 3; + + if (strEqu(event,"color")) + { + zdialog_fetch(zd,"color",color,19); // get color from color wheel + pp = strField(color,"|",1); + if (pp) pixed_RGB[0] = atoi(pp); + pp = strField(color,"|",2); + if (pp) pixed_RGB[1] = atoi(pp); + pp = strField(color,"|",3); + if (pp) pixed_RGB[2] = atoi(pp); + } + + if (strstr("radius trcent tredge",event)) // get new brush attributes + { + zdialog_fetch(zd,"radius",radius); // radius + zdialog_fetch(zd,"trcent",trcent); // center transparency + zdialog_fetch(zd,"tredge",tredge); // edge transparency + + pixed_radius = radius; + trcent = 0.01 * trcent; // scale 0 ... 1 + tredge = 0.01 * tredge; + tredge = (1 - trcent) * (1 - tredge); + tredge = 1 - tredge; + trcent = sqrt(trcent); // speed up the curve + tredge = sqrt(tredge); + + for (dy = -radius; dy <= radius; dy++) // build kernel + for (dx = -radius; dx <= radius; dx++) + { + rad = sqrt(dx*dx + dy*dy); + kern = (radius - rad) / radius; // 1 ... 0 + kern = kern * (trcent - tredge) + tredge; // trcent ... tredge + if (rad > radius) kern = 1; + if (kern < 0) kern = 0; + if (kern > 1) kern = 1; + pixed_kernel[dx+radius][dy+radius] = kern; + } + } + + if (strEqu(event,"undlast")) // undo last edit (click or drag) + pixed_undo1(); + + if (strEqu(event,"undall")) { // undo all edits + edit_reset(); // v.10.3 + pixed_freeundo(); + } + + return 1; +} + + +// pixel edit mouse function + +void pixed_mousefunc() +{ + static int pmxdown = 0, pmydown = 0; + int px, py; + char color[20]; + uint16 *ppix3; + zdialog *zd = EFpixed.zd; + + edit_takeover(EFpixed); // set my edit function + + if (LMclick) // left mouse click + { + LMclick = 0; + px = Mxclick; + py = Myclick; + + if (pixed_mode == 1) // pick new color from image + { + ppix3 = PXMpix(E3pxm16,px,py); + pixed_RGB[0] = ppix3[0] / 256; + pixed_RGB[1] = ppix3[1] / 256; + pixed_RGB[2] = ppix3[2] / 256; + snprintf(color,19,"%d|%d|%d",pixed_RGB[0],pixed_RGB[1],pixed_RGB[2]); + if (zd) zdialog_stuff(zd,"color",color); + } + else { // paint or erase + pixed_undoseq++; // new undo seq. no. + paint_toparc(2); + pixed_dopixels(px,py); // do 1 block of pixels + } + } + + if (RMclick) + { + RMclick = 0; + paint_toparc(2); + pixed_undo1(); // undo last paint v.10.11 + } + + if (Mxdrag || Mydrag) // drag in progress + { + px = Mxdrag; + py = Mydrag; + Mxdrag = Mydrag = 0; + + if (Mxdown != pmxdown || Mydown != pmydown) { // new drag + pixed_undoseq++; // new undo seq. no. + pmxdown = Mxdown; + pmydown = Mydown; + } + paint_toparc(2); + pixed_dopixels(px,py); // do 1 block of pixels + } + + toparcx = Mxposn - pixed_radius; // define brush outline circle + toparcy = Myposn - pixed_radius; + toparcw = toparch = 2 * pixed_radius; + + if (pixed_mode == 1) Ftoparc = 0; + else Ftoparc = 1; + if (Ftoparc) paint_toparc(3); + + return; +} + + +// paint or erase 1 block of pixels within radius of px, py + +void pixed_dopixels(int px, int py) +{ + void pixed_saveundo(int px, int py); + + uint16 *ppix1, *ppix3; + int radius, dx, dy, qx, qy, ii, ww, dist; + int red, green, blue; + double kern; + + edit_zapredo(); // delete redo copy v.10.3 + + pixed_saveundo(px,py); // save pixels for poss. undo v.10.12.1 + + red = 256 * pixed_RGB[0]; + green = 256 * pixed_RGB[1]; + blue = 256 * pixed_RGB[2]; + + radius = pixed_radius; + + for (dy = -radius; dy <= radius; dy++) // loop surrounding block of pixels + for (dx = -radius; dx <= radius; dx++) + { + qx = px + dx; + qy = py + dy; + + if (qx < 0 || qx > E3ww-1) continue; + if (qy < 0 || qy > E3hh-1) continue; + + if (Factivearea) { // select area active v.10.11 + ii = qy * E3ww + qx; + dist = sa_pixmap[ii]; + if (! dist) continue; // pixel is outside area + } + + kern = pixed_kernel[dx+radius][dy+radius]; + ppix1 = PXMpix(E1pxm16,qx,qy); // original image pixel + ppix3 = PXMpix(E3pxm16,qx,qy); // edited image pixel + + if (pixed_mode == 2) // color pixels transparently + { + ppix3[0] = (1.0 - kern) * red + kern * ppix3[0]; + ppix3[1] = (1.0 - kern) * green + kern * ppix3[1]; + ppix3[2] = (1.0 - kern) * blue + kern * ppix3[2]; + CEF->Fmod = 1; + } + + if (pixed_mode == 3) // restore org. pixels transparently + { + ppix3[0] = (1.0 - kern) * ppix1[0] + kern * ppix3[0]; + ppix3[1] = (1.0 - kern) * ppix1[1] + kern * ppix3[1]; + ppix3[2] = (1.0 - kern) * ppix1[2] + kern * ppix3[2]; + } + } + + px = px - radius - 1; + py = py - radius - 1; + ww = 2 * radius + 3; + mwpaint3(px,py,ww,ww); // v.10.11 + return; +} + + +// save 1 block of pixels for possible undo + +void pixed_saveundo(int px, int py) +{ + int npix, radius, dx, dy; + uint16 *ppix3; + pixed_savepix *ppixsave1; + char undomemmessage[100]; + int mempercent; + static int ppercent = 0; + zdialog *zd = EFpixed.zd; + + if (! pixed_undopixmem) // first call + { + pixed_undopixmem = (pixed_savepix **) zmalloc(pixed_undomaxpix * sizeof(void *),"pixed"); + pixed_undototpix = 0; + pixed_undototmem = 0; + } + + if (pixed_undototmem > pixed_undomaxmem) + { + zmessageACK(mWin,ZTX("Undo memory limit has been reached. \n" + "Save work with [done], then resume editing.")); + Mdrag = 0; + return; + } + + radius = pixed_radius; + npix = 0; + + for (dy = -radius; dy <= radius; dy++) // count pixels in block + for (dx = -radius; dx <= radius; dx++) + { + if (px + dx < 0 || px + dx > E3ww-1) continue; + if (py + dy < 0 || py + dy > E3hh-1) continue; + npix++; + } + + ppixsave1 = (pixed_savepix *) zmalloc(npix*6+12,"pixed"); // allocate memory for block + pixed_undopixmem[pixed_undototpix] = ppixsave1; + pixed_undototpix += 1; + pixed_undototmem += npix * 6 + 12; + + ppixsave1->seq = pixed_undoseq; // save pixel block poop + ppixsave1->npix = npix; + ppixsave1->px = px; + ppixsave1->py = py; + ppixsave1->radius = radius; + + npix = 0; + + for (dy = -radius; dy <= radius; dy++) // save pixels in block + for (dx = -radius; dx <= radius; dx++) + { + if (px + dx < 0 || px + dx > E3ww-1) continue; + if (py + dy < 0 || py + dy > E3hh-1) continue; + ppix3 = PXMpix(E3pxm16,(px+dx),(py+dy)); // edited image pixel + ppixsave1->pixel[npix][0] = ppix3[0]; + ppixsave1->pixel[npix][1] = ppix3[1]; + ppixsave1->pixel[npix][2] = ppix3[2]; + npix++; + } + + mempercent = int(100.0 * pixed_undototmem / pixed_undomaxmem); // update undo memory status + if (mempercent != ppercent) { + ppercent = mempercent; + snprintf(undomemmessage,99,pixed_undomemmessage,mempercent,'%'); + zdialog_stuff(zd,"labmem",undomemmessage); + } + + return; +} + + +// undo last undo sequence number + +void pixed_undo1() +{ + int pindex, npix, radius, mempercent; + int ww, px, py, dx, dy; + uint16 *ppix3; + pixed_savepix *ppixsave1; + char undomemmessage[100]; + zdialog *zd = EFpixed.zd; + + pindex = pixed_undototpix; + + while (pindex > 0) + { + --pindex; + ppixsave1 = pixed_undopixmem[pindex]; + if (ppixsave1->seq != pixed_undoseq) break; + px = ppixsave1->px; + py = ppixsave1->py; + radius = ppixsave1->radius; + + npix = 0; + for (dy = -radius; dy <= radius; dy++) + for (dx = -radius; dx <= radius; dx++) + { + if (px + dx < 0 || px + dx > E3ww-1) continue; + if (py + dy < 0 || py + dy > E3hh-1) continue; + ppix3 = PXMpix(E3pxm16,(px+dx),(py+dy)); + ppix3[0] = ppixsave1->pixel[npix][0]; + ppix3[1] = ppixsave1->pixel[npix][1]; + ppix3[2] = ppixsave1->pixel[npix][2]; + npix++; + } + + px = px - radius - 1; // v.10.12 + py = py - radius - 1; + ww = 2 * radius + 3; + mwpaint3(px,py,ww,ww); + + npix = ppixsave1->npix; + zfree(ppixsave1); + pixed_undopixmem[pindex] = 0; + pixed_undototmem -= (npix * 6 + 12); + --pixed_undototpix; + } + + if (pixed_undoseq > 0) --pixed_undoseq; + + mempercent = int(100.0 * pixed_undototmem / pixed_undomaxmem); // update undo memory status + snprintf(undomemmessage,99,pixed_undomemmessage,mempercent,'%'); + zdialog_stuff(zd,"labmem",undomemmessage); + + return; +} + + +// free all undo memory + +void pixed_freeundo() +{ + int pindex; + pixed_savepix *ppixsave1; + char undomemmessage[100]; + zdialog *zd = EFpixed.zd; + + pindex = pixed_undototpix; + + while (pindex > 0) + { + --pindex; + ppixsave1 = pixed_undopixmem[pindex]; + zfree(ppixsave1); + } + + if (pixed_undopixmem) zfree(pixed_undopixmem); + pixed_undopixmem = 0; + + pixed_undoseq = 0; + pixed_undototpix = 0; + pixed_undototmem = 0; + + if (zd) { + snprintf(undomemmessage,99,pixed_undomemmessage,0,'%'); // undo memory = 0% + zdialog_stuff(zd,"labmem",undomemmessage); + } + + return; +} + + + diff -Nru fotoxx-11.11.1/f.select.cc fotoxx-12.01.2/f.select.cc --- fotoxx-11.11.1/f.select.cc 1970-01-01 00:00:00.000000000 +0000 +++ fotoxx-12.01.2/f.select.cc 2012-01-04 08:47:11.000000000 +0000 @@ -0,0 +1,2703 @@ +/************************************************************************** + + Fotoxx edit photos and manage collections + + Copyright 2007 2008 2009 2010 2011 2012 Michael Cornelison + Source URL: http://kornelix.squarespace.com/fotoxx + Contact: kornelix2@googlemail.com + + 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 http://www.gnu.org/licenses/. + +***************************************************************************/ + +#define EX extern // enable extern declarations +#include "fotoxx.h" + +/************************************************************************** + + Fotoxx image editor - select area functions + + Select an area within the current image. + Subsequent edit functions are carried out within the area. + Otherwise, edit functions apply to the entire image. + + sa_stat 0/1/2/3 = none/edit/pause/complete + sa_mode is current area selection method: + 1 select rectangle by drag or clicks + 2 select ellipse by drag + 3 freehand draw by drag + 4 follow edge indicated by clicks + 5 select pixels by mouse (radius, color, range, firewall) + 6 unused v.11.12 + 7 select whole image + +***************************************************************************/ + +// user select area dialog +// line drawing and selection by color range are combined // v.9.7 + +void m_select(GtkWidget *, cchar *) // menu function +{ + int select_dialog_event(zdialog *, cchar *event); // dialog event and completion funcs + + cchar *title = ZTX("Select Area for Edits"); + cchar *helptext = ZTX("Press F1 for help"); + zdialog *zd; + + zfuncs::F1_help_topic = "select_area"; + + if (! curr_file) return; // no image + if (zdsela) return; // already active + + if (CEF && CEF->Farea != 2) { // active edit function + zmessageACK(mWin,ZTX("Select Area not supported \n" // v.11.08 + "by this edit function")); + return; + } + + if (Fpreview) edit_fullsize(); // use full-size image + + if (! Fpxm16) { // create Fpxm16 if not already + mutex_lock(&Fpixmap_lock); + Fpxm16 = f_load(curr_file,16); + mutex_unlock(&Fpixmap_lock); + if (! Fpxm16) return; + } + +/*** v.11.12 + ____________________________________________________ + | Press F1 for help | + | [x] select rectangle [x] select ellipse | + | [x] draw: freehand [x] draw: follow edge | + | [x] select by mouse mouse radius [___] | + | [x] match mouse color [___] | + | search range [__] [x] firewall | + | Blend Width [__] | + | | + | [Show] [Hide] [Color] [Finish] [Unfinish] | + | [Enable] [Disable] [Invert] [Unselect] [Done] | + |____________________________________________________| + +***/ + + zdsela = zdialog_new(title,mWin,null); + zd = zdsela; + + zdialog_add_widget(zd,"label","labhelp","dialog",helptext); + + zdialog_add_widget(zd,"hbox","hbshape","dialog"); + zdialog_add_widget(zd,"vbox","vbsh1","hbshape"); + zdialog_add_widget(zd,"label","space","hbshape",0,"space=10"); + zdialog_add_widget(zd,"vbox","vbsh2","hbshape"); + zdialog_add_widget(zd,"check","ckrect","vbsh1",ZTX("rectangle")); + zdialog_add_widget(zd,"check","ckelips","vbsh2",ZTX("ellipse")); + + zdialog_add_widget(zd,"hbox","hbdraw","dialog"); + zdialog_add_widget(zd,"vbox","vbdr1","hbdraw",0,"homog"); + zdialog_add_widget(zd,"label","space","hbdraw",0,"space=10"); + zdialog_add_widget(zd,"vbox","vbdr2","hbdraw",0,"homog"); + zdialog_add_widget(zd,"check","ckdraw","vbdr1",ZTX("draw: freehand")); + zdialog_add_widget(zd,"check","ckfollow","vbdr2",ZTX("draw: follow edge")); + + zdialog_add_widget(zd,"hbox","hbm1","dialog"); + zdialog_add_widget(zd,"check","ckmouse","hbm1",ZTX("select by mouse")); + zdialog_add_widget(zd,"label","space","hbm1",0,"space=10"); + zdialog_add_widget(zd,"label","labmr","hbm1",ZTX("mouse radius")); + zdialog_add_widget(zd,"spin","mouserad","hbm1","1|300|1|20","space=5"); + zdialog_add_widget(zd,"hbox","hbm2","dialog"); + zdialog_add_widget(zd,"label","space","hbm2",0,"space=10"); + zdialog_add_widget(zd,"check","matchcolor","hbm2",ZTX("match mouse color")); + zdialog_add_widget(zd,"spin","colormatch","hbm2","0|100|1|90","space=10"); + zdialog_add_widget(zd,"hbox","hbm3","dialog"); + zdialog_add_widget(zd,"label","space","hbm3",0,"space=10"); + zdialog_add_widget(zd,"label","labsr","hbm3",ZTX("search range"),"space=5"); + zdialog_add_widget(zd,"spin","searchrange","hbm3","1|20|1|3"); + zdialog_add_widget(zd,"check","firewall","hbm3",ZTX("firewall"),"space=10"); + + zdialog_add_widget(zd,"hbox","hbbwfw","dialog",0,"space=5"); + zdialog_add_widget(zd,"label","labblend","hbbwfw",Bblendwidth,"space=5"); + zdialog_add_widget(zd,"spin","blendwidth","hbbwfw","0|500|1|0"); + + zdialog_add_widget(zd,"hbox","hbb2","dialog",0,"space=5"); + zdialog_add_widget(zd,"button","show","hbb2",Bshow); + zdialog_add_widget(zd,"button","hide","hbb2",Bhide); + zdialog_add_widget(zd,"button","color","hbb2",Bcolor); + zdialog_add_widget(zd,"button","finish","hbb2",Bfinish); + zdialog_add_widget(zd,"button","unfinish","hbb2",Bunfinish); + + zdialog_add_widget(zd,"hbox","hbb3","dialog",0,"space=3"); + zdialog_add_widget(zd,"button","enable","hbb3",Benable); + zdialog_add_widget(zd,"button","disable","hbb3",Bdisable); + zdialog_add_widget(zd,"button","invert","hbb3",Binvert); + zdialog_add_widget(zd,"button","unselect","hbb3",Bunselect); + zdialog_add_widget(zd,"button","done","hbb3",Bdone); + + zdialog_help(zd,"select_area"); // v.11.08 + zdialog_run(zd,select_dialog_event,"save"); // run dialog - parallel v.11.07 + + sa_mouseradius = 20; // initial values matching dialog + sa_colormatch = 90; + sa_matchcolor = 0; + sa_searchrange = 3; + sa_blend = 0; + sa_firewall = 0; + sa_mode = 0; + zdialog_stuff(zd,"ckrect",0); + zdialog_stuff(zd,"ckelips",0); + zdialog_stuff(zd,"ckdraw",0); + zdialog_stuff(zd,"ckfollow",0); + zdialog_stuff(zd,"ckmouse",0); + sa_show(1); // show existing area, if any + + return; +} + + +// dialog event and completion callback function + +int select_dialog_event(zdialog *zd, cchar *event) +{ + struct { + cchar *event; + int stat; + } + eventab[20] = { // dialog events and corresp. + { "ckrect", 1 }, // edit status change + { "ckelips", 1 }, + { "ckdraw", 1 }, + { "ckfollow", 1 }, + { "ckmouse", 1 }, + { "mouserad", 0 }, + { "matchcolor", 0 }, + { "colormatch", 0 }, + { "searchrange", 0 }, + { "firewall", 0 }, + { "blendwidth", 0 }, + { "show", 0 }, + { "hide", 0 }, + { "color", 0 }, + { "finish", 2 }, + { "unfinish", 2 }, + { "enable", 0 }, + { "disable", 2 }, + { "invert", 0 }, + { "unselect", 2 } }; + + int Nevents = 20, ii, jj, kk, cc; + + if (strEqu(event,"done") || zd->zstat) // done or cancel + { + freeMouse(); // disconnect mouse function v.10.12 + zdialog_free(zdsela); // kill dialog + return 0; + } + + if (CEF && CEF->Farea != 2) { // select area not supported v.11.08 + printf("select area ignored \n"); + return 0; + } + + for (ii = 0; ii < Nevents; ii++) + if (strEqu(event,eventab[ii].event)) break; + if (ii == Nevents) return 0; + + if (sa_fww != Fww || sa_fhh != Fhh) // area not valid for image, delete it + sa_unselect(); // bugfix v.11.08 + + if (! sa_stat) { // no area, create one v.11.07 + cc = Fww * Fhh * sizeof(uint16); // allocate sa_pixmap[] for new area + sa_pixmap = (uint16 *) zmalloc(cc,"sa_select"); // maps pixels in area + memset(sa_pixmap,0,cc); + sa_currseq = sa_Ncurrseq = 0; // reset selection sequence + sa_Npixel = sa_blend = sa_calced = Factivearea = 0; + sa_fww = Fww; // valid image size for area v.11.08 + sa_fhh = Fhh; + sa_stat = 1; // status = edit + zdialog_stuff(zd,"blendwidth",0); // init. blend width = 0 + } + + if (ii < 5) // one of the edit mode checkboxes + { + for (jj = 0; jj < 5; jj++) + { + if (jj == ii) { + zdialog_fetch(zd,eventab[ii].event,kk); // toggle checkbox on/off + if (kk) { // on: set edit mode + sa_mode = jj+1; + sa_stat = 1; + sa_Npixel = sa_blend = sa_calced = Factivearea = 0; + zdialog_stuff(zd,"blendwidth",0); + sa_show(1); + } + else { // off: no edit mode, edit paused + sa_mode = 0; + sa_stat = 2; + } + } + else zdialog_stuff(zd,eventab[jj].event,0); // all other checkboxes off + } + } + + if (eventab[ii].stat == 2) { + for (jj = 0; jj < 5; jj++) // no edit mode active + zdialog_stuff(zd,eventab[jj].event,0); // all checkboxes off + sa_stat = 2; // edit is paused + } + + if (strEqu(event,"mouserad")) // mouse selection radius + zdialog_fetch(zd,"mouserad",sa_mouseradius); + + if (strEqu(event,"matchcolor")) // "" color match enable v.11.12 + zdialog_fetch(zdsela,"matchcolor",sa_matchcolor); + + if (strEqu(event,"colormatch")) // "" color match limit, 0 - 99.9 + zdialog_fetch(zdsela,"colormatch",sa_colormatch); + + if (strEqu(event,"searchrange")) // "" "" search range, x radius v.11.12 + zdialog_fetch(zdsela,"searchrange",sa_searchrange); + + if (strEqu(event,"firewall")) // "" color match firewall on/off v.10.11 + zdialog_fetch(zdsela,"firewall",sa_firewall); + + if (strEqu(event,"show")) sa_show(1); // show area + if (strEqu(event,"hide")) sa_show(0); // hide area + if (strEqu(event,"finish")) sa_finish(); // finish (finalize) area + if (strEqu(event,"unfinish")) sa_unfinish(); // unfinish area v.11.07 + if (strEqu(event,"unselect")) sa_unselect(); // unselect area + if (strEqu(event,"enable")) sa_enable(); // enable area + if (strEqu(event,"disable")) sa_disable(); // disable area + if (strEqu(event,"invert")) sa_invert(); // invert area + + if (strEqu(event,"color")) { // change show area color + if (sa_pixRGB == &red) sa_pixRGB = &green; + else if (sa_pixRGB == &green) sa_pixRGB = &black; + else sa_pixRGB = &red; + sa_show(1); + } + + if (strEqu(event,"blendwidth") && Factivearea) { // blend width changed + sa_edgecalc(); // do edge calc. if not already + if (sa_calced && CEF && CEF->zd) { // edit is active + zdialog_fetch(zd,"blendwidth",sa_blend); // update sa_blend + zdialog_send_event(CEF->zd,event); // notify edit dialog + } + } // "ignore once" logic removed v.11.01 + + if (sa_stat == 1) // active edit mode + { + if (sa_mode == 1) takeMouse(zd,sa_geom_mousefunc,dragcursor); // rectangle v.11.03 + if (sa_mode == 2) takeMouse(zd,sa_geom_mousefunc,dragcursor); // ellipse + if (sa_mode == 3) takeMouse(zd,sa_draw_mousefunc,drawcursor); // freehand draw + if (sa_mode == 4) takeMouse(zd,sa_draw_mousefunc,drawcursor); // follow edge + if (sa_mode == 5) takeMouse(zd,sa_mouse_mousefunc,0); // mouse select + if (sa_mode < 3) sa_geom1 = sa_geom2 = 0; // new rectangle or ellipse + if (sa_mode < 5) paint_toparc(2); // erase radius circle + } + else { // edit paused or done + freeMouse(); // disconnect mouse + gdk_window_set_cursor(drWin->window,null); // normal cursor v.12.01 + } + + return 0; +} + + +// select area mouse function - select a rectangle or ellipse + +void sa_geom_mousefunc() // new v.11.03 +{ + static int mx1, my1, mx2, my2; + static int mdx0, mdy0; + + if (sa_stat != 1) return; // area gone? v.11.07 + + if (sa_currseq > sa_maxseq-2) { + zmessageACK(mWin,ZTX("exceed %d edits"),sa_maxseq); // cannot continue + return; + } + + if (RMclick) // right mouse click + { + RMclick = 0; + sa_unselect_pixels(); // remove latest selection + sa_geom1 = sa_geom2 = 0; + mwpaint2(); + return; + } + + if (! Mxdrag && ! Mydrag) return; // v.11.04 + + if (Mxdown != mdx0 || Mydown != mdy0) { // new drag initiated + mdx0 = Mxdown; + mdy0 = Mydown; + mx1 = mdx0; // drag start, one corner + my1 = mdy0; + sa_geom1 = 1; + sa_geom2 = 0; + return; + } + + if (sa_geom2) sa_unselect_pixels(); // remove prior selection + mx2 = Mxdrag; // drag continues, 2nd corner + my2 = Mydrag; + sa_geom2 = 1; + + sa_nextseq(); // next sequence number + + if (sa_mode == 1) // draw rectangle + { + sa_draw_line(mx1,my1,mx2,my1); + sa_draw_line(mx2,my1,mx2,my2); + sa_draw_line(mx2,my2,mx1,my2); + sa_draw_line(mx1,my2,mx1,my1); + } + + if (sa_mode == 2) // draw ellipse + { + double a, b, a2, b2; + double x, y, x2, y2, cx, cy; + int px, py; + + a = abs(mx2 - mx1); // ellipse constants from v.11.04 + b = abs(my2 - my1); // enclosing rectangle + a2 = a * a; + b2 = b * b; + cx = mx1; // center at drag origin v.11.04 + cy = my1; + + for (y = -b; y < b; y++) // step through y values + { + y2 = y * y; + x2 = a2 * (1 - y2 / b2); + x = sqrt(x2); // corresp. x values, + and - + py = y + cy; + px = cx - x + 0.5; + sa_draw1pix(px,py); // draw 2 points on ellipse + px = cx + x + 0.5; + sa_draw1pix(px,py); + } + + for (x = -a; x < a; x++) // step through x values + { + x2 = x * x; + y2 = b2 * (1 - x2 / a2); + y = sqrt(y2); // corresp. y values, + and - + px = cx + x; + py = cy - y + 0.5; + sa_draw1pix(px,py); // draw 2 points on ellipse + py = cy + y + 0.5; + sa_draw1pix(px,py); + } + } + + mwpaint2(); + return; +} + + +// select area mouse function - freehand draw and follow edge + +void sa_draw_mousefunc() +{ + void sa_follow_edge(int mx1, int my1, int mx2, int my2); + + int mx1, my1, mx2, my2; + int npdist, npx, npy; + int ii, click, newseq, thresh; + static int drag = 0, mdx0, mdy0, mdx1, mdy1; + + if (sa_stat != 1) return; // area gone? v.11.07 + + sa_thresh = 4.0 / Mscale + 1; // mouse pixel distance threshold + click = newseq = 0; + + if (LMclick || Mxdrag || Mydrag) // left mouse click or mouse drag + { + if (LMclick) // left mouse click + { + LMclick = 0; + mx1 = mx2 = Mxclick; // click position + my1 = my2 = Myclick; + newseq++; + click++; + drag = 0; + } + else // drag motion + { + if (Mxdown != mdx0 || Mydown != mdy0) { // new drag initiated + mdx0 = mdx1 = Mxdown; + mdy0 = mdy1 = Mydown; + newseq++; + } + mx1 = mdx1; // drag start + my1 = mdy1; + mx2 = Mxdrag; // drag position + my2 = Mydrag; + mdx1 = mx2; // next drag start + mdy1 = my2; + drag++; + click = 0; + } + + if (Mbutton == 3) // right mouse >> erase + { + while (true) { + thresh = sa_thresh; + npdist = sa_nearpix(mx2,my2,thresh,npx,npy); + if (! npdist) break; + ii = npy * Fww + npx; + sa_pixmap[ii] = 0; + } + mwpaint2(); + return; + } + + if (sa_currseq > sa_maxseq-2) { + zmessageACK(mWin,ZTX("exceed %d edits"),sa_maxseq); // cannot continue + return; + } + + if (sa_currseq == 0 && newseq) // 1st pixel(s) of 1st sequence + { + sa_nextseq(); // set next (1st) sequence no. v.10.8 + sa_draw_line(mx1,my1,mx2,my2); // draw initial pixel or line + sa_endpx[sa_currseq] = mx2; + sa_endpy[sa_currseq] = my2; + return; + } + + if (click) { + mx1 = sa_endpx[sa_currseq]; // prior sequence end pixel + my1 = sa_endpy[sa_currseq]; // (before this click) + } + + if (drag) { + if (newseq) thresh = 2 * sa_thresh; // new drag threshold + else thresh = 5 * sa_thresh; // continuation drag threshold + npx = sa_endpx[sa_currseq]; // distance from prior end pixel + npy = sa_endpy[sa_currseq]; // (before this drag) + if (abs(mx1-npx) < thresh && abs(my1-npy) < thresh) { + mx1 = sa_endpx[sa_currseq]; // if < threshold, connect this + my1 = sa_endpy[sa_currseq]; // drag to prior drag or click + } + } + + if (newseq || drag > 50) { + sa_nextseq(); // set next sequence no. v.10.8 + drag = 1; // drag length within sequence + } + + if (sa_mode == 4) sa_follow_edge(mx1,my1,mx2,my2); // follow edge or draw line + else sa_draw_line(mx1,my1,mx2,my2); // from end pixel to mouse + + sa_endpx[sa_currseq] = mx2; // set end pixel for this sequence + sa_endpy[sa_currseq] = my2; + } + + else if (RMclick) // right mouse click + { + RMclick = 0; + sa_unselect_pixels(); // remove latest selection v.10.8 + mwpaint2(); + } + + return; +} + + +// Find the nearest drawn pixel within a radius of a given pixel. +// Returns distance to pixel, or zero if nothing found. +// Returns 1 for adjacent or diagonally adjacent pixel. + +int sa_nearpix(int mx, int my, int rad2, int &npx, int &npy) +{ + int ii, rad, qx, qy, dx, dy; + int mindist, dist; + + npx = npy = 0; + mindist = (rad2+1) * (rad2+1); + + for (rad = 1; rad <= rad2; rad++) // seek neighbors within range + { + if (rad * rad > mindist) break; // can stop searching now + + for (qx = mx-rad; qx <= mx+rad; qx++) // search within rad + for (qy = my-rad; qy <= my+rad; qy++) + { + if (qx != mx-rad && qx != mx+rad && // exclude within rad-1 + qy != my-rad && qy != my+rad) continue; // (already searched) + if (qx < 0 || qx > Fww-1) continue; + if (qy < 0 || qy > Fhh-1) continue; + ii = qy * Fww + qx; + if (! sa_pixmap[ii]) continue; + dx = (mx - qx) * (mx - qx); // found pixel + dy = (my - qy) * (my - qy); + dist = dx + dy; // distance**2 + if (dist < mindist) { + mindist = dist; + npx = qx; // save nearest pixel found + npy = qy; + } + } + } + + if (npx + npy) return sqrt(mindist) + 0.5; + return 0; +} + + +// draw a line between two given pixels +// add all in-line pixels to sa_pixmap[] + +void sa_draw_line(int px1, int py1, int px2, int py2) +{ + void sa_draw1pix(int px, int py); + + int pxm, pym; + double slope; + + if (sa_stat != 1) return; // area gone? v.11.07 + + if (px1 == px2 && py1 == py2) { // only one pixel + sa_draw1pix(px1,py1); + return; + } + + if (abs(py2 - py1) > abs(px2 - px1)) { + slope = 1.0 * (px2 - px1) / (py2 - py1); + if (py2 > py1) { + for (pym = py1; pym <= py2; pym++) { + pxm = round(px1 + slope * (pym - py1)); + sa_draw1pix(pxm,pym); + } + } + else { + for (pym = py1; pym >= py2; pym--) { + pxm = round(px1 + slope * (pym - py1)); + sa_draw1pix(pxm,pym); + } + } + } + else { + slope = 1.0 * (py2 - py1) / (px2 - px1); + if (px2 > px1) { + for (pxm = px1; pxm <= px2; pxm++) { + pym = round(py1 + slope * (pxm - px1)); + sa_draw1pix(pxm,pym); + } + } + else { + for (pxm = px1; pxm >= px2; pxm--) { + pym = round(py1 + slope * (pxm - px1)); + sa_draw1pix(pxm,pym); + } + } + } + + return; +} + + +// draw one pixel only if not already drawn + +void sa_draw1pix(int px, int py) +{ + if (px < 0 || px > Fww-1) return; // bugfix v.11.03.1 + if (py < 0 || py > Fhh-1) return; + int ii = Fww * py + px; + if (sa_pixmap[ii]) return; // map to curr. selection sequence + sa_pixmap[ii] = sa_currseq; + sa_Ncurrseq++; // v.10.8 + draw_fat_pixel(px,py,sa_pixRGB); // v.11.04 + return; +} + + +// Find series of edge pixels from px1/py1 to px2/py2 and connect them together. + +void sa_follow_edge(int px1, int py1, int px2, int py2) // v.10.8 +{ + double sa_get_contrast(int px, int py); + + double px3, py3, px4, py4, px5, py5, px6, py6; + double dx, dy, dist, contrast, maxcontrast; + + if (sa_stat != 1) return; // area gone? v.11.07 + + px3 = px1; // p3 progresses from p1 to p2 + py3 = py1; + + while (true) + { + dx = px2 - px3; + dy = py2 - py3; + + dist = sqrt(dx * dx + dy * dy); // last segment + if (dist < 3) break; + + px4 = px3 + dx / dist; // p4 = p3 moved toward p2 + py4 = py3 + dy / dist; + + maxcontrast = 0; + px6 = px4; + py6 = py4; + + for (int ii = -2; ii <= +2; ii++) // p5 points are in a line through p4 + { // and perpendicular to p4 - p2 + px5 = px4 + ii * dy / dist; + py5 = py4 - ii * dx / dist; + contrast = sa_get_contrast(px5,py5); + contrast *= (7 - abs(ii)); // favor points closer together v.10.9 + if (contrast > maxcontrast) { + px6 = px5; // p6 = highest contrast point in p5 + py6 = py5; + maxcontrast = contrast; + } + } + + sa_draw_line(px3,py3,px6,py6); // draw p3 to p6 + + px3 = px6; // next p3 + py3 = py6; + } + + sa_draw_line(px3,py3,px2,py2); + return; +} + + +// Find max. contrast between neighbors on opposite sides of given pixel + +double sa_get_contrast(int px, int py) // v.10.8 +{ + int map[4][2] = { {1, 0}, {1, 1}, {0, 1}, {-1, 1} }; + int ii, qx, qy; + uint16 *pix1, *pix2; + double red, green, blue; + double contrast, maxcontrast = 0; + double f65k = 1.0 / 65535.0; + + if (px < 1 || px > Fww-2) return 0; // avoid edge pixels + if (py < 1 || py > Fhh-2) return 0; + + for (ii = 0; ii < 4; ii++) // compare pixels around target + { // e.g. (px-1,py) to (px+1,py) + qx = map[ii][0]; + qy = map[ii][1]; + pix1 = PXMpix(Fpxm16,px+qx,py+qy); + pix2 = PXMpix(Fpxm16,px-qx,py-qy); + red = f65k * abs(pix1[0] - pix2[0]); + green = f65k * abs(pix1[1] - pix2[1]); + blue = f65k * abs(pix1[2] - pix2[2]); + contrast = (1.0 - red) * (1.0 - green) * (1.0 - blue); // no contrast = 1.0 + contrast = 1.0 - contrast; // max. contrast = 1.0 + if (contrast > maxcontrast) maxcontrast = contrast; + } + + return maxcontrast; +} + + +// mouse function - select area by mouse and matching color range +// if left click or drag, find and select matching pixels +// if right click, unselect last selection +// if right drag, find and unselect matching pixels + +void sa_mouse_mousefunc() // revised v.11.12 +{ + void sa_find_color_pixels(int select); + + static int mxdown, mydown, drag = 0; + + if (sa_stat != 1) return; // area gone? v.11.07 + + sa_radius = sa_mouseradius; // mouse radius + sa_radius2 = sa_radius * sa_radius; // squared + + sa_radius3 = sa_radius * sa_searchrange; // search range (* mouse radius) + sa_radius3 = sa_radius3 * sa_radius3; // squared + + toparcx = Mxposn - sa_radius; // draw radius outline circle + toparcy = Myposn - sa_radius; + toparcw = toparch = 2 * sa_radius; + Ftoparc = 1; + paint_toparc(3); + + if (RMclick) { // right mouse click + RMclick = 0; + sa_unselect_pixels(); // remove latest selection v.10.8 + mwpaint2(); + return; + } + + if ((Mxdrag || Mydrag) && Mbutton == 3) { // right drag, find and unselect pixels + sa_mousex = Mxdrag; + sa_mousey = Mydrag; + Mxdrag = Mydrag = 0; + sa_find_color_pixels(0); + mwpaint2(); + return; + } + + sa_mousex = sa_mousey = 0; + + if (LMclick) { // left mouse click + sa_mousex = Mxclick; + sa_mousey = Myclick; + LMclick = 0; + sa_nextseq(); // set next sequence no. v.10.8 + drag = 1; // reset drag counter + } + + if ((Mxdrag || Mydrag) && Mbutton == 1) { // left drag, select matching colors + sa_mousex = Mxdrag; + sa_mousey = Mydrag; + Mxdrag = Mydrag = 0; + + if (Mxdown != mxdown || Mydown != mydown) { // detect if new drag started + mxdown = Mxdown; + mydown = Mydown; + sa_nextseq(); // set next sequence no. v.10.8 + drag = 1; // reset drag counter + } + else if (++drag > 30) { // limit work per sequence no. + sa_nextseq(); // set next sequence no. v.10.8 + drag = 1; // reset drag counter + } + } + + if (sa_mousex || sa_mousey) { + sa_find_color_pixels(1); // find and select pixels + mwpaint2(); + } + + return; +} + + +// find all contiguous pixels within the specified range of colors to match +// select or unselect the matching pixels + +void sa_find_color_pixels(int select) // revised v.11.12 +{ + int ii, kk, cc, px, py, rx, ry, rad2; + int ppx, ppy, npx, npy; + uint16 *matchpix; + double match1, match2, ff = 1.0 / 65536.0; + double dred, dgreen, dblue; + char direc; + + px = sa_mousex; + py = sa_mousey; + if (px < 0 || px > Fww-1) return; // mouse outside image + if (py < 0 || py > Fhh-1) return; + + sa_Ncurrseq = 0; // count newly selected pixels + + for (rx = -sa_radius; rx <= sa_radius; rx++) // loop every pixel in radius of mouse + for (ry = -sa_radius; ry <= sa_radius; ry++) // v.11.12 + { + rad2 = rx * rx + ry * ry; + if (rad2 > sa_radius2) continue; // outside radius + px = sa_mousex + rx; + py = sa_mousey + ry; + if (px < 0 || px > Fww-1) continue; // off the image edge + if (py < 0 || py > Fhh-1) continue; + + ii = Fww * py + px; + + if (select) { // select pixel + if (sa_pixmap[ii]) continue; + sa_pixmap[ii] = sa_currseq; // map pixel to current sequence + sa_Ncurrseq++; // current sequence pixel count + } + else sa_pixmap[ii] = 0; // unselect + } + + if (! sa_matchcolor) return; // no color matching, done v.11.12 + + match1 = 0.01 * sa_colormatch; // color match level, 0.01 to 1.0 + sa_Nmatch = 0; // match color count + + for (rx = -sa_radius; rx <= sa_radius; rx++) // loop every pixel in radius of mouse + for (ry = -sa_radius; ry <= sa_radius; ry++) + { + rad2 = rx * rx + ry * ry; + if (rad2 > sa_radius2) continue; // outside radius + px = sa_mousex + rx; + py = sa_mousey + ry; + if (px < 0 || px > Fww-1) continue; // off the image edge + if (py < 0 || py > Fhh-1) continue; + + matchpix = PXMpix(Fpxm16,px,py); // get color at mouse position + + for (ii = 0; ii < sa_Nmatch; ii++) // see if color is already included + { + dred = ff * abs(sa_matchRGB[ii][0] - matchpix[0]); // 0 = perfect match + dgreen = ff * abs(sa_matchRGB[ii][1] - matchpix[1]); + dblue = ff * abs(sa_matchRGB[ii][2] - matchpix[2]); + match2 = (1.0 - dred) * (1.0 - dgreen) * (1.0 - dblue); // 1 = perfect match + if (match2 >= match1) break; // matches close enough + } + + if (ii == sa_Nmatch) { // no close match + sa_matchRGB[ii][0] = matchpix[0]; // add new match color to list + sa_matchRGB[ii][1] = matchpix[1]; + sa_matchRGB[ii][2] = matchpix[2]; + sa_Nmatch++; + if (sa_Nmatch == 1000) goto startsearch; // capacity limit + } + } + +startsearch: + + if (sa_stackdirec) zfree(sa_stackdirec); // get memory + if (sa_stackii) zfree(sa_stackii); + if (sa_pixselc) zfree(sa_pixselc); + cc = Fww * Fhh; + sa_stackdirec = zmalloc(cc,"sa_color"); + sa_stackii = (int *) zmalloc(4*cc,"sa_color"); + sa_maxstack = cc; + sa_Nstack = 0; + sa_pixselc = zmalloc(cc,"sa_color"); + memset(sa_pixselc,0,cc); + + px = sa_mousex; // pixel at mouse + py = sa_mousey; + ii = Fww * py + px; + sa_pixselc[ii] = 1; // pixel is in current selection + + if (! sa_pixmap[ii]) { // if selected for the first time, v.10.12 + sa_pixmap[ii] = sa_currseq; // map pixel to current sequence + sa_Ncurrseq++; // current sequence pixel count + } + + sa_stackii[0] = ii; // put 1st pixel into stack + sa_stackdirec[0] = 'a'; // direction = ahead v.11.04 + sa_Nstack = 1; // stack count + + while (sa_Nstack) + { + kk = sa_Nstack - 1; // get last pixel in stack + ii = sa_stackii[kk]; + direc = sa_stackdirec[kk]; + + py = ii / Fww; // reconstruct px, py + px = ii - Fww * py; + + if (direc == 'x') { // no neighbors left to check + sa_Nstack--; + continue; + } + + if (sa_Nstack > 1) { + ii = sa_Nstack - 2; // get prior pixel in stack + ii = sa_stackii[ii]; + ppy = ii / Fww; + ppx = ii - ppy * Fww; + } + else { + ppx = px - 1; // if only one, assume prior = left + ppy = py; + } + + if (direc == 'a') { // next ahead pixel v.11.04 + npx = px + px - ppx; + npy = py + py - ppy; + sa_stackdirec[kk] = 'r'; // next search direction + } + + else if (direc == 'r') { // next right pixel v.11.04 + npx = px + py - ppy; + npy = py + px - ppx; + sa_stackdirec[kk] = 'l'; + } + + else { /* direc = 'l' */ // next left pixel v.11.04 + npx = px + ppy - py; + npy = py + ppx - px; + sa_stackdirec[kk] = 'x'; + } + + if (npx < 0 || npx > Fww-1) continue; // pixel off the edge v.11.04 + if (npy < 0 || npy > Fhh-1) continue; + + rx = npx - Mxposn; // limit search to + ry = npy - Myposn; // mouse radius * search range + rad2 = rx * rx + ry * ry; + if (rad2 > sa_radius3) continue; // v.11.12 + + ii = npy * Fww + npx; + + if (sa_pixselc[ii]) continue; // already in current selection + + if (select && sa_firewall && sa_pixmap[ii]) // aleady selected, firewall mode + if (rad2 > sa_radius2) continue; // and pixel outside mouse radius + + matchpix = PXMpix(Fpxm16,npx,npy); + for (kk = 0; kk < sa_Nmatch; kk++) { // compare pixel RGB to match colors + dred = ff * abs(sa_matchRGB[kk][0] - matchpix[0]); // v.10.8 + dgreen = ff * abs(sa_matchRGB[kk][1] - matchpix[1]); + dblue = ff * abs(sa_matchRGB[kk][2] - matchpix[2]); + match2 = (1.0 - dred) * (1.0 - dgreen) * (1.0 - dblue); // 1 = perfect match + if (match2 >= match1) break; // within range + } + if (kk == sa_Nmatch) continue; // not within range of any color + + sa_pixselc[ii] = 1; // map pixel to current selection + + if (select) { // select mode + if (! sa_pixmap[ii]) { // if selected for the first time, + sa_pixmap[ii] = sa_currseq; // map pixel to current sequence + sa_Ncurrseq++; // current sequence pixel count + } + } + else sa_pixmap[ii] = 0; // unselect mode v.11.12 + + if (sa_Nstack == sa_maxstack) continue; // stack is full + kk = sa_Nstack++; // push pixel into stack + sa_stackii[kk] = ii; + sa_stackdirec[kk] = 'a'; // direction = ahead v.11.04 + } + + return; +} + + +// set next sequence number for pixels about to be selected + +void sa_nextseq() // v.10.8 +{ + if (sa_Ncurrseq > 0) sa_currseq++; // increase only if some pixels mapped + if (sa_currseq < sa_initseq) sa_currseq = sa_initseq; // start at initial value + sa_Ncurrseq = 0; + return; +} + + +// un-select all pixels mapped to current sequence number +// reduce sequence number and set pixel count = 1 + +void sa_unselect_pixels() +{ + if (sa_stat != 1) return; // area gone? v.11.07 + if (! sa_currseq) return; // no pixels mapped + + for (int ii = 0; ii < Fww * Fhh; ii++) + if (sa_pixmap[ii] == sa_currseq) sa_pixmap[ii] = 0; // unmap current selection + + if (sa_currseq > sa_initseq) { // reduce sequence no. v.10.8 + sa_currseq--; + sa_Ncurrseq = 1; // unknown but > 0 + } + else sa_Ncurrseq = 0; // initial sequence no. reached + + return; +} + + +// Finish select area - map pixels enclosed by edge pixels +// into sa_pixmap[ii]: 0/1/2 = outside/edge/inside (ii=py*Fww+px) +// total count = sa_Npixel + +zdialog *safinzd = 0; + +void sa_finish() // overhauled v.11.02 +{ + void sa_finish_mousefunc(); + int sa_finish_dialog_event(zdialog *, cchar *event); + + cchar *fmess = ZTX("Click one time inside each enclosed area \n" + "(possible gaps in the outline will be found). \n" + "Press F1 for help."); + + GtkWidget *pwin = zdialog_widget(zdsela,"dialog"); + int ii, cc, px, py; + + if (! sa_stat) return; // no area? v.11.07 + if (sa_fww != Fww || sa_fhh != Fhh) return; // area not valid for image v.11.08 + if (sa_mode == 7) return; // a whole image area + + sa_Npixel = Factivearea = 0; // area disabled, unfinished + sa_finOK = sa_finhole = 0; // count areas OK and with holes + sa_show(1); // show outline + + sa_minx = Fww; + sa_maxx = 0; + sa_miny = Fhh; + sa_maxy = 0; + + for (ii = 0; ii < Fww * Fhh; ii++) // get enclosing rectangle + { // for selected area(s) + if (! sa_pixmap[ii]) continue; + py = ii / Fww; + px = ii - Fww * py; + if (px >= sa_maxx) sa_maxx = px+1; // like Fww, sa_maxx = last + 1 + if (px < sa_minx) sa_minx = px; + if (py >= sa_maxy) sa_maxy = py+1; + if (py < sa_miny) sa_miny = py; + } + + sa_map_pixels(); // map edge and interior pixels + if (sa_Npixel < 10) return; // ridiculous + + sa_minx -= 10; // add margins where possible + if (sa_minx < 0) sa_minx = 0; + sa_maxx += 10; + if (sa_maxx > Fww) sa_maxx = Fww; + sa_miny -= 10; + if (sa_miny < 0) sa_miny = 0; + sa_maxy += 10; + if (sa_maxy > Fhh) sa_maxy = Fhh; + + for (py = sa_miny; py < sa_maxy; py++) // loop pixels in rectangle v.10.12 + for (px = sa_minx; px < sa_maxx; px++) + { + ii = Fww * py + px; // eliminate interior pixels + if (sa_pixmap[ii] == 2) sa_pixmap[ii] = 0; // from prior finish functions + } + + cc = (sa_maxx-sa_minx) * (sa_maxy-sa_miny); // allocate stack memory + if (sa_stackdirec) zfree(sa_stackdirec); + sa_stackdirec = zmalloc(cc,"sa_finish"); + if (sa_stackii) zfree(sa_stackii); + sa_stackii = (int *) zmalloc(cc * 4,"sa_finish"); + sa_maxstack = cc; + + safinzd = zdialog_new(ZTX("finish area"),pwin,Bdone,Bcancel,null); // dialog for user to click inside + zdialog_add_widget(safinzd,"label","fmess","dialog",fmess,"space=5"); // each enclosed area + zdialog_add_widget(safinzd,"hbox","hbstat","dialog"); + zdialog_add_widget(safinzd,"label","labstat","hbstat","status:","space=5"); + zdialog_add_widget(safinzd,"label","statmess","hbstat",0); + + takeMouse(safinzd,sa_finish_mousefunc,dragcursor); // connect mouse function v.11.03 + + zdialog_run(safinzd,sa_finish_dialog_event,"save"); // run dialog, parallel v.11.07 + zdialog_wait(safinzd); + return; +} + + +// mouse function - get user clicks and perform pixel searches + +void sa_finish_mousefunc() // overhauled v.11.02 +{ + int px, py, ii, kk; + int ppx, ppy, npx, npy; + int finhole = 0; + char direc; + + if (! LMclick) return; + LMclick = 0; + + if (! sa_stat) return; // area gone? v.11.07 + + ii = Fww * Myclick + Mxclick; // seed pixel from mouse click + if (sa_pixmap[ii] == 1) return; // ignore if edge pixel v.11.07 + sa_pixmap[ii] = 2; // map the pixel, inside area + sa_stackii[0] = ii; // put seed pixel into stack + sa_stackdirec[0] = 'a'; // direction = ahead v.11.04 + sa_Nstack = 1; // stack count + + zdialog_stuff(safinzd,"statmess",ZTX("searching")); + zmainloop(); + zsleep(0.2); + + Ffuncbusy++; + + while (sa_Nstack) // find all pixels outside enclosed area(s) + { + kk = sa_Nstack - 1; // get last pixel in stack + ii = sa_stackii[kk]; + direc = sa_stackdirec[kk]; + + py = ii / Fww; // reconstruct px, py + px = ii - Fww * py; + + if (px < sa_minx || px >= sa_maxx || py < sa_miny || py >= sa_maxy) // moved v.11.08 + { + finhole++; // ran off the edge, seed pixel was + break; // not inside area or area has a hole + } + + if (direc == 'x') { // no neighbors left to check + sa_Nstack--; + continue; + } + + if (sa_Nstack > 1) { + ii = sa_Nstack - 2; // get prior pixel in stack + ii = sa_stackii[ii]; + ppy = ii / Fww; + ppx = ii - ppy * Fww; + } + else { + ppx = px - 1; // if only one, assume prior = left + ppy = py; + } + + if (direc == 'a') { // next ahead pixel v.11.04 + npx = px + px - ppx; + npy = py + py - ppy; + sa_stackdirec[kk] = 'r'; // next search direction + } + + else if (direc == 'r') { // next right pixel v.11.04 + npx = px + py - ppy; + npy = py + px - ppx; + sa_stackdirec[kk] = 'l'; + } + + else { /* direc = 'l' */ // next left pixel v.11.04 + npx = px + ppy - py; + npy = py + ppx - px; + sa_stackdirec[kk] = 'x'; + } + + if (npx < 0 || npx > Fww-1) continue; // next pixel off the image edge + if (npy < 0 || npy > Fhh-1) continue; // bugfix v.11.04 + + ii = npy * Fww + npx; + if (sa_pixmap[ii]) continue; // pixel already mapped + + sa_pixmap[ii] = 2; // map the pixel, inside area + kk = sa_Nstack++; // put pixel into stack + sa_stackii[kk] = ii; + sa_stackdirec[kk] = 'a'; // direction = ahead v.11.04 + draw_pixel(npx,npy,sa_pixRGB); // color mapped pixels + zmainloop(10); // let window update v.11.07 + } + + Ffuncbusy--; + + if (finhole) { // this area has a hole + zdialog_stuff(safinzd,"statmess",ZTX("outline has a gap")); + sa_finhole++; + } + else { + zdialog_stuff(safinzd,"statmess",ZTX("success")); // all pixels found and mapped + sa_finOK++; + } + return; +} + + +// dialog event and completion callback function + +int sa_finish_dialog_event(zdialog *zd, cchar *event) +{ + int zstat; + + zstat = zd->zstat; + if (! zstat) return 0; + + freeMouse(); // disconnect mouse + zdialog_free(safinzd); // kill dialog + + if (! sa_stat) return 0; // area gone? v.11.07 + + if (zstat != 1 || sa_finOK == 0 || sa_finhole) { // user cancel or pixel search failure + sa_unfinish(); // unmap interior pixels, set edit mode + return 0; // v.11.07 + } + + sa_map_pixels(); // count pixels, map interior pixels + + sa_stat = 3; // area is finished + Factivearea = 1; // area is active by default + areanumber++; // next sequential number + sa_calced = sa_blend = 0; // edge calculation is missing + if (zdsela) zdialog_stuff(zdsela,"blendwidth",0); // v.11.12 + mwpaint2(); + return 0; +} + + +// Finish select area automatically when the +// interior selected pixels are already known. + +void sa_finish_auto() +{ + int ii, px, py; + + if (! sa_stat) return; // no area? v.11.07 + if (sa_fww != Fww || sa_fhh != Fhh) return; // area not valid for image v.11.08 + + sa_Npixel = Factivearea = 0; // area disabled, unfinished + + sa_minx = Fww; + sa_maxx = 0; + sa_miny = Fhh; + sa_maxy = 0; + + for (ii = 0; ii < Fww * Fhh; ii++) // get enclosing rectangle + { // for selected area + if (! sa_pixmap[ii]) continue; + py = ii / Fww; + px = ii - Fww * py; + if (px >= sa_maxx) sa_maxx = px+1; // like Fww, sa_maxx = last + 1 + if (px < sa_minx) sa_minx = px; + if (py >= sa_maxy) sa_maxy = py+1; + if (py < sa_miny) sa_miny = py; + } + + sa_minx -= 10; // add margins where possible + if (sa_minx < 0) sa_minx = 0; + sa_maxx += 10; + if (sa_maxx > Fww) sa_maxx = Fww; + sa_miny -= 10; + if (sa_miny < 0) sa_miny = 0; + sa_maxy += 10; + if (sa_maxy > Fhh) sa_maxy = Fhh; + + sa_map_pixels(); // count pixels, map interior pixels + + sa_stat = 3; // area is finished + Factivearea = 1; // area is active by default + areanumber++; // next sequential number + sa_calced = sa_blend = 0; // edge calculation is missing + mwpaint2(); + return; +} + + +// private function +// map edge and interior pixels (sa_pixmap[*] = 1 or 2) +// set sa_Npixel = total pixel count + +void sa_map_pixels() // v.11.07 +{ + int npix, px, py, ii, kk; + + if (! sa_stat) return; // no area? + + npix = 0; + + for (py = sa_miny; py < sa_maxy; py++) // find edge pixels + for (px = sa_minx; px < sa_maxx; px++) + { + ii = py * Fww + px; + if (! sa_pixmap[ii]) continue; + npix++; + + if (px == 0 || px == Fww-1 || py == 0 || py == Fhh-1) // edge of image + goto edgepix; + + if (! sa_pixmap[ii-1] || ! sa_pixmap[ii+1]) goto edgepix; // check 8 neighbor pixels + kk = ii - Fww; + if (! sa_pixmap[kk] || ! sa_pixmap[kk-1] || ! sa_pixmap[kk+1]) goto edgepix; + kk = ii + Fww; + if (! sa_pixmap[kk] || ! sa_pixmap[kk-1] || ! sa_pixmap[kk+1]) goto edgepix; + + sa_pixmap[ii] = 2; // interior pixel + continue; + + edgepix: + sa_pixmap[ii] = 1; // edge pixel + } + + sa_Npixel = npix; // total pixel count + return; +} + + +// unfinish an area - unmap interior pixels and put back in edit mode + +void sa_unfinish() // v.11.07 +{ + int px, py, ii; + + if (! sa_stat) return; // no area? + + for (py = sa_miny; py < sa_maxy; py++) // loop pixels in rectangle + for (px = sa_minx; px < sa_maxx; px++) + { + ii = py * Fww + px; // clear interior pixels found + if (sa_pixmap[ii] == 2) sa_pixmap[ii] = 0; // by finish search function + } + + sa_stat = 1; // resume edit mode + Factivearea = 0; + sa_calced = sa_blend = 0; + if (zdsela) zdialog_stuff(zdsela,"blendwidth",0); // v.11.12 + mwpaint2(); + return; +} + + +// menu function for show, hide, enable, disable, invert, unselect +// (also implemented as buttons in select area dialog) + +void m_select_show(GtkWidget *, cchar *menu) +{ + zfuncs::F1_help_topic = "area_show_hide"; + sa_show(1); + return; +} + + +void m_select_hide(GtkWidget *, cchar *menu) +{ + zfuncs::F1_help_topic = "area_show_hide"; + sa_show(0); + return; +} + + +void m_select_enable(GtkWidget *, cchar *menu) +{ + zfuncs::F1_help_topic = "area_enable_disable"; + sa_enable(); + return; +} + + +void m_select_disable(GtkWidget *, cchar *menu) +{ + zfuncs::F1_help_topic = "area_enable_disable"; + sa_disable(); + return; +} + + +void m_select_invert(GtkWidget *, cchar *menu) +{ + zfuncs::F1_help_topic = "area_invert"; + sa_invert(); + return; +} + + +void m_select_unselect(GtkWidget *, cchar *menu) // delete the area +{ + zfuncs::F1_help_topic = "area_unselect"; + sa_unselect(); + return; +} + + +// show or hide outline of select area +// also called from mwpaint1() if Fshowarea = 1 + +void sa_show(int flag) +{ + int px, py, ii, kk; + + if (! sa_stat) return; // no area + if (sa_fww != Fww || sa_fhh != Fhh) return; // area not valid for image + if (sa_mode == 7) return; // a whole image area + if (Fpreview) return; // preview mode, area ignored + + Fshowarea = flag; // flag for mwpaint1() + + if (! flag) { + mwpaint2(); // erase area outline v.10.8 + return; + } + + for (py = 0; py < Fhh; py++) // find pixels in area bugfix v.10.9 + for (px = 0; px < Fww; px++) + { + ii = py * Fww + px; + if (! sa_pixmap[ii]) continue; // outside of area + + if (px == 0 || px == Fww-1 || py == 0 || py == Fhh-1) // edge of image + goto edgepix; + + if (! sa_pixmap[ii-1] || ! sa_pixmap[ii+1]) goto edgepix; // check 8 neighbor pixels + kk = ii - Fww; + if (! sa_pixmap[kk] || ! sa_pixmap[kk-1] || ! sa_pixmap[kk+1]) goto edgepix; + kk = ii + Fww; + if (! sa_pixmap[kk] || ! sa_pixmap[kk-1] || ! sa_pixmap[kk+1]) goto edgepix; + continue; + + edgepix: + draw_fat_pixel(px,py,sa_pixRGB); // draw fat pixels v.11.04 + } + + return; +} + + +// enable select area that was disabled + +void sa_enable() +{ + if (sa_fww != Fww || sa_fhh != Fhh) return; // area not valid for image v.11.08 + + if (sa_stat != 3) { + zmessageACK(mWin,ZTX("the area is not finished")); // v.11.08 + return; // v.11.06.1 + } + + Factivearea = 1; + areanumber++; // next sequential number + sa_show(1); // v.10.11 + return; +} + + +// disable select area + +void sa_disable() +{ + Factivearea = 0; // v.9.7 + sa_show(0); // v.10.11 + return; +} + + +// invert a selected area + +void sa_invert() +{ + int ii, jj, px, py, npix; + + if (sa_fww != Fww || sa_fhh != Fhh) return; // area not valid for image v.11.08 + + if (sa_stat != 3) { // v.11.06.1 + zmessageACK(mWin,ZTX("the area is not finished")); + return; + } + + if (sa_mode == 7) return; // a whole image area + + npix = 0; + + for (py = 0; py < Fhh; py++) // loop all pixels + for (px = 0; px < Fww; px++) + { + ii = py * Fww + px; + jj = sa_pixmap[ii]; // 0/1/2+ = outside/edge/inside + + if (px == 0 || px == Fww-1 || py == 0 || py == Fhh-1) // pixel on image edge v.10.12 + { + if (jj == 0) { + sa_pixmap[ii] = 1; // outside pixel >> edge pixel + npix++; // count + } + else sa_pixmap[ii] = 0; // edge pixel >> outside + continue; + } + + if (jj > 1) sa_pixmap[ii] = 0; // inside pixel (2+) >> outside (0) + else { + sa_pixmap[ii] = 2 - jj; // edge/outside (1/0) >> edge/inside (1/2) + npix++; // count + } + } + + sa_Npixel = npix; // new select area pixel count + sa_calced = sa_blend = 0; // edge calculation missing + if (zdsela) zdialog_stuff(zdsela,"blendwidth",0); // reset blend width v.11.01 + + sa_minx = Fww; // new enclosing rectangle bugfix v.11.01 + sa_maxx = 0; + sa_miny = Fhh; + sa_maxy = 0; + + for (ii = 0; ii < Fww * Fhh; ii++) + { + if (! sa_pixmap[ii]) continue; + py = ii / Fww; + px = ii - Fww * py; + if (px >= sa_maxx) sa_maxx = px + 1; + if (px < sa_minx) sa_minx = px; + if (py >= sa_maxy) sa_maxy = py + 1; + if (py < sa_miny) sa_miny = py; + } + + return; +} + + +// unselect current area (delete the area) + +void sa_unselect() +{ + sa_stat = sa_Npixel = sa_blend = sa_calced = Factivearea = 0; + sa_currseq = sa_Ncurrseq = 0; + sa_fww = sa_fhh = 0; // v.11.08 + if (sa_pixmap) zfree(sa_pixmap); + if (sa_stackii) zfree(sa_stackii); + if (sa_stackdirec) zfree(sa_stackdirec); + if (sa_pixselc) zfree(sa_pixselc); + sa_pixmap = 0; + sa_stackii = 0; + sa_stackdirec = 0; + sa_pixselc = 0; + mwpaint2(); + return; +} + + +// compute distance from all pixels in area to nearest edge +// output: sa_pixmap[*] = 0/1/2+ = outside, edge, inside distance from edge + +namespace sa_edgecalc_names +{ + uint16 *sa_edgepx, *sa_edgepy, *sa_edgedist; + int sa_Nedge; +} + +void sa_edgecalc() +{ + using namespace sa_edgecalc_names; + + int edgecalc_dialog_event(zdialog*, cchar *event); + void * edgecalc_thread(void *); + + int ii, nn, cc, px, py; + zdialog *zd = 0; + cchar *zectext = ZTX("Edge calculation in progress"); + + if (! sa_stat) return; // area gone? v.11.07 + if (sa_mode == 7) return; // a whole image area + + if (sa_calced) return; // done already + if (! Factivearea) sa_finish(); // finish if needed + if (! Factivearea) return; // no finished area + + zd = zdialog_new(ZTX("Area Edge Calc"),mWin,Bcancel,null); // start dialog for user cancel + zdialog_add_widget(zd,"label","lab1","dialog",zectext,"space=10"); + zdialog_run(zd,edgecalc_dialog_event); + Fkillfunc = 0; + + cc = Fww * Fhh * sizeof(uint16); // allocate memory for calculations + sa_edgedist = (uint16 *) zmalloc(cc,"sa_edgecalc"); + memset(sa_edgedist,0,cc); + + for (ii = nn = 0; ii < Fww * Fhh; ii++) // count edge pixels in select area + if (sa_pixmap[ii] == 1) nn++; + + cc = nn * sizeof(uint16); + sa_edgepx = (uint16 *) zmalloc(cc,"sa_edgecalc"); // allocate memory + sa_edgepy = (uint16 *) zmalloc(cc,"sa_edgecalc"); + + for (ii = nn = 0; ii < Fww * Fhh; ii++) // build list of edge pixels + { // v.9.6 + if (sa_pixmap[ii] != 1) continue; + py = ii / Fww; + px = ii - py * Fww; + if (px < 3 || px > Fww-4) continue; // omit pixels < 3 from image edge + if (py < 3 || py > Fhh-4) continue; + sa_edgepx[nn] = px; + sa_edgepy[nn] = py; + nn++; + } + + sa_Nedge = nn; + SB_goal = sa_Npixel; + SB_done = 0; + + for (ii = 0; ii < Nwt; ii++) // start worker threads to calculate + start_wthread(edgecalc_thread,&wtnx[ii]); // sa_pixmap[] edge distances + wait_wthreads(); // wait for completion + + SB_goal = 0; + + if (! Fkillfunc) { // v.11.07 + for (ii = 0; ii < Fww * Fhh; ii++) // copy data from sa_edgedist[] + { // to sa_pixmap[] + if (sa_pixmap[ii] < 2) continue; // skip outside and edge pixels + sa_pixmap[ii] = sa_edgedist[ii]; // interior pixel edge distance + } + } + + zdialog_free(zd); // kill dialog + zfree(sa_edgedist); // free memory + zfree(sa_edgepx); + zfree(sa_edgepy); + + if (Fkillfunc) { + Fkillfunc = 0; + sa_calced = 0; + if (zdsela) zdialog_stuff(zdsela,"blendwidth",0); // reset blend width v.11.01 + } + + sa_calced = 1; // edge calculation available + + mwpaint2(); + return; +} + + +// dialog event and completion callback function + +int edgecalc_dialog_event(zdialog *zd, cchar *event) // respond to user cancel +{ + if (! zd->zstat) return 0; + Fkillfunc = 1; + printf("edge calc killed \n"); + return 0; +} + + +void * edgecalc_thread(void *arg) // worker thread function +{ // new algorithm v.11.05 + using namespace sa_edgecalc_names; + + void edgecalc_f1(int px, int py); + + int index = *((int *) (arg)); + int midx, midy, radx, rady, rad; + int ii, px, py; + + midx = (sa_maxx + sa_minx) / 2; + midy = (sa_maxy + sa_miny) / 2; + radx = (sa_maxx - sa_minx) / 2 + 1; + rady = (sa_maxy - sa_miny) / 2 + 1; + px = midx; // center of enclosing rectangle + py = midy; + + ii = py * Fww + px; + if (sa_pixmap[ii]) edgecalc_f1(px,py); // do center pixel first + + for (rad = 1; rad < radx || rad < rady; rad++) // expanding square from the center + { + for (px = midx-rad; px <= midx+rad; px += 2 * rad) // process edges only, interior already done + for (py = midy-rad+index; py <= midy+rad; py += Nwt) + { + if (px < 0 || px > Fww-1) continue; + if (py < 0 || py > Fhh-1) continue; + ii = py * Fww + px; + if (! sa_pixmap[ii]) continue; + if (sa_edgedist[ii]) continue; + edgecalc_f1(px,py); + if (Fkillfunc) exit_wthread(); + } + + for (py = midy-rad; py <= midy+rad; py += 2 * rad) + for (px = midx-rad+index; px <= midx+rad; px += Nwt) + { + if (px < 0 || px > Fww-1) continue; + if (py < 0 || py > Fhh-1) continue; + ii = py * Fww + px; + if (! sa_pixmap[ii]) continue; + if (sa_edgedist[ii]) continue; + edgecalc_f1(px,py); + if (Fkillfunc) exit_wthread(); + } + } + + exit_wthread(); + return 0; // not executed, stop gcc warning +} + + +// Find the nearest edge pixel for a given pixel. +// For all pixels in a line from the given pixel to the edge pixel, +// the same edge pixel is used to compute edge distance. + +void edgecalc_f1(int px1, int py1) +{ + using namespace sa_edgecalc_names; + + int ii, px2, py2, mindist; + uint dist2, mindist2; + int epx, epy, pxm, pym, dx, dy, inc; + double slope; + + mindist = 9999; + mindist2 = mindist * mindist; + epx = epy = 0; + + for (ii = 0; ii < sa_Nedge; ii++) // loop all edge pixels + { + px2 = sa_edgepx[ii]; + py2 = sa_edgepy[ii]; + dx = px2 - px1; + dy = py2 - py1; + dist2 = dx*dx + dy*dy; // avoid sqrt() + if (dist2 < mindist2) { + mindist2 = dist2; // remember minimum + epx = px2; // remember nearest edge pixel + mindist = sqrt(dist2); + epy = py2; + } + } + + if (abs(epy - py1) > abs(epx - px1)) { // find all pixels along a line + slope = 1.0 * (epx - px1) / (epy - py1); // to the edge pixel + if (epy > py1) inc = 1; + else inc = -1; + for (pym = py1; pym != epy; pym += inc) { + pxm = px1 + slope * (pym - py1); + ii = pym * Fww + pxm; + if (sa_edgedist[ii]) break; + dx = epx - pxm; // calculate distance to edge + dy = epy - pym; + dist2 = sqrt(dx*dx + dy*dy) + 2; + sa_edgedist[ii] = dist2; // save + SB_done++; // track progress v.11.06 + } + } + + else { + slope = 1.0 * (epy - py1) / (epx - px1); + if (epx > px1) inc = 1; + else inc = -1; + for (pxm = px1; pxm != epx; pxm += inc) { + pym = py1 + slope * (pxm - px1); + ii = pym * Fww + pxm; + if (sa_edgedist[ii]) break; + dx = epx - pxm; + dy = epy - pym; + dist2 = sqrt(dx*dx + dy*dy) + 2; + sa_edgedist[ii] = dist2; + SB_done++; + } + } + + return; +} + + +/************************************************************************** + select area copy and paste menu functions +***************************************************************************/ + +PXM *sacp_image16 = 0; // select area pixmap image +PXM *sacp_info16 = 0; // opacity and edge distance +int sacp_ww, sacp_hh; // original dimensions + +PXM *sacpR_image16 = 0; // resized/rotated image +PXM *sacpR_info16 = 0; // resized/rotated info +int sacpR_ww, sacpR_hh; // resized/rotated dimensions + +double sacp_resize; // size, 1.0 = original size +double sacp_angle; // angle of rotation, -180 to +180 +int sacp_orgx, sacp_orgy; // origin in target image +double sacp_blend; // edge blend with target image + + +// copy selected area, save in memory + +void m_select_copy(GtkWidget *, cchar *menu) // overhauled v.11.02 +{ + int ii, px, py; + int pxmin, pxmax, pymin, pymax; + uint16 *pix1, *pix2; + + if (menu) zfuncs::F1_help_topic = "area_copy_paste"; + + if (sa_mode == 7) return; // a whole image area v.11.01 + if (! Factivearea) sa_finish(); // finish area if not already + if (! Factivearea) return; + sa_edgecalc(); // do edge calc if not already + sa_show(0); + + pxmin = Fww; + pxmax = 0; + pymin = Fhh; + pymax = 0; + + for (ii = 0; ii < Fww * Fhh; ii++) // find pixels in select area + { // v.9.6 + if (! sa_pixmap[ii]) continue; + py = ii / Fww; + px = ii - py * Fww; + if (px > pxmax) pxmax = px; // find enclosing rectangle + if (px < pxmin) pxmin = px; + if (py > pymax) pymax = py; + if (py < pymin) pymin = py; + } + + PXM_free(sacp_image16); // free prior if any + PXM_free(sacp_info16); + PXM_free(sacpR_image16); + PXM_free(sacpR_info16); + + sacp_ww = pxmax - pxmin + 1; // new area image PXM + sacp_hh = pymax - pymin + 1; + sacp_image16 = PXM_make(sacp_ww,sacp_hh,16); + sacp_info16 = PXM_make(sacp_ww,sacp_hh,16); // new info PXM + + for (ii = 0; ii < Fww * Fhh; ii++) // find pixels in select area + { + if (! sa_pixmap[ii]) continue; // 0/1/2+ = outside/edge/inside edge distance + py = ii / Fww; + px = ii - py * Fww; + pix1 = PXMpix(Fpxm16,px,py); // copy pixels into image PXM + px = px - pxmin; + py = py - pymin; + pix2 = PXMpix(sacp_image16,px,py); + pix2[0] = pix1[0]; + pix2[1] = pix1[1]; + pix2[2] = pix1[2]; + pix2 = PXMpix(sacp_info16,px,py); // build info PXM v.11.02 + pix2[0] = 65535; // opacity + pix2[1] = sa_pixmap[ii]; // edge distance + pix2[2] = 0; + } + + return; +} + + +// paste selected area into current image +// this is an edit function - select area image is copied into main image + +int sacp_porg = 0; // pasted area is present +int sacp_porgx, sacp_porgy; // pasted area origin in image +int sacp_pww, sacp_phh; // pasted area dimensions + +editfunc EFpaste; + +void m_select_paste(GtkWidget *, cchar *menu) // menu function +{ + int select_paste_dialog_event(zdialog *, cchar *event); + void select_paste_mousefunc(); + + cchar *dragmess = ZTX("position with mouse click/drag"); + + if (menu) zfuncs::F1_help_topic = "area_copy_paste"; + + if (! sacp_image16) return; // nothing to paste + sa_unselect(); // unselect area if present + + EFpaste.funcname = "paste"; + if (! edit_setup(EFpaste)) return; // setup edit for paste + + sacp_resize = 1.0; // size = 1x + sacp_blend = 1; // edge blend = 1 + sacp_angle = 0; // angle = 0 + + PXM_free(sacpR_image16); // free prior if any + PXM_free(sacpR_info16); + + sacpR_ww = sacp_ww; // setup resized paste image + sacpR_hh = sacp_hh; // (initially 1x, 0 rotation) + sacpR_image16 = PXM_copy(sacp_image16); + sacpR_info16 = PXM_copy(sacp_info16); + + sacp_porg = 0; // no image paste location yet + + CEF->zd = zdialog_new(ZTX("Paste Image"),mWin,Bdone,Bcancel,null); + zdialog_add_widget(CEF->zd,"hbox","hb0","dialog",0,"space=8"); + zdialog_add_widget(CEF->zd,"label","lab1","hb0",dragmess,"space=8"); + + zdialog_add_widget(CEF->zd,"hbox","hbres","dialog",0,"space=5"); + zdialog_add_widget(CEF->zd,"label","labres","hbres","resize"); + zdialog_add_widget(CEF->zd,"button","+.1%","hbres","+.1%"); + zdialog_add_widget(CEF->zd,"button","+1%","hbres","+1%"); + zdialog_add_widget(CEF->zd,"button","+10%","hbres","+10%"); + zdialog_add_widget(CEF->zd,"button","-.1%","hbres","-.1%"); + zdialog_add_widget(CEF->zd,"button","-1%","hbres","-1%"); + zdialog_add_widget(CEF->zd,"button","-10%","hbres","-10%"); + + zdialog_add_widget(CEF->zd,"hbox","hbang","dialog",0,"space=5"); // rotation v.11.02 + zdialog_add_widget(CEF->zd,"label","labang","hbang",ZTX("angle")); + zdialog_add_widget(CEF->zd,"button","+.1°","hbang","+.1°"); + zdialog_add_widget(CEF->zd,"button","+1°","hbang","+1°"); + zdialog_add_widget(CEF->zd,"button","+10°","hbang","+10°"); + zdialog_add_widget(CEF->zd,"button","-.1°","hbang","-.1°"); + zdialog_add_widget(CEF->zd,"button","-1°","hbang","-1°"); + zdialog_add_widget(CEF->zd,"button","-10°","hbang","-10°"); + + zdialog_add_widget(CEF->zd,"hbox","hbbl","dialog",0,"space=5"); + zdialog_add_widget(CEF->zd,"label","lab2","hbbl","edge blend"); + zdialog_add_widget(CEF->zd,"hscale","blend","hbbl","0|20|0.3|0","expand"); // v.11.06 + + zdialog_help(CEF->zd,"area_copy_paste"); // zdialog help topic v.11.08 + zdialog_run(CEF->zd,select_paste_dialog_event,"80/20"); // v.11.07 + + takeMouse(CEF->zd,select_paste_mousefunc,0); // connect mouse function + + return; +} + + +// Dialog event and completion callback function +// Get dialog values and convert image. When done, commit edited image +// (with pasted area) and set up a new select area for the pasted area, +// allowing further editing of the area. + +int select_paste_dialog_event(zdialog *zd, cchar *event) +{ + void select_paste_mousefunc(); + void select_paste_pixmap(); + void select_paste_makearea(); + + int ww, hh; + PXM *pxm_temp; + + if (zd->zstat) // dialog completed + { + freeMouse(); // disconnect mouse + + if (zd->zstat != 1 || ! sacp_porg) { // cancel paste + edit_cancel(EFpaste); // cancel edit, restore image + sa_unselect(); + return 0; + } + + edit_done(EFpaste); // commit the edit (pasted image) + select_paste_makearea(); // make equivalent select area + PXM_free(sacpR_image16); // free memory + PXM_free(sacpR_info16); + return 0; + } + + if (strEqu(event,"focus")) // toggle mouse capture v.12.01 + takeMouse(zd,select_paste_mousefunc,0); + + if (strstr(event,"%") || strstr(event,"°")) // new size or angle + { + if (strEqu(event,"+.1%")) sacp_resize *= 1.001; + if (strEqu(event,"+1%")) sacp_resize *= 1.01; + if (strEqu(event,"+10%")) sacp_resize *= 1.10; + if (strEqu(event,"-.1%")) sacp_resize *= 0.999001; + if (strEqu(event,"-1%")) sacp_resize *= 0.990099; + if (strEqu(event,"-10%")) sacp_resize *= 0.909091; // -10% is really 1.0/1.10 + + if (strEqu(event,"+.1°")) sacp_angle += 0.1; // rotation v.11.02 + if (strEqu(event,"+1°")) sacp_angle += 1.0; + if (strEqu(event,"+10°")) sacp_angle += 10.0; + if (strEqu(event,"-.1°")) sacp_angle -= 0.1; + if (strEqu(event,"-1°")) sacp_angle -= 1.0; + if (strEqu(event,"-10°")) sacp_angle -= 10.0; + + PXM_free(sacpR_image16); // free prior if any + PXM_free(sacpR_info16); + + ww = sacp_resize * sacp_ww; // new size + hh = sacp_resize * sacp_hh; + + pxm_temp = PXM_rescale(sacp_image16,ww,hh); // resized area image + sacpR_image16 = PXM_rotate(pxm_temp,sacp_angle); // rotated area image + PXM_free(pxm_temp); + + pxm_temp = PXM_rescale(sacp_info16,ww,hh); // resized area info + sacpR_info16 = PXM_rotate(pxm_temp,sacp_angle); // rotated/resized area info + PXM_free(pxm_temp); + + sacpR_ww = sacpR_image16->ww; // size after resize/rotate + sacpR_hh = sacpR_image16->hh; + + select_paste_pixmap(); // copy onto target image + } + + if (strEqu(event,"blend") && sacp_porg) { + zdialog_fetch(zd,"blend",sacp_blend); // new edge blend distance + select_paste_pixmap(); // copy onto target image + } + + CEF->Fmod = 1; // image is modified + mwpaint2(); + return 0; +} + + +// convert the pasted image area into an equivalent select area by mouse + +void select_paste_makearea() +{ + int cc, ii; + int px1, py1, px2, py2; + uint16 *pix2; + + sa_unselect(); // unselect old area + + cc = Fww * Fhh * sizeof(uint16); + sa_pixmap = (uint16 *) zmalloc(cc,"sa_paste"); // pixel map for new area + memset(sa_pixmap,0,cc); + + for (py1 = 0; py1 < sacpR_hh; py1++) // map non-transparent pixels + for (px1 = 0; px1 < sacpR_ww; px1++) // into sa_pixmap[] + { + pix2 = PXMpix(sacpR_info16,px1,py1); // opacity and edge distance + if (pix2[0] == 0) continue; // transparent + px2 = px1 + sacp_orgx; + py2 = py1 + sacp_orgy; + if (px2 < 0 || px2 > Fww-1) continue; // parts may be beyond edges + if (py2 < 0 || py2 > Fhh-1) continue; + ii = py2 * Fww + px2; + sa_pixmap[ii] = 1; + } + + sa_stat = 1; + sa_mode = 5; // equivalent select/mouse area + sa_fww = Fww; // v.11.08 + sa_fhh = Fhh; + sa_finish_auto(); // v.11.04 + sa_show(1); + return; +} + + +// mouse function - follow mouse drags and move pasted area accordingly + +void select_paste_mousefunc() +{ + void select_paste_pixmap(); + + int mx1, my1, mx2, my2; + static int mdx0, mdy0, mdx1, mdy1; + + if (LMclick) { // left mouse click + LMclick = 0; + sacp_orgx = Mxclick - sacpR_ww / 2; // position image at mouse v.10.11 + sacp_orgy = Myclick - sacpR_hh / 2; + select_paste_pixmap(); + CEF->Fmod = 1; // image is modified + } + + if (! sacp_porg) return; // no select area paste yet + + if (Mxposn < sacp_orgx || Mxposn > sacp_orgx + sacpR_ww || // mouse outside select area + Myposn < sacp_orgy || Myposn > sacp_orgy + sacpR_hh) + gdk_window_set_cursor(drWin->window,0); // set normal cursor v.11.03 + else + gdk_window_set_cursor(drWin->window,dragcursor); // set drag cursor v.11.03 + + if (Mxdrag + Mydrag == 0) return; // no drag underway + + if (Mxdown != mdx0 || Mydown != mdy0) { // new drag initiated + mdx0 = mdx1 = Mxdown; + mdy0 = mdy1 = Mydown; + } + + mx1 = mdx1; // drag start + my1 = mdy1; + mx2 = Mxdrag; // drag position + my2 = Mydrag; + mdx1 = mx2; // next drag start + mdy1 = my2; + + sacp_orgx += (mx2 - mx1); // move position of select area + sacp_orgy += (my2 - my1); // by mouse drag amount + select_paste_pixmap(); // re-copy area to new position + CEF->Fmod = 1; // image is modified + + return; +} + + +// copy select area into edit image, starting at sacp_orgx/y + +void select_paste_pixmap() // overhauled v.11.02 +{ + int px1, py1, px3, py3, opac, dist; + uint16 *pix1, *pix3; + double f1, f2; + + if (sacp_porg) // prior area overlap rectangle + { + for (py1 = 0; py1 < sacp_phh; py1++) // restore original image pixels v.10.11 + for (px1 = 0; px1 < sacp_pww; px1++) + { + px3 = px1 + sacp_porgx; + py3 = py1 + sacp_porgy; + if (px3 < 0 || px3 >= E3ww) continue; // parts may be beyond edges + if (py3 < 0 || py3 >= E3hh) continue; + pix1 = PXMpix(E1pxm16,px3,py3); + pix3 = PXMpix(E3pxm16,px3,py3); + pix3[0] = pix1[0]; + pix3[1] = pix1[1]; + pix3[2] = pix1[2]; + } + } + + for (py1 = 0; py1 < sacpR_hh; py1++) // copy paste area pixels to new + for (px1 = 0; px1 < sacpR_ww; px1++) // image overlap rectangle + { + pix1 = PXMpix(sacpR_info16,px1,py1); // opacity and edge distance + opac = pix1[0]; + dist = pix1[1]; + if (opac == 0) continue; // skip transparent pixel + px3 = px1 + sacp_orgx; + py3 = py1 + sacp_orgy; + if (px3 < 0 || px3 >= E3ww) continue; // parts may be beyond edges + if (py3 < 0 || py3 >= E3hh) continue; + + pix1 = PXMpix(sacpR_image16,px1,py1); // paste image pixel + pix3 = PXMpix(E3pxm16,px3,py3); // target image pixel + if (dist > sacp_blend) f1 = 1.0; // minor bugfix v.11.06 + else f1 = 1.0 * dist / sacp_blend; // opacity reduction from edge blend + f1 = f1 * opac / 65535.0; // opacity reduction from resize/rescale + f2 = 1.0 - f1; + pix3[0] = f1 * pix1[0] + f2 * pix3[0]; // blend paste and target images + pix3[1] = f1 * pix1[1] + f2 * pix3[1]; + pix3[2] = f1 * pix1[2] + f2 * pix3[2]; + } + + mwpaint3(sacp_porgx,sacp_porgy,sacp_pww,sacp_phh); // update window for old overlap area + mwpaint3(sacp_orgx,sacp_orgy,sacpR_ww,sacpR_hh); // update window for new overlap area + + sacp_porgx = sacp_orgx; // remember location for next call + sacp_porgy = sacp_orgy; + sacp_pww = sacpR_ww; + sacp_phh = sacpR_hh; + sacp_porg = 1; + return; +} + + +/************************************************************************** + select area load from file and save to file functions v.9.9 +***************************************************************************/ + +// Load a select area from a disk file and paste into current image. + +void m_select_open(GtkWidget *, cchar *) +{ + char *pfile1, *pfile2, *pp; + + zfuncs::F1_help_topic = "area_open_save"; // v.10.8 + + pp = zgetfile1(ZTX("load select area from a file"),"open",saved_areas_dirk); + if (! pp) return; + + pfile1 = strdupz(pp,8,"select_open"); + zfree(pp); + pp = strrchr(pfile1,'/'); + if (pp) pp = strrchr(pp,'.'); + if (pp) strcpy(pp,".tiff"); + else strcat(pfile1,".tiff"); + + pfile2 = strdupz(pfile1,0,"select_open"); + pp = strrchr(pfile2,'.'); + strcpy(pp,".info"); + + PXM_free(sacp_image16); // free prior if any + PXM_free(sacp_info16); + + sacp_image16 = TIFFread(pfile1); // .tiff file --> image PXM + if (! sacp_image16) goto fail; + + sacp_info16 = TIFFread(pfile2); // .info file --> info PXM + if (! sacp_info16) goto fail; + + zfree(pfile1); + zfree(pfile2); + + sacp_ww = sacp_image16->ww; // paste into current image + sacp_hh = sacp_image16->hh; + m_select_paste(0,0); + return; + +fail: + zfree(pfile1); + zfree(pfile2); + zmessageACK(mWin,ZTX("cannot open .tiff and .info files")); + return; +} + + +// save a select area as a disk file + +void m_select_save(GtkWidget *, cchar *) +{ + char *pfile1, *pfile2, *pp; + + zfuncs::F1_help_topic = "area_open_save"; // v.10.11 + + if (sa_mode == 7) return; // a whole image area v.11.01 + if (! Factivearea) sa_finish(); // finish select area if not already + if (! Factivearea) return; // v.11.06.1 + m_select_copy(0,0); // copy select area to memory + if (! sacp_image16) return; + + pp = zgetfile1(ZTX("save select area to a file"),"save",saved_areas_dirk); + if (! pp) return; + + pfile1 = strdupz(pp,8,"select_save"); + zfree(pp); + pp = strrchr(pfile1,'/'); + if (pp) pp = strrchr(pp,'.'); + if (pp) strcpy(pp,".tiff"); + else strcat(pfile1,".tiff"); + + pfile2 = strdupz(pfile1,0,"select_save"); + pp = strrchr(pfile2,'.'); + strcpy(pp,".info"); + + TIFFwrite(sacp_image16,pfile1); // image PXM --> .tiff file + TIFFwrite(sacp_info16,pfile2); // info PXM --> .info file + + return; +} + + +/**************************************************************************/ + +// Select the whole image as an area. +// Set "edge distance" 1 to 255 from pixel or RGB color brightness. +// Set "blend width" to 255 +// Edit function coefficient = edge distance / blend width. + +spldat * select_whole_image_curve; + +void m_select_whole_image(GtkWidget *, cchar *) // new v.11.01 +{ + int select_whole_image_event(zdialog *, cchar *event); // dialog event and completion func + void select_whole_image_curve_update(int spc); // curve update callback function + + cchar *title = ZTX("Select Whole Image"); + cchar *legend = ZTX("Edit Function Amplifier"); + + zfuncs::F1_help_topic = "select_whole_image"; + + if (! curr_file) return; // no image + if (zdsela) return; // select dialog already active + if (Fpreview) edit_fullsize(); // use full-size image + +/*** + Edit Function Amplifier + ------------------------------------------ + | | + | | + | curve drawing area | + | | + | | + ------------------------------------------ + darker areas lighter areas + + [+++] [---] [+ -] [- +] [+-+] [-+-] + (o) Brightness (o) Red (o) Green (o) Blue + Curve File: [ Open ] [ Save ] + [ Done ] +***/ + + zdsela = zdialog_new(title,mWin,Bdone,null); + + zdialog_add_widget(zdsela,"label","labt","dialog",legend); + zdialog_add_widget(zdsela,"frame","fr1","dialog",0,"expand"); + zdialog_add_widget(zdsela,"hbox","hba","dialog"); + zdialog_add_widget(zdsela,"label","labda","hba",Bdarker,"space=5"); + zdialog_add_widget(zdsela,"label","space","hba",0,"expand"); + zdialog_add_widget(zdsela,"label","labba","hba",Blighter,"space=5"); + zdialog_add_widget(zdsela,"hbox","hbb","dialog",0,"space=5"); + zdialog_add_widget(zdsela,"button","b +++","hbb","+++"); + zdialog_add_widget(zdsela,"button","b ---","hbb","‒ ‒ ‒"); + zdialog_add_widget(zdsela,"button","b +-", "hbb"," + ‒ "); + zdialog_add_widget(zdsela,"button","b -+", "hbb"," ‒ + "); + zdialog_add_widget(zdsela,"button","b +-+","hbb","+ ‒ +"); + zdialog_add_widget(zdsela,"button","b -+-","hbb","‒ + ‒"); + + zdialog_add_widget(zdsela,"hbox","hbbr","dialog",0,"space=5"); + zdialog_add_widget(zdsela,"radio","bright","hbbr",Bbrightness,"space=5"); + zdialog_add_widget(zdsela,"radio","red","hbbr",Bred,"space=5"); + zdialog_add_widget(zdsela,"radio","green","hbbr",Bgreen,"space=5"); + zdialog_add_widget(zdsela,"radio","blue","hbbr",Bblue,"space=5"); + + zdialog_add_widget(zdsela,"hbox","hbcf","dialog",0,"space=5"); + zdialog_add_widget(zdsela,"label","labcf","hbcf",Bcurvefile,"space=5"); + zdialog_add_widget(zdsela,"button","load","hbcf",Bopen,"space=5"); + zdialog_add_widget(zdsela,"button","save","hbcf",Bsave,"space=5"); + + GtkWidget *frame = zdialog_widget(zdsela,"fr1"); // setup for curve editing + spldat *sd = splcurve_init(frame,select_whole_image_curve_update); // v.11.01 + select_whole_image_curve = sd; + + sd->Nspc = 1; + sd->vert[0] = 0; + sd->nap[0] = 3; // initial curve anchor points + sd->apx[0][0] = 0.01; + sd->apy[0][0] = 0.5; + sd->apx[0][1] = 0.50; + sd->apy[0][1] = 0.5; + sd->apx[0][2] = 0.99; + sd->apy[0][2] = 0.5; + splcurve_generate(sd,0); // generate curve data + + zdialog_stuff(zdsela,"bright",1); + zdialog_stuff(zdsela,"red",0); + zdialog_stuff(zdsela,"green",0); + zdialog_stuff(zdsela,"blue",0); + + sa_unselect(); // unselect current area if any + + zdialog_resize(zdsela,0,360); + zdialog_help(zdsela,"select_whole_image"); // zdialog help topic v.11.08 + zdialog_run(zdsela,select_whole_image_event,"80/20"); // run dialog - parallel v.11.07 + select_whole_image_event(zdsela,"init"); // initialize default params + + return; +} + + +// dialog event and completion function + +int select_whole_image_event(zdialog *zd, cchar *event) +{ + int ii, kk, cc, base, pixbright, pixdist; + double px, py, xval, yval; + uint8 *pixel; + spldat *sd = select_whole_image_curve; + + if (zd->zstat) { // done, kill dialog + zdialog_free(zdsela); + zfree(sd); // free curve edit memory + return 0; + } + + if (! sa_stat) // if no area exists + { + cc = Fww * Fhh * sizeof(uint16); // allocate sa_pixmap[] for new area + sa_pixmap = (uint16 *) zmalloc(cc,"sa_select_image"); + + sa_minx = 0; // enclosing rectangle + sa_maxx = Fww; + sa_miny = 0; + sa_maxy = Fhh; + + sa_Npixel = Fww * Fhh; + sa_stat = 3; // area status = complete + sa_mode = 7; // area mode = whole image + sa_calced = 1; // edge calculation complete + sa_blend = 255; // "blend width" = 255 + sa_fww = Fww; // valid image dimensions v.11.08 + sa_fhh = Fhh; + Factivearea = 1; // area is active + areanumber++; // next sequential number + } + + if (strEqu(event,"load")) { // load saved curve v.11.02 + splcurve_load(sd); + if (CEF && CEF->zd) zdialog_send_event(CEF->zd,"blendwidth"); // notify edit dialog + return 0; + } + + if (strEqu(event,"save")) { // save curve to file v.11.02 + splcurve_save(sd); + return 0; + } + + base = 0; + zdialog_fetch(zd,"bright",ii); // set brightness or color to be used + if (ii) base = 1; + zdialog_fetch(zd,"red",ii); + if (ii) base = 2; + zdialog_fetch(zd,"green",ii); + if (ii) base = 3; + zdialog_fetch(zd,"blue",ii); + if (ii) base = 4; + if (! base) return 0; + + if (strnEqu(event,"b ",2)) { // button to move entire curve + for (ii = 0; ii < sd->nap[0]; ii++) { + px = sd->apx[0][ii]; + py = sd->apy[0][ii]; + if (strEqu(event,"b +++")) py += 0.1; + if (strEqu(event,"b ---")) py -= 0.1; + if (strEqu(event,"b +-")) py += 0.1 - 0.2 * px; + if (strEqu(event,"b -+")) py -= 0.1 - 0.2 * px; + if (strEqu(event,"b +-+")) py -= 0.05 - 0.2 * fabs(px-0.5); + if (strEqu(event,"b -+-")) py += 0.05 - 0.2 * fabs(px-0.5); + if (py > 1) py = 1; + if (py < 0) py = 0; + sd->apy[0][ii] = py; + } + } + + splcurve_generate(sd,0); // regenerate the curve + splcurve_draw(0,0,sd); + + pixel = (uint8 *) Fpxm8->bmp; + + for (ii = 0; ii < Fww * Fhh; ii++) // loop all pixels + { + pixbright = pixel[0] + pixel[1] + pixel[2] + 1; // brightness of pixel, 1 - 766 + if (base == 1) pixbright = pixbright / 3; // brightness, 0 - 255 bugfix v.11.01.2 + else if (base == 2) pixbright = 255 * pixel[0] / pixbright; // red part: 0 - 255 = 100% red + else if (base == 3) pixbright = 255 * pixel[1] / pixbright; // green part + else if (base == 4) pixbright = 255 * pixel[2] / pixbright; // blue part + xval = pixbright / 256.0; // curve x-value, 0 to 0.999 + kk = 1000 * xval; // speedup v.11.06 + if (kk > 999) kk = 999; + yval = sd->yval[0][kk]; + pixdist = 255 * yval; // pixel "edge distance" 0 to 255 + sa_pixmap[ii] = pixdist | 1; // avoid 0 (pixel outside area) + pixel += 3; + } + + if (CEF && CEF->zd) zdialog_send_event(CEF->zd,"blendwidth"); // notify edit dialog + + return 0; +} + + +// this function is called when curve is edited using mouse + +void select_whole_image_curve_update(int) +{ + select_whole_image_event(zdsela,"edit"); + return; +} + + +/**************************************************************************/ + +// Select area and edit in parallel +// Current edit function is applied to areas painted with the mouse. +// Mouse can be weak or strong, and edits are applied incrementally. +// method: +// entire image is a select area with all pixel edge distance = 0 (outside area) +// blendwidth = 10000 +// pixels painted with mouse have increasing edge distance to amplify edits + +int select_edit_radius; +int select_edit_cpower; +int select_edit_epower; + +void m_select_edit(GtkWidget *, cchar *) // menu function v.11.02 +{ + int select_edit_dialog_event(zdialog *, cchar *event); // dialog event function + void select_edit_mousefunc(); // mouse function + + cchar *title = ZTX("Select Area for Edits"); + cchar *helptext1 = ZTX("Press F1 for help"); + cchar *helptext2 = ZTX("Edit function must be active"); + int cc; + + zfuncs::F1_help_topic = "select_edit"; + + if (! curr_file) return; // no image + if (zdsela) return; // select area already active + if (Fpreview) edit_fullsize(); // use full-size image + + if (! Fpxm16) { // create Fpxm16 if not already + mutex_lock(&Fpixmap_lock); + Fpxm16 = f_load(curr_file,16); + mutex_unlock(&Fpixmap_lock); + if (! Fpxm16) return; + } + +/*** + ____________________________________________ + | Press F1 for help | + | Edit Function must be active | + | mouse radius [___|v] | + | power: center [___|v] edge [___|v] | + | [reset area] | + | [done] | + |____________________________________________| + +***/ + + zdsela = zdialog_new(title,mWin,Bdone,null); + zdialog_add_widget(zdsela,"label","labhelp1","dialog",helptext1,"space=5"); + zdialog_add_widget(zdsela,"label","labhelp2","dialog",helptext2); + zdialog_add_widget(zdsela,"label","labspace","dialog"); + zdialog_add_widget(zdsela,"hbox","hbr","dialog",0,"space=3"); + zdialog_add_widget(zdsela,"label","labr","hbr",ZTX("mouse radius"),"space=5"); + zdialog_add_widget(zdsela,"spin","radius","hbr","2|500|1|50"); + zdialog_add_widget(zdsela,"hbox","hbt","dialog",0,"space=3"); + zdialog_add_widget(zdsela,"label","labtc","hbt",ZTX("power: center"),"space=5"); + zdialog_add_widget(zdsela,"spin","center","hbt","0|100|1|50"); + zdialog_add_widget(zdsela,"label","labte","hbt",ZTX("edge"),"space=5"); + zdialog_add_widget(zdsela,"spin","edge","hbt","0|100|1|0"); + zdialog_add_widget(zdsela,"hbox","hbr","dialog",0,"space=5"); + zdialog_add_widget(zdsela,"button","reset","hbr",ZTX("reset area"),"space=5"); + + select_edit_radius = 50; + select_edit_cpower = 50; + select_edit_epower = 0; + + sa_unselect(); // unselect current area if any + cc = Fww * Fhh * sizeof(uint16); // allocate sa_pixmap[] for new area + sa_pixmap = (uint16 *) zmalloc(cc,"sa_select_edit"); + memset(sa_pixmap,0,cc); // edge distance = 0 for all pixels + + sa_minx = 0; // enclosing rectangle + sa_maxx = Fww; + sa_miny = 0; + sa_maxy = Fhh; + + sa_Npixel = Fww * Fhh; + sa_stat = 3; // area status = complete + sa_mode = 7; // area mode = whole image + sa_calced = 1; // edge calculation complete + sa_blend = 10000; // "blend width" + sa_fww = Fww; // valid image dimensions v.11.08 + sa_fhh = Fhh; + Factivearea = 1; // area is active + areanumber++; // next sequential number + + zdialog_help(zdsela,"select_edit"); // zdialog help topic v.11.08 + zdialog_run(zdsela,select_edit_dialog_event,"80/20"); // run dialog - parallel v.11.07 + return; +} + + +// tailor whole image area to increase edit power for pixels within the mouse radius +// sa_pixmap[*] = 0 = never touched by mouse +// = 1 = minimum edit power (barely painted) +// = sa_blend = maximum edit power (edit fully applied) + +int select_edit_dialog_event(zdialog *zd, cchar *event) +{ + void select_edit_mousefunc(); // mouse function + int cc; + + if (! Factivearea) return 1; // area gone v.11.06.1 + + if (zd->zstat) // done or cancel + { + freeMouse(); // disconnect mouse function + zdialog_free(zdsela); // kill dialog + sa_unselect(); // unselect area + return 0; + } + + if (strEqu(event,"focus")) { // toggle mouse capture v.12.01 + if (CEF) takeMouse(zd,select_edit_mousefunc,0); + else freeMouse(); // disconnect mouse + } + + if (strEqu(event,"radius")) + zdialog_fetch(zd,"radius",select_edit_radius); // set mouse radius + + if (strEqu(event,"center")) + zdialog_fetch(zd,"center",select_edit_cpower); // set mouse center power + + if (strEqu(event,"edge")) + zdialog_fetch(zd,"edge",select_edit_epower); // set mouse edge power + + if (strEqu(event,"reset")) { + sa_unselect(); // unselect current area if any + cc = Fww * Fhh * sizeof(uint16); // allocate sa_pixmap[] for new area + sa_pixmap = (uint16 *) zmalloc(cc,"sa_select_edit"); + memset(sa_pixmap,0,cc); // edge distance = 0 for all pixels + + sa_minx = 0; // enclosing rectangle + sa_maxx = Fww; + sa_miny = 0; + sa_maxy = Fhh; + + sa_Npixel = Fww * Fhh; + sa_stat = 3; // area status = complete + sa_mode = 7; // area mode = whole image + sa_calced = 1; // edge calculation complete + sa_blend = 10000; // "blend width" + sa_fww = Fww; // valid image dimensions v.11.08 + sa_fhh = Fhh; + Factivearea = 1; // area is active + areanumber++; // next sequential number + } + + return 1; +} + + +// mouse function - adjust edit strength for areas within mouse radius +// "edge distance" is increased for more strength, decreased for less + +void select_edit_mousefunc() +{ + int ii, cc, px, py, rx, ry; + int radius, radius2, cpower, epower; + double rad, rad2, power; // v.11.06 + + if (! CEF) { // no active edit + freeMouse(); + return; + } + + if (! sa_stat) // area gone? v.11.07 + { + cc = Fww * Fhh * sizeof(uint16); // allocate sa_pixmap[] for new area + sa_pixmap = (uint16 *) zmalloc(cc,"sa_select_edit"); + memset(sa_pixmap,0,cc); // clear to zeros + + sa_minx = 0; // enclosing rectangle + sa_maxx = Fww; + sa_miny = 0; + sa_maxy = Fhh; + + sa_Npixel = Fww * Fhh; + sa_stat = 3; // area status = complete + sa_mode = 7; // area mode = whole image + sa_calced = 1; // edge calculation complete + sa_blend = 10000; // "blend width" + sa_fww = Fww; // valid image dimensions v.11.08 + sa_fhh = Fhh; + Factivearea = 1; // area is active + areanumber++; // next sequential number + } + + radius = select_edit_radius; // pixel selection radius + radius2 = radius * radius; + cpower = select_edit_cpower; + epower = select_edit_epower; + + toparcx = Mxposn - radius; // draw mouse outline circle + toparcy = Myposn - radius; + toparcw = toparch = 2 * radius; + Ftoparc = 1; + paint_toparc(3); + + if (LMclick || RMclick) // mouse click + LMclick = RMclick = 0; + + if (Mbutton != 1 && Mbutton != 3) // button released + return; + + for (rx = -radius; rx <= radius; rx++) // loop every pixel in radius + for (ry = -radius; ry <= radius; ry++) + { + rad2 = rx * rx + ry * ry; + if (rad2 > radius2) continue; // outside radius + px = Mxposn + rx; + py = Myposn + ry; + if (px < 0 || px > Fww-1) continue; // off the image edge + if (py < 0 || py > Fhh-1) continue; + + ii = Fww * py + px; + rad = sqrt(rad2); + power = cpower + rad / radius * (epower - cpower); // power at pixel radius v.11.06 + + if (Mbutton == 1) // left mouse button + { // increase edit power + sa_pixmap[ii] += power; + if (sa_pixmap[ii] > sa_blend) sa_pixmap[ii] = sa_blend; + } + + if (Mbutton == 3) // right mouse button + { // weaken edit power + if (sa_pixmap[ii] <= power) sa_pixmap[ii] = 0; + else sa_pixmap[ii] -= power; + } + } + + sa_minx = Mxposn - radius; // set temp. smaller area around mouse + if (sa_minx < 0) sa_minx = 0; // speedup v.11.06 + sa_maxx = Mxposn + radius; + if (sa_maxx > Fww) sa_maxx = Fww; + sa_miny = Myposn - radius; + if (sa_miny < 0) sa_miny = 0; + sa_maxy = Myposn + radius; + if (sa_maxy > Fhh) sa_maxy = Fhh; + sa_Npixel = (sa_maxx - sa_minx) * (sa_maxy - sa_miny); + + paint_toparc(2); // remove mouse outline + + zdialog_send_event(CEF->zd,"blendwidth"); // notify edit dialog + + Ftoparc = 1; // restore mouse outline + paint_toparc(3); + + sa_minx = 0; // restore whole image area v.11.06 + sa_maxx = Fww; + sa_miny = 0; + sa_maxy = Fhh; + sa_Npixel = Fww * Fhh; + + return; +} + + + diff -Nru fotoxx-11.11.1/f.tools.cc fotoxx-12.01.2/f.tools.cc --- fotoxx-11.11.1/f.tools.cc 1970-01-01 00:00:00.000000000 +0000 +++ fotoxx-12.01.2/f.tools.cc 2012-01-04 08:47:11.000000000 +0000 @@ -0,0 +1,3739 @@ +/************************************************************************** + + Fotoxx edit photos and manage collections + + Copyright 2007 2008 2009 2010 2011 2012 Michael Cornelison + Source URL: http://kornelix.squarespace.com/fotoxx + Contact: kornelix2@googlemail.com + + 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 http://www.gnu.org/licenses/. + +***************************************************************************/ + +#define EX extern // enable extern declarations +#include "fotoxx.h" + + +/************************************************************************** + + Fotoxx image edit - Tools menu functions + +***************************************************************************/ + + +// Manage Collections + +void m_manage_collections(GtkWidget *, cchar *) // v.11.11 +{ + int manage_coll_dialog_event(zdialog *zd, cchar *event); // manage collectiond dialog event func + + zdialog *zd; + cchar *helptext = ZTX("When editing a collection, right-click \n" + "an image or thumbnail to add or remove."); + + zfuncs::F1_help_topic = "manage_collections"; + + if (mod_keep()) return; // unsaved edits + +/*** + __________________________________________ + | | + | Manage Collections | + | | + | When editing a collection, right-click | + | an image or thumbnail to add or remove. | + | | + | [New] Start a new collection | + | [Edit] Edit a collection | + | [View] View a collection | + | [Delete] Delete a collection | + | | + | Editing: | + | Action: xxxxxxxxxxxxxx | + | | + | [Done] | + |__________________________________________| + +***/ + + zd = zdialog_new(ZTX("Manage Collections"),mWin,Bdone,null); + zd_edit_coll = zd; + + zdialog_add_widget(zd,"label","labhelp","dialog",helptext,"space=5"); + + zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=3"); + zdialog_add_widget(zd,"vbox","vb1","hb1",0,"homog|space=5"); + zdialog_add_widget(zd,"vbox","vb2","hb1",0,"homog|space=5"); + + zdialog_add_widget(zd,"button","new","vb1",Bnew); + zdialog_add_widget(zd,"button","edit","vb1",Bedit); + zdialog_add_widget(zd,"button","view","vb1",Bview); + zdialog_add_widget(zd,"button","delete","vb1",Bdelete); + + zdialog_add_widget(zd,"hbox","hbnew","vb2"); + zdialog_add_widget(zd,"label","labnew","hbnew",ZTX("Start new collection")); + zdialog_add_widget(zd,"hbox","hbedit","vb2"); + zdialog_add_widget(zd,"label","labedit","hbedit",ZTX("Edit a collection")); + zdialog_add_widget(zd,"hbox","hbview","vb2"); + zdialog_add_widget(zd,"label","labview","hbview",ZTX("View a collection")); + zdialog_add_widget(zd,"hbox","hbdel","vb2"); + zdialog_add_widget(zd,"label","labdel","hbdel",ZTX("Delete a collection")); + + zdialog_add_widget(zd,"hsep","sep","dialog",0,"space=3"); + zdialog_add_widget(zd,"hbox","hbedit","dialog"); + zdialog_add_widget(zd,"label","labedit","hbedit",ZTX("Editing:"),"space=3"); + zdialog_add_widget(zd,"label","editcoll","hbedit",0,"space=3"); + + zdialog_add_widget(zd,"hbox","hbact","dialog",0,"space=3"); + zdialog_add_widget(zd,"label","labact","hbact",ZTX("Action:"),"space=3"); + zdialog_add_widget(zd,"label","lastact","hbact",0,"space=3"); + + zdialog_help(zd,"manage_collections"); + zdialog_resize(zd,300,0); + zdialog_run(zd,manage_coll_dialog_event); + zdialog_wait(zd); + zdialog_free(zd); + zd_edit_coll = 0; + + if (edit_coll_name) zfree(edit_coll_name); // no collection for editing + edit_coll_name = 0; + + return; +} + + +// manage collections dialog event and completion function + +int manage_coll_dialog_event(zdialog *zd, cchar *event) // v.11.11 +{ + int err; + FILE *fid; + char *pp; + struct stat statb; + + if (strEqu(event,"new")) // start a new collection for editing + { + if (edit_coll_name) { // no current collection + zfree(edit_coll_name); + edit_coll_name = 0; + } + + if (edit_coll_file) zfree(edit_coll_file); + edit_coll_file = zgetfile1(ZTX("New Collection"),"save",collections_dirk); + if (! edit_coll_file) return 0; + + fid = fopen(edit_coll_file,"w"); // open collection file + if (! fid) return 0; + fprintf(fid,"Fotoxx Collection \n"); // write one record + fclose(fid); + + pp = strrchr(edit_coll_file,'/'); // file name = collection name + edit_coll_name = strdupz(pp+1); // set current edit collection + + zdialog_stuff(zd,"editcoll",edit_coll_name); + return 0; + } + + if (strEqu(event,"edit")) // choose a collection for editing + { + if (edit_coll_name) { // no current collection + zfree(edit_coll_name); + edit_coll_name = 0; + } + + if (edit_coll_file) zfree(edit_coll_file); + edit_coll_file = zgetfile1(ZTX("Edit Collection"),"open",collections_dirk); + if (! edit_coll_file) return 0; + + err = stat(edit_coll_file,&statb); + if (err) return 0; + + pp = strrchr(edit_coll_file,'/'); // file name = collection name + edit_coll_name = strdupz(pp+1); // set current edit collection + + zdialog_stuff(zd,"editcoll",edit_coll_name); + return 0; + } + + if (strEqu(event,"view")) // choose a collection for viewing + { + if (edit_coll_file) zfree(edit_coll_file); + edit_coll_file = zgetfile1(ZTX("View Collection"),"open",collections_dirk); + if (! edit_coll_file) return 0; + + err = stat(edit_coll_file,&statb); + if (err) return 0; + + image_gallery(edit_coll_file,"initF",0,m_gallery2,mWin); // generate gallery of files in coll. + + if (edit_coll_memberfile) zfree(edit_coll_memberfile); + edit_coll_memberfile = image_gallery(0,"find",0); // top of list + if (! edit_coll_memberfile) return 0; + f_open(edit_coll_memberfile,1); // open first file + zmainloop(); + + image_gallery(0,"paint1"); // show new image gallery window + return 0; + } + + if (strEqu(event,"delete")) // choose collection to delete + { + if (edit_coll_file) zfree(edit_coll_file); + edit_coll_file = zgetfile1(ZTX("Delete Collection"),"open",collections_dirk); + if (! edit_coll_file) return 0; + + if (! zmessageYN(mWin,ZTX("delete %s ?"),edit_coll_file)) return 0; + + remove(edit_coll_file); // delete it + return 0; + } + + return 0; +} + + +// Popup menu for editing a collection. +// This function is called when a thumbnail is right-clicked. + +void edit_coll_popmenu(GtkWidget *, char *file) +{ + void edit_coll_popfunc(GtkWidget *, cchar *menu); + + GtkWidget *popmenu; + static char addmenuitem[200]; + + if (! edit_coll_name) return; // no edit in progress, do nothing + + if (edit_coll_memberfile) zfree(edit_coll_memberfile); // save clicked thumbnail file + edit_coll_memberfile = strdupz(file,0,"edit_coll"); + + popmenu = create_popmenu(); // create popup menu + + snprintf(addmenuitem,200,ZTX("add image to collection: %s"),edit_coll_name); + add_popmenu_item(popmenu,addmenuitem,edit_coll_popfunc); + add_popmenu_item(popmenu,ZTX("remove image from collection"),edit_coll_popfunc); + add_popmenu_item(popmenu,ZTX("remove and save image"),edit_coll_popfunc); + add_popmenu_item(popmenu,ZTX("insert saved images here"),edit_coll_popfunc); + + popup_menu(popmenu); + return; +} + + +// Response function for the edit collections popup menu + +void edit_coll_popfunc(GtkWidget *, cchar *menu) +{ + int ii, found = 0; + FILE *fidr, *fidw; + char collfile[maxfcc], buff[maxfcc]; + char *filename, tempfile[200]; + + static char *saved_files[100]; + static int Nsaved = 0; + + if (! edit_coll_name) return; // no edit in progress, do nothing + if (! edit_coll_memberfile) return; // no member file for action + if (! zd_edit_coll) return; + + strcpy(collfile,collections_dirk); // edit collection full path + strcat(collfile,edit_coll_name); + + strcpy(tempfile,collections_dirk); // temp file for copying + strcat(tempfile,"tempfile"); + + if (strnEqu(menu,ZTX("add image to collection"),23)) + { + fidw = fopen(collfile,"a"); // append new file at end of list + if (! fidw) return; + fprintf(fidw,"%s\n",edit_coll_memberfile); + fclose(fidw); + + filename = strrchr(edit_coll_memberfile,'/') + 1; // notify in dialog window + sprintf(buff,"Add: %s",filename); + zdialog_stuff(zd_edit_coll,"lastact",buff); + + return; + } + + if (strEqu(menu,ZTX("remove image from collection")) || + strEqu(menu,ZTX("remove and save image"))) + { + fidr = fopen(collfile,"r"); // copy collection file and omit + if (! fidr) return; // the image file being removed + fidw =fopen(tempfile,"w"); + if (! fidw) return; + + while (true) + { + filename = fgets_trim(buff,maxfcc,fidr); + if (! filename) break; + if (strEqu(filename,edit_coll_memberfile)) { + found = 1; + continue; + } + fprintf(fidw,"%s\n",filename); + } + + fclose(fidr); + fclose(fidw); + rename(tempfile,collfile); + + filename = strrchr(edit_coll_memberfile,'/') + 1; // notify in dialog window + if (found) sprintf(buff,"Removed: %s",filename); + else sprintf(buff,"Not found: %s",filename); + zdialog_stuff(zd_edit_coll,"lastact",buff); + + if (found && strEqu(menu,ZTX("remove and save image"))) // add file to list of saved files + { + if (Nsaved > 99) { + zmessageACK(mWin,ZTX("too many saved files")); + return; + } + saved_files[Nsaved] = strdupz(edit_coll_memberfile,0,"edit_coll"); + Nsaved++; + } + + if (strEqu(collfile,image_navi::galleryname)) { + image_gallery(collfile,"initF",0,m_gallery2,mWin); // update gallery window + image_gallery(0,"paint2",-1); + } + + return; + } + + if (strEqu(menu,ZTX("insert saved images here"))) + { + if (! Nsaved) return; + if (strNeq(collfile,image_navi::galleryname)) return; // gallery not the edit collection + + fidr = fopen(collfile,"r"); // copy collection file and insert + if (! fidr) return; // the saved image files + fidw =fopen(tempfile,"w"); + if (! fidw) return; + + while (true) + { + filename = fgets_trim(buff,maxfcc,fidr); + if (! filename) break; + fprintf(fidw,"%s\n",filename); + if (strNeq(filename,edit_coll_memberfile)) continue; + for (ii = 0; ii < Nsaved; ii++) { + fprintf(fidw,"%s\n",saved_files[ii]); + zfree(saved_files[ii]); + } + } + + fclose(fidr); + fclose(fidw); + rename(tempfile,collfile); + + sprintf(buff,"inserted %d files",Nsaved); + zdialog_stuff(zd_edit_coll,"lastact",buff); + Nsaved = 0; + + image_gallery(collfile,"initF",0,m_gallery2,mWin); // update gallery window + image_gallery(0,"paint2",-1); + + return; + } +} + + +/**************************************************************************/ + +// Change the top directory for all image collections. +// This facilitates changing the Fotoxx top image directory +// without having to re-create all collections. + +void m_move_collections(GtkWidget *, cchar *) +{ + zdialog *zd; + char *pp, oldtop[200], newtop[200]; + char command[200], buffr[maxfcc], buffw[maxfcc]; + char collfile[200], tempfile[200]; + int zstat, contx = 0, err; + FILE *fidr, *fidw; + + zfuncs::F1_help_topic = "move_collections"; + + if (mod_keep()) return; // unsaved edits + + zd = zdialog_new(ZTX("Move Collections"),mWin,Bapply,Bcancel,null); + zdialog_add_widget(zd,"hbox","hbold","dialog",0,"space=5"); + zdialog_add_widget(zd,"label","labold","hbold",ZTX("old top directory"),"space=5"); + zdialog_add_widget(zd,"entry","oldtop","hbold",0,"scc=30"); + zdialog_add_widget(zd,"hbox","hbnew","dialog",0,"space=5"); + zdialog_add_widget(zd,"label","labnew","hbnew",ZTX("new top directory"),"space=5"); + zdialog_add_widget(zd,"entry","newtop","hbnew",0,"scc=30"); + + zdialog_stuff(zd,"oldtop",topdirk); + zdialog_stuff(zd,"newtop",topdirk); + + zdialog_help(zd,"move_collections"); + zdialog_run(zd); + + zstat = zdialog_wait(zd); + if (zstat != 1) { + zdialog_free(zd); + return; + } + + zdialog_fetch(zd,"oldtop",oldtop,200); // old and new top directory paths + zdialog_fetch(zd,"newtop",newtop,200); + zdialog_free(zd); + + snprintf(tempfile,200,"%s/move-collection",get_zuserdir()); + + snprintf(command,200,"find -L %s -type f",collections_dirk); // find all collections + printf("%s \n",command); + + while ((pp = command_output(contx,command,null))) // loop all collections + { + printf("%s \n",pp); + strncpy0(collfile,pp,200); + zfree(pp); + + fidr = fopen(collfile,"r"); // open collection and temp files + if (! fidr) break; + + fidw = fopen(tempfile,"w"); + if (! fidw) break; + + while ((pp = fgets(buffr,maxfcc,fidr))) // loop collection recs + { + repl_1str(buffr,buffw,oldtop,newtop); // replace top directory path + err = fputs(buffw,fidw); + if (err < 0) break; + } + + err = fclose(fidr); + err = fclose(fidw); + if (err) break; + + err = rename(tempfile,collfile); // replace collection with temp file + if (err) break; + } + + if (err) { + err = errno; + printf("%s \n %s \n",collfile,strerror(err)); + zmessageACK(mWin,"%s \n %s",collfile,strerror(err)); + } + else zmessageACK(mWin,ZTX("completed")); + + return; +} + + +/**************************************************************************/ + +// Batch file convert - change format (file type), resize, export + +void m_batchconvert(GtkWidget *, cchar *) // new v.10.8 +{ + int batchconvert_dialog_event(zdialog *zd, cchar *event); + + zfuncs::F1_help_topic = "batch_convert"; // v.10.8 + + if (is_syncbusy()) return; // must wait for file sync v.11.11 + if (mod_keep()) return; // unsaved edits + if (! menulock(1)) return; // lock menus + +/*** + Batch Convert/Resize/Export + + [select files] N files selected + new max. width [____] height [____] + new file type (o) same (o) JPG (o) PNG (o) TIF + (o) replace originals [x] remove EXIF + (o) export to location + [browse] [_________________________________] + + [proceed] [cancel] +***/ + + zdialog *zd = zdialog_new(ZTX("Batch Convert/Resize/Export"),mWin,Bproceed,Bcancel,null); + + zdialog_add_widget(zd,"hbox","hbf","dialog",0,"space=5"); + zdialog_add_widget(zd,"button","files","hbf",Bselectfiles,"space=5"); + zdialog_add_widget(zd,"label","fcount","hbf","0 files selected","space=10"); + + zdialog_add_widget(zd,"hbox","hbwh","dialog"); + zdialog_add_widget(zd,"label","labw","hbwh",ZTX("new max. width"),"space=5"); + zdialog_add_widget(zd,"entry","maxw","hbwh","1000","scc=5"); + zdialog_add_widget(zd,"label","space","hbwh",0,"space=5"); + zdialog_add_widget(zd,"label","labh","hbwh",ZTX("height"),"space=5"); + zdialog_add_widget(zd,"entry","maxh","hbwh","700","scc=5"); + + zdialog_add_widget(zd,"hbox","hbtyp","dialog",0,"space=4"); + zdialog_add_widget(zd,"label","labtyp","hbtyp",ZTX("new file type"),"space=5"); + zdialog_add_widget(zd,"radio","same","hbtyp",ZTX("same"),"space=6"); + zdialog_add_widget(zd,"radio","jpg","hbtyp","JPG","space=6"); + zdialog_add_widget(zd,"radio","png","hbtyp","PNG","space=6"); + zdialog_add_widget(zd,"radio","tif","hbtyp","TIF","space=6"); + + zdialog_add_widget(zd,"hbox","hbrep","dialog",0,"space=5"); + zdialog_add_widget(zd,"vbox","vbrep1","hbrep",0,"homog|space=5"); + zdialog_add_widget(zd,"vbox","vbrep2","hbrep",0,"homog|space=5"); + zdialog_add_widget(zd,"radio","replace","vbrep1",ZTX("replace originals")); + zdialog_add_widget(zd,"radio","export","vbrep1",ZTX("export to location")); + zdialog_add_widget(zd,"check","noexif","vbrep2",ZTX("remove EXIF")); + + zdialog_add_widget(zd,"hbox","hbloc","dialog",0,"space=3|expand"); + zdialog_add_widget(zd,"button","browse","hbloc",Bbrowse,"space=5"); + zdialog_add_widget(zd,"entry","location","hbloc",0,"scc=30|expand"); + + zdialog_stuff(zd,"same",1); // defaults: + zdialog_stuff(zd,"replace",0); // same file type, export, no EXIF + zdialog_stuff(zd,"export",1); + zdialog_stuff(zd,"noexif",1); + zdialog_stuff(zd,"maxw",batchresize[0]); // v.10.9 + zdialog_stuff(zd,"maxh",batchresize[1]); + + zdialog_help(zd,"batch_convert"); // zdialog help topic v.11.08 + zdialog_run(zd,batchconvert_dialog_event,"parent"); // run dialog v.11.07 + zdialog_wait(zd); // wait for completion + + menulock(0); + return; +} + + +// dialog event and completion callback function + +int batchconvert_dialog_event(zdialog *zd, cchar *event) +{ + static char **flist = 0; + char countmess[50]; + int Freplace, maxw, maxh, Fnoexif, yn; + int ii, err, lcc, fcc, ww, hh, fposn; + char location[maxfcc], *pp, *ploc, *pfile; + cchar *pext, *ptype; + char *oldfile, *newfile, *tempfile; + double scale, wscale, hscale; + PXM *pxmout; + struct stat statb; + + if (strEqu(event,"files")) // select images to convert + { + if (flist) { // free prior list + for (ii = 0; flist[ii]; ii++) + zfree(flist[ii]); + zfree(flist); + } + + flist = image_gallery_getfiles(0,mWin); // get list of files to convert v.10.9 + + if (flist) // count files selected + for (ii = 0; flist[ii]; ii++); + else ii = 0; + + snprintf(countmess,50,ZTX("%d files selected"),ii); // update dialog + zdialog_stuff(zd,"fcount",countmess); + } + + if (strEqu(event,"browse")) + { + ploc = zgetfile1(ZTX("Select directory"),"folder",curr_dirk); // get directory v.10.9 + if (! ploc) return 0; + zdialog_stuff(zd,"location",ploc); + zfree(ploc); + zdialog_stuff(zd,"export",1); + } + + if (! zd->zstat) return 0; // dialog still busy + + if (zd->zstat != 1) goto cleanup; // dialog canceled + + if (! flist) { // no files selected + zd->zstat = 0; // keep dialog active + return 0; + } + + zdialog_fetch(zd,"maxw",maxw); // new max width + zdialog_fetch(zd,"maxh",maxh); // new max height + zdialog_fetch(zd,"replace",Freplace); // replace originals y/n + zdialog_fetch(zd,"noexif",Fnoexif); // copy EXIF/IPTC y/n + + zdialog_fetch(zd,"same",ii); // get new file type v.11.12 + if (ii) ptype = 0; + zdialog_fetch(zd,"jpg",ii); + if (ii) ptype = ".jpg"; + zdialog_fetch(zd,"png",ii); + if (ii) ptype = ".png"; + zdialog_fetch(zd,"tif",ii); + if (ii) ptype = ".tif"; + + zdialog_fetch(zd,"location",location,maxfcc); // output location (Freplace = 0) + strTrim2(location,location); // trim leading and trailing blanks + + if (Freplace) { + yn = zmessageYN(mWin,ZTX("replace original files? (max. %d x %d)"),maxw,maxh); + if (! yn) { + zd->zstat = 0; + return 0; + } + } + else { + yn = zmessageYN(mWin,ZTX("copy files? (max. %d x %d) \n" + " to location %s"),maxw,maxh,location); + if (! yn) { + zd->zstat = 0; + return 0; + } + } + + if (! Freplace) { + err = stat(location,&statb); + if (err || ! S_ISDIR(statb.st_mode)) { + zmessageACK(mWin,ZTX("location is not a valid directory")); + zd->zstat = 0; + return 0; + } + } + + if (maxw < 20 || maxh < 20) { + zmessageACK(mWin,ZTX("max. size %d x %d is not reasonable"),maxw,maxh); + zd->zstat = 0; + return 0; + } + + write_popup_text("open","Processing files",500,200,mWin); // status monitor popup window + + lcc = strlen(location); + if (! Freplace && location[lcc-1] == '/') lcc--; // remove trailing '/' + + for (ii = 0; flist[ii]; ii++) // loop selected files + { + oldfile = flist[ii]; + + if (Freplace) + newfile = strdupz(oldfile,8,"batchconvert"); // new file = old file + else { + pfile = strrchr(oldfile,'/'); + if (! pfile) continue; + fcc = strlen(pfile); + newfile = strdupz(location,fcc+9,"batchconvert"); + strcpy(newfile+lcc,pfile); // new file at location + } + + pp = strrchr(newfile,'/'); // find existing file .ext + pp = strrchr(pp,'.'); + if (! pp) pp = pp + strlen(pp); + if (strlen(pp) > 5) pp = pp + strlen(pp); + + pext = 0; + if (ptype) pext = ptype; // new .ext from user + else { + if (strstr(".JPG .jpg .JPEG .jpeg",pp)) pext = ".jpg"; // new .ext from existing .ext + if (strstr(".PNG .png",pp)) pext = ".png"; + if (strstr(".TIF .TIFF .tif .tiff",pp)) pext = ".tif"; + } + if (! pext) pext = ".jpg"; + + strcpy(pp,pext); // set new file .ext + + write_popup_text("write",newfile); // report progress + zmainloop(); + + if (! Freplace) { + err = stat(newfile,&statb); // if export, check if file exists + if (! err) { + write_popup_text("write",ZTX("*** file already exists")); + zfree(newfile); + continue; + } + } + + err = f_open(oldfile,0); // open old file + if (err) { + write_popup_text("write",ZTX("*** file type not supported")); + zfree(newfile); + continue; + } + + wscale = hscale = 1.0; + if (Fww > maxw) wscale = 1.0 * maxw / Fww; // compute new size + if (Fhh > maxh) hscale = 1.0 * maxh / Fhh; + if (wscale < hscale) scale = wscale; + else scale = hscale; + ww = Fww * scale; + hh = Fhh * scale; + pxmout = PXM_rescale(Fpxm8,ww,hh); // rescale file + + tempfile = strdupz(newfile,12,"batchconvert"); // temp file needed for EXIF/IPTC copy + pp = strrchr(tempfile,'.'); + strcpy(pp,"-temp"); + strcpy(pp+5,pext); + + if (strstr(".jpg .png",pext)) // write rescaled file to temp file + PXBwrite(pxmout,tempfile); + else + TIFFwrite(pxmout,tempfile); + + if (! Fnoexif) // copy EXIF/IPTC if requested v.11.12 + info_copy(oldfile,tempfile,0,0,0); + + snprintf(command,ccc,"cp -p \"%s\" \"%s\" ",tempfile,newfile); // copy tempfile to newfile + err = system(command); + if (err) write_popup_text("write",wstrerror(err)); + + remove(tempfile); // remove tempfile + + if (Freplace && ! err && strNeq(oldfile,newfile)) // remove oldfile if not + remove(oldfile); // already replaced + + zfree(newfile); + zfree(tempfile); + PXM_free(pxmout); + } + + write_popup_text("write","COMPLETED"); + + batchresize[0] = maxw; // save preferred size v.10.9 + batchresize[1] = maxh; + +cleanup: + + if (flist) { // free memory + for (ii = 0; flist[ii]; ii++) + zfree(flist[ii]); + zfree(flist); + flist = 0; + } + + zdialog_free(zd); // kill dialog + + image_gallery(curr_file,"init"); // generate new gallery list v.11.12 + fposn = image_gallery_position(curr_file,0); + image_gallery(0,"paint2",fposn); // refresh gallery window if active + + return 0; +} + + +/**************************************************************************/ + +// open a single RAW file or convert multiple RAW files to tiff + +void m_conv_raw(GtkWidget *, cchar *menu) // simplified v.11.08 +{ + char **raw_files; + char *rawfile, *outfile, *pp; + int ii, bpc, err, filecount; + cchar *ftype; + + zfuncs::F1_help_topic = "convert_RAW"; + + if (! Fufraw) { + zmessageACK(mWin,ZTX("Program ufraw-batch is required")); + return; + } + + if (is_syncbusy()) return; // must wait for file sync v.11.11 + if (mod_keep()) return; // unsaved edits + if (! menulock(1)) return; + + if (strEqu(menu,"Open RAW File")) // convert one file v.11.08 + { + rawfile = zgetfile1(ZTX("Open RAW File"),"open",curr_dirk); + if (! rawfile) { + menulock(0); + return; + } + raw_files = (char **) zmalloc(2 * sizeof(char *),"conv-RAW"); + raw_files[0] = rawfile; + raw_files[1] = 0; + ftype = "tiff"; // default tiff/16 format v.11.12 + bpc = 16; + } + else // convert multiple files + { + raw_files = zgetfileN(ZTX("Select RAW files to convert"),"openN",curr_dirk); + if (! raw_files) { + menulock(0); + return; + } + ii = zdialog_choose(0,mWin,ZTX("Choose file type"), // set file type v.11.12 + "JPG", "PNG", "TIFF-8", "TIFF-16", null); + if (ii == 1) ftype = "jpg"; + if (ii == 2) ftype = "png"; + if (ii == 3) ftype = "tif"; + if (ii == 4) ftype = "tiff"; + bpc = 8; + if (ii == 4) bpc = 16; + + } + + for (ii = 0; raw_files[ii]; ii++); // count selected files + filecount = ii; + + write_popup_text("open","Converting RAW files",500,200,mWin); // status monitor popup window + write_popup_text("write","converting ..."); + + for (ii = 0; ii < filecount; ii++) + { + rawfile = raw_files[ii]; + outfile = strdupz(rawfile,5,"raw_out"); + pp = strrchr(rawfile,'.'); + pp = outfile + (pp - rawfile); + pp[0] = '.'; + strcpy(pp+1,ftype); // v.11.12 + + write_popup_text("write",rawfile); // write output to log window + + snprintf(command,ccc,"ufraw-batch --wb=camera --out-type=%s --out-depth=%d" + " --overwrite --output=\"%s\" \"%s\" ", ftype, bpc, outfile, rawfile); + err = system(command); + + if (err) { + write_popup_text("write",wstrerror(err)); + zfree(outfile); + continue; + } + + f_open(outfile,0); // open converted file in main window + zfree(outfile); + zmainloop(); + } + + write_popup_text("write","COMPLETED"); + write_popup_text("close",0); + + image_gallery(curr_file,"init"); // update gallery file list + image_gallery(0,"paint2",curr_file_posn); // refresh gallery window if active + + for (ii = 0; raw_files[ii]; ii++) // free memory + zfree(raw_files[ii]); + zfree(raw_files); + + menulock(0); + return; +} + + +/**************************************************************************/ + +// enter or leave slideshow mode + +int ss_interval = 3; // slide show interval +int ss_timer = 0; // slide show timer +int ss_latest = 0; // show only latest revision files +char *ss_oldfile, *ss_newfile; // image files for transition +PXM *ss_pxmold, *ss_pxmnew, *ss_pxmmix; // pixmap images: old, new, mixed +int ss_ww, ss_hh; // full screen window size +int ss_busy = 0; // transition underway +int ss_escape = 0; // user pressed Escape key +int ss_paused = 0; // user pressed P key (pause/resume) + +void ss_instant(); // transition functions +void ss_fadein(); +void ss_rollright(); +void ss_rolldown(); +void ss_shiftleft(); +void ss_venetian(); +void ss_grate(); +void ss_rectangle(); +void ss_ellipse(); +void ss_radar(); +void ss_jaws(); +char * ss_prev(int posn); +char * ss_next(int posn); +char * ss_prev_latest(int posn); +char * ss_next_latest(int posn); +char * ss_basename(char *file); + + +struct ss_table_t { + cchar *name; + cchar *vbox; + void (*func)(); +}; + +ss_table_t ss_table[SSNF] = // image transition types +{ + { "arrow keys", "vb41", null }, // name, zdialog parent, function + { "instant", "vb41", ss_instant }, + { "fade-in", "vb41", ss_fadein }, + { "roll-right", "vb41", ss_rollright }, + { "roll-down", "vb42", ss_rolldown }, + { "shift-left", "vb42", ss_shiftleft }, + { "venetian", "vb42", ss_venetian }, + { "grate", "vb42", ss_grate }, + { "rectangle", "vb43", ss_rectangle }, + { "ellipse", "vb43", ss_ellipse }, + { "radar", "vb43", ss_radar }, + { "jaws", "vb43", ss_jaws } +}; + + +void m_slideshow(GtkWidget *, cchar *) +{ + int slideshow_dialog_event(zdialog *zd, cchar *event); + + zdialog *zd; + int zstat, secs, err, ii; + cchar *esc_message = ZTX("Press ESC to exit slide show"); + cchar *latest_message = ZTX("show only latest file versions"); + + zfuncs::F1_help_topic = "slide_show"; // v.10.8 + + ss_table[0].name = ZTX("arrow keys"); // use translated names + ss_table[1].name = ZTX("instant"); + ss_table[2].name = ZTX("fade-in"); + ss_table[3].name = ZTX("roll-right"); + ss_table[4].name = ZTX("roll-down"); + ss_table[5].name = ZTX("shift-left"); + ss_table[6].name = ZTX("venetian"); + ss_table[7].name = ZTX("grate"); + ss_table[8].name = ZTX("rectangle"); + ss_table[9].name = ZTX("ellipse"); + ss_table[10].name = ZTX("radar"); + ss_table[11].name = ZTX("jaws"); + + if (! Fslideshow) // start slide show + { + if (! curr_file) return; + if (! menulock(1)) return; + + zd = zdialog_new(ZTX("Slide Show"),mWin,Bproceed,Bcancel,null); // user dialog + zdialog_add_widget(zd,"hbox","hbesc","dialog",0,"space=3"); + zdialog_add_widget(zd,"label","labesc","hbesc",esc_message,"space=3"); + zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=3"); + zdialog_add_widget(zd,"label","labsecs","hb1",ZTX("seconds"),"space=3"); + zdialog_add_widget(zd,"entry","secs","hb1","3","scc=5"); + zdialog_add_widget(zd,"check","latest","hb1",latest_message,"space=8"); + zdialog_add_widget(zd,"hbox","hb2","dialog",0,"space=3"); + zdialog_add_widget(zd,"label","lab21","hb2",ZTX("music file"),"space=3"); + zdialog_add_widget(zd,"entry","musicfile","hb2",0,"scc=30|space=5"); + zdialog_add_widget(zd,"button","browse","hb2",Bbrowse,"space=5"); + zdialog_add_widget(zd,"hbox","hb3","dialog",0,"space=3"); + zdialog_add_widget(zd,"label","lab3","hb3",ZTX("transitions"),"space=3"); + zdialog_add_widget(zd,"hbox","hb4","dialog"); + zdialog_add_widget(zd,"vbox","vb41","hb4",0,"space=8"); + zdialog_add_widget(zd,"vbox","vb42","hb4",0,"space=8"); + zdialog_add_widget(zd,"vbox","vb43","hb4",0,"space=8"); + + for (ii = 0; ii < SSNF; ii++) { // add transition check boxes + zdialog_add_widget(zd,"check",ss_table[ii].name, + ss_table[ii].vbox,ss_table[ii].name); + if (ss_funcs[ii]) zdialog_stuff(zd,ss_table[ii].name,1); // restore user preferences + } + + if (ss_interval < 9999) + zdialog_stuff(zd,"secs",ss_interval); // stuff last time interval + zdialog_stuff(zd,"musicfile",ss_musicfile); // stuff last music file + + zdialog_help(zd,"slide_show"); // zdialog help topic v.11.08 + zdialog_run(zd,slideshow_dialog_event); // run dialog + zstat = zdialog_wait(zd); // wait for completion + + if (zstat != 1) { // cancel + zdialog_free(zd); + menulock(0); + return; + } + + zdialog_fetch(zd,"secs",secs); // get interval, seconds + zdialog_fetch(zd,"latest",ss_latest); // get "latest files only" option + + for (ii = 0; ii < SSNF; ii++) // get selected transition types + zdialog_fetch(zd,ss_table[ii].name,ss_funcs[ii]); // v.11.08 + + for (ii = 1; ii < SSNF; ii++) // check selections + if (ss_funcs[ii]) break; + if (ii < SSNF) ss_funcs[0] = 0; // if some, remove arrow keys + else ss_funcs[0] = 1; // if none, default arrow keys + + char *pp = zmalloc(500,"musicfile"); + zdialog_fetch(zd,"musicfile",pp,499); // get music file + ss_musicfile = pp; + + zdialog_free(zd); + + ss_interval = secs; // interval between slides + if (ss_funcs[0]) ss_interval = 9999; // if manual transition, huge interval + ss_paused = 0; // not paused v.11.10 + + if (ss_musicfile && *ss_musicfile && strNeq(ss_musicfile,"undefined")) + { // if music file present, start it up + sprintf(command,"xdg-open \"%s\" ",ss_musicfile); // v.11.04 + printf("command: %s \n",command); + err = system(command); + if (err) printf("error: %s \n",wstrerror(err)); + } + + gtk_widget_hide_all(GTK_WIDGET(mMbar)); // enter slide show mode + gtk_widget_hide_all(GTK_WIDGET(mTbar)); // (full screen, no extras) + gtk_widget_hide_all(GTK_WIDGET(STbar)); + + gdk_window_set_background(drWin->window,&black); // black background v.11.10 + + gtk_window_maximize(MWIN); // avoid gtk_window_fullscreen() + zmainloop(); // must wait for update v.11.10 + gtk_window_get_size(MWIN,&ss_ww,&ss_hh); + + ss_pxmold = PXM_make(ss_ww,ss_hh,8); // make 3 screen-size pixmaps + ss_pxmnew = PXM_make(ss_ww,ss_hh,8); + ss_pxmmix = PXM_make(ss_ww,ss_hh,8); + + ss_newfile = strdupz(curr_file); // start with current image + ss_oldfile = 0; + + ss_timer = get_seconds() + ss_interval; // set timer for first call to + Fslideshow = 1; // ss_slideshow_next() + } + + else // leave slide show mode + { + if (ss_busy) { + ss_escape = 1; // wait for transition done + return; + } + + ss_escape = 0; + Fslideshow = 0; + + gdk_window_set_background(drWin->window,&lgray); // restore background v.11.10 + + gtk_window_unmaximize(MWIN); // restore old window size v.11.10 + gtk_widget_show_all(GTK_WIDGET(mMbar)); + gtk_widget_show_all(GTK_WIDGET(mTbar)); + gtk_widget_show_all(GTK_WIDGET(STbar)); + + if (ss_newfile) zfree(ss_newfile); // free memory + if (ss_oldfile) zfree(ss_oldfile); + ss_newfile = ss_oldfile = 0; + PXM_free(ss_pxmold); + PXM_free(ss_pxmnew); + PXM_free(ss_pxmmix); + + menulock(0); + } + + Fblowup = Fslideshow; + Fzoom = 0; // fit image to window + mwpaint2(); + return; +} + + +// dialog event function - file chooser for music file + +int slideshow_dialog_event(zdialog *zd, cchar *event) // v.11.04 +{ + char *pp; + + if (! strEqu(event,"browse")) return 0; + pp = zgetfile1(ZTX("Select music file or playlist"),"open",ss_musicfile); + if (! pp) return 0; + zdialog_stuff(zd,"musicfile",pp); + zfree(pp); + return 0; +} + + +// Show next slide if time is up or user navigates with arrow keys. +// Called by timer function and by keyboard function if Fslideshow is set. + +void slideshow_next(cchar *mode) // new v.11.01 +{ + void ss_loadimage(char *file, PXM *pxmout); + + double secs; + char *pp = 0; + int Fkey = 0, cp, ii; + static int last_transition = 0; + + if (strEqu(mode,"pause")) // toggle slide show paused status + ss_paused = 1 - ss_paused; // (spacebar) v.11.10 + + if (ss_busy) return; // come back later + + if (ss_escape) { // user pressed escape key + m_slideshow(0,0); // exit slide show + return; + } + + if (strEqu(mode,"timer")) { // timer trigger + if (ss_paused) return; + secs = get_seconds(); + if (secs < ss_timer) return; + mode = "next"; // time for next image + Fkey = 0; + } + else Fkey = 1; // keyboard trigger + + cp = curr_file_posn; + + if (ss_latest) { // get prev/next image file, + if (strEqu(mode,"prev")) // latest version v.11.10 + pp = ss_prev_latest(cp); + if (strEqu(mode,"next")) + pp = ss_next_latest(cp); + } + else { // get prev or next image file + if (strEqu(mode,"prev")) + pp = ss_prev(cp); + if (strEqu(mode,"next")) + pp = ss_next(cp); + } + + if (! pp) return; // there is none + + ss_busy++; + + if (ss_oldfile) zfree(ss_oldfile); + ss_oldfile = ss_newfile; + ss_newfile = pp; + + ss_loadimage(ss_oldfile,ss_pxmold); + ss_loadimage(ss_newfile,ss_pxmnew); + + mutex_lock(&Fpixmap_lock); // block other window updates + + if (Fkey) ss_instant(); // KB input, do instant transition + + else // use next selected transition type + { // v.11.08 + ii = last_transition; // start with last transition type + 1 + if (++ii > SSNF-1) ii = 1; // 1st is omitted (arrow keys) + + while (! ss_funcs[ii]) // infinite loop if none selected + if (++ii > SSNF-1) ii = 1; // bugfix v.11.09.1 + + last_transition = ii; // next transition + if (ii > 0) ss_table[ii].func(); // do image transition + } + + mutex_unlock(&Fpixmap_lock); + + zmainloop(); // catch-up anynch window updates? + + f_open(ss_newfile,0); // sync all image data + + if (zdeditcctext) m_edit_cctext(0,0); // edit caption and comments dialog + + secs = get_seconds(); // set time for next image + ss_timer = secs + ss_interval + 0.5; + ss_busy = 0; + return; +} + + +// get previous file before current file + +char * ss_prev(int cp) +{ + char *pp; + int ii; + + for (ii = cp-1; ii >= 0; ii--) + { + pp = image_gallery(0,"find",ii); + if (pp) return pp; + } + + return 0; +} + + +// get next file after current file + +char * ss_next(int cp) +{ + char *pp; + int ii; + int nfiles = image_navi::nfiles; + + for (ii = cp+1; ii < nfiles; ii++) + { + pp = image_gallery(0,"find",ii); + if (pp) return pp; + } + + return 0; +} + + +// get previous file, latest version, before current file + +char * ss_prev_latest(int cp) // new v.11.10 +{ + char *pp, *name1, *name2; + int ii; + + pp = image_gallery(0,"find",cp); + if (! pp) return 0; + + name1 = ss_basename(pp); + zfree(pp); + + for (ii = cp-1; ii >= 0; ii--) + { + pp = image_gallery(0,"find",ii); + if (! pp) { + zfree(name1); + return 0; + } + name2 = ss_basename(pp); + if (strEqu(name1,name2)) { + zfree(name2); + zfree(pp); + } + else { + zfree(name1); + zfree(name2); + return pp; + } + } + return 0; +} + + +// get next file, latest version, after current file + +char * ss_next_latest(int cp) // new v.11.10 +{ + char *pp1, *pp2, *name1, *name2; + int ii; + int nfiles = image_navi::nfiles; + + pp1 = image_gallery(0,"find",cp+1); + if (! pp1) return 0; + + name1 = ss_basename(pp1); + + for (ii = cp+2; ii < nfiles; ii++) + { + pp2 = image_gallery(0,"find",ii); + if (! pp2) { + zfree(name1); + return pp1; + } + name2 = ss_basename(pp2); + if (strEqu(name1,name2)) { + zfree(pp1); + zfree(name2); + pp1 = pp2; + } + else { + zfree(pp2); + zfree(name1); + zfree(name2); + return pp1; + } + } + return 0; +} + + +// extract base name from image file name +// base name is file name without directory, version, extension + +char * ss_basename(char *file) // v.11.10 +{ + char *pp1, *pp2, *pp3; + + pp1 = strrchr(file,'/'); // skip over directory if present + if (pp1) file = pp1 + 1; + pp1 = strdupz(file,0,"ss.basename"); + pp2 = strrchr(pp1,'.'); // look for .ext + if (! pp2) return pp1; + *pp2 = 0; // strip it off + pp3 = pp2 - 4; + if (! strnEqu(pp3,".v",2)) return pp1; // look for version .v00 to .v99 + if (pp3[2] < '0' || pp3[2] > '9') return pp1; + if (pp3[3] < '0' || pp3[3] > '9') return pp1; + *pp3 = 0; // strip it off + return pp1; +} + + +// load image and rescale to fit in given pixmap = window size + +void ss_loadimage(char *file, PXM *pxmout) // new v.11.01 +{ + int cc, fww, fhh, px, py, orgx, orgy; + PXM *pxmtemp1, *pxmtemp2; + double wscale, hscale, scale; + uint8 *pix1, *pix2; + + cc = ss_ww * ss_hh * 3; // clear output pixmap black v.11.10 + memset(pxmout->bmp,0,cc); + + pxmtemp1 = f_load(file,8); // load image file into 1x pixmap + if (! pxmtemp1) return; + + fww = pxmtemp1->ww; // image size + fhh = pxmtemp1->hh; + + wscale = 1.0 * ss_ww / fww; // find scale to fit in window + hscale = 1.0 * ss_hh / fhh; + if (wscale < hscale) scale = wscale; // use greatest ww/hh ratio + else scale = hscale; + fww = fww * scale; + fhh = fhh * scale; + + pxmtemp2 = PXM_rescale(pxmtemp1,fww,fhh); // rescale image to fit window + + orgx = 0.5 * (ss_ww - fww); // origin of image in window + orgy = 0.5 * (ss_hh - fhh); + + for (py = 0; py < fhh; py++) + for (px = 0; px < fww; px++) + { + pix1 = PXMpix8(pxmtemp2,px,py); + pix2 = PXMpix8(pxmout,px+orgx,py+orgy); + pix2[0] = pix1[0]; + pix2[1] = pix1[1]; + pix2[2] = pix1[2]; + } + + PXM_free(pxmtemp1); + PXM_free(pxmtemp2); + + return; +} + + +// instant transition (for use with keyboard arrow keys) + +void ss_instant() // new v.11.01 +{ + uint8 *pix3; + + pix3 = PXMpix8(ss_pxmnew,0,0); + gdk_draw_rgb_image(drWin->window, gdkgc, 0, 0, ss_ww, ss_hh, NODITHER, pix3, ss_ww*3); + return; +} + + +// fade-out / fade-in transition + +void ss_fadein() // new v.11.01 +{ + int ii, jj, kk, px, py; + double newpart, oldpart; + uint8 *pix1, *pix2, *pix3; + + PXM_free(ss_pxmmix); + ss_pxmmix = PXM_copy(ss_pxmold); + + for (ii = 0; ii <= 100; ii += 10) + { + newpart = 0.01 * ii; + oldpart = 1.0 - newpart; + + for (jj = 0; jj < 2; jj++) // four passes, each modifies 25% + for (kk = 0; kk < 2; kk++) // of the pixels (visually smoother) + { + for (py = jj; py < ss_hh; py += 2) + for (px = kk; px < ss_ww; px += 2) + { + pix1 = PXMpix8(ss_pxmold,px,py); + pix2 = PXMpix8(ss_pxmnew,px,py); + pix3 = PXMpix8(ss_pxmmix,px,py); + pix3[0] = newpart * pix2[0] + oldpart * pix1[0]; + pix3[1] = newpart * pix2[1] + oldpart * pix1[1]; + pix3[2] = newpart * pix2[2] + oldpart * pix1[2]; + } + + pix3 = PXMpix8(ss_pxmmix,0,0); + gdk_draw_rgb_image(drWin->window, gdkgc, 0, 0, ss_ww, ss_hh, NODITHER, pix3, ss_ww*3); + } + } + + pix3 = PXMpix8(ss_pxmnew,0,0); + gdk_draw_rgb_image(drWin->window, gdkgc, 0, 0, ss_ww, ss_hh, NODITHER, pix3, ss_ww*3); + return; +} + + +// new image rolls over prior image from left to right + +void ss_rollright() // new v.11.01 +{ + int px, py; + uint8 *pix1, *pix3; + double delay = 0.5 / ss_ww; // v.11.04 + + PXM_free(ss_pxmmix); + ss_pxmmix = PXM_copy(ss_pxmold); + + for (px = 0; px < ss_ww; px++) + { + pix1 = PXMpix8(ss_pxmnew,px,0); + pix3 = PXMpix8(ss_pxmmix,px,0); + + for (py = 0; py < ss_hh; py++) + { + memmove(pix3,pix1,3); + pix1 += ss_ww * 3; + pix3 += ss_ww * 3; + } + + pix3 = PXMpix8(ss_pxmmix,px,0); + gdk_draw_rgb_image(drWin->window, gdkgc, px, 0, 1, ss_hh, NODITHER, pix3, ss_ww*3); + zsleep(delay); + } + + pix3 = PXMpix8(ss_pxmnew,0,0); + gdk_draw_rgb_image(drWin->window, gdkgc, 0, 0, ss_ww, ss_hh, NODITHER, pix3, ss_ww*3); + return; +} + + +// new image rolls over prior image from top down + +void ss_rolldown() // new v.11.01 +{ + int py; + uint8 *pix3; + double delay = 0.5 / ss_hh; + + for (py = 0; py < ss_hh; py++) + { + pix3 = PXMpix8(ss_pxmnew,0,py); + gdk_draw_rgb_image(drWin->window, gdkgc, 0, py, ss_ww, 1, NODITHER, pix3, ss_ww*3); + zsleep(delay); + } + + pix3 = PXMpix8(ss_pxmnew,0,0); + gdk_draw_rgb_image(drWin->window, gdkgc, 0, 0, ss_ww, ss_hh, NODITHER, pix3, ss_ww*3); + return; +} + + +// shift prior image to the left as next image shifts-in from the right +// (this one flickers annoingly and cannot be fixed) + +void ss_shiftleft() // new v.11.01 +{ + int px, Nsteps = 50; + uint8 *pix1, *pix3; + + for (px = 0; px < ss_ww; px += ss_ww / Nsteps) + { + pix1 = PXMpix8(ss_pxmold,px,0); + pix3 = PXMpix8(ss_pxmnew,0,0); + gdk_draw_rgb_image(drWin->window, gdkgc, 0, 0, ss_ww - px, ss_hh, NODITHER, pix1, ss_ww * 3); + gdk_draw_rgb_image(drWin->window, gdkgc, ss_ww - px, 0, px, ss_hh, NODITHER, pix3, ss_ww * 3); + zsleep(0.01); + } + + pix3 = PXMpix8(ss_pxmnew,0,0); + gdk_draw_rgb_image(drWin->window, gdkgc, 0, 0, ss_ww, ss_hh, NODITHER, pix3, ss_ww * 3); + return; +} + + +// new image opens up in horizontal rows like venetian blinds + +void ss_venetian() // new v.11.01 +{ + int py1, py2; + uint8 *pix3; + int louver, Nlouvers = 20; + int louversize = ss_hh / Nlouvers; + double delay = 1.0 / louversize; + + for (py1 = 0; py1 < louversize; py1++) // y-row within each louver + { + for (louver = 0; louver < Nlouvers; louver++) // louver, first to last + { + py2 = py1 + louver * louversize; + if (py2 >= ss_hh) break; + pix3 = PXMpix8(ss_pxmnew,0,py2); + gdk_draw_rgb_image(drWin->window, gdkgc, 0, py2, ss_ww, 1, NODITHER, pix3, ss_ww*3); + } + + zsleep(delay); + } + + pix3 = PXMpix8(ss_pxmnew,0,0); + gdk_draw_rgb_image(drWin->window, gdkgc, 0, 0, ss_ww, ss_hh, NODITHER, pix3, ss_ww * 3); + return; +} + + +// a grate opens up to show new image + +void ss_grate() // new v.11.01 +{ + int px1, px2, py1, py2; + uint8 *pix3; + int row, col, Nrow, Ncol; // rows and columns + int boxww, boxhh; + double delay; + + Ncol = 20; // 20 columns + boxww = boxhh = ss_ww / Ncol; // square boxes + Nrow = ss_hh / boxhh; // corresp. rows + Ncol++; // round up + Nrow++; + delay = 1.0 / boxhh; + + for (py1 = 0; py1 < boxhh; py1++) + { + for (row = 0; row < Nrow; row++) + { + py2 = py1 + row * boxhh; + if (py2 >= ss_hh) break; + pix3 = PXMpix8(ss_pxmnew,0,py2); + gdk_draw_rgb_image(drWin->window, gdkgc, 0, py2, ss_ww, 1, NODITHER, pix3, ss_ww*3); + } + + px1 = py1; + + for (col = 0; col < Ncol; col++) + { + px2 = px1 + col * boxww; + if (px2 >= ss_ww) break; + pix3 = PXMpix8(ss_pxmnew,px2,0); + gdk_draw_rgb_image(drWin->window, gdkgc, px2, 0, 1, ss_hh, NODITHER, pix3, ss_ww*3); + } + + zsleep(delay); + } + + pix3 = PXMpix8(ss_pxmnew,0,0); + gdk_draw_rgb_image(drWin->window, gdkgc, 0, 0, ss_ww, ss_hh, NODITHER, pix3, ss_ww * 3); + return; +} + + +// A hole opens up from the center and expands outward + +void ss_rectangle() // new v.11.01 +{ + int px1, py1, px2, py2, px3, py3; + int ww1, hh1, ww2, hh2; + uint8 *pix3; + int step, Nsteps = 100; + double delay = 1.0 / Nsteps; + + for (step = 1; step < Nsteps; step++) + { + ww1 = ss_ww * step / Nsteps; + hh1 = ww1 * ss_hh / ss_ww; + ww2 = ss_ww / Nsteps / 2; + hh2 = ss_hh / Nsteps / 2; + + px1 = (ss_ww - ww1) / 2; + py1 = (ss_hh - hh1) / 2; + px2 = px1 + ww1 - ww2; + py2 = py1; + px3 = px1; + py3 = py1 + hh1 - hh2; + + pix3 = PXMpix8(ss_pxmnew,px1,py1); + gdk_draw_rgb_image(drWin->window, gdkgc, px1, py1, ww1+1, hh2+1, NODITHER, pix3, ss_ww*3); + + pix3 = PXMpix8(ss_pxmnew,px2,py2); + gdk_draw_rgb_image(drWin->window, gdkgc, px2, py2, ww2+1, hh1+1, NODITHER, pix3, ss_ww*3); + + pix3 = PXMpix8(ss_pxmnew,px3,py3); + gdk_draw_rgb_image(drWin->window, gdkgc, px3, py3, ww1+1, hh2+1, NODITHER, pix3, ss_ww*3); + + pix3 = PXMpix8(ss_pxmnew,px1,py1); + gdk_draw_rgb_image(drWin->window, gdkgc, px1, py1, ww2+1, hh1+1, NODITHER, pix3, ss_ww*3); + + zmainloop(); + zsleep(delay); + } + + pix3 = PXMpix8(ss_pxmnew,0,0); + gdk_draw_rgb_image(drWin->window, gdkgc, 0, 0, ss_ww, ss_hh, NODITHER, pix3, ss_ww * 3); + return; +} + + +// An ellipse opens up from the center and expands outward + +void ss_ellipse() // new v.11.03 +{ + uint8 *pix3; + int step, Nsteps = 100; + int px1, py1, ww; + double delay = 1.0 / Nsteps; + double a, b, a2, b2, px, py, px2, py2; + double ww2 = ss_ww / 2, hh2 = ss_hh / 2; + + for (step = 1; step < 1.3 * Nsteps; step++) + { + a = ww2 * step / Nsteps; // ellipse a and b constants + b = a * ss_hh / ss_ww; // from tiny to >> image size + a2 = a * a; + b2 = b * b; + + for (py = -b; py <= +b; py += 3) // py from top of ellipse to bottom + { + while (py < -(hh2-2)) py += 3; + if (py > hh2-2) break; + py2 = py * py; + px2 = a2 * (1.0 - py2 / b2); // corresponding px value, + px = sqrt(px2); // (+/- from center of ellipse) + if (px > ww2) px = ww2; + ww = 2 * px; // length of line thru ellipse + px1 = ww2 - px; // relocate origin + py1 = py + hh2; + pix3 = PXMpix8(ss_pxmnew,px1,py1); + gdk_draw_rgb_image(drWin->window, gdkgc, px1, py1, ww, 3, NODITHER, pix3, ss_ww*3); + } + + zmainloop(); + zsleep(delay); + } + + pix3 = PXMpix8(ss_pxmnew,0,0); + gdk_draw_rgb_image(drWin->window, gdkgc, 0, 0, ss_ww, ss_hh, NODITHER, pix3, ss_ww * 3); + return; +} + + +// New image sweeps into view like a circular radar image + +void ss_radar() // new v.11.08 +{ + int px = 0, py = 0, Npx, Npy, Np = 12; // smaller values make compiz jerky *** + double R, Rmax, T, Tmax, dT, delay; + double cosT, sinT; + double ww2 = ss_ww / 2, hh2 = ss_hh / 2; + uint8 *pix3; + + Rmax = sqrt(ww2 * ww2 + hh2 * hh2); + Tmax = pi; + dT = 0.6 * asin(Np / Rmax); + delay = dT / Tmax; // 1 sec. + CPU time + if (delay < 0.001) delay = 0.001; + + for (T = 0; T < Tmax; T += dT) + { + cosT = cos(T); + sinT = sin(T); + + for (R = -Rmax; R < Rmax; R += Np) // v.11.09 + { + px = ww2 + R * cosT; + py = hh2 - R * sinT; + if (px < -Np) continue; + if (py < -Np) continue; + if (px > ss_ww-1) continue; + if (py > ss_hh-1) continue; + Npx = Npy = Np; // do the last piece too v.11.10 + if (px < 0) px = 0; + if (py < 0) py = 0; + if (px + Npx > ss_ww-1) Npx = ss_ww-1 - px; + if (py + Npy > ss_hh-1) Npy = ss_hh-1 - py; + pix3 = PXMpix8(ss_pxmnew,px,py); + gdk_draw_rgb_image(drWin->window, gdkgc, px, py, Npx, Npy, NODITHER, pix3, ss_ww*3); + } + + zsleep(delay); + } + + pix3 = PXMpix8(ss_pxmnew,0,0); + gdk_draw_rgb_image(drWin->window, gdkgc, 0, 0, ss_ww, ss_hh, NODITHER, pix3, ss_ww * 3); + return; +} + + +// New image closes in from top and bottom with jagged teeth + +void ss_jaws() // new v.11.08 +{ + int nteeth = 20, Np = 6; + int tbase1, tbase2, twidth, tlength, tooth, tpos; + int ii, px, py, ww, ww2; + double delay = 2.0 * Np / ss_hh; // 1 sec. + CPU time + uint8 *pix3; + + twidth = ss_ww / nteeth; + tlength = twidth; + + for (ii = 0; ii < ss_hh/2 - tlength/2; ii += Np) + { + tbase1 = ii; // tooth base from top to middle + tbase2 = ss_hh - tbase1 - 1; // tooth base from bottom to middle + + for (tooth = 0; tooth <= nteeth; tooth++) // tooth first to last + 1 + { + for (tpos = 0; tpos < tlength; tpos += Np) // tooth position from base to point + { + ww = twidth * (tlength - tpos) / tlength; // tooth width at scan line + if (ww < 2) break; + + py = tbase1 + tpos; // top teeth scan line y + px = twidth / 2 + tooth * twidth - ww / 2; // scan line x to x + ww + if (px < ss_ww) { + pix3 = PXMpix8(ss_pxmnew,px,py); + ww2 = ww; + if (px + ww2 > ss_ww) ww2 = ss_ww - px; + gdk_draw_rgb_image(drWin->window, gdkgc, px, py, ww2, Np, NODITHER, pix3, ss_ww*3); + } + + py = tbase2 - tpos; // bottom teeth scan line y + px = tooth * twidth - ww / 2; // scan line x to x + ww + if (tooth == 0) { + px = 0; // leftmost tooth is half + ww = ww / 2; + } + if (px < ss_ww) { + pix3 = PXMpix8(ss_pxmnew,px,py); + ww2 = ww; + if (px + ww2 > ss_ww) ww2 = ss_ww - px; + gdk_draw_rgb_image(drWin->window, gdkgc, px, py, ww2, Np, NODITHER, pix3, ss_ww*3); + } + } + } + + zmainloop(); + zsleep(delay); + } + + pix3 = PXMpix8(ss_pxmnew,0,0); + gdk_draw_rgb_image(drWin->window, gdkgc, 0, 0, ss_ww, ss_hh, NODITHER, pix3, ss_ww * 3); + return; +} + + +/**************************************************************************/ + +// menu function, start synchronize files process manually + +void m_syncfiles(GtkWidget *, cchar *) // v.11.11 +{ + int err, syncfd; + + if (mod_keep()) return; // unsaved edits + if (! menulock(1)) return; // edit function busy + + syncfd = global_lock(fsync_lock); // check if sync files running + if (syncfd >= 0) global_unlock(syncfd); + else { + zmessageACK(mWin,ZTX("Sync Files is already running")); // yes, do nothing + menulock(0); + return; + } + + printf("spawn sync files subprocess \n"); + err = system("fotoxx -syncfiles manual &"); // spawn file sync process + if (err) zmessageACK(mWin,"error: %s \n",wstrerror(err)); + + menulock(0); + return; +} + + +/**************************************************************************/ + +// Synchronize files when fotoxx is installed for the first time or +// when new image files have been created or moved outside fotoxx. +// This is a spawned process running parallel to the user GUI process. +// The main window with menus and toolbar is not available. + +struct tag_index_rec { + char *file; // image filespec + char *tags; // image tags + char *comms; // image comments + char *capt; // image caption + char imagedate[12], filedate[16]; // image date, file date + char stars; // image rating, '0' to '5' + char update; // flag, update is needed +}; +tag_index_rec *xrec_old, *xrec_new; + + +int syncfiles_func(void *) // v.11.11 +{ + int syncfiles_dialog_event(zdialog *zd, cchar *event); + char * syncfiles_find(char *imagedirk, int &Finit); + int syncfiles_index_compare(cchar *rec1, cchar *rec2); + int filesync_thumbfile(char *imagefile); + + int contx, syncfd, dosync, yn, err; + cchar *Fsyncreason, *ppc; + char *pp, text[200]; + char *filespec, *thumbfile, *subdirk; + char imagefile[maxfcc], logrec[200]; + zdialog *zd; + int zstat, fcount, flag; + int cc, fcc, dcc, Finit; + FILE *fid; + struct stat statb; + + cchar *sync_message = ZTX("Run Tools > Synchronize Files so that gallery windows \n" + "will be fast and Search Images will work correctly. \n" + "You can view (not edit) images while synchronize runs."); + + cchar *exifkeys[5] = { exif_date_key, iptc_tags_key, iptc_rating_key, + exif_comment_key, iptc_caption_key }; + + zfuncs::F1_help_topic = "sync_files"; + + printf("enter sync files process %d %d \n",Fautosync,Fmansync); + + syncfd = global_lock(fsync_lock); // obtain sync files lock + if (syncfd < 0) { + zmessage_post(0,5,"Sync Files is already running"); + gtk_main_quit(); + return 0; + } + + err = system("which exiftool > /dev/null"); + if (err) { // exiftool is required + zmessageACK(0,Bexiftoolmissing); + gtk_main_quit(); + return 0; + } + + dosync = 0; + Fsyncreason = "none"; + + if (topdirk) { // v.11.12.1 + err = stat(topdirk,&statb); + if (err || ! S_ISDIR(statb.st_mode)) topdirk = 0; + } + + if (! topdirk) { // reasons for sync files + Fsyncreason = ZTX("no top image directory is defined"); + dosync = 2; + } + else { + printf("top image directory: %s \n",topdirk); + err = stat(topdirk,&statb); + if (err) Fsyncreason = ZTX("top image directory is invalid"); + if (err) dosync = 2; + } + + err = stat(search_index_file,&statb); + if (err) Fsyncreason = ZTX("no search index file is present"); + if (err) dosync = 2; + + if (! dosync) // check for new image files v.11.11 + { // since last session or sync + sprintf(command,"find -L \"%s\" -type d -newermt \"%s\" ", + topdirk,last_session); // use directory mod time v.11.11.1 + printf("%s \n",command); + contx = 0; + while ((pp = command_output(contx,command,null))) { + newfiles++; // add to possible prior session count + zfree(pp); + } + if (newfiles) { + strncpy0(text,ZTX("new/modified files are present"),199); // v.11.11.1 + Fsyncreason = text; + dosync = 1; + } + } + + if (dosync) printf("%s \n",Fsyncreason); + else printf("%s \n",ZTX("no new files found")); + + if (! dosync && Fautosync) { // no need to sync and not manual req. + gtk_main_quit(); + return 0; + } + + if (dosync < 2 && ! Fmansync) // dialog not required, not manual req. + goto start_sync; // do auto sync + + +// user dialog to request sync files and supply top image directory + +sync_dialog: + + zd = zdialog_new(ZTX("Synchronize Files"),mWin,Bproceed,Bcancel,null); + zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=3"); + zdialog_add_widget(zd,"label","lab1","hb1",ZTX("Top Image Directory:")); + zdialog_add_widget(zd,"hbox","hb2","dialog",0,"space=3"); + zdialog_add_widget(zd,"entry","topdirk","hb2","??","scc=40|space=5"); + zdialog_add_widget(zd,"button","browse","hb2",Bbrowse,"space=5"); + + if (strNeq(Fsyncreason,"none")) { // show reason for file sync + zdialog_add_widget(zd,"label","labwhy1","dialog",Fsyncreason,"space=3"); + zdialog_add_widget(zd,"label","labwhy2","dialog",sync_message,"space=3"); + } + + if (topdirk) zdialog_stuff(zd,"topdirk",topdirk); // v.11.12.1 + zdialog_help(zd,"sync_files"); + + zdialog_run(zd,syncfiles_dialog_event); + zstat = zdialog_wait(zd); + + if (zstat != 1) { // dialog canceled + zdialog_free(zd); + if (dosync < 2) { // file sync is optional + gtk_main_quit(); + return 0; + } + yn = zmessageYN(0,ZTX("file sync is necessary.\n" + "cancel anyway?")); // v.12.01 + if (! yn) goto sync_dialog; + gtk_main_quit(); + return 0; + } + + pp = zmalloc(200); + zdialog_fetch(zd,"topdirk",pp,200); // get top directory + zdialog_free(zd); + + err = stat(pp,&statb); // check for validity + if (err || ! S_ISDIR(statb.st_mode)) { + zmessageACK(mWin,ZTX("top directory is invalid")); + zfree(pp); + goto sync_dialog; + } + + if (topdirk) zfree(topdirk); + topdirk = strdupz(pp,0,"topdirk"); + zfree(pp); + + cc = strlen(topdirk); // remove trailing '/' if present + if (topdirk[cc-1] == '/') topdirk[cc-1] = 0; // v.11.12 + + fid = fopen(topdirk_file,"w"); // write top directory file + if (fid) { + fprintf(fid,"%s\n",topdirk); + fclose(fid); + } + + +start_sync: + +// look for orphan thumbnail files and delete them + + write_popup_text("open","Synchronize Files",500,300); // popup window for log data + write_popup_text("write","deleting orphan thumbnails"); + + snprintf(command,ccc,"%s*.thumbnails/*.png",topdirk); // find all /topdirk/.thumbnails/*.png + fcount = 0; + flag = 1; + + while ((thumbfile = (char *) SearchWild(command,flag))) // next thumbnail file + { + pp = strrchr(thumbfile,'/'); + if (strnNeq(pp-12,"/.thumbnails/",13)) continue; + fcc = strlen(pp) - 4; + if (strNeq(pp+fcc,".png")) continue; + + strncpy0(imagefile,thumbfile,maxfcc); // construct matching image file + dcc = pp - 12 - thumbfile; + if (dcc + fcc >= maxfcc) continue; + memmove(imagefile+dcc,pp,fcc); + imagefile[dcc+fcc] = 0; + + err = stat(imagefile,&statb); // look for image file + if (! err) continue; // found, keep thumbnail + + *pp = '/'; + remove(thumbfile); // not found, delete thumbnail + fcount++; // count thumbnails deleted + + snprintf(logrec,199,"delete thumbnail: %s",thumbfile); + write_popup_text("write",logrec); + } + + snprintf(logrec,199,"deleted %d orphan thumbnails",fcount); + write_popup_text("write",logrec); + +// look for image files without thumbnails and create the thumbnails + + snprintf(logrec,199,"creating missing and update stale thumbnails"); + write_popup_text("write",logrec); + + snprintf(command,ccc,"find \"%s\" -type d",topdirk); // find directories under top directory + contx = 0; + fcount = 0; + + while ((subdirk = command_output(contx,command))) + { + pp = strrchr(subdirk,'/'); + if (pp && strEqu(pp,"/.thumbnails")) { // /.../.thumbnails/ directory + zfree(subdirk); + continue; // skip + } + + Finit = 1; + filespec = syncfiles_find(subdirk,Finit); // get first image file + + while (filespec) // loop all image files + { + if (image_file_type(filespec) == 2) + { + if (filesync_thumbfile(filespec)) { + snprintf(logrec,199,"create thumbnail: %s",filespec); + write_popup_text("write",logrec); + fcount++; // count thumbnails created v.11.11 + } + } + + zfree(filespec); + filespec = syncfiles_find(subdirk,Finit); // next image file + } + + zfree(subdirk); + } + + snprintf(logrec,199,"created %d thumbnails",fcount); + write_popup_text("write",logrec); + + // Rebuild search index file. + // Process all image files within given top-level directory. + // Works incrementally and is very fast after the first run. + + snprintf(logrec,199,"rebuild search index"); + write_popup_text("write",logrec); + + char **ppv, tagsbuff[tagrecl]; + char *imagedate, *imagetags, *imagestars, *imagecomms, *imagecapt; + int Nold, Nnew, orec, nrec, comp; + int pcache, Ncache, nrec2; + char **ppcache; + cchar *Fcache[50]; + + struct tm bdt; + + fcount = MAXIMAGES; // max. image files supported v.12.01 + + xrec_old = (tag_index_rec *) zmalloc(fcount * sizeof(tag_index_rec),"sync"); + xrec_new = (tag_index_rec *) zmalloc(fcount * sizeof(tag_index_rec),"sync"); + + // read current search index file and build "old list" of tags + + orec = Nold = 0; + fid = 0; + + fid = fopen(search_index_file,"r"); + + if (fid) + { + while (true) // read current search index records + { + pp = fgets_trim(tagsbuff,tagrecl,fid); // next record + if (! pp) break; + + if (strnEqu(pp,"file: ",6)) // start new file entry + { + if (++Nold == fcount) zappcrash("too many image files"); + orec = Nold - 1; + xrec_old[orec].file = strdupz(pp+6,0,"xrec_old.file"); + xrec_old[orec].imagedate[0] = 0; + xrec_old[orec].filedate[0] = 0; + xrec_old[orec].tags = 0; + xrec_old[orec].stars = '0'; + xrec_old[orec].comms = 0; + xrec_old[orec].capt = 0; + xrec_old[orec].update = '0'; + } + + if (strnEqu(pp,"date: ",6)) + { + ppc = strField(pp,' ',2); + if (ppc) strncpy0(xrec_old[orec].imagedate,ppc,12); + ppc = strField(pp,' ',3); + if (ppc) strncpy0(xrec_old[orec].filedate,ppc,16); + } + + if (strnEqu(pp,"tags: ",6)) + xrec_old[orec].tags = strdupz(pp+6,0,"sync"); + + if (strnEqu(pp,"stars: ",7)) + xrec_old[orec].stars = *(pp+7); + + if (strnEqu(pp,"comms: ",7)) + xrec_old[orec].comms = strdupz(pp+7,0,"sync"); + + if (strnEqu(pp,"capt: ",6)) + xrec_old[orec].capt = strdupz(pp+6,0,"sync"); // v.10.12 + } + + fclose(fid); + } + + snprintf(logrec,199,"%d current index records found",Nold); + write_popup_text("write",logrec); + + // find all image files and create "new list" with no tags + + snprintf(logrec,199,"find all image files and build index records"); + write_popup_text("write",logrec); + + snprintf(command,ccc,"find \"%s\" -type d",topdirk); // find directories under top directory + contx = 0; + Nnew = nrec = 0; + + while ((subdirk = command_output(contx,command))) + { + pp = strrchr(subdirk,'/'); + if (pp && strEqu(pp,"/.thumbnails")) // skip ./thumbnails directories + { + zfree(subdirk); + continue; + } + + Finit = 1; + filespec = syncfiles_find(subdirk,Finit); // get first image file + + while (filespec) // loop all image files + { + if (image_file_type(filespec) == 2) // construct new tag record + { + err = stat(filespec,&statb); + if (err) continue; + if (++Nnew == fcount) zappcrash("too many image files"); + nrec = Nnew - 1; + xrec_new[nrec].file = strdupz(filespec,0,"sync"); // image filespec + xrec_new[nrec].imagedate[0] = 0; // image date = empty + gmtime_r(&statb.st_mtime,&bdt); // file date = yyyymmddhhmmss + snprintf(xrec_new[nrec].filedate,16,"%04d%02d%02d%02d%02d%02d", + bdt.tm_year + 1900, bdt.tm_mon + 1, bdt.tm_mday, + bdt.tm_hour, bdt.tm_min, bdt.tm_sec); + xrec_new[nrec].tags = 0; // tags = empty + xrec_new[nrec].stars = '0'; // stars = '0' + xrec_new[nrec].comms = 0; // comments = empty + xrec_new[nrec].capt = 0; // caption = empty v.10.12 + } + + zfree(filespec); + filespec = syncfiles_find(subdirk,Finit); // next image file + } + + zfree(subdirk); + } + + snprintf(logrec,199,"found %d image files",Nnew); + write_popup_text("write",logrec); + + // merge and compare lists + // if filespecs match and have the same date, then old tags are OK + + snprintf(logrec,199,"merging old and new index records"); + write_popup_text("write",logrec); + + HeapSort((char *) xrec_old,sizeof(tag_index_rec),Nold,syncfiles_index_compare); + HeapSort((char *) xrec_new,sizeof(tag_index_rec),Nnew,syncfiles_index_compare); + + for (orec = nrec = 0; nrec < Nnew; ) + { + xrec_new[nrec].update = '1'; // assume update is needed + + if (orec == Nold) comp = +1; + else comp = strcmp(xrec_old[orec].file, xrec_new[nrec].file); // compare filespecs + + if (comp > 0) nrec++; + else if (comp < 0) orec++; + else // matching filespecs + { + if (strEqu(xrec_new[nrec].filedate, xrec_old[orec].filedate)) // and matching file dates + { // copy data from old to new + strncpy0(xrec_new[nrec].imagedate,xrec_old[orec].imagedate,12); + xrec_new[nrec].tags = xrec_old[orec].tags; + xrec_old[orec].tags = 0; + xrec_new[nrec].stars = xrec_old[orec].stars; + xrec_new[nrec].comms = xrec_old[orec].comms; + xrec_old[orec].comms = 0; + xrec_new[nrec].capt = xrec_old[orec].capt; + xrec_old[orec].capt = 0; + xrec_new[nrec].update = '0'; // update is not needed + } + nrec++; + orec++; + } + } + + for (orec = 0; orec < Nold; orec++) // release old list memory + { + zfree(xrec_old[orec].file); + if (xrec_old[orec].tags) zfree(xrec_old[orec].tags); + if (xrec_old[orec].capt) zfree(xrec_old[orec].capt); // memory leak v.11.09 + if (xrec_old[orec].comms) zfree(xrec_old[orec].comms); + } + + zfree(xrec_old); + xrec_old = 0; + + // process entries needing update in new index list + // get updated metadata from image file EXIF/IPTC data + + snprintf(logrec,199,"updating index records"); + write_popup_text("write",logrec); + + Ncache = 0; // cache empty + pcache = 0; + ppcache = 0; + + for (fcount = nrec = 0; nrec < Nnew; nrec++) + { + if (xrec_new[nrec].update == '0') continue; // no update needed + fcount++; // running count of updates + + if (! Ncache) // cache empty v.12.01 + { + for (nrec2 = nrec; Ncache < 50 && nrec2 < Nnew; nrec2++) + { + if (xrec_new[nrec2].update != '0') { // add next 50 files to cache + Fcache[Ncache] = xrec_new[nrec2].file; + Ncache++; + } + } + + ppcache = info_getN(Fcache,Ncache,exifkeys,5); // get metadata for cached files + pcache = 0; // 1st cache position + } + + ppv = ppcache + 5 * pcache; // get key values for next file + + Ncache--; // index to next cache data + pcache++; + + imagedate = ppv[0]; + imagetags = ppv[1]; + imagestars = ppv[2]; + imagecomms = ppv[3]; + imagecapt = ppv[4]; + + if (imagedate && strlen(imagedate) > 3) { // image date v.11.10 + if (strlen(imagedate) > 9) imagedate[10] = 0; // truncate to yyyy:mm:dd + strcpy(xrec_new[nrec].imagedate,imagedate); + } + else strcpy(xrec_new[nrec].imagedate,"null"); + + if (imagetags && strlen(imagetags)) // image tags + xrec_new[nrec].tags = strdupz(imagetags,0,"sync"); + else xrec_new[nrec].tags = strdupz("null"tagdelim2,0,"sync"); // v.11.02 + + if (imagestars && strlen(imagestars)) // image rating + xrec_new[nrec].stars = *imagestars; + + if (imagecomms && strlen(imagecomms)) // image comments + xrec_new[nrec].comms = strdupz(imagecomms,0,"sync"); + else xrec_new[nrec].comms = strdupz("null",0,"sync"); + + if (imagecapt && strlen(imagecapt)) // image caption v.10.12 + xrec_new[nrec].capt = strdupz(imagecapt,0,"sync"); + else xrec_new[nrec].capt = strdupz("null",0,"sync"); + + if (imagedate) zfree(imagedate); + if (imagetags) zfree(imagetags); + if (imagestars) zfree(imagestars); + if (imagecomms) zfree(imagecomms); + if (imagecapt) zfree(imagecapt); + + snprintf(logrec,199,"update index: %s",xrec_new[nrec].file); + write_popup_text("write",logrec); + } + + fid = fopen(search_index_file,"w"); // write new search index file + if (! fid) zappcrash("cannot write tags file"); // with merged data + + for (nrec = 0; nrec < Nnew; nrec++) + { + fprintf(fid,"file: %s""\n",xrec_new[nrec].file); + fprintf(fid,"date: %s %s""\n",xrec_new[nrec].imagedate, xrec_new[nrec].filedate); + fprintf(fid,"tags: %s""\n",xrec_new[nrec].tags); + fprintf(fid,"stars: %c""\n",xrec_new[nrec].stars); + fprintf(fid,"comms: %s""\n",xrec_new[nrec].comms); + fprintf(fid,"capt: %s""\n",xrec_new[nrec].capt); + fprintf(fid,"\n"); + } + + fclose(fid); + + for (nrec = 0; nrec < Nnew; nrec++) // release new list memory + { + zfree(xrec_new[nrec].file); + if (xrec_new[nrec].tags) zfree(xrec_new[nrec].tags); + if (xrec_new[nrec].capt) zfree(xrec_new[nrec].capt); // memory leak v.11.09 + if (xrec_new[nrec].comms) zfree(xrec_new[nrec].comms); + } + + zfree(xrec_new); + xrec_new = 0; + + snprintf(logrec,199,"%d image files updated",fcount); + write_popup_text("write",logrec); + + write_popup_text("write","COMPLETED"); + printf("sync files subprocess completed \n"); + + global_unlock(syncfd); // release file sync lock + + while (zfuncs::open_popup_windows) { // wait for popup window to be closed + zmainloop(); + zsleep(0.1); + } + + gtk_main_quit(); // gone forever + return 0; +} + + +// dialog event function - file chooser for top image directory + +int syncfiles_dialog_event(zdialog *zd, cchar *event) +{ + char *pp; + + if (! strEqu(event,"browse")) return 0; + pp = zgetfile1(ZTX("Select top image directory"),"folder",topdirk); // get topmost directory + if (! pp) return 0; + zdialog_stuff(zd,"topdirk",pp); + zfree(pp); + return 0; +} + + +// find image files in a directory, return one per call // v.11.11 + +char * syncfiles_find(char *imagedirk, int &Finit) +{ + char *file; + cchar *findcommand = "find \"%s\" -maxdepth 1 -type f"; + static int contx, ftyp; + + if (Finit) { + Finit = 0; + contx = 0; + } + + while ((file = command_output(contx,findcommand,imagedirk))) // find next file in directory + { + if (! file) return 0; // EOL + ftyp = image_file_type(file); + if (ftyp == 2) return file; // supported image file type + zfree(file); + continue; + } + + return 0; +} + + +// Find the thumbnail file for the given image file. +// If missing or stale, add or update in /.thumbnails directory. +// Returns 0 if thumbnail file was OK, 1 if it was created. + +int filesync_thumbfile(char *imagefile) // v.11.11 +{ + GdkPixbuf *thumbpxb; + GError *gerror = 0; + char *pfile, *bfile, *thumbfile; + int err, sizew, sizeh; + struct stat statf, statb; + + err = stat(imagefile,&statf); // stat the image file + if (err) return 0; + pfile = strrchr(imagefile,'/'); // get .../filename.xxx + if (! pfile) return 0; + thumbfile = strdupz(imagefile,20,"image_thumbfile"); // construct thumbnail file + bfile = thumbfile + (pfile - imagefile); // .../.thumbnails/filename.xxx.png + strcpy(bfile,"/.thumbnails"); + bfile += 12; + strcpy(bfile,pfile); + strcat(bfile,".png"); + + err = stat(thumbfile,&statb); // stat the thumbnail file + if (! err && statb.st_mtime >= statf.st_mtime) return 0; // found and up to date + + *bfile = 0; + err = stat(thumbfile,&statb); + if (err) err = mkdir(thumbfile,0751); // create .thumbnails directory + if (err) return 0; + + *bfile = *pfile; + sizew = sizeh = image_navi::thumbfilesize; // create thumbnail pixbuf + thumbpxb = gdk_pixbuf_new_from_file_at_size(imagefile,sizew,sizeh,&gerror); + if (! thumbpxb) { + printf("gdk_pixbuf_new error: %s \n",gerror->message); // diagnose error v.3.3 + return 0; + } + gdk_pixbuf_save(thumbpxb,thumbfile,"png",&gerror,null); // save in /.thumbnails/ directory + g_object_unref(thumbpxb); + + return 1; +} + + +// sort compare function - compare tag record filespecs and return +// <0 | 0 | >0 for file1 < | == | > file2 + +int syncfiles_index_compare(cchar *rec1, cchar *rec2) +{ + char * file1 = ((tag_index_rec *) rec1)->file; + char * file2 = ((tag_index_rec *) rec2)->file; + return strcmp(file1,file2); +} + + +/**************************************************************************/ + +// Show RGB values for 1-5 pixels selected with mouse-clicks. + +void show_RGB_mousefunc(); +int show_RGB_timefunc(void *); + +zdialog *RGBSzd; +int RGBSpixel[5][2]; // last 0-5 pixels clicked +int RGBSnpix; // count of pixels +double RGBStime; // last click time +int RGBSmetric = 1; // 1/2/3 = /RGB/EV/OD +int RGBSdelta = 0; // abs/delta mode +int RGBSlabels = 0; // pixel labels on/off + + +void m_show_RGB(GtkWidget *, cchar *menu) // rewritten v.11.07 +{ + int show_RGB_event(zdialog *zd, cchar *event); + + PangoFontDescription *pfontdesc; + GtkWidget *widget; + cchar *mess = ZTX("Click image to select pixels."); + cchar *header = " Pixel Red Green Blue"; + + zfuncs::F1_help_topic = "show_RGB"; + + if (! Fpxm8) return; // no image file + RGBSnpix = 0; // no pixels yet + pfontdesc = pango_font_description_from_string("Monospace 9"); // monospace font + +/*** + + Click image to select pixels. + [x] delta [x] labels + Metric: (o) RGB (o) EV (o) OD + Pixel Red Green Blue + A xxxx xxxx xxxxx xxxxx xxxxx + B xxxx xxxx xxxxx xxxxx xxxxx + C xxxx xxxx xxxxx xxxxx xxxxx + D xxxx xxxx xxxxx xxxxx xxxxx + E xxxx xxxx xxxxx xxxxx xxxxx + + [done] +***/ + + if (RGBSzd) zdialog_free(RGBSzd); // delete previous if any + zdialog *zd = zdialog_new(ZTX("Show RGB"),mWin,Bdone,null); + RGBSzd = zd; + + zdialog_add_widget(zd,"hbox","hbmess","dialog",0,"space=3"); + zdialog_add_widget(zd,"label","labmess","hbmess",mess,"space=5"); + + zdialog_add_widget(zd,"hbox","hbmym","dialog"); + zdialog_add_widget(zd,"check","delta","hbmym","delta","space=8"); + zdialog_add_widget(zd,"check","labels","hbmym","labels","space=8"); + + if (RGBSdelta) zdialog_stuff(zd,"delta",1); // abs/delta mode v.11.08 + + zdialog_add_widget(zd,"hbox","hbmetr","dialog",0,"space=3"); + zdialog_add_widget(zd,"label","labmetr","hbmetr","Metric:","space=5"); + zdialog_add_widget(zd,"radio","radRGB","hbmetr","RGB","space=3"); + zdialog_add_widget(zd,"radio","radEV","hbmetr","EV","space=3"); + zdialog_add_widget(zd,"radio","radOD","hbmetr","OD","space=3"); + + if (RGBSmetric == 1) zdialog_stuff(zd,"radRGB",1); // get which metric to use + if (RGBSmetric == 2) zdialog_stuff(zd,"radEV",1); + if (RGBSmetric == 3) zdialog_stuff(zd,"radOD",1); + + zdialog_add_widget(zd,"vbox","vbdat","dialog"); // vbox for current pixel values + zdialog_add_widget(zd,"hbox","hbpix","vbdat"); + zdialog_add_widget(zd,"label","labheader","hbpix",header); // Pixel Red Green Blue + + zdialog_add_widget(zd,"hbox","hb1","vbdat"); + zdialog_add_widget(zd,"label","pix1","hb1"); // A xxxx yyyy rrr.r ggg.g bbb.b + zdialog_add_widget(zd,"hbox","hb2","vbdat"); + zdialog_add_widget(zd,"label","pix2","hb2"); + zdialog_add_widget(zd,"hbox","hb3","vbdat"); + zdialog_add_widget(zd,"label","pix3","hb3"); + zdialog_add_widget(zd,"hbox","hb4","vbdat"); + zdialog_add_widget(zd,"label","pix4","hb4"); + zdialog_add_widget(zd,"hbox","hb5","vbdat"); + zdialog_add_widget(zd,"label","pix5","hb5"); + + widget = zdialog_widget(zd,"labheader"); + gtk_widget_modify_font(widget,pfontdesc); // use monospace font + widget = zdialog_widget(zd,"pix1"); + gtk_widget_modify_font(widget,pfontdesc); + widget = zdialog_widget(zd,"pix2"); + gtk_widget_modify_font(widget,pfontdesc); + widget = zdialog_widget(zd,"pix3"); + gtk_widget_modify_font(widget,pfontdesc); + widget = zdialog_widget(zd,"pix4"); + gtk_widget_modify_font(widget,pfontdesc); + widget = zdialog_widget(zd,"pix5"); + gtk_widget_modify_font(widget,pfontdesc); + + zdialog_help(zd,"show_RGB"); // zdialog help topic v.11.08 + zdialog_run(zd,show_RGB_event,"save"); // run dialog + takeMouse(zd,show_RGB_mousefunc,dragcursor); // connect mouse function + g_timeout_add(300,show_RGB_timefunc,0); // start timer function, 300 ms + + return; +} + + +// dialog event function + +int show_RGB_event(zdialog *zd, cchar *event) +{ + int button, ii, px, py; + static char label[5][4] = { " A ", " B ", " C ", " D ", " E " }; + + if (zd->zstat) { + freeMouse(); // disconnect mouse function + zdialog_free(RGBSzd); // kill dialog + RGBSzd = 0; + erase_toptext(102); + mwpaint2(); + } + + if (strEqu(event,"focus")) // toggle mouse capture + takeMouse(zd,show_RGB_mousefunc,dragcursor); // connect mouse function + + if (strEqu(event,"delta")) { // set absolute/delta mode + zdialog_fetch(zd,"delta",RGBSdelta); + if (RGBSdelta && ! E3pxm16) { + RGBSdelta = 0; // block delta mode if no edit underway + zdialog_stuff(zd,"delta",0); // v.11.09 + } + } + + if (strEqu(event,"labels")) { // get labels on/off v.11.09 + zdialog_fetch(zd,"labels",RGBSlabels); + + erase_toptext(102); + + if (RGBSlabels) { // labels off to labels on + for (ii = 0; ii < RGBSnpix; ii++) // show pixel labels on image + { // v.11.08 + px = RGBSpixel[ii][0]; + py = RGBSpixel[ii][1]; + add_toptext(102,px,py,label[ii],"Sans 8"); + } + } + + mwpaint2(); + } + + if (strEqu(event,"radRGB")) { // metric = RGB + zdialog_fetch(zd,event,button); + if (button) RGBSmetric = 1; + } + + if (strEqu(event,"radEV")) { // metric = EV + zdialog_fetch(zd,event,button); + if (button) RGBSmetric = 2; + } + + if (strEqu(event,"radOD")) { // metric = OD + zdialog_fetch(zd,event,button); + if (button) RGBSmetric = 3; + } + + return 0; +} + + +// mouse function + +void show_RGB_mousefunc() // mouse function +{ + int ii, px, py; + static char label[5][4] = { " A ", " B ", " C ", " D ", " E " }; + + if (! LMclick) return; + + LMclick = 0; + RGBStime = get_seconds(); // mark time of pixel click + + if (RGBSnpix == 5) { // if all 5 positions filled, + for (ii = 1; ii < 5; ii++) { // remove first (oldest) and + RGBSpixel[ii-1][0] = RGBSpixel[ii][0]; // push the rest back + RGBSpixel[ii-1][1] = RGBSpixel[ii][1]; + } + RGBSnpix = 4; // position for newest + } + + ii = RGBSnpix; // next position to fill + RGBSpixel[ii][0] = Mxclick; // save newest pixel + RGBSpixel[ii][1] = Myclick; + RGBSnpix++; + + erase_toptext(102); + + if (RGBSlabels) { // v.11.09 + for (ii = 0; ii < RGBSnpix; ii++) // show pixel labels on image + { // v.11.08 + px = RGBSpixel[ii][0]; + py = RGBSpixel[ii][1]; + add_toptext(102,px,py,label[ii],"Sans 8"); + } + } + + mwpaint2(); + return; +} + + +// timer function - continuously display RGB values for selected pixels + +int show_RGB_timefunc(void *arg) // up to 5 pixels, live update +{ + int ii, px, py, delta; + double red1, green1, blue1; + double red3, green3, blue3; + char text[100], pixx[8] = "pixx"; + uint8 *ppix8; + uint16 *ppix16a, *ppix16b; + double c1 = 100.0 / 256.0; + + #define ODfunc(rgb) (2.0 - log10(c1 * rgb)) // RGB units (1-256) to OD units + #define EVfunc(rgb) (log2(rgb) - 7) // RGB units to EV (128 == 0 EV) + + if (! RGBSzd) return 1; // user quit, stop timer + if (! RGBSnpix) return 1; // no pixels clicked yet + + if (RGBSdelta && E3pxm16) delta = 1; // delta mode only if edit underway + else delta = 0; // v.11.08 + + red1 = green1 = blue1 = 0; + + if (curr_image_time > RGBStime) { // image time later than click time + RGBSnpix = 0; // data is no longer valid + erase_toptext(102); + mwpaint2(); + } + + for (ii = 0; ii < 5; ii++) // loop positons 0 to 4 + { + pixx[3] = '1' + ii; // widget names "pix1" ... "pix5" + + px = RGBSpixel[ii][0]; // next pixel to report + py = RGBSpixel[ii][1]; + if (ii >= RGBSnpix) { // no pixel there yet + zdialog_stuff(RGBSzd,pixx,""); // blank report line + continue; + } + + if (E3pxm16) { // use current image being edited + if (px < 0 || px > E3ww-1 || // outside image area + py < 0 || py > E3hh-1) return 1; + ppix16a = PXMpix(E3pxm16,px,py); + red3 = ppix16a[0] / 256.0; // "after" image E3 + green3 = ppix16a[1] / 256.0; + blue3 = ppix16a[2] / 256.0; + + if (delta) { // delta RGB for ongoing edited image + ppix16b = PXMpix(E1pxm16,px,py); // "before" image E1 + red1 = ppix16b[0] / 256.0; // v.11.08 + green1 = ppix16b[1] / 256.0; + blue1 = ppix16b[2] / 256.0; + } + } + + else if (Fpxm16) { // use finished edited image + if (px < 0 || px > Fww-1 || + py < 0 || py > Fhh-1) return 1; + ppix16a = PXMpix(Fpxm16,px,py); + red3 = ppix16a[0] / 256.0; + green3 = ppix16a[1] / 256.0; + blue3 = ppix16a[2] / 256.0; + } + + else { // use 8 bpc image + if (px < 0 || px > Fww-1 || + py < 0 || py > Fhh-1) return 1; + ppix8 = (uint8 *) Fpxm8->bmp + (py * Fww + px) * 3; + red3 = ppix8[0]; + green3 = ppix8[1]; + blue3 = ppix8[2]; + } + + sprintf(text," %c %4d %4d ",'A'+ii,px,py); // format pixel " A xxxx yyyy" + + if (RGBSmetric == 1) { // output RGB values + if (delta) { + red3 -= red1; // delta RGB + green3 -= green1; + blue3 -= blue1; + } + sprintf(text+12," %6.2f %6.2f %6.2f ",red3,green3,blue3); // xxx.xx + } + + if (RGBSmetric == 2) { // output EV values v.11.08 + red3 = EVfunc(red3); + green3 = EVfunc(green3); + blue3 = EVfunc(blue3); + if (delta) { + red3 -= EVfunc(red1); // delta EV + green3 -= EVfunc(green1); + blue3 -= EVfunc(blue1); + } + sprintf(text+12," %6.3f %6.3f %6.3f ",red3,green3,blue3); // x.xxx + } + + if (RGBSmetric == 3) { // output OD values v.11.08 + red3 = ODfunc(red3); + green3 = ODfunc(green3); + blue3 = ODfunc(blue3); + if (delta) { + red3 -= ODfunc(red1); // delta OD + green3 -= ODfunc(green1); + blue3 -= ODfunc(blue1); + } + sprintf(text+12," %6.3f %6.3f %6.3f ",red3,green3,blue3); // x.xxx + } + + zdialog_stuff(RGBSzd,pixx,text); // pixel and RGB values >> label + } + + return 1; +} + + +/**************************************************************************/ + +// setup x and y grid lines - count/spacing, enable/disable, offsets + +void m_gridlines(GtkWidget *, cchar *) +{ + int gridlines_dialog_event(zdialog *zd, cchar *event); + + zdialog *zd; + + zfuncs::F1_help_topic = "grid_lines"; // v.10.8 + + zd = zdialog_new(ZTX("Grid Lines"),mWin,Bdone,Bcancel,null); + + zdialog_add_widget(zd,"hbox","hb0","dialog",0,"space=10"); + zdialog_add_widget(zd,"vbox","vb1","hb0",0,"homog|space=5"); + zdialog_add_widget(zd,"vbox","vb2","hb0",0,"homog|space=5"); + zdialog_add_widget(zd,"vbox","vbspace","hb0",0,"homog|space=5"); + zdialog_add_widget(zd,"vbox","vb3","hb0",0,"homog|space=5"); + zdialog_add_widget(zd,"vbox","vb4","hb0",0,"homog|space=5"); + + zdialog_add_widget(zd,"label","lab1x","vb1",ZTX("x-spacing")); + zdialog_add_widget(zd,"label","lab2x","vb1",ZTX("x-count")); + zdialog_add_widget(zd,"label","lab4x","vb1",ZTX("x-enable")); + + zdialog_add_widget(zd,"spin","spacex","vb2","10|200|1|50"); + zdialog_add_widget(zd,"spin","countx","vb2","0|100|1|0"); + zdialog_add_widget(zd,"check","enablex","vb2",0); + + zdialog_add_widget(zd,"label","lab1y","vb3",ZTX("y-spacing")); + zdialog_add_widget(zd,"label","lab2y","vb3",ZTX("y-count")); + zdialog_add_widget(zd,"label","lab4y","vb3",ZTX("y-enable")); + + zdialog_add_widget(zd,"spin","spacey","vb4","10|200|1|50"); + zdialog_add_widget(zd,"spin","county","vb4","0|100|1|0"); + zdialog_add_widget(zd,"check","enabley","vb4",0); + + zdialog_add_widget(zd,"hbox","hboffx","dialog"); + zdialog_add_widget(zd,"label","lab3x","hboffx",ZTX("x-offset"),"space=7"); + zdialog_add_widget(zd,"hscale","offsetx","hboffx","-100|100|1|0","expand"); + + zdialog_add_widget(zd,"hbox","hboffy","dialog"); + zdialog_add_widget(zd,"label","lab3y","hboffy",ZTX("y-offset"),"space=7"); + zdialog_add_widget(zd,"hscale","offsety","hboffy","-100|100|1|0","expand"); + + zdialog_stuff(zd,"spacex",gridspace[0]); + zdialog_stuff(zd,"spacey",gridspace[1]); + zdialog_stuff(zd,"countx",gridcount[0]); + zdialog_stuff(zd,"county",gridcount[1]); + zdialog_stuff(zd,"offsetx",gridoffset[0]); + zdialog_stuff(zd,"offsety",gridoffset[1]); + zdialog_stuff(zd,"enablex",gridon[0]); + zdialog_stuff(zd,"enabley",gridon[1]); + + if (gridon[0] || gridon[1]) Fgrid = 1; + mwpaint2(); + + zdialog_help(zd,"grid_lines"); // zdialog help topic v.11.08 + zdialog_run(zd,gridlines_dialog_event); + zdialog_wait(zd); + return; +} + + +// dialog event function + +int gridlines_dialog_event(zdialog *zd, cchar *event) +{ + int zstat; + + if (zd->zstat) { + zstat = zd->zstat; + if (zstat != 1) Fgrid = gridon[0] = gridon[1] = 0; // cancel, grid lines off v.11.11 + zdialog_free(zd); + mwpaint2(); + return 0; + } + + if (strEqu(event,"enablex")) // x/y grid enable or disable + zdialog_fetch(zd,"enablex",gridon[0]); + + if (strEqu(event,"enabley")) + zdialog_fetch(zd,"enabley",gridon[1]); + + if (strEqu(event,"spacex")) // x/y grid spacing (if counts == 0) + zdialog_fetch(zd,"spacex",gridspace[0]); + + if (strEqu(event,"spacey")) + zdialog_fetch(zd,"spacey",gridspace[1]); + + if (strEqu(event,"countx")) // x/y grid line counts + zdialog_fetch(zd,"countx",gridcount[0]); + + if (strEqu(event,"county")) + zdialog_fetch(zd,"county",gridcount[1]); + + if (strEqu(event,"offsetx")) // x/y grid starting offsets + zdialog_fetch(zd,"offsetx",gridoffset[0]); + + if (strEqu(event,"offsety")) + zdialog_fetch(zd,"offsety",gridoffset[1]); + + if (gridon[0] || gridon[1]) Fgrid = 1; // if either grid enabled, show grid + else Fgrid = 0; + + mwpaint2(); + return 0; +} + + +// load or save grid settings from or to external int array + +void load_grid(int *griddata) // v.11.11 +{ + Fgrid = griddata[0]; + gridon[0] = griddata[1]; + gridon[1] = griddata[2]; + gridspace[0] = griddata[3]; + gridspace[1] = griddata[4]; + gridcount[0] = griddata[5]; + gridcount[1] = griddata[6]; + if (! gridcount[0] && ! gridspace[0]) gridcount[0] = 5; // if never set, use 5 lines + if (! gridcount[1] && ! gridspace[1]) gridcount[1] = 5; + mwpaint2(); + return; +} + +void save_grid(int *griddata) +{ + griddata[0] = Fgrid; + griddata[1] = gridon[0]; + griddata[2] = gridon[1]; + griddata[3] = gridspace[0]; + griddata[4] = gridspace[1]; + griddata[5] = gridcount[0]; + griddata[6] = gridcount[1]; + return; +} + + +// toggle grid lines on or off +// action: 0 = off, 1 = on, 2 = toggle: on > off, off > on + +void toggle_grid(int action) // v.11.11 +{ + if (action == 0) Fgrid = 0; // grid off + if (action == 1) Fgrid = 1; // grid on + if (action == 2) Fgrid = 1 - Fgrid; // toggle grid + + if (Fgrid && ! gridon[0] && ! gridon[1]) // if grid on and x/y both off, + gridon[0] = gridon[1] = 1; // set both grids on + + mwpaint2(); + return; +} + + +/**************************************************************************/ + +// burn images to CD/DVD + +void m_burn(GtkWidget *, cchar *) +{ + int ii, cc, err; + char **filelist, *imagefile, *bcommand; + + if (is_syncbusy()) return; // must wait for file sync v.11.11 + if (mod_keep()) return; // unsaved edits + if (! menulock(1)) return; // lock menus + + zfuncs::F1_help_topic = "burn"; // v.10.8 + + filelist = image_gallery_getfiles(0,mWin); // get list of files to burn v.10.9 + if (! filelist) { + menulock(0); + return; + } + + cc = 0; + for (ii = 0; filelist[ii]; ii++) // get memory for brasero command line + cc += strlen(filelist[ii]) + 4; + + bcommand = zmalloc(cc+20,"brasero"); + strcpy(bcommand,"brasero"); + cc = strlen(bcommand); + + for (ii = 0; filelist[ii]; ii++) // copy files to command line + { + imagefile = filelist[ii]; + strcpy(bcommand+cc," \""); + cc += 2; + strcpy(bcommand+cc,imagefile); + cc += strlen(imagefile); + strcpy(bcommand+cc,"\""); + cc += 1; + zfree(imagefile); + } + + zfree(filelist); + + strcat(bcommand," &"); // brasero command in background + err = system(bcommand); + if (err) zmessageACK(mWin,"error: %s",wstrerror(err)); + zfree(bcommand); + + menulock(0); + return; +} + + +/**************************************************************************/ + +// menu function +// resize selected images and send to preferred e-mail program + +void m_email(GtkWidget *, cchar *) // new v.10.10 +{ + int email_dialog_event(zdialog *zd, cchar *event); + + zdialog *zd; // email dialog + + zfuncs::F1_help_topic = "e-mail"; + + if (is_syncbusy()) return; // must wait for file sync v.11.11 + if (mod_keep()) return; // unsaved edits + if (! menulock(1)) return; // lock menus + + // [select files] N files selected + // max. width [____] + // max. height [____] + // + // [proceed] [cancel] + + zd = zdialog_new(ZTX("E-mail Images"),mWin,Bproceed,Bcancel,null); + zdialog_add_widget(zd,"hbox","hbf","dialog",0,"space=5"); + zdialog_add_widget(zd,"button","files","hbf",Bselectfiles,"space=5"); + zdialog_add_widget(zd,"label","fcount","hbf",ZTX("0 files selected"),"space=10"); + zdialog_add_widget(zd,"hbox","hbwh","dialog","space=10"); + zdialog_add_widget(zd,"vbox","vbwh1","hbwh",0,"homog|space=5"); + zdialog_add_widget(zd,"vbox","vbwh2","hbwh",0,"homog|space=5"); + zdialog_add_widget(zd,"label","labw","vbwh1",ZTX("max. width")); + zdialog_add_widget(zd,"label","labh","vbwh1",ZTX("max. height")); + zdialog_add_widget(zd,"entry","maxw","vbwh2","1000","scc=5"); + zdialog_add_widget(zd,"entry","maxh","vbwh2","700","scc=5"); + + zdialog_stuff(zd,"maxw",emailsize[0]); + zdialog_stuff(zd,"maxh",emailsize[1]); + + zdialog_help(zd,"e-mail"); // zdialog help topic v.11.08 + zdialog_run(zd,email_dialog_event); // run dialog + zdialog_wait(zd); // wait for completion + + menulock(0); + return; +} + + +// dialog event and completion callback function + +int email_dialog_event(zdialog *zd, cchar *event) +{ + static char **flist = 0; + char countmess[50], tempdir[100], sequence[8]; + int maxw, maxh, err, fcc, ww, hh; + int ii, jj, kk; + char *pfile, *pext, *oldfile, *newfile; + double scale, wscale, hscale; + PXM *pxmin, *pxmout; + + if (strEqu(event,"files")) // select images to resize + { + if (flist) { // free prior list + for (ii = 0; flist[ii]; ii++) + zfree(flist[ii]); + zfree(flist); + } + + flist = image_gallery_getfiles(0,mWin); // get list of files to resize v.10.9 + + if (flist) // count files selected + for (ii = 0; flist[ii]; ii++); + else ii = 0; + + snprintf(countmess,50,ZTX("%d files selected"),ii); // update dialog + zdialog_stuff(zd,"fcount",countmess); + } + + if (! zd->zstat) return 0; // dialog still busy + + if (zd->zstat != 1) goto cleanup; // dialog canceled + + if (! flist) { // no files selected + zd->zstat = 0; // keep dialog active + return 0; + } + + zdialog_fetch(zd,"maxw",maxw); // new max width + zdialog_fetch(zd,"maxh",maxh); // new max height + + if (maxw < 20 || maxh < 20) { + zmessageACK(mWin,ZTX("max. size %d x %d is not reasonable"),maxw,maxh); + zd->zstat = 0; + return 0; + } + + *tempdir = 0; // temp dirk: /tmp//fotoxx/email + strncatv(tempdir,99,"/tmp/",getenv("USER"),"/fotoxx/email",null); // v.11.09 + + sprintf(command,"mkdir -p %s",tempdir); // (re)create directory + err = system(command); + if (err) { + zmessageACK(mWin,"%s",strerror(err)); + goto cleanup; + } + + sprintf(command,"rm -f %s/*.jpg",tempdir); // purge prior file list + err = system(command); + + write_popup_text("open","preparing files",500,200,mWin); // status monitor popup window + + strcpy(command,"xdg-email"); // e-mail command: xdg-email + + for (ii = 0; flist[ii]; ii++) // loop selected files + { + oldfile = flist[ii]; + pfile = strrchr(oldfile,'/'); // /filename.ext + if (! pfile) continue; + + fcc = strlen(pfile); + newfile = strdupz(tempdir,fcc+10,"email"); // add extra space for .nn and .ext + strcat(newfile,pfile); // /tmp//fotoxx/filename.ext + pfile = strrchr(newfile,'/'); + + for (jj = kk = 1; pfile[jj]; jj++, kk++) // remove special characters + { // (xdg-email substitutes %nn + pfile[kk] = pfile[jj]; // and thunderbird falls over) + if (pfile[jj] < 0) continue; // UTF-8 multibyte characters OK + if (pfile[jj] == '.') continue; // periods OK + if (pfile[jj] >= 'a' && pfile[jj] <= 'z') continue; // keep a-z, A-Z, 0-9 + if (pfile[jj] >= 'A' && pfile[jj] <= 'Z') continue; + if (pfile[jj] >= '0' && pfile[jj] <= '9') continue; + kk--; // omit others + } + + pfile[kk] = 0; + + pext = strrchr(pfile,'.'); // find .ext if there is one + if (! pext) pext = pfile + strlen(pfile); + if (strlen(pext) > 5) pext = pext + strlen(pext); + + sprintf(sequence,"-%d",ii+1); // replace with sequence number + strcpy(pext,sequence); // filename-nn + + pext = pext + strlen(pext); // add .jpg extension + strcpy(pext,".jpg"); // filename-nn.jpg + + write_popup_text("write",newfile); // log progress + zmainloop(); + + pxmin = f_load(oldfile,8); // load image as PXM-8 pixmap + if (! pxmin) { + printf("f_load error: %s \n",oldfile); + continue; + } + + ww = pxmin->ww; + hh = pxmin->hh; + + wscale = hscale = 1.0; + if (ww > maxw) wscale = 1.0 * maxw / ww; // compute new size + if (hh > maxh) hscale = 1.0 * maxh / hh; + if (wscale < hscale) scale = wscale; + else scale = hscale; + ww = ww * scale; + hh = hh * scale; + pxmout = PXM_rescale(pxmin,ww,hh); // rescale file + + PXBwrite(pxmout,newfile); // write to new file + + PXM_free(pxmin); + PXM_free(pxmout); + + err = strncatv(command,1990," --attach ","\"",newfile,"\"",null); // --attach /tmp//fotoxx/file.jpg + zfree(newfile); + + if (err) { + zmessageACK(mWin,ZTX("too many files")); + goto cleanup; + } + } + + write_popup_text("write","COMPLETED"); + write_popup_text("close",0); + + emailsize[0] = maxw; // save preferred size + emailsize[1] = maxh; + + strcat(command," &"); // wait for email completion + printf("system: %s \n",command); + err = system(command); + +cleanup: + + if (flist) { // free memory + for (ii = 0; flist[ii]; ii++) + zfree(flist[ii]); + zfree(flist); + flist = 0; + } + + zdialog_free(zd); // kill dialog + return 0; +} + + +/**************************************************************************/ + +// monitor test function + +void m_moncheck(GtkWidget *, cchar *) +{ + uint8 *pixel; + int red, green, blue; + int row, col, row1, row2; + int ww = 800, hh = 500; + zdialog *zd; + + cchar *message = ZTX("Brightness should show a gradual ramp \n" + "extending all the way to the edges."); + + zfuncs::F1_help_topic = "check_monitor"; + + if (mod_keep()) return; // unsaved edits + if (! menulock(1)) return; + mutex_lock(&Fpixmap_lock); + + PXM_free(Fpxm8); + Fpxm8 = PXM_make(ww,hh,8); + Fww = ww; + Fhh = hh; + curr_file_bpc = 8; + curr_file_size = 0; + + for (red = 0; red <= 1; red++) // 8 RGB combinations + for (green = 0; green <= 1; green++) + for (blue = 0; blue <= 1; blue++) + { + row1 = 4 * red + 2 * green + blue; // row 0 to 7 + row1 = row1 * hh / 8; // stripe, 1/8 of image + row2 = row1 + hh / 8; + + for (row = row1; row < row2; row++) + for (col = 0; col < ww; col++) + { + pixel = PXMpix8(Fpxm8,col,row); + pixel[0] = red * 256 * col / ww; + pixel[1] = green * 256 * col / ww; + pixel[2] = blue * 256 * col / ww; + } + } + + Fzoom = 0; // scale to window + gtk_window_set_title(MWIN,"monitor check"); + mutex_unlock(&Fpixmap_lock); + mwpaint2(); // repaint window + curr_image_time = get_seconds(); // mark time of image change v.11.07 + + zd = zdialog_new(ZTX("Monitor Check"),mWin,Bdone,null); // start user dialog v.11.04 + zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=5"); + zdialog_add_widget(zd,"label","lab1","hb1",message,"space=5"); + + zdialog_resize(zd,200,0); + zdialog_help(zd,"check_monitor"); // zdialog help topic v.11.08 + zdialog_run(zd); + zdialog_wait(zd); // wait for dialog complete + zdialog_free(zd); + + f_open(curr_file,0); // back to current file v.11.04 + menulock(0); + return; +} + + +/**************************************************************************/ + +// adjust monitor gamma + +void m_mongamma(GtkWidget *, cchar *) // revised v.11.04 +{ + int mongamma_event(zdialog *zd, cchar *event); + char gammachart[200]; + + zdialog *zd; + cchar *permit = "Chart image courtesy of Norman Koren"; + cchar *website1 = "http://www.normankoren.com"; + cchar *website2 = "http://www.imatest.org"; + PXM *pxmtemp; + + zfuncs::F1_help_topic = "monitor_gamma"; + + if (mod_keep()) return; // unsaved edits + if (! menulock(1)) return; + + snprintf(gammachart,200,"%s/images/gammachart.png",get_zdocdir()); // gamma chart .png file + pxmtemp = PXBread(gammachart); + if (! pxmtemp) { + zmessageACK(mWin,"gamma chart is missing"); + menulock(0); + return; + } + + mutex_lock(&Fpixmap_lock); // curr. image = gamma chart + PXM_free(Fpxm8); + Fpxm8 = pxmtemp; + Fww = Fpxm8->ww; + Fhh = Fpxm8->hh; + curr_file_bpc = 8; + curr_file_size = 0; + + Fzoom = 1; // scale 100% (required) + gtk_window_set_title(MWIN,"adjust gamma chart"); + mutex_unlock(&Fpixmap_lock); + mwpaint2(); // repaint window + curr_image_time = get_seconds(); // mark time of image change v.11.07 + + zd = zdialog_new(ZTX("Monitor Gamma"),mWin,Bdone,null); // start user dialog + zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=8"); + zdialog_add_widget(zd,"label","labgamma","hb1","gamma","space=5"); + zdialog_add_widget(zd,"hscale","gamma","hb1","0.6|1.4|0.02|1.0","expand"); + zdialog_add_widget(zd,"hbox","hb2","dialog"); + zdialog_add_widget(zd,"label","permit","hb2",permit,"space=5"); + zdialog_add_widget(zd,"hbox","hb3","dialog"); + zdialog_add_widget(zd,"link","web1","hb3",website1); + zdialog_add_widget(zd,"hbox","hb4","dialog"); + zdialog_add_widget(zd,"link","web2","hb4",website2); + + zdialog_resize(zd,200,0); + zdialog_help(zd,"monitor_gamma"); // zdialog help topic v.11.08 + zdialog_run(zd,mongamma_event); + zdialog_wait(zd); // wait for dialog complete + zdialog_free(zd); + + f_open(curr_file,0); // back to current file v.11.04 + menulock(0); + return; +} + + +// dialog event function + +int mongamma_event(zdialog *zd, cchar *event) +{ + int err; + double gamma; + + if (strEqu(event,"gamma")) { + zdialog_fetch(zd,"gamma",gamma); + sprintf(command,"xgamma -quiet -gamma %.2f",gamma); + err = system(command); + if (err) zmessageACK(mWin,"error: %s",wstrerror(err)); + } + + return 0; +} + + +/**************************************************************************/ + +// create or update brightness histogram graph + +GtkWidget *winhisto = 0; // brightness histogram window +GtkWidget *winhistoH = 0; // histogram drawing area +GtkWidget *winhistoB = 0; // brightness band underneath + + +void m_histogram(GtkWidget *, cchar *menu) // menu function +{ + if (menu) zfuncs::F1_help_topic = "brightness_dist"; + + if (! Dpxm8) return; + + if (winhisto) { // window already present + histogram_paint(); + return; + } + + winhisto = gtk_window_new(GTK_WINDOW_TOPLEVEL); // create histogram window + gtk_window_set_title(GTK_WINDOW(winhisto),ZTX("Brightness Distribution")); + gtk_window_set_transient_for(GTK_WINDOW(winhisto),MWIN); + gtk_window_set_default_size(GTK_WINDOW(winhisto),300,200); + GtkWidget * vbox = gtk_vbox_new(0,3); + gtk_container_add(GTK_CONTAINER(winhisto),vbox); + + winhistoH = gtk_drawing_area_new(); // histogram drawing area + gtk_box_pack_start(GTK_BOX(vbox),winhistoH,1,1,3); + + winhistoB = gtk_drawing_area_new(); // brightness scale under histogram + gtk_box_pack_start(GTK_BOX(vbox),winhistoB,0,0,0); // (progresses from black to white) + gtk_widget_set_size_request(winhistoB,300,12); // v.9.3 + + G_SIGNAL(winhisto,"destroy",histogram_destroy,0); + G_SIGNAL(winhistoH,"expose-event",histogram_paint,0); + G_SIGNAL(winhistoB,"expose-event",histogram_paint,0); + + gtk_widget_show_all(winhisto); + + return; +} + + +void histogram_paint() // paint graph window +{ + GdkGC *gdkgc = 0; // GDK graphics context + GdkColor color; + GdkColormap *colormap = 0; + + int brdist[40], bin, nbins = 40; // increased v.9.3 + int dist_maxbin = 0; + int winww, winhh; + int px, py, ww, hh, orgx, orgy; + uint8 *pix8; + uint16 *pix16; + double bright; + + if (! winhisto) return; + if (! Dpxm8) return; + + gdkgc = gdk_gc_new(winhistoH->window); // use separate graphics context + colormap = gtk_widget_get_colormap(winhistoH); + + for (bin = 0; bin < nbins; bin++) // clear brightness distribution + brdist[bin] = 0; + + mutex_lock(&Fpixmap_lock); + + if (Factivearea && E3pxm16) // compute brightness distribution + { // for selected area being edited + for (int ii = 0; ii < Fww * Fhh; ii++) + { + if (! sa_pixmap[ii]) continue; + py = ii / Fww; + px = ii - Fww * py; + pix16 = PXMpix(E3pxm16,px,py); + bright = 0.003906 * pixbright(pix16); // 0 to 255 + brdist[int(bright / 256 * nbins)]++; // 0 to nbins + } + } + + else + { + for (py = 0; py < dhh; py++) // compute brightness distribution + for (px = 0; px < dww; px++) // for image in visible window + { + pix8 = (uint8 *) Dpxm8->bmp + (py * dww + px) * 3; + bright = pixbright(pix8); // 0 to 255 + brdist[int(bright / 256 * nbins)]++; // 0 to nbins + } + } + + for (bin = 0; bin < nbins; bin++) // find max. bin + if (brdist[bin] > dist_maxbin) dist_maxbin = brdist[bin]; + + mutex_unlock(&Fpixmap_lock); + + gdk_window_clear(winhistoH->window); + + winww = winhistoH->allocation.width; // drawing window size + winhh = winhistoH->allocation.height; + ww = winww / nbins; // bin width + bin = -1; + + color.red = 10000; // a pleasing color + color.green = 25000; + color.blue = 40000; + gdk_rgb_find_color(colormap,&color); + gdk_gc_set_foreground(gdkgc,&color); + + for (px = 0; px < winww; px++) // draw each bin + { + if (px * nbins / winww > bin) { + bin++; + hh = 0.9 * winhh * brdist[bin] / dist_maxbin; + orgx = px; + orgy = winhh - hh; + gdk_draw_rectangle(winhistoH->window,gdkgc,1,orgx,orgy,ww+1,hh); + } + } + + hh = winhistoB->allocation.height; + + for (px = 0; px < winww; px++) // draw brightness scale underneath + { // v.9.3 + color.red = color.green = color.blue = 65536 * px / winww; + gdk_rgb_find_color(colormap,&color); + gdk_gc_set_foreground(gdkgc,&color); + gdk_draw_line(winhistoB->window,gdkgc,px,0,px,hh-1); + } + + return; +} + + +void histogram_destroy() // delete window +{ + if (winhisto) gtk_widget_destroy(winhisto); + winhisto = 0; + return; +} + + +/**************************************************************************/ + +// set GUI language + +void m_lang(GtkWidget *, cchar *) // overhauled v.10.1 +{ + zdialog *zd; + int ii, cc, err, val, zstat; + char lang1[8], *pp; + + cchar *langs[12] = { "en English", "de German", "es Spanish", // english first + "fr French", "gl Galacian", "it Italian", + "nl Dutch", "pt Portuguese", "ru_RU Russian", + "sv Swedish", "zh_CN Chinese", null }; + + cchar *title = ZTX("Available Translations"); + + zfuncs::F1_help_topic = "language"; // v.10.8 + + zd = zdialog_new(ZTX("Set Language"),mWin,Bdone,Bcancel,null); + zdialog_add_widget(zd,"label","title","dialog",title,"space=10"); + zdialog_add_widget(zd,"hbox","hb1","dialog"); + zdialog_add_widget(zd,"vbox","vb1","hb1"); + + for (ii = 0; langs[ii]; ii++) // make radio button per language + zdialog_add_widget(zd,"radio",langs[ii],"vb1",langs[ii]); + + cc = strlen(zfuncs::zlang); // current language + for (ii = 0; langs[ii]; ii++) // match on lc_RC + if (strnEqu(zfuncs::zlang,langs[ii],cc)) break; + if (! langs[ii]) + for (ii = 0; langs[ii]; ii++) // failed, match on lc alone + if (strnEqu(zfuncs::zlang,langs[ii],2)) break; + if (! langs[ii]) ii = 0; // failed, default english + zdialog_stuff(zd,langs[ii],1); + + zdialog_resize(zd,200,0); + zdialog_help(zd,"language"); // zdialog help topic v.11.08 + zdialog_run(zd); // run dialog + zstat = zdialog_wait(zd); + + for (ii = 0; langs[ii]; ii++) { // get active radio button + zdialog_fetch(zd,langs[ii],val); + if (val) break; + } + + zdialog_free(zd); // kill dialog + + if (zstat != 1) return; // user cancel + if (! val) return; // no selection + + strncpy0(lang1,langs[ii],8); + pp = strchr(lang1,' '); // isolate lc_RC part + *pp = 0; + + sprintf(command,"fotoxx -l %s -p &",lang1); // start new fotoxx with language + err = system(command); + if (err) printf("error: %s \n",wstrerror(err)); + + m_quit(0,0); // exit + return; +} + + +/**************************************************************************/ + +// edit translations while running the application interactively + +void m_translate(GtkWidget *, cchar *) // new v.11.06 +{ + zfuncs::F1_help_topic = "translate"; + ZTX_translation_start(mWin); + return; +} + + +/**************************************************************************/ + +// create desktop icon / launcher + +void m_menu_launcher(GtkWidget *, cchar *) // v.11.08 +{ + char *command; + + zfuncs::F1_help_topic = "menu_launcher"; + command = zdialog_text(mWin,ZTX("Make Launcher"),"fotoxx -recent"); + if (! command || ! *command) return; // bugfix v.11.09 + zmake_menu_launcher(command,"Graphics","Image Editor"); + return; +} + + +/**************************************************************************/ + + +// user settings dialog + +void m_settings(GtkWidget *, cchar *) // v.12.01 +{ + int settings_dialog_event(zdialog *zd, cchar *event); + + zdialog *zd; + cchar *zooms[4] = { "1.1892071", "1.2599211", "1.4142136", "2.0" }; + double fzoom; + +/*** + Startup Display (o) Recent Files Gallery + (o) Previous Image Viewed + (o) Blank Window + (o) Directory Gallery + [__________________________] [browse] + (o) Image File + [__________________________] [browse] + + Toolbar Style (o) Text (o) Icons (o) Both + Warn Overwrite [x] + Panorama Params Lens mm [__|v] lens bow [__|v] + Zoom Ratio [___] + [done] +***/ + + zfuncs::F1_help_topic = "user_settings"; + + zd = zdialog_new(ZTX("Settings"),mWin,Bdone,null); + + zdialog_add_widget(zd,"hbox","space","dialog",0,"space=5"); + zdialog_add_widget(zd,"hbox","hbdisp","dialog",0,"space=5"); + zdialog_add_widget(zd,"vbox","vbdisp1","hbdisp",0,"space=5"); + zdialog_add_widget(zd,"label","labdisp","vbdisp1",ZTX("Startup Display")); + zdialog_add_widget(zd,"vbox","vbdisp2","hbdisp",0,"expand"); + zdialog_add_widget(zd,"radio","recent","vbdisp2",ZTX("Recent Files Gallery")); + zdialog_add_widget(zd,"radio","prev","vbdisp2",ZTX("Previous Image Viewed")); + zdialog_add_widget(zd,"radio","blank","vbdisp2",ZTX("Blank Window")); + + zdialog_add_widget(zd,"radio","dirk","vbdisp2",ZTX("Directory Gallery")); + zdialog_add_widget(zd,"hbox","hbstdirk","vbdisp2"); + zdialog_add_widget(zd,"entry","stdirk","hbstdirk",0,"expand|space=5"); + zdialog_add_widget(zd,"button","stdbrowse","hbstdirk",Bbrowse); + + zdialog_add_widget(zd,"radio","file","vbdisp2",ZTX("Image File")); + zdialog_add_widget(zd,"hbox","hbstfile","vbdisp2"); + zdialog_add_widget(zd,"entry","stfile","hbstfile",0,"expand|space=5"); + zdialog_add_widget(zd,"button","stfbrowse","hbstfile",Bbrowse); + + zdialog_add_widget(zd,"hbox","hbtbs","dialog",0,"space=2"); + zdialog_add_widget(zd,"label","labtbs","hbtbs",ZTX("Toolbar Style"),"space=5"); + zdialog_add_widget(zd,"radio","text","hbtbs",ZTX("Text"),"space=5"); + zdialog_add_widget(zd,"radio","icons","hbtbs",ZTX("Icons"),"space=5"); + zdialog_add_widget(zd,"radio","both","hbtbs",ZTX("Both"),"space=5"); + + zdialog_add_widget(zd,"hbox","hbwarn","dialog",0,"space=2"); + zdialog_add_widget(zd,"label","labwarn","hbwarn",ZTX("Warn Overwrite"),"space=5"); + zdialog_add_widget(zd,"check","warn","hbwarn",0); + + zdialog_add_widget(zd,"hbox","hbpano","dialog",0,"space=2"); + zdialog_add_widget(zd,"label","labpano","hbpano","Panorama","space=5"); + zdialog_add_widget(zd,"label","space","hbpano",0,"space=5"); + zdialog_add_widget(zd,"label","labmm","hbpano","lens mm","space=3"); + zdialog_add_widget(zd,"spin","lensmm","hbpano","20|999|0.1|30"); + zdialog_add_widget(zd,"label","space","hbpano",0,"space=5"); + zdialog_add_widget(zd,"label","labow","hbpano","lens bow","space=3"); + zdialog_add_widget(zd,"spin","lensbow","hbpano","-9.99|9.99|0.01|0"); + + zdialog_add_widget(zd,"hbox","hbzoom","dialog",0,"space=2"); + zdialog_add_widget(zd,"label","labzoom","hbzoom","Zoom Ratio","space=5"); + zdialog_add_widget(zd,"combo","zoom","hbzoom",0,"scc=8|space=5"); + + zdialog_stuff(zd,"stdirk",startdirk); // stuff present settings into dialog + zdialog_stuff(zd,"stfile",startfile); + + zdialog_stuff(zd,"recent",0); + zdialog_stuff(zd,"prev",0); + zdialog_stuff(zd,"blank",0); + zdialog_stuff(zd,"dirk",0); + zdialog_stuff(zd,"file",0); + zdialog_stuff(zd,startdisplay,1); + + zdialog_stuff(zd,"icons",0); + zdialog_stuff(zd,"text",0); + zdialog_stuff(zd,"both",0); + zdialog_stuff(zd,tbar_style,1); + + zdialog_stuff(zd,"warn",Fwarnoverwrite); + + zdialog_stuff(zd,"lensmm",lens_settings[0]); + zdialog_stuff(zd,"lensbow",lens_settings[1]); + + zdialog_cb_app(zd,"zoom",zooms[0]); // 4 zooms = 2x + zdialog_cb_app(zd,"zoom",zooms[1]); // 3 zooms = 2x + zdialog_cb_app(zd,"zoom",zooms[2]); // 2 zooms = 2x + zdialog_cb_app(zd,"zoom",zooms[3]); // 1 zoom = 2x + + convSD(zoomratio,fzoom); + if (fzoom < 1.2) zdialog_stuff(zd,"zoom",zooms[0]); + else if (fzoom < 1.3) zdialog_stuff(zd,"zoom",zooms[1]); + else if (fzoom < 1.5) zdialog_stuff(zd,"zoom",zooms[2]); + else zdialog_stuff(zd,"zoom",zooms[3]); + + zdialog_help(zd,"user_settings"); + zdialog_resize(zd,450,0); + + zdialog_run(zd,settings_dialog_event); // run dialog and wait for completion + zdialog_wait(zd); + zdialog_free(zd); + + return; +} + + +// settings dialog event function + +int settings_dialog_event(zdialog *zd, cchar *event) +{ + int nn; + char *pp, temp[200]; + + if (zd->zstat && zd->zstat != 1) return 0; // cancel + + if (zd->zstat == 1) // done, check inputs are valid + { + zdialog_fetch(zd,"stdirk",temp,200); // startup directory + if (*temp > ' ' && image_file_type(temp) != 1) { + zmessageACK(mWin,ZTX("startup directory is invalid")); + zd->zstat = 0; + return 0; + } + else { + if (startdirk) zfree(startdirk); + startdirk = strdupz(temp,0,"settings"); + } + + zdialog_fetch(zd,"stfile",temp,200); // startup file + if (*temp > ' ' && image_file_type(temp) != 2) { + zmessageACK(mWin,ZTX("startup file is invalid")); + zd->zstat = 0; + return 0; + } + else { + if (startfile) zfree(startfile); + startfile = strdupz(temp,0,"settings"); + } + + zdialog_fetch(zd,"recent",nn); // startup display + if (nn) startdisplay = "recent"; + + zdialog_fetch(zd,"prev",nn); + if (nn) startdisplay = "prev"; + + zdialog_fetch(zd,"blank",nn); + if (nn) startdisplay = "blank"; + + zdialog_fetch(zd,"dirk",nn); + if (nn) startdisplay = "dirk"; + + zdialog_fetch(zd,"file",nn); + if (nn) startdisplay = "file"; + + zdialog_fetch(zd,"text",nn); // toolbar style + if (nn) { + tbar_style = "text"; + gtk_toolbar_set_style(GTK_TOOLBAR(mTbar),GTK_TOOLBAR_TEXT); + } + + zdialog_fetch(zd,"icons",nn); + if (nn) { + tbar_style = "icons"; + gtk_toolbar_set_style(GTK_TOOLBAR(mTbar),GTK_TOOLBAR_ICONS); + } + + zdialog_fetch(zd,"both",nn); + if (nn) { + tbar_style = "both"; + gtk_toolbar_set_style(GTK_TOOLBAR(mTbar),GTK_TOOLBAR_BOTH); + } + + zdialog_fetch(zd,"warn",Fwarnoverwrite); // warn overwrite option + + zdialog_fetch(zd,"lensmm",lens_settings[0]); // pano lens parameters + zdialog_fetch(zd,"lensbow",lens_settings[1]); + + zdialog_fetch(zd,"zoom",temp,20); // zoom ratio + zfree((char *) zoomratio); + zoomratio = strdupz(temp); + + save_params(); + return 0; + } + + if (strEqu(event,"stdbrowse")) { // startup directory browse + zdialog_fetch(zd,"stdirk",temp,200); + pp = zgetfile1(ZTX("Select startup directory"),"folder",temp); + if (! pp) return 0; + zdialog_stuff(zd,"stdirk",pp); + zfree(pp); + } + + if (strEqu(event,"stfbrowse")) { // startup file browse + zdialog_fetch(zd,"stfile",temp,200); + pp = zgetfile1(ZTX("Select startup image file"),"open",temp); + if (! pp) return 0; + zdialog_stuff(zd,"stfile",pp); + zfree(pp); + } + + return 0; +} + + +/**************************************************************************/ + +// dump memory usage by category to STDOUT + +void m_memory_usage(GtkWidget *, cchar *) +{ + zfuncs::F1_help_topic = "memory_usage"; + zmalloc_report(); + return; +} + + + + + diff -Nru fotoxx-11.11.1/f.transform.cc fotoxx-12.01.2/f.transform.cc --- fotoxx-11.11.1/f.transform.cc 1970-01-01 00:00:00.000000000 +0000 +++ fotoxx-12.01.2/f.transform.cc 2012-01-04 08:47:11.000000000 +0000 @@ -0,0 +1,3947 @@ +/************************************************************************** + + Fotoxx edit photos and manage collections + + Copyright 2007 2008 2009 2010 2011 2012 Michael Cornelison + Source URL: http://kornelix.squarespace.com/fotoxx + Contact: kornelix2@googlemail.com + + 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 http://www.gnu.org/licenses/. + +***************************************************************************/ + +#define EX extern // enable extern declarations +#include "fotoxx.h" + + +/************************************************************************** + + Fotoxx image edit - transform functions + +***************************************************************************/ + + +// rotate image through any arbitrary angle + +double rotate_angle = 0; // E3 rotatation vs. F +double rotate_delta = 0; +int rotate_trim = 0; + +editfunc EFrotate; + + +void m_rotate(GtkWidget *, cchar *menu) // menu function +{ + int rotate_dialog_event(zdialog *zd, cchar *event); + void * rotate_thread(void *); + void rotate_mousefunc(); + + cchar *rotmess = ZTX("Use buttons or drag right edge with mouse"); + + zfuncs::F1_help_topic = "rotate"; // v.10.8 + + EFrotate.funcname = "rotate"; + EFrotate.Fprev = 1; // use preview + EFrotate.threadfunc = rotate_thread; // thread function + EFrotate.mousefunc = rotate_mousefunc; // mouse function + if (! edit_setup(EFrotate)) return; // setup edit + + zdialog *zd = zdialog_new(ZTX("Rotate Image"),mWin,Bdone,Bcancel,null); + EFrotate.zd = zd; + + zdialog_add_widget(zd,"label","labrot","dialog",ZTX(rotmess),"space=5"); + zdialog_add_widget(zd,"label","labdeg","dialog",ZTX("degrees"),"space=5"); + zdialog_add_widget(zd,"hbox","hb1","dialog",0,"homog|space=5"); + zdialog_add_widget(zd,"vbox","vb1","hb1",0,"space=5"); + zdialog_add_widget(zd,"vbox","vb2","hb1",0,"space=5"); + zdialog_add_widget(zd,"vbox","vb3","hb1",0,"space=5"); + zdialog_add_widget(zd,"vbox","vb4","hb1",0,"space=5"); + zdialog_add_widget(zd,"button"," +0.1 ","vb1"," + 0.1 "); // button name is increment to use + zdialog_add_widget(zd,"button"," -0.1 ","vb1"," - 0.1 "); + zdialog_add_widget(zd,"button"," +1.0 ","vb2"," + 1 "); + zdialog_add_widget(zd,"button"," -1.0 ","vb2"," - 1 "); + zdialog_add_widget(zd,"button"," +10.0 ","vb3"," + 10 "); + zdialog_add_widget(zd,"button"," -10.0 ","vb3"," - 10 "); + zdialog_add_widget(zd,"button"," +90.0 ","vb4"," + 90 "); + zdialog_add_widget(zd,"button"," -90.0 ","vb4"," - 90 "); + zdialog_add_widget(zd,"hbox","hb2","dialog",0,"space=10"); + zdialog_add_widget(zd,"label","space","hb2",0,"expand"); + zdialog_add_widget(zd,"button","trim","hb2",ZTX("Trim"),"space=10"); + zdialog_add_widget(zd,"button","grid","hb2",ZTX("Grid"),"space=10"); + + zdialog_help(zd,"rotate"); // zdialog help topic v.11.08 + zdialog_run(zd,rotate_dialog_event,"save"); // run dialog, parallel v.11.07 + + takeMouse(zd,rotate_mousefunc,dragcursor); // connect mouse function v.11.03 + rotate_angle = rotate_delta = rotate_trim = 0; + + load_grid(rotate_grid); // load grid preferences v.11.11 + + return; +} + + +// dialog event and completion callback function + +int rotate_dialog_event(zdialog *zd, cchar * event) +{ + int err, trim = 0; + double incr; + char text[40]; + + if (zd->zstat) // dialog complete + { + if (zd->zstat == 1) { + rotate_delta = rotate_angle; // rotate main image + rotate_angle = 0; + edit_done(EFrotate); + } + else edit_cancel(EFrotate); // canceled + + rotate_angle = rotate_delta = rotate_trim = 0; + + save_grid(rotate_grid); // save grid preferences v.11.11 + Fgrid = 0; // grid off + + mwpaint2(); + return 0; + } + + if (strEqu(event,"trim")) { + rotate_trim = 1 - rotate_trim; // toggle trim button + if (rotate_trim) zdialog_stuff(zd,"trim",ZTX("Undo Trim")); + else zdialog_stuff(zd,"trim",ZTX("Trim")); + trim = 1; // v.10.3 + } + + if (strpbrk(event,"+-")) { + err = convSD(event,incr); // button name is increment to use + if (err) return 0; + rotate_delta += incr; + } + + if (rotate_delta || trim) { + trim = 0; + zdialog_stuff(zd,"labdeg","computing"); + signal_thread(); // do rotate in thread + wait_thread_idle(); + snprintf(text,40,ZTX("degrees: %.1f"),rotate_angle); // update dialog angle display v.11.08 + zdialog_stuff(zd,"labdeg",text); + } + + if (strEqu(event,"grid")) m_gridlines(0,0); // grid dialog v.11.11 + + if (strstr("KB G KB g",event)) // G key, toggle grid v.11.11 + toggle_grid(2); + + return 1; +} + + +// rotate mouse function - drag right edge of image up/down for rotation + +void rotate_mousefunc() +{ + static int mpx0 = 0, mpy0 = 0; + static int mpy1, mpy2, dist; + zdialog *zd = EFrotate.zd; + + if (! Mxdrag && ! Mydrag) return; // no drag underway + if (Mxdrag < 0.8 * E3ww) return; // not right edge of image + + if (Mxdown != mpx0 || Mydown != mpy0) { + mpx0 = Mxdown; // new drag started + mpy0 = mpy1 = Mydown; + } + + mpy2 = Mydrag; + dist = mpy2 - mpy1; // drag distance + mpy1 = mpy2; // reset origin for next time + if (! dist) return; + + rotate_delta = 30.0 * dist / E3ww; // convert to angle + rotate_dialog_event(zd,"mouse"); + return; +} + + +// rotate thread function + +void * rotate_thread(void *) +{ + int px3, py3, px9, py9; + int wwcut, hhcut, ww, hh; + double trim_angle, radians; + uint16 *pix3, *pix9; + + while (true) + { + thread_idle_loop(); // wait for work or exit request + + mutex_lock(&Fpixmap_lock); + + rotate_angle += rotate_delta; // accum. net rotation + rotate_delta = 0; // from dialog widget + + if (rotate_angle >= 360) rotate_angle -=360; + if (rotate_angle <= -360) rotate_angle +=360; + if (fabs(rotate_angle) < 0.01) rotate_angle = 0; + + if (! rotate_angle) { + PXM_free(E3pxm16); // E1 >> E3 + E3pxm16 = PXM_copy(E1pxm16); + E3ww = E1ww; + E3hh = E1hh; + CEF->Fmod = 0; + } + + if (rotate_angle) { + PXM_free(E3pxm16); + E3pxm16 = PXM_rotate(E1pxm16,rotate_angle); // E3 is rotated E1 + E3ww = E3pxm16->ww; + E3hh = E3pxm16->hh; + CEF->Fmod = 1; + } + + if (rotate_trim) + { // auto trim + trim_angle = fabs(rotate_angle); + while (trim_angle > 45) trim_angle -= 90; + radians = fabs(trim_angle / 57.296); + wwcut = int(E3pxm16->hh * sin(radians) + 1); // amount to trim + hhcut = int(E3pxm16->ww * sin(radians) + 1); + ww = E3pxm16->ww - 2 * wwcut; + hh = E3pxm16->hh - 2 * hhcut; + if (ww > 0 && hh > 0) { + E9pxm16 = PXM_make(ww,hh,16); + + for (py3 = hhcut; py3 < E3hh-hhcut; py3++) // E9 = trimmed E3 + for (px3 = wwcut; px3 < E3ww-wwcut; px3++) + { + px9 = px3 - wwcut; + py9 = py3 - hhcut; + pix3 = PXMpix(E3pxm16,px3,py3); + pix9 = PXMpix(E9pxm16,px9,py9); + pix9[0] = pix3[0]; + pix9[1] = pix3[1]; + pix9[2] = pix3[2]; + } + + PXM_free(E3pxm16); // E3 = E9 + E3pxm16 = E9pxm16; + E9pxm16 = 0; + E3ww = ww; + E3hh = hh; + } + } + + mutex_unlock(&Fpixmap_lock); + mwpaint2(); // update window + } + + return 0; // not executed, stop g++ warning +} + + +/**************************************************************************/ + +// trim image - use mouse to select image region to retain + +int trimx1, trimy1, trimx2, trimy2; // current trim rectangle +int trimpx1, trimpy1, trimpx2, trimpy2; // prior trim rectangle +double trimR; // trim ratio, width/height + +void trim_mousefunc(); // edit trim margins with mouse +void trim_dialog(); +void trim_trim(int mode); // show trim area, trim image + +editfunc EFtrim; + + +void m_trim(GtkWidget *, cchar *menu) +{ + zfuncs::F1_help_topic = "trim_image"; // v.10.8 + + EFtrim.funcname = "trim"; + EFtrim.mousefunc = trim_mousefunc; + if (! edit_setup(EFtrim)) return; // setup edit + + if (! trimbuttons[0] || strEqu(trimbuttons[0],"undefined")) { + trimbuttons[0] = strdupz("1:1",8); // default trim buttons v.10.10.2 + trimbuttons[1] = strdupz("2:1",8); + trimbuttons[2] = strdupz("3:2",8); + trimbuttons[3] = strdupz("4:3",8); + trimbuttons[4] = strdupz("16:9",8); + trimbuttons[5] = strdupz(ZTX("gold"),8); + + trimratios[0] = strdupz("1:1",8); // default trim ratios v.10.10.2 + trimratios[1] = strdupz("2:1",8); + trimratios[2] = strdupz("3:2",8); + trimratios[3] = strdupz("4:3",8); + trimratios[4] = strdupz("16:9",8); + trimratios[5] = strdupz("1.618:1",8); // fix inverted ratio v.10.10.3 + } + + if (strNeq(menu,"autotrim")) // if not auto-trim v.11.12 + { + if (trimsize[0] < iww && trimsize[1] < ihh) { // use last trim size if within limits + trimx1 = Iorgx + 0.5 * (iww - trimsize[0]); // v.11.12 + trimx2 = trimx1 + trimsize[0]; + trimy1 = Iorgy + 0.5 * (ihh - trimsize[1]); + trimy2 = trimy1 + trimsize[1]; + } + else { // else use 90% current dimensions + trimx1 = Iorgx + 0.05 * iww; + trimx2 = Iorgx + 0.95 * iww; + trimy1 = Iorgy + 0.05 * ihh; + trimy2 = Iorgy + 0.95 * ihh; + } + } + + trimpx1 = Iorgx; // prior trim rectangle + trimpx2 = Iorgx + iww; // = 100% of image + trimpy1 = Iorgy; + trimpy2 = Iorgy + ihh; + + trimsize[0] = (trimx2 - trimx1); + trimsize[1] = (trimy2 - trimy1); + trimR = 1.0 * trimsize[0] / trimsize[1]; + + trim_trim(0); // show trim area in image + trim_dialog(); // start dialog + + return; +} + + +// dialog function is called from two places + +void trim_dialog() +{ + int trim_dialog_event(zdialog *zd, cchar *event); + + cchar *trim_message = ZTX("Drag middle to move, drag corners to resize."); + char text[20]; + int ii; + +/** + Drag middle to move, drag corners to resize + + width [___] height [___] ratio [___] // width/height inputs v.11.05 + [1:1] [2:1] [3:2] [4:3] [16:9] [gold] [invert] + [x] Lock Ratio + + [customize] [Done] [Cancel] +**/ + + zdialog *zd = zdialog_new(ZTX("Trim Image"),mWin,ZTX("customize"),Bdone,Bcancel,null); + EFtrim.zd = zd; + + zdialog_add_widget(zd,"label","lab1","dialog",trim_message,"space=8"); + zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=4"); + zdialog_add_widget(zd,"label","labW","hb1",ZTX("width"),"space=3"); + zdialog_add_widget(zd,"spin","width","hb1","20|9999|1|1000"); + zdialog_add_widget(zd,"label","space","hb1",0,"space=5"); + zdialog_add_widget(zd,"label","labH","hb1",ZTX("height"),"space=3"); + zdialog_add_widget(zd,"spin","height","hb1","20|9999|1|600"); + zdialog_add_widget(zd,"label","space","hb1",0,"space=5"); + zdialog_add_widget(zd,"label","labR","hb1",ZTX("ratio"),"space=3"); + zdialog_add_widget(zd,"label","ratio","hb1","1.67 "); + zdialog_add_widget(zd,"hbox","hb2","dialog",0,"space=4"); // ratio buttons + zdialog_add_widget(zd,"hbox","hb3","dialog",0,"space=4"); + zdialog_add_widget(zd,"check","lock","hb3",ZTX("Lock Ratio"),"space=3"); + + for (ii = 0; ii < 6; ii++) // 6 custom buttons v.10.10.2 + zdialog_add_widget(zd,"button",trimbuttons[ii],"hb2",trimbuttons[ii]); + + zdialog_add_widget(zd,"button","invert","hb2",ZTX("invert")); // [invert] button + + zdialog_stuff(zd,"width",trimsize[0]); // stuff width, height, ratio v.11.05 + zdialog_stuff(zd,"height",trimsize[1]); + sprintf(text,"%.2f ",trimR); + zdialog_stuff(zd,"ratio",text); + + zdialog_help(zd,"trim_image"); // zdialog help topic v.11.08 + zdialog_run(zd,trim_dialog_event,"save"); // run dialog - parallel v.11.07 + takeMouse(zd,trim_mousefunc,dragcursor); // connect mouse function v.11.12 + return; +} + + +// dialog event and completion callback function + +int trim_dialog_event(zdialog *zd, cchar *event) // overhauled v.11.05 +{ + void trim_customize(); + + static int flip = 0; + int width, height, delta; + int ii, rlock; + double r1, r2, ratio = 0; + char text[20]; + cchar *pp; + + if (zd->zstat) // dialog complete + { + paint_toplines(2); // erase rectangle outline v.11.05 + + if (zd->zstat == 1) { // customize buttons + freeMouse(); // bugfix v.11.12 + zdialog_free(zd); // kill trim dialog + trim_customize(); // do customize dialog + trim_trim(0); // show trim area in image v.11.05 + trim_dialog(); // restart trim dialog + return 0; + } + + if (zd->zstat != 2) { // cancel + edit_cancel(EFtrim); + return 0; + } + + trimsize[0] = trimx2 - trimx1; // apply + trimsize[1] = trimy2 - trimy1; + + trim_trim(1); // do trim on image + Fzoom = 0; // v.11.01 + edit_done(EFtrim); + return 0; + } + + if (strEqu(event,"focus")) { + takeMouse(zd,trim_mousefunc,dragcursor); // connect mouse function v.12.01 + return 0; + } + + if (strstr("width height",event)) // get direct width/height inputs + { // v.11.05 + zdialog_fetch(zd,"width",width); + zdialog_fetch(zd,"height",height); + zdialog_fetch(zd,"lock",rlock); // lock ratio on/off + + + if (strEqu(event,"width")) { // v.11.05 + if (width > iww) width = iww; + if (rlock) { // ratio locked + height = width / trimR + 0.5; // try to keep ratio + if (height > ihh) height = ihh; + zdialog_stuff(zd,"height",height); + } + } + + if (strEqu(event,"height")) { + if (height > ihh) height = ihh; + if (rlock) { + width = height * trimR + 0.5; + if (width > iww) width = iww; + zdialog_stuff(zd,"width",width); + } + } + + flip = 1 - flip; // alternates 0, 1, 0, 1 ... + + delta = width - trimsize[0]; + + if (delta > 0) { // increase width + trimx1 = trimx1 - delta / 2; // left and right sides equally + trimx2 = trimx2 + delta / 2; + if (delta % 2) { // if increase is odd + trimx1 = trimx1 - flip; // add 1 alternatively to each side + trimx2 = trimx2 + 1 - flip; + } + } + + if (delta < 0) { // decrease width + trimx1 = trimx1 - delta / 2; + trimx2 = trimx2 + delta / 2; + if (delta % 2) { + trimx1 = trimx1 + flip; + trimx2 = trimx2 - 1 + flip; + } + } + + delta = height - trimsize[1]; + + if (delta > 0) { // increase width + trimy1 = trimy1 - delta / 2; // left and right sides equally + trimy2 = trimy2 + delta / 2; + if (delta % 2) { // if increase is odd + trimy1 = trimy1 - flip; // add 1 alternatively to each side + trimy2 = trimy2 + 1 - flip; + } + } + + if (delta < 0) { // decrease width + trimy1 = trimy1 - delta / 2; + trimy2 = trimy2 + delta / 2; + if (delta % 2) { + trimy1 = trimy1 + flip; + trimy2 = trimy2 - 1 + flip; + } + } + + if (trimx1 < Iorgx) trimx1 = Iorgx; + if (trimx2 > Iorgx + iww) trimx2 = Iorgx + iww; + if (trimy1 < Iorgy) trimy1 = Iorgy; + if (trimy2 > Iorgy + ihh) trimy2 = Iorgy + ihh; + + width = trimx2 - trimx1; // new width and height + height = trimy2 - trimy1; + + zdialog_stuff(zd,"width",width); // update dialog values + zdialog_stuff(zd,"height",height); + + trimsize[0] = width; // new rectangle dimensions + trimsize[1] = height; + + if (! rlock) // set new ratio if not locked + trimR = 1.0 * trimsize[0] / trimsize[1]; + + sprintf(text,"%.2f ",trimR); // stuff new ratio + zdialog_stuff(zd,"ratio",text); + + trim_trim(0); // show trim area in image + return 0; + } + + for (ii = 0; ii < 6; ii++) // trim ratio buttons + if (strEqu(event,trimbuttons[ii])) break; + if (ii < 6) { + r1 = r2 = ratio = 0; + pp = strField(trimratios[ii],':',1); + if (pp) r1 = atof(pp); + pp = strField(trimratios[ii],':',2); + if (pp) r2 = atof(pp); + if (r1 > 0 && r2 > 0) ratio = r1/r2; + if (ratio < 0.1 || ratio > 10) ratio = 1.0; + if (! ratio) return 0; + zdialog_stuff(zd,"lock",1); // assume lock is wanted + trimR = ratio; + } + + if (strEqu(event,"invert")) // invert ratio button + if (trimR) ratio = 1.0 / trimR; + + if (ratio) // ratio was changed + { + trimR = ratio; + + if (trimx2 - trimx1 > trimy2 - trimy1) + trimy2 = trimy1 + (trimx2 - trimx1) / trimR; // adjust smaller dimension + else + trimx2 = trimx1 + (trimy2 - trimy1) * trimR; + + if (trimx2 > Iorgx + iww) { // if off the right edge, + trimx2 = Iorgx + iww; // adjust height + trimy2 = trimy1 + (trimx2 - trimx1) / trimR; + } + + if (trimy2 > Iorgy + ihh) { // if off the bottom edge, + trimy2 = Iorgy + ihh; // adjust width + trimx2 = trimx1 + (trimy2 - trimy1) * trimR; + } + + trimsize[0] = trimx2 - trimx1; // new rectangle dimensions + trimsize[1] = trimy2 - trimy1; + + zdialog_stuff(zd,"width",trimsize[0]); // stuff width, height, ratio v.11.05 + zdialog_stuff(zd,"height",trimsize[1]); + sprintf(text,"%.2f ",trimR); + zdialog_stuff(zd,"ratio",text); + + trim_trim(0); // show trim area in image + return 0; + } + + return 0; +} + + +// trim mouse function + +void trim_mousefunc() +{ + int mpx, mpy, xdrag, ydrag, rlock; + int corner, chop, moveall = 0; + int dx, dy, dd, d1, d2, d3, d4; + char text[20]; + double drr; + zdialog *zd = EFtrim.zd; + + if (LMclick || Mxdrag || Mydrag) // mouse click or drag + { + if (LMclick) { + mpx = Mxclick; // click + mpy = Myclick; + xdrag = ydrag = 0; + LMclick = 0; + } + else { + mpx = Mxdrag; // drag + mpy = Mydrag; + xdrag = Mxdrag - Mxdown; + ydrag = Mydrag - Mydown; + Mxdown = Mxdrag; // reset drag origin + Mydown = Mydrag; + } + + if (Mxdrag || Mydrag) { + moveall = 1; + dd = 0.1 * (trimx2 - trimx1); // test if mouse is in the broad + if (mpx < trimx1 + dd) moveall = 0; // middle of the rectangle + if (mpx > trimx2 - dd) moveall = 0; + dd = 0.1 * (trimy2 - trimy1); + if (mpy < trimy1 + dd) moveall = 0; + if (mpy > trimy2 - dd) moveall = 0; + } + + if (moveall) { // yes, move the whole rectangle + trimx1 += xdrag; + trimx2 += xdrag; + trimy1 += ydrag; + trimy2 += ydrag; + corner = 0; + } + + else { // no, find closest corner + dx = mpx - trimx1; + dy = mpy - trimy1; + d1 = sqrt(dx*dx + dy*dy); // distance from NW corner + + dx = mpx - trimx2; + dy = mpy - trimy1; + d2 = sqrt(dx*dx + dy*dy); + + dx = mpx - trimx2; + dy = mpy - trimy2; + d3 = sqrt(dx*dx + dy*dy); + + dx = mpx - trimx1; + dy = mpy - trimy2; + d4 = sqrt(dx*dx + dy*dy); + + corner = 1; // NW + dd = d1; + if (d2 < dd) { corner = 2; dd = d2; } // NE + if (d3 < dd) { corner = 3; dd = d3; } // SE + if (d4 < dd) { corner = 4; dd = d4; } // SW + + if (corner == 1) { trimx1 = mpx; trimy1 = mpy; } // move this corner to mouse + if (corner == 2) { trimx2 = mpx; trimy1 = mpy; } + if (corner == 3) { trimx2 = mpx; trimy2 = mpy; } + if (corner == 4) { trimx1 = mpx; trimy2 = mpy; } + } + + if (trimx1 < Iorgx) trimx1 = Iorgx; // keep within visible area v.11.05 + if (trimx2 > Iorgx + iww) trimx2 = Iorgx + iww; + if (trimy1 < Iorgy) trimy1 = Iorgy; + if (trimy2 > Iorgy + ihh) trimy2 = Iorgy + ihh; + + if (trimx1 > trimx2-10) trimx1 = trimx2-10; // sanity limits + if (trimy1 > trimy2-10) trimy1 = trimy2-10; + + zdialog_fetch(zd,"lock",rlock); // w/h ratio locked + if (rlock && corner) { + if (corner < 3) // bugfix v.10.3.1 + trimy2 = trimy1 + 1.0 * (trimx2 - trimx1) / trimR; + else + trimy1 = trimy2 - 1.0 * (trimx2 - trimx1) / trimR; + } + + chop = 0; + if (trimx1 < Iorgx) { // look for off the edge v.10.1 + trimx1 = Iorgx; + chop = 1; + } + + if (trimx2 > Iorgx + iww) { // after corner move v.10.3.1 + trimx2 = Iorgx + iww; + chop = 2; + } + + if (trimy1 < Iorgy) { + trimy1 = Iorgy; + chop = 3; + } + + if (trimy2 > Iorgy + ihh) { + trimy2 = Iorgy + ihh; + chop = 4; + } + + if (rlock && chop) { // keep ratio if off edge v.10.1 + if (chop < 3) + trimy2 = trimy1 + 1.0 * (trimx2 - trimx1) / trimR; + else + trimx2 = trimx1 + 1.0 * (trimy2 - trimy1) * trimR; + } + + if (trimx1 > trimx2-10) trimx1 = trimx2-10; // sanity limits + if (trimy1 > trimy2-10) trimy1 = trimy2-10; + + if (trimx1 < Iorgx) trimx1 = Iorgx; // keep within visible area v.11.05 + if (trimx2 > Iorgx + iww) trimx2 = Iorgx + iww; + if (trimy1 < Iorgy) trimy1 = Iorgy; + if (trimy2 > Iorgy + ihh) trimy2 = Iorgy + ihh; + + trimsize[0] = trimx2 - trimx1; // new rectangle dimensions + trimsize[1] = trimy2 - trimy1; + + drr = 1.0 * trimsize[0] / trimsize[1]; // new w/h ratio + if (! rlock) trimR = drr; + + zdialog_stuff(zd,"width",trimsize[0]); // stuff width, height, ratio v.11.05 + zdialog_stuff(zd,"height",trimsize[1]); + sprintf(text,"%.2f ",trimR); + zdialog_stuff(zd,"ratio",text); + + trim_trim(0); // show trim area in image + } + + return; +} + + +// darken image pixels outside of current trim margins +// messy logic: update pixmaps only for changed pixels to increase speed + +void trim_trim(int mode) +{ + int ox1, oy1, ox2, oy2; // outer trim rectangle + int nx1, ny1, nx2, ny2; // inner trim rectangle + int px, py, px1, py1, px2, py2; + uint16 *pix1, *pix3; + + if (mode == 1) // do the final trim + { + mutex_lock(&Fpixmap_lock); + PXM_free(E3pxm16); + E3pxm16 = PXM_make(trimsize[0],trimsize[1],16); // new pixmap with requested size + E3ww = trimsize[0]; + E3hh = trimsize[1]; + + for (py1 = trimy1; py1 < trimy2; py1++) // copy pixels + for (px1 = trimx1; px1 < trimx2; px1++) + { + px2 = px1 - trimx1; + py2 = py1 - trimy1; + pix1 = PXMpix(E1pxm16,px1,py1); + pix3 = PXMpix(E3pxm16,px2,py2); + pix3[0] = pix1[0]; + pix3[1] = pix1[1]; + pix3[2] = pix1[2]; + } + + CEF->Fmod = 1; + mutex_unlock(&Fpixmap_lock); + mwpaint2(); // update window + return; + } + + if (trimx1 < Iorgx) trimx1 = Iorgx; // keep within visible area v.11.05 + if (trimx2 > Iorgx + iww) trimx2 = Iorgx + iww; + if (trimy1 < Iorgy) trimy1 = Iorgy; + if (trimy2 > Iorgy + ihh) trimy2 = Iorgy + ihh; + + if (trimpx1 < trimx1) ox1 = trimpx1; // outer rectangle + else ox1 = trimx1; + if (trimpx2 > trimx2) ox2 = trimpx2; + else ox2 = trimx2; + if (trimpy1 < trimy1) oy1 = trimpy1; + else oy1 = trimy1; + if (trimpy2 > trimy2) oy2 = trimpy2; + else oy2 = trimy2; + + if (trimpx1 > trimx1) nx1 = trimpx1; // inner rectangle + else nx1 = trimx1; + if (trimpx2 < trimx2) nx2 = trimpx2; + else nx2 = trimx2; + if (trimpy1 > trimy1) ny1 = trimpy1; + else ny1 = trimy1; + if (trimpy2 < trimy2) ny2 = trimpy2; + else ny2 = trimy2; + + trimpx1 = trimx1; // set prior trim rectangle + trimpx2 = trimx2; // from current trim rectangle + trimpy1 = trimy1; + trimpy2 = trimy2; + + if (ox1 > 0) ox1--; + if (ox2 < E3ww-1) ox2++; + if (oy1 > 0) oy1--; + if (oy2 < E3hh-1) oy2++; + + for (py = oy1; py < ny1; py++) // top band of pixels + for (px = ox1; px < ox2; px++) + { + pix1 = PXMpix(E1pxm16,px,py); + pix3 = PXMpix(E3pxm16,px,py); + if (px < trimx1 || px > trimx2 || py < trimy1 || py > trimy2) { + pix3[0] = pix1[0] / 2; // outside trim margins + pix3[1] = pix1[1] / 2; // 50% brightness + pix3[2] = pix1[2] / 2; + } + else { + pix3[0] = pix1[0]; // inside trim margins + pix3[1] = pix1[1]; // 100% brightness + pix3[2] = pix1[2]; + } + } + + for (py = oy1; py < oy2; py++) // right band + for (px = nx2; px < ox2; px++) + { + pix1 = PXMpix(E1pxm16,px,py); + pix3 = PXMpix(E3pxm16,px,py); + if (px < trimx1 || px > trimx2 || py < trimy1 || py > trimy2) { + pix3[0] = pix1[0] / 2; + pix3[1] = pix1[1] / 2; + pix3[2] = pix1[2] / 2; + } + else { + pix3[0] = pix1[0]; + pix3[1] = pix1[1]; + pix3[2] = pix1[2]; + } + } + + for (py = ny2; py < oy2; py++) // bottom band + for (px = ox1; px < ox2; px++) + { + pix1 = PXMpix(E1pxm16,px,py); + pix3 = PXMpix(E3pxm16,px,py); + if (px < trimx1 || px > trimx2 || py < trimy1 || py > trimy2) { + pix3[0] = pix1[0] / 2; + pix3[1] = pix1[1] / 2; + pix3[2] = pix1[2] / 2; + } + else { + pix3[0] = pix1[0]; + pix3[1] = pix1[1]; + pix3[2] = pix1[2]; + } + } + + for (py = oy1; py < oy2; py++) // left band + for (px = ox1; px < nx1; px++) + { + pix1 = PXMpix(E1pxm16,px,py); + pix3 = PXMpix(E3pxm16,px,py); + if (px < trimx1 || px > trimx2 || py < trimy1 || py > trimy2) { + pix3[0] = pix1[0] / 2; + pix3[1] = pix1[1] / 2; + pix3[2] = pix1[2] / 2; + } + else { + pix3[0] = pix1[0]; + pix3[1] = pix1[1]; + pix3[2] = pix1[2]; + } + } + + mwpaint3(ox1,oy1,ox2-ox1+1,ny1-oy1+1); // 4 updated rectangles + mwpaint3(nx2,oy1,ox2-nx2+1,oy2-oy1+1); // ww+1, hh+1 v.11.05 + mwpaint3(ox1,ny2,ox2-ox1+1,oy2-ny2+1); + mwpaint3(ox1,oy1,nx1-ox1+1,oy2-oy1+1); + + Ntoplines = 4; // outline trim rectangle v.11.05 + toplinex1[0] = trimx1; + topliney1[0] = trimy1; + toplinex2[0] = trimx2; + topliney2[0] = trimy1; + toplinex1[1] = trimx2; + topliney1[1] = trimy1; + toplinex2[1] = trimx2; + topliney2[1] = trimy2; + toplinex1[2] = trimx2; + topliney1[2] = trimy2; + toplinex2[2] = trimx1; + topliney2[2] = trimy2; + toplinex1[3] = trimx1; + topliney1[3] = trimy2; + toplinex2[3] = trimx1; + topliney2[3] = trimy1; + paint_toplines(1); + + return; +} + + +// dialog to get custom trim button names and corresponding ratios + +void trim_customize() +{ + char text[20], blab[8], rlab[8]; + double r1, r2, ratio; + cchar *pp; + int ii, zstat; + + zdialog *zd = zdialog_new(ZTX("Trim Buttons"),mWin,Bdone,Bcancel,null); // start dialog + zdialog_add_widget(zd,"hbox","hbb","dialog",0,"homog|space=5"); + zdialog_add_widget(zd,"hbox","hbr","dialog",0,"homog|space=5"); + + strcpy(blab,"butt-0"); + strcpy(rlab,"ratio-0"); + + for (ii = 0; ii < 6; ii++) + { + blab[5] = '0' + ii; + rlab[6] = '0' + ii; + zdialog_add_widget(zd,"entry",blab,"hbb",trimbuttons[ii],"scc=6"); + zdialog_add_widget(zd,"entry",rlab,"hbr",trimratios[ii],"scc=6"); + } + + zdialog_run(zd,0,"mouse"); // run dialog v.11.07 + zstat = zdialog_wait(zd); + + if (zstat == 1) // apply + { + for (ii = 0; ii < 6; ii++) // get custom button names + { + blab[5] = '0' + ii; + zdialog_fetch(zd,blab,text,12); + strTrim2(text); + if (! *text) continue; + zfree(trimbuttons[ii]); + trimbuttons[ii] = strdupz(text,0,"trim"); + } + + for (ii = 0; ii < 6; ii++) // get custom ratios + { + rlab[6] = '0' + ii; + zdialog_fetch(zd,rlab,text,12); + strTrim2(text); + r1 = r2 = ratio = 0; + pp = strField(text,':',1); + if (! pp) continue; + r1 = atof(pp); + pp = strField(text,':',2); + if (! pp) continue; + r2 = atof(pp); + if (r1 > 0 && r2 > 0) ratio = r1/r2; + if (ratio < 0.1 || ratio > 10) continue; + zfree(trimratios[ii]); + trimratios[ii] = strdupz(text,0,"trim"); + } + } + + zdialog_free(zd); // kill dialog + return; +} + + +/**************************************************************************/ + +// auto-trim image - set trim rectangle to exclude black margins +// left over from rotate or warp functions + +void m_autotrim(GtkWidget *, cchar *) // new v.11.12 +{ + int px1, py1, px3, py3; + int qx1, qy1, qx3, qy3; + int qx, qy, step1, step2; + int area1, area2, Fgrow = 0; + uint8 *ppix; + + if (! Fpxm8) return; + + px1 = 0.4 * Fww; // select small rectangle in the middle + py1 = 0.4 * Fhh; + px3 = 0.6 * Fww; + py3 = 0.6 * Fhh; + + step1 = 0.05 * (Fww + Fhh); // start with big search steps + step2 = 0.2 * step1; + + while (true) + { + while (true) + { + Fgrow = 0; + + area1 = (px3 - px1) * (py3 - py1); // area of current selection rectangle + area2 = area1; + + for (qx1 = px1-step1; qx1 <= px1+step1; qx1 += step2) // loop, vary NW and SE corners + for (qy1 = py1-step1; qy1 <= py1+step1; qy1 += step2) + for (qx3 = px3-step1; qx3 <= px3+step1; qx3 += step2) + for (qy3 = py3-step1; qy3 <= py3+step1; qy3 += step2) + { + if (qx1 < 0) continue; // check image limits + if (qy1 < 0) continue; + if (qx1 > 0.5 * Fww) continue; + if (qy1 > 0.5 * Fhh) continue; + if (qx3 > Fww-1) continue; + if (qy3 > Fhh-1) continue; + if (qx3 < 0.5 * Fww) continue; + if (qy3 < 0.5 * Fhh) continue; + + ppix = (uint8 *) Fpxm8->bmp + (qy1 * Fww + qx1) * 3; // check 4 corners are not + if (ppix[0] + ppix[1] + ppix[2] == 0) continue; // in the black margin zones + ppix = (uint8 *) Fpxm8->bmp + (qy1 * Fww + qx3) * 3; + if (ppix[0] + ppix[1] + ppix[2] == 0) continue; + ppix = (uint8 *) Fpxm8->bmp + (qy3 * Fww + qx3) * 3; + if (ppix[0] + ppix[1] + ppix[2] == 0) continue; + ppix = (uint8 *) Fpxm8->bmp + (qy3 * Fww + qx1) * 3; + if (ppix[0] + ppix[1] + ppix[2] == 0) continue; + + area2 = (qx3 - qx1) * (qy3 - qy1); // look for larger enclosed area + if (area2 <= area1) continue; + + for (qx = qx1; qx < qx3; qx++) { // check 4 sides don't intersect + ppix = (uint8 *) Fpxm8->bmp + (qy1 * Fww + qx) * 3; // the black margin zones + if (ppix[0] + ppix[1] + ppix[2] == 0) break; + ppix = (uint8 *) Fpxm8->bmp + (qy3 * Fww + qx) * 3; + if (ppix[0] + ppix[1] + ppix[2] == 0) break; + } + if (qx < qx3) continue; + + for (qy = qy1; qy < qy3; qy++) { + ppix = (uint8 *) Fpxm8->bmp + (qy * Fww + qx1) * 3; + if (ppix[0] + ppix[1] + ppix[2] == 0) break; + ppix = (uint8 *) Fpxm8->bmp + (qy * Fww + qx3) * 3; + if (ppix[0] + ppix[1] + ppix[2] == 0) break; + } + if (qy < qy3) continue; + + Fgrow = 1; // successfully grew the rectangle + px1 = qx1; // new bigger rectangle coordinates + py1 = qy1; // for the next search iteration + px3 = qx3; + py3 = qy3; + break; + } + + if (! Fgrow) break; + } + + if (step2 == 1) break; // done + + step1 = 0.6 * step1; // reduce search step size + step2 = 0.2 * step1; + if (step2 < 1) step2 = 1; + } + + trimx1 = px1; // set parameters for trim function + trimx2 = px3; + trimy1 = py1; + trimy2 = py3; + + m_trim(0,"autotrim"); // perform regular trim with + return; // pre-set margins +} + + +/**************************************************************************/ + +// Resize (rescale) image +// +// Output pixels are composites of input pixels, e.g. 2/3 size means +// that 3x3 input pixels are mapped into 2x2 output pixels, and an +// image size of 1000 x 600 becomes 667 x 400. + +int resize_ww0, resize_hh0; // original size +int resize_ww1, resize_hh1; // new size + +editfunc EFresize; + +void m_resize(GtkWidget *, cchar *) +{ + int resize_dialog_event(zdialog *zd, cchar *event); + void * resize_thread(void *); + + cchar *lockmess = ZTX("Lock aspect ratio"); + + zfuncs::F1_help_topic = "resize"; // v.10.8 + + EFresize.funcname = "resize"; + EFresize.threadfunc = resize_thread; // thread function + if (! edit_setup(EFresize)) return; // setup edit + + zdialog *zd = zdialog_new(ZTX("Resize Image"),mWin,Bdone,Bcancel,null); + EFresize.zd = zd; + + zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=10"); + zdialog_add_widget(zd,"vbox","vb11","hb1",0,"homog|space=5"); + zdialog_add_widget(zd,"vbox","vb12","hb1",0,"homog|space=5"); + zdialog_add_widget(zd,"vbox","vb13","hb1",0,"homog|space=5"); + zdialog_add_widget(zd,"label","placeholder","vb11",0); // pixels percent + zdialog_add_widget(zd,"label","labw","vb11",Bwidth); // width [______] [______] + zdialog_add_widget(zd,"label","labh","vb11",Bheight); // height [______] [______] + zdialog_add_widget(zd,"label","labpix","vb12","pixels"); // + zdialog_add_widget(zd,"spin","wpix","vb12","20|9999|1|20"); // presets [2/3] [1/2] [1/3] [1/4] [Prev] + zdialog_add_widget(zd,"spin","hpix","vb12","20|9999|1|20"); // + zdialog_add_widget(zd,"label","labpct","vb13",Bpercent); // [_] lock aspect ratio + zdialog_add_widget(zd,"spin","wpct","vb13","1|500|0.1|100"); // + zdialog_add_widget(zd,"spin","hpct","vb13","1|500|0.1|100"); // [done] [cancel] + zdialog_add_widget(zd,"hbox","hb2","dialog",0,"space=5"); + zdialog_add_widget(zd,"label","preset","hb2",Bpresets,"space=5"); + zdialog_add_widget(zd,"button","b 3/4","hb2","3/4"); + zdialog_add_widget(zd,"button","b 2/3","hb2","2/3"); + zdialog_add_widget(zd,"button","b 1/2","hb2","1/2"); + zdialog_add_widget(zd,"button","b 1/3","hb2","1/3"); + zdialog_add_widget(zd,"button","b 1/4","hb2","1/4"); + zdialog_add_widget(zd,"button","prev","hb2",ZTX("Prev")); + zdialog_add_widget(zd,"hbox","hb3","dialog",0,"space=5"); + zdialog_add_widget(zd,"check","lock","hb3",lockmess,"space=5"); + + resize_ww0 = Fpxm16->ww; // original width, height + resize_hh0 = Fpxm16->hh; + + zdialog_stuff(zd,"wpix",resize_ww0); + zdialog_stuff(zd,"hpix",resize_hh0); + zdialog_stuff(zd,"lock",1); + + zdialog_help(zd,"resize"); // zdialog help topic v.11.08 + zdialog_run(zd,resize_dialog_event,"save"); // run dialog v.11.07 + zdialog_wait(zd); // wait for completion + return; +} + + +// dialog event and completion callback function + +int resize_dialog_event(zdialog *zd, cchar * event) +{ + int lock; + double wpct1, hpct1; + + if (zd->zstat) // dialog complete + { + if (zd->zstat != 1) { // user cancel + edit_cancel(EFresize); + return 0; + } + + editresize[0] = resize_ww1; // remember size used v.10.10 + editresize[1] = resize_hh1; + + Fzoom = 0; // v.11.01 + edit_done(EFresize); + return 0; + } + + if (strnEqu(event,"KB",2)) return 0; // ignore KB inputs v.11.11 + + zdialog_fetch(zd,"wpix",resize_ww1); // get all widget values + zdialog_fetch(zd,"hpix",resize_hh1); + zdialog_fetch(zd,"wpct",wpct1); + zdialog_fetch(zd,"hpct",hpct1); + zdialog_fetch(zd,"lock",lock); + + if (strEqu(event,"b 3/4")) { + resize_ww1 = (3 * resize_ww0 + 3) / 4; + resize_hh1 = (3 * resize_hh0 + 3) / 4; + } + + if (strEqu(event,"b 2/3")) { + resize_ww1 = (2 * resize_ww0 + 2) / 3; + resize_hh1 = (2 * resize_hh0 + 2) / 3; + } + + if (strEqu(event,"b 1/2")) { + resize_ww1 = (resize_ww0 + 1) / 2; + resize_hh1 = (resize_hh0 + 1) / 2; + } + + if (strEqu(event,"b 1/3")) { + resize_ww1 = (resize_ww0 + 2) / 3; + resize_hh1 = (resize_hh0 + 2) / 3; + } + + if (strEqu(event,"b 1/4")) { + resize_ww1 = (resize_ww0 + 3) / 4; + resize_hh1 = (resize_hh0 + 3) / 4; + } + + if (strEqu(event,"prev")) { // use previous resize values v.10.10 + resize_ww1 = editresize[0]; + resize_hh1 = editresize[1]; + } + + if (strEqu(event,"wpct")) // width % - set pixel width + resize_ww1 = int(wpct1 / 100.0 * resize_ww0 + 0.5); + + if (strEqu(event,"hpct")) // height % - set pixel height + resize_hh1 = int(hpct1 / 100.0 * resize_hh0 + 0.5); + + if (lock && event[0] == 'w') // preserve width/height ratio + resize_hh1 = int(resize_ww1 * (1.0 * resize_hh0 / resize_ww0) + 0.5); + if (lock && event[0] == 'h') + resize_ww1 = int(resize_hh1 * (1.0 * resize_ww0 / resize_hh0) + 0.5); + + hpct1 = 100.0 * resize_hh1 / resize_hh0; // set percents to match pixels + wpct1 = 100.0 * resize_ww1 / resize_ww0; + + zdialog_stuff(zd,"wpix",resize_ww1); // index all widget values + zdialog_stuff(zd,"hpix",resize_hh1); + zdialog_stuff(zd,"wpct",wpct1); + zdialog_stuff(zd,"hpct",hpct1); + + signal_thread(); // do the update, don't wait for idle + return 1; +} + + +// do the resize job + +void * resize_thread(void *) // v.10.12 +{ + CEF->Fmod = 0; + + while (true) + { + thread_idle_loop(); // wait for signal + + mutex_lock(&Fpixmap_lock); + PXM_free(E3pxm16); + E3pxm16 = PXM_rescale(Fpxm16,resize_ww1,resize_hh1); // rescale the edit image + E3ww = resize_ww1; + E3hh = resize_hh1; + CEF->Fmod = 1; + mutex_unlock(&Fpixmap_lock); + mwpaint2(); + } + + return 0; +} + + +/**************************************************************************/ + +// edit image annotation - write text on the image itself + +char annotate_file[1000] = ""; // file for annotation data +int annotate_mode = 0; // 0/1/2 = 1st write / re-write / erase +int annotate_px, annotate_py; // text position on image +PXM *annotate_pxm = 0; // buffer for rendered annotation text +PXM *annotate_pxm_transp = 0; // buffer for transparency data + +void annotate_dialog_stuff(zdialog *zd); // stuff dialog widgets from memory data +int annotate_dialog_event(zdialog *zd, cchar *event); // dialog event function +void annotate_mousefunc(); // mouse event function +void annotate_gettext(); // render text into graphic image +void annotate_write(); // write text on image +void annotate_load(); // load annotation data from file +void annotate_save(); // save annotation data to file + +editfunc EFannotate; + + +void m_annotate(GtkWidget *, cchar *menu) // overhauled v.10.11 +{ + char *pp; + cchar *intro = ZTX("Enter text, click/drag on image.\n" + "Right click to remove"); + + zfuncs::F1_help_topic = "annotate"; // user guide topic + + EFannotate.funcname = "annotate"; + EFannotate.Farea = 1; // select area ignored + if (! edit_setup(EFannotate)) return; // setup edit + + if (! annotate_text) + annotate_text = strdupz("enter text",0,"annotate"); + + if (! annotate_font || strEqu(annotate_font,"undefined")) + annotate_font = strdupz("FreeMono Bold Italic 44",4,"annotate"); // default font and size + else annotate_font = strdupz(annotate_font,4,"annotate"); // add extra space bugfix v.11.02 + + + if (! annotate_color[0] || strEqu(annotate_color[0],"undefined")) { // default colors + annotate_color[0] = strdupz("255|0|0",0,"annotate"); // text + annotate_color[1] = strdupz("0|0|255",0,"annotate"); // background + annotate_color[2] = strdupz("0|255|0",0,"annotate"); // text outline + annotate_outline = 6; // outline width + } + + pp = annotate_color[0]; // insure at least 20 bytes + annotate_color[0] = strdupz(pp,20,"annotate"); + zfree(pp); + pp = annotate_color[1]; + annotate_color[1] = strdupz(pp,20,"annotate"); + zfree(pp); + pp = annotate_color[2]; + annotate_color[2] = strdupz(pp,20,"annotate"); + zfree(pp); + +// Annotate Image +// +// Text [__________________________________] // dialog +// +// [font] size [___|v] angle [___|v] +// +// text backing outline // v.11.04 +// Color [color] [color] [color] +// Transparency [___|v] [___|v] [___|v] +// Width [___|v] +// +// Annotation File: [Open] [Save] +// +// [Done] [Cancel] + + zdialog *zd = zdialog_new(ZTX("Annotate Image"),mWin,Bdone,Bcancel,null); + EFannotate.zd = zd; + EFannotate.mousefunc = annotate_mousefunc; + + zdialog_add_widget(zd,"label","intro","dialog",intro,"space=3"); + zdialog_add_widget(zd,"hbox","hbtext","dialog",0,"space=3"); + zdialog_add_widget(zd,"label","labtext","hbtext",ZTX("Text"),"space=5"); + zdialog_add_widget(zd,"frame","frtext","hbtext",0,"expand"); + zdialog_add_widget(zd,"edit","text","frtext",0,"expand"); + + zdialog_add_widget(zd,"hbox","hbfont","dialog",0,"space=8"); + zdialog_add_widget(zd,"button","font","hbfont",Bfont,"space=5"); + zdialog_add_widget(zd,"label","space","hbfont","","space=5"); + zdialog_add_widget(zd,"label","labsize","hbfont",ZTX("Size"),"space=3"); + zdialog_add_widget(zd,"spin","size","hbfont","6|99|1|20","space=3"); + zdialog_add_widget(zd,"label","space","hbfont","","space=5"); + zdialog_add_widget(zd,"label","labangle","hbfont",ZTX("Angle"),"space=3"); + zdialog_add_widget(zd,"spin","angle","hbfont","-180|180|0.2|0","space=3"); + + zdialog_add_widget(zd,"hsep","hs1","dialog",0,"space=3"); + zdialog_add_widget(zd,"hbox","hbcol","dialog",0,"space=3"); + zdialog_add_widget(zd,"vbox","vbcol1","hbcol",0,"homog|space=5"); + zdialog_add_widget(zd,"vbox","vbcol2","hbcol",0,"homog|space=5"); + zdialog_add_widget(zd,"vbox","vbcol3","hbcol",0,"homog|space=5"); + zdialog_add_widget(zd,"vbox","vbcol4","hbcol",0,"homog|space=5"); + + zdialog_add_widget(zd,"label","space","vbcol1"); + zdialog_add_widget(zd,"label","labcol","vbcol1",ZTX("Color")); + zdialog_add_widget(zd,"label","labcol","vbcol1",ZTX("Transparency")); + zdialog_add_widget(zd,"label","space","vbcol1"); + + zdialog_add_widget(zd,"label","labtext","vbcol2",ZTX("text")); + zdialog_add_widget(zd,"colorbutt","fgcolor","vbcol2","0|0|0"); + zdialog_add_widget(zd,"spin","fgtrans","vbcol2","0|100|1|0"); + zdialog_add_widget(zd,"label","space","vbcol2"); + + zdialog_add_widget(zd,"label","labback","vbcol3",ZTX("backing")); + zdialog_add_widget(zd,"colorbutt","bgcolor","vbcol3","255|255|255"); + zdialog_add_widget(zd,"spin","bgtrans","vbcol3","0|100|1|0"); + zdialog_add_widget(zd,"label","labw","vbcol3",ZTX("Outline\n Width")); + + zdialog_add_widget(zd,"label","laboutln","vbcol4",ZTX("outline")); + zdialog_add_widget(zd,"colorbutt","tocolor","vbcol4","255|0|0"); + zdialog_add_widget(zd,"spin","totrans","vbcol4","0|100|1|0"); + zdialog_add_widget(zd,"spin","outline","vbcol4","0|9|1|0"); + + zdialog_add_widget(zd,"hsep","hs1","dialog",0,"space=3"); + zdialog_add_widget(zd,"hbox","hbaf","dialog",0,"space=8"); + zdialog_add_widget(zd,"label","labbg","hbaf",ZTX("Annotation File:"),"space=3"); + zdialog_add_widget(zd,"button","load","hbaf",Bopen,"space=5"); + zdialog_add_widget(zd,"button","save","hbaf",Bsave,"space=5"); + + annotate_dialog_stuff(zd); // stuff dialog widgets from memory data + + zdialog_help(zd,"annotate"); // zdialog help topic v.11.08 + zdialog_run(zd,annotate_dialog_event,"save"); // run dialog, parallel v.11.07 + + takeMouse(zd,annotate_mousefunc,dragcursor); // connect mouse function v.10.12 + + annotate_mode = 0; // no write on image (yet) + annotate_px = annotate_py = -1; // no location on image (yet) + return; +} + + +// stuff all dialog widgets from annotation data in memory + +void annotate_dialog_stuff(zdialog *zd) +{ + int size; + char *pp; + + zdialog_stuff(zd,"text",annotate_text); + zdialog_stuff(zd,"angle",annotate_angle); + zdialog_stuff(zd,"fgtrans",annotate_trans[0]); + zdialog_stuff(zd,"bgtrans",annotate_trans[1]); + zdialog_stuff(zd,"totrans",annotate_trans[2]); + zdialog_stuff(zd,"fgcolor",annotate_color[0]); + zdialog_stuff(zd,"bgcolor",annotate_color[1]); + zdialog_stuff(zd,"tocolor",annotate_color[2]); + zdialog_stuff(zd,"outline",annotate_outline); + + pp = annotate_font + strlen(annotate_font); + while (*pp != ' ') pp--; + if (pp > annotate_font) { + size = atoi(pp); + if (size >= 6 && size <= 99) + zdialog_stuff(zd,"size",size); + } + + annotate_gettext(); // build text buffer from annotation data + + return; +} + + +// dialog event and completion callback function + +int annotate_dialog_event(zdialog *zd, cchar *event) +{ + GtkWidget *font_dialog; + int size; + char *pp, text[1000]; + + if (zd->zstat) + { + if (zd->zstat == 1 && CEF->Fmod) edit_done(EFannotate); // Done, complete pending edit + else edit_cancel(EFannotate); // Cancel or kill + return 0; + } + + if (strEqu(event,"focus")) // toggle mouse capture + takeMouse(zd,annotate_mousefunc,dragcursor); // connect mouse function v.12.01 + + if (strEqu(event,"text")) { + zdialog_fetch(zd,"text",text,999); // get text from dialog + if (annotate_text) zfree(annotate_text); + annotate_text = 0; + if (*text) annotate_text = strdupz(text,0,"annotate"); + } + + if (strEqu(event,"font")) { // new font + font_dialog = gtk_font_selection_dialog_new(ZTX("select font")); + gtk_font_selection_dialog_set_font_name(GTK_FONT_SELECTION_DIALOG(font_dialog),annotate_font); + gtk_dialog_run(GTK_DIALOG(font_dialog)); + pp = gtk_font_selection_dialog_get_font_name(GTK_FONT_SELECTION_DIALOG(font_dialog)); + gtk_widget_destroy(GTK_WIDGET(font_dialog)); + + if (pp) { + zfree(annotate_font); + annotate_font = strdupz(pp,6,"annotate"); // update font and size + g_free(pp); + pp = annotate_font + strlen(annotate_font); + while (*pp != ' ') pp--; + if (pp > annotate_font) { + size = atoi(pp); + if (size >= 6 && size <= 99) zdialog_stuff(zd,"size",size); + } + } + } + + if (strEqu(event,"load")) { // load annotate data from file + annotate_load(); + annotate_dialog_stuff(zd); + return 1; + } + + if (strEqu(event,"save")) { // save annotate data to file + annotate_save(); + return 1; + } + + if (strEqu(event,"size")) { // new font size + zdialog_fetch(zd,"size",size); + pp = annotate_font + strlen(annotate_font); // "fontname NN" + while (*pp != ' ') pp--; // back-up to " NN" + if (pp > annotate_font) sprintf(pp," %d",size); // replace NN with new size + } + + if (strEqu(event,"angle")) + zdialog_fetch(zd,"angle",annotate_angle); + + if (strEqu(event,"fgcolor")) // foreground (text) color + zdialog_fetch(zd,"fgcolor",annotate_color[0],20); + + if (strEqu(event,"bgcolor")) // background color + zdialog_fetch(zd,"bgcolor",annotate_color[1],20); + + if (strEqu(event,"tocolor")) // text outline color + zdialog_fetch(zd,"tocolor",annotate_color[2],20); + + if (strEqu(event,"fgtrans")) // foreground transparency + zdialog_fetch(zd,"fgtrans",annotate_trans[0]); + + if (strEqu(event,"bgtrans")) // background transparency + zdialog_fetch(zd,"bgtrans",annotate_trans[1]); + + if (strEqu(event,"totrans")) // text outline transparency + zdialog_fetch(zd,"totrans",annotate_trans[2]); + + if (strEqu(event,"outline")) // text outline width + zdialog_fetch(zd,"outline",annotate_outline); + + annotate_gettext(); // rebuild text buffer + annotate_write(); // write on image + zmainloop(); + + return 1; +} + + +// mouse function, set position for annotation text on image + +void annotate_mousefunc() +{ + static int dragging = 0; + + if (LMclick) { // left mouse click + LMclick = 0; + annotate_px = Mxclick; // new text position on image + annotate_py = Myclick; + annotate_write(); // write text on image + } + + if (RMclick) { // right mouse click + RMclick = 0; + annotate_mode = 2; // erase text on image + annotate_write(); + annotate_px = annotate_py = -1; // no location on image + } + + if (Mxdrag || Mydrag) // mouse dragged + { + if (! dragging && annotate_mode) dragging = 1; + + if (dragging) { + annotate_px = Mxdrag; // new text position on image + annotate_py = Mydrag; + annotate_write(); // write text on image + } + } + else dragging = 0; // no drag underway + + return; +} + + +// write annotation text on image at designated place, if wanted +// annotate_mode: 0/1/2 = 1st write / re-write / erase + +void annotate_write() +{ + uint8 *pix1, *pix2; + uint16 *pix3, *pix31, *pix33; + int px1, py1, px3, py3; + double e3part, f256 = 1.0 / 256.0; + + static int orgx1 = 0, orgy1 = 0, ww1 = 0, hh1 = 0; // old text image overlap rectangle + int orgx2, orgy2, ww2, hh2; // new overlap rectangle + + if (annotate_mode) // re-write or erase + { + for (py3 = orgy1; py3 < orgy1 + hh1; py3++) // erase prior text image + for (px3 = orgx1; px3 < orgx1 + ww1; px3++) // replace E3 pixels with E1 pixels + { // in prior overlap rectangle + if (px3 < 0 || px3 >= E3ww) continue; + if (py3 < 0 || py3 >= E3hh) continue; + pix31 = PXMpix(E1pxm16,px3,py3); + pix33 = PXMpix(E3pxm16,px3,py3); + pix33[0] = pix31[0]; + pix33[1] = pix31[1]; + pix33[2] = pix31[2]; + } + + CEF->Fmod = 0; + } + + if (annotate_mode == 2) { // erase only + annotate_mode = 0; // next time is a 1st write + mwpaint3(orgx1,orgy1,ww1,hh1); // update window + return; + } + + if (! annotate_text) { // no text to write + annotate_mode = 0; // next time is a 1st write + mwpaint3(orgx1,orgy1,ww1,hh1); // update window + return; + } + + if (annotate_px < 0 || annotate_py < 0) { // no image position to write + annotate_mode = 0; // next time is a 1st write + mwpaint3(orgx1,orgy1,ww1,hh1); // update window + return; + } + + annotate_mode = 1; // next time is a re-write + + ww2 = annotate_pxm->ww; // text image buffer + hh2 = annotate_pxm->hh; + + orgx2 = annotate_px - ww2/2; // copy-to image3 location + orgy2 = annotate_py - hh2/2; + + for (py1 = 0; py1 < hh2; py1++) // loop all pixels in text image + for (px1 = 0; px1 < ww2; px1++) + { + px3 = orgx2 + px1; // copy-to image3 pixel + py3 = orgy2 + py1; + + if (px3 < 0 || px3 >= E3ww) continue; // omit parts beyond edges + if (py3 < 0 || py3 >= E3hh) continue; + + pix1 = PXMpix8(annotate_pxm,px1,py1); // copy-from text pixel + pix2 = PXMpix8(annotate_pxm_transp,px1,py1); // copy-from transparency + pix3 = PXMpix(E3pxm16,px3,py3); // copy-to image pixel + + e3part = pix2[0] * f256; // image part visible through text + + pix3[0] = (pix1[0] << 8) + e3part * pix3[0]; // combine text part + image part + pix3[1] = (pix1[1] << 8) + e3part * pix3[1]; + pix3[2] = (pix1[2] << 8) + e3part * pix3[2]; + } + + mwpaint3(orgx1,orgy1,ww1,hh1); // restore prior overlap rectangle + mwpaint3(orgx2,orgy2,ww2,hh2); // update new overlap rectangle + + CEF->Fmod = 1; + + orgx1 = orgx2; // remember overlap rectangle + orgy1 = orgy2; // for next call + + ww1 = ww2; + hh1 = hh2; + return; +} + + +// Create a graphic image with text, white on black, any font, any angle. + +void annotate_gettext() // revised v.10.12 +{ + PXM * annotate_addoutline(PXM *); + + PangoFontDescription *pfont; + static GdkColormap *colormap = 0; + static GdkColor black, white; + PangoLayout *playout; + GdkPixmap *pixmap; + GdkGC *gdkgc; + GdkPixbuf *pixbuf; + + char *text = annotate_text; + double angle = annotate_angle; + PXM *pxm_temp1, *pxm_temp2, *pxm_temp3; + uint8 *pix1, *pix2, *pix3, *ppix; + int px, py, ww, hh, rs, fontsize; + char *pp, font[100]; + cchar *ppc; + int fgred, fggreen, fgblue; + int bgred, bggreen, bgblue; + int tored, togreen, toblue; + int red, green, blue; + double fgtrans, bgtrans, totrans, fgpart, bgpart; + double f256 = 1.0 / 256.0; + + if (! annotate_text || ! *annotate_text) return; // no annotation text + + strncpy0(font,annotate_font,99); + pp = font + strlen(font); // save current font size + while (*pp != ' ') pp--; + fontsize = atoi(pp); + if (fontsize < 6 || fontsize > 99) fontsize = 20; + + strcpy(pp+1,"99"); // use large size for text generation + + if (! colormap) { + colormap = gtk_widget_get_colormap(drWin); + black.red = black.green = black.blue = 0; + white.red = white.green = white.blue = 0xffff; + gdk_rgb_find_color(colormap,&black); + gdk_rgb_find_color(colormap,&white); + } + + pfont = pango_font_description_from_string(font); // make layout with text + playout = gtk_widget_create_pango_layout(drWin,null); + pango_layout_set_font_description(playout,pfont); + pango_layout_set_text(playout,text,-1); + pango_layout_get_pixel_size(playout,&ww,&hh); + + ww += 10; // sometimes it is a little too small + hh += 2; + pixmap = gdk_pixmap_new(drWin->window,ww,hh,-1); // then make pixmap + gdkgc = gdk_gc_new(pixmap); + gdk_draw_rectangle(pixmap,gdkgc,1,0,0,ww,hh); + gdk_draw_layout_with_colors(pixmap,gdkgc,0,0,playout,&white,&black); + + pixbuf = gdk_pixbuf_get_from_drawable(null,pixmap,0,0,0,0,0,ww,hh); // then make pixbuf + + ww = gdk_pixbuf_get_width(pixbuf); // pixbuf dimensions + hh = gdk_pixbuf_get_height(pixbuf); + rs = gdk_pixbuf_get_rowstride(pixbuf); + ppix = gdk_pixbuf_get_pixels(pixbuf); + + pxm_temp1 = PXM_make(ww,hh,8); + + for (py = 0; py < hh; py++) // copy pixbuf to PXM + for (px = 0; px < ww; px++) + { // text color is gray/white + pix1 = ppix + rs * py + 3 * px; // can erase all but one color + pix2 = PXMpix8(pxm_temp1,px,py); + pix2[0] = pix1[0]; + pix2[1] = pix2[2] = 0; + } + + g_object_unref(playout); + g_object_unref(pixmap); + g_object_unref(gdkgc); + g_object_unref(pixbuf); + + pxm_temp2 = annotate_addoutline(pxm_temp1); // add text outline color if any + if (pxm_temp2) { + PXM_free(pxm_temp1); + pxm_temp1 = pxm_temp2; + } + + if (fabs(angle) > 0.1) { // rotate text if wanted + pxm_temp2 = PXM_rotate(pxm_temp1,angle); + PXM_free(pxm_temp1); + pxm_temp1 = pxm_temp2; + } + + fgred = fggreen = fgblue = 0; + bgred = bggreen = bgblue = 255; + tored = togreen = toblue = 0; + + ppc = strField(annotate_color[0],'|',1); // get text foreground color + if (ppc) fgred = atoi(ppc); // 0 - 255 per RGB color + ppc = strField(annotate_color[0],'|',2); + if (ppc) fggreen = atoi(ppc); + ppc = strField(annotate_color[0],'|',3); + if (ppc) fgblue = atoi(ppc); + + ppc = strField(annotate_color[1],'|',1); // get text background color + if (ppc) bgred = atoi(ppc); + ppc = strField(annotate_color[1],'|',2); + if (ppc) bggreen = atoi(ppc); + ppc = strField(annotate_color[1],'|',3); + if (ppc) bgblue = atoi(ppc); + + ppc = strField(annotate_color[2],'|',1); // get text outline color + if (ppc) tored = atoi(ppc); + ppc = strField(annotate_color[2],'|',2); + if (ppc) togreen = atoi(ppc); + ppc = strField(annotate_color[2],'|',3); + if (ppc) toblue = atoi(ppc); + + fgtrans = 0.01 * annotate_trans[0]; // get transparencies + bgtrans = 0.01 * annotate_trans[1]; // text, background, text outline + totrans = 0.01 * annotate_trans[2]; + + ww = pxm_temp1->ww; // text image input pixmap + hh = pxm_temp1->hh; + + pxm_temp2 = PXM_make(ww,hh,8); // text image output pixmap + pxm_temp3 = PXM_make(ww,hh,8); // output transparency map + + for (py = 0; py < hh; py++) // loop all pixels in text image + for (px = 0; px < ww; px++) + { + pix1 = PXMpix8(pxm_temp1,px,py); // copy-from pixel + pix2 = PXMpix8(pxm_temp2,px,py); // copy-to pixel + pix3 = PXMpix8(pxm_temp3,px,py); // copy-to transparency + + fgpart = pix1[0] * f256; // white part = text foreground, 0 - 1 + bgpart = 1.0 - fgpart; // rest = text background part, 1 - 0 + + if (pix1[1]) // use text outline color + { + fgpart = fgpart * (1.0 - totrans); // reduce for transparencies + bgpart = bgpart * (1.0 - bgtrans); + red = tored * fgpart + bgred * bgpart; // red part for text outline + background + green = togreen * fgpart + bggreen * bgpart; // same for green + blue = toblue * fgpart + bgblue * bgpart; // same for blue + } + + else // use text foreground color + { + fgpart = fgpart * (1.0 - fgtrans); // reduce for transparencies + bgpart = bgpart * (1.0 - bgtrans); + red = fgred * fgpart + bgred * bgpart; // red part for text + text background + green = fggreen * fgpart + bggreen * bgpart; // same for green + blue = fgblue * fgpart + bgblue * bgpart; // same for blue + } + + pix2[0] = red; // output total red, green blue + pix2[1] = green; + pix2[2] = blue; + + pix3[0] = 255 * (1.0 - fgpart - bgpart); // image part visible through text + } + + ww = ww * fontsize / 99.0 + 0.5; // resize from size 99 font + hh = hh * fontsize / 99.0 + 0.5; // to requested font size + PXM_free(pxm_temp1); + pxm_temp1 = PXM_rescale(pxm_temp2,ww,hh); + PXM_free(pxm_temp2); + PXM_free(annotate_pxm); + annotate_pxm = pxm_temp1; + + pxm_temp1 = PXM_rescale(pxm_temp3,ww,hh); // resize transparency map + PXM_free(pxm_temp3); + PXM_free(annotate_pxm_transp); + annotate_pxm_transp = pxm_temp1; + + return; +} + + +// add an outline color to the text character edges + +PXM * annotate_addoutline(PXM *pxm1) // new v.10.12 +{ + PXM *pxm2; + int toww, toww2; + int ww1, hh1, ww2, hh2; + int px1, py1, px2, py2, ii, diff; + uint8 *pix1, *pix2; + + toww = annotate_outline; // text outline color width + if (toww == 0) return 0; // zero + toww2 = 2 * toww; + + ww1 = pxm1->ww; // input PXM dimensions + hh1 = pxm1->hh; + + ww2 = ww1 + toww2; // output PXM with added margins + hh2 = hh1 + toww2; + pxm2 = PXM_make(ww2,hh2,8); + + memset(pxm2->bmp,0,ww2*hh2*3); // clear output to black + + for (py1 = 0; py1 < hh1; py1++) // copy input to output, + for (px1 = 0; px1 < ww1; px1++) // displaced for margins + { + pix1 = PXMpix8(pxm1,px1,py1); + pix2 = PXMpix8(pxm2,px1+toww,py1+toww); + pix2[0] = pix1[0]; + pix2[1] = pix1[1]; + pix2[2] = pix1[2]; + } + + for (py1 = 0; py1 < hh1; py1++) + for (px1 = 0; px1 < ww1-toww-2; px1++) // horizontal forward scan + { + pix1 = PXMpix8(pxm1,px1,py1); + diff = (pix1+6)[0] - pix1[0]; + if (diff < 200) continue; + + px2 = px1 + toww; + py2 = py1 + toww; + pix2 = PXMpix8(pxm2,px2-toww/2,py2); + + for (ii = 0; ii < toww + 1; ii++) + { + pix2[0] = pix1[0]; + pix2[1] = 1; + pix1 += 3; + pix2 += 3; + } + } + + for (py1 = 0; py1 < hh1; py1++) + for (px1 = ww1-1; px1 > toww+2; px1--) // horizontal reverse scan + { + pix1 = PXMpix8(pxm1,px1,py1); + diff = (pix1-6)[0] - pix1[0]; + if (diff < 200) continue; + + px2 = px1 + toww; + py2 = py1 + toww; + pix2 = PXMpix8(pxm2,px2+toww/2,py2); + + for (ii = 0; ii < toww + 1; ii++) + { + pix2[0] = pix1[0]; + pix2[1] = 1; + pix1 -= 3; + pix2 -= 3; + } + } + + for (px1 = 0; px1 < ww1; px1++) + for (py1 = 0; py1 < hh1-toww-2; py1++) // vertical forward scan + { + pix1 = PXMpix8(pxm1,px1,py1); + diff = (pix1+6*ww1)[0] - pix1[0]; + if (diff < 200) continue; + + px2 = px1 + toww; + py2 = py1 + toww; + pix2 = PXMpix8(pxm2,px2,py2-toww/2); + + for (ii = 0; ii < toww + 1; ii++) + { + if (pix2[0] < pix1[0]) pix2[0] = pix1[0]; + pix2[1] = 1; + pix1 += 3*ww1; + pix2 += 3*ww2; + } + } + + for (px1 = 0; px1 < ww1; px1++) + for (py1 = hh1-1; py1 > toww+2; py1--) // vertical reverse scan + { + pix1 = PXMpix8(pxm1,px1,py1); + diff = (pix1-6*ww1)[0] - pix1[0]; + if (diff < 200) continue; + + px2 = px1 + toww; + py2 = py1 + toww; + pix2 = PXMpix8(pxm2,px2,py2+toww/2); + + for (ii = 0; ii < toww + 1; ii++) + { + if (pix2[0] < pix1[0]) pix2[0] = pix1[0]; + pix2[1] = 1; + pix1 -= 3*ww1; + pix2 -= 3*ww2; + } + } + + return pxm2; +} + + +// load annotation data from a file + +void annotate_load() // v.10.11 +{ + FILE *fid; + int cc, err; + char *pp, *file, buff[1200]; + cchar *dialogtitle = "load annotation data from a file"; + + file = zgetfile1(dialogtitle,"open",annotations_dirk); // get input file from user + if (! file) return; + + fid = fopen(file,"r"); // open for read + if (! fid) { + zmessageACK(mWin,"%s",strerror(errno)); + zfree(file); + return; + } + + while (true) + { + pp = fgets_trim(buff,1200,fid,1); + if (! pp) break; + + if (strnEqu(pp,"annotate_text ",15)) { + if (annotate_text) zfree(annotate_text); + cc = strlen(pp+15) + 100; + annotate_text = zmalloc(cc,"annotate"); + repl_1str(pp+15,annotate_text,"\\n","\n"); // replace "\n" with real newline char. + } + + if (strnEqu(pp,"annotate_font ",15)) + strcpy(annotate_font,pp+15); + + if (strnEqu(pp,"annotate_angle ",16)) + convSD(pp+16,annotate_angle,-180,+180); + + if (strnEqu(pp,"annotate_fgcolor ",18)) + strcpy(annotate_color[0],pp+18); + + if (strnEqu(pp,"annotate_bgcolor ",18)) + strcpy(annotate_color[1],pp+18); + + if (strnEqu(pp,"annotate_tocolor ",18)) + strcpy(annotate_color[2],pp+18); + + if (strnEqu(pp,"annotate_fgtrans ",18)) + convSI(pp+18,annotate_trans[0],0,100); + + if (strnEqu(pp,"annotate_bgtrans ",18)) + convSI(pp+18,annotate_trans[1],0,100); + + if (strnEqu(pp,"annotate_totrans ",18)) + convSI(pp+18,annotate_trans[2],0,100); + + if (strnEqu(pp,"annotate_outline ",18)) + convSI(pp+18,annotate_outline,0,9); + } + + err = fclose(fid); + if (err) { + zmessageACK(mWin,"%s",strerror(errno)); + zfree(file); + return; + } + + strcpy(annotate_file,file); // update current file + zfree(file); + + return; +} + + +// save annotation data to a file + +void annotate_save() // v.10.11 +{ + FILE *fid; + char *file, text[1100]; + cchar *dialogtitle = "save annotation data to a file"; + int err; + + file = zgetfile1(dialogtitle,"save",annotations_dirk); // get output file from user + if (! file) return; + + fid = fopen(file,"w"); // open for write + if (! fid) { + zmessageACK(mWin,"%s",strerror(errno)); + zfree(file); + return; + } + + repl_1str(annotate_text,text,"\n","\\n"); // replace newlines with "\n" + + fprintf(fid,"annotate_text %s \n", text); + fprintf(fid,"annotate_font %s \n", annotate_font); + fprintf(fid,"annotate_angle %.1f \n", annotate_angle); + fprintf(fid,"annotate_fgcolor %s \n", annotate_color[0]); + fprintf(fid,"annotate_bgcolor %s \n", annotate_color[1]); + fprintf(fid,"annotate_tocolor %s \n", annotate_color[2]); + fprintf(fid,"annotate_fgtrans %d \n", annotate_trans[0]); + fprintf(fid,"annotate_bgtrans %d \n", annotate_trans[1]); + fprintf(fid,"annotate_totrans %d \n", annotate_trans[2]); + fprintf(fid,"annotate_outline %d \n", annotate_outline); + + fprintf(fid,"\n"); + + err = fclose(fid); + if (err) { + zmessageACK(mWin,"file I/O error %s",file); + zfree(file); + return; + } + + strcpy(annotate_file,file); // update current file + zfree(file); + + return; +} + + +/**************************************************************************/ + +// flip an image horizontally or vertically + +editfunc EFflip; + +void m_flip(GtkWidget *, cchar *) +{ + int flip_dialog_event(zdialog *zd, cchar *event); + + zfuncs::F1_help_topic = "flip_image"; // v.10.8 + + EFflip.funcname = "flip"; + if (! edit_setup(EFflip)) return; // setup edit + + zdialog *zd = zdialog_new(ZTX("Flip Image"),mWin,Bdone,Bcancel,null); + EFflip.zd = zd; + + zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=10"); + zdialog_add_widget(zd,"button","horz","hb1",ZTX("horizontal"),"space=5"); + zdialog_add_widget(zd,"button","vert","hb1",ZTX("vertical"),"space=5"); + + zdialog_help(zd,"flip_image"); // zdialog help topic v.11.08 + zdialog_run(zd,flip_dialog_event,"save"); // run dialog, parallel v.11.07 + return; +} + + +// dialog event and completion callback function + +int flip_dialog_event(zdialog *zd, cchar *event) +{ + int flip_horz(); + int flip_vert(); + + if (zd->zstat) // dialog complete + { + if (zd->zstat == 1) edit_done(EFflip); + else edit_cancel(EFflip); + return 0; + } + + if (strEqu(event,"horz")) flip_horz(); + if (strEqu(event,"vert")) flip_vert(); + return 0; +} + + +int flip_horz() +{ + int px, py; + uint16 *pix3, *pix9; + + edit_zapredo(); // delete redo copy v.10.3 + + E9pxm16 = PXM_copy(E3pxm16); + + for (py = 0; py < E3hh; py++) + for (px = 0; px < E3ww; px++) + { + pix3 = PXMpix(E3pxm16,px,py); // image9 = flipped image3 + pix9 = PXMpix(E9pxm16,E3ww-1-px,py); + pix9[0] = pix3[0]; + pix9[1] = pix3[1]; + pix9[2] = pix3[2]; + } + + mutex_lock(&Fpixmap_lock); + PXM_free(E3pxm16); // image9 >> image3 + E3pxm16 = E9pxm16; + E9pxm16 = 0; + mutex_unlock(&Fpixmap_lock); + + CEF->Fmod = 1; + mwpaint2(); + return 0; +} + + +int flip_vert() +{ + int px, py; + uint16 *pix3, *pix9; + + edit_zapredo(); // delete redo copy v.10.3 + + E9pxm16 = PXM_copy(E3pxm16); + + for (py = 0; py < E3hh; py++) + for (px = 0; px < E3ww; px++) + { + pix3 = PXMpix(E3pxm16,px,py); // image9 = flipped image3 + pix9 = PXMpix(E9pxm16,px,E3hh-1-py); + pix9[0] = pix3[0]; + pix9[1] = pix3[1]; + pix9[2] = pix3[2]; + } + + mutex_lock(&Fpixmap_lock); + PXM_free(E3pxm16); // image9 >> image3 + E3pxm16 = E9pxm16; + E9pxm16 = 0; + mutex_unlock(&Fpixmap_lock); + + CEF->Fmod = 1; + mwpaint2(); + return 0; +} + + +/**************************************************************************/ + +// make a black & white or color negative image + +editfunc EFnegate; + +void m_negate(GtkWidget *, cchar *) // v.10.9 +{ + int negate_dialog_event(zdialog *zd, cchar *event); + + zfuncs::F1_help_topic = "make_negative"; + + EFnegate.funcname = "negate"; + if (! edit_setup(EFnegate)) return; // setup edit: no preview + + zdialog *zd = zdialog_new(ZTX("Make Negative"),mWin,Bdone,Bcancel,null); + EFnegate.zd = zd; + + zdialog_add_widget(zd,"radio","b&wpos","dialog",ZTX("black/white positive")); + zdialog_add_widget(zd,"radio","b&wneg","dialog",ZTX("black/white negative")); + zdialog_add_widget(zd,"radio","colpos","dialog",ZTX("color positive")); + zdialog_add_widget(zd,"radio","colneg","dialog",ZTX("color negative")); + + zdialog_stuff(zd,"colpos",1); + + zdialog_resize(zd,200,0); + zdialog_help(zd,"make_negative"); // zdialog help topic v.11.08 + zdialog_run(zd,negate_dialog_event,"save"); // run dialog - parallel v.11.07 + return; +} + + +// dialog event and completion callback function + +int negate_dialog_event(zdialog *zd, cchar *event) +{ + int mode, px, py; + int red, green, blue; + uint16 *pix1, *pix3; + + if (zd->zstat) // dialog complete + { + if (zd->zstat == 1) edit_done(EFnegate); + else edit_cancel(EFnegate); + return 0; + } + + if (strEqu(event,"b&wpos")) mode = 1; + if (strEqu(event,"b&wneg")) mode = 2; + if (strEqu(event,"colpos")) mode = 3; + if (strEqu(event,"colneg")) mode = 4; + + edit_zapredo(); // delete redo copy + + for (py = 0; py < E3hh; py++) + for (px = 0; px < E3ww; px++) + { + pix1 = PXMpix(E1pxm16,px,py); + + red = pix1[0]; + green = pix1[1]; + blue = pix1[2]; + + if (mode == 1) // black and white positive + red = green = blue = (red + green + blue) / 3; + + else if (mode == 2) // black and white negative + red = green = blue = 65535 - (red + green + blue) / 3; + + if (mode == 3) { /** do nothing **/ } // color positive + + if (mode == 4) { // color negative + red = 65535 - red; + green = 65535 - green; + blue = 65535 - blue; + } + + pix3 = PXMpix(E3pxm16,px,py); + + pix3[0] = red; + pix3[1] = green; + pix3[2] = blue; + } + + CEF->Fmod = 1; + mwpaint2(); + + return 0; +} + + +/**************************************************************************/ + +// unbend an image +// straighten curvature added by pano or improve perspective + +double unbend_lin_horz, unbend_lin_vert; // unbend values from dialog +double unbend_cur_horz, unbend_cur_vert; +double unbend_x1, unbend_x2, unbend_y1, unbend_y2; // unbend axes scaled 0 to 1 +int unbend_hx1, unbend_hy1, unbend_hx2, unbend_hy2; +int unbend_vx1, unbend_vy1, unbend_vx2, unbend_vy2; + +editfunc EFunbend; + + +void m_unbend(GtkWidget *, cchar *) // overhauled v.11.04 +{ + int unbend_dialog_event(zdialog* zd, cchar *event); + void * unbend_thread(void *); + void unbend_mousefunc(); + + zfuncs::F1_help_topic = "unbend"; + + EFunbend.funcname = "unbend"; + EFunbend.Fprev = 1; // use preview + EFunbend.threadfunc = unbend_thread; // thread function + EFunbend.mousefunc = unbend_mousefunc; // mouse function + if (! edit_setup(EFunbend)) return; // setup edit + +/*** ___________________________________ + | | + | Unbend Image | + | | + | linear curved | + | vertical [__|v] [__|v] | + | horizontal [__|v] [__|v] | + | | + | [grid] | + | [done] [cancel] | + |___________________________________| +***/ + + zdialog *zd = zdialog_new(ZTX("Unbend Image"),mWin,Bdone,Bcancel,null); + EFunbend.zd = zd; + + zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=8"); + zdialog_add_widget(zd,"vbox","vb1","hb1",0,"homog|space=5"); + zdialog_add_widget(zd,"vbox","vb2","hb1",0,"homog|space=5"); + zdialog_add_widget(zd,"vbox","vb3","hb1",0,"homog|space=5"); + zdialog_add_widget(zd,"label","labspace","vb1",""); + zdialog_add_widget(zd,"label","labvert","vb1",ZTX("vertical")); + zdialog_add_widget(zd,"label","labhorz","vb1",ZTX("horizontal")); + zdialog_add_widget(zd,"label","lablin","vb2",ZTX("linear")); + zdialog_add_widget(zd,"spin","splinvert","vb2","-99|99|1|0"); + zdialog_add_widget(zd,"spin","splinhorz","vb2","-99|99|1|0"); + zdialog_add_widget(zd,"label","labhorz","vb3",ZTX("curved")); + zdialog_add_widget(zd,"spin","spcurvert","vb3","-99|99|1|0"); + zdialog_add_widget(zd,"spin","spcurhorz","vb3","-99|99|1|0"); + zdialog_add_widget(zd,"hbox","hb2","dialog",0,"space=5"); + zdialog_add_widget(zd,"button","grid","hb2",ZTX("Grid"),"space=10"); + + zdialog_help(zd,"unbend"); // zdialog help topic v.11.08 + zdialog_run(zd,unbend_dialog_event,"save"); // run dialog, parallel v.11.07 + + unbend_x1 = unbend_x2 = unbend_y1 = unbend_y2 = 0.5; // initial axes thru image middle + unbend_lin_horz = unbend_lin_vert = 0; + unbend_cur_horz = unbend_cur_vert = 0; + + load_grid(unbend_grid); // load grid preferences v.11.11 + + takeMouse(zd,unbend_mousefunc,dragcursor); // connect mouse function v.11.03 + signal_thread(); + return; +} + + +// dialog event and completion callback function + +int unbend_dialog_event(zdialog *zd, cchar *event) +{ + if (zd->zstat) // dialog complete + { + paint_toplines(2); // erase axes-lines + + save_grid(unbend_grid); // save grid preferences v.11.11 + Fgrid = 0; // grid off + + if (zd->zstat != 1) { + edit_cancel(EFunbend); // canceled + return 0; + } + + if (unbend_cur_vert || unbend_cur_horz || // image3 modified + unbend_lin_vert || unbend_lin_horz) CEF->Fmod = 1; + else CEF->Fmod = 0; + + edit_done(EFunbend); // commit changes to image3 + return 1; + } + + if (strstr(event,"splinvert")) { // get new unbend value + zdialog_fetch(zd,"splinvert",unbend_lin_vert); + signal_thread(); // trigger thread + } + + if (strstr(event,"splinhorz")) { + zdialog_fetch(zd,"splinhorz",unbend_lin_horz); + signal_thread(); + } + + if (strstr(event,"spcurvert")) { + zdialog_fetch(zd,"spcurvert",unbend_cur_vert); + signal_thread(); + } + + if (strstr(event,"spcurhorz")) { + zdialog_fetch(zd,"spcurhorz",unbend_cur_horz); + signal_thread(); + } + + if (strEqu(event,"grid")) m_gridlines(0,0); // grid dialog v.11.11 + + if (strstr("KB G KB g",event)) // G key, toggle grid v.11.11 + toggle_grid(2); + + + return 1; +} + + +// unbend mouse function // adjustable axes + +void unbend_mousefunc() +{ + cchar *close; + double dist1, dist2; + double mpx = 0, mpy = 0; + + if (LMclick) { // left mouse click + LMclick = 0; + mpx = Mxclick; + mpy = Myclick; + } + + if (Mxdrag || Mydrag) { // mouse dragged + mpx = Mxdrag; + mpy = Mydrag; + } + + if (! mpx && ! mpy) return; + + mpx = 1.0 * mpx / E3ww; // scale mouse position 0 to 1 + mpy = 1.0 * mpy / E3hh; + + if (mpx < 0.2 || mpx > 0.8 ) { // check reasonable position + if (mpy < 0.1 || mpy > 0.9) return; + } + else if (mpy < 0.2 || mpy > 0.8) { + if (mpx < 0.1 || mpx > 0.9) return; + } + else return; + + close = "?"; // find closest axis end-point + dist1 = 2; + + dist2 = mpx * mpx + (mpy-unbend_y1) * (mpy-unbend_y1); + if (dist2 < dist1) { + dist1 = dist2; + close = "left"; + } + + dist2 = (1-mpx) * (1-mpx) + (mpy-unbend_y2) * (mpy-unbend_y2); + if (dist2 < dist1) { + dist1 = dist2; + close = "right"; + } + + dist2 = (mpx-unbend_x1) * (mpx-unbend_x1) + mpy * mpy; + if (dist2 < dist1) { + dist1 = dist2; + close = "top"; + } + + dist2 = (mpx-unbend_x2) * (mpx-unbend_x2) + (1-mpy) * (1-mpy); + if (dist2 < dist1) { + dist1 = dist2; + close = "bottom"; + } + + if (strEqu(close,"left")) unbend_y1 = mpy; // set new axis end-point + if (strEqu(close,"right")) unbend_y2 = mpy; + if (strEqu(close,"top")) unbend_x1 = mpx; + if (strEqu(close,"bottom")) unbend_x2 = mpx; + + signal_thread(); // trigger thread + + return; +} + + +// unbend thread function + +void * unbend_thread(void *arg) +{ + void * unbend_wthread(void *); + + while (true) + { + thread_idle_loop(); // wait for work or exit request + + unbend_hx1 = 0; // scale axes to E3ww/hh + unbend_hy1 = unbend_y1 * E3hh; + unbend_hx2 = E3ww; + unbend_hy2 = unbend_y2 * E3hh; + + unbend_vx1 = unbend_x1 * E3ww; + unbend_vy1 = 0; + unbend_vx2 = unbend_x2 * E3ww; + unbend_vy2 = E3hh; + + if (Fpreview) { // omit for final unbend + Ntoplines = 2; + toplinex1[0] = unbend_hx1; // lines on window + topliney1[0] = unbend_hy1; + toplinex2[0] = unbend_hx2; + topliney2[0] = unbend_hy2; + toplinex1[1] = unbend_vx1; + topliney1[1] = unbend_vy1; + toplinex2[1] = unbend_vx2; + topliney2[1] = unbend_vy2; + } + + for (int ii = 0; ii < Nwt; ii++) // start worker threads + start_wthread(unbend_wthread,&wtnx[ii]); + wait_wthreads(); // wait for completion + + mwpaint2(); // update window + } + + return 0; // not executed, stop g++ warning +} + + +void * unbend_wthread(void *arg) // worker thread function +{ + int index = *((int *) arg); + int vstat, px3, py3, cx3, cy3; + double dispx, dispy, dispx2, dispy2; + double px1, py1, vx1, vx2, hy1, hy2; + double curvert, curhorz, linvert, linhorz; + uint16 vpix[3], *pix3; + + curvert = int(unbend_cur_vert * 0.01 * E3hh); // -0.99 to +0.99 + curhorz = int(unbend_cur_horz * 0.01 * E3ww); + linvert = int(unbend_lin_vert * 0.0013 * E3hh); // -0.13 to +0.13 + linhorz = int(unbend_lin_horz * 0.0013 * E3ww); + + vx1 = unbend_vx1; + vx2 = unbend_vx2; + hy1 = unbend_hy1; + hy2 = unbend_hy2; + + for (py3 = index; py3 < E3hh; py3 += Nwt) // step through F3 pixels + for (px3 = 0; px3 < E3ww; px3++) + { + cx3 = vx1 + (vx2 - vx1) * py3 / E3hh; // center of unbend + cy3 = hy1 + (hy2 - hy1) * px3 / E3ww; + dispx = 2.0 * (px3 - cx3) / E3ww; // -1.0 .. 0.0 .. +1.0 (roughly) + dispy = 2.0 * (py3 - cy3) / E3hh; // -1.0 .. 0.0 .. +1.0 + dispx2 = -cos(0.8 * dispx) + 1; // curved v.11.03 + dispy2 = -cos(0.8 * dispy) + 1; // v.11.04 + + pix3 = PXMpix(E3pxm16,px3,py3); // output pixel + px1 = px3; // input pixel = output + py1 = py3; + + px1 += dispx * dispy * linhorz; // move input pixel + py1 += dispy * dispx * linvert; + px1 += dispx * dispy2 * curhorz; + py1 += dispy * dispx2 * curvert; + + vstat = vpixel(E1pxm16,px1,py1,vpix); + if (vstat) { + pix3[0] = vpix[0]; // input pixel >> output pixel + pix3[1] = vpix[1]; + pix3[2] = vpix[2]; + } + else pix3[0] = pix3[1] = pix3[2] = 0; + } + + exit_wthread(); + return 0; // not executed, avoid gcc warning +} + + +/**************************************************************************/ + +// Convert a selected tetragon area into a rectangle, converting the +// rest of the image to match and keeping straight lines straight. + +int KST_pixel[4][2]; // last 0-4 pixels clicked +int KST_npix; // count of pixels +char KST_pixlab[4][4] = { " A ", " B ", " C ", " D " }; + +editfunc EFkeystone; + +int KST_dialog_event(zdialog *zd, cchar *event); +void KST_mousefunc(void); +void KST_warpfunc(void); + + +void m_keystone(GtkWidget *, cchar *) // new v.11.10 +{ + cchar *KST_message = ZTX( + " Click the four corners of a tetragon area. Press [apply]. \n" + " The image is warped to make the tetragon into a rectangle."); + + zfuncs::F1_help_topic = "keystone"; + + EFkeystone.funcname = "keystone"; + EFkeystone.Fprev = 0; // no preview + EFkeystone.mousefunc = KST_mousefunc; // mouse function + if (! edit_setup(EFkeystone)) return; // setup edit + + KST_npix = 0; // no pixels yet + + zdialog *zd = zdialog_new(ZTX("Keystone Correction"),mWin,Bapply,Breset,Bdone,null); + zdialog_add_widget(zd,"label","lab1","dialog",KST_message,"space=5"); + zdialog_help(zd,"keystone"); // zdialog help topic + + EFkeystone.zd = zd; + zdialog_run(zd,KST_dialog_event,"save"); // run dialog, parallel + + takeMouse(zd,KST_mousefunc,dragcursor); // connect mouse function + return; +} + + +// dialog completion callback function + +int KST_dialog_event(zdialog *zd, cchar *event) +{ + int ii, px, py; + + if (strEqu(event,"focus")) // toggle mouse capture 12.01 + takeMouse(zd,KST_mousefunc,dragcursor); + + if (! zd->zstat) return 1; // wait for completion + + if (zd->zstat == 1) // apply + { + erase_toptext(102); // erase points + KST_warpfunc(); // do the warp + zd->zstat = 0; // keep dialog active + } + + else if (zd->zstat == 2) // reset + { + edit_reset(); + zd->zstat = 0; + + for (ii = 0; ii < KST_npix; ii++) // show pixel labels on image + { + px = KST_pixel[ii][0]; + py = KST_pixel[ii][1]; + add_toptext(102,px,py,KST_pixlab[ii],"Sans 8"); + } + mwpaint2(); + } + + else if (zd->zstat == 3) // done + { + erase_toptext(102); // erase points + edit_done(EFkeystone); + } + + else { // cancel + erase_toptext(102); // erase points + edit_cancel(EFkeystone); + } + + return 0; +} + + +// mouse function - click on 4 corners of tetragon + +void KST_mousefunc(void) +{ + int ii, minii, jj, px, py; + double dist, distx, disty, mindist; + + if (LMclick) // left click + { + LMclick = 0; + + for (ii = 0; ii < KST_npix; ii++) // check if very near a previous corner + { + if (abs(KST_pixel[ii][0] - Mxclick) < 0.07 * E3ww + && abs(KST_pixel[ii][1] - Myclick) < 0.07 * E3hh) + { + KST_pixel[ii][0] = Mxclick; // yes, set new corner position + KST_pixel[ii][1] = Myclick; + goto showcorners; + } + } + + if (KST_npix < 4) // if < 4 corners, add a new one + { + ii = KST_npix; // next corner to fill + KST_pixel[ii][0] = Mxclick; // save newest corner position + KST_pixel[ii][1] = Myclick; + KST_npix++; + goto showcorners; + } + + mindist = 99999; // all 4 corners already specified + minii = -1; + + for (ii = 0; ii < 4; ii++) // find closest corner to click position + { + distx = (Mxclick - KST_pixel[ii][0]); + disty = (Myclick - KST_pixel[ii][1]); + dist = sqrt(distx*distx + disty*disty); + if (dist < mindist) { + mindist = dist; + minii = ii; + } + } + + if (minii >= 0) { // set new corner position + ii = minii; + KST_pixel[ii][0] = Mxclick; + KST_pixel[ii][1] = Myclick; + goto showcorners; + } + } + + else if (RMclick) // right click + { + RMclick = 0; + mindist = 99999; + minii = -1; + + for (ii = 0; ii < KST_npix; ii++) // find closest corner to click position + { + distx = (Mxclick - KST_pixel[ii][0]); + disty = (Myclick - KST_pixel[ii][1]); + dist = sqrt(distx*distx + disty*disty); + if (dist < mindist) { + mindist = dist; + minii = ii; + } + } + + if (minii >= 0) { // replace deleted corner with + ii = minii; // last corner + jj = KST_npix - 1; + KST_pixel[ii][0] = KST_pixel[jj][0]; + KST_pixel[ii][1] = KST_pixel[jj][1]; + --KST_npix; // reduce corner count + goto showcorners; + } + } + +showcorners: + // show corner labels on image + erase_toptext(102); + + for (ii = 0; ii < KST_npix; ii++) + { + px = KST_pixel[ii][0]; + py = KST_pixel[ii][1]; + add_toptext(102,px,py,KST_pixlab[ii],"Sans 8"); + } + + mwpaint2(); + return; +} + + +// keystone warp function - make input tetragon into a rectangle + +void KST_warpfunc(void) +{ + int ii, jj, tempx, tempy, vstat; + double px3, py3, trpx[4], trpy[4]; + double sqpx0, sqpy0, sqpx1, sqpy1, sqpx2, sqpy2, sqpx3, sqpy3; + double cdx0, cdy0, cdx1, cdy1, cdx2, cdy2, cdx3, cdy3; + double px1, py1, dispx, dispy, sqww, sqhh; + double f0, f1, f2, f3; + uint16 vpix1[3], *pix3; + + if (KST_npix != 4) { + zmessageACK(mWin,ZTX("must have 4 corners")); + return; + } + + for (ii = 0; ii < 4; ii++) { // get 4 selected tetragon points + trpx[ii] = KST_pixel[ii][0]; + trpy[ii] = KST_pixel[ii][1]; + } + + // sort 4 points in clockwise order NW, NE, SE, SW + + for (ii = 0; ii < 4; ii++) { // sort top to bottom (y order) + for (jj = ii; jj < 4; jj++) { + if (trpy[jj] < trpy[ii]) { + tempx = trpx[ii]; + tempy = trpy[ii]; + trpx[ii] = trpx[jj]; + trpy[ii] = trpy[jj]; + trpx[jj] = tempx; + trpy[jj] = tempy; + } + } + } + + if (trpx[1] < trpx[0]) { // sort upper two left, right + tempx = trpx[0]; + tempy = trpy[0]; + trpx[0] = trpx[1]; + trpy[0] = trpy[1]; + trpx[1] = tempx; + trpy[1] = tempy; + } + + if (trpx[2] < trpx[3]) { // sort lower two right, left + tempx = trpx[2]; + tempy = trpy[2]; + trpx[2] = trpx[3]; + trpy[2] = trpy[3]; + trpx[3] = tempx; + trpy[3] = tempy; + } + + if (trpx[0] < trpx[3]) sqpx0 = sqpx3 = trpx[0]; // rectangle enclosing tetragon + else sqpx0 = sqpx3 = trpx[3]; + if (trpx[1] > trpx[2]) sqpx1 = sqpx2 = trpx[1]; + else sqpx1 = sqpx2 = trpx[2]; + if (trpy[0] < trpy[1]) sqpy0 = sqpy1 = trpy[0]; + else sqpy0 = sqpy1 = trpy[1]; + if (trpy[2] > trpy[3]) sqpy2 = sqpy3 = trpy[2]; + else sqpy2 = sqpy3 = trpy[3]; + +/*** + sqpx0 = sqpx3 = 0.5 * (trpx[0] + trpx[3]); // rectangle bisecting tetragon sides + sqpx1 = sqpx2 = 0.5 * (trpx[1] + trpx[2]); + sqpy0 = sqpy1 = 0.5 * (trpy[0] + trpy[1]); + sqpy2 = sqpy3 = 0.5 * (trpy[2] + trpy[3]); +***/ + + cdx0 = sqpx0 - trpx[0]; // displavement of tetragon corner + cdy0 = sqpy0 - trpy[0]; // to corresponding rectangle corner + cdx1 = sqpx1 - trpx[1]; + cdy1 = sqpy1 - trpy[1]; + cdx2 = sqpx2 - trpx[2]; + cdy2 = sqpy2 - trpy[2]; + cdx3 = sqpx3 - trpx[3]; + cdy3 = sqpy3 - trpy[3]; + + sqww = 1.0 / (sqpx1 - sqpx0); // rectangle width and height + sqhh = 1.0 / (sqpy3 - sqpy0); + + for (py3 = 0; py3 < E3hh; py3++) // loop all output pixels + for (px3 = 0; px3 < E3ww; px3++) + { + f0 = (1.0 - (px3 - sqpx0) * sqww) * (1.0 - (py3 - sqpy0) * sqhh); + f1 = (px3 - sqpx0) * sqww * (1.0 - (py3 - sqpy0) * sqhh); + f2 = (px3 - sqpx0) * sqww * (py3 - sqpy0) * sqhh; + f3 = (1.0 - (px3 - sqpx0) * sqww) * (py3 - sqpy0) * sqhh; + + dispx = cdx0 * f0 + cdx1 * f1 + cdx2 * f2 + cdx3 * f3; + dispy = cdy0 * f0 + cdy1 * f1 + cdy2 * f2 + cdy3 * f3; + + px1 = px3 - dispx; // input virtual pixel for px3/py3 + py1 = py3 - dispy; + + pix3 = PXMpix(E3pxm16,int(px3),int(py3)); // output pixel + + vstat = vpixel(E1pxm16,px1,py1,vpix1); // output pixel = input virtual pixel + if (vstat) { + pix3[0] = vpix1[0]; + pix3[1] = vpix1[1]; + pix3[2] = vpix1[2]; + } + else pix3[0] = pix3[1] = pix3[2] = 0; + } + + CEF->Fmod = 1; // image is modified + mwpaint2(); // update window + return; +} + + +/**************************************************************************/ + +// warp/distort area - select image area and pull with mouse + +float *WarpAx, *WarpAy; // memory of all displaced pixels +float WarpAmem[4][100]; // undo memory, last 100 warps +int NWarpA; // WarpA mem count +int WarpA_started; +int WarpA_areanumber; + +editfunc EFwarpA; + +void WarpA_init(); +void WarpA_warpfunc(float wdx, float wdy, float wdw, float wdh, int acc); +void WarpA_mousefunc(); + + +void m_warp_area(GtkWidget *, cchar *) +{ + int WarpA_dialog_event(zdialog *zd, cchar *event); + + cchar *WarpA_message = ZTX( + " Select an area to warp using select area function. \n" + " Press [start warp] and pull area with mouse. \n" + " Make multiple mouse pulls until satisfied. \n" + " When finished, select another area or press [done]."); + + zfuncs::F1_help_topic = "warp_area"; + + EFwarpA.funcname = "warp-area"; + EFwarpA.Farea = 2; // select area usable + EFwarpA.mousefunc = WarpA_mousefunc; // mouse function + if (! edit_setup(EFwarpA)) return; // setup edit + + zdialog *zd = zdialog_new(ZTX("Warp Image (area)"),mWin,Bdone,Bcancel,null); + EFwarpA.zd = zd; + + zdialog_add_widget(zd,"label","lab1","dialog",WarpA_message,"space=5"); + zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=5"); + zdialog_add_widget(zd,"button","start","hb1",ZTX("start warp"),"space=5"); + zdialog_add_widget(zd,"button","undolast","hb1",Bundolast,"space=5"); + zdialog_add_widget(zd,"button","undoall","hb1",Bundoall,"space=5"); + + zdialog_help(zd,"warp_area"); // zdialog help topic v.11.08 + zdialog_run(zd,WarpA_dialog_event,"save"); // run dialog, parallel v.11.07 + + WarpAx = (float *) zmalloc(E3ww * E3hh * sizeof(float),"warpA"); // get memory for pixel displacements + WarpAy = (float *) zmalloc(E3ww * E3hh * sizeof(float),"warpA"); + + WarpA_init(); + + return; +} + + +// clear warp data when warp started or re-started after new select area + +void WarpA_init() // v.11.12 +{ + int px, py, ii; + + NWarpA = 0; // no warp data + WarpA_started = 0; + WarpA_areanumber = 0; + + for (py = 0; py < E3hh; py++) // no pixel displacements + for (px = 0; px < E3ww; px++) + { + ii = py * E3ww + px; + WarpAx[ii] = WarpAy[ii] = 0.0; + } + + mwpaint2(); + return; +} + + +// dialog event and completion callback function + +int WarpA_dialog_event(zdialog * zd, cchar *event) +{ + int px, py, ii; + float wdx, wdy, wdw, wdh; + + if (zd->zstat) // dialog complete + { + if (NWarpA) CEF->Fmod = 1; + else CEF->Fmod = 0; + + if (zd->zstat == 1) edit_done(EFwarpA); + else edit_cancel(EFwarpA); + + zfree(WarpAx); // release undo memory + zfree(WarpAy); + return 0; + } + + if (! Factivearea || sa_mode == 7) // no select area active v.11.12 + WarpA_init(); + + if (WarpA_started && WarpA_areanumber != areanumber) // select area changed v.11.12 + WarpA_init(); + + if (strEqu(event,"start")) // start warp + { + if (! Factivearea || sa_mode == 7) { // no select area active v.11.01 + zmessageACK(mWin,ZTX("no active Select Area")); + return 0; + } + sa_edgecalc(); // calculate area edge distances + takeMouse(zd,WarpA_mousefunc,dragcursor); // connect mouse function v.11.03 + WarpA_started = 1; + WarpA_areanumber = areanumber; + } + + if (strEqu(event,"focus")) // toggle mouse capture v.12.01 + takeMouse(zd,WarpA_mousefunc,dragcursor); + + if (strEqu(event,"undolast")) { + if (NWarpA) { // undo most recent warp + ii = --NWarpA; + wdx = WarpAmem[0][ii]; + wdy = WarpAmem[1][ii]; + wdw = WarpAmem[2][ii]; + wdh = WarpAmem[3][ii]; + WarpA_warpfunc(wdx,wdy,-wdw,-wdh,0); // unwarp image + WarpA_warpfunc(wdx,wdy,-wdw,-wdh,1); // unwarp memory + } + } + + if (strEqu(event,"undoall")) // undo all warps + { + edit_reset(); // v.10.3 + + for (py = 0; py < E3hh; py++) // reset pixel displacements + for (px = 0; px < E3ww; px++) + { + ii = py * E3ww + px; + WarpAx[ii] = WarpAy[ii] = 0.0; + } + + NWarpA = 0; // erase undo memory + mwpaint2(); + } + + return 1; +} + + +// warp mouse function + +void WarpA_mousefunc() +{ + static float wdx, wdy, wdw, wdh; + static int ii, warped = 0; + + if (Mxdrag || Mydrag) // mouse drag underway + { + wdx = Mxdown; // drag origin, image coordinates + wdy = Mydown; + wdw = Mxdrag - Mxdown; // drag increment + wdh = Mydrag - Mydown; + WarpA_warpfunc(wdx,wdy,wdw,wdh,0); // warp image + warped = 1; + return; + } + + else if (warped) + { + warped = 0; + WarpA_warpfunc(wdx,wdy,wdw,wdh,1); // drag done, add to warp memory + + if (NWarpA == 100) // if full, throw away oldest + { + NWarpA = 99; + for (ii = 0; ii < NWarpA; ii++) + { + WarpAmem[0][ii] = WarpAmem[0][ii+1]; + WarpAmem[1][ii] = WarpAmem[1][ii+1]; + WarpAmem[2][ii] = WarpAmem[2][ii+1]; + WarpAmem[3][ii] = WarpAmem[3][ii+1]; + } + } + + ii = NWarpA; + WarpAmem[0][ii] = wdx; // save warp for undo + WarpAmem[1][ii] = wdy; + WarpAmem[2][ii] = wdw; + WarpAmem[3][ii] = wdh; + NWarpA++; + } + + return; +} + + +// warp image and accumulate warp memory + +void WarpA_warpfunc(float wdx, float wdy, float wdw, float wdh, int acc) +{ + int ii, px, py, ww, hh, vstat; + double ddx, ddy, dpe, dpm, mag, dispx, dispy; + uint16 vpix[3], *pix3; + + edit_zapredo(); // delete redo copy v.10.3 + + if (! Factivearea) return; // area erased v.11.06.1 + + for (py = sa_miny; py < sa_maxy; py++) // loop all pixels in area v.10.11 + for (px = sa_minx; px < sa_maxx; px++) + { + ii = py * Fww + px; + dpe = sa_pixmap[ii]; // distance from area edge + if (dpe < 1) continue; + dpe -= 1; // v.11.12 + + ddx = (px - wdx); + ddy = (py - wdy); + dpm = sqrt(ddx*ddx + ddy*ddy); // distance from drag origin + + mag = (dpe / (dpm + dpe)) * (1.0 - dpm / (dpm + dpe)); // v.11.12 + + dispx = -wdw * mag; // pixel movement from drag movement + dispy = -wdh * mag; + + if (acc) { // mouse drag done, + WarpAx[ii] += dispx; // accumulate warp memory + WarpAy[ii] += dispy; + continue; + } + + dispx += WarpAx[ii]; // add this warp to prior + dispy += WarpAy[ii]; + + vstat = vpixel(E1pxm16,px+dispx,py+dispy,vpix); // input virtual pixel + if (vstat) { + pix3 = PXMpix(E3pxm16,px,py); // output pixel + pix3[0] = vpix[0]; + pix3[1] = vpix[1]; + pix3[2] = vpix[2]; + } + } + + ww = sa_maxx - sa_minx; // update window v.10.11 + hh = sa_maxy - sa_miny; + mwpaint3(sa_minx,sa_miny,ww,hh); + + CEF->Fmod = 1; // v.10.2 + return; +} + + +/**************************************************************************/ + +// warp/distort whole image with a curved transform +// fix perspective problems (e.g. curved walls, leaning buildings) + +float *WarpCx, *WarpCy; // memory of all dragged pixels +float WarpCmem[4][100]; // undo memory, last 100 drags +int NWarpC; // WarpCmem count +int WarpCdrag; +int WarpCww, WarpChh; + +editfunc EFwarpC; + +void WarpC_warpfunc(float wdx, float wdy, float wdw, float wdh, int acc); +void WarpC_mousefunc(void); + + +void m_warp_curved(GtkWidget *, cchar *) +{ + int WarpC_dialog_event(zdialog *zd, cchar *event); + + cchar *WarpC_message = ZTX( + " Pull an image position using the mouse. \n" + " Make multiple mouse pulls until satisfied. \n" + " When finished, press [done]."); + + int px, py, ii; + + zfuncs::F1_help_topic = "warp_curved"; + + EFwarpC.funcname = "warp-curved"; + EFwarpC.Fprev = 1; // use preview + EFwarpC.mousefunc = WarpC_mousefunc; // mouse function + if (! edit_setup(EFwarpC)) return; // setup edit + + zdialog *zd = zdialog_new(ZTX("Warp Image (curved)"),mWin,Bdone,Bcancel,null); + EFwarpC.zd = zd; + + zdialog_add_widget(zd,"label","lab1","dialog",WarpC_message,"space=5"); + zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=10"); + zdialog_add_widget(zd,"button","undolast","hb1",Bundolast,"space=5"); + zdialog_add_widget(zd,"button","undoall","hb1",Bundoall,"space=5"); + zdialog_add_widget(zd,"hbox","hb2","dialog",0,"space=10"); + zdialog_add_widget(zd,"button","grid","hb2",ZTX("Grid"),"space=10"); + + load_grid(warpC_grid); // load grid preferences v.11.11 + + zdialog_help(zd,"warp_curved"); // zdialog help topic + zdialog_run(zd,WarpC_dialog_event,"save"); // run dialog, parallel v.11.07 + + NWarpC = WarpCdrag = 0; // no drag data + + WarpCx = (float *) zmalloc(E3ww * E3hh * sizeof(float),"warpC"); // get memory for pixel displacements + WarpCy = (float *) zmalloc(E3ww * E3hh * sizeof(float),"warpC"); + + for (py = 0; py < E3hh; py++) // no pixel displacements + for (px = 0; px < E3ww; px++) + { + ii = py * E3ww + px; + WarpCx[ii] = WarpCy[ii] = 0.0; + } + + WarpCww = E3ww; // preview dimensions + WarpChh = E3hh; + + takeMouse(zd,WarpC_mousefunc,dragcursor); // connect mouse function v.11.03 + return; +} + + +// dialog event and completion callback function + +int WarpC_dialog_event(zdialog * zd, cchar *event) +{ + int px, py, ii; + float wdx, wdy, wdw, wdh; + int fpx, fpy, epx, epy, vstat; + double scale, dispx, dispy; + uint16 vpix[3], *pix3; + + if (zd->zstat) goto complete; + + if (strEqu(event,"undolast")) + { + if (NWarpC == 1) event = "undoall"; + else if (NWarpC) { // undo most recent drag + ii = --NWarpC; + wdx = WarpCmem[0][ii]; + wdy = WarpCmem[1][ii]; + wdw = WarpCmem[2][ii]; + wdh = WarpCmem[3][ii]; + WarpC_warpfunc(wdx,wdy,-wdw,-wdh,0); // undrag image + WarpC_warpfunc(wdx,wdy,-wdw,-wdh,1); // undrag memory + } + } + + if (strEqu(event,"undoall")) // undo all drags + { + NWarpC = 0; // erase undo memory + + for (py = 0; py < E3hh; py++) // reset pixel displacements + for (px = 0; px < E3ww; px++) + { + ii = py * E3ww + px; + WarpCx[ii] = WarpCy[ii] = 0.0; + } + edit_reset(); // restore image 1 v.10.3 + } + + if (strEqu(event,"grid")) m_gridlines(0,0); // grid dialog v.11.11 + + if (strstr("KB G KB g",event)) // G key, toggle grid v.11.11 + toggle_grid(2); + + return 1; + +complete: + + save_grid(warpC_grid); // save grid preferences v.11.11 + Fgrid = 0; // grid off + + if (zd->zstat != 1) edit_cancel(EFwarpC); + else if (NWarpC == 0) edit_cancel(EFwarpC); + else + { + edit_fullsize(); // get full-size E1/E3 + + scale = 1.0 * (E3ww + E3hh) / (WarpCww + WarpChh); + + for (fpy = 0; fpy < E3hh; fpy++) // scale net pixel displacements + for (fpx = 0; fpx < E3ww; fpx++) // to full image size + { + epx = WarpCww * fpx / E3ww; + epy = WarpChh * fpy / E3hh; + ii = epy * WarpCww + epx; + dispx = WarpCx[ii] * scale; + dispy = WarpCy[ii] * scale; + + vstat = vpixel(E1pxm16,fpx+dispx,fpy+dispy,vpix); // input virtual pixel + pix3 = PXMpix(E3pxm16,fpx,fpy); // output pixel + if (vstat) { + pix3[0] = vpix[0]; + pix3[1] = vpix[1]; + pix3[2] = vpix[2]; + } + else pix3[0] = pix3[1] = pix3[2] = 0; + } + + edit_done(EFwarpC); + } + + zfree(WarpCx); // release memory + zfree(WarpCy); + return 0; +} + + +// WarpC mouse function + +void WarpC_mousefunc(void) +{ + static float wdx, wdy, wdw, wdh; + int ii; + + if (Mxdrag || Mydrag) // mouse drag underway + { + wdx = Mxdown; // drag origin, window coordinates + wdy = Mydown; + wdw = Mxdrag - Mxdown; // drag increment + wdh = Mydrag - Mydown; + WarpC_warpfunc(wdx,wdy,wdw,wdh,0); // drag image + WarpCdrag = 1; + return; + } + + else if (WarpCdrag) + { + WarpCdrag = 0; + WarpC_warpfunc(wdx,wdy,wdw,wdh,1); // drag done, add to memory + + if (NWarpC == 100) // if full, throw away oldest + { + NWarpC = 99; + for (ii = 0; ii < NWarpC; ii++) + { + WarpCmem[0][ii] = WarpCmem[0][ii+1]; + WarpCmem[1][ii] = WarpCmem[1][ii+1]; + WarpCmem[2][ii] = WarpCmem[2][ii+1]; + WarpCmem[3][ii] = WarpCmem[3][ii+1]; + } + } + + ii = NWarpC; + WarpCmem[0][ii] = wdx; // save drag for undo + WarpCmem[1][ii] = wdy; + WarpCmem[2][ii] = wdw; + WarpCmem[3][ii] = wdh; + NWarpC++; + } + + return; +} + + +// warp image and accumulate warp memory +// mouse at (mx,my) is moved (mw,mh) pixels + +void WarpC_warpfunc(float mx, float my, float mw, float mh, int acc) +{ + int ii, px, py, vstat; + double mag, dispx, dispy; + double d1, d2, d3, d4; + uint16 vpix[3], *pix3; + + edit_zapredo(); // delete redo copy v.10.3 + + d1 = (mx-0) * (mx-0) + (my-0) * (my-0); // distance, mouse to 4 corners + d2 = (E3ww-mx) * (E3ww-mx) + (my-0) * (my-0); + d3 = (E3ww-mx) * (E3ww-mx) + (E3hh-my) * (E3hh-my); + d4 = (mx-0) * (mx-0) + (E3hh-my) * (E3hh-my); + + if (d2 > d1) d1 = d2; // d1 = greatest v.10.11 + if (d3 > d1) d1 = d3; + if (d4 > d1) d1 = d4; + + for (py = 0; py < E3hh; py++) // process all pixels + for (px = 0; px < E3ww; px++) + { + d2 = (px-mx)*(px-mx) + (py-my)*(py-my); + mag = (1.0 - d2 / d1); + mag = mag * mag; // faster than pow(mag,16); + mag = mag * mag; + + dispx = -mw * mag; // displacement = drag * mag + dispy = -mh * mag; + + ii = py * E3ww + px; + + if (acc) { // drag done, accumulate drag sum + WarpCx[ii] += dispx; + WarpCy[ii] += dispy; + continue; + } + + dispx += WarpCx[ii]; // add this drag to prior sum + dispy += WarpCy[ii]; + + vstat = vpixel(E1pxm16,px+dispx,py+dispy,vpix); // input virtual pixel + pix3 = PXMpix(E3pxm16,px,py); // output pixel + if (vstat) { + pix3[0] = vpix[0]; + pix3[1] = vpix[1]; + pix3[2] = vpix[2]; + } + else pix3[0] = pix3[1] = pix3[2] = 0; + } + + CEF->Fmod = 1; + mwpaint2(); // update window + return; +} + + +/**************************************************************************/ + +// warp/distort whole image with a linear transform +// fix perspective problems (e.g. curved walls, leaning buildings) + +float *WarpLx, *WarpLy; // memory of all dragged pixels +float WarpLmem[4][100]; // undo memory, last 100 drags +int NWarpL; // WarpLmem count +int WarpLdrag; +int WarpLww, WarpLhh; + +editfunc EFwarpL; + +void WarpL_warpfunc(float wdx, float wdy, float wdw, float wdh, int acc); +void WarpL_mousefunc(void); + + +void m_warp_linear(GtkWidget *, cchar *) // new v.10.11 +{ + int WarpL_dialog_event(zdialog *zd, cchar *event); + + cchar *WarpL_message = ZTX( + " Pull an image position using the mouse. \n" + " Make multiple mouse pulls until satisfied. \n" + " When finished, press [done]."); + + int px, py, ii; + + zfuncs::F1_help_topic = "warp_linear"; + + EFwarpL.funcname = "warp-linear"; + EFwarpL.Fprev = 1; // use preview + EFwarpL.mousefunc = WarpL_mousefunc; // mouse function + if (! edit_setup(EFwarpL)) return; // setup edit + + zdialog *zd = zdialog_new(ZTX("Warp Image (linear)"),mWin,Bdone,Bcancel,null); + EFwarpL.zd = zd; + + zdialog_add_widget(zd,"label","lab1","dialog",WarpL_message,"space=5"); + zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=10"); + zdialog_add_widget(zd,"button","undolast","hb1",Bundolast,"space=5"); + zdialog_add_widget(zd,"button","undoall","hb1",Bundoall,"space=5"); + zdialog_add_widget(zd,"hbox","hb2","dialog",0,"space=10"); + zdialog_add_widget(zd,"button","grid","hb2",ZTX("Grid"),"space=10"); + + load_grid(warpL_grid); // load grid preferences v.11.11 + + zdialog_help(zd,"warp_linear"); // zdialog help topic v.11.08 + zdialog_run(zd,WarpL_dialog_event,"save"); // run dialog, parallel v.11.07 + + NWarpL = WarpLdrag = 0; // no drag data + + WarpLx = (float *) zmalloc(E3ww * E3hh * sizeof(float),"warpL"); // get memory for pixel displacements + WarpLy = (float *) zmalloc(E3ww * E3hh * sizeof(float),"warpL"); + + for (py = 0; py < E3hh; py++) // no pixel displacements + for (px = 0; px < E3ww; px++) + { + ii = py * E3ww + px; + WarpLx[ii] = WarpLy[ii] = 0.0; + } + + WarpLww = E3ww; // preview dimensions + WarpLhh = E3hh; + + takeMouse(zd,WarpL_mousefunc,dragcursor); // connect mouse function v.11.03 + return; +} + + +// dialog event and completion callback function + +int WarpL_dialog_event(zdialog * zd, cchar *event) +{ + int px, py, ii; + float wdx, wdy, wdw, wdh; + int fpx, fpy, epx, epy, vstat; + double scale, dispx, dispy; + uint16 vpix[3], *pix3; + + if (zd->zstat) goto complete; + + if (strEqu(event,"undolast")) + { + if (NWarpL == 1) event = "undoall"; + else if (NWarpL) { // undo most recent drag + ii = --NWarpL; + wdx = WarpLmem[0][ii]; + wdy = WarpLmem[1][ii]; + wdw = WarpLmem[2][ii]; + wdh = WarpLmem[3][ii]; + WarpL_warpfunc(wdx,wdy,-wdw,-wdh,0); // undrag image + WarpL_warpfunc(wdx,wdy,-wdw,-wdh,1); // undrag memory + } + } + + if (strEqu(event,"undoall")) // undo all drags + { + NWarpL = 0; // erase undo memory + + for (py = 0; py < E3hh; py++) // reset pixel displacements + for (px = 0; px < E3ww; px++) + { + ii = py * E3ww + px; + WarpLx[ii] = WarpLy[ii] = 0.0; + } + edit_reset(); // restore image 1 v.10.3 + } + + if (strEqu(event,"grid")) m_gridlines(0,0); // grid dialog v.11.11 + + if (strstr("KB G KB g",event)) // G key, toggle grid v.11.11 + toggle_grid(2); + + return 1; + +complete: + + save_grid(warpL_grid); // save grid preferences v.11.11 + Fgrid = 0; // grid off + + if (zd->zstat != 1) edit_cancel(EFwarpL); + else if (NWarpL == 0) edit_cancel(EFwarpL); + else + { + edit_fullsize(); // get full-size E1/E3 + + scale = 1.0 * (E3ww + E3hh) / (WarpLww + WarpLhh); + + for (fpy = 0; fpy < E3hh; fpy++) // scale net pixel displacements + for (fpx = 0; fpx < E3ww; fpx++) // to full image size + { + epx = WarpLww * fpx / E3ww; + epy = WarpLhh * fpy / E3hh; + ii = epy * WarpLww + epx; + dispx = WarpLx[ii] * scale; + dispy = WarpLy[ii] * scale; + + vstat = vpixel(E1pxm16,fpx+dispx,fpy+dispy,vpix); // input virtual pixel + pix3 = PXMpix(E3pxm16,fpx,fpy); // output pixel + if (vstat) { + pix3[0] = vpix[0]; + pix3[1] = vpix[1]; + pix3[2] = vpix[2]; + } + else pix3[0] = pix3[1] = pix3[2] = 0; + } + + edit_done(EFwarpL); + } + + zfree(WarpLx); // release memory + zfree(WarpLy); + return 0; +} + + +// WarpL mouse function + +void WarpL_mousefunc(void) +{ + static float wdx, wdy, wdw, wdh; + int ii; + + if (Mxdrag || Mydrag) // mouse drag underway + { + wdx = Mxdown; // drag origin, window coordinates + wdy = Mydown; + wdw = Mxdrag - Mxdown; // drag increment + wdh = Mydrag - Mydown; + WarpL_warpfunc(wdx,wdy,wdw,wdh,0); // drag image + WarpLdrag = 1; + return; + } + + else if (WarpLdrag) + { + WarpLdrag = 0; + WarpL_warpfunc(wdx,wdy,wdw,wdh,1); // drag done, add to memory + + if (NWarpL == 100) // if full, throw away oldest + { + NWarpL = 99; + for (ii = 0; ii < NWarpL; ii++) + { + WarpLmem[0][ii] = WarpLmem[0][ii+1]; + WarpLmem[1][ii] = WarpLmem[1][ii+1]; + WarpLmem[2][ii] = WarpLmem[2][ii+1]; + WarpLmem[3][ii] = WarpLmem[3][ii+1]; + } + } + + ii = NWarpL; + WarpLmem[0][ii] = wdx; // save drag for undo + WarpLmem[1][ii] = wdy; + WarpLmem[2][ii] = wdw; + WarpLmem[3][ii] = wdh; + NWarpL++; + } + + return; +} + + +// warp image and accumulate warp memory +// mouse at (mx,my) is moved (mw,mh) pixels + +void WarpL_warpfunc(float mx, float my, float mw, float mh, int acc) +{ + int ii, px, py, vstat; + double mag, dispx, dispy; + double d1, d2, d3, d4; + uint16 vpix[3], *pix3; + + edit_zapredo(); // delete redo copy v.10.3 + + d1 = (mx-0) * (mx-0) + (my-0) * (my-0); // distance, mouse to 4 corners + d2 = (E3ww-mx) * (E3ww-mx) + (my-0) * (my-0); + d3 = (E3ww-mx) * (E3ww-mx) + (E3hh-my) * (E3hh-my); + d4 = (mx-0) * (mx-0) + (E3hh-my) * (E3hh-my); + + if (d2 > d1) d1 = d2; // d1 = greatest v.10.11 + if (d3 > d1) d1 = d3; + if (d4 > d1) d1 = d4; + + d1 = sqrt(d1); + + for (py = 0; py < E3hh; py++) // process all pixels + for (px = 0; px < E3ww; px++) + { + d2 = (px-mx)*(px-mx) + (py-my)*(py-my); + d2 = sqrt(d2); + mag = (1.0 - d2 / d1); + + dispx = -mw * mag; // displacement = drag * mag + dispy = -mh * mag; + + ii = py * E3ww + px; + + if (acc) { // drag done, accumulate drag sum + WarpLx[ii] += dispx; + WarpLy[ii] += dispy; + continue; + } + + dispx += WarpLx[ii]; // add this drag to prior sum + dispy += WarpLy[ii]; + + vstat = vpixel(E1pxm16,px+dispx,py+dispy,vpix); // input virtual pixel + pix3 = PXMpix(E3pxm16,px,py); // output pixel + if (vstat) { + pix3[0] = vpix[0]; + pix3[1] = vpix[1]; + pix3[2] = vpix[2]; + } + else pix3[0] = pix3[1] = pix3[2] = 0; + } + + CEF->Fmod = 1; + mwpaint2(); // update window + return; +} + + +/**************************************************************************/ + +// warp/distort whole image using affine transform +// (straight lines remain straight) + +double WarpF_old[3][2]; // 3 original image points +double WarpF_new[3][2]; // corresponding warped points +double WarpF_coeff[6]; // transform coefficients +double WarpF_Icoeff[6]; // inverse transform coefficients +int WarpF_ftf; // first time flag + +editfunc EFwarpF; + +void WarpF_warpfunc(); // image warp function +void WarpF_mousefunc(void); +void WarpF_affine(double po[3][2], double pn[3][2], double coeff[6]); // compute affine transform coefficients +void WarpF_invert(double coeff[6], double Icoeff[6]); // compute reverse transform coefficients + + +void m_warp_affine(GtkWidget *, cchar *) +{ + int WarpF_dialog_event(zdialog *zd, cchar *event); + + cchar *WarpF_message = ZTX( + " Pull on an image corner using the mouse. \n" + " Make multiple mouse pulls until satisfied. \n" + " When finished, press [done]."); + + zfuncs::F1_help_topic = "warp_affine"; + + EFwarpF.funcname = "warp-affine"; + EFwarpF.Fprev = 1; // use preview + EFwarpF.mousefunc = WarpF_mousefunc; // mouse function + if (! edit_setup(EFwarpF)) return; // setup edit + + zdialog *zd = zdialog_new(ZTX("Warp Image (affine)"),mWin,Bdone,Bcancel,null); + EFwarpF.zd = zd; + + zdialog_add_widget(zd,"label","lab1","dialog",WarpF_message,"space=5"); + zdialog_add_widget(zd,"hbox","hb2","dialog",0,"space=10"); + zdialog_add_widget(zd,"button","grid","hb2",ZTX("Grid"),"space=10"); + + load_grid(warpF_grid); // load grid preferences v.11.11 + + zdialog_help(zd,"warp_affine"); // zdialog help topic v.11.08 + zdialog_run(zd,WarpF_dialog_event,"save"); // run dialog, parallel v.11.07 + + WarpF_ftf = 1; // 1st warp flag + + takeMouse(zd,WarpF_mousefunc,dragcursor); // connect mouse function v.11.03 + return; +} + + +// dialog event and completion callback function + +int WarpF_dialog_event(zdialog *zd, cchar *event) +{ + double scale; + int ww, hh; + + if (strEqu(event,"grid")) m_gridlines(0,0); // grid dialog v.11.11 + + if (strstr("KB G KB g",event)) // G key, toggle grid v.11.11 + toggle_grid(2); + + if (! zd->zstat) return 1; // wait for completion + + save_grid(warpF_grid); // save grid preferences v.11.11 + Fgrid = 0; // grid off + + if (zd->zstat != 1 || ! CEF->Fmod) { + edit_cancel(EFwarpF); // bugfix v.11.11 + return 0; + } + + ww = E3ww; // preview image dimensions + hh = E3hh; + + edit_fullsize(); // get full-size images + + scale = 1.0 * (E3ww + E3hh) / (ww + hh); // preview to full-size scale factor + + WarpF_old[0][0] = WarpF_old[0][0] * scale; // re-scale new and old points + WarpF_old[0][1] = WarpF_old[0][1] * scale; + WarpF_old[1][0] = WarpF_old[1][0] * scale; + WarpF_old[1][1] = WarpF_old[1][1] * scale; + WarpF_old[2][0] = WarpF_old[2][0] * scale; + WarpF_old[2][1] = WarpF_old[2][1] * scale; + + WarpF_new[0][0] = WarpF_new[0][0] * scale; + WarpF_new[0][1] = WarpF_new[0][1] * scale; + WarpF_new[1][0] = WarpF_new[1][0] * scale; + WarpF_new[1][1] = WarpF_new[1][1] * scale; + WarpF_new[2][0] = WarpF_new[2][0] * scale; + WarpF_new[2][1] = WarpF_new[2][1] * scale; + + WarpF_warpfunc(); // warp full-size image + edit_done(EFwarpF); + + return 0; +} + + +// WarpF mouse function + +void WarpF_mousefunc(void) +{ + int mdx1, mdy1, mdx2, mdy2; + double x1o, y1o, x2o, y2o, x3o, y3o; + double x1n, y1n, x2n, y2n, x3n, y3n; + double a, b, c, d, e, f; + + if (Mxdrag + Mydrag == 0) return; + + mdx1 = Mxdown; // mouse drag origin + mdy1 = Mydown; + mdx2 = Mxdrag; // mouse drag position + mdy2 = Mydrag; + + Mxdown = Mxdrag; // reset origin for next time + Mydown = Mydrag; + + x1n = mdx1; // point 1 = drag origin + y1n = mdy1; + x2n = E3ww - x1n; // point 2 = mirror of point1 + y2n = E3hh - y1n; + x3n = E3ww * (y2n / E3hh); + y3n = E3hh * (1.0 - (x2n / E3ww)); + + if (WarpF_ftf) // first warp + { + WarpF_ftf = 0; + x1o = x1n; // old = current positions + y1o = y1n; + x2o = x2n; + y2o = y2n; + x3o = x3n; + y3o = y3n; + } + else + { + WarpF_invert(WarpF_coeff,WarpF_Icoeff); // get inverse coefficients + a = WarpF_Icoeff[0]; + b = WarpF_Icoeff[1]; + c = WarpF_Icoeff[2]; + d = WarpF_Icoeff[3]; + e = WarpF_Icoeff[4]; + f = WarpF_Icoeff[5]; + + x1o = a * x1n + b * y1n + c; // compute old from current positions + y1o = d * x1n + e * y1n + f; + x2o = a * x2n + b * y2n + c; + y2o = d * x2n + e * y2n + f; + x3o = a * x3n + b * y3n + c; + y3o = d * x3n + e * y3n + f; + } + + WarpF_old[0][0] = x1o; // set up 3 old points and corresponding + WarpF_old[0][1] = y1o; // new points for affine translation + WarpF_old[1][0] = x2o; + WarpF_old[1][1] = y2o; + WarpF_old[2][0] = x3o; + WarpF_old[2][1] = y3o; + + x1n = mdx2; // point 1 new position = drag position + y1n = mdy2; + x2n = E3ww - x1n; // point 2 new = mirror of point1 new + y2n = E3hh - y1n; + + WarpF_new[0][0] = x1n; // 3 new points + WarpF_new[0][1] = y1n; + WarpF_new[1][0] = x2n; + WarpF_new[1][1] = y2n; + WarpF_new[2][0] = x3n; + WarpF_new[2][1] = y3n; + + WarpF_warpfunc(); // do the warp + + return; +} + + +// warp image and accumulate warp memory + +void WarpF_warpfunc() +{ + double a, b, c, d, e, f; + int px3, py3, vstat; + double px1, py1; + uint16 vpix1[3], *pix3; + + edit_zapredo(); // delete redo copy v.10.3 + + WarpF_affine(WarpF_old, WarpF_new, WarpF_coeff); // get coefficients for forward transform + WarpF_invert(WarpF_coeff, WarpF_Icoeff); // get coefficients for reverse transform + + a = WarpF_Icoeff[0]; // coefficients to map output pixels + b = WarpF_Icoeff[1]; // to corresponding input pixels + c = WarpF_Icoeff[2]; + d = WarpF_Icoeff[3]; + e = WarpF_Icoeff[4]; + f = WarpF_Icoeff[5]; + + for (py3 = 0; py3 < E3hh; py3++) // loop all output pixels + for (px3 = 0; px3 < E3ww; px3++) + { + px1 = a * px3 + b * py3 + c; // corresponding input pixel + py1 = d * px3 + e * py3 + f; + + vstat = vpixel(E1pxm16,px1,py1,vpix1); // input virtual pixel + pix3 = PXMpix(E3pxm16,px3,py3); // output pixel + + if (vstat) { + pix3[0] = vpix1[0]; + pix3[1] = vpix1[1]; + pix3[2] = vpix1[2]; + } + else pix3[0] = pix3[1] = pix3[2] = 0; + } + + CEF->Fmod = 1; + mwpaint2(); // update window + return; +} + + +/************************************************************************** + + Compute affine transformation of an image (warp image). + + Given 3 new (warped) positions for 3 image points, derive the + coefficients of the translation function to warp the entire image. + + Inputs: + pold[3][2] (x,y) coordinates for 3 points in original image + pnew[3][2] (x,y) coordinates for same points in warped image + + Output: + coeff[6] coefficients of translation function which can be used + to convert all image points to their warped positions + + If coeff[6] = (a, b, c, d, e, f) then the following formula + can be used to convert an image point to its warped position: + + Xnew = a * Xold + b * Yold + c + Ynew = d * Xold + e * Yold + f + +***************************************************************************/ + +void WarpF_affine(double pold[3][2], double pnew[3][2], double coeff[6]) +{ + double x11, y11, x12, y12, x13, y13; // original points + double x21, y21, x22, y22, x23, y23; // moved points + double a, b, c, d, e, f; // coefficients + double A1, A2, B1, B2, C1, C2; + + x11 = pold[0][0]; + y11 = pold[0][1]; + x12 = pold[1][0]; + y12 = pold[1][1]; + x13 = pold[2][0]; + y13 = pold[2][1]; + + x21 = pnew[0][0]; + y21 = pnew[0][1]; + x22 = pnew[1][0]; + y22 = pnew[1][1]; + x23 = pnew[2][0]; + y23 = pnew[2][1]; + + A1 = x11 - x12; + A2 = x12 - x13; + B1 = y11 - y12; + B2 = y12 - y13; + C1 = x21 - x22; + C2 = x22 - x23; + + a = (B1 * C2 - B2 * C1) / (A2 * B1 - A1 * B2); + b = (A1 * C2 - A2 * C1) / (A1 * B2 - A2 * B1); + c = x23 - a * x13 - b * y13; + + C1 = y21 - y22; + C2 = y22 - y23; + + d = (B1 * C2 - B2 * C1) / (A2 * B1 - A1 * B2); + e = (A1 * C2 - A2 * C1) / (A1 * B2 - A2 * B1); + f = y23 - d * x13 - e * y13; + + coeff[0] = a; + coeff[1] = b; + coeff[2] = c; + coeff[3] = d; + coeff[4] = e; + coeff[5] = f; + + return; +} + + +/************************************************************************** + + Invert affine transform + + Input: + coeff[6] coefficients of translation function to convert + image points to their warped positions + Output: + Icoeff[6] coefficients of translation function to convert + warped image points to their original positions + + If Icoeff[6] = (a, b, c, d, e, f) then the following formula can be + used to translate a warped image point to its original position: + + Xold = a * Xnew + b * Ynew + c + Yold = d * Xnew + e * Ynew + f + +***************************************************************************/ + +void WarpF_invert(double coeff[6], double Icoeff[6]) +{ + double a, b, c, d, e, f, Z; + + a = coeff[0]; + b = coeff[1]; + c = coeff[2]; + d = coeff[3]; + e = coeff[4]; + f = coeff[5]; + + Z = 1.0 / (a * e - b * d); + + Icoeff[0] = e * Z; + Icoeff[1] = - b * Z; + Icoeff[2] = Z * (b * f - c * e); + Icoeff[3] = - d * Z; + Icoeff[4] = a * Z; + Icoeff[5] = Z * (c * d - a * f); + + return; +} + + + Binary files /tmp/tO1AdX0GAK/fotoxx-11.11.1/icons/fotoxx128.png and /tmp/PEei9XmU3C/fotoxx-12.01.2/icons/fotoxx128.png differ Binary files /tmp/tO1AdX0GAK/fotoxx-11.11.1/icons/fotoxx16.png and /tmp/PEei9XmU3C/fotoxx-12.01.2/icons/fotoxx16.png differ Binary files /tmp/tO1AdX0GAK/fotoxx-11.11.1/icons/fotoxx24.png and /tmp/PEei9XmU3C/fotoxx-12.01.2/icons/fotoxx24.png differ Binary files /tmp/tO1AdX0GAK/fotoxx-11.11.1/icons/fotoxx32.png and /tmp/PEei9XmU3C/fotoxx-12.01.2/icons/fotoxx32.png differ Binary files /tmp/tO1AdX0GAK/fotoxx-11.11.1/icons/fotoxx48.png and /tmp/PEei9XmU3C/fotoxx-12.01.2/icons/fotoxx48.png differ Binary files /tmp/tO1AdX0GAK/fotoxx-11.11.1/icons/fotoxx64.png and /tmp/PEei9XmU3C/fotoxx-12.01.2/icons/fotoxx64.png differ Binary files /tmp/tO1AdX0GAK/fotoxx-11.11.1/icons/fotoxx.png and /tmp/PEei9XmU3C/fotoxx-12.01.2/icons/fotoxx.png differ diff -Nru fotoxx-11.11.1/locales/de/fotoxx.po fotoxx-12.01.2/locales/de/fotoxx.po --- fotoxx-11.11.1/locales/de/fotoxx.po 2011-11-05 05:30:37.000000000 +0000 +++ fotoxx-12.01.2/locales/de/fotoxx.po 1970-01-01 00:00:00.000000000 +0000 @@ -1,2209 +0,0 @@ -# German translations for fotoxx package. -# Copyright (C) 2009 THE fotoxx'S COPYRIGHT HOLDER -# This file is distributed under the same license as the fotoxx package. -# -# -msgid "" -msgstr "" -"Project-Id-Version: fotoxx 6.0\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2011-11-05 05:48+0100\n" -"PO-Revision-Date: 2009-03-06 09:57+0100\n" -"Last-Translator: Justa\n" -"Language-Team: German\n" -"Language: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#: fotoxx-11.11.1.cc:179 -msgid "File" -msgstr "Datei" - -#: fotoxx-11.11.1.cc:180 fotoxx-11.11.1.cc:316 -msgid "Image Gallery" -msgstr "Bildergalerie" - -#: fotoxx-11.11.1.cc:181 -msgid "Clone 50/50" -msgstr "50/50 klonen" - -#: fotoxx-11.11.1.cc:182 -msgid "Clone Overlay" -msgstr "Überlagernd klonen" - -#: fotoxx-11.11.1.cc:183 fotoxx-11.11.1.cc:317 fotoxx-11.11.1.cc:2272 -#: fotoxx-11.11.1.cc:2444 -msgid "Open Image File" -msgstr "Bilddatei öffnen" - -#: fotoxx-11.11.1.cc:184 -msgid "Open in New Window" -msgstr "im neuen Fenster öffnen" - -#: fotoxx-11.11.1.cc:185 fotoxx-11.11.1.cc:318 -msgid "Open Previous File" -msgstr "Vorherige Bilddatei öffnen" - -#: fotoxx-11.11.1.cc:186 -msgid "Open Recent File" -msgstr "zuletzt benutzte Dateien" - -#: fotoxx-11.11.1.cc:187 fotoxx-11.11.1.cc:326 -msgid "Save to Same File" -msgstr "in gleicher Datei speichern" - -#: fotoxx-11.11.1.cc:188 fotoxx-11.11.1.cc:327 -msgid "Save to New Version" -msgstr "in neuer Version speichern" - -#: fotoxx-11.11.1.cc:189 fotoxx-11.11.1.cc:328 -msgid "Save to New File" -msgstr "in neuer Datei speichern" - -#: fotoxx-11.11.1.cc:190 fotoxx-11.11.1.cc:2990 -msgid "Create Blank Image" -msgstr "Leerbild erstellen" - -#: fotoxx-11.11.1.cc:191 -msgid "Trash Image File" -msgstr "Bilddatei in den Abfall" - -#: fotoxx-11.11.1.cc:192 fotoxx-11.11.1.cc:3216 -msgid "Rename Image File" -msgstr "Bilddatei umbenennen" - -#: fotoxx-11.11.1.cc:193 -msgid "Batch Rename Files" -msgstr "Bilddateien umbenennen" - -#: fotoxx-11.11.1.cc:194 -msgid "Print Image File" -msgstr "Bilddatei drucken" - -#: fotoxx-11.11.1.cc:195 fotoxx-11.11.1.cc:332 -msgid "Quit fotoxx" -msgstr "fotoxx beenden" - -#: fotoxx-11.11.1.cc:197 -msgid "Tools" -msgstr "Werkzeuge" - -#: fotoxx-11.11.1.cc:198 fotoxx_tools.cc:70 -msgid "Manage Collections" -msgstr "Sammlungen verwalten" - -#: fotoxx-11.11.1.cc:199 fotoxx_tools.cc:373 -msgid "Move Collections" -msgstr "Sammlungen versetzen" - -#: fotoxx-11.11.1.cc:200 -msgid "Check Monitor" -msgstr "Monitor prüfen" - -#: fotoxx-11.11.1.cc:201 fotoxx_tools.cc:550 -msgid "Monitor Gamma" -msgstr "Bildschirm-Gamma" - -#: fotoxx-11.11.1.cc:202 -msgid "Brightness Graph" -msgstr "Helligkeitsdiagramm" - -#: fotoxx-11.11.1.cc:203 fotoxx_tools.cc:819 -msgid "Slide Show" -msgstr "Dia-Show" - -#: fotoxx-11.11.1.cc:204 fotoxx_tools.cc:1668 -msgid "Show RGB" -msgstr "RGB-Werte zeigen" - -#: fotoxx-11.11.1.cc:205 fotoxx_tools.cc:1962 -msgid "Grid Lines" -msgstr "Gitterlinien" - -#: fotoxx-11.11.1.cc:206 fotoxx_tools.cc:2135 -msgid "Lens Parameters" -msgstr "Objektivparameter" - -#: fotoxx-11.11.1.cc:207 -msgid "Change Language" -msgstr "Sprache wechseln" - -#: fotoxx-11.11.1.cc:209 -msgid "Add Menu and Launcher" -msgstr "Menu und Starter addieren" - -#: fotoxx-11.11.1.cc:210 -msgid "Convert RAW files" -msgstr "RAW-Dateien konvertieren" - -#: fotoxx-11.11.1.cc:211 -msgid "Burn Images to CD/DVD" -msgstr "Bilder auf CD/DVD brennen" - -#: fotoxx-11.11.1.cc:212 fotoxx_tools.cc:2460 -msgid "E-mail Images" -msgstr "Bilder E-mailen" - -#: fotoxx-11.11.1.cc:213 fotoxx_tools.cc:2783 -msgid "Synchronize Files" -msgstr "Dateien synchronisieren" - -#: fotoxx-11.11.1.cc:214 fotoxx_tools.cc:3376 -msgid "Toolbar Style" -msgstr "Symbolleiste-Stil" - -#: fotoxx-11.11.1.cc:215 -msgid "Memory Usage" -msgstr "Speicherbelegung" - -#: fotoxx-11.11.1.cc:218 -msgid "Edit Caption/Comments" -msgstr "Titel/Kommentare bearbeiten" - -#: fotoxx-11.11.1.cc:219 fotoxx_info.cc:156 -msgid "Edit Tags" -msgstr "Tags bearbeiten" - -#: fotoxx-11.11.1.cc:220 fotoxx_info.cc:345 -msgid "Manage Tags" -msgstr "Tags verwalten" - -#: fotoxx-11.11.1.cc:221 fotoxx_info.cc:1345 -msgid "Batch Add Tags" -msgstr "Mehrere Tags zuweisen" - -#: fotoxx-11.11.1.cc:222 fotoxx_info.cc:1547 -msgid "Batch Delete Tag" -msgstr "Tag in Bilder löschen" - -#: fotoxx-11.11.1.cc:223 -msgid "View Info (short)" -msgstr "Info ansehen (kurz)" - -#: fotoxx-11.11.1.cc:224 -msgid "View Info (long)" -msgstr "Info ansehen (lang)" - -#: fotoxx-11.11.1.cc:225 fotoxx_info.cc:1883 -msgid "Edit Info" -msgstr "Info bearbeiten" - -#: fotoxx-11.11.1.cc:226 fotoxx_info.cc:1981 -msgid "Delete Info" -msgstr "Info löschen" - -#: fotoxx-11.11.1.cc:227 -msgid "Search Images" -msgstr "Bilddatei durchsuchen" - -#: fotoxx-11.11.1.cc:229 fotoxx-11.11.1.cc:230 -msgid "Select" -msgstr "Auswählen" - -#: fotoxx-11.11.1.cc:231 -msgid "Show" -msgstr "Zeigen" - -#: fotoxx-11.11.1.cc:232 -msgid "Hide" -msgstr "Ausblenden" - -#: fotoxx-11.11.1.cc:233 -msgid "Enable" -msgstr "Aktivieren" - -#: fotoxx-11.11.1.cc:234 -msgid "Disable" -msgstr "Ausschalten" - -#: fotoxx-11.11.1.cc:235 -msgid "Invert" -msgstr "Invertieren" - -#: fotoxx-11.11.1.cc:236 -msgid "Unselect" -msgstr "Deselektieren" - -#: fotoxx-11.11.1.cc:237 -msgid "Copy" -msgstr "Kopieren" - -#: fotoxx-11.11.1.cc:238 -msgid "Paste" -msgstr "Einfügen" - -#: fotoxx-11.11.1.cc:239 fotoxx-11.11.1.cc:317 fotoxx_retouch.cc:2314 -#: fotoxx_retouch.cc:2319 -msgid "Open" -msgstr "Öffnen" - -#: fotoxx-11.11.1.cc:240 fotoxx-11.11.1.cc:326 -msgid "Save" -msgstr "Speichern" - -#: fotoxx-11.11.1.cc:241 fotoxx_area.cc:2215 -msgid "Select Whole Image" -msgstr "Gesamtbild auswählen" - -#: fotoxx-11.11.1.cc:242 -msgid "Select and Edit" -msgstr "Auswählen und bearbeiten" - -#: fotoxx-11.11.1.cc:244 -msgid "Transform" -msgstr "Umwandeln" - -#: fotoxx-11.11.1.cc:245 fotoxx_transform.cc:60 -msgid "Rotate Image" -msgstr "Bild drehen" - -#: fotoxx-11.11.1.cc:246 fotoxx_transform.cc:346 -msgid "Trim Image" -msgstr "Bild zuschneiden" - -#: fotoxx-11.11.1.cc:247 fotoxx_transform.cc:972 -msgid "Resize Image" -msgstr "Bildgröße verändern" - -#: fotoxx-11.11.1.cc:248 -msgid "Batch Resize/Export" -msgstr "Dateiengrößen verändern/auslagern" - -#: fotoxx-11.11.1.cc:249 fotoxx_transform.cc:1436 -msgid "Annotate Image" -msgstr "Bild kommentieren" - -#: fotoxx-11.11.1.cc:250 fotoxx_transform.cc:2193 -msgid "Flip Image" -msgstr "Bild spiegeln" - -#: fotoxx-11.11.1.cc:251 fotoxx_transform.cc:2303 -msgid "Make Negative" -msgstr "Negativ erstellen" - -#: fotoxx-11.11.1.cc:252 fotoxx_transform.cc:2420 -msgid "Unbend Image" -msgstr "Bild entkrümmen" - -#: fotoxx-11.11.1.cc:253 fotoxx_transform.cc:2704 -msgid "Keystone Correction" -msgstr "Schlussstein-Korrektur" - -#: fotoxx-11.11.1.cc:254 fotoxx_transform.cc:3013 -msgid "Warp Image (area)" -msgstr "Bild krümmen (Ausschnitt)" - -#: fotoxx-11.11.1.cc:255 fotoxx_transform.cc:3255 -msgid "Warp Image (curved)" -msgstr "Bild krümmen (kurvig)" - -#: fotoxx-11.11.1.cc:256 fotoxx_transform.cc:3518 -msgid "Warp Image (linear)" -msgstr "Bild krümmen (linear)" - -#: fotoxx-11.11.1.cc:257 fotoxx_transform.cc:3782 -msgid "Warp Image (affine)" -msgstr "Bild krümmen (affine)" - -#: fotoxx-11.11.1.cc:259 -msgid "Retouch" -msgstr "Retuschieren" - -#: fotoxx-11.11.1.cc:260 -msgid "Brightness/Color" -msgstr "Helligkeit/Farbe" - -#: fotoxx-11.11.1.cc:261 -msgid "Gamma Curves" -msgstr "Gamma Kurven" - -#: fotoxx-11.11.1.cc:262 -msgid "Expand Brightness" -msgstr "Helligkeit ausdehnen" - -#: fotoxx-11.11.1.cc:263 -msgid "Flatten Brightness" -msgstr "Helligkeit ausgleichen" - -#: fotoxx-11.11.1.cc:264 -msgid "Brightness Ramp" -msgstr "Helligkeit rampen" - -#: fotoxx-11.11.1.cc:265 fotoxx_retouch.cc:1729 -msgid "Tone Mapping" -msgstr "Tone Mapping" - -#: fotoxx-11.11.1.cc:266 -msgid "White Balance" -msgstr "Weißabgleich" - -#: fotoxx-11.11.1.cc:267 -msgid "Match Colors" -msgstr "Farben anpassen" - -#: fotoxx-11.11.1.cc:269 fotoxx_retouch.cc:2941 -msgid "Revise RGB" -msgstr "RGB revidieren" - -#: fotoxx-11.11.1.cc:270 -msgid "Red Eyes" -msgstr "Rote Augen" - -#: fotoxx-11.11.1.cc:271 -msgid "Blur Image" -msgstr "Bild verwischen" - -#: fotoxx-11.11.1.cc:272 fotoxx_retouch.cc:4077 -msgid "Sharpen Image" -msgstr "Bild schärfen" - -#: fotoxx-11.11.1.cc:273 -msgid "Reduce Noise" -msgstr "Rauschen vermindern" - -#: fotoxx-11.11.1.cc:274 fotoxx_retouch.cc:4881 -msgid "Smart Erase" -msgstr "Smart löschen" - -#: fotoxx-11.11.1.cc:275 fotoxx_retouch.cc:5271 -msgid "Remove Dust" -msgstr "Staub entfernen" - -#: fotoxx-11.11.1.cc:276 fotoxx_retouch.cc:5877 -msgid "Edit Pixels" -msgstr "Pixel bearbeiten" - -#: fotoxx-11.11.1.cc:278 -msgid "Art" -msgstr "Kunst" - -#: fotoxx-11.11.1.cc:279 -msgid "Color Depth" -msgstr "Farbtiefe" - -#: fotoxx-11.11.1.cc:280 -msgid "Drawing" -msgstr "Zeichnung" - -#: fotoxx-11.11.1.cc:281 -msgid "Outlines" -msgstr "Umrisse" - -#: fotoxx-11.11.1.cc:282 -msgid "Embossing" -msgstr "Prägung" - -#: fotoxx-11.11.1.cc:283 -msgid "Tiles" -msgstr "Kacheln" - -#: fotoxx-11.11.1.cc:284 -msgid "Dots" -msgstr "Rasterpunkte" - -#: fotoxx-11.11.1.cc:285 -msgid "Painting" -msgstr "Gemälde" - -#: fotoxx-11.11.1.cc:287 -msgid "Combine" -msgstr "Verbund" - -#: fotoxx-11.11.1.cc:288 -msgid "High Dynamic Range" -msgstr "Hoher Dynamikbereich" - -#: fotoxx-11.11.1.cc:289 -msgid "High Depth of Field" -msgstr "Hohe Schärfentiefe" - -#: fotoxx-11.11.1.cc:290 -msgid "Stack / Paint" -msgstr "Stapeln / malen" - -#: fotoxx-11.11.1.cc:291 -msgid "Stack / Noise" -msgstr "Stapeln / Rauschen" - -#: fotoxx-11.11.1.cc:292 -msgid "Panorama" -msgstr "Panorama" - -#: fotoxx-11.11.1.cc:293 -msgid "Vertical Panorama" -msgstr "Vertikales Panorama" - -#: fotoxx-11.11.1.cc:296 -msgid "Edit Plugins" -msgstr "Plugins bearbeiten" - -#: fotoxx-11.11.1.cc:305 fotoxx-11.11.1.cc:333 fotoxx-11.11.1.cc:4616 -msgid "Help" -msgstr "Hilfe" - -#: fotoxx-11.11.1.cc:306 fotoxx-11.11.1.cc:4606 -msgid "About" -msgstr "Über fotoxx" - -#: fotoxx-11.11.1.cc:307 fotoxx-11.11.1.cc:4610 -msgid "User Guide" -msgstr "Benutzeranleitung" - -#: fotoxx-11.11.1.cc:308 fotoxx-11.11.1.cc:4613 -msgid "User Guide Changes" -msgstr "Benutzeranleitung Änderungen" - -#: fotoxx-11.11.1.cc:309 fotoxx-11.11.1.cc:4622 -msgid "Edit Functions Summary" -msgstr "Verarbeitungsfunktionen Übersicht" - -#: fotoxx-11.11.1.cc:310 fotoxx-11.11.1.cc:4625 -msgid "Change Log" -msgstr "Änderungslog" - -#: fotoxx-11.11.1.cc:311 fotoxx-11.11.1.cc:4628 -msgid "Translations" -msgstr "Übersetzungen" - -#: fotoxx-11.11.1.cc:312 fotoxx-11.11.1.cc:4631 -msgid "Home Page" -msgstr "Homepage" - -#: fotoxx-11.11.1.cc:316 -msgid "Gallery" -msgstr "Galerie" - -#: fotoxx-11.11.1.cc:318 fotoxx_transform.cc:995 -msgid "Prev" -msgstr "Vorheriges" - -#: fotoxx-11.11.1.cc:319 -msgid "Next" -msgstr "Nächstes" - -#: fotoxx-11.11.1.cc:319 -msgid "Open Next File" -msgstr "Nächste Bilddatei öffnen" - -#: fotoxx-11.11.1.cc:320 -msgid "Zoom-in (bigger)" -msgstr "Heranzoomen (größer)" - -#: fotoxx-11.11.1.cc:321 -msgid "Zoom-out (smaller)" -msgstr "Herauszoomen (kleiner)" - -#: fotoxx-11.11.1.cc:322 -msgid "Undo" -msgstr "Undo" - -#: fotoxx-11.11.1.cc:322 -msgid "Undo One Edit" -msgstr "Eine Änderung rückgängig machen" - -#: fotoxx-11.11.1.cc:323 -msgid "Redo" -msgstr "Redo" - -#: fotoxx-11.11.1.cc:323 -msgid "Redo One Edit" -msgstr "Verworfene Änderung wieder anwenden" - -#: fotoxx-11.11.1.cc:327 -msgid "Save+V" -msgstr "Speich.V" - -#: fotoxx-11.11.1.cc:328 -msgid "Save+F" -msgstr "Speich.D" - -#: fotoxx-11.11.1.cc:329 -msgid "Move Image to Trash" -msgstr "Bilddatei in den Abfall" - -#: fotoxx-11.11.1.cc:329 -msgid "Trash" -msgstr "Abfall" - -#: fotoxx-11.11.1.cc:332 -msgid "Quit" -msgstr "Beenden" - -#: fotoxx-11.11.1.cc:333 -msgid "Fotoxx Essentials" -msgstr "Fotoxx wichtig" - -#: fotoxx-11.11.1.cc:429 -msgid "first time startup" -msgstr "Das erste Mal Start" - -#: fotoxx-11.11.1.cc:1815 -msgid "Exceed 50 anchor points" -msgstr "50 Ankerpunkte überschritten" - -#: fotoxx-11.11.1.cc:2000 -msgid "load curve from a file" -msgstr "Kurven-Datei öffnen" - -#: fotoxx-11.11.1.cc:2053 -msgid "curve file is invalid" -msgstr "Kurven-Datei ist ungültig" - -#: fotoxx-11.11.1.cc:2058 -msgid "curve file has different no. of curves" -msgstr "Datei Kurvenanzahl stimmt nicht" - -#: fotoxx-11.11.1.cc:2073 -msgid "save curve to a file" -msgstr "Kurven-Datei speichern" - -#: fotoxx-11.11.1.cc:2420 -#, c-format -msgid "" -"Discard special gallery list? \n" -" %s" -msgstr "" -"Spezielle Bildliste abwerfen? \n" -" %s" - -#: fotoxx-11.11.1.cc:2430 fotoxx-11.11.1.cc:4452 -msgid "prior function still active" -msgstr "Vorherige Funktion noch aktiv" - -#: fotoxx-11.11.1.cc:2607 -msgid "Overwrite original file?" -msgstr "Originaldatei überschreiben?" - -#: fotoxx-11.11.1.cc:2608 -msgid "Do not warn again" -msgstr "Nicht wieder warnen" - -#: fotoxx-11.11.1.cc:2624 -msgid "Warning" -msgstr "Warnung" - -#: fotoxx-11.11.1.cc:2747 -msgid "Save File" -msgstr "Datei speichern" - -#: fotoxx-11.11.1.cc:2770 -msgid "quality" -msgstr "Qualität" - -#: fotoxx-11.11.1.cc:2772 -msgid "make current" -msgstr "aktuell machen" - -#: fotoxx-11.11.1.cc:2829 -msgid "jpeg quality must be 1-100" -msgstr "jpeg Qualität muss 1-100 sein" - -#: fotoxx-11.11.1.cc:2851 -#, c-format -msgid "" -"Overwrite file? \n" -" %s" -msgstr "" -"Datei überschreiben? \n" -" %s" - -#: fotoxx-11.11.1.cc:2992 -msgid "file name" -msgstr "Dateiname" - -#: fotoxx-11.11.1.cc:2997 fotoxx_transform.cc:351 -msgid "width" -msgstr "Breite" - -#: fotoxx-11.11.1.cc:3000 fotoxx_transform.cc:354 -msgid "height" -msgstr "Höhe" - -#: fotoxx-11.11.1.cc:3006 fotoxx_art.cc:628 fotoxx_retouch.cc:5881 -msgid "color" -msgstr "Farbe" - -#: fotoxx-11.11.1.cc:3120 -msgid "" -"Linux standard trash is not supported. \n" -"Desktop trash folder will be created." -msgstr "" -"Linux Standard-Abfall nicht unterstützt. \n" -"Desktop Abfall-Ordner wird erstellt." - -#: fotoxx-11.11.1.cc:3138 -msgid "Move read-only file to trash?" -msgstr "Schreibgeschützte Datei in den Abfall?" - -#: fotoxx-11.11.1.cc:3164 -#, c-format -msgid "Cannot create trash folder: %s" -msgstr "Kann Abfallkorb nicht erstellen: %s" - -#: fotoxx-11.11.1.cc:3172 fotoxx-11.11.1.cc:3178 -#, c-format -msgid "error: %s" -msgstr "Fehler: %s" - -#: fotoxx-11.11.1.cc:3221 -msgid "old name" -msgstr "Vorheriger Name" - -#: fotoxx-11.11.1.cc:3222 -msgid "rename to" -msgstr "Umbenennen in" - -#: fotoxx-11.11.1.cc:3223 -msgid "previous" -msgstr "Vorheriges" - -#: fotoxx-11.11.1.cc:3309 -msgid "The target file already exists" -msgstr "Zieldatei existiert schon" - -#: fotoxx-11.11.1.cc:3317 -#, c-format -msgid "" -"Rename failed: \n" -" %s" -msgstr "" -"Umbenennen gescheitert: \n" -" %s" - -#: fotoxx-11.11.1.cc:3365 -msgid "Batch Rename" -msgstr "Bilddateien umbenennen" - -#: fotoxx-11.11.1.cc:3368 fotoxx-11.11.1.cc:3420 fotoxx_info.cc:1513 -#: fotoxx_info.cc:1767 fotoxx_tools.cc:2510 fotoxx_transform.cc:1213 -#, c-format -msgid "%d files selected" -msgstr "%d Dateien ausgewählt" - -#: fotoxx-11.11.1.cc:3370 -msgid "new base name" -msgstr "neue Basisname" - -#: fotoxx-11.11.1.cc:3373 -msgid "starting sequence" -msgstr "Anfangs-Sequenznummer" - -#: fotoxx-11.11.1.cc:3375 -msgid "increment" -msgstr "Zuwachs" - -#: fotoxx-11.11.1.cc:3396 -msgid "select files to rename" -msgstr "Dateien zum Umbenennen auswählen" - -#: fotoxx-11.11.1.cc:3401 -msgid "base name / sequence / increment not reasonable" -msgstr "Basisname / Sequenz / Zuwachs nicht sinnvoll" - -#: fotoxx-11.11.1.cc:3460 -msgid "new file already exists:" -msgstr "Zieldatei existiert schon:" - -#: fotoxx-11.11.1.cc:3468 -msgid "filespec too long:" -msgstr "Dateiname zu lang:" - -#: fotoxx-11.11.1.cc:3479 -msgid "Rename failed:" -msgstr "Umbenennen gescheitert:" - -#: fotoxx-11.11.1.cc:3739 -msgid "Add" -msgstr "Addieren" - -#: fotoxx-11.11.1.cc:3739 -msgid "Remove" -msgstr "Entfernen" - -#: fotoxx-11.11.1.cc:3741 -msgid "menu name" -msgstr "Menuname" - -#: fotoxx-11.11.1.cc:3812 fotoxx-11.11.1.cc:3833 -msgid "Restart Fotoxx to update plugin menu" -msgstr "Fotoxx neu starten um Menus zu aktualisieren" - -#: fotoxx-11.11.1.cc:3927 -msgid "cannot parallel edit" -msgstr "Kann nicht parallel laufen" - -#: fotoxx-11.11.1.cc:3937 -msgid "" -"exiftool is not installed \n" -"edited images will lose EXIF data" -msgstr "" -"EXIFTtool-Paket nicht installiert \n" -"(bearbeitete Bilder verlieren ihre EXIF-Daten!)" - -#: fotoxx-11.11.1.cc:3943 -msgid "Too many edits, please save image" -msgstr "Zuviele Änderungen, bitte Bild speichern" - -#: fotoxx-11.11.1.cc:3948 -msgid "" -"Select area cannot be kept.\n" -"Continue?" -msgstr "" -"Ausschnitt kann nicht behalten werden.\n" -"Fortfahren?" - -#: fotoxx-11.11.1.cc:3956 -msgid "" -"Select area not active.\n" -"Continue?" -msgstr "" -"Ausschnit nicht aktiviert.\n" -"Fortfahren?" - -#: fotoxx-11.11.1.cc:4427 -msgid "Discard edits?" -msgstr "Änderungen verwerfen?" - -#: fotoxx-11.11.1.cc:4428 -msgid "" -"This action will discard current edits.\n" -"Continue to discard edits.\n" -"Go Back to keep edits." -msgstr "" -"Vorgang wird aktuelle Änderungen verwerfen.\n" -"Fortsetzen um diese zu verwerfen.\n" -"Zurückgehen um diese zu behalten." - -#: fotoxx-11.11.1.cc:4431 -msgid "Continue" -msgstr "Fortfahren" - -#: fotoxx-11.11.1.cc:4432 -msgid "Go Back" -msgstr "Zurückgehen" - -#: fotoxx-11.11.1.cc:5240 -msgid "cannot open thumbnail file" -msgstr "Thumbnaildatei nicht lesbar" - -#: fotoxx-11.11.1.cc:5433 fotoxx-11.11.1.cc:5549 -msgid "TIFF open failure" -msgstr "TIFF öffnen Fehler" - -#: fotoxx-11.11.1.cc:5449 -#, c-format -msgid "TIFF bits/color=%d not supported" -msgstr "TIFF Farbtiefe=%d nicht unterstützt" - -#: fotoxx-11.11.1.cc:5464 fotoxx-11.11.1.cc:5502 -msgid "TIFF read failure" -msgstr "TIFF Lesefehler" - -#: fotoxx-11.11.1.cc:5608 -msgid "TIFF write failure" -msgstr "TIFF Schreibfehler" - -#: fotoxx-11.11.1.cc:5638 -msgid "file type not supported" -msgstr "Dateiart nicht unterstützt" - -#: fotoxx-11.11.1.cc:5745 -msgid "pixbuf write failure" -msgstr "Pixbuf Schreibfehler" - -#: fotoxx_area.cc:54 fotoxx_area.cc:2427 -msgid "Select Area for Edits" -msgstr "Ausschnitt für Bearbeitung auswählen" - -#: fotoxx_area.cc:55 fotoxx_area.cc:2428 -msgid "Press F1 for help" -msgstr "F1 für Hilfe drucken" - -#: fotoxx_area.cc:63 -msgid "" -"Select Area not supported \n" -"by this edit function" -msgstr "" -"Ausschnitt nicht unterstützt \n" -"von dieser Bearbeitungsfunktion" - -#: fotoxx_area.cc:99 fotoxx_tools.cc:809 -msgid "rectangle" -msgstr "Rechteck" - -#: fotoxx_area.cc:100 fotoxx_tools.cc:810 -msgid "ellipse" -msgstr "Ellipse" - -#: fotoxx_area.cc:101 -msgid "draw: freehand" -msgstr "Zeichnen: freihand" - -#: fotoxx_area.cc:102 -msgid "draw: follow edge" -msgstr "Zeichnen: Rand folgen" - -#: fotoxx_area.cc:103 -msgid "select by mouse" -msgstr "mit der Maus selektieren" - -#: fotoxx_area.cc:104 -msgid "select by color" -msgstr "nach Farbe selektieren" - -#: fotoxx_area.cc:112 -msgid "radius" -msgstr "Radius" - -#: fotoxx_area.cc:116 -msgid "match" -msgstr "Übereinstimmung" - -#: fotoxx_area.cc:121 -msgid "firewall" -msgstr "Brandmauer" - -#: fotoxx_area.cc:274 fotoxx_area.cc:415 -#, c-format -msgid "exceed %d edits" -msgstr "%d Edits überschritten" - -#: fotoxx_area.cc:992 -msgid "" -"Click one time inside each enclosed area \n" -"(possible gaps in the outline will be found). \n" -"Press F1 for help." -msgstr "" -"Jeden umschlossen Ausschnitt einmal innen anklicken \n" -"(mögliche Lücken im Rand werden gefunden). \n" -"Für Hilfe F1 drucken." - -#: fotoxx_area.cc:1049 -msgid "finish area" -msgstr "Ausschnitt fertigstellen" - -#: fotoxx_area.cc:1083 -msgid "searching" -msgstr "wird gesucht" - -#: fotoxx_area.cc:1155 -msgid "outline has a gap" -msgstr "Umriss hat eine Lücke" - -#: fotoxx_area.cc:1157 -msgid "success" -msgstr "Erfolg" - -#: fotoxx_area.cc:1401 fotoxx_area.cc:1430 -msgid "the area is not finished" -msgstr "Der Ausschnitt ist nicht fertig" - -#: fotoxx_area.cc:1522 -msgid "Edge calculation in progress" -msgstr "Rand Berechnung in Arbeit" - -#: fotoxx_area.cc:1531 -msgid "Area Edge Calc" -msgstr "Ausschnitt Randberechnung" - -#: fotoxx_area.cc:1824 -msgid "position with mouse click/drag" -msgstr "Mit Maus klicken/ziehen positionieren" - -#: fotoxx_area.cc:1848 -msgid "Paste Image" -msgstr "Bild einfügen" - -#: fotoxx_area.cc:1863 -msgid "angle" -msgstr "Winkel" - -#: fotoxx_area.cc:2127 -msgid "load select area from a file" -msgstr "Auschnitt von Datei lesen" - -#: fotoxx_area.cc:2161 -msgid "cannot open .tiff and .info files" -msgstr "Kann .tiff und .info Dateien nicht öffnen" - -#: fotoxx_area.cc:2180 -msgid "save select area to a file" -msgstr "Ausschnitt in Datei speichern" - -#: fotoxx_area.cc:2216 -msgid "Edit Function Amplifier" -msgstr "Bearbeitungs-Verstärker" - -#: fotoxx_area.cc:2459 -msgid "mouse radius" -msgstr "Mausradius" - -#: fotoxx_area.cc:2462 -msgid "power: center" -msgstr "Stärke: Mitte" - -#: fotoxx_area.cc:2464 -msgid "edge" -msgstr "Rand" - -#: fotoxx_area.cc:2468 -msgid "reset area" -msgstr "zurücksetzen" - -#: fotoxx_area.cc:2523 -msgid "start edit function first" -msgstr "Zuerst Bearbeitungsfunktion starten" - -#: fotoxx_art.cc:47 -msgid "Set color depth to 1-16 bits" -msgstr "Farbtiefe auf 1-16 Bits festlegen" - -#: fotoxx_art.cc:57 -msgid "Set Color Depth" -msgstr "Farbtiefe festlegen" - -#: fotoxx_art.cc:171 -msgid "Simulate Drawing" -msgstr "Zeichen Simulieren" - -#: fotoxx_art.cc:213 fotoxx_retouch.cc:1758 -msgid "contrast" -msgstr "Kontrast" - -#: fotoxx_art.cc:215 -msgid "outlines" -msgstr "Umrisse" - -#: fotoxx_art.cc:220 -msgid "pencil" -msgstr "Stift" - -#: fotoxx_art.cc:221 -msgid "chalk" -msgstr "Kreide" - -#: fotoxx_art.cc:381 -msgid "Add Image Outlines" -msgstr "Bildumrisse addieren" - -#: fotoxx_art.cc:394 -msgid "outline threshold" -msgstr "Umriss-Grenzwert" - -#: fotoxx_art.cc:397 -msgid "outline width" -msgstr "Umrissbreite" - -#: fotoxx_art.cc:400 -msgid "image brightness" -msgstr "Bildhelligkeit" - -#: fotoxx_art.cc:611 -msgid "Simulate Embossing" -msgstr "Prägen Simulieren" - -#: fotoxx_art.cc:626 -msgid "depth" -msgstr "Tiefe" - -#: fotoxx_art.cc:821 -msgid "Simulate Tiles" -msgstr "Kacheln Simulieren" - -#: fotoxx_art.cc:825 -msgid "tile size" -msgstr "Kachelgröße" - -#: fotoxx_art.cc:829 -msgid "tile gap" -msgstr "Spaltbreite" - -#: fotoxx_art.cc:1003 -msgid "Convert Image to Dots" -msgstr "Bild in Rasterpunkte umwandeln" - -#: fotoxx_art.cc:1007 -msgid "dot size" -msgstr "Punktgroße" - -#: fotoxx_art.cc:1222 -msgid "Simulate Painting" -msgstr "Malen Simulieren" - -#: fotoxx_art.cc:1226 -msgid "color depth" -msgstr "Farbtiefe" - -#: fotoxx_art.cc:1230 -msgid "patch area goal" -msgstr "Fleckgröße Ziel" - -#: fotoxx_art.cc:1234 -msgid "req. color match" -msgstr "Farbeanpassung" - -#: fotoxx_art.cc:1238 -msgid "borders" -msgstr "Ränder" - -#: fotoxx_comp.cc:1956 fotoxx_comp.cc:1961 fotoxx_comp.cc:2582 -#: fotoxx_comp.cc:2587 fotoxx_comp.cc:3275 fotoxx_comp.cc:3280 -#: fotoxx_comp.cc:3830 fotoxx_comp.cc:3835 -msgid "Select 2 to 9 files" -msgstr "2-9 Dateien auswählen" - -#: fotoxx_comp.cc:1982 fotoxx_comp.cc:2608 fotoxx_comp.cc:3301 -#: fotoxx_comp.cc:3856 -msgid "Images are not all the same size" -msgstr "Bilder sind nicht gleich gross" - -#: fotoxx_comp.cc:2321 -msgid "Adjust Image Contributions" -msgstr "Bild Beiträge einstellen" - -#: fotoxx_comp.cc:2324 fotoxx_retouch.cc:885 -msgid "dark pixels" -msgstr "dunkele Pixel" - -#: fotoxx_comp.cc:2326 -msgid "light pixels" -msgstr "helle Pixel" - -#: fotoxx_comp.cc:2328 fotoxx_info.cc:159 -msgid "file:" -msgstr "Datei:" - -#: fotoxx_comp.cc:2844 -msgid "Paint and Warp Image" -msgstr "Bild malen und krümmen" - -#: fotoxx_comp.cc:2847 fotoxx_comp.cc:3529 fotoxx_comp.cc:4972 -#: fotoxx_comp.cc:5717 -msgid "image" -msgstr "Bild" - -#: fotoxx_comp.cc:2851 fotoxx_retouch.cc:5885 -msgid "paint" -msgstr "malen" - -#: fotoxx_comp.cc:2852 -msgid "warp" -msgstr "Krümmen" - -#: fotoxx_comp.cc:3527 -msgid "Select and Paint Image" -msgstr "Bild auswählen und malen" - -#: fotoxx_comp.cc:4045 -msgid "Adjust Pixel Composition" -msgstr "Pixel Zusammensetzung einstellen" - -#: fotoxx_comp.cc:4297 fotoxx_comp.cc:4302 fotoxx_comp.cc:5186 -#: fotoxx_comp.cc:5191 -msgid "Select 2 to 4 files" -msgstr "2-4 Dateien auswählen" - -#: fotoxx_comp.cc:4374 -msgid "" -"Drag images into rough alignment.\n" -"To rotate, drag from lower edge." -msgstr "" -"Bilder zur Grobabstimmung mit der Maus ziehen.\n" -"Zum Drehen unteren Rand links/rechts ziehen" - -#: fotoxx_comp.cc:4376 -msgid "Search for lens mm and bow" -msgstr "Suche für Brennweite und Krümmung" - -#: fotoxx_comp.cc:4422 fotoxx_comp.cc:5310 -msgid "Pre-align Images" -msgstr "Bilder grob anpassen" - -#: fotoxx_comp.cc:4426 fotoxx_comp.cc:5314 fotoxx_tools.cc:2151 -msgid "lens mm" -msgstr "Objektiv-Brennweite mm" - -#: fotoxx_comp.cc:4430 fotoxx_comp.cc:5318 fotoxx_tools.cc:2156 -msgid "lens bow" -msgstr "Objektivkrümmung" - -#: fotoxx_comp.cc:4432 fotoxx_comp.cc:5320 -msgid "Resize" -msgstr "Größe verändern" - -#: fotoxx_comp.cc:4433 fotoxx_comp.cc:5321 -msgid "resize window" -msgstr "Fenstergröße ändern" - -#: fotoxx_comp.cc:4470 -msgid "use two images only" -msgstr "Zwei Bilder benutzen" - -#: fotoxx_comp.cc:4491 fotoxx_comp.cc:4689 fotoxx_comp.cc:4888 -#: fotoxx_comp.cc:5369 fotoxx_comp.cc:5632 -msgid "Too little overlap, cannot align" -msgstr "Unzureichende Überlappung, Ausrichtung nicht möglich" - -#: fotoxx_comp.cc:4963 fotoxx_comp.cc:5708 -msgid "Match Brightness and Color" -msgstr "Helligkeit und Farbe anpassen" - -#: fotoxx_comp.cc:4987 fotoxx_comp.cc:5732 -msgid "auto color" -msgstr "Auto-Farbe" - -#: fotoxx_comp.cc:4988 fotoxx_comp.cc:5733 -msgid "file color" -msgstr "Datei-Farbe" - -#: fotoxx_comp.cc:5263 -msgid "" -"Drag images into rough alignment.\n" -"To rotate, drag from right edge." -msgstr "" -"Bilder zur Grobabstimmung mit der Maus ziehen.\n" -"Zum Drehen, vom rechten Rand ziehen" - -#: fotoxx_info.cc:70 -msgid "Edit Caption and Comments" -msgstr "Titel und Kommentare bearbeiten" - -#: fotoxx_info.cc:163 -msgid "image date (yyyymmdd)" -msgstr "Bilddatum (jjjjmmtt)" - -#: fotoxx_info.cc:165 -msgid "use last" -msgstr "Letztes" - -#: fotoxx_info.cc:168 -msgid "image stars" -msgstr "Bild-Sterne" - -#: fotoxx_info.cc:186 -msgid "current tags" -msgstr "Aktuelle Tags" - -#: fotoxx_info.cc:191 -msgid "recent tags" -msgstr "Kürzliche Tags" - -#: fotoxx_info.cc:196 fotoxx_info.cc:358 fotoxx_info.cc:1362 -#: fotoxx_info.cc:2290 -msgid "defined tags" -msgstr "Definierte Tags" - -#: fotoxx_info.cc:348 -msgid "category" -msgstr "Gruppe" - -#: fotoxx_info.cc:351 -msgid "tag" -msgstr "Tag" - -#: fotoxx_info.cc:354 -msgid "create" -msgstr "Erstellen" - -#: fotoxx_info.cc:355 -msgid "delete" -msgstr "Löschen" - -#: fotoxx_info.cc:1229 fotoxx_info.cc:1313 -#, c-format -msgid "search index file error: %s" -msgstr "Fehler in Such-Index Datei: %s" - -#: fotoxx_info.cc:1348 -msgid "tags to add" -msgstr "Tags zum Zuweisen" - -#: fotoxx_info.cc:1353 -msgid "create tag" -msgstr "Tag erstellen" - -#: fotoxx_info.cc:1409 fotoxx_info.cc:1602 -#, c-format -msgid "" -"%s \n" -" too many tags" -msgstr "" -"%s \n" -" Zuviele Tags" - -#: fotoxx_info.cc:1550 -msgid "tag to remove" -msgstr "Tag zu entfernen" - -#: fotoxx_info.cc:1554 -msgid "optional replacement" -msgstr "Wahlersatz" - -#: fotoxx_info.cc:1559 fotoxx_tools.cc:2463 -msgid "0 files selected" -msgstr "0 Dateien ausgewählt" - -#: fotoxx_info.cc:1562 -msgid "search all files" -msgstr "Alle Dateien durchsuchen" - -#: fotoxx_info.cc:1647 -msgid "no files selected" -msgstr "Keine Dateien ausgewählt" - -#: fotoxx_info.cc:1653 -msgid "no tag specified" -msgstr "Kein Tag angegeben" - -#: fotoxx_info.cc:1677 fotoxx_info.cc:1706 -msgid "specify tag" -msgstr "Tag angeben" - -#: fotoxx_info.cc:1815 -msgid "View Info" -msgstr "Info ansehen" - -#: fotoxx_info.cc:1983 -msgid "All" -msgstr "Alles" - -#: fotoxx_info.cc:1984 -msgid "One Key:" -msgstr "Ein Key:" - -#: fotoxx_info.cc:2249 -msgid "Search Tags, Comments, File Names" -msgstr "Tags, Kommentare, Dateinamen durchsuchen" - -#: fotoxx_info.cc:2255 -msgid "date range" -msgstr "Datumsbereich" - -#: fotoxx_info.cc:2256 -msgid "stars range" -msgstr "Sterne-Wertebereich" - -#: fotoxx_info.cc:2257 -msgid "search tags" -msgstr "Such-Tags" - -#: fotoxx_info.cc:2258 -msgid "search text" -msgstr "Text durchsuchen" - -#: fotoxx_info.cc:2259 -msgid "file names" -msgstr "Dateinamen" - -#: fotoxx_info.cc:2264 -msgid "(yyyymmdd)" -msgstr "(jjjjmmtt)" - -#: fotoxx_info.cc:2270 -msgid "all/any" -msgstr "alle/irgendeines" - -#: fotoxx_info.cc:2598 -msgid "No matching images found" -msgstr "Keine übereinstimmenden Bilder gefunden" - -#: fotoxx_info.cc:2611 -msgid "No search index file present" -msgstr "Such-Index Datei fehlt" - -#: fotoxx_info.cc:2615 -#, c-format -msgid "Search results file error %s" -msgstr "Suchergebnis-Dateifehler %s" - -#: fotoxx_retouch.cc:55 -msgid "Adjust Brightness and Color" -msgstr "Helligkeit und Farbe abstimmen" - -#: fotoxx_retouch.cc:109 -msgid "small-steps" -msgstr "Kleinschritte" - -#: fotoxx_retouch.cc:118 -msgid "color saturation" -msgstr "Farbsättigung" - -#: fotoxx_retouch.cc:125 -msgid " reset 1 " -msgstr "1 zurücksetzen" - -#: fotoxx_retouch.cc:126 -msgid "reset all" -msgstr "Alle zurücksetzen" - -#: fotoxx_retouch.cc:598 -msgid "adjust image gamma" -msgstr "Bildgamma justieren" - -#: fotoxx_retouch.cc:884 -msgid "Expand Brightness Range" -msgstr "Helligkeitsbreite ausdehned" - -#: fotoxx_retouch.cc:886 -msgid "bright pixels" -msgstr "Helle Pixel" - -#: fotoxx_retouch.cc:1057 -msgid "Flatten Brightness Distribution" -msgstr "Helligkeitsverteilung ausgleichen" - -#: fotoxx_retouch.cc:1071 -msgid "Flatten" -msgstr "Ausgleichen" - -#: fotoxx_retouch.cc:1333 -msgid "Ramp brightness across image" -msgstr "Helligkeit bereichsweise im Bild ändern" - -#: fotoxx_retouch.cc:1757 -msgid "low" -msgstr "niedrig" - -#: fotoxx_retouch.cc:1759 -msgid "high" -msgstr "hoch" - -#: fotoxx_retouch.cc:1762 -msgid "Amplify" -msgstr "Verstärken" - -#: fotoxx_retouch.cc:2068 -msgid "Adjust White Balance" -msgstr "Weißabgleich abstimmen" - -#: fotoxx_retouch.cc:2069 -msgid "Click white or gray image location" -msgstr "Weißen oder grauen Bildbereich anklicken" - -#: fotoxx_retouch.cc:2283 -msgid "Color Match Images" -msgstr "Bilderfarben anpassen" - -#: fotoxx_retouch.cc:2312 -msgid "mouse radius for color sample" -msgstr "Mausradius für Farbauswahl" - -#: fotoxx_retouch.cc:2315 -msgid "image for source color" -msgstr "Bild für Quellfarbe" - -#: fotoxx_retouch.cc:2317 -msgid "click on image to get source color" -msgstr "Bild anklicken zur Quellfarbe bestimmen" - -#: fotoxx_retouch.cc:2320 -msgid "image to set matching color" -msgstr "Bild zur Abgleichfarbe festlegen" - -#: fotoxx_retouch.cc:2322 -msgid "click on image to set matching color" -msgstr "Bild anklicken zur Abgleichfarbe festlegen" - -#: fotoxx_retouch.cc:2377 -msgid "select source image color first" -msgstr "Farbe vom Quellbild zuerst wählen" - -#: fotoxx_retouch.cc:2903 fotoxx_tools.cc:1643 -msgid "Click image to select pixels." -msgstr "Bild anklicken zum Pixeln auswählen" - -#: fotoxx_retouch.cc:2955 -msgid "Metric:" -msgstr "Einheit" - -#: fotoxx_retouch.cc:3010 -msgid "Blend" -msgstr "Beimischen" - -#: fotoxx_retouch.cc:3394 -msgid "" -"Method 1:\n" -" Left-click on red-eye to darken.\n" -"Method 2:\n" -" Drag down and right to enclose red-eye.\n" -" Left-click on red-eye to darken.\n" -"Undo red-eye:\n" -" Right-click on red-eye." -msgstr "" -"Methode 1:\n" -" Linksklick in das rote Auge zum Abdunkeln.\n" -"Methode 2:\n" -" Linke Maustaste gedrückt nach rechts unten ziehen zur Markierung des roten " -"Auges.\n" -" Linksklick in das rote Auge zum Abdunkeln.\n" -"Zurücksetzen:\n" -" Rechtsklick in das rote Auge." - -#: fotoxx_retouch.cc:3409 -msgid "Red Eye Reduction" -msgstr "Rote-Augen beseitigen" - -#: fotoxx_retouch.cc:3850 -msgid "Set Blur Radius" -msgstr "Verwisch-Radius festlegen" - -#: fotoxx_retouch.cc:4084 -msgid "edge detection" -msgstr "Kantenerkennung" - -#: fotoxx_retouch.cc:4085 -msgid "cycles" -msgstr "Zyklen" - -#: fotoxx_retouch.cc:4086 -msgid "reduce" -msgstr "Vermindern" - -#: fotoxx_retouch.cc:4097 -msgid "unsharp mask" -msgstr "Unscharf maskieren" - -#: fotoxx_retouch.cc:4110 -msgid "brightness gradient" -msgstr "Helligkeits-Gradient" - -#: fotoxx_retouch.cc:4516 -msgid "" -" Press the reduce button to \n" -" reduce noise in small steps. \n" -" Use undo to start over." -msgstr "" -" [Vermindern] drücken zur \n" -" schrittweisen Rauschreduzierung. \n" -" [undo] zum Neustart." - -#: fotoxx_retouch.cc:4527 -msgid "Noise Reduction" -msgstr "Rauschverminderung" - -#: fotoxx_retouch.cc:4532 -msgid "algorithm" -msgstr "Algorithmus" - -#: fotoxx_retouch.cc:4539 -msgid "flatten outliers by color (1)" -msgstr "Ausreißer nach Farbe mitteln (1)" - -#: fotoxx_retouch.cc:4540 -msgid "flatten outliers by color (2)" -msgstr "Ausreißer nach Farbe mitteln (2)" - -#: fotoxx_retouch.cc:4541 -msgid "set median brightness by color" -msgstr "Mittlere Helligkeit pro Farbe setzen" - -#: fotoxx_retouch.cc:4542 fotoxx_retouch.cc:4543 -msgid "top hat filter by color" -msgstr "Tophat-Filter nach Farbe" - -#: fotoxx_retouch.cc:4858 -msgid "" -"1. Drag mouse to select. \n" -"2. Erase. 3. Repeat. " -msgstr "" -"1. Zum Selektieren, Maus ziehen. \n" -"2. Löschen. 3. Wiederholen. " - -#: fotoxx_retouch.cc:4889 -msgid "Radius" -msgstr "Radius" - -#: fotoxx_retouch.cc:4891 -msgid "Blur" -msgstr "Verwischen" - -#: fotoxx_retouch.cc:4894 -msgid "New Area" -msgstr "Neuer Ausschnitt" - -#: fotoxx_retouch.cc:5275 -msgid "spot size limit" -msgstr "Fleckgrößen Limit" - -#: fotoxx_retouch.cc:5278 -msgid "max. brightness" -msgstr "max. Helligkeit" - -#: fotoxx_retouch.cc:5281 -msgid "min. contrast" -msgstr "Min. Kontrast" - -#: fotoxx_retouch.cc:5875 -#, c-format -msgid "Undo Memory %d%c" -msgstr "Undo-Speicher %d%c" - -#: fotoxx_retouch.cc:5884 -msgid "pick" -msgstr "wählen" - -#: fotoxx_retouch.cc:5886 -msgid "erase" -msgstr "löschen" - -#: fotoxx_retouch.cc:5894 -msgid "paintbrush radius" -msgstr "Pinsel-Radius" - -#: fotoxx_retouch.cc:5895 -msgid "transparency center" -msgstr "Transparenz Mitte" - -#: fotoxx_retouch.cc:5896 -msgid "transparency edge" -msgstr "Transparenz Rand" - -#: fotoxx_retouch.cc:6166 -msgid "" -"Undo memory limit has been reached. \n" -"Save work with [done], then resume editing." -msgstr "" -"Undo Speicherkapazität erreicht. \n" -"Arbeit mit [fertig] sichern, dann Fortfahren." - -#: fotoxx_tools.cc:42 -msgid "" -"When editing a collection, right-click \n" -"an image or thumbnail to add or remove." -msgstr "" -"Beim Verarbeiten einer Sammlung, rechts anklicken \n" -"um ein Bild oder Thumbnail zu addieren oder entfernen." - -#: fotoxx_tools.cc:85 -msgid "Start new collection" -msgstr "Neue Sammlung starten" - -#: fotoxx_tools.cc:87 -msgid "Edit a collection" -msgstr "Sammlung verarbeiten" - -#: fotoxx_tools.cc:89 -msgid "View a collection" -msgstr "Sammlung ansehen" - -#: fotoxx_tools.cc:91 -msgid "Delete a collection" -msgstr "Sammlung löschen" - -#: fotoxx_tools.cc:95 -msgid "Editing:" -msgstr "Verarbeiten:" - -#: fotoxx_tools.cc:99 -msgid "Action:" -msgstr "Vorgang:" - -#: fotoxx_tools.cc:133 -msgid "New Collection" -msgstr "Neue Sammlung" - -#: fotoxx_tools.cc:156 -msgid "Edit Collection" -msgstr "Sammlung bearbeiten" - -#: fotoxx_tools.cc:172 -msgid "View Collection" -msgstr "Sammlung ansehen" - -#: fotoxx_tools.cc:193 -msgid "Delete Collection" -msgstr "Sammlung löschen" - -#: fotoxx_tools.cc:196 -#, c-format -msgid "delete %s ?" -msgstr "%s löschen?" - -#: fotoxx_tools.cc:223 -#, c-format -msgid "add image to collection: %s" -msgstr "Bild in Sammlung: %s einfügen" - -#: fotoxx_tools.cc:225 fotoxx_tools.cc:270 -msgid "remove image from collection" -msgstr "Bild aus Sammlung entfernen" - -#: fotoxx_tools.cc:226 fotoxx_tools.cc:271 fotoxx_tools.cc:298 -msgid "remove and save image" -msgstr "Bild entfernen und aufheben" - -#: fotoxx_tools.cc:227 fotoxx_tools.cc:316 -msgid "insert saved images here" -msgstr "Aufgehobene Bilder hier einfügen" - -#: fotoxx_tools.cc:256 -msgid "add image to collection" -msgstr "Bild in Sammlung einfügen" - -#: fotoxx_tools.cc:301 -msgid "too many saved files" -msgstr "Zu viele aufgehobene Dateien" - -#: fotoxx_tools.cc:375 -msgid "old top directory" -msgstr "Altes oberstes Bild-Verzeichnis" - -#: fotoxx_tools.cc:378 -msgid "new top directory" -msgstr "Neues oberstes Bild-Verzeichnis" - -#: fotoxx_tools.cc:434 -msgid "completed" -msgstr "Fertig" - -#: fotoxx_tools.cc:452 -msgid "" -"Brightness should show a gradual ramp \n" -"extending all the way to the edges." -msgstr "" -"Helligkeit soll einen allmählichen Ansteig \n" -"zeigen, auch ganz bis zu den Rändern." - -#: fotoxx_tools.cc:492 -msgid "Monitor Check" -msgstr "Monitor Prüfung" - -#: fotoxx_tools.cc:612 -msgid "Brightness Distribution" -msgstr "Helligkeitsverteilung" - -#: fotoxx_tools.cc:796 -msgid "Press ESC to exit slide show" -msgstr "ESC drücken um zu beenden" - -#: fotoxx_tools.cc:797 -msgid "show only latest file versions" -msgstr "Nur neueste Dateiversionen zeigen" - -#: fotoxx_tools.cc:801 -msgid "arrow keys" -msgstr "Pfeiltasten" - -#: fotoxx_tools.cc:802 -msgid "instant" -msgstr "Sofortig" - -#: fotoxx_tools.cc:803 -msgid "fade-in" -msgstr "Einblenden" - -#: fotoxx_tools.cc:804 -msgid "roll-right" -msgstr "Nach rechts rollend" - -#: fotoxx_tools.cc:805 -msgid "roll-down" -msgstr "Nach unten rollend" - -#: fotoxx_tools.cc:806 -msgid "shift-left" -msgstr "Nach links verlagern" - -#: fotoxx_tools.cc:807 -msgid "venetian" -msgstr "Jalousie" - -#: fotoxx_tools.cc:808 -msgid "grate" -msgstr "Gitter" - -#: fotoxx_tools.cc:811 -msgid "radar" -msgstr "Radar" - -#: fotoxx_tools.cc:812 -msgid "jaws" -msgstr "Haifisch" - -#: fotoxx_tools.cc:823 -msgid "seconds" -msgstr "Sekunden" - -#: fotoxx_tools.cc:827 -msgid "music file" -msgstr "Musikdatei" - -#: fotoxx_tools.cc:831 -msgid "transitions" -msgstr "Übergänge" - -#: fotoxx_tools.cc:948 -msgid "Select music file or playlist" -msgstr "Musikdatei oder Playlist wählen" - -#: fotoxx_tools.cc:1971 -msgid "x-spacing" -msgstr "x-Abstand" - -#: fotoxx_tools.cc:1972 -msgid "x-count" -msgstr "x-Anzahl" - -#: fotoxx_tools.cc:1973 -msgid "x-enable" -msgstr "x-aktivieren" - -#: fotoxx_tools.cc:1979 -msgid "y-spacing" -msgstr "y-Abstand" - -#: fotoxx_tools.cc:1980 -msgid "y-count" -msgstr "y-Anzahl" - -#: fotoxx_tools.cc:1981 -msgid "y-enable" -msgstr "y-aktivieren" - -#: fotoxx_tools.cc:1988 -msgid "x-offset" -msgstr "x-Verschiebung" - -#: fotoxx_tools.cc:1992 -msgid "y-offset" -msgstr "y-Verschiebung" - -#: fotoxx_tools.cc:2146 -msgid "lens name" -msgstr "Lens-Name" - -#: fotoxx_tools.cc:2220 -msgid "Available Translations" -msgstr "Vorhandene Übersetzungen" - -#: fotoxx_tools.cc:2224 -msgid "Set Language" -msgstr "Sprache wechseln" - -#: fotoxx_tools.cc:2290 -msgid "Make Launcher" -msgstr "Start-Icon erzeugen" - -#: fotoxx_tools.cc:2310 -msgid "Program ufraw-batch is required" -msgstr "Program ufraw-batch ist nötig" - -#: fotoxx_tools.cc:2320 -msgid "Open RAW File" -msgstr "RAW-Datei öffnen" - -#: fotoxx_tools.cc:2331 -msgid "Select RAW files to convert" -msgstr "RAW Dateien zum konvertieren auswählen" - -#: fotoxx_tools.cc:2467 -msgid "max. width" -msgstr "max. Breite" - -#: fotoxx_tools.cc:2468 -msgid "max. height" -msgstr "max. Höhe" - -#: fotoxx_tools.cc:2527 fotoxx_transform.cc:1268 -#, c-format -msgid "max. size %d x %d is not reasonable" -msgstr "Max. größe %d x %d nicht sinnvoll" - -#: fotoxx_tools.cc:2613 -msgid "too many files" -msgstr "zu viele Dateien" - -#: fotoxx_tools.cc:2656 -msgid "Sync Files is already running" -msgstr "Datei Synchronisierung läuft schon" - -#: fotoxx_tools.cc:2707 -msgid "" -"Run Tools > Synchronize Files so that gallery windows \n" -"will be fast and Search Images will work correctly. \n" -"You can view (not edit) images while synchronize runs." -msgstr "" -"Werkzeuge > Synchronisieren benutzen, damit Galleriefenster \n" -"schnell erscheinen und Bild durchsuchen korrekt funktioniert. \n" -"Sie können Bilder ansehen (nicht verarbeiten) während Synchronisierung." - -#: fotoxx_tools.cc:2736 -msgid "no top image directory is defined" -msgstr "Oberstes Bild-Verzeichnis nicht definiert" - -#: fotoxx_tools.cc:2742 -msgid "top image directory is invalid" -msgstr "Oberstes Bild-Verzeichnis ist ungültig" - -#: fotoxx_tools.cc:2747 -msgid "no search index file is present" -msgstr "Such-Index Datei fehlt" - -#: fotoxx_tools.cc:2761 -msgid "new/modified files are present" -msgstr "neue/geänderte Dateien gefunden" - -#: fotoxx_tools.cc:2768 -msgid "no new files found" -msgstr "Keine neue Dateien gefunden" - -#: fotoxx_tools.cc:2785 -msgid "Top Image Directory:" -msgstr "Oberste Bild-Verzeichnis" - -#: fotoxx_tools.cc:2807 -msgid "file sync is mandatory" -msgstr "Synchronisierung ist nötig" - -#: fotoxx_tools.cc:2817 -msgid "top directory is invalid" -msgstr "Oberstes-Bildverzeichnis ist ungültig" - -#: fotoxx_tools.cc:3201 -msgid "Select top image directory" -msgstr "Oberstes Bildverzeichnis wählen" - -#: fotoxx_tools.cc:3378 -msgid "icons" -msgstr "Symbole" - -#: fotoxx_tools.cc:3379 fotoxx_transform.cc:1467 -msgid "text" -msgstr "Text" - -#: fotoxx_tools.cc:3380 -msgid "both" -msgstr "Beide" - -#: fotoxx_transform.cc:50 -msgid "Use buttons or drag right edge with mouse" -msgstr "" -"Knöpfe benutzen oder \n" -"rechten Rand mit der Maus ziehen" - -#: fotoxx_transform.cc:64 -msgid "degrees" -msgstr "Grad" - -#: fotoxx_transform.cc:80 fotoxx_transform.cc:124 -msgid "Trim" -msgstr "Schnitt" - -#: fotoxx_transform.cc:81 fotoxx_transform.cc:2437 fotoxx_transform.cc:3263 -#: fotoxx_transform.cc:3526 fotoxx_transform.cc:3787 -msgid "Grid" -msgstr "Gitter" - -#: fotoxx_transform.cc:123 -msgid "Undo Trim" -msgstr "Undo Schnitt" - -#: fotoxx_transform.cc:139 -#, c-format -msgid "degrees: %.1f" -msgstr "Grad: %.1f" - -#: fotoxx_transform.cc:286 -msgid "gold" -msgstr "Gold" - -#: fotoxx_transform.cc:332 -msgid "Drag middle to move, drag corners to resize." -msgstr "Zum Bewegen mittig ziehen, Ecken um Größe zu verändern." - -#: fotoxx_transform.cc:346 -msgid "customize" -msgstr "Anpassen" - -#: fotoxx_transform.cc:357 -msgid "ratio" -msgstr "Verhältnis" - -#: fotoxx_transform.cc:361 -msgid "Lock Ratio" -msgstr "Seitenverhältniss fixieren" - -#: fotoxx_transform.cc:367 -msgid "invert" -msgstr "Invert." - -#: fotoxx_transform.cc:892 -msgid "Trim Buttons" -msgstr "Schnitt-Knöpfe" - -#: fotoxx_transform.cc:964 -msgid "Lock aspect ratio" -msgstr "Breite/Höhe-Verhältnis fixieren" - -#: fotoxx_transform.cc:1145 -msgid "Batch Resize" -msgstr "Dateiengrößen verändern" - -#: fotoxx_transform.cc:1153 -msgid "new max. width" -msgstr "Neu max. Breite" - -#: fotoxx_transform.cc:1154 -msgid "new max. height" -msgstr "Neu max. Höhe" - -#: fotoxx_transform.cc:1161 -msgid "replace originals" -msgstr "Dateien überschreiben" - -#: fotoxx_transform.cc:1162 -msgid "export to location" -msgstr "In Ordner exportieren" - -#: fotoxx_transform.cc:1166 -msgid "copy EXIF" -msgstr "EXIF kopieren" - -#: fotoxx_transform.cc:1219 -msgid "Select directory" -msgstr "Bildverzeichnis wählen" - -#: fotoxx_transform.cc:1243 -#, c-format -msgid "replace original files? (max. %d x %d)" -msgstr "Originaldateien überschreiben? (max. %d %d)" - -#: fotoxx_transform.cc:1250 -#, c-format -msgid "" -"copy files? (max. %d x %d) \n" -" to location %s" -msgstr "" -"Dateien kopieren? (max. %d x %d) \n" -" in Ordner %s" - -#: fotoxx_transform.cc:1261 -msgid "location is not a valid directory" -msgstr "Kein gültiger Dateiordner" - -#: fotoxx_transform.cc:1304 -msgid "new file already exists" -msgstr "Datei existiert schon" - -#: fotoxx_transform.cc:1388 -msgid "" -"Enter text, click/drag on image.\n" -"Right click to remove" -msgstr "" -"Text eingeben, Bild mit der Maus klicken/ziehen.\n" -"Zum Entfernen rechts klicken" - -#: fotoxx_transform.cc:1442 -msgid "Text" -msgstr "Text" - -#: fotoxx_transform.cc:1449 -msgid "Size" -msgstr "Größe" - -#: fotoxx_transform.cc:1452 -msgid "Angle" -msgstr "Winkel" - -#: fotoxx_transform.cc:1463 -msgid "Color" -msgstr "Farbe" - -#: fotoxx_transform.cc:1464 -msgid "Transparency" -msgstr "Transparenz" - -#: fotoxx_transform.cc:1472 -msgid "backing" -msgstr "Hinterfarbe" - -#: fotoxx_transform.cc:1475 -msgid "" -"Outline\n" -" Width" -msgstr "" -"Umriss\n" -"Breite" - -#: fotoxx_transform.cc:1477 -msgid "outline" -msgstr "Umriss" - -#: fotoxx_transform.cc:1486 -msgid "Annotation File:" -msgstr "Kommentardatei" - -#: fotoxx_transform.cc:1564 -msgid "select font" -msgstr "Font wählen" - -#: fotoxx_transform.cc:2197 fotoxx_transform.cc:2429 -msgid "horizontal" -msgstr "Horizontal" - -#: fotoxx_transform.cc:2198 fotoxx_transform.cc:2428 -msgid "vertical" -msgstr "Vertikal" - -#: fotoxx_transform.cc:2306 -msgid "black/white positive" -msgstr "schwarzweiß Positiv" - -#: fotoxx_transform.cc:2307 -msgid "black/white negative" -msgstr "schwarzweiß Negativ" - -#: fotoxx_transform.cc:2308 -msgid "color positive" -msgstr "farbige Positiv" - -#: fotoxx_transform.cc:2309 -msgid "color negative" -msgstr "farbige Negativ" - -#: fotoxx_transform.cc:2430 -msgid "linear" -msgstr "linear" - -#: fotoxx_transform.cc:2433 -msgid "curved" -msgstr "kurvig" - -#: fotoxx_transform.cc:2692 -msgid "" -" Click the four corners of a tetragon area. Press [apply]. \n" -" The image is warped to make the tetragon into a rectangle." -msgstr "" -" Die vier Ecken eines Tetragonalbereich anklicken. [Anwenden] drücken. \n" -" Das Tetragon wird zu einem geraden Rechteck verzogen." - -#: fotoxx_transform.cc:2878 -msgid "must have 4 corners" -msgstr "Vier Ecken sind nötig" - -#: fotoxx_transform.cc:2999 -msgid "" -" Select an area to warp using select area function. \n" -" Press [start warp] and pull area with mouse. \n" -" Make multiple mouse pulls until satisfied. \n" -" When finished, select another area or press [done]." -msgstr "" -" Ausschnitt zum Krümmen wählen mittels Menü, Ausschnitt wählen. \n" -" [Krümmen starten] drücken, Ausschnitt mit der Maus ziehen. \n" -" Mehrmals ziehen/strecken bis zum erwünschten Ergebniss. \n" -" Wenn fertig, anderen Ausschnitt wählen oder [Fertig] drücken." - -#: fotoxx_transform.cc:3018 -msgid "start warp" -msgstr "Krümmen starten" - -#: fotoxx_transform.cc:3067 -msgid "Select area first" -msgstr "Zuerst Ausschnitt wählen" - -#: fotoxx_transform.cc:3242 fotoxx_transform.cc:3505 -msgid "" -" Pull an image position using the mouse. \n" -" Make multiple mouse pulls until satisfied. \n" -" When finished, press [done]." -msgstr "" -" Bildstelle mit der Maus ziehen. \n" -" Mehrmals ziehen bis zufriedenstellend. \n" -" Wenn fertig, [Fertig] drücken." - -#: fotoxx_transform.cc:3771 -msgid "" -" Pull on an image corner using the mouse. \n" -" Make multiple mouse pulls until satisfied. \n" -" When finished, press [done]." -msgstr "" -" Bildecke mit der Maus ziehen. \n" -" Mehrmals ziehen bis zufriedengestellt. \n" -" Wenn fertig, [Fertig] drücken." - -#~ msgid "%d new/modified files found" -#~ msgstr "%d neue/geänderte Dateien gefunden" - -#~ msgid "Create Collection" -#~ msgstr "Sammlung Kreieren" - -#~ msgid "Open Collection" -#~ msgstr "Sammlung öffnen" - -#~ msgid "Straighten Image" -#~ msgstr "Bild gerade biegen" - -#~ msgid "Translate" -#~ msgstr "Übersetzen" - -#~ msgid "" -#~ "Run Tools > Synchronize Files so that gallery windows \n" -#~ "will be fast and Search Images will work correctly." -#~ msgstr "" -#~ "Werkzeuge > Synchronisieren benutzen, damit Galleriefenster \n" -#~ "schnell erscheinen und Bild durchsuchen korrekt funktioniert." - -#~ msgid "%d files modified since last fotoxx use" -#~ msgstr "%d Dateien geändert seit dem letzten Fotoxx Lauf" - -#~ msgid "Synchronize Files needed" -#~ msgstr "Datei Synchronisierung nötig" - -#~ msgid "Save Collection" -#~ msgstr "Sammlung speichern" - -#~ msgid "Add new images to collection" -#~ msgstr "Neue Bilder zur Sammlung addieren" - -#~ msgid "Delete images from collection" -#~ msgstr "Bilder von Sammlung entfernen" - -#~ msgid "Remove and save images" -#~ msgstr "Bilder entfernen und aufheben" - -#~ msgid "Insert new or saved images" -#~ msgstr "Neue oder aufgehobene Bilder einfügen" - -#~ msgid "" -#~ "Select images to add, then \n" -#~ "press [Paste] to insert them." -#~ msgstr "" -#~ "Bilder zum Addieren auswählen, dann \n" -#~ "[Einfügen] drucken zum Einfügen." - -#~ msgid "select image files" -#~ msgstr "Bilddatei auswählen" - -#~ msgid "Click on images to delete." -#~ msgstr "Bilder zum Entfernen anklicken." - -#~ msgid "" -#~ "Click on images to remove and save, \n" -#~ "then press [Paste] to insert them." -#~ msgstr "" -#~ "Bilder zum Entfernen und Aufheben anklicken, \n" -#~ "Dann [Einfügen] drucken zum Einfügen." - -#~ msgid "" -#~ "Click on image where new or saved \n" -#~ "images are to be inserted (after)." -#~ msgstr "" -#~ "Bild anklicken wo (nach) neue oder \n" -#~ "aufgehobene Bilder einzufügen sind." - -#~ msgid "enable" -#~ msgstr "aktivieren" - -#~ msgid "x-grid" -#~ msgstr "x-Gitter" - -#~ msgid "y-grid" -#~ msgstr "y-Gitter" - -#~ msgid "full rebuild" -#~ msgstr "Kompletter Neuaufbau" - -#~ msgid "incremental" -#~ msgstr "Inkremental" diff -Nru fotoxx-11.11.1/locales/de/zfuncs.po fotoxx-12.01.2/locales/de/zfuncs.po --- fotoxx-11.11.1/locales/de/zfuncs.po 2011-11-05 05:30:37.000000000 +0000 +++ fotoxx-12.01.2/locales/de/zfuncs.po 1970-01-01 00:00:00.000000000 +0000 @@ -1,293 +0,0 @@ -# German translations for home package. -# Copyright (C) 2008 THE home'S COPYRIGHT HOLDER -# This file is distributed under the same license as the home package. -# mico , 2008. -# -msgid "" -msgstr "" -"Project-Id-Version: zfuncs\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2011-11-05 05:48+0100\n" -"PO-Revision-Date: 2010-07-30 13:03+0100\n" -"Last-Translator: kornelix \n" -"Language-Team: German\n" -"Language: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#: zfuncs.cc:3192 -#, c-format -msgid "help file not found: %s" -msgstr "Hilfedatei nicht gefunden: %s" - -#: zfuncs.cc:3296 -#, c-format -msgid "error: %s" -msgstr "Fehler: %s" - -#: zfuncs.cc:4415 zfuncs.cc:8771 -#, c-format -msgid "cannot open file %s" -msgstr "Kann Datei nicht öffnen %s" - -#: zfuncs.cc:4448 -msgid "save screen to file" -msgstr "Bildschirm in Datei speichern" - -#: zfuncs.cc:6198 -msgid "No" -msgstr "Nein" - -#: zfuncs.cc:6198 -msgid "Yes" -msgstr "Ja" - -#: zfuncs.cc:6272 zfuncs.cc:6308 zfuncs.cc:6461 zfuncs.cc:6865 zfuncs.cc:8358 -#: zfuncs.cc:8883 zfuncs.cc:8889 zfuncs.cc:8895 zfuncs.cc:8901 -msgid "cancel" -msgstr "Abbrechen" - -#: zfuncs.cc:6423 zfuncs.cc:7552 -msgid "open" -msgstr "Öffnen" - -#: zfuncs.cc:6428 -msgid "choose" -msgstr "Wählen" - -#: zfuncs.cc:6433 -msgid "save" -msgstr "Speichern" - -#: zfuncs.cc:6439 -msgid "open folder" -msgstr "Verzeichnis öffnen" - -#: zfuncs.cc:6444 -msgid "create folder" -msgstr "Ordner erstellen" - -#: zfuncs.cc:6450 -msgid "hidden" -msgstr "Versteckt" - -#: zfuncs.cc:6454 -msgid "quality" -msgstr "Qualität" - -#: zfuncs.cc:6511 -msgid "JPG quality 0-100" -msgstr "JPG-Qualität 0-100" - -#: zfuncs.cc:6865 zfuncs.cc:8358 -msgid "done" -msgstr "fertig" - -#: zfuncs.cc:6865 zfuncs.cc:6878 -msgid "margins" -msgstr "Ränder" - -#: zfuncs.cc:6874 -msgid "top" -msgstr "oben" - -#: zfuncs.cc:6875 -msgid "bottom" -msgstr "unten" - -#: zfuncs.cc:6876 -msgid "left" -msgstr "links" - -#: zfuncs.cc:6877 -msgid "right" -msgstr "rechts" - -#: zfuncs.cc:7278 zfuncs.cc:7532 zfuncs.cc:7670 zfuncs.cc:7671 zfuncs.cc:7673 -msgid "bigger" -msgstr "Größer" - -#: zfuncs.cc:7278 -msgid "increase thumbnail size" -msgstr "Thumbnails vergrößern" - -#: zfuncs.cc:7279 -msgid "reduce thumbnail size" -msgstr "Thumbnails verkleinern" - -#: zfuncs.cc:7279 zfuncs.cc:7542 zfuncs.cc:7672 zfuncs.cc:7674 -msgid "smaller" -msgstr "Kleiner" - -#: zfuncs.cc:7280 zfuncs.cc:7571 -msgid "parent" -msgstr "Stamm" - -#: zfuncs.cc:7280 -msgid "parent directory" -msgstr "Übergeordnetes Verzeichniss" - -#: zfuncs.cc:7281 zfuncs.cc:7589 zfuncs.cc:7681 -msgid "first page" -msgstr "Erste Seite" - -#: zfuncs.cc:7281 -msgid "jump to first file" -msgstr "Zur ersten Datei" - -#: zfuncs.cc:7282 zfuncs.cc:7587 zfuncs.cc:7676 zfuncs.cc:7683 -msgid "prev page" -msgstr "Vorherige Seite" - -#: zfuncs.cc:7282 -msgid "previous page" -msgstr "Vorherige Seite" - -#: zfuncs.cc:7283 zfuncs.cc:7585 zfuncs.cc:7678 -msgid "prev row" -msgstr "Vorherige Reihe" - -#: zfuncs.cc:7283 -msgid "previous row" -msgstr "Vorherige Reihe" - -#: zfuncs.cc:7284 zfuncs.cc:7586 zfuncs.cc:7679 -msgid "next row" -msgstr "Nächste Reihe" - -#: zfuncs.cc:7285 zfuncs.cc:7588 zfuncs.cc:7677 zfuncs.cc:7684 -msgid "next page" -msgstr "Nächste Seite" - -#: zfuncs.cc:7286 -msgid "jump to last file" -msgstr "Zur letzten Datei" - -#: zfuncs.cc:7286 zfuncs.cc:7590 zfuncs.cc:7682 -msgid "last page" -msgstr "Letzte Seite" - -#: zfuncs.cc:7287 zfuncs.cc:7527 -msgid "close" -msgstr "Schließen" - -#: zfuncs.cc:7287 -msgid "close image gallery" -msgstr "Bildergalerie schließen" - -#: zfuncs.cc:7558 -msgid "select new file" -msgstr "Neue Datei wählen" - -#: zfuncs.cc:8358 -msgid "Select Files" -msgstr "Dateien wählen" - -#: zfuncs.cc:8366 -msgid "delete" -msgstr "löschen" - -#: zfuncs.cc:8367 -msgid "insert" -msgstr "hinzufügen" - -#: zfuncs.cc:8368 -msgid "add all" -msgstr "Alle hinzufügen" - -#: zfuncs.cc:8658 -msgid "" -"Initial parameters file created. \n" -"Inspect and revise if necessary." -msgstr "" -"Anfangsparameter-Datei wurde angelegt. \n" -"Bei Bedarf kontrollieren und berichtigen ." - -#: zfuncs.cc:8674 -msgid "load parameters from a file" -msgstr "Parameter aus einer Datei laden" - -#: zfuncs.cc:8743 -msgid "save parameters to a file" -msgstr "Parameter in Datei speichern" - -#: zfuncs.cc:8881 zfuncs.cc:8887 zfuncs.cc:8893 zfuncs.cc:8899 -msgid "edit parameters" -msgstr "Parameter ändern" - -#: zfuncs.cc:8882 zfuncs.cc:8888 -msgid "" -"list\n" -"all" -msgstr "" -"Auflisten\n" -"Alle" - -#: zfuncs.cc:8882 zfuncs.cc:8888 zfuncs.cc:8894 zfuncs.cc:8900 -msgid "" -"load\n" -"file" -msgstr "" -"Laden\n" -"Datei" - -#: zfuncs.cc:8882 zfuncs.cc:8888 zfuncs.cc:8894 zfuncs.cc:8900 -msgid "" -"save\n" -"file" -msgstr "" -"Speichern\n" -"Datei" - -#: zfuncs.cc:8883 zfuncs.cc:8895 -msgid "" -"add\n" -"new" -msgstr "" -"hinzufügen\n" -"Neu" - -#: zfuncs.cc:8883 zfuncs.cc:8889 zfuncs.cc:8895 zfuncs.cc:8901 -msgid "apply" -msgstr "Anwenden" - -#: zfuncs.cc:8935 -msgid "apply?" -msgstr "Anwenden?" - -#: zfuncs.cc:8992 -msgid "(new parm name)" -msgstr "(neuer Parameter-Name)" - -#: zfuncs.cc:8992 -msgid "add parameter" -msgstr "Parameter hinzufügen" - -#~ msgid "Yes or No" -#~ msgstr "Ja oder Nein" - -#~ msgid "paper format is crazy" -#~ msgstr "Papierformat sinnlos" - -#~ msgid "margins:" -#~ msgstr "Ränder" - -#~ msgid "landscape" -#~ msgstr "Querformat" - -#~ msgid "portrait" -#~ msgstr "Hochformat" - -#~ msgid "paper format" -#~ msgstr "Papierformat" - -#~ msgid "printer ID" -#~ msgstr "Drucker ID" - -#~ msgid "print" -#~ msgstr "Drucken" - -#~ msgid "open a file" -#~ msgstr "Datei öffnen" diff -Nru fotoxx-11.11.1/locales/en/fotoxx.po fotoxx-12.01.2/locales/en/fotoxx.po --- fotoxx-11.11.1/locales/en/fotoxx.po 2011-11-05 05:30:36.000000000 +0000 +++ fotoxx-12.01.2/locales/en/fotoxx.po 1970-01-01 00:00:00.000000000 +0000 @@ -1,2206 +0,0 @@ -# English translations for home package. -# Copyright (C) 2011 THE home'S COPYRIGHT HOLDER -# This file is distributed under the same license as the home package. -# mico , 2011. -# -msgid "" -msgstr "" -"Project-Id-Version: home 2\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2011-11-05 05:48+0100\n" -"PO-Revision-Date: 2011-01-01 11:29+0100\n" -"Last-Translator: mico \n" -"Language-Team: English\n" -"Language: en\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=ASCII\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#: fotoxx-11.11.1.cc:179 -msgid "File" -msgstr "File" - -#: fotoxx-11.11.1.cc:180 fotoxx-11.11.1.cc:316 -msgid "Image Gallery" -msgstr "Image Gallery" - -#: fotoxx-11.11.1.cc:181 -msgid "Clone 50/50" -msgstr "Clone 50/50" - -#: fotoxx-11.11.1.cc:182 -msgid "Clone Overlay" -msgstr "Clone Overlay" - -#: fotoxx-11.11.1.cc:183 fotoxx-11.11.1.cc:317 fotoxx-11.11.1.cc:2272 -#: fotoxx-11.11.1.cc:2444 -msgid "Open Image File" -msgstr "Open Image File" - -#: fotoxx-11.11.1.cc:184 -msgid "Open in New Window" -msgstr "Open in New Window" - -#: fotoxx-11.11.1.cc:185 fotoxx-11.11.1.cc:318 -msgid "Open Previous File" -msgstr "Open Previous File" - -#: fotoxx-11.11.1.cc:186 -msgid "Open Recent File" -msgstr "Open Recent File" - -#: fotoxx-11.11.1.cc:187 fotoxx-11.11.1.cc:326 -msgid "Save to Same File" -msgstr "Save to Same File" - -#: fotoxx-11.11.1.cc:188 fotoxx-11.11.1.cc:327 -msgid "Save to New Version" -msgstr "Save to New Version" - -#: fotoxx-11.11.1.cc:189 fotoxx-11.11.1.cc:328 -msgid "Save to New File" -msgstr "Save to New File" - -#: fotoxx-11.11.1.cc:190 fotoxx-11.11.1.cc:2990 -msgid "Create Blank Image" -msgstr "Create Blank Image" - -#: fotoxx-11.11.1.cc:191 -msgid "Trash Image File" -msgstr "Trash Image File" - -#: fotoxx-11.11.1.cc:192 fotoxx-11.11.1.cc:3216 -msgid "Rename Image File" -msgstr "Rename Image File" - -#: fotoxx-11.11.1.cc:193 -msgid "Batch Rename Files" -msgstr "Batch Rename Files" - -#: fotoxx-11.11.1.cc:194 -msgid "Print Image File" -msgstr "Print Image File" - -#: fotoxx-11.11.1.cc:195 fotoxx-11.11.1.cc:332 -msgid "Quit fotoxx" -msgstr "Quit fotoxx" - -#: fotoxx-11.11.1.cc:197 -msgid "Tools" -msgstr "Tools" - -#: fotoxx-11.11.1.cc:198 fotoxx_tools.cc:70 -msgid "Manage Collections" -msgstr "Manage Collections" - -#: fotoxx-11.11.1.cc:199 fotoxx_tools.cc:373 -msgid "Move Collections" -msgstr "Move Collections" - -#: fotoxx-11.11.1.cc:200 -msgid "Check Monitor" -msgstr "Check Monitor" - -#: fotoxx-11.11.1.cc:201 fotoxx_tools.cc:550 -msgid "Monitor Gamma" -msgstr "Monitor Gamma" - -#: fotoxx-11.11.1.cc:202 -msgid "Brightness Graph" -msgstr "Brightness Graph" - -#: fotoxx-11.11.1.cc:203 fotoxx_tools.cc:819 -msgid "Slide Show" -msgstr "Slide Show" - -#: fotoxx-11.11.1.cc:204 fotoxx_tools.cc:1668 -msgid "Show RGB" -msgstr "Show RGB" - -#: fotoxx-11.11.1.cc:205 fotoxx_tools.cc:1962 -msgid "Grid Lines" -msgstr "Grid Lines" - -#: fotoxx-11.11.1.cc:206 fotoxx_tools.cc:2135 -msgid "Lens Parameters" -msgstr "Lens Parameters" - -#: fotoxx-11.11.1.cc:207 -msgid "Change Language" -msgstr "Change Language" - -#: fotoxx-11.11.1.cc:209 -msgid "Add Menu and Launcher" -msgstr "Add Menu and Launcher" - -#: fotoxx-11.11.1.cc:210 -msgid "Convert RAW files" -msgstr "Convert RAW files" - -#: fotoxx-11.11.1.cc:211 -msgid "Burn Images to CD/DVD" -msgstr "Burn Images to CD/DVD" - -#: fotoxx-11.11.1.cc:212 fotoxx_tools.cc:2460 -msgid "E-mail Images" -msgstr "E-mail Images" - -#: fotoxx-11.11.1.cc:213 fotoxx_tools.cc:2783 -msgid "Synchronize Files" -msgstr "Synchronize Files" - -#: fotoxx-11.11.1.cc:214 fotoxx_tools.cc:3376 -msgid "Toolbar Style" -msgstr "Toolbar Style" - -#: fotoxx-11.11.1.cc:215 -msgid "Memory Usage" -msgstr "Memory Usage" - -#: fotoxx-11.11.1.cc:218 -msgid "Edit Caption/Comments" -msgstr "Edit Caption/Comments" - -#: fotoxx-11.11.1.cc:219 fotoxx_info.cc:156 -msgid "Edit Tags" -msgstr "Edit Tags" - -#: fotoxx-11.11.1.cc:220 fotoxx_info.cc:345 -msgid "Manage Tags" -msgstr "Manage Tags" - -#: fotoxx-11.11.1.cc:221 fotoxx_info.cc:1345 -msgid "Batch Add Tags" -msgstr "Batch Add Tags" - -#: fotoxx-11.11.1.cc:222 fotoxx_info.cc:1547 -msgid "Batch Delete Tag" -msgstr "Batch Delete Tag" - -#: fotoxx-11.11.1.cc:223 -msgid "View Info (short)" -msgstr "View Info (short)" - -#: fotoxx-11.11.1.cc:224 -msgid "View Info (long)" -msgstr "View Info (long)" - -#: fotoxx-11.11.1.cc:225 fotoxx_info.cc:1883 -msgid "Edit Info" -msgstr "Edit Info" - -#: fotoxx-11.11.1.cc:226 fotoxx_info.cc:1981 -msgid "Delete Info" -msgstr "Delete Info" - -#: fotoxx-11.11.1.cc:227 -msgid "Search Images" -msgstr "Search Images" - -#: fotoxx-11.11.1.cc:229 fotoxx-11.11.1.cc:230 -msgid "Select" -msgstr "Select" - -#: fotoxx-11.11.1.cc:231 -msgid "Show" -msgstr "Show" - -#: fotoxx-11.11.1.cc:232 -msgid "Hide" -msgstr "Hide" - -#: fotoxx-11.11.1.cc:233 -msgid "Enable" -msgstr "Enable" - -#: fotoxx-11.11.1.cc:234 -msgid "Disable" -msgstr "Disable" - -#: fotoxx-11.11.1.cc:235 -msgid "Invert" -msgstr "Invert" - -#: fotoxx-11.11.1.cc:236 -msgid "Unselect" -msgstr "Unselect" - -#: fotoxx-11.11.1.cc:237 -msgid "Copy" -msgstr "Copy" - -#: fotoxx-11.11.1.cc:238 -msgid "Paste" -msgstr "Paste" - -#: fotoxx-11.11.1.cc:239 fotoxx-11.11.1.cc:317 fotoxx_retouch.cc:2314 -#: fotoxx_retouch.cc:2319 -msgid "Open" -msgstr "Open" - -#: fotoxx-11.11.1.cc:240 fotoxx-11.11.1.cc:326 -msgid "Save" -msgstr "Save" - -#: fotoxx-11.11.1.cc:241 fotoxx_area.cc:2215 -msgid "Select Whole Image" -msgstr "Select Whole Image" - -#: fotoxx-11.11.1.cc:242 -msgid "Select and Edit" -msgstr "Select and Edit" - -#: fotoxx-11.11.1.cc:244 -msgid "Transform" -msgstr "Transform" - -#: fotoxx-11.11.1.cc:245 fotoxx_transform.cc:60 -msgid "Rotate Image" -msgstr "Rotate Image" - -#: fotoxx-11.11.1.cc:246 fotoxx_transform.cc:346 -msgid "Trim Image" -msgstr "Trim Image" - -#: fotoxx-11.11.1.cc:247 fotoxx_transform.cc:972 -msgid "Resize Image" -msgstr "Resize Image" - -#: fotoxx-11.11.1.cc:248 -msgid "Batch Resize/Export" -msgstr "Batch Resize/Export" - -#: fotoxx-11.11.1.cc:249 fotoxx_transform.cc:1436 -msgid "Annotate Image" -msgstr "Annotate Image" - -#: fotoxx-11.11.1.cc:250 fotoxx_transform.cc:2193 -msgid "Flip Image" -msgstr "Flip Image" - -#: fotoxx-11.11.1.cc:251 fotoxx_transform.cc:2303 -msgid "Make Negative" -msgstr "Make Negative" - -#: fotoxx-11.11.1.cc:252 fotoxx_transform.cc:2420 -msgid "Unbend Image" -msgstr "Unbend Image" - -#: fotoxx-11.11.1.cc:253 fotoxx_transform.cc:2704 -msgid "Keystone Correction" -msgstr "Keystone Correction" - -#: fotoxx-11.11.1.cc:254 fotoxx_transform.cc:3013 -msgid "Warp Image (area)" -msgstr "Warp Image (area)" - -#: fotoxx-11.11.1.cc:255 fotoxx_transform.cc:3255 -msgid "Warp Image (curved)" -msgstr "Warp Image (curved)" - -#: fotoxx-11.11.1.cc:256 fotoxx_transform.cc:3518 -msgid "Warp Image (linear)" -msgstr "Warp Image (linear)" - -#: fotoxx-11.11.1.cc:257 fotoxx_transform.cc:3782 -msgid "Warp Image (affine)" -msgstr "Warp Image (affine)" - -#: fotoxx-11.11.1.cc:259 -msgid "Retouch" -msgstr "Retouch" - -#: fotoxx-11.11.1.cc:260 -msgid "Brightness/Color" -msgstr "Brightness/Color" - -#: fotoxx-11.11.1.cc:261 -msgid "Gamma Curves" -msgstr "Gamma Curves" - -#: fotoxx-11.11.1.cc:262 -msgid "Expand Brightness" -msgstr "Expand Brightness" - -#: fotoxx-11.11.1.cc:263 -msgid "Flatten Brightness" -msgstr "Flatten Brightness" - -#: fotoxx-11.11.1.cc:264 -msgid "Brightness Ramp" -msgstr "Brightness Ramp" - -#: fotoxx-11.11.1.cc:265 fotoxx_retouch.cc:1729 -msgid "Tone Mapping" -msgstr "Tone Mapping" - -#: fotoxx-11.11.1.cc:266 -msgid "White Balance" -msgstr "White Balance" - -#: fotoxx-11.11.1.cc:267 -msgid "Match Colors" -msgstr "Match Colors" - -#: fotoxx-11.11.1.cc:269 fotoxx_retouch.cc:2941 -msgid "Revise RGB" -msgstr "Revise RGB" - -#: fotoxx-11.11.1.cc:270 -msgid "Red Eyes" -msgstr "Red Eyes" - -#: fotoxx-11.11.1.cc:271 -msgid "Blur Image" -msgstr "Blur Image" - -#: fotoxx-11.11.1.cc:272 fotoxx_retouch.cc:4077 -msgid "Sharpen Image" -msgstr "Sharpen Image" - -#: fotoxx-11.11.1.cc:273 -msgid "Reduce Noise" -msgstr "Reduce Noise" - -#: fotoxx-11.11.1.cc:274 fotoxx_retouch.cc:4881 -msgid "Smart Erase" -msgstr "Smart Erase" - -#: fotoxx-11.11.1.cc:275 fotoxx_retouch.cc:5271 -msgid "Remove Dust" -msgstr "Remove Dust" - -#: fotoxx-11.11.1.cc:276 fotoxx_retouch.cc:5877 -msgid "Edit Pixels" -msgstr "Edit Pixels" - -#: fotoxx-11.11.1.cc:278 -msgid "Art" -msgstr "Art" - -#: fotoxx-11.11.1.cc:279 -msgid "Color Depth" -msgstr "Color Depth" - -#: fotoxx-11.11.1.cc:280 -msgid "Drawing" -msgstr "Drawing" - -#: fotoxx-11.11.1.cc:281 -msgid "Outlines" -msgstr "Outlines" - -#: fotoxx-11.11.1.cc:282 -msgid "Embossing" -msgstr "Embossing" - -#: fotoxx-11.11.1.cc:283 -msgid "Tiles" -msgstr "Tiles" - -#: fotoxx-11.11.1.cc:284 -msgid "Dots" -msgstr "Dots" - -#: fotoxx-11.11.1.cc:285 -msgid "Painting" -msgstr "Painting" - -#: fotoxx-11.11.1.cc:287 -msgid "Combine" -msgstr "Combine" - -#: fotoxx-11.11.1.cc:288 -msgid "High Dynamic Range" -msgstr "High Dynamic Range" - -#: fotoxx-11.11.1.cc:289 -msgid "High Depth of Field" -msgstr "High Depth of Field" - -#: fotoxx-11.11.1.cc:290 -msgid "Stack / Paint" -msgstr "Stack / Paint" - -#: fotoxx-11.11.1.cc:291 -msgid "Stack / Noise" -msgstr "Stack / Noise" - -#: fotoxx-11.11.1.cc:292 -msgid "Panorama" -msgstr "Panorama" - -#: fotoxx-11.11.1.cc:293 -msgid "Vertical Panorama" -msgstr "Vertical Panorama" - -#: fotoxx-11.11.1.cc:296 -msgid "Edit Plugins" -msgstr "Edit Plugins" - -#: fotoxx-11.11.1.cc:305 fotoxx-11.11.1.cc:333 fotoxx-11.11.1.cc:4616 -msgid "Help" -msgstr "Help" - -#: fotoxx-11.11.1.cc:306 fotoxx-11.11.1.cc:4606 -msgid "About" -msgstr "About" - -#: fotoxx-11.11.1.cc:307 fotoxx-11.11.1.cc:4610 -msgid "User Guide" -msgstr "User Guide" - -#: fotoxx-11.11.1.cc:308 fotoxx-11.11.1.cc:4613 -msgid "User Guide Changes" -msgstr "User Guide Changes" - -#: fotoxx-11.11.1.cc:309 fotoxx-11.11.1.cc:4622 -msgid "Edit Functions Summary" -msgstr "Edit Functions Summary" - -#: fotoxx-11.11.1.cc:310 fotoxx-11.11.1.cc:4625 -msgid "Change Log" -msgstr "Change Log" - -#: fotoxx-11.11.1.cc:311 fotoxx-11.11.1.cc:4628 -msgid "Translations" -msgstr "Translations" - -#: fotoxx-11.11.1.cc:312 fotoxx-11.11.1.cc:4631 -msgid "Home Page" -msgstr "Home Page" - -#: fotoxx-11.11.1.cc:316 -msgid "Gallery" -msgstr "Gallery" - -#: fotoxx-11.11.1.cc:318 fotoxx_transform.cc:995 -msgid "Prev" -msgstr "Prev" - -#: fotoxx-11.11.1.cc:319 -msgid "Next" -msgstr "Next" - -#: fotoxx-11.11.1.cc:319 -msgid "Open Next File" -msgstr "Open Next File" - -#: fotoxx-11.11.1.cc:320 -msgid "Zoom-in (bigger)" -msgstr "Zoom-in (bigger)" - -#: fotoxx-11.11.1.cc:321 -msgid "Zoom-out (smaller)" -msgstr "Zoom-out (smaller)" - -#: fotoxx-11.11.1.cc:322 -msgid "Undo" -msgstr "Undo" - -#: fotoxx-11.11.1.cc:322 -msgid "Undo One Edit" -msgstr "Undo One Edit" - -#: fotoxx-11.11.1.cc:323 -msgid "Redo" -msgstr "Redo" - -#: fotoxx-11.11.1.cc:323 -msgid "Redo One Edit" -msgstr "Redo One Edit" - -#: fotoxx-11.11.1.cc:327 -msgid "Save+V" -msgstr "Save+V" - -#: fotoxx-11.11.1.cc:328 -msgid "Save+F" -msgstr "Save+F" - -#: fotoxx-11.11.1.cc:329 -msgid "Move Image to Trash" -msgstr "Move Image to Trash" - -#: fotoxx-11.11.1.cc:329 -msgid "Trash" -msgstr "Trash" - -#: fotoxx-11.11.1.cc:332 -msgid "Quit" -msgstr "Quit" - -#: fotoxx-11.11.1.cc:333 -msgid "Fotoxx Essentials" -msgstr "Fotoxx Essentials" - -#: fotoxx-11.11.1.cc:429 -msgid "first time startup" -msgstr "first time startup" - -#: fotoxx-11.11.1.cc:1815 -msgid "Exceed 50 anchor points" -msgstr "Exceed 50 anchor points" - -#: fotoxx-11.11.1.cc:2000 -msgid "load curve from a file" -msgstr "load curve from a file" - -#: fotoxx-11.11.1.cc:2053 -msgid "curve file is invalid" -msgstr "curve file is invalid" - -#: fotoxx-11.11.1.cc:2058 -msgid "curve file has different no. of curves" -msgstr "curve file has different no. of curves" - -#: fotoxx-11.11.1.cc:2073 -msgid "save curve to a file" -msgstr "save curve to a file" - -#: fotoxx-11.11.1.cc:2420 -#, c-format -msgid "" -"Discard special gallery list? \n" -" %s" -msgstr "" -"Discard special gallery list? \n" -" %s" - -#: fotoxx-11.11.1.cc:2430 fotoxx-11.11.1.cc:4452 -msgid "prior function still active" -msgstr "prior function still active" - -#: fotoxx-11.11.1.cc:2607 -msgid "Overwrite original file?" -msgstr "Overwrite original file?" - -#: fotoxx-11.11.1.cc:2608 -msgid "Do not warn again" -msgstr "Do not warn again" - -#: fotoxx-11.11.1.cc:2624 -msgid "Warning" -msgstr "Warning" - -#: fotoxx-11.11.1.cc:2747 -msgid "Save File" -msgstr "Save File" - -#: fotoxx-11.11.1.cc:2770 -msgid "quality" -msgstr "quality" - -#: fotoxx-11.11.1.cc:2772 -msgid "make current" -msgstr "make current" - -#: fotoxx-11.11.1.cc:2829 -msgid "jpeg quality must be 1-100" -msgstr "jpeg quality must be 1-100" - -#: fotoxx-11.11.1.cc:2851 -#, c-format -msgid "" -"Overwrite file? \n" -" %s" -msgstr "" -"Overwrite file? \n" -" %s" - -#: fotoxx-11.11.1.cc:2992 -msgid "file name" -msgstr "file name" - -#: fotoxx-11.11.1.cc:2997 fotoxx_transform.cc:351 -msgid "width" -msgstr "width" - -#: fotoxx-11.11.1.cc:3000 fotoxx_transform.cc:354 -msgid "height" -msgstr "height" - -#: fotoxx-11.11.1.cc:3006 fotoxx_art.cc:628 fotoxx_retouch.cc:5881 -msgid "color" -msgstr "color" - -#: fotoxx-11.11.1.cc:3120 -msgid "" -"Linux standard trash is not supported. \n" -"Desktop trash folder will be created." -msgstr "" -"Linux standard trash is not supported. \n" -"Desktop trash folder will be created." - -#: fotoxx-11.11.1.cc:3138 -msgid "Move read-only file to trash?" -msgstr "Move read-only file to trash?" - -#: fotoxx-11.11.1.cc:3164 -#, c-format -msgid "Cannot create trash folder: %s" -msgstr "Cannot create trash folder: %s" - -#: fotoxx-11.11.1.cc:3172 fotoxx-11.11.1.cc:3178 -#, c-format -msgid "error: %s" -msgstr "error: %s" - -#: fotoxx-11.11.1.cc:3221 -msgid "old name" -msgstr "old name" - -#: fotoxx-11.11.1.cc:3222 -msgid "rename to" -msgstr "rename to" - -#: fotoxx-11.11.1.cc:3223 -msgid "previous" -msgstr "previous" - -#: fotoxx-11.11.1.cc:3309 -msgid "The target file already exists" -msgstr "The target file already exists" - -#: fotoxx-11.11.1.cc:3317 -#, c-format -msgid "" -"Rename failed: \n" -" %s" -msgstr "" -"Rename failed: \n" -" %s" - -#: fotoxx-11.11.1.cc:3365 -msgid "Batch Rename" -msgstr "Batch Rename" - -#: fotoxx-11.11.1.cc:3368 fotoxx-11.11.1.cc:3420 fotoxx_info.cc:1513 -#: fotoxx_info.cc:1767 fotoxx_tools.cc:2510 fotoxx_transform.cc:1213 -#, c-format -msgid "%d files selected" -msgstr "%d files selected" - -#: fotoxx-11.11.1.cc:3370 -msgid "new base name" -msgstr "new base name" - -#: fotoxx-11.11.1.cc:3373 -msgid "starting sequence" -msgstr "starting sequence" - -#: fotoxx-11.11.1.cc:3375 -msgid "increment" -msgstr "increment" - -#: fotoxx-11.11.1.cc:3396 -msgid "select files to rename" -msgstr "select files to rename" - -#: fotoxx-11.11.1.cc:3401 -msgid "base name / sequence / increment not reasonable" -msgstr "base name / sequence / increment not reasonable" - -#: fotoxx-11.11.1.cc:3460 -msgid "new file already exists:" -msgstr "new file already exists:" - -#: fotoxx-11.11.1.cc:3468 -msgid "filespec too long:" -msgstr "filespec too long:" - -#: fotoxx-11.11.1.cc:3479 -msgid "Rename failed:" -msgstr "Rename failed:" - -#: fotoxx-11.11.1.cc:3739 -msgid "Add" -msgstr "Add" - -#: fotoxx-11.11.1.cc:3739 -msgid "Remove" -msgstr "Remove" - -#: fotoxx-11.11.1.cc:3741 -msgid "menu name" -msgstr "menu name" - -#: fotoxx-11.11.1.cc:3812 fotoxx-11.11.1.cc:3833 -msgid "Restart Fotoxx to update plugin menu" -msgstr "Restart Fotoxx to update plugin menu" - -#: fotoxx-11.11.1.cc:3927 -msgid "cannot parallel edit" -msgstr "cannot parallel edit" - -#: fotoxx-11.11.1.cc:3937 -msgid "" -"exiftool is not installed \n" -"edited images will lose EXIF data" -msgstr "" -"exiftool is not installed \n" -"edited images will lose EXIF data" - -#: fotoxx-11.11.1.cc:3943 -msgid "Too many edits, please save image" -msgstr "Too many edits, please save image" - -#: fotoxx-11.11.1.cc:3948 -msgid "" -"Select area cannot be kept.\n" -"Continue?" -msgstr "" -"Select area cannot be kept.\n" -"Continue?" - -#: fotoxx-11.11.1.cc:3956 -msgid "" -"Select area not active.\n" -"Continue?" -msgstr "" -"Select area not active.\n" -"Continue?" - -#: fotoxx-11.11.1.cc:4427 -msgid "Discard edits?" -msgstr "Discard edits?" - -#: fotoxx-11.11.1.cc:4428 -msgid "" -"This action will discard current edits.\n" -"Continue to discard edits.\n" -"Go Back to keep edits." -msgstr "" -"This action will discard current edits.\n" -"Continue to discard edits.\n" -"Go Back to keep edits." - -#: fotoxx-11.11.1.cc:4431 -msgid "Continue" -msgstr "Continue" - -#: fotoxx-11.11.1.cc:4432 -msgid "Go Back" -msgstr "Go Back" - -#: fotoxx-11.11.1.cc:5240 -msgid "cannot open thumbnail file" -msgstr "cannot open thumbnail file" - -#: fotoxx-11.11.1.cc:5433 fotoxx-11.11.1.cc:5549 -msgid "TIFF open failure" -msgstr "TIFF open failure" - -#: fotoxx-11.11.1.cc:5449 -#, c-format -msgid "TIFF bits/color=%d not supported" -msgstr "TIFF bits/color=%d not supported" - -#: fotoxx-11.11.1.cc:5464 fotoxx-11.11.1.cc:5502 -msgid "TIFF read failure" -msgstr "TIFF read failure" - -#: fotoxx-11.11.1.cc:5608 -msgid "TIFF write failure" -msgstr "TIFF write failure" - -#: fotoxx-11.11.1.cc:5638 -msgid "file type not supported" -msgstr "file type not supported" - -#: fotoxx-11.11.1.cc:5745 -msgid "pixbuf write failure" -msgstr "pixbuf write failure" - -#: fotoxx_area.cc:54 fotoxx_area.cc:2427 -msgid "Select Area for Edits" -msgstr "Select Area for Edits" - -#: fotoxx_area.cc:55 fotoxx_area.cc:2428 -msgid "Press F1 for help" -msgstr "Press F1 for help" - -#: fotoxx_area.cc:63 -msgid "" -"Select Area not supported \n" -"by this edit function" -msgstr "" -"Select Area not supported \n" -"by this edit function" - -#: fotoxx_area.cc:99 fotoxx_tools.cc:809 -msgid "rectangle" -msgstr "rectangle" - -#: fotoxx_area.cc:100 fotoxx_tools.cc:810 -msgid "ellipse" -msgstr "ellipse" - -#: fotoxx_area.cc:101 -msgid "draw: freehand" -msgstr "draw: freehand" - -#: fotoxx_area.cc:102 -msgid "draw: follow edge" -msgstr "draw: follow edge" - -#: fotoxx_area.cc:103 -msgid "select by mouse" -msgstr "select by mouse" - -#: fotoxx_area.cc:104 -msgid "select by color" -msgstr "select by color" - -#: fotoxx_area.cc:112 -msgid "radius" -msgstr "radius" - -#: fotoxx_area.cc:116 -msgid "match" -msgstr "match" - -#: fotoxx_area.cc:121 -msgid "firewall" -msgstr "firewall" - -#: fotoxx_area.cc:274 fotoxx_area.cc:415 -#, c-format -msgid "exceed %d edits" -msgstr "exceed %d edits" - -#: fotoxx_area.cc:992 -msgid "" -"Click one time inside each enclosed area \n" -"(possible gaps in the outline will be found). \n" -"Press F1 for help." -msgstr "" -"Click one time inside each enclosed area \n" -"(possible gaps in the outline will be found). \n" -"Press F1 for help." - -#: fotoxx_area.cc:1049 -msgid "finish area" -msgstr "finish area" - -#: fotoxx_area.cc:1083 -msgid "searching" -msgstr "searching" - -#: fotoxx_area.cc:1155 -msgid "outline has a gap" -msgstr "outline has a gap" - -#: fotoxx_area.cc:1157 -msgid "success" -msgstr "success" - -#: fotoxx_area.cc:1401 fotoxx_area.cc:1430 -msgid "the area is not finished" -msgstr "the area is not finished" - -#: fotoxx_area.cc:1522 -msgid "Edge calculation in progress" -msgstr "Edge calculation in progress" - -#: fotoxx_area.cc:1531 -msgid "Area Edge Calc" -msgstr "Area Edge Calc" - -#: fotoxx_area.cc:1824 -msgid "position with mouse click/drag" -msgstr "position with mouse click/drag" - -#: fotoxx_area.cc:1848 -msgid "Paste Image" -msgstr "Paste Image" - -#: fotoxx_area.cc:1863 -msgid "angle" -msgstr "angle" - -#: fotoxx_area.cc:2127 -msgid "load select area from a file" -msgstr "load select area from a file" - -#: fotoxx_area.cc:2161 -msgid "cannot open .tiff and .info files" -msgstr "cannot open .tiff and .info files" - -#: fotoxx_area.cc:2180 -msgid "save select area to a file" -msgstr "save select area to a file" - -#: fotoxx_area.cc:2216 -msgid "Edit Function Amplifier" -msgstr "Edit Function Amplifier" - -#: fotoxx_area.cc:2459 -msgid "mouse radius" -msgstr "mouse radius" - -#: fotoxx_area.cc:2462 -msgid "power: center" -msgstr "power: center" - -#: fotoxx_area.cc:2464 -msgid "edge" -msgstr "edge" - -#: fotoxx_area.cc:2468 -msgid "reset area" -msgstr "reset area" - -#: fotoxx_area.cc:2523 -msgid "start edit function first" -msgstr "start edit function first" - -#: fotoxx_art.cc:47 -msgid "Set color depth to 1-16 bits" -msgstr "Set color depth to 1-16 bits" - -#: fotoxx_art.cc:57 -msgid "Set Color Depth" -msgstr "Set Color Depth" - -#: fotoxx_art.cc:171 -msgid "Simulate Drawing" -msgstr "Simulate Drawing" - -#: fotoxx_art.cc:213 fotoxx_retouch.cc:1758 -msgid "contrast" -msgstr "contrast" - -#: fotoxx_art.cc:215 -msgid "outlines" -msgstr "outlines" - -#: fotoxx_art.cc:220 -msgid "pencil" -msgstr "pencil" - -#: fotoxx_art.cc:221 -msgid "chalk" -msgstr "chalk" - -#: fotoxx_art.cc:381 -msgid "Add Image Outlines" -msgstr "Add Image Outlines" - -#: fotoxx_art.cc:394 -msgid "outline threshold" -msgstr "outline threshold" - -#: fotoxx_art.cc:397 -msgid "outline width" -msgstr "outline width" - -#: fotoxx_art.cc:400 -msgid "image brightness" -msgstr "image brightness" - -#: fotoxx_art.cc:611 -msgid "Simulate Embossing" -msgstr "Simulate Embossing" - -#: fotoxx_art.cc:626 -msgid "depth" -msgstr "depth" - -#: fotoxx_art.cc:821 -msgid "Simulate Tiles" -msgstr "Simulate Tiles" - -#: fotoxx_art.cc:825 -msgid "tile size" -msgstr "tile size" - -#: fotoxx_art.cc:829 -msgid "tile gap" -msgstr "tile gap" - -#: fotoxx_art.cc:1003 -msgid "Convert Image to Dots" -msgstr "Convert Image to Dots" - -#: fotoxx_art.cc:1007 -msgid "dot size" -msgstr "dot size" - -#: fotoxx_art.cc:1222 -msgid "Simulate Painting" -msgstr "Simulate Painting" - -#: fotoxx_art.cc:1226 -msgid "color depth" -msgstr "color depth" - -#: fotoxx_art.cc:1230 -msgid "patch area goal" -msgstr "patch area goal" - -#: fotoxx_art.cc:1234 -msgid "req. color match" -msgstr "req. color match" - -#: fotoxx_art.cc:1238 -msgid "borders" -msgstr "borders" - -#: fotoxx_comp.cc:1956 fotoxx_comp.cc:1961 fotoxx_comp.cc:2582 -#: fotoxx_comp.cc:2587 fotoxx_comp.cc:3275 fotoxx_comp.cc:3280 -#: fotoxx_comp.cc:3830 fotoxx_comp.cc:3835 -msgid "Select 2 to 9 files" -msgstr "Select 2 to 9 files" - -#: fotoxx_comp.cc:1982 fotoxx_comp.cc:2608 fotoxx_comp.cc:3301 -#: fotoxx_comp.cc:3856 -msgid "Images are not all the same size" -msgstr "Images are not all the same size" - -#: fotoxx_comp.cc:2321 -msgid "Adjust Image Contributions" -msgstr "Adjust Image Contributions" - -#: fotoxx_comp.cc:2324 fotoxx_retouch.cc:885 -msgid "dark pixels" -msgstr "dark pixels" - -#: fotoxx_comp.cc:2326 -msgid "light pixels" -msgstr "light pixels" - -#: fotoxx_comp.cc:2328 fotoxx_info.cc:159 -msgid "file:" -msgstr "file:" - -#: fotoxx_comp.cc:2844 -msgid "Paint and Warp Image" -msgstr "Paint and Warp Image" - -#: fotoxx_comp.cc:2847 fotoxx_comp.cc:3529 fotoxx_comp.cc:4972 -#: fotoxx_comp.cc:5717 -msgid "image" -msgstr "image" - -#: fotoxx_comp.cc:2851 fotoxx_retouch.cc:5885 -msgid "paint" -msgstr "paint" - -#: fotoxx_comp.cc:2852 -msgid "warp" -msgstr "warp" - -#: fotoxx_comp.cc:3527 -msgid "Select and Paint Image" -msgstr "Select and Paint Image" - -#: fotoxx_comp.cc:4045 -msgid "Adjust Pixel Composition" -msgstr "Adjust Pixel Composition" - -#: fotoxx_comp.cc:4297 fotoxx_comp.cc:4302 fotoxx_comp.cc:5186 -#: fotoxx_comp.cc:5191 -msgid "Select 2 to 4 files" -msgstr "Select 2 to 4 files" - -#: fotoxx_comp.cc:4374 -msgid "" -"Drag images into rough alignment.\n" -"To rotate, drag from lower edge." -msgstr "" -"Drag images into rough alignment.\n" -"To rotate, drag from lower edge." - -#: fotoxx_comp.cc:4376 -msgid "Search for lens mm and bow" -msgstr "Search for lens mm and bow" - -#: fotoxx_comp.cc:4422 fotoxx_comp.cc:5310 -msgid "Pre-align Images" -msgstr "Pre-align Images" - -#: fotoxx_comp.cc:4426 fotoxx_comp.cc:5314 fotoxx_tools.cc:2151 -msgid "lens mm" -msgstr "lens mm" - -#: fotoxx_comp.cc:4430 fotoxx_comp.cc:5318 fotoxx_tools.cc:2156 -msgid "lens bow" -msgstr "lens bow" - -#: fotoxx_comp.cc:4432 fotoxx_comp.cc:5320 -msgid "Resize" -msgstr "Resize" - -#: fotoxx_comp.cc:4433 fotoxx_comp.cc:5321 -msgid "resize window" -msgstr "resize window" - -#: fotoxx_comp.cc:4470 -msgid "use two images only" -msgstr "use two images only" - -#: fotoxx_comp.cc:4491 fotoxx_comp.cc:4689 fotoxx_comp.cc:4888 -#: fotoxx_comp.cc:5369 fotoxx_comp.cc:5632 -msgid "Too little overlap, cannot align" -msgstr "Too little overlap, cannot align" - -#: fotoxx_comp.cc:4963 fotoxx_comp.cc:5708 -msgid "Match Brightness and Color" -msgstr "Match Brightness and Color" - -#: fotoxx_comp.cc:4987 fotoxx_comp.cc:5732 -msgid "auto color" -msgstr "auto color" - -#: fotoxx_comp.cc:4988 fotoxx_comp.cc:5733 -msgid "file color" -msgstr "file color" - -#: fotoxx_comp.cc:5263 -msgid "" -"Drag images into rough alignment.\n" -"To rotate, drag from right edge." -msgstr "" -"Drag images into rough alignment.\n" -"To rotate, drag from right edge." - -#: fotoxx_info.cc:70 -msgid "Edit Caption and Comments" -msgstr "Edit Caption and Comments" - -#: fotoxx_info.cc:163 -msgid "image date (yyyymmdd)" -msgstr "image date (yyyymmdd)" - -#: fotoxx_info.cc:165 -msgid "use last" -msgstr "use last" - -#: fotoxx_info.cc:168 -msgid "image stars" -msgstr "image stars" - -#: fotoxx_info.cc:186 -msgid "current tags" -msgstr "current tags" - -#: fotoxx_info.cc:191 -msgid "recent tags" -msgstr "recent tags" - -#: fotoxx_info.cc:196 fotoxx_info.cc:358 fotoxx_info.cc:1362 -#: fotoxx_info.cc:2290 -msgid "defined tags" -msgstr "defined tags" - -#: fotoxx_info.cc:348 -msgid "category" -msgstr "category" - -#: fotoxx_info.cc:351 -msgid "tag" -msgstr "tag" - -#: fotoxx_info.cc:354 -msgid "create" -msgstr "create" - -#: fotoxx_info.cc:355 -msgid "delete" -msgstr "delete" - -#: fotoxx_info.cc:1229 fotoxx_info.cc:1313 -#, c-format -msgid "search index file error: %s" -msgstr "search index file error: %s" - -#: fotoxx_info.cc:1348 -msgid "tags to add" -msgstr "tags to add" - -#: fotoxx_info.cc:1353 -msgid "create tag" -msgstr "create tag" - -#: fotoxx_info.cc:1409 fotoxx_info.cc:1602 -#, c-format -msgid "" -"%s \n" -" too many tags" -msgstr "" -"%s \n" -" too many tags" - -#: fotoxx_info.cc:1550 -msgid "tag to remove" -msgstr "tag to remove" - -#: fotoxx_info.cc:1554 -msgid "optional replacement" -msgstr "optional replacement" - -#: fotoxx_info.cc:1559 fotoxx_tools.cc:2463 -msgid "0 files selected" -msgstr "0 files selected" - -#: fotoxx_info.cc:1562 -msgid "search all files" -msgstr "search all files" - -#: fotoxx_info.cc:1647 -msgid "no files selected" -msgstr "no files selected" - -#: fotoxx_info.cc:1653 -msgid "no tag specified" -msgstr "no tag specified" - -#: fotoxx_info.cc:1677 fotoxx_info.cc:1706 -msgid "specify tag" -msgstr "specify tag" - -#: fotoxx_info.cc:1815 -msgid "View Info" -msgstr "View Info" - -#: fotoxx_info.cc:1983 -msgid "All" -msgstr "All" - -#: fotoxx_info.cc:1984 -msgid "One Key:" -msgstr "One Key:" - -#: fotoxx_info.cc:2249 -msgid "Search Tags, Comments, File Names" -msgstr "Search Tags, Comments, File Names" - -#: fotoxx_info.cc:2255 -msgid "date range" -msgstr "date range" - -#: fotoxx_info.cc:2256 -msgid "stars range" -msgstr "stars range" - -#: fotoxx_info.cc:2257 -msgid "search tags" -msgstr "search tags" - -#: fotoxx_info.cc:2258 -msgid "search text" -msgstr "search text" - -#: fotoxx_info.cc:2259 -msgid "file names" -msgstr "file names" - -#: fotoxx_info.cc:2264 -msgid "(yyyymmdd)" -msgstr "(yyyymmdd)" - -#: fotoxx_info.cc:2270 -msgid "all/any" -msgstr "all/any" - -#: fotoxx_info.cc:2598 -msgid "No matching images found" -msgstr "No matching images found" - -#: fotoxx_info.cc:2611 -msgid "No search index file present" -msgstr "No search index file present" - -#: fotoxx_info.cc:2615 -#, c-format -msgid "Search results file error %s" -msgstr "Search results file error %s" - -#: fotoxx_retouch.cc:55 -msgid "Adjust Brightness and Color" -msgstr "Adjust Brightness and Color" - -#: fotoxx_retouch.cc:109 -msgid "small-steps" -msgstr "small-steps" - -#: fotoxx_retouch.cc:118 -msgid "color saturation" -msgstr "color saturation" - -#: fotoxx_retouch.cc:125 -msgid " reset 1 " -msgstr " reset 1 " - -#: fotoxx_retouch.cc:126 -msgid "reset all" -msgstr "reset all" - -#: fotoxx_retouch.cc:598 -msgid "adjust image gamma" -msgstr "adjust image gamma" - -#: fotoxx_retouch.cc:884 -msgid "Expand Brightness Range" -msgstr "Expand Brightness Range" - -#: fotoxx_retouch.cc:886 -msgid "bright pixels" -msgstr "bright pixels" - -#: fotoxx_retouch.cc:1057 -msgid "Flatten Brightness Distribution" -msgstr "Flatten Brightness Distribution" - -#: fotoxx_retouch.cc:1071 -msgid "Flatten" -msgstr "Flatten" - -#: fotoxx_retouch.cc:1333 -msgid "Ramp brightness across image" -msgstr "Ramp brightness across image" - -#: fotoxx_retouch.cc:1757 -msgid "low" -msgstr "low" - -#: fotoxx_retouch.cc:1759 -msgid "high" -msgstr "high" - -#: fotoxx_retouch.cc:1762 -msgid "Amplify" -msgstr "Amplify" - -#: fotoxx_retouch.cc:2068 -msgid "Adjust White Balance" -msgstr "Adjust White Balance" - -#: fotoxx_retouch.cc:2069 -msgid "Click white or gray image location" -msgstr "Click white or gray image location" - -#: fotoxx_retouch.cc:2283 -msgid "Color Match Images" -msgstr "Color Match Images" - -#: fotoxx_retouch.cc:2312 -msgid "mouse radius for color sample" -msgstr "mouse radius for color sample" - -#: fotoxx_retouch.cc:2315 -msgid "image for source color" -msgstr "image for source color" - -#: fotoxx_retouch.cc:2317 -msgid "click on image to get source color" -msgstr "click on image to get source color" - -#: fotoxx_retouch.cc:2320 -msgid "image to set matching color" -msgstr "image to set matching color" - -#: fotoxx_retouch.cc:2322 -msgid "click on image to set matching color" -msgstr "click on image to set matching color" - -#: fotoxx_retouch.cc:2377 -msgid "select source image color first" -msgstr "select source image color first" - -#: fotoxx_retouch.cc:2903 fotoxx_tools.cc:1643 -msgid "Click image to select pixels." -msgstr "Click image to select pixels." - -#: fotoxx_retouch.cc:2955 -msgid "Metric:" -msgstr "Metric:" - -#: fotoxx_retouch.cc:3010 -msgid "Blend" -msgstr "Blend" - -#: fotoxx_retouch.cc:3394 -msgid "" -"Method 1:\n" -" Left-click on red-eye to darken.\n" -"Method 2:\n" -" Drag down and right to enclose red-eye.\n" -" Left-click on red-eye to darken.\n" -"Undo red-eye:\n" -" Right-click on red-eye." -msgstr "" -"Method 1:\n" -" Left-click on red-eye to darken.\n" -"Method 2:\n" -" Drag down and right to enclose red-eye.\n" -" Left-click on red-eye to darken.\n" -"Undo red-eye:\n" -" Right-click on red-eye." - -#: fotoxx_retouch.cc:3409 -msgid "Red Eye Reduction" -msgstr "Red Eye Reduction" - -#: fotoxx_retouch.cc:3850 -msgid "Set Blur Radius" -msgstr "Set Blur Radius" - -#: fotoxx_retouch.cc:4084 -msgid "edge detection" -msgstr "edge detection" - -#: fotoxx_retouch.cc:4085 -msgid "cycles" -msgstr "cycles" - -#: fotoxx_retouch.cc:4086 -msgid "reduce" -msgstr "reduce" - -#: fotoxx_retouch.cc:4097 -msgid "unsharp mask" -msgstr "unsharp mask" - -#: fotoxx_retouch.cc:4110 -msgid "brightness gradient" -msgstr "brightness gradient" - -#: fotoxx_retouch.cc:4516 -msgid "" -" Press the reduce button to \n" -" reduce noise in small steps. \n" -" Use undo to start over." -msgstr "" -" Press the reduce button to \n" -" reduce noise in small steps. \n" -" Use undo to start over." - -#: fotoxx_retouch.cc:4527 -msgid "Noise Reduction" -msgstr "Noise Reduction" - -#: fotoxx_retouch.cc:4532 -msgid "algorithm" -msgstr "algorithm" - -#: fotoxx_retouch.cc:4539 -msgid "flatten outliers by color (1)" -msgstr "flatten outliers by color (1)" - -#: fotoxx_retouch.cc:4540 -msgid "flatten outliers by color (2)" -msgstr "flatten outliers by color (2)" - -#: fotoxx_retouch.cc:4541 -msgid "set median brightness by color" -msgstr "set median brightness by color" - -#: fotoxx_retouch.cc:4542 fotoxx_retouch.cc:4543 -msgid "top hat filter by color" -msgstr "top hat filter by color" - -#: fotoxx_retouch.cc:4858 -msgid "" -"1. Drag mouse to select. \n" -"2. Erase. 3. Repeat. " -msgstr "" -"1. Drag mouse to select. \n" -"2. Erase. 3. Repeat. " - -#: fotoxx_retouch.cc:4889 -msgid "Radius" -msgstr "Radius" - -#: fotoxx_retouch.cc:4891 -msgid "Blur" -msgstr "Blur" - -#: fotoxx_retouch.cc:4894 -msgid "New Area" -msgstr "New Area" - -#: fotoxx_retouch.cc:5275 -msgid "spot size limit" -msgstr "spot size limit" - -#: fotoxx_retouch.cc:5278 -msgid "max. brightness" -msgstr "max. brightness" - -#: fotoxx_retouch.cc:5281 -msgid "min. contrast" -msgstr "min. contrast" - -#: fotoxx_retouch.cc:5875 -#, c-format -msgid "Undo Memory %d%c" -msgstr "Undo Memory %d%c" - -#: fotoxx_retouch.cc:5884 -msgid "pick" -msgstr "pick" - -#: fotoxx_retouch.cc:5886 -msgid "erase" -msgstr "erase" - -#: fotoxx_retouch.cc:5894 -msgid "paintbrush radius" -msgstr "paintbrush radius" - -#: fotoxx_retouch.cc:5895 -msgid "transparency center" -msgstr "transparency center" - -#: fotoxx_retouch.cc:5896 -msgid "transparency edge" -msgstr "transparency edge" - -#: fotoxx_retouch.cc:6166 -msgid "" -"Undo memory limit has been reached. \n" -"Save work with [done], then resume editing." -msgstr "" -"Undo memory limit has been reached. \n" -"Save work with [done], then resume editing." - -#: fotoxx_tools.cc:42 -msgid "" -"When editing a collection, right-click \n" -"an image or thumbnail to add or remove." -msgstr "" -"When editing a collection, right-click \n" -"an image or thumbnail to add or remove." - -#: fotoxx_tools.cc:85 -msgid "Start new collection" -msgstr "Start new collection" - -#: fotoxx_tools.cc:87 -msgid "Edit a collection" -msgstr "Edit a collection" - -#: fotoxx_tools.cc:89 -msgid "View a collection" -msgstr "View a collection" - -#: fotoxx_tools.cc:91 -msgid "Delete a collection" -msgstr "Delete a collection" - -#: fotoxx_tools.cc:95 -msgid "Editing:" -msgstr "Editing:" - -#: fotoxx_tools.cc:99 -msgid "Action:" -msgstr "Action:" - -#: fotoxx_tools.cc:133 -msgid "New Collection" -msgstr "New Collection" - -#: fotoxx_tools.cc:156 -msgid "Edit Collection" -msgstr "Edit Collection" - -#: fotoxx_tools.cc:172 -msgid "View Collection" -msgstr "View Collection" - -#: fotoxx_tools.cc:193 -msgid "Delete Collection" -msgstr "Delete Collection" - -#: fotoxx_tools.cc:196 -#, c-format -msgid "delete %s ?" -msgstr "delete %s ?" - -#: fotoxx_tools.cc:223 -#, c-format -msgid "add image to collection: %s" -msgstr "add image to collection: %s" - -#: fotoxx_tools.cc:225 fotoxx_tools.cc:270 -msgid "remove image from collection" -msgstr "remove image from collection" - -#: fotoxx_tools.cc:226 fotoxx_tools.cc:271 fotoxx_tools.cc:298 -msgid "remove and save image" -msgstr "remove and save image" - -#: fotoxx_tools.cc:227 fotoxx_tools.cc:316 -msgid "insert saved images here" -msgstr "insert saved images here" - -#: fotoxx_tools.cc:256 -msgid "add image to collection" -msgstr "add image to collection" - -#: fotoxx_tools.cc:301 -msgid "too many saved files" -msgstr "too many saved files" - -#: fotoxx_tools.cc:375 -msgid "old top directory" -msgstr "old top directory" - -#: fotoxx_tools.cc:378 -msgid "new top directory" -msgstr "new top directory" - -#: fotoxx_tools.cc:434 -msgid "completed" -msgstr "completed" - -#: fotoxx_tools.cc:452 -msgid "" -"Brightness should show a gradual ramp \n" -"extending all the way to the edges." -msgstr "" -"Brightness should show a gradual ramp \n" -"extending all the way to the edges." - -#: fotoxx_tools.cc:492 -msgid "Monitor Check" -msgstr "Monitor Check" - -#: fotoxx_tools.cc:612 -msgid "Brightness Distribution" -msgstr "Brightness Distribution" - -#: fotoxx_tools.cc:796 -msgid "Press ESC to exit slide show" -msgstr "Press ESC to exit slide show" - -#: fotoxx_tools.cc:797 -msgid "show only latest file versions" -msgstr "show only latest file versions" - -#: fotoxx_tools.cc:801 -msgid "arrow keys" -msgstr "arrow keys" - -#: fotoxx_tools.cc:802 -msgid "instant" -msgstr "instant" - -#: fotoxx_tools.cc:803 -msgid "fade-in" -msgstr "fade-in" - -#: fotoxx_tools.cc:804 -msgid "roll-right" -msgstr "roll-right" - -#: fotoxx_tools.cc:805 -msgid "roll-down" -msgstr "roll-down" - -#: fotoxx_tools.cc:806 -msgid "shift-left" -msgstr "shift-left" - -#: fotoxx_tools.cc:807 -msgid "venetian" -msgstr "venetian" - -#: fotoxx_tools.cc:808 -msgid "grate" -msgstr "grate" - -#: fotoxx_tools.cc:811 -msgid "radar" -msgstr "radar" - -#: fotoxx_tools.cc:812 -msgid "jaws" -msgstr "jaws" - -#: fotoxx_tools.cc:823 -msgid "seconds" -msgstr "seconds" - -#: fotoxx_tools.cc:827 -msgid "music file" -msgstr "music file" - -#: fotoxx_tools.cc:831 -msgid "transitions" -msgstr "transitions" - -#: fotoxx_tools.cc:948 -msgid "Select music file or playlist" -msgstr "Select music file or playlist" - -#: fotoxx_tools.cc:1971 -msgid "x-spacing" -msgstr "x-spacing" - -#: fotoxx_tools.cc:1972 -msgid "x-count" -msgstr "x-count" - -#: fotoxx_tools.cc:1973 -msgid "x-enable" -msgstr "x-enable" - -#: fotoxx_tools.cc:1979 -msgid "y-spacing" -msgstr "y-spacing" - -#: fotoxx_tools.cc:1980 -msgid "y-count" -msgstr "y-count" - -#: fotoxx_tools.cc:1981 -msgid "y-enable" -msgstr "y-enable" - -#: fotoxx_tools.cc:1988 -msgid "x-offset" -msgstr "x-offset" - -#: fotoxx_tools.cc:1992 -msgid "y-offset" -msgstr "y-offset" - -#: fotoxx_tools.cc:2146 -msgid "lens name" -msgstr "lens name" - -#: fotoxx_tools.cc:2220 -msgid "Available Translations" -msgstr "Available Translations" - -#: fotoxx_tools.cc:2224 -msgid "Set Language" -msgstr "Set Language" - -#: fotoxx_tools.cc:2290 -msgid "Make Launcher" -msgstr "Make Launcher" - -#: fotoxx_tools.cc:2310 -msgid "Program ufraw-batch is required" -msgstr "Program ufraw-batch is required" - -#: fotoxx_tools.cc:2320 -msgid "Open RAW File" -msgstr "Open RAW File" - -#: fotoxx_tools.cc:2331 -msgid "Select RAW files to convert" -msgstr "Select RAW files to convert" - -#: fotoxx_tools.cc:2467 -msgid "max. width" -msgstr "max. width" - -#: fotoxx_tools.cc:2468 -msgid "max. height" -msgstr "max. height" - -#: fotoxx_tools.cc:2527 fotoxx_transform.cc:1268 -#, c-format -msgid "max. size %d x %d is not reasonable" -msgstr "max. size %d x %d is not reasonable" - -#: fotoxx_tools.cc:2613 -msgid "too many files" -msgstr "too many files" - -#: fotoxx_tools.cc:2656 -msgid "Sync Files is already running" -msgstr "Sync Files is already running" - -#: fotoxx_tools.cc:2707 -msgid "" -"Run Tools > Synchronize Files so that gallery windows \n" -"will be fast and Search Images will work correctly. \n" -"You can view (not edit) images while synchronize runs." -msgstr "" -"Run Tools > Synchronize Files so that gallery windows \n" -"will be fast and Search Images will work correctly. \n" -"You can view (not edit) images while synchronize runs." - -#: fotoxx_tools.cc:2736 -msgid "no top image directory is defined" -msgstr "no top image directory is defined" - -#: fotoxx_tools.cc:2742 -msgid "top image directory is invalid" -msgstr "top image directory is invalid" - -#: fotoxx_tools.cc:2747 -msgid "no search index file is present" -msgstr "no search index file is present" - -#: fotoxx_tools.cc:2761 -msgid "new/modified files are present" -msgstr "new/modified files are present" - -#: fotoxx_tools.cc:2768 -msgid "no new files found" -msgstr "no new files found" - -#: fotoxx_tools.cc:2785 -msgid "Top Image Directory:" -msgstr "Top Image Directory:" - -#: fotoxx_tools.cc:2807 -msgid "file sync is mandatory" -msgstr "file sync is mandatory" - -#: fotoxx_tools.cc:2817 -msgid "top directory is invalid" -msgstr "top directory is invalid" - -#: fotoxx_tools.cc:3201 -msgid "Select top image directory" -msgstr "Select top image directory" - -#: fotoxx_tools.cc:3378 -msgid "icons" -msgstr "icons" - -#: fotoxx_tools.cc:3379 fotoxx_transform.cc:1467 -msgid "text" -msgstr "text" - -#: fotoxx_tools.cc:3380 -msgid "both" -msgstr "both" - -#: fotoxx_transform.cc:50 -msgid "Use buttons or drag right edge with mouse" -msgstr "Use buttons or drag right edge with mouse" - -#: fotoxx_transform.cc:64 -msgid "degrees" -msgstr "degrees" - -#: fotoxx_transform.cc:80 fotoxx_transform.cc:124 -msgid "Trim" -msgstr "Trim" - -#: fotoxx_transform.cc:81 fotoxx_transform.cc:2437 fotoxx_transform.cc:3263 -#: fotoxx_transform.cc:3526 fotoxx_transform.cc:3787 -msgid "Grid" -msgstr "Grid" - -#: fotoxx_transform.cc:123 -msgid "Undo Trim" -msgstr "Undo Trim" - -#: fotoxx_transform.cc:139 -#, c-format -msgid "degrees: %.1f" -msgstr "degrees: %.1f" - -#: fotoxx_transform.cc:286 -msgid "gold" -msgstr "gold" - -#: fotoxx_transform.cc:332 -msgid "Drag middle to move, drag corners to resize." -msgstr "Drag middle to move, drag corners to resize." - -#: fotoxx_transform.cc:346 -msgid "customize" -msgstr "customize" - -#: fotoxx_transform.cc:357 -msgid "ratio" -msgstr "ratio" - -#: fotoxx_transform.cc:361 -msgid "Lock Ratio" -msgstr "Lock Ratio" - -#: fotoxx_transform.cc:367 -msgid "invert" -msgstr "invert" - -#: fotoxx_transform.cc:892 -msgid "Trim Buttons" -msgstr "Trim Buttons" - -#: fotoxx_transform.cc:964 -msgid "Lock aspect ratio" -msgstr "Lock aspect ratio" - -#: fotoxx_transform.cc:1145 -msgid "Batch Resize" -msgstr "Batch Resize" - -#: fotoxx_transform.cc:1153 -msgid "new max. width" -msgstr "new max. width" - -#: fotoxx_transform.cc:1154 -msgid "new max. height" -msgstr "new max. height" - -#: fotoxx_transform.cc:1161 -msgid "replace originals" -msgstr "replace originals" - -#: fotoxx_transform.cc:1162 -msgid "export to location" -msgstr "export to location" - -#: fotoxx_transform.cc:1166 -msgid "copy EXIF" -msgstr "copy EXIF" - -#: fotoxx_transform.cc:1219 -msgid "Select directory" -msgstr "Select directory" - -#: fotoxx_transform.cc:1243 -#, c-format -msgid "replace original files? (max. %d x %d)" -msgstr "replace original files? (max. %d x %d)" - -#: fotoxx_transform.cc:1250 -#, c-format -msgid "" -"copy files? (max. %d x %d) \n" -" to location %s" -msgstr "" -"copy files? (max. %d x %d) \n" -" to location %s" - -#: fotoxx_transform.cc:1261 -msgid "location is not a valid directory" -msgstr "location is not a valid directory" - -#: fotoxx_transform.cc:1304 -msgid "new file already exists" -msgstr "new file already exists" - -#: fotoxx_transform.cc:1388 -msgid "" -"Enter text, click/drag on image.\n" -"Right click to remove" -msgstr "" -"Enter text, click/drag on image.\n" -"Right click to remove" - -#: fotoxx_transform.cc:1442 -msgid "Text" -msgstr "Text" - -#: fotoxx_transform.cc:1449 -msgid "Size" -msgstr "Size" - -#: fotoxx_transform.cc:1452 -msgid "Angle" -msgstr "Angle" - -#: fotoxx_transform.cc:1463 -msgid "Color" -msgstr "Color" - -#: fotoxx_transform.cc:1464 -msgid "Transparency" -msgstr "Transparency" - -#: fotoxx_transform.cc:1472 -msgid "backing" -msgstr "backing" - -#: fotoxx_transform.cc:1475 -msgid "" -"Outline\n" -" Width" -msgstr "" -"Outline\n" -" Width" - -#: fotoxx_transform.cc:1477 -msgid "outline" -msgstr "outline" - -#: fotoxx_transform.cc:1486 -msgid "Annotation File:" -msgstr "Annotation File:" - -#: fotoxx_transform.cc:1564 -msgid "select font" -msgstr "select font" - -#: fotoxx_transform.cc:2197 fotoxx_transform.cc:2429 -msgid "horizontal" -msgstr "horizontal" - -#: fotoxx_transform.cc:2198 fotoxx_transform.cc:2428 -msgid "vertical" -msgstr "vertical" - -#: fotoxx_transform.cc:2306 -msgid "black/white positive" -msgstr "black/white positive" - -#: fotoxx_transform.cc:2307 -msgid "black/white negative" -msgstr "black/white negative" - -#: fotoxx_transform.cc:2308 -msgid "color positive" -msgstr "color positive" - -#: fotoxx_transform.cc:2309 -msgid "color negative" -msgstr "color negative" - -#: fotoxx_transform.cc:2430 -msgid "linear" -msgstr "linear" - -#: fotoxx_transform.cc:2433 -msgid "curved" -msgstr "curved" - -#: fotoxx_transform.cc:2692 -msgid "" -" Click the four corners of a tetragon area. Press [apply]. \n" -" The image is warped to make the tetragon into a rectangle." -msgstr "" -" Click the four corners of a tetragon area. Press [apply]. \n" -" The image is warped to make the tetragon into a rectangle." - -#: fotoxx_transform.cc:2878 -msgid "must have 4 corners" -msgstr "must have 4 corners" - -#: fotoxx_transform.cc:2999 -msgid "" -" Select an area to warp using select area function. \n" -" Press [start warp] and pull area with mouse. \n" -" Make multiple mouse pulls until satisfied. \n" -" When finished, select another area or press [done]." -msgstr "" -" Select an area to warp using select area function. \n" -" Press [start warp] and pull area with mouse. \n" -" Make multiple mouse pulls until satisfied. \n" -" When finished, select another area or press [done]." - -#: fotoxx_transform.cc:3018 -msgid "start warp" -msgstr "start warp" - -#: fotoxx_transform.cc:3067 -msgid "Select area first" -msgstr "Select area first" - -#: fotoxx_transform.cc:3242 fotoxx_transform.cc:3505 -msgid "" -" Pull an image position using the mouse. \n" -" Make multiple mouse pulls until satisfied. \n" -" When finished, press [done]." -msgstr "" -" Pull an image position using the mouse. \n" -" Make multiple mouse pulls until satisfied. \n" -" When finished, press [done]." - -#: fotoxx_transform.cc:3771 -msgid "" -" Pull on an image corner using the mouse. \n" -" Make multiple mouse pulls until satisfied. \n" -" When finished, press [done]." -msgstr "" -" Pull on an image corner using the mouse. \n" -" Make multiple mouse pulls until satisfied. \n" -" When finished, press [done]." - -#~ msgid "%d new/modified files found" -#~ msgstr "%d new/modified files found" - -#~ msgid "incremental" -#~ msgstr "incremental" - -#~ msgid "full rebuild" -#~ msgstr "full rebuild" - -#~ msgid "y-grid" -#~ msgstr "y-grid" - -#~ msgid "x-grid" -#~ msgstr "x-grid" - -#~ msgid "enable" -#~ msgstr "enable" - -#~ msgid "" -#~ "Click on image where new or saved \n" -#~ "images are to be inserted (after)." -#~ msgstr "" -#~ "Click on image where new or saved \n" -#~ "images are to be inserted (after)." - -#~ msgid "" -#~ "Click on images to remove and save, \n" -#~ "then press [Paste] to insert them." -#~ msgstr "" -#~ "Click on images to remove and save, \n" -#~ "then press [Paste] to insert them." - -#~ msgid "Click on images to delete." -#~ msgstr "Click on images to delete." - -#~ msgid "select image files" -#~ msgstr "select image files" - -#~ msgid "" -#~ "Select images to add, then \n" -#~ "press [Paste] to insert them." -#~ msgstr "" -#~ "Select images to add, then \n" -#~ "press [Paste] to insert them." - -#~ msgid "Insert new or saved images" -#~ msgstr "Insert new or saved images" - -#~ msgid "Remove and save images" -#~ msgstr "Remove and save images" - -#~ msgid "Delete images from collection" -#~ msgstr "Delete images from collection" - -#~ msgid "Add new images to collection" -#~ msgstr "Add new images to collection" - -#~ msgid "Save Collection" -#~ msgstr "Save Collection" - -#~ msgid "Synchronize Files needed" -#~ msgstr "Synchronize Files needed" - -#~ msgid "%d files modified since last fotoxx use" -#~ msgstr "%d files modified since last fotoxx use" - -#~ msgid "" -#~ "Run Tools > Synchronize Files so that gallery windows \n" -#~ "will be fast and Search Images will work correctly." -#~ msgstr "" -#~ "Run Tools > Synchronize Files so that gallery windows \n" -#~ "will be fast and Search Images will work correctly." - -#~ msgid "Translate" -#~ msgstr "Translate" - -#~ msgid "Straighten Image" -#~ msgstr "Straighten Image" - -#~ msgid "Open Collection" -#~ msgstr "Open Collection" - -#~ msgid "Create Collection" -#~ msgstr "Create Collection" diff -Nru fotoxx-11.11.1/locales/en/zfuncs.po fotoxx-12.01.2/locales/en/zfuncs.po --- fotoxx-11.11.1/locales/en/zfuncs.po 2011-11-05 05:30:36.000000000 +0000 +++ fotoxx-12.01.2/locales/en/zfuncs.po 1970-01-01 00:00:00.000000000 +0000 @@ -1,290 +0,0 @@ -# English translations for home package. -# Copyright (C) 2011 THE home'S COPYRIGHT HOLDER -# This file is distributed under the same license as the home package. -# mico , 2011. -# -msgid "" -msgstr "" -"Project-Id-Version: home 2\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2011-11-05 05:48+0100\n" -"PO-Revision-Date: 2011-04-08 14:44+0200\n" -"Last-Translator: mico \n" -"Language-Team: English\n" -"Language: en\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=ASCII\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#: zfuncs.cc:3192 -#, c-format -msgid "help file not found: %s" -msgstr "help file not found: %s" - -#: zfuncs.cc:3296 -#, c-format -msgid "error: %s" -msgstr "error: %s" - -#: zfuncs.cc:4415 zfuncs.cc:8771 -#, c-format -msgid "cannot open file %s" -msgstr "cannot open file %s" - -#: zfuncs.cc:4448 -msgid "save screen to file" -msgstr "save screen to file" - -#: zfuncs.cc:6198 -msgid "No" -msgstr "No" - -#: zfuncs.cc:6198 -msgid "Yes" -msgstr "Yes" - -#: zfuncs.cc:6272 zfuncs.cc:6308 zfuncs.cc:6461 zfuncs.cc:6865 zfuncs.cc:8358 -#: zfuncs.cc:8883 zfuncs.cc:8889 zfuncs.cc:8895 zfuncs.cc:8901 -msgid "cancel" -msgstr "cancel" - -#: zfuncs.cc:6423 zfuncs.cc:7552 -msgid "open" -msgstr "open" - -#: zfuncs.cc:6428 -msgid "choose" -msgstr "choose" - -#: zfuncs.cc:6433 -msgid "save" -msgstr "save" - -#: zfuncs.cc:6439 -msgid "open folder" -msgstr "open folder" - -#: zfuncs.cc:6444 -msgid "create folder" -msgstr "create folder" - -#: zfuncs.cc:6450 -msgid "hidden" -msgstr "hidden" - -#: zfuncs.cc:6454 -msgid "quality" -msgstr "quality" - -#: zfuncs.cc:6511 -msgid "JPG quality 0-100" -msgstr "JPG quality 0-100" - -#: zfuncs.cc:6865 zfuncs.cc:8358 -msgid "done" -msgstr "done" - -#: zfuncs.cc:6865 zfuncs.cc:6878 -msgid "margins" -msgstr "margins" - -#: zfuncs.cc:6874 -msgid "top" -msgstr "top" - -#: zfuncs.cc:6875 -msgid "bottom" -msgstr "bottom" - -#: zfuncs.cc:6876 -msgid "left" -msgstr "left" - -#: zfuncs.cc:6877 -msgid "right" -msgstr "right" - -#: zfuncs.cc:7278 zfuncs.cc:7532 zfuncs.cc:7670 zfuncs.cc:7671 zfuncs.cc:7673 -msgid "bigger" -msgstr "bigger" - -#: zfuncs.cc:7278 -msgid "increase thumbnail size" -msgstr "increase thumbnail size" - -#: zfuncs.cc:7279 -msgid "reduce thumbnail size" -msgstr "reduce thumbnail size" - -#: zfuncs.cc:7279 zfuncs.cc:7542 zfuncs.cc:7672 zfuncs.cc:7674 -msgid "smaller" -msgstr "smaller" - -#: zfuncs.cc:7280 zfuncs.cc:7571 -msgid "parent" -msgstr "parent" - -#: zfuncs.cc:7280 -msgid "parent directory" -msgstr "parent directory" - -#: zfuncs.cc:7281 zfuncs.cc:7589 zfuncs.cc:7681 -msgid "first page" -msgstr "first page" - -#: zfuncs.cc:7281 -msgid "jump to first file" -msgstr "jump to first file" - -#: zfuncs.cc:7282 zfuncs.cc:7587 zfuncs.cc:7676 zfuncs.cc:7683 -msgid "prev page" -msgstr "prev page" - -#: zfuncs.cc:7282 -msgid "previous page" -msgstr "previous page" - -#: zfuncs.cc:7283 zfuncs.cc:7585 zfuncs.cc:7678 -msgid "prev row" -msgstr "prev row" - -#: zfuncs.cc:7283 -msgid "previous row" -msgstr "previous row" - -#: zfuncs.cc:7284 zfuncs.cc:7586 zfuncs.cc:7679 -msgid "next row" -msgstr "next row" - -#: zfuncs.cc:7285 zfuncs.cc:7588 zfuncs.cc:7677 zfuncs.cc:7684 -msgid "next page" -msgstr "next page" - -#: zfuncs.cc:7286 -msgid "jump to last file" -msgstr "jump to last file" - -#: zfuncs.cc:7286 zfuncs.cc:7590 zfuncs.cc:7682 -msgid "last page" -msgstr "last page" - -#: zfuncs.cc:7287 zfuncs.cc:7527 -msgid "close" -msgstr "close" - -#: zfuncs.cc:7287 -msgid "close image gallery" -msgstr "close image gallery" - -#: zfuncs.cc:7558 -msgid "select new file" -msgstr "select new file" - -#: zfuncs.cc:8358 -msgid "Select Files" -msgstr "Select Files" - -#: zfuncs.cc:8366 -msgid "delete" -msgstr "delete" - -#: zfuncs.cc:8367 -msgid "insert" -msgstr "insert" - -#: zfuncs.cc:8368 -msgid "add all" -msgstr "add all" - -#: zfuncs.cc:8658 -msgid "" -"Initial parameters file created. \n" -"Inspect and revise if necessary." -msgstr "" -"Initial parameters file created. \n" -"Inspect and revise if necessary." - -#: zfuncs.cc:8674 -msgid "load parameters from a file" -msgstr "load parameters from a file" - -#: zfuncs.cc:8743 -msgid "save parameters to a file" -msgstr "save parameters to a file" - -#: zfuncs.cc:8881 zfuncs.cc:8887 zfuncs.cc:8893 zfuncs.cc:8899 -msgid "edit parameters" -msgstr "edit parameters" - -#: zfuncs.cc:8882 zfuncs.cc:8888 -msgid "" -"list\n" -"all" -msgstr "" -"list\n" -"all" - -#: zfuncs.cc:8882 zfuncs.cc:8888 zfuncs.cc:8894 zfuncs.cc:8900 -msgid "" -"load\n" -"file" -msgstr "" -"load\n" -"file" - -#: zfuncs.cc:8882 zfuncs.cc:8888 zfuncs.cc:8894 zfuncs.cc:8900 -msgid "" -"save\n" -"file" -msgstr "" -"save\n" -"file" - -#: zfuncs.cc:8883 zfuncs.cc:8895 -msgid "" -"add\n" -"new" -msgstr "" -"add\n" -"new" - -#: zfuncs.cc:8883 zfuncs.cc:8889 zfuncs.cc:8895 zfuncs.cc:8901 -msgid "apply" -msgstr "apply" - -#: zfuncs.cc:8935 -msgid "apply?" -msgstr "apply?" - -#: zfuncs.cc:8992 -msgid "(new parm name)" -msgstr "(new parm name)" - -#: zfuncs.cc:8992 -msgid "add parameter" -msgstr "add parameter" - -#~ msgid "paper format is crazy" -#~ msgstr "paper format is crazy" - -#~ msgid "margins:" -#~ msgstr "margins" - -#~ msgid "landscape" -#~ msgstr "landscape" - -#~ msgid "portrait" -#~ msgstr "portrait" - -#~ msgid "paper format" -#~ msgstr "paper format" - -#~ msgid "printer ID" -#~ msgstr "printer ID" - -#~ msgid "print" -#~ msgstr "print" - -#~ msgid "open a file" -#~ msgstr "open a file" diff -Nru fotoxx-11.11.1/locales/es/fotoxx.po fotoxx-12.01.2/locales/es/fotoxx.po --- fotoxx-11.11.1/locales/es/fotoxx.po 2011-11-05 05:30:37.000000000 +0000 +++ fotoxx-12.01.2/locales/es/fotoxx.po 1970-01-01 00:00:00.000000000 +0000 @@ -1,2772 +0,0 @@ -# Spanish translations for home package. -# Copyright (C) 2008 THE home'S COPYRIGHT HOLDER -# This file is distributed under the same license as the home package. -# mico , 2008. -# -msgid "" -msgstr "" -"Project-Id-Version: fotoxx-6.9.2\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2011-11-05 05:49+0100\n" -"PO-Revision-Date: 2009-11-04 23:35+0100\n" -"Last-Translator: Miguel Anxo Bouzada \n" -"Language-Team: GALPon MiniNo \n" -"Language: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Poedit-Language: Spanish\n" -"X-Poedit-Country: SPAIN\n" - -#: fotoxx-11.11.1.cc:179 -msgid "File" -msgstr "Archivo" - -#: fotoxx-11.11.1.cc:180 fotoxx-11.11.1.cc:316 -msgid "Image Gallery" -msgstr "Galería de imágenes" - -#: fotoxx-11.11.1.cc:181 -msgid "Clone 50/50" -msgstr "" - -#: fotoxx-11.11.1.cc:182 -msgid "Clone Overlay" -msgstr "" - -#: fotoxx-11.11.1.cc:183 fotoxx-11.11.1.cc:317 fotoxx-11.11.1.cc:2272 -#: fotoxx-11.11.1.cc:2444 -msgid "Open Image File" -msgstr "Abrir archivo de imagen" - -#: fotoxx-11.11.1.cc:184 -msgid "Open in New Window" -msgstr "" - -#: fotoxx-11.11.1.cc:185 fotoxx-11.11.1.cc:318 -msgid "Open Previous File" -msgstr "Abrir archivo anterior" - -#: fotoxx-11.11.1.cc:186 -msgid "Open Recent File" -msgstr "Abrir archivo reciente" - -#: fotoxx-11.11.1.cc:187 fotoxx-11.11.1.cc:326 -msgid "Save to Same File" -msgstr "Guardar en el mismo archivo" - -#: fotoxx-11.11.1.cc:188 fotoxx-11.11.1.cc:327 -msgid "Save to New Version" -msgstr "" - -#: fotoxx-11.11.1.cc:189 fotoxx-11.11.1.cc:328 -msgid "Save to New File" -msgstr "Guardar en un archivo nuevo" - -#: fotoxx-11.11.1.cc:190 fotoxx-11.11.1.cc:2990 -msgid "Create Blank Image" -msgstr "" - -#: fotoxx-11.11.1.cc:191 -msgid "Trash Image File" -msgstr "Mover imagen a la papelera" - -#: fotoxx-11.11.1.cc:192 fotoxx-11.11.1.cc:3216 -msgid "Rename Image File" -msgstr "Renombrar archivo de imagen" - -#: fotoxx-11.11.1.cc:193 -msgid "Batch Rename Files" -msgstr "" - -#: fotoxx-11.11.1.cc:194 -msgid "Print Image File" -msgstr "Imprimir archivo de imagen" - -#: fotoxx-11.11.1.cc:195 fotoxx-11.11.1.cc:332 -msgid "Quit fotoxx" -msgstr "Salir de Fotoxx" - -#: fotoxx-11.11.1.cc:197 -msgid "Tools" -msgstr "Herramientas" - -#: fotoxx-11.11.1.cc:198 fotoxx_tools.cc:70 -msgid "Manage Collections" -msgstr "" - -#: fotoxx-11.11.1.cc:199 fotoxx_tools.cc:373 -msgid "Move Collections" -msgstr "" - -#: fotoxx-11.11.1.cc:200 -msgid "Check Monitor" -msgstr "Comprobar monitor" - -#: fotoxx-11.11.1.cc:201 fotoxx_tools.cc:550 -msgid "Monitor Gamma" -msgstr "" - -#: fotoxx-11.11.1.cc:202 -msgid "Brightness Graph" -msgstr "Gráfica de brillo" - -#: fotoxx-11.11.1.cc:203 fotoxx_tools.cc:819 -msgid "Slide Show" -msgstr "Diaporama" - -#: fotoxx-11.11.1.cc:204 fotoxx_tools.cc:1668 -msgid "Show RGB" -msgstr "Mostrar RGB" - -#: fotoxx-11.11.1.cc:205 fotoxx_tools.cc:1962 -msgid "Grid Lines" -msgstr "" - -#: fotoxx-11.11.1.cc:206 fotoxx_tools.cc:2135 -msgid "Lens Parameters" -msgstr "Parámetros de óptica" - -#: fotoxx-11.11.1.cc:207 -msgid "Change Language" -msgstr "Cambiar el idioma" - -#: fotoxx-11.11.1.cc:209 -msgid "Add Menu and Launcher" -msgstr "" - -#: fotoxx-11.11.1.cc:210 -msgid "Convert RAW files" -msgstr "Convetir múltiples archivos RAW" - -#: fotoxx-11.11.1.cc:211 -msgid "Burn Images to CD/DVD" -msgstr "Grabar imágenes en un CD/DVD" - -#: fotoxx-11.11.1.cc:212 fotoxx_tools.cc:2460 -msgid "E-mail Images" -msgstr "" - -#: fotoxx-11.11.1.cc:213 fotoxx_tools.cc:2783 -msgid "Synchronize Files" -msgstr "" - -#: fotoxx-11.11.1.cc:214 fotoxx_tools.cc:3376 -msgid "Toolbar Style" -msgstr "" - -#: fotoxx-11.11.1.cc:215 -msgid "Memory Usage" -msgstr "" - -#: fotoxx-11.11.1.cc:218 -msgid "Edit Caption/Comments" -msgstr "" - -#: fotoxx-11.11.1.cc:219 fotoxx_info.cc:156 -msgid "Edit Tags" -msgstr "Editar etiquetas" - -#: fotoxx-11.11.1.cc:220 fotoxx_info.cc:345 -msgid "Manage Tags" -msgstr "" - -#: fotoxx-11.11.1.cc:221 fotoxx_info.cc:1345 -msgid "Batch Add Tags" -msgstr "" - -#: fotoxx-11.11.1.cc:222 fotoxx_info.cc:1547 -msgid "Batch Delete Tag" -msgstr "" - -#: fotoxx-11.11.1.cc:223 -msgid "View Info (short)" -msgstr "" - -#: fotoxx-11.11.1.cc:224 -msgid "View Info (long)" -msgstr "" - -#: fotoxx-11.11.1.cc:225 fotoxx_info.cc:1883 -msgid "Edit Info" -msgstr "" - -#: fotoxx-11.11.1.cc:226 fotoxx_info.cc:1981 -msgid "Delete Info" -msgstr "" - -#: fotoxx-11.11.1.cc:227 -#, fuzzy -msgid "Search Images" -msgstr "Buscar etiquetas" - -#: fotoxx-11.11.1.cc:229 fotoxx-11.11.1.cc:230 -msgid "Select" -msgstr "" - -#: fotoxx-11.11.1.cc:231 -msgid "Show" -msgstr "Mostrar" - -#: fotoxx-11.11.1.cc:232 -msgid "Hide" -msgstr "Ocultar" - -#: fotoxx-11.11.1.cc:233 -msgid "Enable" -msgstr "" - -#: fotoxx-11.11.1.cc:234 -msgid "Disable" -msgstr "Desactivar" - -#: fotoxx-11.11.1.cc:235 -msgid "Invert" -msgstr "Invertir" - -#: fotoxx-11.11.1.cc:236 -msgid "Unselect" -msgstr "" - -#: fotoxx-11.11.1.cc:237 -msgid "Copy" -msgstr "" - -#: fotoxx-11.11.1.cc:238 -msgid "Paste" -msgstr "" - -#: fotoxx-11.11.1.cc:239 fotoxx-11.11.1.cc:317 fotoxx_retouch.cc:2314 -#: fotoxx_retouch.cc:2319 -msgid "Open" -msgstr "Abrir" - -#: fotoxx-11.11.1.cc:240 fotoxx-11.11.1.cc:326 -msgid "Save" -msgstr "Guardar" - -#: fotoxx-11.11.1.cc:241 fotoxx_area.cc:2215 -msgid "Select Whole Image" -msgstr "" - -#: fotoxx-11.11.1.cc:242 -msgid "Select and Edit" -msgstr "" - -#: fotoxx-11.11.1.cc:244 -msgid "Transform" -msgstr "" - -#: fotoxx-11.11.1.cc:245 fotoxx_transform.cc:60 -msgid "Rotate Image" -msgstr "Rotar imagen" - -#: fotoxx-11.11.1.cc:246 fotoxx_transform.cc:346 -msgid "Trim Image" -msgstr "Recortar imagen" - -#: fotoxx-11.11.1.cc:247 fotoxx_transform.cc:972 -msgid "Resize Image" -msgstr "Redimensionar imagen" - -#: fotoxx-11.11.1.cc:248 -msgid "Batch Resize/Export" -msgstr "" - -#: fotoxx-11.11.1.cc:249 fotoxx_transform.cc:1436 -msgid "Annotate Image" -msgstr "" - -#: fotoxx-11.11.1.cc:250 fotoxx_transform.cc:2193 -msgid "Flip Image" -msgstr "" - -#: fotoxx-11.11.1.cc:251 fotoxx_transform.cc:2303 -msgid "Make Negative" -msgstr "" - -#: fotoxx-11.11.1.cc:252 fotoxx_transform.cc:2420 -msgid "Unbend Image" -msgstr "Enderezar imagen" - -#: fotoxx-11.11.1.cc:253 fotoxx_transform.cc:2704 -msgid "Keystone Correction" -msgstr "" - -#: fotoxx-11.11.1.cc:254 fotoxx_transform.cc:3013 -msgid "Warp Image (area)" -msgstr "" - -#: fotoxx-11.11.1.cc:255 fotoxx_transform.cc:3255 -msgid "Warp Image (curved)" -msgstr "" - -#: fotoxx-11.11.1.cc:256 fotoxx_transform.cc:3518 -msgid "Warp Image (linear)" -msgstr "" - -#: fotoxx-11.11.1.cc:257 fotoxx_transform.cc:3782 -msgid "Warp Image (affine)" -msgstr "" - -#: fotoxx-11.11.1.cc:259 -msgid "Retouch" -msgstr "Retocar" - -#: fotoxx-11.11.1.cc:260 -msgid "Brightness/Color" -msgstr "Ajustar brillo y color" - -#: fotoxx-11.11.1.cc:261 -msgid "Gamma Curves" -msgstr "" - -#: fotoxx-11.11.1.cc:262 -msgid "Expand Brightness" -msgstr "" - -#: fotoxx-11.11.1.cc:263 -msgid "Flatten Brightness" -msgstr "Distribuir el brillo uniformemente" - -#: fotoxx-11.11.1.cc:264 -msgid "Brightness Ramp" -msgstr "" - -#: fotoxx-11.11.1.cc:265 fotoxx_retouch.cc:1729 -msgid "Tone Mapping" -msgstr "" - -#: fotoxx-11.11.1.cc:266 -msgid "White Balance" -msgstr "Balance de blanco" - -#: fotoxx-11.11.1.cc:267 -msgid "Match Colors" -msgstr "" - -#: fotoxx-11.11.1.cc:269 fotoxx_retouch.cc:2941 -msgid "Revise RGB" -msgstr "" - -#: fotoxx-11.11.1.cc:270 -msgid "Red Eyes" -msgstr "Ojos rojos" - -#: fotoxx-11.11.1.cc:271 -msgid "Blur Image" -msgstr "Imagen borrosa" - -#: fotoxx-11.11.1.cc:272 fotoxx_retouch.cc:4077 -msgid "Sharpen Image" -msgstr "Enfoque de imagen" - -#: fotoxx-11.11.1.cc:273 -msgid "Reduce Noise" -msgstr "Reducción de ruido" - -#: fotoxx-11.11.1.cc:274 fotoxx_retouch.cc:4881 -msgid "Smart Erase" -msgstr "" - -#: fotoxx-11.11.1.cc:275 fotoxx_retouch.cc:5271 -msgid "Remove Dust" -msgstr "" - -#: fotoxx-11.11.1.cc:276 fotoxx_retouch.cc:5877 -msgid "Edit Pixels" -msgstr "Editar píxeles" - -#: fotoxx-11.11.1.cc:278 -msgid "Art" -msgstr "Arte" - -#: fotoxx-11.11.1.cc:279 -msgid "Color Depth" -msgstr "Profundidad de color" - -#: fotoxx-11.11.1.cc:280 -msgid "Drawing" -msgstr "" - -#: fotoxx-11.11.1.cc:281 -msgid "Outlines" -msgstr "" - -#: fotoxx-11.11.1.cc:282 -msgid "Embossing" -msgstr "" - -#: fotoxx-11.11.1.cc:283 -msgid "Tiles" -msgstr "" - -#: fotoxx-11.11.1.cc:284 -msgid "Dots" -msgstr "" - -#: fotoxx-11.11.1.cc:285 -msgid "Painting" -msgstr "" - -#: fotoxx-11.11.1.cc:287 -msgid "Combine" -msgstr "Combinar" - -#: fotoxx-11.11.1.cc:288 -msgid "High Dynamic Range" -msgstr "" - -#: fotoxx-11.11.1.cc:289 -msgid "High Depth of Field" -msgstr "" - -#: fotoxx-11.11.1.cc:290 -msgid "Stack / Paint" -msgstr "" - -#: fotoxx-11.11.1.cc:291 -msgid "Stack / Noise" -msgstr "" - -#: fotoxx-11.11.1.cc:292 -msgid "Panorama" -msgstr "Panoramica" - -#: fotoxx-11.11.1.cc:293 -msgid "Vertical Panorama" -msgstr "" - -#: fotoxx-11.11.1.cc:296 -msgid "Edit Plugins" -msgstr "" - -#: fotoxx-11.11.1.cc:305 fotoxx-11.11.1.cc:333 fotoxx-11.11.1.cc:4616 -msgid "Help" -msgstr "Ayuda" - -#: fotoxx-11.11.1.cc:306 fotoxx-11.11.1.cc:4606 -msgid "About" -msgstr "Acerca de" - -#: fotoxx-11.11.1.cc:307 fotoxx-11.11.1.cc:4610 -msgid "User Guide" -msgstr "Guía de usuario" - -#: fotoxx-11.11.1.cc:308 fotoxx-11.11.1.cc:4613 -msgid "User Guide Changes" -msgstr "" - -#: fotoxx-11.11.1.cc:309 fotoxx-11.11.1.cc:4622 -msgid "Edit Functions Summary" -msgstr "" - -#: fotoxx-11.11.1.cc:310 fotoxx-11.11.1.cc:4625 -msgid "Change Log" -msgstr "Editar el registro" - -#: fotoxx-11.11.1.cc:311 fotoxx-11.11.1.cc:4628 -msgid "Translations" -msgstr "" - -#: fotoxx-11.11.1.cc:312 fotoxx-11.11.1.cc:4631 -msgid "Home Page" -msgstr "Página de inicio" - -#: fotoxx-11.11.1.cc:316 -msgid "Gallery" -msgstr "Galería" - -#: fotoxx-11.11.1.cc:318 fotoxx_transform.cc:995 -msgid "Prev" -msgstr "Anterior" - -#: fotoxx-11.11.1.cc:319 -msgid "Next" -msgstr "Siguiente" - -#: fotoxx-11.11.1.cc:319 -msgid "Open Next File" -msgstr "Abrir siguiente archivo" - -#: fotoxx-11.11.1.cc:320 -msgid "Zoom-in (bigger)" -msgstr "Zoom ampliar" - -#: fotoxx-11.11.1.cc:321 -msgid "Zoom-out (smaller)" -msgstr "Zoom reducir" - -#: fotoxx-11.11.1.cc:322 -msgid "Undo" -msgstr "Deshacer" - -#: fotoxx-11.11.1.cc:322 -msgid "Undo One Edit" -msgstr "Deshacer un paso" - -#: fotoxx-11.11.1.cc:323 -msgid "Redo" -msgstr "Rehacer" - -#: fotoxx-11.11.1.cc:323 -msgid "Redo One Edit" -msgstr "Rehacer un paso" - -#: fotoxx-11.11.1.cc:327 -msgid "Save+V" -msgstr "" - -#: fotoxx-11.11.1.cc:328 -msgid "Save+F" -msgstr "" - -#: fotoxx-11.11.1.cc:329 -msgid "Move Image to Trash" -msgstr "Enviar la imagen a la papelera" - -#: fotoxx-11.11.1.cc:329 -msgid "Trash" -msgstr "Papelera" - -#: fotoxx-11.11.1.cc:332 -msgid "Quit" -msgstr "Salir" - -#: fotoxx-11.11.1.cc:333 -msgid "Fotoxx Essentials" -msgstr "" - -#: fotoxx-11.11.1.cc:429 -msgid "first time startup" -msgstr "" - -#: fotoxx-11.11.1.cc:1815 -msgid "Exceed 50 anchor points" -msgstr "Se exceden los 50 puntos de anclaje" - -#: fotoxx-11.11.1.cc:2000 -msgid "load curve from a file" -msgstr "" - -#: fotoxx-11.11.1.cc:2053 -msgid "curve file is invalid" -msgstr "" - -#: fotoxx-11.11.1.cc:2058 -msgid "curve file has different no. of curves" -msgstr "" - -#: fotoxx-11.11.1.cc:2073 -msgid "save curve to a file" -msgstr "" - -#: fotoxx-11.11.1.cc:2420 -#, c-format -msgid "" -"Discard special gallery list? \n" -" %s" -msgstr "" - -#: fotoxx-11.11.1.cc:2430 fotoxx-11.11.1.cc:4452 -msgid "prior function still active" -msgstr "" - -#: fotoxx-11.11.1.cc:2607 -msgid "Overwrite original file?" -msgstr "" - -#: fotoxx-11.11.1.cc:2608 -msgid "Do not warn again" -msgstr "" - -#: fotoxx-11.11.1.cc:2624 -msgid "Warning" -msgstr "" - -#: fotoxx-11.11.1.cc:2747 -msgid "Save File" -msgstr "Guardar el archivo" - -#: fotoxx-11.11.1.cc:2770 -msgid "quality" -msgstr "" - -#: fotoxx-11.11.1.cc:2772 -msgid "make current" -msgstr "" - -#: fotoxx-11.11.1.cc:2829 -msgid "jpeg quality must be 1-100" -msgstr "" - -#: fotoxx-11.11.1.cc:2851 -#, c-format -msgid "" -"Overwrite file? \n" -" %s" -msgstr "" -"¿Sobreescribir archivo? \n" -" %s" - -#: fotoxx-11.11.1.cc:2992 -msgid "file name" -msgstr "" - -#: fotoxx-11.11.1.cc:2997 fotoxx_transform.cc:351 -msgid "width" -msgstr "" - -#: fotoxx-11.11.1.cc:3000 fotoxx_transform.cc:354 -msgid "height" -msgstr "" - -#: fotoxx-11.11.1.cc:3006 fotoxx_art.cc:628 fotoxx_retouch.cc:5881 -msgid "color" -msgstr "Color" - -#: fotoxx-11.11.1.cc:3120 -msgid "" -"Linux standard trash is not supported. \n" -"Desktop trash folder will be created." -msgstr "" - -#: fotoxx-11.11.1.cc:3138 -msgid "Move read-only file to trash?" -msgstr "¿Enviar el fichero de solo lectura a la papelera?" - -#: fotoxx-11.11.1.cc:3164 -#, c-format -msgid "Cannot create trash folder: %s" -msgstr "No se puede crear carpeta de papelera: %s" - -#: fotoxx-11.11.1.cc:3172 fotoxx-11.11.1.cc:3178 -#, c-format -msgid "error: %s" -msgstr "error: %s" - -#: fotoxx-11.11.1.cc:3221 -msgid "old name" -msgstr "Nombre antiguo" - -#: fotoxx-11.11.1.cc:3222 -msgid "rename to" -msgstr "Renombrar como" - -#: fotoxx-11.11.1.cc:3223 -msgid "previous" -msgstr "Anterior" - -#: fotoxx-11.11.1.cc:3309 -msgid "The target file already exists" -msgstr "El archivo de destino ya existe" - -#: fotoxx-11.11.1.cc:3317 -#, c-format -msgid "" -"Rename failed: \n" -" %s" -msgstr "" - -#: fotoxx-11.11.1.cc:3365 -msgid "Batch Rename" -msgstr "" - -#: fotoxx-11.11.1.cc:3368 fotoxx-11.11.1.cc:3420 fotoxx_info.cc:1513 -#: fotoxx_info.cc:1767 fotoxx_tools.cc:2510 fotoxx_transform.cc:1213 -#, c-format -msgid "%d files selected" -msgstr "" - -#: fotoxx-11.11.1.cc:3370 -msgid "new base name" -msgstr "" - -#: fotoxx-11.11.1.cc:3373 -msgid "starting sequence" -msgstr "" - -#: fotoxx-11.11.1.cc:3375 -msgid "increment" -msgstr "" - -#: fotoxx-11.11.1.cc:3396 -msgid "select files to rename" -msgstr "" - -#: fotoxx-11.11.1.cc:3401 -msgid "base name / sequence / increment not reasonable" -msgstr "" - -#: fotoxx-11.11.1.cc:3460 -msgid "new file already exists:" -msgstr "" - -#: fotoxx-11.11.1.cc:3468 -msgid "filespec too long:" -msgstr "" - -#: fotoxx-11.11.1.cc:3479 -msgid "Rename failed:" -msgstr "" - -#: fotoxx-11.11.1.cc:3739 -msgid "Add" -msgstr "" - -#: fotoxx-11.11.1.cc:3739 -msgid "Remove" -msgstr "" - -#: fotoxx-11.11.1.cc:3741 -msgid "menu name" -msgstr "" - -#: fotoxx-11.11.1.cc:3812 fotoxx-11.11.1.cc:3833 -msgid "Restart Fotoxx to update plugin menu" -msgstr "" - -#: fotoxx-11.11.1.cc:3927 -msgid "cannot parallel edit" -msgstr "" - -#: fotoxx-11.11.1.cc:3937 -msgid "" -"exiftool is not installed \n" -"edited images will lose EXIF data" -msgstr "" -"El paquete «exiftool» no está instalado \n" -"al editar las imagenes se perderan los datos EXIF" - -#: fotoxx-11.11.1.cc:3943 -msgid "Too many edits, please save image" -msgstr "" - -#: fotoxx-11.11.1.cc:3948 -msgid "" -"Select area cannot be kept.\n" -"Continue?" -msgstr "" -"No se puede conservar la selección de área.\n" -"¿Continuar?" - -#: fotoxx-11.11.1.cc:3956 -msgid "" -"Select area not active.\n" -"Continue?" -msgstr "" - -#: fotoxx-11.11.1.cc:4427 -msgid "Discard edits?" -msgstr "" - -#: fotoxx-11.11.1.cc:4428 -msgid "" -"This action will discard current edits.\n" -"Continue to discard edits.\n" -"Go Back to keep edits." -msgstr "" - -#: fotoxx-11.11.1.cc:4431 -msgid "Continue" -msgstr "" - -#: fotoxx-11.11.1.cc:4432 -msgid "Go Back" -msgstr "" - -#: fotoxx-11.11.1.cc:5240 -msgid "cannot open thumbnail file" -msgstr "" - -#: fotoxx-11.11.1.cc:5433 fotoxx-11.11.1.cc:5549 -msgid "TIFF open failure" -msgstr "" - -#: fotoxx-11.11.1.cc:5449 -#, c-format -msgid "TIFF bits/color=%d not supported" -msgstr "" - -#: fotoxx-11.11.1.cc:5464 fotoxx-11.11.1.cc:5502 -msgid "TIFF read failure" -msgstr "" - -#: fotoxx-11.11.1.cc:5608 -msgid "TIFF write failure" -msgstr "" - -#: fotoxx-11.11.1.cc:5638 -msgid "file type not supported" -msgstr "" - -#: fotoxx-11.11.1.cc:5745 -msgid "pixbuf write failure" -msgstr "" - -#: fotoxx_area.cc:54 fotoxx_area.cc:2427 -msgid "Select Area for Edits" -msgstr "" - -#: fotoxx_area.cc:55 fotoxx_area.cc:2428 -msgid "Press F1 for help" -msgstr "" - -#: fotoxx_area.cc:63 -msgid "" -"Select Area not supported \n" -"by this edit function" -msgstr "" - -#: fotoxx_area.cc:99 fotoxx_tools.cc:809 -msgid "rectangle" -msgstr "" - -#: fotoxx_area.cc:100 fotoxx_tools.cc:810 -msgid "ellipse" -msgstr "" - -#: fotoxx_area.cc:101 -msgid "draw: freehand" -msgstr "" - -#: fotoxx_area.cc:102 -msgid "draw: follow edge" -msgstr "" - -#: fotoxx_area.cc:103 -msgid "select by mouse" -msgstr "" - -#: fotoxx_area.cc:104 -msgid "select by color" -msgstr "" - -#: fotoxx_area.cc:112 -msgid "radius" -msgstr "Radio" - -#: fotoxx_area.cc:116 -msgid "match" -msgstr "" - -#: fotoxx_area.cc:121 -msgid "firewall" -msgstr "" - -#: fotoxx_area.cc:274 fotoxx_area.cc:415 -#, c-format -msgid "exceed %d edits" -msgstr "" - -#: fotoxx_area.cc:992 -msgid "" -"Click one time inside each enclosed area \n" -"(possible gaps in the outline will be found). \n" -"Press F1 for help." -msgstr "" - -#: fotoxx_area.cc:1049 -msgid "finish area" -msgstr "" - -#: fotoxx_area.cc:1083 -msgid "searching" -msgstr "" - -#: fotoxx_area.cc:1155 -msgid "outline has a gap" -msgstr "" - -#: fotoxx_area.cc:1157 -msgid "success" -msgstr "" - -#: fotoxx_area.cc:1401 fotoxx_area.cc:1430 -msgid "the area is not finished" -msgstr "" - -#: fotoxx_area.cc:1522 -msgid "Edge calculation in progress" -msgstr "Necesita calcular el borde" - -#: fotoxx_area.cc:1531 -msgid "Area Edge Calc" -msgstr "Calcular el área de borde" - -#: fotoxx_area.cc:1824 -msgid "position with mouse click/drag" -msgstr "" - -#: fotoxx_area.cc:1848 -msgid "Paste Image" -msgstr "" - -#: fotoxx_area.cc:1863 -msgid "angle" -msgstr "" - -#: fotoxx_area.cc:2127 -msgid "load select area from a file" -msgstr "" - -#: fotoxx_area.cc:2161 -msgid "cannot open .tiff and .info files" -msgstr "" - -#: fotoxx_area.cc:2180 -msgid "save select area to a file" -msgstr "" - -#: fotoxx_area.cc:2216 -msgid "Edit Function Amplifier" -msgstr "" - -#: fotoxx_area.cc:2459 -msgid "mouse radius" -msgstr "" - -#: fotoxx_area.cc:2462 -msgid "power: center" -msgstr "" - -#: fotoxx_area.cc:2464 -msgid "edge" -msgstr "" - -#: fotoxx_area.cc:2468 -msgid "reset area" -msgstr "" - -#: fotoxx_area.cc:2523 -msgid "start edit function first" -msgstr "" - -#: fotoxx_art.cc:47 -msgid "Set color depth to 1-16 bits" -msgstr "Establecer profundidad de color 1-16 bits" - -#: fotoxx_art.cc:57 -msgid "Set Color Depth" -msgstr "Ajustar la profundidad de color" - -#: fotoxx_art.cc:171 -msgid "Simulate Drawing" -msgstr "Simular un dibujo" - -#: fotoxx_art.cc:213 fotoxx_retouch.cc:1758 -msgid "contrast" -msgstr "Contraste" - -#: fotoxx_art.cc:215 -msgid "outlines" -msgstr "Contornos" - -#: fotoxx_art.cc:220 -msgid "pencil" -msgstr "Lapiz" - -#: fotoxx_art.cc:221 -msgid "chalk" -msgstr "Tiza" - -#: fotoxx_art.cc:381 -msgid "Add Image Outlines" -msgstr "" - -#: fotoxx_art.cc:394 -msgid "outline threshold" -msgstr "" - -#: fotoxx_art.cc:397 -msgid "outline width" -msgstr "" - -#: fotoxx_art.cc:400 -msgid "image brightness" -msgstr "" - -#: fotoxx_art.cc:611 -msgid "Simulate Embossing" -msgstr "Simular un repujado" - -#: fotoxx_art.cc:626 -msgid "depth" -msgstr "Profundidad" - -#: fotoxx_art.cc:821 -msgid "Simulate Tiles" -msgstr "Simular un mosaico" - -#: fotoxx_art.cc:825 -msgid "tile size" -msgstr "Tamaño del mosaico" - -#: fotoxx_art.cc:829 -msgid "tile gap" -msgstr "Separación do mosaico" - -#: fotoxx_art.cc:1003 -msgid "Convert Image to Dots" -msgstr "" - -#: fotoxx_art.cc:1007 -msgid "dot size" -msgstr "" - -#: fotoxx_art.cc:1222 -msgid "Simulate Painting" -msgstr "Simular una pintura" - -#: fotoxx_art.cc:1226 -msgid "color depth" -msgstr "Profundidad de color" - -#: fotoxx_art.cc:1230 -msgid "patch area goal" -msgstr "" - -#: fotoxx_art.cc:1234 -msgid "req. color match" -msgstr "Correspondencia de color requerida" - -#: fotoxx_art.cc:1238 -msgid "borders" -msgstr "Bordes" - -#: fotoxx_comp.cc:1956 fotoxx_comp.cc:1961 fotoxx_comp.cc:2582 -#: fotoxx_comp.cc:2587 fotoxx_comp.cc:3275 fotoxx_comp.cc:3280 -#: fotoxx_comp.cc:3830 fotoxx_comp.cc:3835 -msgid "Select 2 to 9 files" -msgstr "" - -#: fotoxx_comp.cc:1982 fotoxx_comp.cc:2608 fotoxx_comp.cc:3301 -#: fotoxx_comp.cc:3856 -msgid "Images are not all the same size" -msgstr "" - -#: fotoxx_comp.cc:2321 -msgid "Adjust Image Contributions" -msgstr "" - -#: fotoxx_comp.cc:2324 fotoxx_retouch.cc:885 -msgid "dark pixels" -msgstr "" - -#: fotoxx_comp.cc:2326 -msgid "light pixels" -msgstr "" - -#: fotoxx_comp.cc:2328 fotoxx_info.cc:159 -msgid "file:" -msgstr "Archivo:" - -#: fotoxx_comp.cc:2844 -msgid "Paint and Warp Image" -msgstr "" - -#: fotoxx_comp.cc:2847 fotoxx_comp.cc:3529 fotoxx_comp.cc:4972 -#: fotoxx_comp.cc:5717 -msgid "image" -msgstr "" - -#: fotoxx_comp.cc:2851 fotoxx_retouch.cc:5885 -msgid "paint" -msgstr "Pintar" - -#: fotoxx_comp.cc:2852 -msgid "warp" -msgstr "" - -#: fotoxx_comp.cc:3527 -msgid "Select and Paint Image" -msgstr "" - -#: fotoxx_comp.cc:4045 -msgid "Adjust Pixel Composition" -msgstr "" - -#: fotoxx_comp.cc:4297 fotoxx_comp.cc:4302 fotoxx_comp.cc:5186 -#: fotoxx_comp.cc:5191 -msgid "Select 2 to 4 files" -msgstr "" - -#: fotoxx_comp.cc:4374 -msgid "" -"Drag images into rough alignment.\n" -"To rotate, drag from lower edge." -msgstr "" - -#: fotoxx_comp.cc:4376 -msgid "Search for lens mm and bow" -msgstr "" - -#: fotoxx_comp.cc:4422 fotoxx_comp.cc:5310 -msgid "Pre-align Images" -msgstr "Pre-alinear imágenes" - -#: fotoxx_comp.cc:4426 fotoxx_comp.cc:5314 fotoxx_tools.cc:2151 -msgid "lens mm" -msgstr "Longitud focal (mm)" - -#: fotoxx_comp.cc:4430 fotoxx_comp.cc:5318 fotoxx_tools.cc:2156 -msgid "lens bow" -msgstr "Curvatura de la lente" - -#: fotoxx_comp.cc:4432 fotoxx_comp.cc:5320 -msgid "Resize" -msgstr "" - -#: fotoxx_comp.cc:4433 fotoxx_comp.cc:5321 -msgid "resize window" -msgstr "" - -#: fotoxx_comp.cc:4470 -msgid "use two images only" -msgstr "" - -#: fotoxx_comp.cc:4491 fotoxx_comp.cc:4689 fotoxx_comp.cc:4888 -#: fotoxx_comp.cc:5369 fotoxx_comp.cc:5632 -msgid "Too little overlap, cannot align" -msgstr "Solapamiento demasiado pequeño, no puedo alinear" - -#: fotoxx_comp.cc:4963 fotoxx_comp.cc:5708 -msgid "Match Brightness and Color" -msgstr "" - -#: fotoxx_comp.cc:4987 fotoxx_comp.cc:5732 -msgid "auto color" -msgstr "" - -#: fotoxx_comp.cc:4988 fotoxx_comp.cc:5733 -msgid "file color" -msgstr "" - -#: fotoxx_comp.cc:5263 -msgid "" -"Drag images into rough alignment.\n" -"To rotate, drag from right edge." -msgstr "" - -#: fotoxx_info.cc:70 -msgid "Edit Caption and Comments" -msgstr "" - -#: fotoxx_info.cc:163 -msgid "image date (yyyymmdd)" -msgstr "Fecha de la imagen (aaaammdd)" - -#: fotoxx_info.cc:165 -msgid "use last" -msgstr "Usar el último" - -#: fotoxx_info.cc:168 -msgid "image stars" -msgstr "Imagen estrella" - -#: fotoxx_info.cc:186 -msgid "current tags" -msgstr "Etiquetas actuales" - -#: fotoxx_info.cc:191 -msgid "recent tags" -msgstr "" - -#: fotoxx_info.cc:196 fotoxx_info.cc:358 fotoxx_info.cc:1362 -#: fotoxx_info.cc:2290 -msgid "defined tags" -msgstr "" - -#: fotoxx_info.cc:348 -msgid "category" -msgstr "" - -#: fotoxx_info.cc:351 -msgid "tag" -msgstr "" - -#: fotoxx_info.cc:354 -msgid "create" -msgstr "" - -#: fotoxx_info.cc:355 -msgid "delete" -msgstr "Borrar" - -#: fotoxx_info.cc:1229 fotoxx_info.cc:1313 -#, c-format -msgid "search index file error: %s" -msgstr "" - -#: fotoxx_info.cc:1348 -msgid "tags to add" -msgstr "" - -#: fotoxx_info.cc:1353 -msgid "create tag" -msgstr "Crear etiqueta" - -#: fotoxx_info.cc:1409 fotoxx_info.cc:1602 -#, c-format -msgid "" -"%s \n" -" too many tags" -msgstr "" - -#: fotoxx_info.cc:1550 -msgid "tag to remove" -msgstr "" - -#: fotoxx_info.cc:1554 -msgid "optional replacement" -msgstr "" - -#: fotoxx_info.cc:1559 fotoxx_tools.cc:2463 -msgid "0 files selected" -msgstr "" - -#: fotoxx_info.cc:1562 -msgid "search all files" -msgstr "" - -#: fotoxx_info.cc:1647 -msgid "no files selected" -msgstr "" - -#: fotoxx_info.cc:1653 -msgid "no tag specified" -msgstr "" - -#: fotoxx_info.cc:1677 fotoxx_info.cc:1706 -msgid "specify tag" -msgstr "" - -#: fotoxx_info.cc:1815 -msgid "View Info" -msgstr "" - -#: fotoxx_info.cc:1983 -msgid "All" -msgstr "" - -#: fotoxx_info.cc:1984 -msgid "One Key:" -msgstr "" - -#: fotoxx_info.cc:2249 -msgid "Search Tags, Comments, File Names" -msgstr "" - -#: fotoxx_info.cc:2255 -msgid "date range" -msgstr "Rango de fechas" - -#: fotoxx_info.cc:2256 -msgid "stars range" -msgstr "Rango de estrellas" - -#: fotoxx_info.cc:2257 -msgid "search tags" -msgstr "Buscar etiquetas" - -#: fotoxx_info.cc:2258 -msgid "search text" -msgstr "" - -#: fotoxx_info.cc:2259 -msgid "file names" -msgstr "" - -#: fotoxx_info.cc:2264 -msgid "(yyyymmdd)" -msgstr "" - -#: fotoxx_info.cc:2270 -msgid "all/any" -msgstr "" - -#: fotoxx_info.cc:2598 -msgid "No matching images found" -msgstr "No se encontró ninguna imagen" - -#: fotoxx_info.cc:2611 -msgid "No search index file present" -msgstr "" - -#: fotoxx_info.cc:2615 -#, c-format -msgid "Search results file error %s" -msgstr "Error en los resultados de la búsqueda %s" - -#: fotoxx_retouch.cc:55 -msgid "Adjust Brightness and Color" -msgstr "Ajustar brillo y color" - -#: fotoxx_retouch.cc:109 -msgid "small-steps" -msgstr "" - -#: fotoxx_retouch.cc:118 -msgid "color saturation" -msgstr "Saturación de color" - -#: fotoxx_retouch.cc:125 -msgid " reset 1 " -msgstr " Restablecer 1" - -#: fotoxx_retouch.cc:126 -msgid "reset all" -msgstr "Restablecer todo" - -#: fotoxx_retouch.cc:598 -msgid "adjust image gamma" -msgstr "" - -#: fotoxx_retouch.cc:884 -msgid "Expand Brightness Range" -msgstr "" - -#: fotoxx_retouch.cc:886 -msgid "bright pixels" -msgstr "" - -#: fotoxx_retouch.cc:1057 -msgid "Flatten Brightness Distribution" -msgstr "Distribución uniforme del brillo" - -#: fotoxx_retouch.cc:1071 -msgid "Flatten" -msgstr "Aplanar" - -#: fotoxx_retouch.cc:1333 -msgid "Ramp brightness across image" -msgstr "" - -#: fotoxx_retouch.cc:1757 -msgid "low" -msgstr "" - -#: fotoxx_retouch.cc:1759 -msgid "high" -msgstr "" - -#: fotoxx_retouch.cc:1762 -msgid "Amplify" -msgstr "" - -#: fotoxx_retouch.cc:2068 -msgid "Adjust White Balance" -msgstr "Ajustar balance de blanco" - -#: fotoxx_retouch.cc:2069 -msgid "Click white or gray image location" -msgstr "Haga clic en la ubicación de la imagen en blanco o gris" - -#: fotoxx_retouch.cc:2283 -msgid "Color Match Images" -msgstr "" - -#: fotoxx_retouch.cc:2312 -msgid "mouse radius for color sample" -msgstr "" - -#: fotoxx_retouch.cc:2315 -msgid "image for source color" -msgstr "" - -#: fotoxx_retouch.cc:2317 -msgid "click on image to get source color" -msgstr "" - -#: fotoxx_retouch.cc:2320 -msgid "image to set matching color" -msgstr "" - -#: fotoxx_retouch.cc:2322 -msgid "click on image to set matching color" -msgstr "" - -#: fotoxx_retouch.cc:2377 -msgid "select source image color first" -msgstr "" - -#: fotoxx_retouch.cc:2903 fotoxx_tools.cc:1643 -msgid "Click image to select pixels." -msgstr "" - -#: fotoxx_retouch.cc:2955 -msgid "Metric:" -msgstr "" - -#: fotoxx_retouch.cc:3010 -msgid "Blend" -msgstr "" - -#: fotoxx_retouch.cc:3394 -msgid "" -"Method 1:\n" -" Left-click on red-eye to darken.\n" -"Method 2:\n" -" Drag down and right to enclose red-eye.\n" -" Left-click on red-eye to darken.\n" -"Undo red-eye:\n" -" Right-click on red-eye." -msgstr "" -"Método 1:\n" -" Clic-izquierdo en el ojo rojo para oscurecer.\n" -"Método 2:\n" -" Pica y arrastra a la derecha para delimitar el ojo rojo.\n" -" Clic-izquierdo para oscurecer el ojo rojo.\n" -"Deshacer ojos rojos:\n" -" Clic-derecho en el ojo rojo." - -#: fotoxx_retouch.cc:3409 -msgid "Red Eye Reduction" -msgstr "Reducción de ojos rojos" - -#: fotoxx_retouch.cc:3850 -msgid "Set Blur Radius" -msgstr "Establecer radio de desenfoque" - -#: fotoxx_retouch.cc:4084 -msgid "edge detection" -msgstr "Detección de borde" - -#: fotoxx_retouch.cc:4085 -msgid "cycles" -msgstr "Ciclos" - -#: fotoxx_retouch.cc:4086 -msgid "reduce" -msgstr "reducir" - -#: fotoxx_retouch.cc:4097 -msgid "unsharp mask" -msgstr "Máscara de desenfoque" - -#: fotoxx_retouch.cc:4110 -msgid "brightness gradient" -msgstr "" - -#: fotoxx_retouch.cc:4516 -msgid "" -" Press the reduce button to \n" -" reduce noise in small steps. \n" -" Use undo to start over." -msgstr "" -" Pulse el botón de reducción para \n" -" reducir el ruido en pequeños pasos. \n" -" Utilice Deshacer para empezar de nuevo." - -#: fotoxx_retouch.cc:4527 -msgid "Noise Reduction" -msgstr "Reducción de ruido" - -#: fotoxx_retouch.cc:4532 -msgid "algorithm" -msgstr "algoritmo" - -#: fotoxx_retouch.cc:4539 -msgid "flatten outliers by color (1)" -msgstr "Aplanar los valores extremos de color (1)" - -#: fotoxx_retouch.cc:4540 -msgid "flatten outliers by color (2)" -msgstr "Aplanar los valores extremos de color (2)" - -#: fotoxx_retouch.cc:4541 -msgid "set median brightness by color" -msgstr "Configurar la mediana de brillo por color" - -#: fotoxx_retouch.cc:4542 fotoxx_retouch.cc:4543 -msgid "top hat filter by color" -msgstr "Filtro de color «sombrero de copa (Top-hat)»" - -#: fotoxx_retouch.cc:4858 -msgid "" -"1. Drag mouse to select. \n" -"2. Erase. 3. Repeat. " -msgstr "" - -#: fotoxx_retouch.cc:4889 -msgid "Radius" -msgstr "Radio" - -#: fotoxx_retouch.cc:4891 -msgid "Blur" -msgstr "" - -#: fotoxx_retouch.cc:4894 -msgid "New Area" -msgstr "" - -#: fotoxx_retouch.cc:5275 -msgid "spot size limit" -msgstr "" - -#: fotoxx_retouch.cc:5278 -msgid "max. brightness" -msgstr "" - -#: fotoxx_retouch.cc:5281 -msgid "min. contrast" -msgstr "" - -#: fotoxx_retouch.cc:5875 -#, c-format -msgid "Undo Memory %d%c" -msgstr "Memoria de deshacer %d%c" - -#: fotoxx_retouch.cc:5884 -msgid "pick" -msgstr "Recoger" - -#: fotoxx_retouch.cc:5886 -msgid "erase" -msgstr "Borrar" - -#: fotoxx_retouch.cc:5894 -msgid "paintbrush radius" -msgstr "Radio del pincel" - -#: fotoxx_retouch.cc:5895 -msgid "transparency center" -msgstr "Centro de la transparencia" - -#: fotoxx_retouch.cc:5896 -msgid "transparency edge" -msgstr "Borde de la transparencia" - -#: fotoxx_retouch.cc:6166 -msgid "" -"Undo memory limit has been reached. \n" -"Save work with [done], then resume editing." -msgstr "" -"Se alcanzó el límite de memoria de deshacer. \n" -"Guarde el trabajo con [Hecho], y luego reanude la edición." - -#: fotoxx_tools.cc:42 -msgid "" -"When editing a collection, right-click \n" -"an image or thumbnail to add or remove." -msgstr "" - -#: fotoxx_tools.cc:85 -msgid "Start new collection" -msgstr "" - -#: fotoxx_tools.cc:87 -msgid "Edit a collection" -msgstr "" - -#: fotoxx_tools.cc:89 -msgid "View a collection" -msgstr "" - -#: fotoxx_tools.cc:91 -msgid "Delete a collection" -msgstr "" - -#: fotoxx_tools.cc:95 -msgid "Editing:" -msgstr "" - -#: fotoxx_tools.cc:99 -msgid "Action:" -msgstr "" - -#: fotoxx_tools.cc:133 -msgid "New Collection" -msgstr "" - -#: fotoxx_tools.cc:156 -msgid "Edit Collection" -msgstr "" - -#: fotoxx_tools.cc:172 -msgid "View Collection" -msgstr "" - -#: fotoxx_tools.cc:193 -msgid "Delete Collection" -msgstr "" - -#: fotoxx_tools.cc:196 -#, c-format -msgid "delete %s ?" -msgstr "" - -#: fotoxx_tools.cc:223 -#, c-format -msgid "add image to collection: %s" -msgstr "" - -#: fotoxx_tools.cc:225 fotoxx_tools.cc:270 -msgid "remove image from collection" -msgstr "" - -#: fotoxx_tools.cc:226 fotoxx_tools.cc:271 fotoxx_tools.cc:298 -msgid "remove and save image" -msgstr "" - -#: fotoxx_tools.cc:227 fotoxx_tools.cc:316 -msgid "insert saved images here" -msgstr "" - -#: fotoxx_tools.cc:256 -msgid "add image to collection" -msgstr "" - -#: fotoxx_tools.cc:301 -msgid "too many saved files" -msgstr "" - -#: fotoxx_tools.cc:375 -msgid "old top directory" -msgstr "" - -#: fotoxx_tools.cc:378 -msgid "new top directory" -msgstr "" - -#: fotoxx_tools.cc:434 -msgid "completed" -msgstr "" - -#: fotoxx_tools.cc:452 -msgid "" -"Brightness should show a gradual ramp \n" -"extending all the way to the edges." -msgstr "" - -#: fotoxx_tools.cc:492 -msgid "Monitor Check" -msgstr "" - -#: fotoxx_tools.cc:612 -msgid "Brightness Distribution" -msgstr "Distribuir el brillo" - -#: fotoxx_tools.cc:796 -msgid "Press ESC to exit slide show" -msgstr "" - -#: fotoxx_tools.cc:797 -msgid "show only latest file versions" -msgstr "" - -#: fotoxx_tools.cc:801 -msgid "arrow keys" -msgstr "" - -#: fotoxx_tools.cc:802 -msgid "instant" -msgstr "" - -#: fotoxx_tools.cc:803 -msgid "fade-in" -msgstr "" - -#: fotoxx_tools.cc:804 -msgid "roll-right" -msgstr "" - -#: fotoxx_tools.cc:805 -msgid "roll-down" -msgstr "" - -#: fotoxx_tools.cc:806 -msgid "shift-left" -msgstr "" - -#: fotoxx_tools.cc:807 -msgid "venetian" -msgstr "" - -#: fotoxx_tools.cc:808 -msgid "grate" -msgstr "" - -#: fotoxx_tools.cc:811 -msgid "radar" -msgstr "" - -#: fotoxx_tools.cc:812 -msgid "jaws" -msgstr "" - -#: fotoxx_tools.cc:823 -msgid "seconds" -msgstr "segundos" - -#: fotoxx_tools.cc:827 -msgid "music file" -msgstr "" - -#: fotoxx_tools.cc:831 -msgid "transitions" -msgstr "" - -#: fotoxx_tools.cc:948 -msgid "Select music file or playlist" -msgstr "" - -#: fotoxx_tools.cc:1971 -msgid "x-spacing" -msgstr "" - -#: fotoxx_tools.cc:1972 -msgid "x-count" -msgstr "" - -#: fotoxx_tools.cc:1973 -msgid "x-enable" -msgstr "" - -#: fotoxx_tools.cc:1979 -msgid "y-spacing" -msgstr "" - -#: fotoxx_tools.cc:1980 -msgid "y-count" -msgstr "" - -#: fotoxx_tools.cc:1981 -msgid "y-enable" -msgstr "" - -#: fotoxx_tools.cc:1988 -msgid "x-offset" -msgstr "" - -#: fotoxx_tools.cc:1992 -msgid "y-offset" -msgstr "" - -#: fotoxx_tools.cc:2146 -msgid "lens name" -msgstr "Nombre de la lente" - -#: fotoxx_tools.cc:2220 -msgid "Available Translations" -msgstr "Traducciones disponibles" - -#: fotoxx_tools.cc:2224 -msgid "Set Language" -msgstr "Seleccionar el idioma" - -#: fotoxx_tools.cc:2290 -msgid "Make Launcher" -msgstr "" - -#: fotoxx_tools.cc:2310 -msgid "Program ufraw-batch is required" -msgstr "" - -#: fotoxx_tools.cc:2320 -msgid "Open RAW File" -msgstr "Abrir fichero RAW" - -#: fotoxx_tools.cc:2331 -msgid "Select RAW files to convert" -msgstr "" - -#: fotoxx_tools.cc:2467 -msgid "max. width" -msgstr "" - -#: fotoxx_tools.cc:2468 -msgid "max. height" -msgstr "" - -#: fotoxx_tools.cc:2527 fotoxx_transform.cc:1268 -#, c-format -msgid "max. size %d x %d is not reasonable" -msgstr "" - -#: fotoxx_tools.cc:2613 -msgid "too many files" -msgstr "" - -#: fotoxx_tools.cc:2656 -msgid "Sync Files is already running" -msgstr "" - -#: fotoxx_tools.cc:2707 -msgid "" -"Run Tools > Synchronize Files so that gallery windows \n" -"will be fast and Search Images will work correctly. \n" -"You can view (not edit) images while synchronize runs." -msgstr "" - -#: fotoxx_tools.cc:2736 -msgid "no top image directory is defined" -msgstr "" - -#: fotoxx_tools.cc:2742 -msgid "top image directory is invalid" -msgstr "" - -#: fotoxx_tools.cc:2747 -msgid "no search index file is present" -msgstr "" - -#: fotoxx_tools.cc:2761 -msgid "new/modified files are present" -msgstr "" - -#: fotoxx_tools.cc:2768 -msgid "no new files found" -msgstr "" - -#: fotoxx_tools.cc:2785 -msgid "Top Image Directory:" -msgstr "" - -#: fotoxx_tools.cc:2807 -msgid "file sync is mandatory" -msgstr "" - -#: fotoxx_tools.cc:2817 -msgid "top directory is invalid" -msgstr "" - -#: fotoxx_tools.cc:3201 -msgid "Select top image directory" -msgstr "Seleccionar el directorio raíz de imágenes" - -#: fotoxx_tools.cc:3378 -msgid "icons" -msgstr "" - -#: fotoxx_tools.cc:3379 fotoxx_transform.cc:1467 -msgid "text" -msgstr "" - -#: fotoxx_tools.cc:3380 -msgid "both" -msgstr "" - -#: fotoxx_transform.cc:50 -msgid "Use buttons or drag right edge with mouse" -msgstr "Utilice los botones o arrastre el borde derecho con el ratón" - -#: fotoxx_transform.cc:64 -msgid "degrees" -msgstr "Grados" - -#: fotoxx_transform.cc:80 fotoxx_transform.cc:124 -msgid "Trim" -msgstr "Recortar" - -#: fotoxx_transform.cc:81 fotoxx_transform.cc:2437 fotoxx_transform.cc:3263 -#: fotoxx_transform.cc:3526 fotoxx_transform.cc:3787 -msgid "Grid" -msgstr "" - -#: fotoxx_transform.cc:123 -msgid "Undo Trim" -msgstr "Deshacer recortar" - -#: fotoxx_transform.cc:139 -#, c-format -msgid "degrees: %.1f" -msgstr "Grados: %.1f" - -#: fotoxx_transform.cc:286 -msgid "gold" -msgstr "" - -#: fotoxx_transform.cc:332 -msgid "Drag middle to move, drag corners to resize." -msgstr "" - -#: fotoxx_transform.cc:346 -msgid "customize" -msgstr "" - -#: fotoxx_transform.cc:357 -msgid "ratio" -msgstr "" - -#: fotoxx_transform.cc:361 -msgid "Lock Ratio" -msgstr "Bloquear la relación" - -#: fotoxx_transform.cc:367 -msgid "invert" -msgstr "" - -#: fotoxx_transform.cc:892 -msgid "Trim Buttons" -msgstr "" - -#: fotoxx_transform.cc:964 -msgid "Lock aspect ratio" -msgstr "Bloquar la relación de aspecto" - -#: fotoxx_transform.cc:1145 -msgid "Batch Resize" -msgstr "" - -#: fotoxx_transform.cc:1153 -msgid "new max. width" -msgstr "" - -#: fotoxx_transform.cc:1154 -msgid "new max. height" -msgstr "" - -#: fotoxx_transform.cc:1161 -msgid "replace originals" -msgstr "" - -#: fotoxx_transform.cc:1162 -msgid "export to location" -msgstr "" - -#: fotoxx_transform.cc:1166 -msgid "copy EXIF" -msgstr "" - -#: fotoxx_transform.cc:1219 -msgid "Select directory" -msgstr "" - -#: fotoxx_transform.cc:1243 -#, c-format -msgid "replace original files? (max. %d x %d)" -msgstr "" - -#: fotoxx_transform.cc:1250 -#, c-format -msgid "" -"copy files? (max. %d x %d) \n" -" to location %s" -msgstr "" - -#: fotoxx_transform.cc:1261 -msgid "location is not a valid directory" -msgstr "" - -#: fotoxx_transform.cc:1304 -msgid "new file already exists" -msgstr "" - -#: fotoxx_transform.cc:1388 -msgid "" -"Enter text, click/drag on image.\n" -"Right click to remove" -msgstr "" - -#: fotoxx_transform.cc:1442 -msgid "Text" -msgstr "" - -#: fotoxx_transform.cc:1449 -msgid "Size" -msgstr "Tamaño" - -#: fotoxx_transform.cc:1452 -msgid "Angle" -msgstr "" - -#: fotoxx_transform.cc:1463 -msgid "Color" -msgstr "" - -#: fotoxx_transform.cc:1464 -msgid "Transparency" -msgstr "" - -#: fotoxx_transform.cc:1472 -msgid "backing" -msgstr "" - -#: fotoxx_transform.cc:1475 -msgid "" -"Outline\n" -" Width" -msgstr "" - -#: fotoxx_transform.cc:1477 -msgid "outline" -msgstr "" - -#: fotoxx_transform.cc:1486 -msgid "Annotation File:" -msgstr "" - -#: fotoxx_transform.cc:1564 -msgid "select font" -msgstr "" - -#: fotoxx_transform.cc:2197 fotoxx_transform.cc:2429 -msgid "horizontal" -msgstr "Horizontal" - -#: fotoxx_transform.cc:2198 fotoxx_transform.cc:2428 -msgid "vertical" -msgstr "Vertical" - -#: fotoxx_transform.cc:2306 -msgid "black/white positive" -msgstr "" - -#: fotoxx_transform.cc:2307 -msgid "black/white negative" -msgstr "" - -#: fotoxx_transform.cc:2308 -msgid "color positive" -msgstr "" - -#: fotoxx_transform.cc:2309 -msgid "color negative" -msgstr "" - -#: fotoxx_transform.cc:2430 -msgid "linear" -msgstr "" - -#: fotoxx_transform.cc:2433 -msgid "curved" -msgstr "" - -#: fotoxx_transform.cc:2692 -msgid "" -" Click the four corners of a tetragon area. Press [apply]. \n" -" The image is warped to make the tetragon into a rectangle." -msgstr "" - -#: fotoxx_transform.cc:2878 -msgid "must have 4 corners" -msgstr "" - -#: fotoxx_transform.cc:2999 -msgid "" -" Select an area to warp using select area function. \n" -" Press [start warp] and pull area with mouse. \n" -" Make multiple mouse pulls until satisfied. \n" -" When finished, select another area or press [done]." -msgstr "" -" Seleccione una área para deformar utilizando el botón [Seleccionar]. \n" -" Pulse [Comenzar deformación] y tire de la área con el ratón. \n" -" Hacer varios tirones con el ratón hasta que quede satisfecho. \n" -" Cuando haya terminado, seleccione otra área o pulse [Hecho]." - -#: fotoxx_transform.cc:3018 -msgid "start warp" -msgstr "Comenzar deformación" - -#: fotoxx_transform.cc:3067 -msgid "Select area first" -msgstr "Debe seleccionar primero el área" - -#: fotoxx_transform.cc:3242 fotoxx_transform.cc:3505 -msgid "" -" Pull an image position using the mouse. \n" -" Make multiple mouse pulls until satisfied. \n" -" When finished, press [done]." -msgstr "" - -#: fotoxx_transform.cc:3771 -msgid "" -" Pull on an image corner using the mouse. \n" -" Make multiple mouse pulls until satisfied. \n" -" When finished, press [done]." -msgstr "" -" Tirar de un borde de la imagen utilizando el ratón. \n" -" Hacer varios tirones con el ratón hasta que quede satisfecho. \n" -" Cuando haya terminado, pulse [Hecho]." - -#~ msgid "Translate" -#~ msgstr "Traducciones" - -#~ msgid "" -#~ "Rename failed \n" -#~ " %s" -#~ msgstr "" -#~ "Falló el renombrado \n" -#~ " %s" - -#~ msgid "Discard modifications?" -#~ msgstr "¿Descartar modificaciones?" - -#~ msgid "whiteness" -#~ msgstr "Aclarar" - -#~ msgid "unknown image format" -#~ msgstr "Formato de imagen desconocido" - -#~ msgid "undo image changes" -#~ msgstr "Deshacer cambios en la imagen" - -#~ msgid "unbend panorama image" -#~ msgstr "Enderezar imagen panorámica" - -#~ msgid "trim image" -#~ msgstr "Recortar imagen" - -#~ msgid "toolbar::save" -#~ msgstr "Guardar" - -#, fuzzy -#~ msgid "this area cannot be processed" -#~ msgstr "" -#~ "No se puede conservar la selección de área.\n" -#~ "¿Continuar?" - -#~ msgid "sharpen image" -#~ msgstr "Enfoque de imagen" - -#~ msgid "set color intensity" -#~ msgstr "Establecer intensidad de color" - -#, fuzzy -#~ msgid "set blend radius" -#~ msgstr "Establecer radio de desenfoque" - -#~ msgid "set RGB spread" -#~ msgstr "Establece el rango RGB" - -#~ msgid "rotate image" -#~ msgstr "Rotar imagen" - -#~ msgid "resize image" -#~ msgstr "Redimensionar imagen" - -#~ msgid "redo image changes" -#~ msgstr "Rehacer cambios en imagen" - -#~ msgid "red" -#~ msgstr "Rojo" - -#~ msgid "recently added" -#~ msgstr "Recientemente añadido" - -#, fuzzy -#~ msgid "radius limit" -#~ msgstr "Radio" - -#~ msgid "quit" -#~ msgstr "Salir" - -#~ msgid "prior function still running" -#~ msgstr "Función anterior todavía en marcha" - -#~ msgid "photo stars" -#~ msgstr "Estrellas" - -#~ msgid "photo date (yyyymmdd)" -#~ msgstr "Fecha de la foto (aaaammdd)" - -#~ msgid "open new image file" -#~ msgstr "Abrir nuevo archivo" - -#~ msgid "open image file" -#~ msgstr "Abrir archivo" - -#~ msgid "open RAW file" -#~ msgstr "Abrir archivo RAW" - -#~ msgid "open" -#~ msgstr "Abrir" - -#~ msgid "kill running function" -#~ msgstr "Cerrar función en marcha" - -#~ msgid "kill" -#~ msgstr "Cerrar" - -#~ msgid "insert" -#~ msgstr "Insertar" - -#~ msgid "input image 2" -#~ msgstr "Elegir imagen 2" - -#~ msgid "image not 8 or 16 bits/color: %s" -#~ msgstr "La imagen %s no tiene 8 o 16 bits/color" - -#~ msgid "image format error: %s" -#~ msgstr "Error en el formato de la imagen: %s" - -#~ msgid "graph" -#~ msgstr "Gráfica" - -#~ msgid "" -#~ "file cannot be read: \n" -#~ " %s" -#~ msgstr "" -#~ "No se puede leer el archivo: \n" -#~ " %s" - -#~ msgid "exiv2 package is required" -#~ msgstr "Se requiere el paquete «exiv2»" - -#~ msgid "exiftool is required to generate tags index" -#~ msgstr "Se necesita «exiftool» para generar el índice de etiquetas" - -#~ msgid "exiftool is required to create tags" -#~ msgstr "Se necesita «exiftool» para cear etiquetas" - -#, fuzzy -#~ msgid "edge calculation missing" -#~ msgstr "Necesita calcular el borde" - -#~ msgid "defog" -#~ msgstr "Desempañar" - -#~ msgid "date range (yyyymmdd)" -#~ msgstr "Formato de fecha (aaaammdd)" - -#~ msgid "computing" -#~ msgstr "computing" - -#~ msgid "color balance" -#~ msgstr "Balance de color" - -#~ msgid "click or drag trim margins" -#~ msgstr "Haz clic o arrastra el borde" - -#~ msgid "" -#~ "cannot create %s \n" -#~ " %s" -#~ msgstr "" -#~ "No se puede crear %s \n" -#~ " %s" - -#~ msgid "brightness distribution" -#~ msgstr "Distribuir el brillo" - -#~ msgid "blur radius" -#~ msgstr "Radio de desenfoque" - -#~ msgid "blend" -#~ msgstr "Mezcla" - -#~ msgid "bigger image" -#~ msgstr "Image más grande" - -#~ msgid "assigned tags" -#~ msgstr "Etiquetas asignadas" - -#~ msgid "adjust brightness / whiteness" -#~ msgstr "Ajustar brillo / claridad" - -#~ msgid "Zoom-" -#~ msgstr "Zoom-" - -#~ msgid "Zoom+" -#~ msgstr "Zoom+" - -#~ msgid "Warp Global" -#~ msgstr "Deformación de la imagen" - -#~ msgid "Warp" -#~ msgstr "Deformar" - -#~ msgid "Unable to save image: %s" -#~ msgstr "No se puede guardar la imagen: %s" - -#~ msgid "Unable to save image" -#~ msgstr "No se puede guardar la imagen" - -#, fuzzy -#~ msgid "Unable to replace file" -#~ msgstr "No se puede guardar la imagen" - -#~ msgid "Unable to copy EXIF data" -#~ msgstr "No se pueden copiar los datos EXIF" - -#~ msgid "Tune Image" -#~ msgstr "Afinar la imagen" - -#~ msgid "Total tags exceed %d characters" -#~ msgstr "El número total de etiquetas excedió en %d caracteres" - -#~ msgid "Too many undo buffers, please save image" -#~ msgstr "Demasiados «deshacer» en el búfer, guarde la imagen" - -#~ msgid "Too many tags: %d" -#~ msgstr "Demasiadas etiquetas: %d" - -#~ msgid "Too many points" -#~ msgstr "Demasiados puntos" - -#~ msgid "Thumbnail Index" -#~ msgstr "Índice de miniaturas" - -#~ msgid "Special Art Effects" -#~ msgstr "Efectos artísticos especiales" - -#~ msgid "Simulate embossing" -#~ msgstr "Simular un repujado" - -#, fuzzy -#~ msgid "Simulate Mosaic" -#~ msgstr "Simular repujado" - -#, fuzzy -#~ msgid "Simulat Mosaic" -#~ msgstr "Simular repujado" - -#~ msgid "Show Area" -#~ msgstr "Mostrar área" - -#~ msgid "Sharp" -#~ msgstr "Enfoque" - -#~ msgid "" -#~ "Select area is not finished.\n" -#~ "Continue without using it?" -#~ msgstr "" -#~ "No se completó la selección de área.\n" -#~ "¿Continuar sin usarla?" - -#~ msgid "Select Area -mouse" -#~ msgstr "Seleccionar área -ratón" - -#~ msgid "Select Area -color" -#~ msgstr "Seleccionar área -color" - -#~ msgid "Save Image as File" -#~ msgstr "Guardar imagen como archivo" - -#~ msgid "Rotate" -#~ msgstr "Rotar" - -#~ msgid "RGB spread" -#~ msgstr "Rango RGB" - -#~ msgid "RGB Spread" -#~ msgstr "Rango RGB" - -#~ msgid "README" -#~ msgstr "LEAME" - -#~ msgid "RAW file template" -#~ msgstr "Plantilla de archivo RAW" - -#~ msgid "Print" -#~ msgstr "Imprimir" - -#~ msgid "Paint Pixels" -#~ msgstr "Pintar píxeles" - -#~ msgid "Package exiftool is missing" -#~ msgstr "No se encuentra el paquete «exiftool»" - -#~ msgid "Output Image" -#~ msgstr "Imagen de salida" - -#, fuzzy -#~ msgid "Outline Image Area for Following Edits" -#~ msgstr "Área de la imagen para ediciones siguientes" - -#~ msgid "No assigned tags index file" -#~ msgstr "Etiquetas sin asignar al archivo de índice" - -#~ msgid "Make HDR Image" -#~ msgstr "Hacer imagen HDR" - -#~ msgid "Make HDF Image" -#~ msgstr "Hacer imagen HDF" - -#~ msgid "" -#~ "Left click/drag: add to selected area. \n" -#~ "Right click: remove prior selection(s). \n" -#~ "Color range: add more or less at once." -#~ msgstr "" -#~ "Hacer clic en el botón izquierdo y arrastrar: añadir al área " -#~ "seleccionada. \n" -#~ "Hacer clic en botón derecho: quitar la(s) selección(es) previa(s). \n" -#~ "Gama de colores: añadir más o menos a la vez." - -#~ msgid "Invert Area" -#~ msgstr "Invertir área" - -#~ msgid "Input Images" -#~ msgstr "Imágenes de entrada" - -#~ msgid "Index Tags and Thumbs" -#~ msgstr "Sincronizar etiquetas y miniaturas" - -#~ msgid "Index (thumbnails)" -#~ msgstr "Índice (miniaturas)" - -#~ msgid "Index" -#~ msgstr "Índice" - -#~ msgid "Image Weights per Brightness Level" -#~ msgstr "Peso de la imagen por nivel de brillo" - -#~ msgid "Hide Area" -#~ msgstr "Ocultar área" - -#~ msgid "HDR Image Weights" -#~ msgstr "Peso de la imagen HDR" - -#, fuzzy -#~ msgid "FreeImage" -#~ msgstr "Redimensionar imagen" - -#, fuzzy -#~ msgid "Flash" -#~ msgstr "Papelera" - -#~ msgid "FREEIMAGE unknown error" -#~ msgstr "Error desconocido en FREEIMAGE " - -#~ msgid "FREEIMAGE error: %s" -#~ msgstr "Error en FREEIMAGE: %s" - -#~ msgid "Error Log" -#~ msgstr "Registro de errores" - -#~ msgid "Edge Calc" -#~ msgstr "Calcular el borde" - -#~ msgid "" -#~ "Drag middle to move \n" -#~ "Drag corners to resize" -#~ msgstr "" -#~ "Arrastre desde el interior para mover \n" -#~ "Arrastre las esquinas para redimensionar" - -#, fuzzy -#~ msgid "" -#~ "Drag and click to enclose an area.\n" -#~ "Use right click to undo prior." -#~ msgstr "" -#~ "Use el ratón, arrastre y haga clic para cerrar un área\n" -#~ "y el botón derecho para deshacer." - -#~ msgid "Distortion" -#~ msgstr "Distorsión" - -#~ msgid "" -#~ "Distance calculation needs a long time.\n" -#~ " Do you want to continue?" -#~ msgstr "" -#~ "El cálculo de la distancia necesita bastante tiempo.\n" -#~ " ¿Desea continuar?" - -#~ msgid "Dimensions" -#~ msgstr "Dimensiones" - -#~ msgid "Delete selected area?" -#~ msgstr "¿Borrar el área seleccionada?" - -#~ msgid "Delete Area" -#~ msgstr "Borrar área" - -#~ msgid "" -#~ "Convert raw file to 48-bit tiff format? \n" -#~ " (this may take a while) " -#~ msgstr "" -#~ "¿Convertir archivos RAW a formato tiff de 48 bits?\n" -#~ " (esto puede tardar un poco)" - -#~ msgid "Convert multiple RAWs" -#~ msgstr "Convertir múltiples RAW" - -#~ msgid "Composite Images" -#~ msgstr "Composición de imágenes" - -#~ msgid "Color Intensity" -#~ msgstr "Intensidad de color" - -#~ msgid "Clear Select Area" -#~ msgstr "Limpiar área seleccionada" - -#~ msgid "Build Tags Index" -#~ msgstr "Construir índice de etiquetas" - -#~ msgid "Brightness/Whiteness" -#~ msgstr "Ajustar brillo / claridad" - -#~ msgid "Brightness/Contrast/Color" -#~ msgstr "Brillo/Contraste/Color" - -#, fuzzy -#~ msgid "Blend Area Edges" -#~ msgstr "Radio de desenfoque" - -#~ msgid "Bend" -#~ msgstr "Mezcla" - -#~ msgid "Assigned tags file error: %s" -#~ msgstr "Error al asignar etiquetas de archivo: %s" - -#~ msgid "Adjust Saturation (RGB spread)" -#~ msgstr "Ajuste de saturación (rango RGB)" - -#~ msgid "2nd image not same size as 1st image" -#~ msgstr "La 2ª imagen no tiene el mismo tamaño que la 1ª" - -#~ msgid "2nd file is not compatible with 1st" -#~ msgstr "Segundo archivo no compatible con el primero" - -#~ msgid " color balance red " -#~ msgstr " balance de color rojo" - -#~ msgid " color balance green " -#~ msgstr " balance de color verde" - -#~ msgid " color balance blue " -#~ msgstr " balance de color azul" - -#~ msgid "" -#~ " Set color depth to 1-8 bits per color. \n" -#~ " Press [apply] to update the image." -#~ msgstr "" -#~ " Establece la profundidad de color a 1-8 bits por color, \n" -#~ " entonces presiona [Aplicar] para actualizar la imagen." - -#~ msgid " green" -#~ msgstr " Verde" - -#~ msgid " blue" -#~ msgstr " Azul" - -#~ msgid " adjust red" -#~ msgstr " Ajuste rojo" - -#~ msgid "" -#~ " left: no color (grey) \n" -#~ " middle: normal (unmodified) \n" -#~ " right: maximum color" -#~ msgstr "" -#~ "izquierda: sin color (gris) \n" -#~ " centro: normal (sin modificar) \n" -#~ " derecha: máximo color" - -#~ msgid "" -#~ " left: no RGB spread (gray) \n" -#~ " middle: normal (unmodified) \n" -#~ " right: maximum RGB spread" -#~ msgstr "" -#~ "izquierda: sin rango RGB (gris) \n" -#~ " centro: normal (sin modificar) \n" -#~ " derecha: rango máximo RGB" - -#~ msgid "" -#~ "\n" -#~ " brightness \n" -#~ " level" -#~ msgstr "" -#~ "\n" -#~ " Brillo \n" -#~ " Nivel" - -#~ msgid "Select image to combine" -#~ msgstr "Seleccionar imagen a combinar" - -#~ msgid "Retouch Image" -#~ msgstr "Retoque de imagen" - -#~ msgid "Package ufraw required for this function" -#~ msgstr "Se necesita la aplicación «ufraw» para esta función" - -#~ msgid "Merge the images together" -#~ msgstr "Mezclar las imágenes en conjunto" - -#~ msgid "Match Images" -#~ msgstr "Ensamblar las imágenes" - -#~ msgid "" -#~ "Drag right image into rough alignment with left \n" -#~ " to rotate, drag right edge up or down" -#~ msgstr "" -#~ "Arrastre la imagen derecha para alinearla con la de la izquierda \n" -#~ " para rotarla, arrastre del borde hacia arriba o abajo" - -#~ msgid "Auto-search lens mm and bow" -#~ msgstr "Busqueda automática de lente mm y curva" - -#~ msgid "Auto" -#~ msgstr "Auto" - -#~ msgid "" -#~ "\n" -#~ " Match Brightness and Color" -#~ msgstr "" -#~ "\n" -#~ " Ensamblar la luminosidad y el color" - -#~ msgid "color range" -#~ msgstr "Rango de color" - -#~ msgid "add tags" -#~ msgstr "Etiquetas asignadas" - -#~ msgid "Fix Image Perspective" -#~ msgstr "Fijar imagen en perspectiva" - -#~ msgid "Burn" -#~ msgstr "Grabar" - -#~ msgid "color intensity" -#~ msgstr "Intensidad de color" - -#~ msgid "Warp Image in Selected Area" -#~ msgstr "Deformar imagen en el área seleccionada" - -#~ msgid "Warp Area" -#~ msgstr "Deformación de área" - -#~ msgid "" -#~ " Pull on an image edge using the mouse. \n" -#~ " Make multiple mouse pulls until satisfied. \n" -#~ " When finished, press [done]." -#~ msgstr "" -#~ " Tirar de un borde de la imagen utilizando el ratón. \n" -#~ " Hacer varios tirones con el ratón hasta que quede satisfecho. \n" -#~ " Cuando haya terminado, pulse [Hecho]." - -#~ msgid "match any tag" -#~ msgstr "Elegir cualquier etiqueta" - -#~ msgid "match all tags" -#~ msgstr "Elegir todas las etiquetas" - -#~ msgid "Tags" -#~ msgstr "Etiquetas" - -#~ msgid "Suspend" -#~ msgstr "Suspender" - -#~ msgid "Set Tile and Gap Size" -#~ msgstr "Configurar mosaico y tamaño de la separación" - -#~ msgid "Search Tags" -#~ msgstr "Buscar etiquetas" - -#~ msgid "Resume" -#~ msgstr "Reanudar" - -#~ msgid "Basic EXIF data" -#~ msgstr "Datos EXIF básicos" - -#~ msgid "All EXIF data" -#~ msgstr "Todos los datos EXIF" - -#~ msgid "/path*/file*" -#~ msgstr "/ruta*/archivo*" - -#~ msgid "HDR" -#~ msgstr "HDR" - -#~ msgid "HDF" -#~ msgstr "HDF" - -#~ msgid "Area" -#~ msgstr "Área" - -#~ msgid "target group area" -#~ msgstr "Área de grupo de destino" - -#~ msgid "vertical unbend" -#~ msgstr "Enderezamiento vertical" - -#~ msgid "horizontal unbend" -#~ msgstr "Enderezamiento horizontal" - -#~ msgid "Create Launcher" -#~ msgstr "Crear un lanzador" - -#~ msgid "Width" -#~ msgstr "Ancho" - -#~ msgid "Unknown file type, save as tiff/jpeg/png to edit" -#~ msgstr "" -#~ "Tipo de fichero desconocido, guarde como tiff/jpeg/png para editarlo" - -#~ msgid "Undo Last" -#~ msgstr "Deshacer el último" - -#~ msgid "Undo All" -#~ msgstr "Deshacer todo" - -#~ msgid "Start" -#~ msgstr "Comenzar" - -#~ msgid "Search" -#~ msgstr "Buscar" - -#~ msgid "Save As" -#~ msgstr "Guardar como" - -#~ msgid "Reduce" -#~ msgstr "Reducir" - -#~ msgid "Red" -#~ msgstr "Rojo" - -#~ msgid "Proceed" -#~ msgstr "Proceder" - -#~ msgid "Presets" -#~ msgstr "Predefinidos" - -#~ msgid "Percent" -#~ msgstr "Porcentaje" - -#~ msgid "OK" -#~ msgstr "Conforme" - -#~ msgid "Lighter Areas" -#~ msgstr "Iluminar áreas" - -#~ msgid "Insert" -#~ msgstr "Insertar" - -#~ msgid "Height" -#~ msgstr "Altura" - -#~ msgid "Green" -#~ msgstr "Verde" - -#~ msgid "Finish" -#~ msgstr "Terminar" - -#~ msgid "Edit" -#~ msgstr "Editar" - -#~ msgid "Done" -#~ msgstr "Hecho" - -#~ msgid "Darker Areas" -#~ msgstr "Oscurecer áreas" - -#~ msgid "Clone fotoxx" -#~ msgstr "Clonar Fotoxx" - -#~ msgid "Clear" -#~ msgstr "Limpiar" - -#~ msgid "Cancel" -#~ msgstr "Cancelar" - -#~ msgid "Brightness" -#~ msgstr "Brillo" - -#~ msgid "Blue" -#~ msgstr "Azul" - -#~ msgid "Blend Width" -#~ msgstr "Mezclar por ancho" - -#~ msgid "Apply" -#~ msgstr "Aplicar" - -#~ msgid "Add All" -#~ msgstr "Añadir todo" - -#~ msgid "Time Interval" -#~ msgstr "Intervalo de tiempo" - -#~ msgid "Delete" -#~ msgstr "Borrar" diff -Nru fotoxx-11.11.1/locales/es/zfuncs.po fotoxx-12.01.2/locales/es/zfuncs.po --- fotoxx-11.11.1/locales/es/zfuncs.po 2011-11-05 05:30:37.000000000 +0000 +++ fotoxx-12.01.2/locales/es/zfuncs.po 1970-01-01 00:00:00.000000000 +0000 @@ -1,292 +0,0 @@ -# Spanish translations for home package. -# Copyright (C) 2008 THE home'S COPYRIGHT HOLDER -# This file is distributed under the same license as the home package. -# mico , 2008. -# -msgid "" -msgstr "" -"Project-Id-Version: zfunks-2.10\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2011-11-05 05:49+0100\n" -"PO-Revision-Date: 2009-10-19 12:37+0100\n" -"Last-Translator: Miguel Anxo Bouzada \n" -"Language-Team: GALPon MiniNo \n" -"Language: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Poedit-Language: Spanish\n" -"X-Poedit-Country: SPAIN\n" - -#: zfuncs.cc:3192 -#, c-format -msgid "help file not found: %s" -msgstr "Archivo de ayuda no encontrado: %s" - -#: zfuncs.cc:3296 -#, c-format -msgid "error: %s" -msgstr "Error: %s" - -#: zfuncs.cc:4415 zfuncs.cc:8771 -#, c-format -msgid "cannot open file %s" -msgstr "No puedo abrir el archivo %s" - -#: zfuncs.cc:4448 -msgid "save screen to file" -msgstr "Guardar pantalla a archivo" - -#: zfuncs.cc:6198 -msgid "No" -msgstr "" - -#: zfuncs.cc:6198 -msgid "Yes" -msgstr "" - -#: zfuncs.cc:6272 zfuncs.cc:6308 zfuncs.cc:6461 zfuncs.cc:6865 zfuncs.cc:8358 -#: zfuncs.cc:8883 zfuncs.cc:8889 zfuncs.cc:8895 zfuncs.cc:8901 -msgid "cancel" -msgstr "Cancelar" - -#: zfuncs.cc:6423 zfuncs.cc:7552 -msgid "open" -msgstr "Abrir" - -#: zfuncs.cc:6428 -msgid "choose" -msgstr "" - -#: zfuncs.cc:6433 -msgid "save" -msgstr "Guardar" - -#: zfuncs.cc:6439 -msgid "open folder" -msgstr "Abrir carpeta" - -#: zfuncs.cc:6444 -msgid "create folder" -msgstr "Crear carpeta" - -#: zfuncs.cc:6450 -msgid "hidden" -msgstr "Ocultar" - -#: zfuncs.cc:6454 -msgid "quality" -msgstr "Calidad" - -#: zfuncs.cc:6511 -msgid "JPG quality 0-100" -msgstr "Calidad de JPG 0-100" - -#: zfuncs.cc:6865 zfuncs.cc:8358 -msgid "done" -msgstr "" - -#: zfuncs.cc:6865 zfuncs.cc:6878 -msgid "margins" -msgstr "" - -#: zfuncs.cc:6874 -msgid "top" -msgstr "" - -#: zfuncs.cc:6875 -msgid "bottom" -msgstr "" - -#: zfuncs.cc:6876 -msgid "left" -msgstr "" - -#: zfuncs.cc:6877 -msgid "right" -msgstr "" - -#: zfuncs.cc:7278 zfuncs.cc:7532 zfuncs.cc:7670 zfuncs.cc:7671 zfuncs.cc:7673 -msgid "bigger" -msgstr "Mayor" - -#: zfuncs.cc:7278 -msgid "increase thumbnail size" -msgstr "Aumentar tamaño de miniatura" - -#: zfuncs.cc:7279 -msgid "reduce thumbnail size" -msgstr "Reducir tamaño de la miniatura" - -#: zfuncs.cc:7279 zfuncs.cc:7542 zfuncs.cc:7672 zfuncs.cc:7674 -msgid "smaller" -msgstr "Menor" - -#: zfuncs.cc:7280 zfuncs.cc:7571 -msgid "parent" -msgstr "" - -#: zfuncs.cc:7280 -msgid "parent directory" -msgstr "" - -#: zfuncs.cc:7281 zfuncs.cc:7589 zfuncs.cc:7681 -msgid "first page" -msgstr "Primera página" - -#: zfuncs.cc:7281 -msgid "jump to first file" -msgstr "Cambiar al primer archivo" - -#: zfuncs.cc:7282 zfuncs.cc:7587 zfuncs.cc:7676 zfuncs.cc:7683 -msgid "prev page" -msgstr "Página anterior." - -#: zfuncs.cc:7282 -msgid "previous page" -msgstr "Página anterior" - -#: zfuncs.cc:7283 zfuncs.cc:7585 zfuncs.cc:7678 -msgid "prev row" -msgstr "Fila anterior." - -#: zfuncs.cc:7283 -msgid "previous row" -msgstr "Fila anterior" - -#: zfuncs.cc:7284 zfuncs.cc:7586 zfuncs.cc:7679 -msgid "next row" -msgstr "Siguiente fila" - -#: zfuncs.cc:7285 zfuncs.cc:7588 zfuncs.cc:7677 zfuncs.cc:7684 -msgid "next page" -msgstr "Página sig." - -#: zfuncs.cc:7286 -msgid "jump to last file" -msgstr "Cambiar al último archivo" - -#: zfuncs.cc:7286 zfuncs.cc:7590 zfuncs.cc:7682 -msgid "last page" -msgstr "Última página" - -#: zfuncs.cc:7287 zfuncs.cc:7527 -msgid "close" -msgstr "Cerrar" - -#: zfuncs.cc:7287 -msgid "close image gallery" -msgstr "Cerrar la galería de imágenes" - -#: zfuncs.cc:7558 -msgid "select new file" -msgstr "Seleccionar archivo nuevo" - -#: zfuncs.cc:8358 -msgid "Select Files" -msgstr "" - -#: zfuncs.cc:8366 -msgid "delete" -msgstr "" - -#: zfuncs.cc:8367 -msgid "insert" -msgstr "" - -#: zfuncs.cc:8368 -msgid "add all" -msgstr "" - -#: zfuncs.cc:8658 -msgid "" -"Initial parameters file created. \n" -"Inspect and revise if necessary." -msgstr "" -"Parámetros iniciales creados. \n" -"Revíselos si lo desea." - -#: zfuncs.cc:8674 -msgid "load parameters from a file" -msgstr "Cargar parámetros desde archivo" - -#: zfuncs.cc:8743 -msgid "save parameters to a file" -msgstr "Guardar parámetros a un archivo" - -#: zfuncs.cc:8881 zfuncs.cc:8887 zfuncs.cc:8893 zfuncs.cc:8899 -msgid "edit parameters" -msgstr "Editar parámetros" - -#: zfuncs.cc:8882 zfuncs.cc:8888 -msgid "" -"list\n" -"all" -msgstr "" -"Listar\n" -"Todo" - -#: zfuncs.cc:8882 zfuncs.cc:8888 zfuncs.cc:8894 zfuncs.cc:8900 -msgid "" -"load\n" -"file" -msgstr "" -"Cargar\n" -"Archivo" - -#: zfuncs.cc:8882 zfuncs.cc:8888 zfuncs.cc:8894 zfuncs.cc:8900 -msgid "" -"save\n" -"file" -msgstr "" -"Guardar\n" -"Archivo" - -#: zfuncs.cc:8883 zfuncs.cc:8895 -msgid "" -"add\n" -"new" -msgstr "" -"Añadir\n" -"Nuevo" - -#: zfuncs.cc:8883 zfuncs.cc:8889 zfuncs.cc:8895 zfuncs.cc:8901 -msgid "apply" -msgstr "Aplicar" - -#: zfuncs.cc:8935 -msgid "apply?" -msgstr "¿Aplicar?" - -#: zfuncs.cc:8992 -msgid "(new parm name)" -msgstr "(Nuevo parámetro)" - -#: zfuncs.cc:8992 -msgid "add parameter" -msgstr "Añadir parámetro" - -#~ msgid "open a file" -#~ msgstr "Abrir un fichero" - -#~ msgid "xdg-utils package not installed" -#~ msgstr "El paquete «xdg-utils» no está instalado" - -#~ msgid "select new folder" -#~ msgstr "Seleccionar nueva carpeta" - -#~ msgid "open a directory" -#~ msgstr "Abrir un directorio" - -#~ msgid "jump to specific file" -#~ msgstr "Cambia a un archivo específico" - -#~ msgid "folder" -#~ msgstr "carpeta" - -#~ msgid "file" -#~ msgstr "Archivo" - -#~ msgid "close thumbnail window" -#~ msgstr "Cerrar Índice de miniaturas" diff -Nru fotoxx-11.11.1/locales/fotoxx-de.po fotoxx-12.01.2/locales/fotoxx-de.po --- fotoxx-11.11.1/locales/fotoxx-de.po 1970-01-01 00:00:00.000000000 +0000 +++ fotoxx-12.01.2/locales/fotoxx-de.po 2012-01-04 08:47:11.000000000 +0000 @@ -0,0 +1,2747 @@ +# German translations for fotoxx package. +# Copyright (C) 2009 THE fotoxx'S COPYRIGHT HOLDER +# This file is distributed under the same license as the fotoxx package. +# +# +msgid "" +msgstr "" +"Project-Id-Version: fotoxx 6.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-12-31 21:04+0100\n" +"PO-Revision-Date: 2009-03-06 09:57+0100\n" +"Language-Team: German\n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: f.art.cc:47 +msgid "Set color depth to 1-16 bits" +msgstr "Farbtiefe auf 1-16 Bits festlegen" + +#: f.art.cc:57 +msgid "Set Color Depth" +msgstr "Farbtiefe festlegen" + +#: f.art.cc:171 +msgid "Simulate Drawing" +msgstr "Zeichen Simulieren" + +#: f.art.cc:213 f.retouch.cc:1759 f.retouch.cc:5991 +msgid "contrast" +msgstr "Kontrast" + +#: f.art.cc:215 +msgid "outlines" +msgstr "Umrisse" + +#: f.art.cc:220 +msgid "pencil" +msgstr "Stift" + +#: f.art.cc:221 +msgid "chalk" +msgstr "Kreide" + +#: f.art.cc:381 +msgid "Add Image Outlines" +msgstr "Bildumrisse addieren" + +#: f.art.cc:394 +msgid "outline threshold" +msgstr "Umriss-Grenzwert" + +#: f.art.cc:397 +msgid "outline width" +msgstr "Umrissbreite" + +#: f.art.cc:400 +msgid "image brightness" +msgstr "Bildhelligkeit" + +#: f.art.cc:611 +msgid "Simulate Embossing" +msgstr "Prägen Simulieren" + +#: f.art.cc:626 +msgid "depth" +msgstr "Tiefe" + +#: f.art.cc:628 f.file.cc:919 f.retouch.cc:6692 +msgid "color" +msgstr "Farbe" + +#: f.art.cc:821 +msgid "Simulate Tiles" +msgstr "Kacheln Simulieren" + +#: f.art.cc:825 +msgid "tile size" +msgstr "Kachelgröße" + +#: f.art.cc:829 +msgid "tile gap" +msgstr "Spaltbreite" + +#: f.art.cc:1003 +msgid "Convert Image to Dots" +msgstr "Bild in Rasterpunkte umwandeln" + +#: f.art.cc:1007 +msgid "dot size" +msgstr "Punktgroße" + +#: f.art.cc:1222 +msgid "Simulate Painting" +msgstr "Malen Simulieren" + +#: f.art.cc:1226 +msgid "color depth" +msgstr "Farbtiefe" + +#: f.art.cc:1230 +msgid "patch area goal" +msgstr "Fleckgröße Ziel" + +#: f.art.cc:1234 +msgid "req. color match" +msgstr "Farbeanpassung" + +#: f.art.cc:1238 +msgid "borders" +msgstr "Ränder" + +#: f.comp.cc:1956 f.comp.cc:1961 f.comp.cc:2582 f.comp.cc:2587 f.comp.cc:3266 +#: f.comp.cc:3271 f.comp.cc:3816 f.comp.cc:3821 +msgid "Select 2 to 9 files" +msgstr "2-9 Dateien auswählen" + +#: f.comp.cc:1982 f.comp.cc:2608 f.comp.cc:3292 f.comp.cc:3842 +msgid "Images are not all the same size" +msgstr "Bilder sind nicht gleich gross" + +#: f.comp.cc:2321 +msgid "Adjust Image Contributions" +msgstr "Bild Beiträge einstellen" + +#: f.comp.cc:2324 f.retouch.cc:886 +msgid "dark pixels" +msgstr "dunkele Pixel" + +#: f.comp.cc:2326 +msgid "light pixels" +msgstr "helle Pixel" + +#: f.comp.cc:2328 f.info.cc:159 +msgid "file:" +msgstr "Datei:" + +#: f.comp.cc:2843 +msgid "Paint and Warp Image" +msgstr "Bild malen und krümmen" + +#: f.comp.cc:2846 f.comp.cc:3520 f.comp.cc:4959 f.comp.cc:5705 +msgid "image" +msgstr "Bild" + +#: f.comp.cc:2850 f.retouch.cc:6696 +msgid "paint" +msgstr "malen" + +#: f.comp.cc:2851 +msgid "warp" +msgstr "Krümmen" + +#: f.comp.cc:3518 +msgid "Select and Paint Image" +msgstr "Bild auswählen und malen" + +#: f.comp.cc:4031 +msgid "Adjust Pixel Composition" +msgstr "Pixel Zusammensetzung einstellen" + +#: f.comp.cc:4283 f.comp.cc:4288 f.comp.cc:5173 f.comp.cc:5178 +msgid "Select 2 to 4 files" +msgstr "2-4 Dateien auswählen" + +#: f.comp.cc:4361 +msgid "" +"Drag images into rough alignment.\n" +"To rotate, drag from lower edge." +msgstr "" +"Bilder zur Grobabstimmung mit der Maus ziehen.\n" +"Zum Drehen unteren Rand links/rechts ziehen" + +#: f.comp.cc:4363 +msgid "Search for lens mm and bow" +msgstr "Suche für Brennweite und Krümmung" + +#: f.comp.cc:4409 f.comp.cc:5298 +msgid "Pre-align Images" +msgstr "Bilder grob anpassen" + +#: f.comp.cc:4413 f.comp.cc:5302 +msgid "lens mm" +msgstr "Objektiv-Brennweite mm" + +#: f.comp.cc:4417 f.comp.cc:5306 +msgid "lens bow" +msgstr "Objektivkrümmung" + +#: f.comp.cc:4419 f.comp.cc:5308 +msgid "Resize" +msgstr "Größe verändern" + +#: f.comp.cc:4420 f.comp.cc:5309 +msgid "resize window" +msgstr "Fenstergröße ändern" + +#: f.comp.cc:4457 +msgid "use two images only" +msgstr "Zwei Bilder benutzen" + +#: f.comp.cc:4478 f.comp.cc:4676 f.comp.cc:4875 f.comp.cc:5357 f.comp.cc:5620 +msgid "Too little overlap, cannot align" +msgstr "Unzureichende Überlappung, Ausrichtung nicht möglich" + +#: f.comp.cc:4950 f.comp.cc:5696 +msgid "Match Brightness and Color" +msgstr "Helligkeit und Farbe anpassen" + +#: f.comp.cc:4974 f.comp.cc:5720 +msgid "auto color" +msgstr "Auto-Farbe" + +#: f.comp.cc:4975 f.comp.cc:5721 +msgid "file color" +msgstr "Datei-Farbe" + +#: f.comp.cc:5251 +msgid "" +"Drag images into rough alignment.\n" +"To rotate, drag from right edge." +msgstr "" +"Bilder zur Grobabstimmung mit der Maus ziehen.\n" +"Zum Drehen, vom rechten Rand ziehen" + +#: f.file.cc:169 f.file.cc:341 fotoxx-12.01.cc:189 fotoxx-12.01.cc:325 +msgid "Open Image File" +msgstr "Bilddatei öffnen" + +#: f.file.cc:321 fotoxx-12.01.cc:2862 +msgid "prior function still active" +msgstr "Vorherige Funktion noch aktiv" + +#: f.file.cc:503 +msgid "Overwrite original file?" +msgstr "Originaldatei überschreiben?" + +#: f.file.cc:504 +msgid "Do not warn again" +msgstr "Nicht wieder warnen" + +#: f.file.cc:520 +msgid "Warning" +msgstr "Warnung" + +#: f.file.cc:643 +msgid "Save File" +msgstr "Datei speichern" + +#: f.file.cc:666 zfuncs.cc:6478 +msgid "quality" +msgstr "Qualität" + +#: f.file.cc:668 +msgid "make current" +msgstr "aktuell machen" + +#: f.file.cc:725 +msgid "jpeg quality must be 1-100" +msgstr "jpeg Qualität muss 1-100 sein" + +#: f.file.cc:747 +#, c-format +msgid "" +"Overwrite file? \n" +" %s" +msgstr "" +"Datei überschreiben? \n" +" %s" + +#: f.file.cc:903 fotoxx-12.01.cc:196 +msgid "Create Blank Image" +msgstr "Leerbild erstellen" + +#: f.file.cc:905 +msgid "file name" +msgstr "Dateiname" + +#: f.file.cc:910 f.transform.cc:353 +msgid "width" +msgstr "Breite" + +#: f.file.cc:913 f.tools.cc:477 f.transform.cc:356 +msgid "height" +msgstr "Höhe" + +#: f.file.cc:1033 +msgid "" +"Linux standard trash is not supported. \n" +"Desktop trash folder will be created." +msgstr "" +"Linux Standard-Abfall nicht unterstützt. \n" +"Desktop Abfall-Ordner wird erstellt." + +#: f.file.cc:1051 +msgid "Move read-only file to trash?" +msgstr "Schreibgeschützte Datei in den Abfall?" + +#: f.file.cc:1077 +#, c-format +msgid "Cannot create trash folder: %s" +msgstr "Kann Abfallkorb nicht erstellen: %s" + +#: f.file.cc:1085 f.file.cc:1091 zfuncs.cc:3356 +#, c-format +msgid "error: %s" +msgstr "Fehler: %s" + +#: f.file.cc:1136 fotoxx-12.01.cc:198 +msgid "Rename Image File" +msgstr "Bilddatei umbenennen" + +#: f.file.cc:1141 +msgid "old name" +msgstr "Vorheriger Name" + +#: f.file.cc:1142 +msgid "rename to" +msgstr "Umbenennen in" + +#: f.file.cc:1143 +msgid "previous" +msgstr "Vorheriges" + +#: f.file.cc:1229 +msgid "The target file already exists" +msgstr "Zieldatei existiert schon" + +#: f.file.cc:1237 +#, c-format +msgid "" +"Rename failed: \n" +" %s" +msgstr "" +"Umbenennen gescheitert: \n" +" %s" + +#: f.file.cc:1285 +msgid "Batch Rename" +msgstr "Bilddateien umbenennen" + +#: f.file.cc:1288 f.file.cc:1340 f.info.cc:1519 f.info.cc:1773 f.tools.cc:543 +#: f.tools.cc:2990 +#, c-format +msgid "%d files selected" +msgstr "%d Dateien ausgewählt" + +#: f.file.cc:1290 +msgid "new base name" +msgstr "neue Basisname" + +#: f.file.cc:1293 +msgid "starting sequence" +msgstr "Anfangs-Sequenznummer" + +#: f.file.cc:1295 +msgid "increment" +msgstr "Zuwachs" + +#: f.file.cc:1316 +msgid "select files to rename" +msgstr "Dateien zum Umbenennen auswählen" + +#: f.file.cc:1321 +msgid "base name / sequence / increment not reasonable" +msgstr "Basisname / Sequenz / Zuwachs nicht sinnvoll" + +#: f.file.cc:1380 +msgid "new file already exists:" +msgstr "Zieldatei existiert schon:" + +#: f.file.cc:1388 +msgid "filespec too long:" +msgstr "Dateiname zu lang:" + +#: f.file.cc:1399 +msgid "Rename failed:" +msgstr "Umbenennen gescheitert:" + +#: f.file.cc:1660 fotoxx.h:729 +msgid "Add" +msgstr "Addieren" + +#: f.file.cc:1660 fotoxx.h:781 +msgid "Remove" +msgstr "Entfernen" + +#: f.file.cc:1662 +msgid "menu name" +msgstr "Menuname" + +#: f.file.cc:1733 f.file.cc:1754 +msgid "Restart Fotoxx to update plugin menu" +msgstr "Fotoxx neu starten um Menus zu aktualisieren" + +#: f.info.cc:70 +msgid "Edit Caption and Comments" +msgstr "Titel und Kommentare bearbeiten" + +#: f.info.cc:156 fotoxx-12.01.cc:225 +msgid "Edit Tags" +msgstr "Tags bearbeiten" + +#: f.info.cc:163 +msgid "image date (yyyymmdd)" +msgstr "Bilddatum (jjjjmmtt)" + +#: f.info.cc:165 +msgid "use last" +msgstr "Letztes" + +#: f.info.cc:168 +msgid "image stars" +msgstr "Bild-Sterne" + +#: f.info.cc:186 +msgid "current tags" +msgstr "Aktuelle Tags" + +#: f.info.cc:191 +msgid "recent tags" +msgstr "Kürzliche Tags" + +#: f.info.cc:196 f.info.cc:358 f.info.cc:1368 f.info.cc:2384 +msgid "defined tags" +msgstr "Definierte Tags" + +#: f.info.cc:345 fotoxx-12.01.cc:226 +msgid "Manage Tags" +msgstr "Tags verwalten" + +#: f.info.cc:348 +msgid "category" +msgstr "Gruppe" + +#: f.info.cc:351 +msgid "tag" +msgstr "Tag" + +#: f.info.cc:354 +msgid "create" +msgstr "Erstellen" + +#: f.info.cc:355 f.navi.cc:1421 +msgid "delete" +msgstr "Löschen" + +#: f.info.cc:1235 f.info.cc:1319 +#, c-format +msgid "search index file error: %s" +msgstr "Fehler in Such-Index Datei: %s" + +#: f.info.cc:1351 fotoxx-12.01.cc:227 +msgid "Batch Add Tags" +msgstr "Mehrere Tags zuweisen" + +#: f.info.cc:1354 +msgid "tags to add" +msgstr "Tags zum Zuweisen" + +#: f.info.cc:1359 +msgid "create tag" +msgstr "Tag erstellen" + +#: f.info.cc:1415 f.info.cc:1608 +#, c-format +msgid "" +"%s \n" +" too many tags" +msgstr "" +"%s \n" +" Zuviele Tags" + +#: f.info.cc:1553 fotoxx-12.01.cc:228 +msgid "Batch Delete Tag" +msgstr "Tag in Bilder löschen" + +#: f.info.cc:1556 +msgid "tag to remove" +msgstr "Tag zu entfernen" + +#: f.info.cc:1560 +msgid "optional replacement" +msgstr "Wahlersatz" + +#: f.info.cc:1565 f.tools.cc:2943 +msgid "0 files selected" +msgstr "0 Dateien ausgewählt" + +#: f.info.cc:1568 +msgid "search all files" +msgstr "Alle Dateien durchsuchen" + +#: f.info.cc:1653 +msgid "no files selected" +msgstr "Keine Dateien ausgewählt" + +#: f.info.cc:1659 +msgid "no tag specified" +msgstr "Kein Tag angegeben" + +#: f.info.cc:1683 f.info.cc:1712 +msgid "specify tag" +msgstr "Tag angeben" + +#: f.info.cc:1821 +msgid "View Info" +msgstr "Info ansehen" + +#: f.info.cc:1889 fotoxx-12.01.cc:231 +msgid "Edit Info" +msgstr "Info bearbeiten" + +#: f.info.cc:1987 fotoxx-12.01.cc:232 +msgid "Delete Info" +msgstr "Info löschen" + +#: f.info.cc:1989 fotoxx.h:731 +msgid "All" +msgstr "Alles" + +#: f.info.cc:1990 +msgid "One Key:" +msgstr "Ein Key:" + +#: f.info.cc:2343 +msgid "Search Tags, Comments, File Names" +msgstr "Tags, Kommentare, Dateinamen durchsuchen" + +#: f.info.cc:2350 +msgid "date range" +msgstr "Datumsbereich" + +#: f.info.cc:2351 +msgid "stars range" +msgstr "Sterne-Wertebereich" + +#: f.info.cc:2352 +msgid "search tags" +msgstr "Such-Tags" + +#: f.info.cc:2353 +msgid "search text" +msgstr "Text durchsuchen" + +#: f.info.cc:2354 +msgid "file names" +msgstr "Dateinamen" + +#: f.info.cc:2359 +msgid "(yyyymmdd)" +msgstr "(jjjjmmtt)" + +#: f.info.cc:2365 +msgid "all/any" +msgstr "alle/irgendeines" + +#: f.info.cc:2702 +msgid "No matching images found" +msgstr "Keine übereinstimmenden Bilder gefunden" + +#: f.info.cc:2706 f.info.cc:3059 +msgid "No search index file present" +msgstr "Such-Index Datei fehlt" + +#: f.info.cc:2777 +msgid "Additional Items for Report" +msgstr "Zusätzliche Metadaten im Bericht" + +#: f.navi.cc:188 f.navi.cc:576 f.navi.cc:706 f.navi.cc:707 f.navi.cc:709 +msgid "bigger" +msgstr "Größer" + +#: f.navi.cc:188 +msgid "increase thumbnail size" +msgstr "Thumbnails vergrößern" + +#: f.navi.cc:189 +msgid "reduce thumbnail size" +msgstr "Thumbnails verkleinern" + +#: f.navi.cc:189 f.navi.cc:586 f.navi.cc:708 f.navi.cc:710 +msgid "smaller" +msgstr "Kleiner" + +#: f.navi.cc:190 f.navi.cc:600 +msgid "parent" +msgstr "Stamm" + +#: f.navi.cc:190 +msgid "parent directory" +msgstr "Übergeordnetes Verzeichniss" + +#: f.navi.cc:191 f.navi.cc:625 f.navi.cc:717 +msgid "first page" +msgstr "Erste Seite" + +#: f.navi.cc:191 +msgid "jump to first file" +msgstr "Zur ersten Datei" + +#: f.navi.cc:192 f.navi.cc:623 f.navi.cc:712 f.navi.cc:719 +msgid "prev page" +msgstr "Vorherige Seite" + +#: f.navi.cc:192 +msgid "previous page" +msgstr "Vorherige Seite" + +#: f.navi.cc:193 f.navi.cc:621 f.navi.cc:714 +msgid "prev row" +msgstr "Vorherige Reihe" + +#: f.navi.cc:193 +msgid "previous row" +msgstr "Vorherige Reihe" + +#: f.navi.cc:194 f.navi.cc:622 f.navi.cc:715 +msgid "next row" +msgstr "Nächste Reihe" + +#: f.navi.cc:195 f.navi.cc:624 f.navi.cc:713 f.navi.cc:720 +msgid "next page" +msgstr "Nächste Seite" + +#: f.navi.cc:195 +msgid "ttip::next page" +msgstr "Nächste Seite" + +#: f.navi.cc:196 +msgid "jump to last file" +msgstr "Zur letzten Datei" + +#: f.navi.cc:196 f.navi.cc:626 f.navi.cc:718 +msgid "last page" +msgstr "Letzte Seite" + +#: f.navi.cc:197 f.navi.cc:571 +msgid "close" +msgstr "Schließen" + +#: f.navi.cc:197 +msgid "close image gallery" +msgstr "Bildergalerie schließen" + +#: f.navi.cc:1413 fotoxx.h:787 +msgid "Select Files" +msgstr "Dateien auswählen" + +#: f.navi.cc:1413 zfuncs.cc:6296 zfuncs.cc:6332 zfuncs.cc:6485 zfuncs.cc:6728 +#: zfuncs.cc:7427 zfuncs.cc:7433 zfuncs.cc:7439 zfuncs.cc:7445 +msgid "cancel" +msgstr "Abbrechen" + +#: f.navi.cc:1413 zfuncs.cc:6728 +msgid "done" +msgstr "fertig" + +#: f.navi.cc:1422 +msgid "insert" +msgstr "hinzufügen" + +#: f.navi.cc:1423 +msgid "add all" +msgstr "Alle hinzufügen" + +#: f.retouch.cc:55 +msgid "Adjust Brightness and Color" +msgstr "Helligkeit und Farbe abstimmen" + +#: f.retouch.cc:110 +msgid "small-steps" +msgstr "Kleinschritte" + +#: f.retouch.cc:119 +msgid "color saturation" +msgstr "Farbsättigung" + +#: f.retouch.cc:126 +msgid " reset 1 " +msgstr "1 zurücksetzen" + +#: f.retouch.cc:127 +msgid "reset all" +msgstr "Alle zurücksetzen" + +#: f.retouch.cc:599 +msgid "adjust image gamma" +msgstr "Bildgamma justieren" + +#: f.retouch.cc:885 +msgid "Expand Brightness Range" +msgstr "Helligkeitsbreite ausdehned" + +#: f.retouch.cc:887 +msgid "bright pixels" +msgstr "Helle Pixel" + +#: f.retouch.cc:1058 +msgid "Flatten Brightness Distribution" +msgstr "Helligkeitsverteilung ausgleichen" + +#: f.retouch.cc:1072 +msgid "Flatten" +msgstr "Ausgleichen" + +#: f.retouch.cc:1334 +msgid "Ramp brightness across image" +msgstr "Helligkeit bereichsweise im Bild ändern" + +#: f.retouch.cc:1730 fotoxx-12.01.cc:272 +msgid "Tone Mapping" +msgstr "Tone Mapping" + +#: f.retouch.cc:1758 +msgid "low" +msgstr "niedrig" + +#: f.retouch.cc:1760 +msgid "high" +msgstr "hoch" + +#: f.retouch.cc:1763 +msgid "Amplify" +msgstr "Verstärken" + +#: f.retouch.cc:2069 +msgid "Adjust White Balance" +msgstr "Weißabgleich abstimmen" + +#: f.retouch.cc:2070 +msgid "Click white or gray image location" +msgstr "Weißen oder grauen Bildbereich anklicken" + +#: f.retouch.cc:2278 +msgid "Color Match Images" +msgstr "Bilderfarben anpassen" + +#: f.retouch.cc:2307 +msgid "mouse radius for color sample" +msgstr "Mausradius für Farbauswahl" + +#: f.retouch.cc:2309 f.retouch.cc:2314 fotoxx-12.01.cc:246 fotoxx-12.01.cc:325 +#: fotoxx.h:769 +msgid "Open" +msgstr "Öffnen" + +#: f.retouch.cc:2310 +msgid "image for source color" +msgstr "Bild für Quellfarbe" + +#: f.retouch.cc:2312 +msgid "click on image to get source color" +msgstr "Bild anklicken zur Quellfarbe bestimmen" + +#: f.retouch.cc:2315 +msgid "image to set matching color" +msgstr "Bild zur Abgleichfarbe festlegen" + +#: f.retouch.cc:2317 +msgid "click on image to set matching color" +msgstr "Bild anklicken zur Abgleichfarbe festlegen" + +#: f.retouch.cc:2372 +msgid "select source image color first" +msgstr "Farbe vom Quellbild zuerst wählen" + +#: f.retouch.cc:2584 +msgid "Add standard bias" +msgstr "Normalabstand addieren" + +#: f.retouch.cc:2591 +msgid "+Brightness -Density" +msgstr "+Helligkeit -Dichte" + +#: f.retouch.cc:2592 +msgid "+Red -Cyan" +msgstr "+Rot -Zyan" + +#: f.retouch.cc:2593 +msgid "+Green -Magenta" +msgstr "+Grün -Magenta" + +#: f.retouch.cc:2594 +msgid "+Blue -Yellow" +msgstr "+Blau -Gelb" + +#: f.retouch.cc:2599 +msgid "Contrast" +msgstr "Kontrast" + +#: f.retouch.cc:2600 fotoxx.h:778 +msgid "Red" +msgstr "Rot" + +#: f.retouch.cc:2601 fotoxx.h:758 +msgid "Green" +msgstr "Grün" + +#: f.retouch.cc:2602 fotoxx.h:736 +msgid "Blue" +msgstr "Blau" + +#: f.retouch.cc:2730 +msgid "Load DRGB parameters" +msgstr "DRGB Parameter laden" + +#: f.retouch.cc:2732 f.retouch.cc:2804 f.retouch.cc:6102 f.retouch.cc:6198 +msgid "File:" +msgstr "Datei:" + +#: f.retouch.cc:2751 f.retouch.cc:2824 +msgid "DRGB parameters file" +msgstr "DRGB Parameter-Datei" + +#: f.retouch.cc:2769 f.retouch.cc:6142 +msgid "file not found" +msgstr "Datei nicht gefunden" + +#: f.retouch.cc:2802 +msgid "Save DRGB parameters" +msgstr "DRGB Parameter speichern" + +#: f.retouch.cc:3034 f.tools.cc:2404 +msgid "Click image to select pixels." +msgstr "Bild anklicken zum Pixeln auswählen" + +#: f.retouch.cc:3072 fotoxx-12.01.cc:276 +msgid "Revise RGB" +msgstr "RGB revidieren" + +#: f.retouch.cc:3084 +msgid "Metric:" +msgstr "Einheit" + +#: f.retouch.cc:3139 +msgid "Blend" +msgstr "Beimischen" + +#: f.retouch.cc:3519 +msgid "" +"Method 1:\n" +" Left-click on red-eye to darken.\n" +"Method 2:\n" +" Drag down and right to enclose red-eye.\n" +" Left-click on red-eye to darken.\n" +"Undo red-eye:\n" +" Right-click on red-eye." +msgstr "" +"Methode 1:\n" +" Linksklick in das rote Auge zum Abdunkeln.\n" +"Methode 2:\n" +" Linke Maustaste gedrückt nach rechts unten ziehen zur Markierung des roten " +"Auges.\n" +" Linksklick in das rote Auge zum Abdunkeln.\n" +"Zurücksetzen:\n" +" Rechtsklick in das rote Auge." + +#: f.retouch.cc:3534 +msgid "Red Eye Reduction" +msgstr "Rote-Augen beseitigen" + +#: f.retouch.cc:3968 +msgid "Set Blur Radius" +msgstr "Verwisch-Radius festlegen" + +#: f.retouch.cc:4195 fotoxx-12.01.cc:279 +msgid "Sharpen Image" +msgstr "Bild schärfen" + +#: f.retouch.cc:4202 +msgid "edge detection" +msgstr "Kantenerkennung" + +#: f.retouch.cc:4203 +msgid "cycles" +msgstr "Zyklen" + +#: f.retouch.cc:4204 +msgid "reduce" +msgstr "Vermindern" + +#: f.retouch.cc:4215 +msgid "unsharp mask" +msgstr "Unscharf maskieren" + +#: f.retouch.cc:4228 +msgid "brightness gradient" +msgstr "Helligkeits-Gradient" + +#: f.retouch.cc:4634 +msgid "" +" Press the reduce button to \n" +" reduce noise in small steps. \n" +" Use undo to start over." +msgstr "" +" [Vermindern] drücken zur \n" +" schrittweisen Rauschreduzierung. \n" +" [undo] zum Neustart." + +#: f.retouch.cc:4645 +msgid "Noise Reduction" +msgstr "Rauschverminderung" + +#: f.retouch.cc:4650 +msgid "algorithm" +msgstr "Algorithmus" + +#: f.retouch.cc:4657 +msgid "flatten outliers by color (1)" +msgstr "Ausreißer nach Farbe mitteln (1)" + +#: f.retouch.cc:4658 +msgid "flatten outliers by color (2)" +msgstr "Ausreißer nach Farbe mitteln (2)" + +#: f.retouch.cc:4659 +msgid "set median brightness by color" +msgstr "Mittlere Helligkeit pro Farbe setzen" + +#: f.retouch.cc:4660 f.retouch.cc:4661 +msgid "top hat filter by color" +msgstr "Tophat-Filter nach Farbe" + +#: f.retouch.cc:4976 +msgid "" +"1. Drag mouse to select. \n" +"2. Erase. 3. Repeat. " +msgstr "" +"1. Zum Selektieren, Maus ziehen. \n" +"2. Löschen. 3. Wiederholen. " + +#: f.retouch.cc:4998 fotoxx-12.01.cc:281 +msgid "Smart Erase" +msgstr "Smart löschen" + +#: f.retouch.cc:5003 fotoxx.h:776 +msgid "Radius" +msgstr "Radius" + +#: f.retouch.cc:5005 +msgid "Blur" +msgstr "Verwischen" + +#: f.retouch.cc:5008 +msgid "New Area" +msgstr "Neuer Ausschnitt" + +#: f.retouch.cc:5379 fotoxx-12.01.cc:282 +msgid "Remove Dust" +msgstr "Staub entfernen" + +#: f.retouch.cc:5383 +msgid "spot size limit" +msgstr "Fleckgrößen Limit" + +#: f.retouch.cc:5386 +msgid "max. brightness" +msgstr "max. Helligkeit" + +#: f.retouch.cc:5389 +msgid "min. contrast" +msgstr "Min. Kontrast" + +#: f.retouch.cc:5983 fotoxx-12.01.cc:283 +msgid "Fix Stuck Pixels" +msgstr "Festpixel reparieren" + +#: f.retouch.cc:5989 +msgid "pixel group" +msgstr "Pixelgruppe" + +#: f.retouch.cc:5990 +msgid "circle color" +msgstr "Kreisfarbe" + +#: f.retouch.cc:6100 +msgid "Load Stuck Pixels" +msgstr "Festpixel laden" + +#: f.retouch.cc:6124 f.retouch.cc:6220 +msgid "Stuck Pixels file" +msgstr "Festpixel Datei" + +#: f.retouch.cc:6164 +msgid "file format error" +msgstr "Dateiformat Fehler" + +#: f.retouch.cc:6192 +msgid "there are zero stuck pixels" +msgstr "Keine Festpixel" + +#: f.retouch.cc:6196 +msgid "Save Stuck Pixels" +msgstr "Festpixel speichern" + +#: f.retouch.cc:6686 +#, c-format +msgid "Undo Memory %d%c" +msgstr "Undo-Speicher %d%c" + +#: f.retouch.cc:6688 fotoxx-12.01.cc:284 +msgid "Edit Pixels" +msgstr "Pixel bearbeiten" + +#: f.retouch.cc:6695 +msgid "pick" +msgstr "wählen" + +#: f.retouch.cc:6697 +msgid "erase" +msgstr "löschen" + +#: f.retouch.cc:6705 +msgid "paintbrush radius" +msgstr "Pinsel-Radius" + +#: f.retouch.cc:6706 +msgid "transparency center" +msgstr "Transparenz Mitte" + +#: f.retouch.cc:6707 +msgid "transparency edge" +msgstr "Transparenz Rand" + +#: f.retouch.cc:6972 +msgid "" +"Undo memory limit has been reached. \n" +"Save work with [done], then resume editing." +msgstr "" +"Undo Speicherkapazität erreicht. \n" +"Arbeit mit [fertig] sichern, dann Fortfahren." + +#: f.select.cc:54 f.select.cc:2461 +msgid "Select Area for Edits" +msgstr "Ausschnitt für Bearbeitung auswählen" + +#: f.select.cc:55 f.select.cc:2462 +msgid "Press F1 for help" +msgstr "F1 für Hilfe drucken" + +#: f.select.cc:64 +msgid "" +"Select Area not supported \n" +"by this edit function" +msgstr "" +"Ausschnitt nicht unterstützt \n" +"von dieser Bearbeitungsfunktion" + +#: f.select.cc:103 f.tools.cc:901 +msgid "rectangle" +msgstr "Rechteck" + +#: f.select.cc:104 f.tools.cc:902 +msgid "ellipse" +msgstr "Ellipse" + +#: f.select.cc:110 +msgid "draw: freehand" +msgstr "Zeichnen: freihand" + +#: f.select.cc:111 +msgid "draw: follow edge" +msgstr "Zeichnen: Rand folgen" + +#: f.select.cc:114 +msgid "select by mouse" +msgstr "mit der Maus selektieren" + +#: f.select.cc:116 f.select.cc:2496 +msgid "mouse radius" +msgstr "Mausradius" + +#: f.select.cc:120 +msgid "match mouse color" +msgstr "Übereinstimmung der Mausfarbe" + +#: f.select.cc:124 +msgid "search range" +msgstr "Suchweite" + +#: f.select.cc:126 +msgid "firewall" +msgstr "Brandmauer" + +#: f.select.cc:326 f.select.cc:467 +#, c-format +msgid "exceed %d edits" +msgstr "%d Edits überschritten" + +#: f.select.cc:1021 +msgid "" +"Click one time inside each enclosed area \n" +"(possible gaps in the outline will be found). \n" +"Press F1 for help." +msgstr "" +"Jeden umschlossen Ausschnitt einmal innen anklicken \n" +"(mögliche Lücken im Rand werden gefunden). \n" +"Für Hilfe F1 drucken." + +#: f.select.cc:1078 +msgid "finish area" +msgstr "Ausschnitt fertigstellen" + +#: f.select.cc:1113 +msgid "searching" +msgstr "wird gesucht" + +#: f.select.cc:1185 +msgid "outline has a gap" +msgstr "Umriss hat eine Lücke" + +#: f.select.cc:1189 +msgid "success" +msgstr "Erfolg" + +#: f.select.cc:1440 f.select.cc:1470 +msgid "the area is not finished" +msgstr "Der Ausschnitt ist nicht fertig" + +#: f.select.cc:1563 +msgid "Edge calculation in progress" +msgstr "Rand Berechnung in Arbeit" + +#: f.select.cc:1572 +msgid "Area Edge Calc" +msgstr "Ausschnitt Randberechnung" + +#: f.select.cc:1863 +msgid "position with mouse click/drag" +msgstr "Mit Maus klicken/ziehen positionieren" + +#: f.select.cc:1887 +msgid "Paste Image" +msgstr "Bild einfügen" + +#: f.select.cc:1901 +msgid "angle" +msgstr "Winkel" + +#: f.select.cc:2160 +msgid "load select area from a file" +msgstr "Auschnitt von Datei lesen" + +#: f.select.cc:2194 +msgid "cannot open .tiff and .info files" +msgstr "Kann .tiff und .info Dateien nicht öffnen" + +#: f.select.cc:2213 +msgid "save select area to a file" +msgstr "Ausschnitt in Datei speichern" + +#: f.select.cc:2248 fotoxx-12.01.cc:248 +msgid "Select Whole Image" +msgstr "Gesamtbild auswählen" + +#: f.select.cc:2249 +msgid "Edit Function Amplifier" +msgstr "Bearbeitungs-Verstärker" + +#: f.select.cc:2463 +msgid "Edit function must be active" +msgstr "Erst Bearbeitungsfunktion aktivieren" + +#: f.select.cc:2499 +msgid "power: center" +msgstr "Stärke: Mitte" + +#: f.select.cc:2501 +msgid "edge" +msgstr "Rand" + +#: f.select.cc:2504 +msgid "reset area" +msgstr "zurücksetzen" + +#: f.tools.cc:42 +msgid "" +"When editing a collection, right-click \n" +"an image or thumbnail to add or remove." +msgstr "" +"Beim Verarbeiten einer Sammlung, rechts anklicken \n" +"um ein Bild oder Thumbnail zu addieren oder entfernen." + +#: f.tools.cc:70 fotoxx-12.01.cc:204 +msgid "Manage Collections" +msgstr "Sammlungen verwalten" + +#: f.tools.cc:85 +msgid "Start new collection" +msgstr "Neue Sammlung starten" + +#: f.tools.cc:87 +msgid "Edit a collection" +msgstr "Sammlung verarbeiten" + +#: f.tools.cc:89 +msgid "View a collection" +msgstr "Sammlung ansehen" + +#: f.tools.cc:91 +msgid "Delete a collection" +msgstr "Sammlung löschen" + +#: f.tools.cc:95 +msgid "Editing:" +msgstr "Verarbeiten:" + +#: f.tools.cc:99 +msgid "Action:" +msgstr "Vorgang:" + +#: f.tools.cc:133 +msgid "New Collection" +msgstr "Neue Sammlung" + +#: f.tools.cc:156 +msgid "Edit Collection" +msgstr "Sammlung bearbeiten" + +#: f.tools.cc:172 +msgid "View Collection" +msgstr "Sammlung ansehen" + +#: f.tools.cc:193 +msgid "Delete Collection" +msgstr "Sammlung löschen" + +#: f.tools.cc:196 +#, c-format +msgid "delete %s ?" +msgstr "%s löschen?" + +#: f.tools.cc:223 +#, c-format +msgid "add image to collection: %s" +msgstr "Bild in Sammlung: %s einfügen" + +#: f.tools.cc:225 f.tools.cc:270 +msgid "remove image from collection" +msgstr "Bild aus Sammlung entfernen" + +#: f.tools.cc:226 f.tools.cc:271 f.tools.cc:298 +msgid "remove and save image" +msgstr "Bild entfernen und aufheben" + +#: f.tools.cc:227 f.tools.cc:316 +msgid "insert saved images here" +msgstr "Aufgehobene Bilder hier einfügen" + +#: f.tools.cc:256 +msgid "add image to collection" +msgstr "Bild in Sammlung einfügen" + +#: f.tools.cc:301 +msgid "too many saved files" +msgstr "Zu viele aufgehobene Dateien" + +#: f.tools.cc:373 fotoxx-12.01.cc:205 +msgid "Move Collections" +msgstr "Sammlungen versetzen" + +#: f.tools.cc:375 +msgid "old top directory" +msgstr "Altes oberstes Bild-Verzeichnis" + +#: f.tools.cc:378 +msgid "new top directory" +msgstr "Neues oberstes Bild-Verzeichnis" + +#: f.tools.cc:434 +msgid "completed" +msgstr "Fertig" + +#: f.tools.cc:467 +msgid "Batch Convert/Resize/Export" +msgstr "Dateien konvertieren/skalieren/auslagern" + +#: f.tools.cc:474 +msgid "new max. width" +msgstr "Neu max. Breite" + +#: f.tools.cc:481 +msgid "new file type" +msgstr "Neue Dateityp" + +#: f.tools.cc:482 +msgid "same" +msgstr "Ebenso" + +#: f.tools.cc:490 +msgid "replace originals" +msgstr "Dateien überschreiben" + +#: f.tools.cc:491 +msgid "export to location" +msgstr "In Ordner auslagern" + +#: f.tools.cc:492 +msgid "remove EXIF" +msgstr "EXIF entfernen" + +#: f.tools.cc:549 +msgid "Select directory" +msgstr "Bildverzeichnis wählen" + +#: f.tools.cc:583 +#, c-format +msgid "replace original files? (max. %d x %d)" +msgstr "Originaldateien überschreiben? (max. %d %d)" + +#: f.tools.cc:590 +#, c-format +msgid "" +"copy files? (max. %d x %d) \n" +" to location %s" +msgstr "" +"Dateien kopieren? (max. %d x %d) \n" +" in Ordner %s" + +#: f.tools.cc:601 +msgid "location is not a valid directory" +msgstr "Kein gültiger Dateiordner" + +#: f.tools.cc:608 f.tools.cc:3007 +#, c-format +msgid "max. size %d x %d is not reasonable" +msgstr "Max. größe %d x %d nicht sinnvoll" + +#: f.tools.cc:654 +msgid "*** file already exists" +msgstr "*** Datei existiert schon" + +#: f.tools.cc:662 +msgid "*** file type not supported" +msgstr "*** Dateityp nicht unterstützt" + +#: f.tools.cc:741 +msgid "Program ufraw-batch is required" +msgstr "Program ufraw-batch ist nötig" + +#: f.tools.cc:751 fotoxx.h:770 +msgid "Open RAW File" +msgstr "RAW-Datei öffnen" + +#: f.tools.cc:764 +msgid "Select RAW files to convert" +msgstr "RAW Dateien zum konvertieren auswählen" + +#: f.tools.cc:769 +msgid "Choose file type" +msgstr "Dateityp wählen" + +#: f.tools.cc:888 +msgid "Press ESC to exit slide show" +msgstr "ESC drücken um zu beenden" + +#: f.tools.cc:889 +msgid "show only latest file versions" +msgstr "Nur neueste Dateiversionen zeigen" + +#: f.tools.cc:893 +msgid "arrow keys" +msgstr "Pfeiltasten" + +#: f.tools.cc:894 +msgid "instant" +msgstr "Sofortig" + +#: f.tools.cc:895 +msgid "fade-in" +msgstr "Einblenden" + +#: f.tools.cc:896 +msgid "roll-right" +msgstr "Nach rechts rollend" + +#: f.tools.cc:897 +msgid "roll-down" +msgstr "Nach unten rollend" + +#: f.tools.cc:898 +msgid "shift-left" +msgstr "Nach links verlagern" + +#: f.tools.cc:899 +msgid "venetian" +msgstr "Jalousie" + +#: f.tools.cc:900 +msgid "grate" +msgstr "Gitter" + +#: f.tools.cc:903 +msgid "radar" +msgstr "Radar" + +#: f.tools.cc:904 +msgid "jaws" +msgstr "Haifisch" + +#: f.tools.cc:911 fotoxx-12.01.cc:208 +msgid "Slide Show" +msgstr "Dia-Show" + +#: f.tools.cc:915 +msgid "seconds" +msgstr "Sekunden" + +#: f.tools.cc:919 +msgid "music file" +msgstr "Musikdatei" + +#: f.tools.cc:923 +msgid "transitions" +msgstr "Übergänge" + +#: f.tools.cc:1040 +msgid "Select music file or playlist" +msgstr "Musikdatei oder Playlist wählen" + +#: f.tools.cc:1727 +msgid "Sync Files is already running" +msgstr "Datei Synchronisierung läuft schon" + +#: f.tools.cc:1778 +msgid "" +"Run Tools > Synchronize Files so that gallery windows \n" +"will be fast and Search Images will work correctly. \n" +"You can view (not edit) images while synchronize runs." +msgstr "" +"Werkzeuge > Synchronisieren benutzen, damit Galleriefenster \n" +"schnell erscheinen und Bild durchsuchen korrekt funktioniert. \n" +"Sie können Bilder ansehen (nicht verarbeiten) während Synchronisierung." + +#: f.tools.cc:1812 +msgid "no top image directory is defined" +msgstr "Oberstes Bild-Verzeichnis nicht definiert" + +#: f.tools.cc:1818 +msgid "top image directory is invalid" +msgstr "Oberstes Bild-Verzeichnis ist ungültig" + +#: f.tools.cc:1823 +msgid "no search index file is present" +msgstr "Such-Index Datei fehlt" + +#: f.tools.cc:1837 +msgid "new/modified files are present" +msgstr "neue/geänderte Dateien gefunden" + +#: f.tools.cc:1844 +msgid "no new files found" +msgstr "Keine neue Dateien gefunden" + +#: f.tools.cc:1859 fotoxx-12.01.cc:209 +msgid "Synchronize Files" +msgstr "Dateien synchronisieren" + +#: f.tools.cc:1861 +msgid "Top Image Directory:" +msgstr "Oberste Bild-Verzeichnis" + +#: f.tools.cc:1883 +msgid "" +"file sync is necessary.\n" +"cancel anyway?" +msgstr "" +"Sunchronisieren ist notwendig.\n" +"Trotzdem abbrechen?" + +#: f.tools.cc:1896 +msgid "top directory is invalid" +msgstr "Oberstes-Bildverzeichnis ist ungültig" + +#: f.tools.cc:2292 +msgid "Select top image directory" +msgstr "Oberstes Bildverzeichnis wählen" + +#: f.tools.cc:2429 fotoxx-12.01.cc:210 +msgid "Show RGB" +msgstr "RGB-Werte zeigen" + +#: f.tools.cc:2719 fotoxx-12.01.cc:211 +msgid "Grid Lines" +msgstr "Gitterlinien" + +#: f.tools.cc:2728 +msgid "x-spacing" +msgstr "x-Abstand" + +#: f.tools.cc:2729 +msgid "x-count" +msgstr "x-Anzahl" + +#: f.tools.cc:2730 +msgid "x-enable" +msgstr "x-aktivieren" + +#: f.tools.cc:2736 +msgid "y-spacing" +msgstr "y-Abstand" + +#: f.tools.cc:2737 +msgid "y-count" +msgstr "y-Anzahl" + +#: f.tools.cc:2738 +msgid "y-enable" +msgstr "y-aktivieren" + +#: f.tools.cc:2745 +msgid "x-offset" +msgstr "x-Verschiebung" + +#: f.tools.cc:2749 +msgid "y-offset" +msgstr "y-Verschiebung" + +#: f.tools.cc:2940 fotoxx-12.01.cc:213 +msgid "E-mail Images" +msgstr "Bilder E-mailen" + +#: f.tools.cc:2947 +msgid "max. width" +msgstr "max. Breite" + +#: f.tools.cc:2948 +msgid "max. height" +msgstr "max. Höhe" + +#: f.tools.cc:3093 +msgid "too many files" +msgstr "zu viele Dateien" + +#: f.tools.cc:3134 +msgid "" +"Brightness should show a gradual ramp \n" +"extending all the way to the edges." +msgstr "" +"Helligkeit soll einen allmählichen Ansteig \n" +"zeigen, auch ganz bis zu den Rändern." + +#: f.tools.cc:3174 +msgid "Monitor Check" +msgstr "Monitor Prüfung" + +#: f.tools.cc:3232 fotoxx-12.01.cc:215 +msgid "Monitor Gamma" +msgstr "Bildschirm-Gamma" + +#: f.tools.cc:3294 fotoxx-12.01.cc:216 +msgid "Brightness Distribution" +msgstr "Helligkeitsverteilung" + +#: f.tools.cc:3432 +msgid "Available Translations" +msgstr "Vorhandene Übersetzungen" + +#: f.tools.cc:3436 +msgid "Set Language" +msgstr "Sprache wechseln" + +#: f.tools.cc:3502 +msgid "Make Launcher" +msgstr "Start-Icon erzeugen" + +#: f.tools.cc:3540 +msgid "Settings" +msgstr "Einstellungen" + +#: f.tools.cc:3545 +msgid "Startup Display" +msgstr "Anfangsbild" + +#: f.tools.cc:3547 +msgid "Recent Files Gallery" +msgstr "Neueste Dateien Gallerie" + +#: f.tools.cc:3548 +msgid "Previous Image Viewed" +msgstr "Vorher gesehenes Bild" + +#: f.tools.cc:3549 +msgid "Blank Window" +msgstr "Leeres Bild" + +#: f.tools.cc:3551 +msgid "Directory Gallery" +msgstr "Verzeichnis Gallerie" + +#: f.tools.cc:3556 +msgid "Image File" +msgstr "Bild Datei" + +#: f.tools.cc:3562 +msgid "Toolbar Style" +msgstr "Symbolleiste-Stil" + +#: f.tools.cc:3563 f.transform.cc:1300 +msgid "Text" +msgstr "Text" + +#: f.tools.cc:3564 +msgid "Icons" +msgstr "Icons" + +#: f.tools.cc:3565 +msgid "Both" +msgstr "Beides" + +#: f.tools.cc:3568 +msgid "Warn Overwrite" +msgstr "Überschreib Warnung" + +#: f.tools.cc:3639 +msgid "startup directory is invalid" +msgstr "Anfangsverzeichnis ungültig" + +#: f.tools.cc:3650 +msgid "startup file is invalid" +msgstr "Anfangsdatei ungültig" + +#: f.tools.cc:3707 +msgid "Select startup directory" +msgstr "Anfangsverzeichnis wählen" + +#: f.tools.cc:3715 +msgid "Select startup image file" +msgstr "Anfangsbild wählen" + +#: f.transform.cc:50 +msgid "Use buttons or drag right edge with mouse" +msgstr "" +"Knöpfe benutzen oder \n" +"rechten Rand mit der Maus ziehen" + +#: f.transform.cc:60 fotoxx-12.01.cc:252 +msgid "Rotate Image" +msgstr "Bild drehen" + +#: f.transform.cc:64 +msgid "degrees" +msgstr "Grad" + +#: f.transform.cc:80 f.transform.cc:124 +msgid "Trim" +msgstr "Schnitt" + +#: f.transform.cc:81 f.transform.cc:2289 f.transform.cc:3120 +#: f.transform.cc:3383 f.transform.cc:3644 +msgid "Grid" +msgstr "Gitter" + +#: f.transform.cc:123 +msgid "Undo Trim" +msgstr "Undo Schnitt" + +#: f.transform.cc:139 +#, c-format +msgid "degrees: %.1f" +msgstr "Grad: %.1f" + +#: f.transform.cc:286 +msgid "gold" +msgstr "Gold" + +#: f.transform.cc:334 +msgid "Drag middle to move, drag corners to resize." +msgstr "Zum Bewegen mittig ziehen, Ecken um Größe zu verändern." + +#: f.transform.cc:348 fotoxx-12.01.cc:253 +msgid "Trim Image" +msgstr "Bild zuschneiden" + +#: f.transform.cc:348 +msgid "customize" +msgstr "Anpassen" + +#: f.transform.cc:359 +msgid "ratio" +msgstr "Verhältnis" + +#: f.transform.cc:363 +msgid "Lock Ratio" +msgstr "Seitenverhältniss fixieren" + +#: f.transform.cc:368 +msgid "invert" +msgstr "Invert." + +#: f.transform.cc:890 +msgid "Trim Buttons" +msgstr "Schnitt-Knöpfe" + +#: f.transform.cc:1064 +msgid "Lock aspect ratio" +msgstr "Breite/Höhe-Verhältnis fixieren" + +#: f.transform.cc:1072 fotoxx-12.01.cc:255 +msgid "Resize Image" +msgstr "Bildgröße verändern" + +#: f.transform.cc:1095 fotoxx-12.01.cc:326 +msgid "Prev" +msgstr "Vorheriges" + +#: f.transform.cc:1245 +msgid "" +"Enter text, click/drag on image.\n" +"Right click to remove" +msgstr "" +"Text eingeben, Bild mit der Maus klicken/ziehen.\n" +"Zum Entfernen rechts klicken" + +#: f.transform.cc:1294 fotoxx-12.01.cc:256 +msgid "Annotate Image" +msgstr "Bild kommentieren" + +#: f.transform.cc:1307 +msgid "Size" +msgstr "Größe" + +#: f.transform.cc:1310 +msgid "Angle" +msgstr "Winkel" + +#: f.transform.cc:1321 fotoxx.h:741 +msgid "Color" +msgstr "Farbe" + +#: f.transform.cc:1322 +msgid "Transparency" +msgstr "Transparenz" + +#: f.transform.cc:1325 +msgid "text" +msgstr "Text" + +#: f.transform.cc:1330 +msgid "backing" +msgstr "Hinterfarbe" + +#: f.transform.cc:1333 +msgid "" +"Outline\n" +" Width" +msgstr "" +"Umriss\n" +"Breite" + +#: f.transform.cc:1335 +msgid "outline" +msgstr "Umriss" + +#: f.transform.cc:1342 +msgid "Annotation File:" +msgstr "Kommentardatei" + +#: f.transform.cc:1416 +msgid "select font" +msgstr "Font wählen" + +#: f.transform.cc:2045 fotoxx-12.01.cc:257 +msgid "Flip Image" +msgstr "Bild spiegeln" + +#: f.transform.cc:2049 f.transform.cc:2281 +msgid "horizontal" +msgstr "Horizontal" + +#: f.transform.cc:2050 f.transform.cc:2280 +msgid "vertical" +msgstr "Vertikal" + +#: f.transform.cc:2155 fotoxx-12.01.cc:258 +msgid "Make Negative" +msgstr "Negativ erstellen" + +#: f.transform.cc:2158 +msgid "black/white positive" +msgstr "schwarzweiß Positiv" + +#: f.transform.cc:2159 +msgid "black/white negative" +msgstr "schwarzweiß Negativ" + +#: f.transform.cc:2160 +msgid "color positive" +msgstr "farbige Positiv" + +#: f.transform.cc:2161 +msgid "color negative" +msgstr "farbige Negativ" + +#: f.transform.cc:2272 fotoxx-12.01.cc:259 +msgid "Unbend Image" +msgstr "Bild entkrümmen" + +#: f.transform.cc:2282 +msgid "linear" +msgstr "linear" + +#: f.transform.cc:2285 +msgid "curved" +msgstr "kurvig" + +#: f.transform.cc:2544 +msgid "" +" Click the four corners of a tetragon area. Press [apply]. \n" +" The image is warped to make the tetragon into a rectangle." +msgstr "" +" Die vier Ecken eines Tetragonalbereich anklicken. [Anwenden] drücken. \n" +" Das Tetragon wird zu einem geraden Rechteck verzogen." + +#: f.transform.cc:2556 fotoxx-12.01.cc:260 +msgid "Keystone Correction" +msgstr "Schlussstein-Korrektur" + +#: f.transform.cc:2724 +msgid "must have 4 corners" +msgstr "Vier Ecken sind nötig" + +#: f.transform.cc:2847 +msgid "" +" Select an area to warp using select area function. \n" +" Press [start warp] and pull area with mouse. \n" +" Make multiple mouse pulls until satisfied. \n" +" When finished, select another area or press [done]." +msgstr "" +" Ausschnitt zum Krümmen wählen mittels Menü, Ausschnitt wählen. \n" +" [Krümmen starten] drücken, Ausschnitt mit der Maus ziehen. \n" +" Mehrmals ziehen/strecken bis zum erwünschten Ergebniss. \n" +" Wenn fertig, anderen Ausschnitt wählen oder [Fertig] drücken." + +#: f.transform.cc:2859 fotoxx-12.01.cc:261 +msgid "Warp Image (area)" +msgstr "Bild krümmen (Ausschnitt)" + +#: f.transform.cc:2864 +msgid "start warp" +msgstr "Krümmen starten" + +#: f.transform.cc:2931 +msgid "no active Select Area" +msgstr "Ausschnit nicht aktiviert" + +#: f.transform.cc:3099 f.transform.cc:3362 +msgid "" +" Pull an image position using the mouse. \n" +" Make multiple mouse pulls until satisfied. \n" +" When finished, press [done]." +msgstr "" +" Bildstelle mit der Maus ziehen. \n" +" Mehrmals ziehen bis zufriedenstellend. \n" +" Wenn fertig, [Fertig] drücken." + +#: f.transform.cc:3112 fotoxx-12.01.cc:262 +msgid "Warp Image (curved)" +msgstr "Bild krümmen (kurvig)" + +#: f.transform.cc:3375 fotoxx-12.01.cc:263 +msgid "Warp Image (linear)" +msgstr "Bild krümmen (linear)" + +#: f.transform.cc:3628 +msgid "" +" Pull on an image corner using the mouse. \n" +" Make multiple mouse pulls until satisfied. \n" +" When finished, press [done]." +msgstr "" +" Bildecke mit der Maus ziehen. \n" +" Mehrmals ziehen bis zufriedengestellt. \n" +" Wenn fertig, [Fertig] drücken." + +#: f.transform.cc:3639 fotoxx-12.01.cc:264 +msgid "Warp Image (affine)" +msgstr "Bild krümmen (affine)" + +#: fotoxx-12.01.cc:185 +msgid "File" +msgstr "Datei" + +#: fotoxx-12.01.cc:186 fotoxx-12.01.cc:324 +msgid "Image Gallery" +msgstr "Bildergalerie" + +#: fotoxx-12.01.cc:187 +msgid "Clone 50/50" +msgstr "50/50 klonen" + +#: fotoxx-12.01.cc:188 +msgid "Clone Overlay" +msgstr "Überlagernd klonen" + +#: fotoxx-12.01.cc:190 +msgid "Open in New Window" +msgstr "im neuen Fenster öffnen" + +#: fotoxx-12.01.cc:191 fotoxx-12.01.cc:326 +msgid "Open Previous File" +msgstr "Vorherige Bilddatei öffnen" + +#: fotoxx-12.01.cc:192 +msgid "Open Recent File" +msgstr "zuletzt benutzte Dateien" + +#: fotoxx-12.01.cc:193 fotoxx-12.01.cc:334 +msgid "Save to Same File" +msgstr "in gleicher Datei speichern" + +#: fotoxx-12.01.cc:194 fotoxx-12.01.cc:335 +msgid "Save to New Version" +msgstr "in neuer Version speichern" + +#: fotoxx-12.01.cc:195 fotoxx-12.01.cc:336 +msgid "Save to New File" +msgstr "in neuer Datei speichern" + +#: fotoxx-12.01.cc:197 +msgid "Trash Image File" +msgstr "Bilddatei in den Abfall" + +#: fotoxx-12.01.cc:199 +msgid "Batch Rename Files" +msgstr "Bilddateien umbenennen" + +#: fotoxx-12.01.cc:200 +msgid "Print Image File" +msgstr "Bilddatei drucken" + +#: fotoxx-12.01.cc:201 fotoxx-12.01.cc:340 +msgid "Quit fotoxx" +msgstr "fotoxx beenden" + +#: fotoxx-12.01.cc:203 +msgid "Tools" +msgstr "Werkzeuge" + +#: fotoxx-12.01.cc:206 +msgid "Batch Convert" +msgstr "Dateien konvertieren" + +#: fotoxx-12.01.cc:207 +msgid "Convert RAW files" +msgstr "RAW-Dateien konvertieren" + +#: fotoxx-12.01.cc:212 +msgid "Burn Images to CD/DVD" +msgstr "Bilder auf CD/DVD brennen" + +#: fotoxx-12.01.cc:214 +msgid "Check Monitor" +msgstr "Monitor prüfen" + +#: fotoxx-12.01.cc:217 +msgid "Change Language" +msgstr "Sprache wechseln" + +#: fotoxx-12.01.cc:219 +msgid "Menu and Launcher" +msgstr "Menu und Starter" + +#: fotoxx-12.01.cc:220 +msgid "User Settings" +msgstr "Benutzereinstellungen" + +#: fotoxx-12.01.cc:221 +msgid "Memory Usage" +msgstr "Speicherbelegung" + +#: fotoxx-12.01.cc:224 +msgid "Edit Caption/Comments" +msgstr "Titel/Kommentare bearbeiten" + +#: fotoxx-12.01.cc:229 +msgid "View Info (short)" +msgstr "Info ansehen (kurz)" + +#: fotoxx-12.01.cc:230 +msgid "View Info (long)" +msgstr "Info ansehen (lang)" + +#: fotoxx-12.01.cc:233 +msgid "Search Images" +msgstr "Bilddatei durchsuchen" + +#: fotoxx-12.01.cc:234 +msgid "Search Metadata" +msgstr "Metadaten suchen" + +#: fotoxx-12.01.cc:236 fotoxx-12.01.cc:237 fotoxx.h:786 +msgid "Select" +msgstr "Auswählen" + +#: fotoxx-12.01.cc:238 fotoxx.h:788 +msgid "Show" +msgstr "Zeigen" + +#: fotoxx-12.01.cc:239 fotoxx.h:761 +msgid "Hide" +msgstr "Ausblenden" + +#: fotoxx-12.01.cc:240 fotoxx.h:752 +msgid "Enable" +msgstr "Aktivieren" + +#: fotoxx-12.01.cc:241 fotoxx.h:748 +msgid "Disable" +msgstr "Ausschalten" + +#: fotoxx-12.01.cc:242 fotoxx.h:763 +msgid "Invert" +msgstr "Invertieren" + +#: fotoxx-12.01.cc:243 fotoxx.h:796 +msgid "Unselect" +msgstr "Deselektieren" + +#: fotoxx-12.01.cc:244 fotoxx.h:743 +msgid "Copy" +msgstr "Kopieren" + +#: fotoxx-12.01.cc:245 fotoxx.h:771 +msgid "Paste" +msgstr "Einfügen" + +#: fotoxx-12.01.cc:247 fotoxx-12.01.cc:334 fotoxx.h:783 +msgid "Save" +msgstr "Speichern" + +#: fotoxx-12.01.cc:249 +msgid "Select and Edit" +msgstr "Auswählen und bearbeiten" + +#: fotoxx-12.01.cc:251 +msgid "Transform" +msgstr "Umwandeln" + +#: fotoxx-12.01.cc:254 +msgid "Auto-Trim Image" +msgstr "Bild auto-zuschneiden" + +#: fotoxx-12.01.cc:266 +msgid "Retouch" +msgstr "Retuschieren" + +#: fotoxx-12.01.cc:267 +msgid "Brightness/Color" +msgstr "Helligkeit/Farbe" + +#: fotoxx-12.01.cc:268 +msgid "Gamma Curves" +msgstr "Gamma Kurven" + +#: fotoxx-12.01.cc:269 +msgid "Expand Brightness" +msgstr "Helligkeit ausdehnen" + +#: fotoxx-12.01.cc:270 +msgid "Flatten Brightness" +msgstr "Helligkeit ausgleichen" + +#: fotoxx-12.01.cc:271 +msgid "Brightness Ramp" +msgstr "Helligkeit rampen" + +#: fotoxx-12.01.cc:273 +msgid "White Balance" +msgstr "Weißabgleich" + +#: fotoxx-12.01.cc:274 +msgid "Match Colors" +msgstr "Farben anpassen" + +#: fotoxx-12.01.cc:277 +msgid "Red Eyes" +msgstr "Rote Augen" + +#: fotoxx-12.01.cc:278 +msgid "Blur Image" +msgstr "Bild verwischen" + +#: fotoxx-12.01.cc:280 +msgid "Reduce Noise" +msgstr "Rauschen vermindern" + +#: fotoxx-12.01.cc:286 +msgid "Art" +msgstr "Kunst" + +#: fotoxx-12.01.cc:287 +msgid "Color Depth" +msgstr "Farbtiefe" + +#: fotoxx-12.01.cc:288 +msgid "Drawing" +msgstr "Zeichnung" + +#: fotoxx-12.01.cc:289 +msgid "Outlines" +msgstr "Umrisse" + +#: fotoxx-12.01.cc:290 +msgid "Embossing" +msgstr "Prägung" + +#: fotoxx-12.01.cc:291 +msgid "Tiles" +msgstr "Kacheln" + +#: fotoxx-12.01.cc:292 +msgid "Dots" +msgstr "Rasterpunkte" + +#: fotoxx-12.01.cc:293 +msgid "Painting" +msgstr "Gemälde" + +#: fotoxx-12.01.cc:295 +msgid "Combine" +msgstr "Verbund" + +#: fotoxx-12.01.cc:296 +msgid "High Dynamic Range" +msgstr "Hoher Dynamikbereich" + +#: fotoxx-12.01.cc:297 +msgid "High Depth of Field" +msgstr "Hohe Schärfentiefe" + +#: fotoxx-12.01.cc:298 +msgid "Stack / Paint" +msgstr "Stapeln / malen" + +#: fotoxx-12.01.cc:299 +msgid "Stack / Noise" +msgstr "Stapeln / Rauschen" + +#: fotoxx-12.01.cc:300 +msgid "Panorama" +msgstr "Panorama" + +#: fotoxx-12.01.cc:301 +msgid "Vertical Panorama" +msgstr "Vertikales Panorama" + +#: fotoxx-12.01.cc:304 +msgid "Edit Plugins" +msgstr "Plugins bearbeiten" + +#: fotoxx-12.01.cc:313 fotoxx-12.01.cc:341 fotoxx-12.01.cc:3026 +msgid "Help" +msgstr "Hilfe" + +#: fotoxx-12.01.cc:314 fotoxx-12.01.cc:3016 +msgid "About" +msgstr "Über Fotoxx" + +#: fotoxx-12.01.cc:315 fotoxx-12.01.cc:3020 +msgid "User Guide" +msgstr "Benutzeranleitung" + +#: fotoxx-12.01.cc:316 fotoxx-12.01.cc:3023 +msgid "User Guide Changes" +msgstr "Benutzeranleitung Änderungen" + +#: fotoxx-12.01.cc:317 fotoxx-12.01.cc:3032 +msgid "Edit Functions Summary" +msgstr "Verarbeitungsfunktionen Übersicht" + +#: fotoxx-12.01.cc:318 fotoxx-12.01.cc:3035 +msgid "Change Log" +msgstr "Änderungslog" + +#: fotoxx-12.01.cc:319 fotoxx-12.01.cc:3038 +msgid "Translations" +msgstr "Übersetzungen" + +#: fotoxx-12.01.cc:320 fotoxx-12.01.cc:3041 +msgid "Home Page" +msgstr "Homepage" + +#: fotoxx-12.01.cc:324 +msgid "Gallery" +msgstr "Galerie" + +#: fotoxx-12.01.cc:327 fotoxx.h:767 +msgid "Next" +msgstr "Nächstes" + +#: fotoxx-12.01.cc:327 +msgid "Open Next File" +msgstr "Nächste Bilddatei öffnen" + +#: fotoxx-12.01.cc:328 +msgid "Zoom-in (bigger)" +msgstr "Heranzoomen (größer)" + +#: fotoxx-12.01.cc:329 +msgid "Zoom-out (smaller)" +msgstr "Herauszoomen (kleiner)" + +#: fotoxx-12.01.cc:330 fotoxx.h:794 +msgid "Undo" +msgstr "Undo" + +#: fotoxx-12.01.cc:330 +msgid "Undo One Edit" +msgstr "Eine Änderung rückgängig machen" + +#: fotoxx-12.01.cc:331 fotoxx.h:779 +msgid "Redo" +msgstr "Redo" + +#: fotoxx-12.01.cc:331 +msgid "Redo One Edit" +msgstr "Verworfene Änderung wieder anwenden" + +#: fotoxx-12.01.cc:335 +msgid "Save+V" +msgstr "Speich.V" + +#: fotoxx-12.01.cc:336 +msgid "Save+F" +msgstr "Speich.D" + +#: fotoxx-12.01.cc:337 +msgid "Move Image to Trash" +msgstr "Bilddatei in den Abfall" + +#: fotoxx-12.01.cc:337 +msgid "Trash" +msgstr "Abfall" + +#: fotoxx-12.01.cc:340 +msgid "Quit" +msgstr "Beenden" + +#: fotoxx-12.01.cc:341 +msgid "Fotoxx Essentials" +msgstr "Fotoxx wichtig" + +#: fotoxx-12.01.cc:448 +msgid "first time startup" +msgstr "Das erste Mal Start" + +#: fotoxx-12.01.cc:1944 +msgid "Exceed 50 anchor points" +msgstr "50 Ankerpunkte überschritten" + +#: fotoxx-12.01.cc:2129 +msgid "load curve from a file" +msgstr "Kurven-Datei öffnen" + +#: fotoxx-12.01.cc:2182 +msgid "curve file is invalid" +msgstr "Kurven-Datei ist ungültig" + +#: fotoxx-12.01.cc:2187 +msgid "curve file has different no. of curves" +msgstr "Datei Kurvenanzahl stimmt nicht" + +#: fotoxx-12.01.cc:2202 +msgid "save curve to a file" +msgstr "Kurven-Datei speichern" + +#: fotoxx-12.01.cc:2337 +msgid "cannot parallel edit" +msgstr "Kann nicht parallel laufen" + +#: fotoxx-12.01.cc:2347 +msgid "" +"exiftool is not installed \n" +"edited images will lose EXIF data" +msgstr "" +"EXIFTtool-Paket nicht installiert \n" +"(bearbeitete Bilder verlieren ihre EXIF-Daten!)" + +#: fotoxx-12.01.cc:2353 +msgid "Too many edits, please save image" +msgstr "Zuviele Änderungen, bitte Bild speichern" + +#: fotoxx-12.01.cc:2358 +msgid "" +"Select area cannot be kept.\n" +"Continue?" +msgstr "" +"Ausschnitt kann nicht behalten werden.\n" +"Fortfahren?" + +#: fotoxx-12.01.cc:2366 +msgid "" +"Select area not active.\n" +"Continue?" +msgstr "" +"Ausschnit nicht aktiviert.\n" +"Fortfahren?" + +#: fotoxx-12.01.cc:2837 +msgid "Discard edits?" +msgstr "Änderungen verwerfen?" + +#: fotoxx-12.01.cc:2838 +msgid "" +"This action will discard current edits.\n" +"Continue to discard edits.\n" +"Go Back to keep edits." +msgstr "" +"Vorgang wird aktuelle Änderungen verwerfen.\n" +"Fortfahren um diese zu verwerfen.\n" +"Zurückgehen um diese zu behalten." + +#: fotoxx-12.01.cc:2841 +msgid "Continue" +msgstr "Fortfahren" + +#: fotoxx-12.01.cc:2842 +msgid "Go Back" +msgstr "Zurückgehen" + +#: fotoxx-12.01.cc:3659 +msgid "cannot open thumbnail file" +msgstr "Thumbnaildatei nicht lesbar" + +#: fotoxx-12.01.cc:3870 fotoxx-12.01.cc:3992 +msgid "TIFF open failure" +msgstr "TIFF öffnen Fehler" + +#: fotoxx-12.01.cc:3886 +#, c-format +msgid "TIFF bits/color=%d not supported" +msgstr "TIFF Farbtiefe=%d nicht unterstützt" + +#: fotoxx-12.01.cc:3901 fotoxx-12.01.cc:3939 +msgid "TIFF read failure" +msgstr "TIFF Lesefehler" + +#: fotoxx-12.01.cc:4051 +msgid "TIFF write failure" +msgstr "TIFF Schreibfehler" + +#: fotoxx-12.01.cc:4071 +msgid "file type not supported" +msgstr "Dateityp nicht unterstützt" + +#: fotoxx-12.01.cc:4178 +msgid "pixbuf write failure" +msgstr "Pixbuf Schreibfehler" + +#: fotoxx.h:728 +msgid "absolute" +msgstr "absolute" + +#: fotoxx.h:730 +msgid "Add All" +msgstr "Alle einfügen" + +#: fotoxx.h:732 +msgid "Amount" +msgstr "Wert" + +#: fotoxx.h:733 +msgid "Apply" +msgstr "Anwenden" + +#: fotoxx.h:734 +msgid "Black" +msgstr "Schwarz" + +#: fotoxx.h:735 +msgid "Blend Width" +msgstr "Mischbreite" + +#: fotoxx.h:737 +msgid "Brightness" +msgstr "Helligkeit" + +#: fotoxx.h:738 +msgid "Browse" +msgstr "Durchsuchen" + +#: fotoxx.h:739 +msgid "Cancel" +msgstr "Abbrechen" + +#: fotoxx.h:740 +msgid "Clear" +msgstr "Aufräumen" + +#: fotoxx.h:742 +msgid "Commit" +msgstr "Binden" + +#: fotoxx.h:744 +msgid "Curve File:" +msgstr "Kurven-Datei" + +#: fotoxx.h:745 +msgid "Cut" +msgstr "Ausschneiden" + +#: fotoxx.h:746 +msgid "Darker Areas" +msgstr "Dunklere Bereiche" + +#: fotoxx.h:747 +msgid "Delete" +msgstr "Löschen" + +#: fotoxx.h:749 +#, c-format +msgid "" +"Discard special gallery list? \n" +" %s" +msgstr "" +"Spezielle Bildliste abwerfen? \n" +" %s" + +#: fotoxx.h:750 +msgid "Done" +msgstr "Fertig" + +#: fotoxx.h:751 +msgid "Edit" +msgstr "Bearbeiten" + +#: fotoxx.h:753 +msgid "Erase" +msgstr "Löschen" + +#: fotoxx.h:754 +msgid "package libimage-exiftool-perl is required" +msgstr "Packet libimage-exiftool-perl fehlt" + +#: fotoxx.h:755 +msgid "Fetch" +msgstr "Holen" + +#: fotoxx.h:756 +msgid "Finish" +msgstr "Fertigstellen" + +#: fotoxx.h:757 +msgid "Font" +msgstr "Font" + +#: fotoxx.h:759 +msgid "Height" +msgstr "Höhe" + +#: fotoxx.h:760 +msgid "histogram" +msgstr "Histogramm" + +#: fotoxx.h:762 +msgid "Insert" +msgstr "Einfügen" + +#: fotoxx.h:764 +msgid "Lighter Areas" +msgstr "Hellere Bereiche" + +#: fotoxx.h:765 +msgid "limit" +msgstr "Limit" + +#: fotoxx.h:766 +msgid "New" +msgstr "Neu" + +#: fotoxx.h:768 +msgid "OK" +msgstr "OK" + +#: fotoxx.h:772 +msgid "Pause" +msgstr "Unterbrechen" + +#: fotoxx.h:773 +msgid "Percent" +msgstr "Prozent" + +#: fotoxx.h:774 +msgid "Presets" +msgstr "Voreinstellungen" + +#: fotoxx.h:775 +msgid "Proceed" +msgstr "Weiter" + +#: fotoxx.h:777 +msgid "range" +msgstr "Wertbereich" + +#: fotoxx.h:780 +msgid "Reduce" +msgstr "Vermindern" + +#: fotoxx.h:782 +msgid "Reset" +msgstr "Zurücksetzen" + +#: fotoxx.h:784 +msgid "Unknown file type, save as tiff/jpeg/png to edit" +msgstr "Dateityp unbekannt, zum bearbeiten als tiff/jpeg/png speichern" + +#: fotoxx.h:785 +msgid "Search" +msgstr "Durchsuchen" + +#: fotoxx.h:789 +msgid "Start" +msgstr "Starten" + +#: fotoxx.h:790 +msgid "Threshold" +msgstr "Schwelle" + +#: fotoxx.h:791 +#, c-format +msgid "exceed %d files" +msgstr "%d Dateien überschritten" + +#: fotoxx.h:792 +msgid "Undo All" +msgstr "Alles rückgängig" + +#: fotoxx.h:793 +msgid "Undo Last" +msgstr "Letztes rückgängig" + +#: fotoxx.h:795 +msgid "Unfinish" +msgstr "Unfertigstellen" + +#: fotoxx.h:797 +msgid "View" +msgstr "Ansehen" + +#: fotoxx.h:798 +msgid "White" +msgstr "Weiß" + +#: fotoxx.h:799 +msgid "Width" +msgstr "Breite" + +#: zfuncs.cc:3252 +#, c-format +msgid "help file not found: %s" +msgstr "Hilfedatei nicht gefunden: %s" + +#: zfuncs.cc:3664 zfuncs.cc:7315 +#, c-format +msgid "cannot open file %s" +msgstr "Kann Datei nicht öffnen %s" + +#: zfuncs.cc:3697 +msgid "save screen to file" +msgstr "Bildschirm in Datei speichern" + +#: zfuncs.cc:6222 +msgid "No" +msgstr "Nein" + +#: zfuncs.cc:6222 +msgid "Yes" +msgstr "Ja" + +#: zfuncs.cc:6447 +msgid "open" +msgstr "Öffnen" + +#: zfuncs.cc:6452 +msgid "choose" +msgstr "Wählen" + +#: zfuncs.cc:6457 +msgid "save" +msgstr "Speichern" + +#: zfuncs.cc:6463 +msgid "open folder" +msgstr "Verzeichnis öffnen" + +#: zfuncs.cc:6468 +msgid "create folder" +msgstr "Ordner erstellen" + +#: zfuncs.cc:6474 +msgid "hidden" +msgstr "Versteckt" + +#: zfuncs.cc:6535 +msgid "JPG quality 0-100" +msgstr "JPG-Qualität 0-100" + +#: zfuncs.cc:6728 zfuncs.cc:6741 +msgid "margins" +msgstr "Ränder" + +#: zfuncs.cc:6737 +msgid "top" +msgstr "oben" + +#: zfuncs.cc:6738 +msgid "bottom" +msgstr "unten" + +#: zfuncs.cc:6739 +msgid "left" +msgstr "links" + +#: zfuncs.cc:6740 +msgid "right" +msgstr "rechts" + +#: zfuncs.cc:7202 +msgid "" +"Initial parameters file created. \n" +"Inspect and revise if necessary." +msgstr "" +"Anfangsparameter-Datei wurde angelegt. \n" +"Bei Bedarf kontrollieren und berichtigen ." + +#: zfuncs.cc:7218 +msgid "load parameters from a file" +msgstr "Parameter aus einer Datei laden" + +#: zfuncs.cc:7287 +msgid "save parameters to a file" +msgstr "Parameter in Datei speichern" + +#: zfuncs.cc:7425 zfuncs.cc:7431 zfuncs.cc:7437 zfuncs.cc:7443 +msgid "edit parameters" +msgstr "Parameter ändern" + +#: zfuncs.cc:7426 zfuncs.cc:7432 +msgid "" +"list\n" +"all" +msgstr "" +"Auflisten\n" +"Alle" + +#: zfuncs.cc:7426 zfuncs.cc:7432 zfuncs.cc:7438 zfuncs.cc:7444 +msgid "" +"load\n" +"file" +msgstr "" +"Laden\n" +"Datei" + +#: zfuncs.cc:7426 zfuncs.cc:7432 zfuncs.cc:7438 zfuncs.cc:7444 +msgid "" +"save\n" +"file" +msgstr "" +"Speichern\n" +"Datei" + +#: zfuncs.cc:7427 zfuncs.cc:7439 +msgid "" +"add\n" +"new" +msgstr "" +"hinzufügen\n" +"Neu" + +#: zfuncs.cc:7427 zfuncs.cc:7433 zfuncs.cc:7439 zfuncs.cc:7445 +msgid "apply" +msgstr "Anwenden" + +#: zfuncs.cc:7479 +msgid "apply?" +msgstr "Anwenden?" + +#: zfuncs.cc:7536 +msgid "(new parm name)" +msgstr "(neuer Parameter-Name)" + +#: zfuncs.cc:7536 +msgid "add parameter" +msgstr "Parameter hinzufügen" + +#~ msgid "select new file" +#~ msgstr "Neue Datei wählen" + +#~ msgid "Brightness Graph" +#~ msgstr "Helligkeitsdiagramm" + +#~ msgid "Add Menu and Launcher" +#~ msgstr "Menu und Starter addieren" + +#~ msgid "Batch Resize/Export" +#~ msgstr "Dateiengrößen verändern/auslagern" + +#~ msgid "select by color" +#~ msgstr "nach Farbe selektieren" + +#~ msgid "radius" +#~ msgstr "Radius" + +#~ msgid "match" +#~ msgstr "Übereinstimmung" + +#~ msgid "Batch Resize" +#~ msgstr "Dateiengrößen verändern" + +#~ msgid "new max. height" +#~ msgstr "Neu max. Höhe" + +#~ msgid "copy EXIF" +#~ msgstr "EXIF kopieren" + +#~ msgid "new file already exists" +#~ msgstr "Datei existiert schon" + +#~ msgid "Select area first" +#~ msgstr "Zuerst Ausschnitt wählen" + +#~ msgid "Search results file error %s" +#~ msgstr "Suchergebnis-Dateifehler %s" + +#~ msgid "my mouse" +#~ msgstr "meine Maus" + +#~ msgid "both" +#~ msgstr "Beide" + +#~ msgid "icons" +#~ msgstr "Symbole" + +#~ msgid "lens name" +#~ msgstr "Lens-Name" + +#~ msgid "Lens Parameters" +#~ msgstr "Objektivparameter" + +#~ msgid "file sync is mandatory" +#~ msgstr "Synchronisierung ist nötig" + +#~ msgid "start edit function first" +#~ msgstr "Zuerst Bearbeitungsfunktion starten" diff -Nru fotoxx-11.11.1/locales/fotoxx-en.po fotoxx-12.01.2/locales/fotoxx-en.po --- fotoxx-11.11.1/locales/fotoxx-en.po 1970-01-01 00:00:00.000000000 +0000 +++ fotoxx-12.01.2/locales/fotoxx-en.po 2012-01-04 08:47:11.000000000 +0000 @@ -0,0 +1,2687 @@ +# English translations for home package. +# Copyright (C) 2011 THE home'S COPYRIGHT HOLDER +# This file is distributed under the same license as the home package. +# mico , 2011. +# +msgid "" +msgstr "" +"Project-Id-Version: home 2\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-12-31 20:58+0100\n" +"PO-Revision-Date: 2011-01-01 11:29+0100\n" +"Last-Translator: mico \n" +"Language-Team: English\n" +"Language: en\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=ASCII\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: f.art.cc:47 +msgid "Set color depth to 1-16 bits" +msgstr "Set color depth to 1-16 bits" + +#: f.art.cc:57 +msgid "Set Color Depth" +msgstr "Set Color Depth" + +#: f.art.cc:171 +msgid "Simulate Drawing" +msgstr "Simulate Drawing" + +#: f.art.cc:213 f.retouch.cc:1759 f.retouch.cc:5991 +msgid "contrast" +msgstr "contrast" + +#: f.art.cc:215 +msgid "outlines" +msgstr "outlines" + +#: f.art.cc:220 +msgid "pencil" +msgstr "pencil" + +#: f.art.cc:221 +msgid "chalk" +msgstr "chalk" + +#: f.art.cc:381 +msgid "Add Image Outlines" +msgstr "Add Image Outlines" + +#: f.art.cc:394 +msgid "outline threshold" +msgstr "outline threshold" + +#: f.art.cc:397 +msgid "outline width" +msgstr "outline width" + +#: f.art.cc:400 +msgid "image brightness" +msgstr "image brightness" + +#: f.art.cc:611 +msgid "Simulate Embossing" +msgstr "Simulate Embossing" + +#: f.art.cc:626 +msgid "depth" +msgstr "depth" + +#: f.art.cc:628 f.file.cc:919 f.retouch.cc:6692 +msgid "color" +msgstr "color" + +#: f.art.cc:821 +msgid "Simulate Tiles" +msgstr "Simulate Tiles" + +#: f.art.cc:825 +msgid "tile size" +msgstr "tile size" + +#: f.art.cc:829 +msgid "tile gap" +msgstr "tile gap" + +#: f.art.cc:1003 +msgid "Convert Image to Dots" +msgstr "Convert Image to Dots" + +#: f.art.cc:1007 +msgid "dot size" +msgstr "dot size" + +#: f.art.cc:1222 +msgid "Simulate Painting" +msgstr "Simulate Painting" + +#: f.art.cc:1226 +msgid "color depth" +msgstr "color depth" + +#: f.art.cc:1230 +msgid "patch area goal" +msgstr "patch area goal" + +#: f.art.cc:1234 +msgid "req. color match" +msgstr "req. color match" + +#: f.art.cc:1238 +msgid "borders" +msgstr "borders" + +#: f.comp.cc:1956 f.comp.cc:1961 f.comp.cc:2582 f.comp.cc:2587 f.comp.cc:3266 +#: f.comp.cc:3271 f.comp.cc:3816 f.comp.cc:3821 +msgid "Select 2 to 9 files" +msgstr "Select 2 to 9 files" + +#: f.comp.cc:1982 f.comp.cc:2608 f.comp.cc:3292 f.comp.cc:3842 +msgid "Images are not all the same size" +msgstr "Images are not all the same size" + +#: f.comp.cc:2321 +msgid "Adjust Image Contributions" +msgstr "Adjust Image Contributions" + +#: f.comp.cc:2324 f.retouch.cc:886 +msgid "dark pixels" +msgstr "dark pixels" + +#: f.comp.cc:2326 +msgid "light pixels" +msgstr "light pixels" + +#: f.comp.cc:2328 f.info.cc:159 +msgid "file:" +msgstr "file:" + +#: f.comp.cc:2843 +msgid "Paint and Warp Image" +msgstr "Paint and Warp Image" + +#: f.comp.cc:2846 f.comp.cc:3520 f.comp.cc:4959 f.comp.cc:5705 +msgid "image" +msgstr "image" + +#: f.comp.cc:2850 f.retouch.cc:6696 +msgid "paint" +msgstr "paint" + +#: f.comp.cc:2851 +msgid "warp" +msgstr "warp" + +#: f.comp.cc:3518 +msgid "Select and Paint Image" +msgstr "Select and Paint Image" + +#: f.comp.cc:4031 +msgid "Adjust Pixel Composition" +msgstr "Adjust Pixel Composition" + +#: f.comp.cc:4283 f.comp.cc:4288 f.comp.cc:5173 f.comp.cc:5178 +msgid "Select 2 to 4 files" +msgstr "Select 2 to 4 files" + +#: f.comp.cc:4361 +msgid "" +"Drag images into rough alignment.\n" +"To rotate, drag from lower edge." +msgstr "" +"Drag images into rough alignment.\n" +"To rotate, drag from lower edge." + +#: f.comp.cc:4363 +msgid "Search for lens mm and bow" +msgstr "Search for lens mm and bow" + +#: f.comp.cc:4409 f.comp.cc:5298 +msgid "Pre-align Images" +msgstr "Pre-align Images" + +#: f.comp.cc:4413 f.comp.cc:5302 +msgid "lens mm" +msgstr "lens mm" + +#: f.comp.cc:4417 f.comp.cc:5306 +msgid "lens bow" +msgstr "lens bow" + +#: f.comp.cc:4419 f.comp.cc:5308 +msgid "Resize" +msgstr "Resize" + +#: f.comp.cc:4420 f.comp.cc:5309 +msgid "resize window" +msgstr "resize window" + +#: f.comp.cc:4457 +msgid "use two images only" +msgstr "use two images only" + +#: f.comp.cc:4478 f.comp.cc:4676 f.comp.cc:4875 f.comp.cc:5357 f.comp.cc:5620 +msgid "Too little overlap, cannot align" +msgstr "Too little overlap, cannot align" + +#: f.comp.cc:4950 f.comp.cc:5696 +msgid "Match Brightness and Color" +msgstr "Match Brightness and Color" + +#: f.comp.cc:4974 f.comp.cc:5720 +msgid "auto color" +msgstr "auto color" + +#: f.comp.cc:4975 f.comp.cc:5721 +msgid "file color" +msgstr "file color" + +#: f.comp.cc:5251 +msgid "" +"Drag images into rough alignment.\n" +"To rotate, drag from right edge." +msgstr "" +"Drag images into rough alignment.\n" +"To rotate, drag from right edge." + +#: f.file.cc:169 f.file.cc:341 fotoxx-12.01.cc:189 fotoxx-12.01.cc:325 +msgid "Open Image File" +msgstr "Open Image File" + +#: f.file.cc:321 fotoxx-12.01.cc:2862 +msgid "prior function still active" +msgstr "prior function still active" + +#: f.file.cc:503 +msgid "Overwrite original file?" +msgstr "Overwrite original file?" + +#: f.file.cc:504 +msgid "Do not warn again" +msgstr "Do not warn again" + +#: f.file.cc:520 +msgid "Warning" +msgstr "Warning" + +#: f.file.cc:643 +msgid "Save File" +msgstr "Save File" + +#: f.file.cc:666 zfuncs.cc:6478 +msgid "quality" +msgstr "quality" + +#: f.file.cc:668 +msgid "make current" +msgstr "make current" + +#: f.file.cc:725 +msgid "jpeg quality must be 1-100" +msgstr "jpeg quality must be 1-100" + +#: f.file.cc:747 +#, c-format +msgid "" +"Overwrite file? \n" +" %s" +msgstr "" +"Overwrite file? \n" +" %s" + +#: f.file.cc:903 fotoxx-12.01.cc:196 +msgid "Create Blank Image" +msgstr "Create Blank Image" + +#: f.file.cc:905 +msgid "file name" +msgstr "file name" + +#: f.file.cc:910 f.transform.cc:353 +msgid "width" +msgstr "width" + +#: f.file.cc:913 f.tools.cc:477 f.transform.cc:356 +msgid "height" +msgstr "height" + +#: f.file.cc:1033 +msgid "" +"Linux standard trash is not supported. \n" +"Desktop trash folder will be created." +msgstr "" +"Linux standard trash is not supported. \n" +"Desktop trash folder will be created." + +#: f.file.cc:1051 +msgid "Move read-only file to trash?" +msgstr "Move read-only file to trash?" + +#: f.file.cc:1077 +#, c-format +msgid "Cannot create trash folder: %s" +msgstr "Cannot create trash folder: %s" + +#: f.file.cc:1085 f.file.cc:1091 zfuncs.cc:3356 +#, c-format +msgid "error: %s" +msgstr "error: %s" + +#: f.file.cc:1136 fotoxx-12.01.cc:198 +msgid "Rename Image File" +msgstr "Rename Image File" + +#: f.file.cc:1141 +msgid "old name" +msgstr "old name" + +#: f.file.cc:1142 +msgid "rename to" +msgstr "rename to" + +#: f.file.cc:1143 +msgid "previous" +msgstr "previous" + +#: f.file.cc:1229 +msgid "The target file already exists" +msgstr "The target file already exists" + +#: f.file.cc:1237 +#, c-format +msgid "" +"Rename failed: \n" +" %s" +msgstr "" +"Rename failed: \n" +" %s" + +#: f.file.cc:1285 +msgid "Batch Rename" +msgstr "Batch Rename" + +#: f.file.cc:1288 f.file.cc:1340 f.info.cc:1519 f.info.cc:1773 f.tools.cc:543 +#: f.tools.cc:2990 +#, c-format +msgid "%d files selected" +msgstr "%d files selected" + +#: f.file.cc:1290 +msgid "new base name" +msgstr "new base name" + +#: f.file.cc:1293 +msgid "starting sequence" +msgstr "starting sequence" + +#: f.file.cc:1295 +msgid "increment" +msgstr "increment" + +#: f.file.cc:1316 +msgid "select files to rename" +msgstr "select files to rename" + +#: f.file.cc:1321 +msgid "base name / sequence / increment not reasonable" +msgstr "base name / sequence / increment not reasonable" + +#: f.file.cc:1380 +msgid "new file already exists:" +msgstr "new file already exists:" + +#: f.file.cc:1388 +msgid "filespec too long:" +msgstr "filespec too long:" + +#: f.file.cc:1399 +msgid "Rename failed:" +msgstr "Rename failed:" + +#: f.file.cc:1660 fotoxx.h:729 +msgid "Add" +msgstr "Add" + +#: f.file.cc:1660 fotoxx.h:781 +msgid "Remove" +msgstr "Remove" + +#: f.file.cc:1662 +msgid "menu name" +msgstr "menu name" + +#: f.file.cc:1733 f.file.cc:1754 +msgid "Restart Fotoxx to update plugin menu" +msgstr "Restart Fotoxx to update plugin menu" + +#: f.info.cc:70 +msgid "Edit Caption and Comments" +msgstr "Edit Caption and Comments" + +#: f.info.cc:156 fotoxx-12.01.cc:225 +msgid "Edit Tags" +msgstr "Edit Tags" + +#: f.info.cc:163 +msgid "image date (yyyymmdd)" +msgstr "image date (yyyymmdd)" + +#: f.info.cc:165 +msgid "use last" +msgstr "use last" + +#: f.info.cc:168 +msgid "image stars" +msgstr "image stars" + +#: f.info.cc:186 +msgid "current tags" +msgstr "current tags" + +#: f.info.cc:191 +msgid "recent tags" +msgstr "recent tags" + +#: f.info.cc:196 f.info.cc:358 f.info.cc:1368 f.info.cc:2384 +msgid "defined tags" +msgstr "defined tags" + +#: f.info.cc:345 fotoxx-12.01.cc:226 +msgid "Manage Tags" +msgstr "Manage Tags" + +#: f.info.cc:348 +msgid "category" +msgstr "category" + +#: f.info.cc:351 +msgid "tag" +msgstr "tag" + +#: f.info.cc:354 +msgid "create" +msgstr "create" + +#: f.info.cc:355 f.navi.cc:1421 +msgid "delete" +msgstr "delete" + +#: f.info.cc:1235 f.info.cc:1319 +#, c-format +msgid "search index file error: %s" +msgstr "search index file error: %s" + +#: f.info.cc:1351 fotoxx-12.01.cc:227 +msgid "Batch Add Tags" +msgstr "Batch Add Tags" + +#: f.info.cc:1354 +msgid "tags to add" +msgstr "tags to add" + +#: f.info.cc:1359 +msgid "create tag" +msgstr "create tag" + +#: f.info.cc:1415 f.info.cc:1608 +#, c-format +msgid "" +"%s \n" +" too many tags" +msgstr "" +"%s \n" +" too many tags" + +#: f.info.cc:1553 fotoxx-12.01.cc:228 +msgid "Batch Delete Tag" +msgstr "Batch Delete Tag" + +#: f.info.cc:1556 +msgid "tag to remove" +msgstr "tag to remove" + +#: f.info.cc:1560 +msgid "optional replacement" +msgstr "optional replacement" + +#: f.info.cc:1565 f.tools.cc:2943 +msgid "0 files selected" +msgstr "0 files selected" + +#: f.info.cc:1568 +msgid "search all files" +msgstr "search all files" + +#: f.info.cc:1653 +msgid "no files selected" +msgstr "no files selected" + +#: f.info.cc:1659 +msgid "no tag specified" +msgstr "no tag specified" + +#: f.info.cc:1683 f.info.cc:1712 +msgid "specify tag" +msgstr "specify tag" + +#: f.info.cc:1821 +msgid "View Info" +msgstr "View Info" + +#: f.info.cc:1889 fotoxx-12.01.cc:231 +msgid "Edit Info" +msgstr "Edit Info" + +#: f.info.cc:1987 fotoxx-12.01.cc:232 +msgid "Delete Info" +msgstr "Delete Info" + +#: f.info.cc:1989 fotoxx.h:731 +msgid "All" +msgstr "All" + +#: f.info.cc:1990 +msgid "One Key:" +msgstr "One Key:" + +#: f.info.cc:2343 +msgid "Search Tags, Comments, File Names" +msgstr "Search Tags, Comments, File Names" + +#: f.info.cc:2350 +msgid "date range" +msgstr "date range" + +#: f.info.cc:2351 +msgid "stars range" +msgstr "stars range" + +#: f.info.cc:2352 +msgid "search tags" +msgstr "search tags" + +#: f.info.cc:2353 +msgid "search text" +msgstr "search text" + +#: f.info.cc:2354 +msgid "file names" +msgstr "file names" + +#: f.info.cc:2359 +msgid "(yyyymmdd)" +msgstr "(yyyymmdd)" + +#: f.info.cc:2365 +msgid "all/any" +msgstr "all/any" + +#: f.info.cc:2702 +msgid "No matching images found" +msgstr "No matching images found" + +#: f.info.cc:2706 f.info.cc:3059 +msgid "No search index file present" +msgstr "No search index file present" + +#: f.info.cc:2777 +msgid "Additional Items for Report" +msgstr "Additional Items for Report" + +#: f.navi.cc:188 f.navi.cc:576 f.navi.cc:706 f.navi.cc:707 f.navi.cc:709 +msgid "bigger" +msgstr "bigger" + +#: f.navi.cc:188 +msgid "increase thumbnail size" +msgstr "increase thumbnail size" + +#: f.navi.cc:189 +msgid "reduce thumbnail size" +msgstr "reduce thumbnail size" + +#: f.navi.cc:189 f.navi.cc:586 f.navi.cc:708 f.navi.cc:710 +msgid "smaller" +msgstr "smaller" + +#: f.navi.cc:190 f.navi.cc:600 +msgid "parent" +msgstr "parent" + +#: f.navi.cc:190 +msgid "parent directory" +msgstr "parent directory" + +#: f.navi.cc:191 f.navi.cc:625 f.navi.cc:717 +msgid "first page" +msgstr "first page" + +#: f.navi.cc:191 +msgid "jump to first file" +msgstr "jump to first file" + +#: f.navi.cc:192 f.navi.cc:623 f.navi.cc:712 f.navi.cc:719 +msgid "prev page" +msgstr "prev page" + +#: f.navi.cc:192 +msgid "previous page" +msgstr "previous page" + +#: f.navi.cc:193 f.navi.cc:621 f.navi.cc:714 +msgid "prev row" +msgstr "prev row" + +#: f.navi.cc:193 +msgid "previous row" +msgstr "previous row" + +#: f.navi.cc:194 f.navi.cc:622 f.navi.cc:715 +msgid "next row" +msgstr "next row" + +#: f.navi.cc:195 f.navi.cc:624 f.navi.cc:713 f.navi.cc:720 +msgid "next page" +msgstr "next page" + +#: f.navi.cc:195 +msgid "ttip::next page" +msgstr "next page" + +#: f.navi.cc:196 +msgid "jump to last file" +msgstr "jump to last file" + +#: f.navi.cc:196 f.navi.cc:626 f.navi.cc:718 +msgid "last page" +msgstr "last page" + +#: f.navi.cc:197 f.navi.cc:571 +msgid "close" +msgstr "close" + +#: f.navi.cc:197 +msgid "close image gallery" +msgstr "close image gallery" + +#: f.navi.cc:1413 fotoxx.h:787 +msgid "Select Files" +msgstr "Select Files" + +#: f.navi.cc:1413 zfuncs.cc:6296 zfuncs.cc:6332 zfuncs.cc:6485 zfuncs.cc:6728 +#: zfuncs.cc:7427 zfuncs.cc:7433 zfuncs.cc:7439 zfuncs.cc:7445 +msgid "cancel" +msgstr "cancel" + +#: f.navi.cc:1413 zfuncs.cc:6728 +msgid "done" +msgstr "done" + +#: f.navi.cc:1422 +msgid "insert" +msgstr "insert" + +#: f.navi.cc:1423 +msgid "add all" +msgstr "add all" + +#: f.retouch.cc:55 +msgid "Adjust Brightness and Color" +msgstr "Adjust Brightness and Color" + +#: f.retouch.cc:110 +msgid "small-steps" +msgstr "small-steps" + +#: f.retouch.cc:119 +msgid "color saturation" +msgstr "color saturation" + +#: f.retouch.cc:126 +msgid " reset 1 " +msgstr " reset 1 " + +#: f.retouch.cc:127 +msgid "reset all" +msgstr "reset all" + +#: f.retouch.cc:599 +msgid "adjust image gamma" +msgstr "adjust image gamma" + +#: f.retouch.cc:885 +msgid "Expand Brightness Range" +msgstr "Expand Brightness Range" + +#: f.retouch.cc:887 +msgid "bright pixels" +msgstr "bright pixels" + +#: f.retouch.cc:1058 +msgid "Flatten Brightness Distribution" +msgstr "Flatten Brightness Distribution" + +#: f.retouch.cc:1072 +msgid "Flatten" +msgstr "Flatten" + +#: f.retouch.cc:1334 +msgid "Ramp brightness across image" +msgstr "Ramp brightness across image" + +#: f.retouch.cc:1730 fotoxx-12.01.cc:272 +msgid "Tone Mapping" +msgstr "Tone Mapping" + +#: f.retouch.cc:1758 +msgid "low" +msgstr "low" + +#: f.retouch.cc:1760 +msgid "high" +msgstr "high" + +#: f.retouch.cc:1763 +msgid "Amplify" +msgstr "Amplify" + +#: f.retouch.cc:2069 +msgid "Adjust White Balance" +msgstr "Adjust White Balance" + +#: f.retouch.cc:2070 +msgid "Click white or gray image location" +msgstr "Click white or gray image location" + +#: f.retouch.cc:2278 +msgid "Color Match Images" +msgstr "Color Match Images" + +#: f.retouch.cc:2307 +msgid "mouse radius for color sample" +msgstr "mouse radius for color sample" + +#: f.retouch.cc:2309 f.retouch.cc:2314 fotoxx-12.01.cc:246 fotoxx-12.01.cc:325 +#: fotoxx.h:769 +msgid "Open" +msgstr "Open" + +#: f.retouch.cc:2310 +msgid "image for source color" +msgstr "image for source color" + +#: f.retouch.cc:2312 +msgid "click on image to get source color" +msgstr "click on image to get source color" + +#: f.retouch.cc:2315 +msgid "image to set matching color" +msgstr "image to set matching color" + +#: f.retouch.cc:2317 +msgid "click on image to set matching color" +msgstr "click on image to set matching color" + +#: f.retouch.cc:2372 +msgid "select source image color first" +msgstr "select source image color first" + +#: f.retouch.cc:2584 +msgid "Add standard bias" +msgstr "Add standard bias" + +#: f.retouch.cc:2591 +msgid "+Brightness -Density" +msgstr "+Brightness -Density" + +#: f.retouch.cc:2592 +msgid "+Red -Cyan" +msgstr "+Red -Cyan" + +#: f.retouch.cc:2593 +msgid "+Green -Magenta" +msgstr "+Green -Magenta" + +#: f.retouch.cc:2594 +msgid "+Blue -Yellow" +msgstr "+Blue -Yellow" + +#: f.retouch.cc:2599 +msgid "Contrast" +msgstr "Contrast" + +#: f.retouch.cc:2600 fotoxx.h:778 +msgid "Red" +msgstr "Red" + +#: f.retouch.cc:2601 fotoxx.h:758 +msgid "Green" +msgstr "Green" + +#: f.retouch.cc:2602 fotoxx.h:736 +msgid "Blue" +msgstr "Blue" + +#: f.retouch.cc:2730 +msgid "Load DRGB parameters" +msgstr "Load DRGB parameters" + +#: f.retouch.cc:2732 f.retouch.cc:2804 f.retouch.cc:6102 f.retouch.cc:6198 +msgid "File:" +msgstr "File:" + +#: f.retouch.cc:2751 f.retouch.cc:2824 +msgid "DRGB parameters file" +msgstr "DRGB parameters file" + +#: f.retouch.cc:2769 f.retouch.cc:6142 +msgid "file not found" +msgstr "file not found" + +#: f.retouch.cc:2802 +msgid "Save DRGB parameters" +msgstr "Save DRGB parameters" + +#: f.retouch.cc:3034 f.tools.cc:2404 +msgid "Click image to select pixels." +msgstr "Click image to select pixels." + +#: f.retouch.cc:3072 fotoxx-12.01.cc:276 +msgid "Revise RGB" +msgstr "Revise RGB" + +#: f.retouch.cc:3084 +msgid "Metric:" +msgstr "Metric:" + +#: f.retouch.cc:3139 +msgid "Blend" +msgstr "Blend" + +#: f.retouch.cc:3519 +msgid "" +"Method 1:\n" +" Left-click on red-eye to darken.\n" +"Method 2:\n" +" Drag down and right to enclose red-eye.\n" +" Left-click on red-eye to darken.\n" +"Undo red-eye:\n" +" Right-click on red-eye." +msgstr "" +"Method 1:\n" +" Left-click on red-eye to darken.\n" +"Method 2:\n" +" Drag down and right to enclose red-eye.\n" +" Left-click on red-eye to darken.\n" +"Undo red-eye:\n" +" Right-click on red-eye." + +#: f.retouch.cc:3534 +msgid "Red Eye Reduction" +msgstr "Red Eye Reduction" + +#: f.retouch.cc:3968 +msgid "Set Blur Radius" +msgstr "Set Blur Radius" + +#: f.retouch.cc:4195 fotoxx-12.01.cc:279 +msgid "Sharpen Image" +msgstr "Sharpen Image" + +#: f.retouch.cc:4202 +msgid "edge detection" +msgstr "edge detection" + +#: f.retouch.cc:4203 +msgid "cycles" +msgstr "cycles" + +#: f.retouch.cc:4204 +msgid "reduce" +msgstr "reduce" + +#: f.retouch.cc:4215 +msgid "unsharp mask" +msgstr "unsharp mask" + +#: f.retouch.cc:4228 +msgid "brightness gradient" +msgstr "brightness gradient" + +#: f.retouch.cc:4634 +msgid "" +" Press the reduce button to \n" +" reduce noise in small steps. \n" +" Use undo to start over." +msgstr "" +" Press the reduce button to \n" +" reduce noise in small steps. \n" +" Use undo to start over." + +#: f.retouch.cc:4645 +msgid "Noise Reduction" +msgstr "Noise Reduction" + +#: f.retouch.cc:4650 +msgid "algorithm" +msgstr "algorithm" + +#: f.retouch.cc:4657 +msgid "flatten outliers by color (1)" +msgstr "flatten outliers by color (1)" + +#: f.retouch.cc:4658 +msgid "flatten outliers by color (2)" +msgstr "flatten outliers by color (2)" + +#: f.retouch.cc:4659 +msgid "set median brightness by color" +msgstr "set median brightness by color" + +#: f.retouch.cc:4660 f.retouch.cc:4661 +msgid "top hat filter by color" +msgstr "top hat filter by color" + +#: f.retouch.cc:4976 +msgid "" +"1. Drag mouse to select. \n" +"2. Erase. 3. Repeat. " +msgstr "" +"1. Drag mouse to select. \n" +"2. Erase. 3. Repeat. " + +#: f.retouch.cc:4998 fotoxx-12.01.cc:281 +msgid "Smart Erase" +msgstr "Smart Erase" + +#: f.retouch.cc:5003 fotoxx.h:776 +msgid "Radius" +msgstr "Radius" + +#: f.retouch.cc:5005 +msgid "Blur" +msgstr "Blur" + +#: f.retouch.cc:5008 +msgid "New Area" +msgstr "New Area" + +#: f.retouch.cc:5379 fotoxx-12.01.cc:282 +msgid "Remove Dust" +msgstr "Remove Dust" + +#: f.retouch.cc:5383 +msgid "spot size limit" +msgstr "spot size limit" + +#: f.retouch.cc:5386 +msgid "max. brightness" +msgstr "max. brightness" + +#: f.retouch.cc:5389 +msgid "min. contrast" +msgstr "min. contrast" + +#: f.retouch.cc:5983 fotoxx-12.01.cc:283 +msgid "Fix Stuck Pixels" +msgstr "Fix Stuck Pixels" + +#: f.retouch.cc:5989 +msgid "pixel group" +msgstr "pixel group" + +#: f.retouch.cc:5990 +msgid "circle color" +msgstr "circle color" + +#: f.retouch.cc:6100 +msgid "Load Stuck Pixels" +msgstr "Load Stuck Pixels" + +#: f.retouch.cc:6124 f.retouch.cc:6220 +msgid "Stuck Pixels file" +msgstr "Stuck Pixels file" + +#: f.retouch.cc:6164 +msgid "file format error" +msgstr "file format error" + +#: f.retouch.cc:6192 +msgid "there are zero stuck pixels" +msgstr "there are zero stuck pixels" + +#: f.retouch.cc:6196 +msgid "Save Stuck Pixels" +msgstr "Save Stuck Pixels" + +#: f.retouch.cc:6686 +#, c-format +msgid "Undo Memory %d%c" +msgstr "Undo Memory %d%c" + +#: f.retouch.cc:6688 fotoxx-12.01.cc:284 +msgid "Edit Pixels" +msgstr "Edit Pixels" + +#: f.retouch.cc:6695 +msgid "pick" +msgstr "pick" + +#: f.retouch.cc:6697 +msgid "erase" +msgstr "erase" + +#: f.retouch.cc:6705 +msgid "paintbrush radius" +msgstr "paintbrush radius" + +#: f.retouch.cc:6706 +msgid "transparency center" +msgstr "transparency center" + +#: f.retouch.cc:6707 +msgid "transparency edge" +msgstr "transparency edge" + +#: f.retouch.cc:6972 +msgid "" +"Undo memory limit has been reached. \n" +"Save work with [done], then resume editing." +msgstr "" +"Undo memory limit has been reached. \n" +"Save work with [done], then resume editing." + +#: f.select.cc:54 f.select.cc:2461 +msgid "Select Area for Edits" +msgstr "Select Area for Edits" + +#: f.select.cc:55 f.select.cc:2462 +msgid "Press F1 for help" +msgstr "Press F1 for help" + +#: f.select.cc:64 +msgid "" +"Select Area not supported \n" +"by this edit function" +msgstr "" +"Select Area not supported \n" +"by this edit function" + +#: f.select.cc:103 f.tools.cc:901 +msgid "rectangle" +msgstr "rectangle" + +#: f.select.cc:104 f.tools.cc:902 +msgid "ellipse" +msgstr "ellipse" + +#: f.select.cc:110 +msgid "draw: freehand" +msgstr "draw: freehand" + +#: f.select.cc:111 +msgid "draw: follow edge" +msgstr "draw: follow edge" + +#: f.select.cc:114 +msgid "select by mouse" +msgstr "select by mouse" + +#: f.select.cc:116 f.select.cc:2496 +msgid "mouse radius" +msgstr "mouse radius" + +#: f.select.cc:120 +msgid "match mouse color" +msgstr "match mouse color" + +#: f.select.cc:124 +msgid "search range" +msgstr "search range" + +#: f.select.cc:126 +msgid "firewall" +msgstr "firewall" + +#: f.select.cc:326 f.select.cc:467 +#, c-format +msgid "exceed %d edits" +msgstr "exceed %d edits" + +#: f.select.cc:1021 +msgid "" +"Click one time inside each enclosed area \n" +"(possible gaps in the outline will be found). \n" +"Press F1 for help." +msgstr "" +"Click one time inside each enclosed area \n" +"(possible gaps in the outline will be found). \n" +"Press F1 for help." + +#: f.select.cc:1078 +msgid "finish area" +msgstr "finish area" + +#: f.select.cc:1113 +msgid "searching" +msgstr "searching" + +#: f.select.cc:1185 +msgid "outline has a gap" +msgstr "outline has a gap" + +#: f.select.cc:1189 +msgid "success" +msgstr "success" + +#: f.select.cc:1440 f.select.cc:1470 +msgid "the area is not finished" +msgstr "the area is not finished" + +#: f.select.cc:1563 +msgid "Edge calculation in progress" +msgstr "Edge calculation in progress" + +#: f.select.cc:1572 +msgid "Area Edge Calc" +msgstr "Area Edge Calc" + +#: f.select.cc:1863 +msgid "position with mouse click/drag" +msgstr "position with mouse click/drag" + +#: f.select.cc:1887 +msgid "Paste Image" +msgstr "Paste Image" + +#: f.select.cc:1901 +msgid "angle" +msgstr "angle" + +#: f.select.cc:2160 +msgid "load select area from a file" +msgstr "load select area from a file" + +#: f.select.cc:2194 +msgid "cannot open .tiff and .info files" +msgstr "cannot open .tiff and .info files" + +#: f.select.cc:2213 +msgid "save select area to a file" +msgstr "save select area to a file" + +#: f.select.cc:2248 fotoxx-12.01.cc:248 +msgid "Select Whole Image" +msgstr "Select Whole Image" + +#: f.select.cc:2249 +msgid "Edit Function Amplifier" +msgstr "Edit Function Amplifier" + +#: f.select.cc:2463 +msgid "Edit function must be active" +msgstr "Edit function must be active" + +#: f.select.cc:2499 +msgid "power: center" +msgstr "power: center" + +#: f.select.cc:2501 +msgid "edge" +msgstr "edge" + +#: f.select.cc:2504 +msgid "reset area" +msgstr "reset area" + +#: f.tools.cc:42 +msgid "" +"When editing a collection, right-click \n" +"an image or thumbnail to add or remove." +msgstr "" +"When editing a collection, right-click \n" +"an image or thumbnail to add or remove." + +#: f.tools.cc:70 fotoxx-12.01.cc:204 +msgid "Manage Collections" +msgstr "Manage Collections" + +#: f.tools.cc:85 +msgid "Start new collection" +msgstr "Start new collection" + +#: f.tools.cc:87 +msgid "Edit a collection" +msgstr "Edit a collection" + +#: f.tools.cc:89 +msgid "View a collection" +msgstr "View a collection" + +#: f.tools.cc:91 +msgid "Delete a collection" +msgstr "Delete a collection" + +#: f.tools.cc:95 +msgid "Editing:" +msgstr "Editing:" + +#: f.tools.cc:99 +msgid "Action:" +msgstr "Action:" + +#: f.tools.cc:133 +msgid "New Collection" +msgstr "New Collection" + +#: f.tools.cc:156 +msgid "Edit Collection" +msgstr "Edit Collection" + +#: f.tools.cc:172 +msgid "View Collection" +msgstr "View Collection" + +#: f.tools.cc:193 +msgid "Delete Collection" +msgstr "Delete Collection" + +#: f.tools.cc:196 +#, c-format +msgid "delete %s ?" +msgstr "delete %s ?" + +#: f.tools.cc:223 +#, c-format +msgid "add image to collection: %s" +msgstr "add image to collection: %s" + +#: f.tools.cc:225 f.tools.cc:270 +msgid "remove image from collection" +msgstr "remove image from collection" + +#: f.tools.cc:226 f.tools.cc:271 f.tools.cc:298 +msgid "remove and save image" +msgstr "remove and save image" + +#: f.tools.cc:227 f.tools.cc:316 +msgid "insert saved images here" +msgstr "insert saved images here" + +#: f.tools.cc:256 +msgid "add image to collection" +msgstr "add image to collection" + +#: f.tools.cc:301 +msgid "too many saved files" +msgstr "too many saved files" + +#: f.tools.cc:373 fotoxx-12.01.cc:205 +msgid "Move Collections" +msgstr "Move Collections" + +#: f.tools.cc:375 +msgid "old top directory" +msgstr "old top directory" + +#: f.tools.cc:378 +msgid "new top directory" +msgstr "new top directory" + +#: f.tools.cc:434 +msgid "completed" +msgstr "completed" + +#: f.tools.cc:467 +msgid "Batch Convert/Resize/Export" +msgstr "Batch Convert/Resize/Export" + +#: f.tools.cc:474 +msgid "new max. width" +msgstr "new max. width" + +#: f.tools.cc:481 +msgid "new file type" +msgstr "new file type" + +#: f.tools.cc:482 +msgid "same" +msgstr "same" + +#: f.tools.cc:490 +msgid "replace originals" +msgstr "replace originals" + +#: f.tools.cc:491 +msgid "export to location" +msgstr "export to location" + +#: f.tools.cc:492 +msgid "remove EXIF" +msgstr "remove EXIF" + +#: f.tools.cc:549 +msgid "Select directory" +msgstr "Select directory" + +#: f.tools.cc:583 +#, c-format +msgid "replace original files? (max. %d x %d)" +msgstr "replace original files? (max. %d x %d)" + +#: f.tools.cc:590 +#, c-format +msgid "" +"copy files? (max. %d x %d) \n" +" to location %s" +msgstr "" +"copy files? (max. %d x %d) \n" +" to location %s" + +#: f.tools.cc:601 +msgid "location is not a valid directory" +msgstr "location is not a valid directory" + +#: f.tools.cc:608 f.tools.cc:3007 +#, c-format +msgid "max. size %d x %d is not reasonable" +msgstr "max. size %d x %d is not reasonable" + +#: f.tools.cc:654 +msgid "*** file already exists" +msgstr "*** file already exists" + +#: f.tools.cc:662 +msgid "*** file type not supported" +msgstr "*** file type not supported" + +#: f.tools.cc:741 +msgid "Program ufraw-batch is required" +msgstr "Program ufraw-batch is required" + +#: f.tools.cc:751 fotoxx.h:770 +msgid "Open RAW File" +msgstr "Open RAW File" + +#: f.tools.cc:764 +msgid "Select RAW files to convert" +msgstr "Select RAW files to convert" + +#: f.tools.cc:769 +msgid "Choose file type" +msgstr "Choose file type" + +#: f.tools.cc:888 +msgid "Press ESC to exit slide show" +msgstr "Press ESC to exit slide show" + +#: f.tools.cc:889 +msgid "show only latest file versions" +msgstr "show only latest file versions" + +#: f.tools.cc:893 +msgid "arrow keys" +msgstr "arrow keys" + +#: f.tools.cc:894 +msgid "instant" +msgstr "instant" + +#: f.tools.cc:895 +msgid "fade-in" +msgstr "fade-in" + +#: f.tools.cc:896 +msgid "roll-right" +msgstr "roll-right" + +#: f.tools.cc:897 +msgid "roll-down" +msgstr "roll-down" + +#: f.tools.cc:898 +msgid "shift-left" +msgstr "shift-left" + +#: f.tools.cc:899 +msgid "venetian" +msgstr "venetian" + +#: f.tools.cc:900 +msgid "grate" +msgstr "grate" + +#: f.tools.cc:903 +msgid "radar" +msgstr "radar" + +#: f.tools.cc:904 +msgid "jaws" +msgstr "jaws" + +#: f.tools.cc:911 fotoxx-12.01.cc:208 +msgid "Slide Show" +msgstr "Slide Show" + +#: f.tools.cc:915 +msgid "seconds" +msgstr "seconds" + +#: f.tools.cc:919 +msgid "music file" +msgstr "music file" + +#: f.tools.cc:923 +msgid "transitions" +msgstr "transitions" + +#: f.tools.cc:1040 +msgid "Select music file or playlist" +msgstr "Select music file or playlist" + +#: f.tools.cc:1727 +msgid "Sync Files is already running" +msgstr "Sync Files is already running" + +#: f.tools.cc:1778 +msgid "" +"Run Tools > Synchronize Files so that gallery windows \n" +"will be fast and Search Images will work correctly. \n" +"You can view (not edit) images while synchronize runs." +msgstr "" +"Run Tools > Synchronize Files so that gallery windows \n" +"will be fast and Search Images will work correctly. \n" +"You can view (not edit) images while synchronize runs." + +#: f.tools.cc:1812 +msgid "no top image directory is defined" +msgstr "no top image directory is defined" + +#: f.tools.cc:1818 +msgid "top image directory is invalid" +msgstr "top image directory is invalid" + +#: f.tools.cc:1823 +msgid "no search index file is present" +msgstr "no search index file is present" + +#: f.tools.cc:1837 +msgid "new/modified files are present" +msgstr "new/modified files are present" + +#: f.tools.cc:1844 +msgid "no new files found" +msgstr "no new files found" + +#: f.tools.cc:1859 fotoxx-12.01.cc:209 +msgid "Synchronize Files" +msgstr "Synchronize Files" + +#: f.tools.cc:1861 +msgid "Top Image Directory:" +msgstr "Top Image Directory:" + +#: f.tools.cc:1883 +msgid "" +"file sync is necessary.\n" +"cancel anyway?" +msgstr +"file sync is necessary.\n" +"cancel anyway?" + +#: f.tools.cc:1896 +msgid "top directory is invalid" +msgstr "top directory is invalid" + +#: f.tools.cc:2292 +msgid "Select top image directory" +msgstr "Select top image directory" + +#: f.tools.cc:2429 fotoxx-12.01.cc:210 +msgid "Show RGB" +msgstr "Show RGB" + +#: f.tools.cc:2719 fotoxx-12.01.cc:211 +msgid "Grid Lines" +msgstr "Grid Lines" + +#: f.tools.cc:2728 +msgid "x-spacing" +msgstr "x-spacing" + +#: f.tools.cc:2729 +msgid "x-count" +msgstr "x-count" + +#: f.tools.cc:2730 +msgid "x-enable" +msgstr "x-enable" + +#: f.tools.cc:2736 +msgid "y-spacing" +msgstr "y-spacing" + +#: f.tools.cc:2737 +msgid "y-count" +msgstr "y-count" + +#: f.tools.cc:2738 +msgid "y-enable" +msgstr "y-enable" + +#: f.tools.cc:2745 +msgid "x-offset" +msgstr "x-offset" + +#: f.tools.cc:2749 +msgid "y-offset" +msgstr "y-offset" + +#: f.tools.cc:2940 fotoxx-12.01.cc:213 +msgid "E-mail Images" +msgstr "E-mail Images" + +#: f.tools.cc:2947 +msgid "max. width" +msgstr "max. width" + +#: f.tools.cc:2948 +msgid "max. height" +msgstr "max. height" + +#: f.tools.cc:3093 +msgid "too many files" +msgstr "too many files" + +#: f.tools.cc:3134 +msgid "" +"Brightness should show a gradual ramp \n" +"extending all the way to the edges." +msgstr "" +"Brightness should show a gradual ramp \n" +"extending all the way to the edges." + +#: f.tools.cc:3174 +msgid "Monitor Check" +msgstr "Monitor Check" + +#: f.tools.cc:3232 fotoxx-12.01.cc:215 +msgid "Monitor Gamma" +msgstr "Monitor Gamma" + +#: f.tools.cc:3294 fotoxx-12.01.cc:216 +msgid "Brightness Distribution" +msgstr "Brightness Distribution" + +#: f.tools.cc:3432 +msgid "Available Translations" +msgstr "Available Translations" + +#: f.tools.cc:3436 +msgid "Set Language" +msgstr "Set Language" + +#: f.tools.cc:3502 +msgid "Make Launcher" +msgstr "Make Launcher" + +#: f.tools.cc:3540 +msgid "Settings" +msgstr "Settings" + +#: f.tools.cc:3545 +msgid "Startup Display" +msgstr "Startup Display" + +#: f.tools.cc:3547 +msgid "Recent Files Gallery" +msgstr "Recent Files Gallery" + +#: f.tools.cc:3548 +msgid "Previous Image Viewed" +msgstr "Previous Image Viewed" + +#: f.tools.cc:3549 +msgid "Blank Window" +msgstr "Blank Window" + +#: f.tools.cc:3551 +msgid "Directory Gallery" +msgstr "Directory Gallery" + +#: f.tools.cc:3556 +msgid "Image File" +msgstr "Image File" + +#: f.tools.cc:3562 +msgid "Toolbar Style" +msgstr "Toolbar Style" + +#: f.tools.cc:3563 f.transform.cc:1300 +msgid "Text" +msgstr "Text" + +#: f.tools.cc:3564 +msgid "Icons" +msgstr "Icons" + +#: f.tools.cc:3565 +msgid "Both" +msgstr "Both" + +#: f.tools.cc:3568 +msgid "Warn Overwrite" +msgstr "Warn Overwrite" + +#: f.tools.cc:3639 +msgid "startup directory is invalid" +msgstr "startup directory is invalid" + +#: f.tools.cc:3650 +msgid "startup file is invalid" +msgstr "startup file is invalid" + +#: f.tools.cc:3707 +msgid "Select startup directory" +msgstr "Select startup directory" + +#: f.tools.cc:3715 +msgid "Select startup image file" +msgstr "Select startup image file" + +#: f.transform.cc:50 +msgid "Use buttons or drag right edge with mouse" +msgstr "Use buttons or drag right edge with mouse" + +#: f.transform.cc:60 fotoxx-12.01.cc:252 +msgid "Rotate Image" +msgstr "Rotate Image" + +#: f.transform.cc:64 +msgid "degrees" +msgstr "degrees" + +#: f.transform.cc:80 f.transform.cc:124 +msgid "Trim" +msgstr "Trim" + +#: f.transform.cc:81 f.transform.cc:2289 f.transform.cc:3120 +#: f.transform.cc:3383 f.transform.cc:3644 +msgid "Grid" +msgstr "Grid" + +#: f.transform.cc:123 +msgid "Undo Trim" +msgstr "Undo Trim" + +#: f.transform.cc:139 +#, c-format +msgid "degrees: %.1f" +msgstr "degrees: %.1f" + +#: f.transform.cc:286 +msgid "gold" +msgstr "gold" + +#: f.transform.cc:334 +msgid "Drag middle to move, drag corners to resize." +msgstr "Drag middle to move, drag corners to resize." + +#: f.transform.cc:348 fotoxx-12.01.cc:253 +msgid "Trim Image" +msgstr "Trim Image" + +#: f.transform.cc:348 +msgid "customize" +msgstr "customize" + +#: f.transform.cc:359 +msgid "ratio" +msgstr "ratio" + +#: f.transform.cc:363 +msgid "Lock Ratio" +msgstr "Lock Ratio" + +#: f.transform.cc:368 +msgid "invert" +msgstr "invert" + +#: f.transform.cc:890 +msgid "Trim Buttons" +msgstr "Trim Buttons" + +#: f.transform.cc:1064 +msgid "Lock aspect ratio" +msgstr "Lock aspect ratio" + +#: f.transform.cc:1072 fotoxx-12.01.cc:255 +msgid "Resize Image" +msgstr "Resize Image" + +#: f.transform.cc:1095 fotoxx-12.01.cc:326 +msgid "Prev" +msgstr "Prev" + +#: f.transform.cc:1245 +msgid "" +"Enter text, click/drag on image.\n" +"Right click to remove" +msgstr "" +"Enter text, click/drag on image.\n" +"Right click to remove" + +#: f.transform.cc:1294 fotoxx-12.01.cc:256 +msgid "Annotate Image" +msgstr "Annotate Image" + +#: f.transform.cc:1307 +msgid "Size" +msgstr "Size" + +#: f.transform.cc:1310 +msgid "Angle" +msgstr "Angle" + +#: f.transform.cc:1321 fotoxx.h:741 +msgid "Color" +msgstr "Color" + +#: f.transform.cc:1322 +msgid "Transparency" +msgstr "Transparency" + +#: f.transform.cc:1325 +msgid "text" +msgstr "text" + +#: f.transform.cc:1330 +msgid "backing" +msgstr "backing" + +#: f.transform.cc:1333 +msgid "" +"Outline\n" +" Width" +msgstr "" +"Outline\n" +" Width" + +#: f.transform.cc:1335 +msgid "outline" +msgstr "outline" + +#: f.transform.cc:1342 +msgid "Annotation File:" +msgstr "Annotation File:" + +#: f.transform.cc:1416 +msgid "select font" +msgstr "select font" + +#: f.transform.cc:2045 fotoxx-12.01.cc:257 +msgid "Flip Image" +msgstr "Flip Image" + +#: f.transform.cc:2049 f.transform.cc:2281 +msgid "horizontal" +msgstr "horizontal" + +#: f.transform.cc:2050 f.transform.cc:2280 +msgid "vertical" +msgstr "vertical" + +#: f.transform.cc:2155 fotoxx-12.01.cc:258 +msgid "Make Negative" +msgstr "Make Negative" + +#: f.transform.cc:2158 +msgid "black/white positive" +msgstr "black/white positive" + +#: f.transform.cc:2159 +msgid "black/white negative" +msgstr "black/white negative" + +#: f.transform.cc:2160 +msgid "color positive" +msgstr "color positive" + +#: f.transform.cc:2161 +msgid "color negative" +msgstr "color negative" + +#: f.transform.cc:2272 fotoxx-12.01.cc:259 +msgid "Unbend Image" +msgstr "Unbend Image" + +#: f.transform.cc:2282 +msgid "linear" +msgstr "linear" + +#: f.transform.cc:2285 +msgid "curved" +msgstr "curved" + +#: f.transform.cc:2544 +msgid "" +" Click the four corners of a tetragon area. Press [apply]. \n" +" The image is warped to make the tetragon into a rectangle." +msgstr "" +" Click the four corners of a tetragon area. Press [apply]. \n" +" The image is warped to make the tetragon into a rectangle." + +#: f.transform.cc:2556 fotoxx-12.01.cc:260 +msgid "Keystone Correction" +msgstr "Keystone Correction" + +#: f.transform.cc:2724 +msgid "must have 4 corners" +msgstr "must have 4 corners" + +#: f.transform.cc:2847 +msgid "" +" Select an area to warp using select area function. \n" +" Press [start warp] and pull area with mouse. \n" +" Make multiple mouse pulls until satisfied. \n" +" When finished, select another area or press [done]." +msgstr "" +" Select an area to warp using select area function. \n" +" Press [start warp] and pull area with mouse. \n" +" Make multiple mouse pulls until satisfied. \n" +" When finished, select another area or press [done]." + +#: f.transform.cc:2859 fotoxx-12.01.cc:261 +msgid "Warp Image (area)" +msgstr "Warp Image (area)" + +#: f.transform.cc:2864 +msgid "start warp" +msgstr "start warp" + +#: f.transform.cc:2931 +msgid "no active Select Area" +msgstr "no active Select Area" + +#: f.transform.cc:3099 f.transform.cc:3362 +msgid "" +" Pull an image position using the mouse. \n" +" Make multiple mouse pulls until satisfied. \n" +" When finished, press [done]." +msgstr "" +" Pull an image position using the mouse. \n" +" Make multiple mouse pulls until satisfied. \n" +" When finished, press [done]." + +#: f.transform.cc:3112 fotoxx-12.01.cc:262 +msgid "Warp Image (curved)" +msgstr "Warp Image (curved)" + +#: f.transform.cc:3375 fotoxx-12.01.cc:263 +msgid "Warp Image (linear)" +msgstr "Warp Image (linear)" + +#: f.transform.cc:3628 +msgid "" +" Pull on an image corner using the mouse. \n" +" Make multiple mouse pulls until satisfied. \n" +" When finished, press [done]." +msgstr "" +" Pull on an image corner using the mouse. \n" +" Make multiple mouse pulls until satisfied. \n" +" When finished, press [done]." + +#: f.transform.cc:3639 fotoxx-12.01.cc:264 +msgid "Warp Image (affine)" +msgstr "Warp Image (affine)" + +#: fotoxx-12.01.cc:185 +msgid "File" +msgstr "File" + +#: fotoxx-12.01.cc:186 fotoxx-12.01.cc:324 +msgid "Image Gallery" +msgstr "Image Gallery" + +#: fotoxx-12.01.cc:187 +msgid "Clone 50/50" +msgstr "Clone 50/50" + +#: fotoxx-12.01.cc:188 +msgid "Clone Overlay" +msgstr "Clone Overlay" + +#: fotoxx-12.01.cc:190 +msgid "Open in New Window" +msgstr "Open in New Window" + +#: fotoxx-12.01.cc:191 fotoxx-12.01.cc:326 +msgid "Open Previous File" +msgstr "Open Previous File" + +#: fotoxx-12.01.cc:192 +msgid "Open Recent File" +msgstr "Open Recent File" + +#: fotoxx-12.01.cc:193 fotoxx-12.01.cc:334 +msgid "Save to Same File" +msgstr "Save to Same File" + +#: fotoxx-12.01.cc:194 fotoxx-12.01.cc:335 +msgid "Save to New Version" +msgstr "Save to New Version" + +#: fotoxx-12.01.cc:195 fotoxx-12.01.cc:336 +msgid "Save to New File" +msgstr "Save to New File" + +#: fotoxx-12.01.cc:197 +msgid "Trash Image File" +msgstr "Trash Image File" + +#: fotoxx-12.01.cc:199 +msgid "Batch Rename Files" +msgstr "Batch Rename Files" + +#: fotoxx-12.01.cc:200 +msgid "Print Image File" +msgstr "Print Image File" + +#: fotoxx-12.01.cc:201 fotoxx-12.01.cc:340 +msgid "Quit fotoxx" +msgstr "Quit fotoxx" + +#: fotoxx-12.01.cc:203 +msgid "Tools" +msgstr "Tools" + +#: fotoxx-12.01.cc:206 +msgid "Batch Convert" +msgstr "Batch Convert" + +#: fotoxx-12.01.cc:207 +msgid "Convert RAW files" +msgstr "Convert RAW files" + +#: fotoxx-12.01.cc:212 +msgid "Burn Images to CD/DVD" +msgstr "Burn Images to CD/DVD" + +#: fotoxx-12.01.cc:214 +msgid "Check Monitor" +msgstr "Check Monitor" + +#: fotoxx-12.01.cc:217 +msgid "Change Language" +msgstr "Change Language" + +#: fotoxx-12.01.cc:219 +msgid "Menu and Launcher" +msgstr "Menu and Launcher" + +#: fotoxx-12.01.cc:220 +msgid "User Settings" +msgstr "User Settings" + +#: fotoxx-12.01.cc:221 +msgid "Memory Usage" +msgstr "Memory Usage" + +#: fotoxx-12.01.cc:224 +msgid "Edit Caption/Comments" +msgstr "Edit Caption/Comments" + +#: fotoxx-12.01.cc:229 +msgid "View Info (short)" +msgstr "View Info (short)" + +#: fotoxx-12.01.cc:230 +msgid "View Info (long)" +msgstr "View Info (long)" + +#: fotoxx-12.01.cc:233 +msgid "Search Images" +msgstr "Search Images" + +#: fotoxx-12.01.cc:234 +msgid "Search Metadata" +msgstr "Search Metadata" + +#: fotoxx-12.01.cc:236 fotoxx-12.01.cc:237 fotoxx.h:786 +msgid "Select" +msgstr "Select" + +#: fotoxx-12.01.cc:238 fotoxx.h:788 +msgid "Show" +msgstr "Show" + +#: fotoxx-12.01.cc:239 fotoxx.h:761 +msgid "Hide" +msgstr "Hide" + +#: fotoxx-12.01.cc:240 fotoxx.h:752 +msgid "Enable" +msgstr "Enable" + +#: fotoxx-12.01.cc:241 fotoxx.h:748 +msgid "Disable" +msgstr "Disable" + +#: fotoxx-12.01.cc:242 fotoxx.h:763 +msgid "Invert" +msgstr "Invert" + +#: fotoxx-12.01.cc:243 fotoxx.h:796 +msgid "Unselect" +msgstr "Unselect" + +#: fotoxx-12.01.cc:244 fotoxx.h:743 +msgid "Copy" +msgstr "Copy" + +#: fotoxx-12.01.cc:245 fotoxx.h:771 +msgid "Paste" +msgstr "Paste" + +#: fotoxx-12.01.cc:247 fotoxx-12.01.cc:334 fotoxx.h:783 +msgid "Save" +msgstr "Save" + +#: fotoxx-12.01.cc:249 +msgid "Select and Edit" +msgstr "Select and Edit" + +#: fotoxx-12.01.cc:251 +msgid "Transform" +msgstr "Transform" + +#: fotoxx-12.01.cc:254 +msgid "Auto-Trim Image" +msgstr "Auto-Trim Image" + +#: fotoxx-12.01.cc:266 +msgid "Retouch" +msgstr "Retouch" + +#: fotoxx-12.01.cc:267 +msgid "Brightness/Color" +msgstr "Brightness/Color" + +#: fotoxx-12.01.cc:268 +msgid "Gamma Curves" +msgstr "Gamma Curves" + +#: fotoxx-12.01.cc:269 +msgid "Expand Brightness" +msgstr "Expand Brightness" + +#: fotoxx-12.01.cc:270 +msgid "Flatten Brightness" +msgstr "Flatten Brightness" + +#: fotoxx-12.01.cc:271 +msgid "Brightness Ramp" +msgstr "Brightness Ramp" + +#: fotoxx-12.01.cc:273 +msgid "White Balance" +msgstr "White Balance" + +#: fotoxx-12.01.cc:274 +msgid "Match Colors" +msgstr "Match Colors" + +#: fotoxx-12.01.cc:277 +msgid "Red Eyes" +msgstr "Red Eyes" + +#: fotoxx-12.01.cc:278 +msgid "Blur Image" +msgstr "Blur Image" + +#: fotoxx-12.01.cc:280 +msgid "Reduce Noise" +msgstr "Reduce Noise" + +#: fotoxx-12.01.cc:286 +msgid "Art" +msgstr "Art" + +#: fotoxx-12.01.cc:287 +msgid "Color Depth" +msgstr "Color Depth" + +#: fotoxx-12.01.cc:288 +msgid "Drawing" +msgstr "Drawing" + +#: fotoxx-12.01.cc:289 +msgid "Outlines" +msgstr "Outlines" + +#: fotoxx-12.01.cc:290 +msgid "Embossing" +msgstr "Embossing" + +#: fotoxx-12.01.cc:291 +msgid "Tiles" +msgstr "Tiles" + +#: fotoxx-12.01.cc:292 +msgid "Dots" +msgstr "Dots" + +#: fotoxx-12.01.cc:293 +msgid "Painting" +msgstr "Painting" + +#: fotoxx-12.01.cc:295 +msgid "Combine" +msgstr "Combine" + +#: fotoxx-12.01.cc:296 +msgid "High Dynamic Range" +msgstr "High Dynamic Range" + +#: fotoxx-12.01.cc:297 +msgid "High Depth of Field" +msgstr "High Depth of Field" + +#: fotoxx-12.01.cc:298 +msgid "Stack / Paint" +msgstr "Stack / Paint" + +#: fotoxx-12.01.cc:299 +msgid "Stack / Noise" +msgstr "Stack / Noise" + +#: fotoxx-12.01.cc:300 +msgid "Panorama" +msgstr "Panorama" + +#: fotoxx-12.01.cc:301 +msgid "Vertical Panorama" +msgstr "Vertical Panorama" + +#: fotoxx-12.01.cc:304 +msgid "Edit Plugins" +msgstr "Edit Plugins" + +#: fotoxx-12.01.cc:313 fotoxx-12.01.cc:341 fotoxx-12.01.cc:3026 +msgid "Help" +msgstr "Help" + +#: fotoxx-12.01.cc:314 fotoxx-12.01.cc:3016 +msgid "About" +msgstr "About" + +#: fotoxx-12.01.cc:315 fotoxx-12.01.cc:3020 +msgid "User Guide" +msgstr "User Guide" + +#: fotoxx-12.01.cc:316 fotoxx-12.01.cc:3023 +msgid "User Guide Changes" +msgstr "User Guide Changes" + +#: fotoxx-12.01.cc:317 fotoxx-12.01.cc:3032 +msgid "Edit Functions Summary" +msgstr "Edit Functions Summary" + +#: fotoxx-12.01.cc:318 fotoxx-12.01.cc:3035 +msgid "Change Log" +msgstr "Change Log" + +#: fotoxx-12.01.cc:319 fotoxx-12.01.cc:3038 +msgid "Translations" +msgstr "Translations" + +#: fotoxx-12.01.cc:320 fotoxx-12.01.cc:3041 +msgid "Home Page" +msgstr "Home Page" + +#: fotoxx-12.01.cc:324 +msgid "Gallery" +msgstr "Gallery" + +#: fotoxx-12.01.cc:327 fotoxx.h:767 +msgid "Next" +msgstr "Next" + +#: fotoxx-12.01.cc:327 +msgid "Open Next File" +msgstr "Open Next File" + +#: fotoxx-12.01.cc:328 +msgid "Zoom-in (bigger)" +msgstr "Zoom-in (bigger)" + +#: fotoxx-12.01.cc:329 +msgid "Zoom-out (smaller)" +msgstr "Zoom-out (smaller)" + +#: fotoxx-12.01.cc:330 fotoxx.h:794 +msgid "Undo" +msgstr "Undo" + +#: fotoxx-12.01.cc:330 +msgid "Undo One Edit" +msgstr "Undo One Edit" + +#: fotoxx-12.01.cc:331 fotoxx.h:779 +msgid "Redo" +msgstr "Redo" + +#: fotoxx-12.01.cc:331 +msgid "Redo One Edit" +msgstr "Redo One Edit" + +#: fotoxx-12.01.cc:335 +msgid "Save+V" +msgstr "Save+V" + +#: fotoxx-12.01.cc:336 +msgid "Save+F" +msgstr "Save+F" + +#: fotoxx-12.01.cc:337 +msgid "Move Image to Trash" +msgstr "Move Image to Trash" + +#: fotoxx-12.01.cc:337 +msgid "Trash" +msgstr "Trash" + +#: fotoxx-12.01.cc:340 +msgid "Quit" +msgstr "Quit" + +#: fotoxx-12.01.cc:341 +msgid "Fotoxx Essentials" +msgstr "Fotoxx Essentials" + +#: fotoxx-12.01.cc:448 +msgid "first time startup" +msgstr "first time startup" + +#: fotoxx-12.01.cc:1944 +msgid "Exceed 50 anchor points" +msgstr "Exceed 50 anchor points" + +#: fotoxx-12.01.cc:2129 +msgid "load curve from a file" +msgstr "load curve from a file" + +#: fotoxx-12.01.cc:2182 +msgid "curve file is invalid" +msgstr "curve file is invalid" + +#: fotoxx-12.01.cc:2187 +msgid "curve file has different no. of curves" +msgstr "curve file has different no. of curves" + +#: fotoxx-12.01.cc:2202 +msgid "save curve to a file" +msgstr "save curve to a file" + +#: fotoxx-12.01.cc:2337 +msgid "cannot parallel edit" +msgstr "cannot parallel edit" + +#: fotoxx-12.01.cc:2347 +msgid "" +"exiftool is not installed \n" +"edited images will lose EXIF data" +msgstr "" +"exiftool is not installed \n" +"edited images will lose EXIF data" + +#: fotoxx-12.01.cc:2353 +msgid "Too many edits, please save image" +msgstr "Too many edits, please save image" + +#: fotoxx-12.01.cc:2358 +msgid "" +"Select area cannot be kept.\n" +"Continue?" +msgstr "" +"Select area cannot be kept.\n" +"Continue?" + +#: fotoxx-12.01.cc:2366 +msgid "" +"Select area not active.\n" +"Continue?" +msgstr "" +"Select area not active.\n" +"Continue?" + +#: fotoxx-12.01.cc:2837 +msgid "Discard edits?" +msgstr "Discard edits?" + +#: fotoxx-12.01.cc:2838 +msgid "" +"This action will discard current edits.\n" +"Continue to discard edits.\n" +"Go Back to keep edits." +msgstr "" +"This action will discard current edits.\n" +"Continue to discard edits.\n" +"Go Back to keep edits." + +#: fotoxx-12.01.cc:2841 +msgid "Continue" +msgstr "Continue" + +#: fotoxx-12.01.cc:2842 +msgid "Go Back" +msgstr "Go Back" + +#: fotoxx-12.01.cc:3659 +msgid "cannot open thumbnail file" +msgstr "cannot open thumbnail file" + +#: fotoxx-12.01.cc:3870 fotoxx-12.01.cc:3992 +msgid "TIFF open failure" +msgstr "TIFF open failure" + +#: fotoxx-12.01.cc:3886 +#, c-format +msgid "TIFF bits/color=%d not supported" +msgstr "TIFF bits/color=%d not supported" + +#: fotoxx-12.01.cc:3901 fotoxx-12.01.cc:3939 +msgid "TIFF read failure" +msgstr "TIFF read failure" + +#: fotoxx-12.01.cc:4051 +msgid "TIFF write failure" +msgstr "TIFF write failure" + +#: fotoxx-12.01.cc:4071 +msgid "file type not supported" +msgstr "file type not supported" + +#: fotoxx-12.01.cc:4178 +msgid "pixbuf write failure" +msgstr "pixbuf write failure" + +#: fotoxx.h:728 +msgid "absolute" +msgstr "absolute" + +#: fotoxx.h:730 +msgid "Add All" +msgstr "Add All" + +#: fotoxx.h:732 +msgid "Amount" +msgstr "Amount" + +#: fotoxx.h:733 +msgid "Apply" +msgstr "Apply" + +#: fotoxx.h:734 +msgid "Black" +msgstr "Black" + +#: fotoxx.h:735 +msgid "Blend Width" +msgstr "Blend Width" + +#: fotoxx.h:737 +msgid "Brightness" +msgstr "Brightness" + +#: fotoxx.h:738 +msgid "Browse" +msgstr "Browse" + +#: fotoxx.h:739 +msgid "Cancel" +msgstr "Cancel" + +#: fotoxx.h:740 +msgid "Clear" +msgstr "Clear" + +#: fotoxx.h:742 +msgid "Commit" +msgstr "Commit" + +#: fotoxx.h:744 +msgid "Curve File:" +msgstr "Curve File:" + +#: fotoxx.h:745 +msgid "Cut" +msgstr "Cut" + +#: fotoxx.h:746 +msgid "Darker Areas" +msgstr "Darker Areas" + +#: fotoxx.h:747 +msgid "Delete" +msgstr "Delete" + +#: fotoxx.h:749 +#, c-format +msgid "" +"Discard special gallery list? \n" +" %s" +msgstr "" +"Discard special gallery list? \n" +" %s" + +#: fotoxx.h:750 +msgid "Done" +msgstr "Done" + +#: fotoxx.h:751 +msgid "Edit" +msgstr "Edit" + +#: fotoxx.h:753 +msgid "Erase" +msgstr "Erase" + +#: fotoxx.h:754 +msgid "package libimage-exiftool-perl is required" +msgstr "package libimage-exiftool-perl is required" + +#: fotoxx.h:755 +msgid "Fetch" +msgstr "Fetch" + +#: fotoxx.h:756 +msgid "Finish" +msgstr "Finish" + +#: fotoxx.h:757 +msgid "Font" +msgstr "Font" + +#: fotoxx.h:759 +msgid "Height" +msgstr "Height" + +#: fotoxx.h:760 +msgid "histogram" +msgstr "histogram" + +#: fotoxx.h:762 +msgid "Insert" +msgstr "Insert" + +#: fotoxx.h:764 +msgid "Lighter Areas" +msgstr "Lighter Areas" + +#: fotoxx.h:765 +msgid "limit" +msgstr "limit" + +#: fotoxx.h:766 +msgid "New" +msgstr "New" + +#: fotoxx.h:768 +msgid "OK" +msgstr "OK" + +#: fotoxx.h:772 +msgid "Pause" +msgstr "Pause" + +#: fotoxx.h:773 +msgid "Percent" +msgstr "Percent" + +#: fotoxx.h:774 +msgid "Presets" +msgstr "Presets" + +#: fotoxx.h:775 +msgid "Proceed" +msgstr "Proceed" + +#: fotoxx.h:777 +msgid "range" +msgstr "range" + +#: fotoxx.h:780 +msgid "Reduce" +msgstr "Reduce" + +#: fotoxx.h:782 +msgid "Reset" +msgstr "Reset" + +#: fotoxx.h:784 +msgid "Unknown file type, save as tiff/jpeg/png to edit" +msgstr "Unknown file type, save as tiff/jpeg/png to edit" + +#: fotoxx.h:785 +msgid "Search" +msgstr "Search" + +#: fotoxx.h:789 +msgid "Start" +msgstr "Start" + +#: fotoxx.h:790 +msgid "Threshold" +msgstr "Threshold" + +#: fotoxx.h:791 +#, c-format +msgid "exceed %d files" +msgstr "exceed %d files" + +#: fotoxx.h:792 +msgid "Undo All" +msgstr "Undo All" + +#: fotoxx.h:793 +msgid "Undo Last" +msgstr "Undo Last" + +#: fotoxx.h:795 +msgid "Unfinish" +msgstr "Unfinish" + +#: fotoxx.h:797 +msgid "View" +msgstr "View" + +#: fotoxx.h:798 +msgid "White" +msgstr "White" + +#: fotoxx.h:799 +msgid "Width" +msgstr "Width" + +#: zfuncs.cc:3252 +#, c-format +msgid "help file not found: %s" +msgstr "help file not found: %s" + +#: zfuncs.cc:3664 zfuncs.cc:7315 +#, c-format +msgid "cannot open file %s" +msgstr "cannot open file %s" + +#: zfuncs.cc:3697 +msgid "save screen to file" +msgstr "save screen to file" + +#: zfuncs.cc:6222 +msgid "No" +msgstr "No" + +#: zfuncs.cc:6222 +msgid "Yes" +msgstr "Yes" + +#: zfuncs.cc:6447 +msgid "open" +msgstr "open" + +#: zfuncs.cc:6452 +msgid "choose" +msgstr "choose" + +#: zfuncs.cc:6457 +msgid "save" +msgstr "save" + +#: zfuncs.cc:6463 +msgid "open folder" +msgstr "open folder" + +#: zfuncs.cc:6468 +msgid "create folder" +msgstr "create folder" + +#: zfuncs.cc:6474 +msgid "hidden" +msgstr "hidden" + +#: zfuncs.cc:6535 +msgid "JPG quality 0-100" +msgstr "JPG quality 0-100" + +#: zfuncs.cc:6728 zfuncs.cc:6741 +msgid "margins" +msgstr "margins" + +#: zfuncs.cc:6737 +msgid "top" +msgstr "top" + +#: zfuncs.cc:6738 +msgid "bottom" +msgstr "bottom" + +#: zfuncs.cc:6739 +msgid "left" +msgstr "left" + +#: zfuncs.cc:6740 +msgid "right" +msgstr "right" + +#: zfuncs.cc:7202 +msgid "" +"Initial parameters file created. \n" +"Inspect and revise if necessary." +msgstr "" +"Initial parameters file created. \n" +"Inspect and revise if necessary." + +#: zfuncs.cc:7218 +msgid "load parameters from a file" +msgstr "load parameters from a file" + +#: zfuncs.cc:7287 +msgid "save parameters to a file" +msgstr "save parameters to a file" + +#: zfuncs.cc:7425 zfuncs.cc:7431 zfuncs.cc:7437 zfuncs.cc:7443 +msgid "edit parameters" +msgstr "edit parameters" + +#: zfuncs.cc:7426 zfuncs.cc:7432 +msgid "" +"list\n" +"all" +msgstr "" +"list\n" +"all" + +#: zfuncs.cc:7426 zfuncs.cc:7432 zfuncs.cc:7438 zfuncs.cc:7444 +msgid "" +"load\n" +"file" +msgstr "" +"load\n" +"file" + +#: zfuncs.cc:7426 zfuncs.cc:7432 zfuncs.cc:7438 zfuncs.cc:7444 +msgid "" +"save\n" +"file" +msgstr "" +"save\n" +"file" + +#: zfuncs.cc:7427 zfuncs.cc:7439 +msgid "" +"add\n" +"new" +msgstr "" +"add\n" +"new" + +#: zfuncs.cc:7427 zfuncs.cc:7433 zfuncs.cc:7439 zfuncs.cc:7445 +msgid "apply" +msgstr "apply" + +#: zfuncs.cc:7479 +msgid "apply?" +msgstr "apply?" + +#: zfuncs.cc:7536 +msgid "(new parm name)" +msgstr "(new parm name)" + +#: zfuncs.cc:7536 +msgid "add parameter" +msgstr "add parameter" + + diff -Nru fotoxx-11.11.1/locales/fotoxx-es.po fotoxx-12.01.2/locales/fotoxx-es.po --- fotoxx-11.11.1/locales/fotoxx-es.po 1970-01-01 00:00:00.000000000 +0000 +++ fotoxx-12.01.2/locales/fotoxx-es.po 2012-01-04 08:47:11.000000000 +0000 @@ -0,0 +1,3279 @@ +# Spanish translations for home package. +# Copyright (C) 2008 THE home'S COPYRIGHT HOLDER +# This file is distributed under the same license as the home package. +# mico , 2008. +# +msgid "" +msgstr "" +"Project-Id-Version: fotoxx-6.9.2\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-12-31 21:05+0100\n" +"PO-Revision-Date: 2009-11-04 23:35+0100\n" +"Last-Translator: Miguel Anxo Bouzada \n" +"Language-Team: GALPon MiniNo \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Poedit-Language: Spanish\n" +"X-Poedit-Country: SPAIN\n" + +#: f.art.cc:47 +msgid "Set color depth to 1-16 bits" +msgstr "Establecer profundidad de color 1-16 bits" + +#: f.art.cc:57 +msgid "Set Color Depth" +msgstr "Ajustar la profundidad de color" + +#: f.art.cc:171 +msgid "Simulate Drawing" +msgstr "Simular un dibujo" + +#: f.art.cc:213 f.retouch.cc:1759 f.retouch.cc:5991 +msgid "contrast" +msgstr "Contraste" + +#: f.art.cc:215 +msgid "outlines" +msgstr "Contornos" + +#: f.art.cc:220 +msgid "pencil" +msgstr "Lapiz" + +#: f.art.cc:221 +msgid "chalk" +msgstr "Tiza" + +#: f.art.cc:381 +msgid "Add Image Outlines" +msgstr "" + +#: f.art.cc:394 +msgid "outline threshold" +msgstr "" + +#: f.art.cc:397 +msgid "outline width" +msgstr "" + +#: f.art.cc:400 +msgid "image brightness" +msgstr "" + +#: f.art.cc:611 +msgid "Simulate Embossing" +msgstr "Simular un repujado" + +#: f.art.cc:626 +msgid "depth" +msgstr "Profundidad" + +#: f.art.cc:628 f.file.cc:919 f.retouch.cc:6692 +msgid "color" +msgstr "Color" + +#: f.art.cc:821 +msgid "Simulate Tiles" +msgstr "Simular un mosaico" + +#: f.art.cc:825 +msgid "tile size" +msgstr "Tamaño del mosaico" + +#: f.art.cc:829 +msgid "tile gap" +msgstr "Separación do mosaico" + +#: f.art.cc:1003 +msgid "Convert Image to Dots" +msgstr "" + +#: f.art.cc:1007 +msgid "dot size" +msgstr "" + +#: f.art.cc:1222 +msgid "Simulate Painting" +msgstr "Simular una pintura" + +#: f.art.cc:1226 +msgid "color depth" +msgstr "Profundidad de color" + +#: f.art.cc:1230 +msgid "patch area goal" +msgstr "" + +#: f.art.cc:1234 +msgid "req. color match" +msgstr "Correspondencia de color requerida" + +#: f.art.cc:1238 +msgid "borders" +msgstr "Bordes" + +#: f.comp.cc:1956 f.comp.cc:1961 f.comp.cc:2582 f.comp.cc:2587 f.comp.cc:3266 +#: f.comp.cc:3271 f.comp.cc:3816 f.comp.cc:3821 +msgid "Select 2 to 9 files" +msgstr "" + +#: f.comp.cc:1982 f.comp.cc:2608 f.comp.cc:3292 f.comp.cc:3842 +msgid "Images are not all the same size" +msgstr "" + +#: f.comp.cc:2321 +msgid "Adjust Image Contributions" +msgstr "" + +#: f.comp.cc:2324 f.retouch.cc:886 +msgid "dark pixels" +msgstr "" + +#: f.comp.cc:2326 +msgid "light pixels" +msgstr "" + +#: f.comp.cc:2328 f.info.cc:159 +msgid "file:" +msgstr "Archivo:" + +#: f.comp.cc:2843 +msgid "Paint and Warp Image" +msgstr "" + +#: f.comp.cc:2846 f.comp.cc:3520 f.comp.cc:4959 f.comp.cc:5705 +msgid "image" +msgstr "" + +#: f.comp.cc:2850 f.retouch.cc:6696 +msgid "paint" +msgstr "Pintar" + +#: f.comp.cc:2851 +msgid "warp" +msgstr "" + +#: f.comp.cc:3518 +msgid "Select and Paint Image" +msgstr "" + +#: f.comp.cc:4031 +msgid "Adjust Pixel Composition" +msgstr "" + +#: f.comp.cc:4283 f.comp.cc:4288 f.comp.cc:5173 f.comp.cc:5178 +msgid "Select 2 to 4 files" +msgstr "" + +#: f.comp.cc:4361 +msgid "" +"Drag images into rough alignment.\n" +"To rotate, drag from lower edge." +msgstr "" + +#: f.comp.cc:4363 +msgid "Search for lens mm and bow" +msgstr "" + +#: f.comp.cc:4409 f.comp.cc:5298 +msgid "Pre-align Images" +msgstr "Pre-alinear imágenes" + +#: f.comp.cc:4413 f.comp.cc:5302 +msgid "lens mm" +msgstr "Longitud focal (mm)" + +#: f.comp.cc:4417 f.comp.cc:5306 +msgid "lens bow" +msgstr "Curvatura de la lente" + +#: f.comp.cc:4419 f.comp.cc:5308 +msgid "Resize" +msgstr "" + +#: f.comp.cc:4420 f.comp.cc:5309 +msgid "resize window" +msgstr "" + +#: f.comp.cc:4457 +msgid "use two images only" +msgstr "" + +#: f.comp.cc:4478 f.comp.cc:4676 f.comp.cc:4875 f.comp.cc:5357 f.comp.cc:5620 +msgid "Too little overlap, cannot align" +msgstr "Solapamiento demasiado pequeño, no puedo alinear" + +#: f.comp.cc:4950 f.comp.cc:5696 +msgid "Match Brightness and Color" +msgstr "" + +#: f.comp.cc:4974 f.comp.cc:5720 +msgid "auto color" +msgstr "" + +#: f.comp.cc:4975 f.comp.cc:5721 +msgid "file color" +msgstr "" + +#: f.comp.cc:5251 +msgid "" +"Drag images into rough alignment.\n" +"To rotate, drag from right edge." +msgstr "" + +#: f.file.cc:169 f.file.cc:341 fotoxx-12.01.cc:189 fotoxx-12.01.cc:325 +msgid "Open Image File" +msgstr "Abrir archivo de imagen" + +#: f.file.cc:321 fotoxx-12.01.cc:2862 +msgid "prior function still active" +msgstr "" + +#: f.file.cc:503 +msgid "Overwrite original file?" +msgstr "" + +#: f.file.cc:504 +msgid "Do not warn again" +msgstr "" + +#: f.file.cc:520 +msgid "Warning" +msgstr "" + +#: f.file.cc:643 +msgid "Save File" +msgstr "Guardar el archivo" + +#: f.file.cc:666 zfuncs.cc:6478 +msgid "quality" +msgstr "" + +#: f.file.cc:668 +msgid "make current" +msgstr "" + +#: f.file.cc:725 +msgid "jpeg quality must be 1-100" +msgstr "" + +#: f.file.cc:747 +#, c-format +msgid "" +"Overwrite file? \n" +" %s" +msgstr "" +"¿Sobreescribir archivo? \n" +" %s" + +#: f.file.cc:903 fotoxx-12.01.cc:196 +msgid "Create Blank Image" +msgstr "" + +#: f.file.cc:905 +msgid "file name" +msgstr "" + +#: f.file.cc:910 f.transform.cc:353 +msgid "width" +msgstr "" + +#: f.file.cc:913 f.tools.cc:477 f.transform.cc:356 +msgid "height" +msgstr "" + +#: f.file.cc:1033 +msgid "" +"Linux standard trash is not supported. \n" +"Desktop trash folder will be created." +msgstr "" + +#: f.file.cc:1051 +msgid "Move read-only file to trash?" +msgstr "¿Enviar el fichero de solo lectura a la papelera?" + +#: f.file.cc:1077 +#, c-format +msgid "Cannot create trash folder: %s" +msgstr "No se puede crear carpeta de papelera: %s" + +#: f.file.cc:1085 f.file.cc:1091 zfuncs.cc:3356 +#, c-format +msgid "error: %s" +msgstr "error: %s" + +#: f.file.cc:1136 fotoxx-12.01.cc:198 +msgid "Rename Image File" +msgstr "Renombrar archivo de imagen" + +#: f.file.cc:1141 +msgid "old name" +msgstr "Nombre antiguo" + +#: f.file.cc:1142 +msgid "rename to" +msgstr "Renombrar como" + +#: f.file.cc:1143 +msgid "previous" +msgstr "Anterior" + +#: f.file.cc:1229 +msgid "The target file already exists" +msgstr "El archivo de destino ya existe" + +#: f.file.cc:1237 +#, c-format +msgid "" +"Rename failed: \n" +" %s" +msgstr "" + +#: f.file.cc:1285 +msgid "Batch Rename" +msgstr "" + +#: f.file.cc:1288 f.file.cc:1340 f.info.cc:1519 f.info.cc:1773 f.tools.cc:543 +#: f.tools.cc:2990 +#, c-format +msgid "%d files selected" +msgstr "" + +#: f.file.cc:1290 +msgid "new base name" +msgstr "" + +#: f.file.cc:1293 +msgid "starting sequence" +msgstr "" + +#: f.file.cc:1295 +msgid "increment" +msgstr "" + +#: f.file.cc:1316 +msgid "select files to rename" +msgstr "" + +#: f.file.cc:1321 +msgid "base name / sequence / increment not reasonable" +msgstr "" + +#: f.file.cc:1380 +msgid "new file already exists:" +msgstr "" + +#: f.file.cc:1388 +msgid "filespec too long:" +msgstr "" + +#: f.file.cc:1399 +msgid "Rename failed:" +msgstr "" + +#: f.file.cc:1660 fotoxx.h:729 +msgid "Add" +msgstr "" + +#: f.file.cc:1660 fotoxx.h:781 +msgid "Remove" +msgstr "" + +#: f.file.cc:1662 +msgid "menu name" +msgstr "" + +#: f.file.cc:1733 f.file.cc:1754 +msgid "Restart Fotoxx to update plugin menu" +msgstr "" + +#: f.info.cc:70 +msgid "Edit Caption and Comments" +msgstr "" + +#: f.info.cc:156 fotoxx-12.01.cc:225 +msgid "Edit Tags" +msgstr "Editar etiquetas" + +#: f.info.cc:163 +msgid "image date (yyyymmdd)" +msgstr "Fecha de la imagen (aaaammdd)" + +#: f.info.cc:165 +msgid "use last" +msgstr "Usar el último" + +#: f.info.cc:168 +msgid "image stars" +msgstr "Imagen estrella" + +#: f.info.cc:186 +msgid "current tags" +msgstr "Etiquetas actuales" + +#: f.info.cc:191 +msgid "recent tags" +msgstr "" + +#: f.info.cc:196 f.info.cc:358 f.info.cc:1368 f.info.cc:2384 +msgid "defined tags" +msgstr "" + +#: f.info.cc:345 fotoxx-12.01.cc:226 +msgid "Manage Tags" +msgstr "" + +#: f.info.cc:348 +msgid "category" +msgstr "" + +#: f.info.cc:351 +msgid "tag" +msgstr "" + +#: f.info.cc:354 +msgid "create" +msgstr "" + +#: f.info.cc:355 f.navi.cc:1421 +msgid "delete" +msgstr "Borrar" + +#: f.info.cc:1235 f.info.cc:1319 +#, c-format +msgid "search index file error: %s" +msgstr "" + +#: f.info.cc:1351 fotoxx-12.01.cc:227 +msgid "Batch Add Tags" +msgstr "" + +#: f.info.cc:1354 +msgid "tags to add" +msgstr "" + +#: f.info.cc:1359 +msgid "create tag" +msgstr "Crear etiqueta" + +#: f.info.cc:1415 f.info.cc:1608 +#, c-format +msgid "" +"%s \n" +" too many tags" +msgstr "" + +#: f.info.cc:1553 fotoxx-12.01.cc:228 +msgid "Batch Delete Tag" +msgstr "" + +#: f.info.cc:1556 +msgid "tag to remove" +msgstr "" + +#: f.info.cc:1560 +msgid "optional replacement" +msgstr "" + +#: f.info.cc:1565 f.tools.cc:2943 +msgid "0 files selected" +msgstr "" + +#: f.info.cc:1568 +msgid "search all files" +msgstr "" + +#: f.info.cc:1653 +msgid "no files selected" +msgstr "" + +#: f.info.cc:1659 +msgid "no tag specified" +msgstr "" + +#: f.info.cc:1683 f.info.cc:1712 +msgid "specify tag" +msgstr "" + +#: f.info.cc:1821 +msgid "View Info" +msgstr "" + +#: f.info.cc:1889 fotoxx-12.01.cc:231 +msgid "Edit Info" +msgstr "" + +#: f.info.cc:1987 fotoxx-12.01.cc:232 +msgid "Delete Info" +msgstr "" + +#: f.info.cc:1989 fotoxx.h:731 +msgid "All" +msgstr "" + +#: f.info.cc:1990 +msgid "One Key:" +msgstr "" + +#: f.info.cc:2343 +msgid "Search Tags, Comments, File Names" +msgstr "" + +#: f.info.cc:2350 +msgid "date range" +msgstr "Rango de fechas" + +#: f.info.cc:2351 +msgid "stars range" +msgstr "Rango de estrellas" + +#: f.info.cc:2352 +msgid "search tags" +msgstr "Buscar etiquetas" + +#: f.info.cc:2353 +msgid "search text" +msgstr "" + +#: f.info.cc:2354 +msgid "file names" +msgstr "" + +#: f.info.cc:2359 +msgid "(yyyymmdd)" +msgstr "" + +#: f.info.cc:2365 +msgid "all/any" +msgstr "" + +#: f.info.cc:2702 +msgid "No matching images found" +msgstr "No se encontró ninguna imagen" + +#: f.info.cc:2706 f.info.cc:3059 +msgid "No search index file present" +msgstr "" + +#: f.info.cc:2777 +msgid "Additional Items for Report" +msgstr "" + +#: f.navi.cc:188 f.navi.cc:576 f.navi.cc:706 f.navi.cc:707 f.navi.cc:709 +msgid "bigger" +msgstr "Mayor" + +#: f.navi.cc:188 +msgid "increase thumbnail size" +msgstr "Aumentar tamaño de miniatura" + +#: f.navi.cc:189 +msgid "reduce thumbnail size" +msgstr "Reducir tamaño de la miniatura" + +#: f.navi.cc:189 f.navi.cc:586 f.navi.cc:708 f.navi.cc:710 +msgid "smaller" +msgstr "Menor" + +#: f.navi.cc:190 f.navi.cc:600 +msgid "parent" +msgstr "" + +#: f.navi.cc:190 +msgid "parent directory" +msgstr "" + +#: f.navi.cc:191 f.navi.cc:625 f.navi.cc:717 +msgid "first page" +msgstr "Primera página" + +#: f.navi.cc:191 +msgid "jump to first file" +msgstr "Cambiar al primer archivo" + +#: f.navi.cc:192 f.navi.cc:623 f.navi.cc:712 f.navi.cc:719 +msgid "prev page" +msgstr "Página anterior." + +#: f.navi.cc:192 +msgid "previous page" +msgstr "Página anterior" + +#: f.navi.cc:193 f.navi.cc:621 f.navi.cc:714 +msgid "prev row" +msgstr "Fila anterior." + +#: f.navi.cc:193 +msgid "previous row" +msgstr "Fila anterior" + +#: f.navi.cc:194 f.navi.cc:622 f.navi.cc:715 +msgid "next row" +msgstr "Siguiente fila" + +#: f.navi.cc:195 f.navi.cc:624 f.navi.cc:713 f.navi.cc:720 +msgid "next page" +msgstr "Página sig." + +#: f.navi.cc:195 +msgid "ttip::next page" +msgstr "" + +#: f.navi.cc:196 +msgid "jump to last file" +msgstr "Cambiar al último archivo" + +#: f.navi.cc:196 f.navi.cc:626 f.navi.cc:718 +msgid "last page" +msgstr "Última página" + +#: f.navi.cc:197 f.navi.cc:571 +msgid "close" +msgstr "Cerrar" + +#: f.navi.cc:197 +msgid "close image gallery" +msgstr "Cerrar la galería de imágenes" + +#: f.navi.cc:1413 fotoxx.h:787 +msgid "Select Files" +msgstr "" + +#: f.navi.cc:1413 zfuncs.cc:6296 zfuncs.cc:6332 zfuncs.cc:6485 zfuncs.cc:6728 +#: zfuncs.cc:7427 zfuncs.cc:7433 zfuncs.cc:7439 zfuncs.cc:7445 +msgid "cancel" +msgstr "Cancelar" + +#: f.navi.cc:1413 zfuncs.cc:6728 +msgid "done" +msgstr "" + +#: f.navi.cc:1422 +msgid "insert" +msgstr "Insertar" + +#: f.navi.cc:1423 +msgid "add all" +msgstr "" + +#: f.retouch.cc:55 +msgid "Adjust Brightness and Color" +msgstr "Ajustar brillo y color" + +#: f.retouch.cc:110 +msgid "small-steps" +msgstr "" + +#: f.retouch.cc:119 +msgid "color saturation" +msgstr "Saturación de color" + +#: f.retouch.cc:126 +msgid " reset 1 " +msgstr " Restablecer 1" + +#: f.retouch.cc:127 +msgid "reset all" +msgstr "Restablecer todo" + +#: f.retouch.cc:599 +msgid "adjust image gamma" +msgstr "" + +#: f.retouch.cc:885 +msgid "Expand Brightness Range" +msgstr "" + +#: f.retouch.cc:887 +msgid "bright pixels" +msgstr "" + +#: f.retouch.cc:1058 +msgid "Flatten Brightness Distribution" +msgstr "Distribución uniforme del brillo" + +#: f.retouch.cc:1072 +msgid "Flatten" +msgstr "Aplanar" + +#: f.retouch.cc:1334 +msgid "Ramp brightness across image" +msgstr "" + +#: f.retouch.cc:1730 fotoxx-12.01.cc:272 +msgid "Tone Mapping" +msgstr "" + +#: f.retouch.cc:1758 +msgid "low" +msgstr "" + +#: f.retouch.cc:1760 +msgid "high" +msgstr "" + +#: f.retouch.cc:1763 +msgid "Amplify" +msgstr "" + +#: f.retouch.cc:2069 +msgid "Adjust White Balance" +msgstr "Ajustar balance de blanco" + +#: f.retouch.cc:2070 +msgid "Click white or gray image location" +msgstr "Haga clic en la ubicación de la imagen en blanco o gris" + +#: f.retouch.cc:2278 +msgid "Color Match Images" +msgstr "" + +#: f.retouch.cc:2307 +msgid "mouse radius for color sample" +msgstr "" + +#: f.retouch.cc:2309 f.retouch.cc:2314 fotoxx-12.01.cc:246 fotoxx-12.01.cc:325 +#: fotoxx.h:769 +msgid "Open" +msgstr "Abrir" + +#: f.retouch.cc:2310 +msgid "image for source color" +msgstr "" + +#: f.retouch.cc:2312 +msgid "click on image to get source color" +msgstr "" + +#: f.retouch.cc:2315 +msgid "image to set matching color" +msgstr "" + +#: f.retouch.cc:2317 +msgid "click on image to set matching color" +msgstr "" + +#: f.retouch.cc:2372 +msgid "select source image color first" +msgstr "" + +#: f.retouch.cc:2584 +msgid "Add standard bias" +msgstr "" + +#: f.retouch.cc:2591 +msgid "+Brightness -Density" +msgstr "" + +#: f.retouch.cc:2592 +msgid "+Red -Cyan" +msgstr "" + +#: f.retouch.cc:2593 +msgid "+Green -Magenta" +msgstr "" + +#: f.retouch.cc:2594 +msgid "+Blue -Yellow" +msgstr "" + +#: f.retouch.cc:2599 +msgid "Contrast" +msgstr "" + +#: f.retouch.cc:2600 fotoxx.h:778 +msgid "Red" +msgstr "Rojo" + +#: f.retouch.cc:2601 fotoxx.h:758 +msgid "Green" +msgstr "Verde" + +#: f.retouch.cc:2602 fotoxx.h:736 +msgid "Blue" +msgstr "Azul" + +#: f.retouch.cc:2730 +msgid "Load DRGB parameters" +msgstr "" + +#: f.retouch.cc:2732 f.retouch.cc:2804 f.retouch.cc:6102 f.retouch.cc:6198 +msgid "File:" +msgstr "" + +#: f.retouch.cc:2751 f.retouch.cc:2824 +msgid "DRGB parameters file" +msgstr "" + +#: f.retouch.cc:2769 f.retouch.cc:6142 +msgid "file not found" +msgstr "" + +#: f.retouch.cc:2802 +msgid "Save DRGB parameters" +msgstr "" + +#: f.retouch.cc:3034 f.tools.cc:2404 +msgid "Click image to select pixels." +msgstr "" + +#: f.retouch.cc:3072 fotoxx-12.01.cc:276 +msgid "Revise RGB" +msgstr "" + +#: f.retouch.cc:3084 +msgid "Metric:" +msgstr "" + +#: f.retouch.cc:3139 +msgid "Blend" +msgstr "" + +#: f.retouch.cc:3519 +msgid "" +"Method 1:\n" +" Left-click on red-eye to darken.\n" +"Method 2:\n" +" Drag down and right to enclose red-eye.\n" +" Left-click on red-eye to darken.\n" +"Undo red-eye:\n" +" Right-click on red-eye." +msgstr "" +"Método 1:\n" +" Clic-izquierdo en el ojo rojo para oscurecer.\n" +"Método 2:\n" +" Pica y arrastra a la derecha para delimitar el ojo rojo.\n" +" Clic-izquierdo para oscurecer el ojo rojo.\n" +"Deshacer ojos rojos:\n" +" Clic-derecho en el ojo rojo." + +#: f.retouch.cc:3534 +msgid "Red Eye Reduction" +msgstr "Reducción de ojos rojos" + +#: f.retouch.cc:3968 +msgid "Set Blur Radius" +msgstr "Establecer radio de desenfoque" + +#: f.retouch.cc:4195 fotoxx-12.01.cc:279 +msgid "Sharpen Image" +msgstr "Enfoque de imagen" + +#: f.retouch.cc:4202 +msgid "edge detection" +msgstr "Detección de borde" + +#: f.retouch.cc:4203 +msgid "cycles" +msgstr "Ciclos" + +#: f.retouch.cc:4204 +msgid "reduce" +msgstr "reducir" + +#: f.retouch.cc:4215 +msgid "unsharp mask" +msgstr "Máscara de desenfoque" + +#: f.retouch.cc:4228 +msgid "brightness gradient" +msgstr "" + +#: f.retouch.cc:4634 +msgid "" +" Press the reduce button to \n" +" reduce noise in small steps. \n" +" Use undo to start over." +msgstr "" +" Pulse el botón de reducción para \n" +" reducir el ruido en pequeños pasos. \n" +" Utilice Deshacer para empezar de nuevo." + +#: f.retouch.cc:4645 +msgid "Noise Reduction" +msgstr "Reducción de ruido" + +#: f.retouch.cc:4650 +msgid "algorithm" +msgstr "algoritmo" + +#: f.retouch.cc:4657 +msgid "flatten outliers by color (1)" +msgstr "Aplanar los valores extremos de color (1)" + +#: f.retouch.cc:4658 +msgid "flatten outliers by color (2)" +msgstr "Aplanar los valores extremos de color (2)" + +#: f.retouch.cc:4659 +msgid "set median brightness by color" +msgstr "Configurar la mediana de brillo por color" + +#: f.retouch.cc:4660 f.retouch.cc:4661 +msgid "top hat filter by color" +msgstr "Filtro de color «sombrero de copa (Top-hat)»" + +#: f.retouch.cc:4976 +msgid "" +"1. Drag mouse to select. \n" +"2. Erase. 3. Repeat. " +msgstr "" + +#: f.retouch.cc:4998 fotoxx-12.01.cc:281 +msgid "Smart Erase" +msgstr "" + +#: f.retouch.cc:5003 fotoxx.h:776 +msgid "Radius" +msgstr "Radio" + +#: f.retouch.cc:5005 +msgid "Blur" +msgstr "" + +#: f.retouch.cc:5008 +msgid "New Area" +msgstr "" + +#: f.retouch.cc:5379 fotoxx-12.01.cc:282 +msgid "Remove Dust" +msgstr "" + +#: f.retouch.cc:5383 +msgid "spot size limit" +msgstr "" + +#: f.retouch.cc:5386 +msgid "max. brightness" +msgstr "" + +#: f.retouch.cc:5389 +msgid "min. contrast" +msgstr "" + +#: f.retouch.cc:5983 fotoxx-12.01.cc:283 +msgid "Fix Stuck Pixels" +msgstr "" + +#: f.retouch.cc:5989 +msgid "pixel group" +msgstr "" + +#: f.retouch.cc:5990 +msgid "circle color" +msgstr "" + +#: f.retouch.cc:6100 +msgid "Load Stuck Pixels" +msgstr "" + +#: f.retouch.cc:6124 f.retouch.cc:6220 +msgid "Stuck Pixels file" +msgstr "" + +#: f.retouch.cc:6164 +msgid "file format error" +msgstr "" + +#: f.retouch.cc:6192 +msgid "there are zero stuck pixels" +msgstr "" + +#: f.retouch.cc:6196 +msgid "Save Stuck Pixels" +msgstr "" + +#: f.retouch.cc:6686 +#, c-format +msgid "Undo Memory %d%c" +msgstr "Memoria de deshacer %d%c" + +#: f.retouch.cc:6688 fotoxx-12.01.cc:284 +msgid "Edit Pixels" +msgstr "Editar píxeles" + +#: f.retouch.cc:6695 +msgid "pick" +msgstr "Recoger" + +#: f.retouch.cc:6697 +msgid "erase" +msgstr "Borrar" + +#: f.retouch.cc:6705 +msgid "paintbrush radius" +msgstr "Radio del pincel" + +#: f.retouch.cc:6706 +msgid "transparency center" +msgstr "Centro de la transparencia" + +#: f.retouch.cc:6707 +msgid "transparency edge" +msgstr "Borde de la transparencia" + +#: f.retouch.cc:6972 +msgid "" +"Undo memory limit has been reached. \n" +"Save work with [done], then resume editing." +msgstr "" +"Se alcanzó el límite de memoria de deshacer. \n" +"Guarde el trabajo con [Hecho], y luego reanude la edición." + +#: f.select.cc:54 f.select.cc:2461 +msgid "Select Area for Edits" +msgstr "" + +#: f.select.cc:55 f.select.cc:2462 +msgid "Press F1 for help" +msgstr "" + +#: f.select.cc:64 +msgid "" +"Select Area not supported \n" +"by this edit function" +msgstr "" + +#: f.select.cc:103 f.tools.cc:901 +msgid "rectangle" +msgstr "" + +#: f.select.cc:104 f.tools.cc:902 +msgid "ellipse" +msgstr "" + +#: f.select.cc:110 +msgid "draw: freehand" +msgstr "" + +#: f.select.cc:111 +msgid "draw: follow edge" +msgstr "" + +#: f.select.cc:114 +msgid "select by mouse" +msgstr "" + +#: f.select.cc:116 f.select.cc:2496 +msgid "mouse radius" +msgstr "" + +#: f.select.cc:120 +msgid "match mouse color" +msgstr "" + +#: f.select.cc:124 +msgid "search range" +msgstr "" + +#: f.select.cc:126 +msgid "firewall" +msgstr "" + +#: f.select.cc:326 f.select.cc:467 +#, c-format +msgid "exceed %d edits" +msgstr "" + +#: f.select.cc:1021 +msgid "" +"Click one time inside each enclosed area \n" +"(possible gaps in the outline will be found). \n" +"Press F1 for help." +msgstr "" + +#: f.select.cc:1078 +msgid "finish area" +msgstr "" + +#: f.select.cc:1113 +msgid "searching" +msgstr "" + +#: f.select.cc:1185 +msgid "outline has a gap" +msgstr "" + +#: f.select.cc:1189 +msgid "success" +msgstr "" + +#: f.select.cc:1440 f.select.cc:1470 +msgid "the area is not finished" +msgstr "" + +#: f.select.cc:1563 +msgid "Edge calculation in progress" +msgstr "Necesita calcular el borde" + +#: f.select.cc:1572 +msgid "Area Edge Calc" +msgstr "Calcular el área de borde" + +#: f.select.cc:1863 +msgid "position with mouse click/drag" +msgstr "" + +#: f.select.cc:1887 +msgid "Paste Image" +msgstr "" + +#: f.select.cc:1901 +msgid "angle" +msgstr "" + +#: f.select.cc:2160 +msgid "load select area from a file" +msgstr "" + +#: f.select.cc:2194 +msgid "cannot open .tiff and .info files" +msgstr "" + +#: f.select.cc:2213 +msgid "save select area to a file" +msgstr "" + +#: f.select.cc:2248 fotoxx-12.01.cc:248 +msgid "Select Whole Image" +msgstr "" + +#: f.select.cc:2249 +msgid "Edit Function Amplifier" +msgstr "" + +#: f.select.cc:2463 +msgid "Edit function must be active" +msgstr "" + +#: f.select.cc:2499 +msgid "power: center" +msgstr "" + +#: f.select.cc:2501 +msgid "edge" +msgstr "" + +#: f.select.cc:2504 +msgid "reset area" +msgstr "" + +#: f.tools.cc:42 +msgid "" +"When editing a collection, right-click \n" +"an image or thumbnail to add or remove." +msgstr "" + +#: f.tools.cc:70 fotoxx-12.01.cc:204 +msgid "Manage Collections" +msgstr "" + +#: f.tools.cc:85 +msgid "Start new collection" +msgstr "" + +#: f.tools.cc:87 +msgid "Edit a collection" +msgstr "" + +#: f.tools.cc:89 +msgid "View a collection" +msgstr "" + +#: f.tools.cc:91 +msgid "Delete a collection" +msgstr "" + +#: f.tools.cc:95 +msgid "Editing:" +msgstr "" + +#: f.tools.cc:99 +msgid "Action:" +msgstr "" + +#: f.tools.cc:133 +msgid "New Collection" +msgstr "" + +#: f.tools.cc:156 +msgid "Edit Collection" +msgstr "" + +#: f.tools.cc:172 +msgid "View Collection" +msgstr "" + +#: f.tools.cc:193 +msgid "Delete Collection" +msgstr "" + +#: f.tools.cc:196 +#, c-format +msgid "delete %s ?" +msgstr "" + +#: f.tools.cc:223 +#, c-format +msgid "add image to collection: %s" +msgstr "" + +#: f.tools.cc:225 f.tools.cc:270 +msgid "remove image from collection" +msgstr "" + +#: f.tools.cc:226 f.tools.cc:271 f.tools.cc:298 +msgid "remove and save image" +msgstr "" + +#: f.tools.cc:227 f.tools.cc:316 +msgid "insert saved images here" +msgstr "" + +#: f.tools.cc:256 +msgid "add image to collection" +msgstr "" + +#: f.tools.cc:301 +msgid "too many saved files" +msgstr "" + +#: f.tools.cc:373 fotoxx-12.01.cc:205 +msgid "Move Collections" +msgstr "" + +#: f.tools.cc:375 +msgid "old top directory" +msgstr "" + +#: f.tools.cc:378 +msgid "new top directory" +msgstr "" + +#: f.tools.cc:434 +msgid "completed" +msgstr "" + +#: f.tools.cc:467 +msgid "Batch Convert/Resize/Export" +msgstr "" + +#: f.tools.cc:474 +msgid "new max. width" +msgstr "" + +#: f.tools.cc:481 +msgid "new file type" +msgstr "" + +#: f.tools.cc:482 +msgid "same" +msgstr "" + +#: f.tools.cc:490 +msgid "replace originals" +msgstr "" + +#: f.tools.cc:491 +msgid "export to location" +msgstr "" + +#: f.tools.cc:492 +msgid "remove EXIF" +msgstr "" + +#: f.tools.cc:549 +msgid "Select directory" +msgstr "" + +#: f.tools.cc:583 +#, c-format +msgid "replace original files? (max. %d x %d)" +msgstr "" + +#: f.tools.cc:590 +#, c-format +msgid "" +"copy files? (max. %d x %d) \n" +" to location %s" +msgstr "" + +#: f.tools.cc:601 +msgid "location is not a valid directory" +msgstr "" + +#: f.tools.cc:608 f.tools.cc:3007 +#, c-format +msgid "max. size %d x %d is not reasonable" +msgstr "" + +#: f.tools.cc:654 +msgid "*** file already exists" +msgstr "" + +#: f.tools.cc:662 +msgid "*** file type not supported" +msgstr "" + +#: f.tools.cc:741 +msgid "Program ufraw-batch is required" +msgstr "" + +#: f.tools.cc:751 fotoxx.h:770 +msgid "Open RAW File" +msgstr "Abrir fichero RAW" + +#: f.tools.cc:764 +msgid "Select RAW files to convert" +msgstr "" + +#: f.tools.cc:769 +msgid "Choose file type" +msgstr "" + +#: f.tools.cc:888 +msgid "Press ESC to exit slide show" +msgstr "" + +#: f.tools.cc:889 +msgid "show only latest file versions" +msgstr "" + +#: f.tools.cc:893 +msgid "arrow keys" +msgstr "" + +#: f.tools.cc:894 +msgid "instant" +msgstr "" + +#: f.tools.cc:895 +msgid "fade-in" +msgstr "" + +#: f.tools.cc:896 +msgid "roll-right" +msgstr "" + +#: f.tools.cc:897 +msgid "roll-down" +msgstr "" + +#: f.tools.cc:898 +msgid "shift-left" +msgstr "" + +#: f.tools.cc:899 +msgid "venetian" +msgstr "" + +#: f.tools.cc:900 +msgid "grate" +msgstr "" + +#: f.tools.cc:903 +msgid "radar" +msgstr "" + +#: f.tools.cc:904 +msgid "jaws" +msgstr "" + +#: f.tools.cc:911 fotoxx-12.01.cc:208 +msgid "Slide Show" +msgstr "Diaporama" + +#: f.tools.cc:915 +msgid "seconds" +msgstr "segundos" + +#: f.tools.cc:919 +msgid "music file" +msgstr "" + +#: f.tools.cc:923 +msgid "transitions" +msgstr "" + +#: f.tools.cc:1040 +msgid "Select music file or playlist" +msgstr "" + +#: f.tools.cc:1727 +msgid "Sync Files is already running" +msgstr "" + +#: f.tools.cc:1778 +msgid "" +"Run Tools > Synchronize Files so that gallery windows \n" +"will be fast and Search Images will work correctly. \n" +"You can view (not edit) images while synchronize runs." +msgstr "" + +#: f.tools.cc:1812 +msgid "no top image directory is defined" +msgstr "" + +#: f.tools.cc:1818 +msgid "top image directory is invalid" +msgstr "" + +#: f.tools.cc:1823 +msgid "no search index file is present" +msgstr "" + +#: f.tools.cc:1837 +msgid "new/modified files are present" +msgstr "" + +#: f.tools.cc:1844 +msgid "no new files found" +msgstr "" + +#: f.tools.cc:1859 fotoxx-12.01.cc:209 +msgid "Synchronize Files" +msgstr "" + +#: f.tools.cc:1861 +msgid "Top Image Directory:" +msgstr "" + +#: f.tools.cc:1883 +msgid "" +"file sync is necessary.\n" +"cancel anyway?" +msgstr "" + +#: f.tools.cc:1896 +msgid "top directory is invalid" +msgstr "" + +#: f.tools.cc:2292 +msgid "Select top image directory" +msgstr "Seleccionar el directorio raíz de imágenes" + +#: f.tools.cc:2429 fotoxx-12.01.cc:210 +msgid "Show RGB" +msgstr "Mostrar RGB" + +#: f.tools.cc:2719 fotoxx-12.01.cc:211 +msgid "Grid Lines" +msgstr "" + +#: f.tools.cc:2728 +msgid "x-spacing" +msgstr "" + +#: f.tools.cc:2729 +msgid "x-count" +msgstr "" + +#: f.tools.cc:2730 +msgid "x-enable" +msgstr "" + +#: f.tools.cc:2736 +msgid "y-spacing" +msgstr "" + +#: f.tools.cc:2737 +msgid "y-count" +msgstr "" + +#: f.tools.cc:2738 +msgid "y-enable" +msgstr "" + +#: f.tools.cc:2745 +msgid "x-offset" +msgstr "" + +#: f.tools.cc:2749 +msgid "y-offset" +msgstr "" + +#: f.tools.cc:2940 fotoxx-12.01.cc:213 +msgid "E-mail Images" +msgstr "" + +#: f.tools.cc:2947 +msgid "max. width" +msgstr "" + +#: f.tools.cc:2948 +msgid "max. height" +msgstr "" + +#: f.tools.cc:3093 +msgid "too many files" +msgstr "" + +#: f.tools.cc:3134 +msgid "" +"Brightness should show a gradual ramp \n" +"extending all the way to the edges." +msgstr "" + +#: f.tools.cc:3174 +msgid "Monitor Check" +msgstr "" + +#: f.tools.cc:3232 fotoxx-12.01.cc:215 +msgid "Monitor Gamma" +msgstr "" + +#: f.tools.cc:3294 fotoxx-12.01.cc:216 +msgid "Brightness Distribution" +msgstr "Distribuir el brillo" + +#: f.tools.cc:3432 +msgid "Available Translations" +msgstr "Traducciones disponibles" + +#: f.tools.cc:3436 +msgid "Set Language" +msgstr "Seleccionar el idioma" + +#: f.tools.cc:3502 +msgid "Make Launcher" +msgstr "" + +#: f.tools.cc:3540 +msgid "Settings" +msgstr "" + +#: f.tools.cc:3545 +msgid "Startup Display" +msgstr "" + +#: f.tools.cc:3547 +msgid "Recent Files Gallery" +msgstr "" + +#: f.tools.cc:3548 +msgid "Previous Image Viewed" +msgstr "" + +#: f.tools.cc:3549 +msgid "Blank Window" +msgstr "" + +#: f.tools.cc:3551 +msgid "Directory Gallery" +msgstr "" + +#: f.tools.cc:3556 +msgid "Image File" +msgstr "" + +#: f.tools.cc:3562 +msgid "Toolbar Style" +msgstr "" + +#: f.tools.cc:3563 f.transform.cc:1300 +msgid "Text" +msgstr "" + +#: f.tools.cc:3564 +msgid "Icons" +msgstr "" + +#: f.tools.cc:3565 +msgid "Both" +msgstr "" + +#: f.tools.cc:3568 +msgid "Warn Overwrite" +msgstr "" + +#: f.tools.cc:3639 +msgid "startup directory is invalid" +msgstr "" + +#: f.tools.cc:3650 +msgid "startup file is invalid" +msgstr "" + +#: f.tools.cc:3707 +msgid "Select startup directory" +msgstr "" + +#: f.tools.cc:3715 +msgid "Select startup image file" +msgstr "" + +#: f.transform.cc:50 +msgid "Use buttons or drag right edge with mouse" +msgstr "Utilice los botones o arrastre el borde derecho con el ratón" + +#: f.transform.cc:60 fotoxx-12.01.cc:252 +msgid "Rotate Image" +msgstr "Rotar imagen" + +#: f.transform.cc:64 +msgid "degrees" +msgstr "Grados" + +#: f.transform.cc:80 f.transform.cc:124 +msgid "Trim" +msgstr "Recortar" + +#: f.transform.cc:81 f.transform.cc:2289 f.transform.cc:3120 +#: f.transform.cc:3383 f.transform.cc:3644 +msgid "Grid" +msgstr "" + +#: f.transform.cc:123 +msgid "Undo Trim" +msgstr "Deshacer recortar" + +#: f.transform.cc:139 +#, c-format +msgid "degrees: %.1f" +msgstr "Grados: %.1f" + +#: f.transform.cc:286 +msgid "gold" +msgstr "" + +#: f.transform.cc:334 +msgid "Drag middle to move, drag corners to resize." +msgstr "" + +#: f.transform.cc:348 fotoxx-12.01.cc:253 +msgid "Trim Image" +msgstr "Recortar imagen" + +#: f.transform.cc:348 +msgid "customize" +msgstr "" + +#: f.transform.cc:359 +msgid "ratio" +msgstr "" + +#: f.transform.cc:363 +msgid "Lock Ratio" +msgstr "Bloquear la relación" + +#: f.transform.cc:368 +msgid "invert" +msgstr "" + +#: f.transform.cc:890 +msgid "Trim Buttons" +msgstr "" + +#: f.transform.cc:1064 +msgid "Lock aspect ratio" +msgstr "Bloquar la relación de aspecto" + +#: f.transform.cc:1072 fotoxx-12.01.cc:255 +msgid "Resize Image" +msgstr "Redimensionar imagen" + +#: f.transform.cc:1095 fotoxx-12.01.cc:326 +msgid "Prev" +msgstr "Anterior" + +#: f.transform.cc:1245 +msgid "" +"Enter text, click/drag on image.\n" +"Right click to remove" +msgstr "" + +#: f.transform.cc:1294 fotoxx-12.01.cc:256 +msgid "Annotate Image" +msgstr "" + +#: f.transform.cc:1307 +msgid "Size" +msgstr "Tamaño" + +#: f.transform.cc:1310 +msgid "Angle" +msgstr "" + +#: f.transform.cc:1321 fotoxx.h:741 +msgid "Color" +msgstr "" + +#: f.transform.cc:1322 +msgid "Transparency" +msgstr "" + +#: f.transform.cc:1325 +msgid "text" +msgstr "" + +#: f.transform.cc:1330 +msgid "backing" +msgstr "" + +#: f.transform.cc:1333 +msgid "" +"Outline\n" +" Width" +msgstr "" + +#: f.transform.cc:1335 +msgid "outline" +msgstr "" + +#: f.transform.cc:1342 +msgid "Annotation File:" +msgstr "" + +#: f.transform.cc:1416 +msgid "select font" +msgstr "" + +#: f.transform.cc:2045 fotoxx-12.01.cc:257 +msgid "Flip Image" +msgstr "" + +#: f.transform.cc:2049 f.transform.cc:2281 +msgid "horizontal" +msgstr "Horizontal" + +#: f.transform.cc:2050 f.transform.cc:2280 +msgid "vertical" +msgstr "Vertical" + +#: f.transform.cc:2155 fotoxx-12.01.cc:258 +msgid "Make Negative" +msgstr "" + +#: f.transform.cc:2158 +msgid "black/white positive" +msgstr "" + +#: f.transform.cc:2159 +msgid "black/white negative" +msgstr "" + +#: f.transform.cc:2160 +msgid "color positive" +msgstr "" + +#: f.transform.cc:2161 +msgid "color negative" +msgstr "" + +#: f.transform.cc:2272 fotoxx-12.01.cc:259 +msgid "Unbend Image" +msgstr "Enderezar imagen" + +#: f.transform.cc:2282 +msgid "linear" +msgstr "" + +#: f.transform.cc:2285 +msgid "curved" +msgstr "" + +#: f.transform.cc:2544 +msgid "" +" Click the four corners of a tetragon area. Press [apply]. \n" +" The image is warped to make the tetragon into a rectangle." +msgstr "" + +#: f.transform.cc:2556 fotoxx-12.01.cc:260 +msgid "Keystone Correction" +msgstr "" + +#: f.transform.cc:2724 +msgid "must have 4 corners" +msgstr "" + +#: f.transform.cc:2847 +msgid "" +" Select an area to warp using select area function. \n" +" Press [start warp] and pull area with mouse. \n" +" Make multiple mouse pulls until satisfied. \n" +" When finished, select another area or press [done]." +msgstr "" +" Seleccione una área para deformar utilizando el botón [Seleccionar]. \n" +" Pulse [Comenzar deformación] y tire de la área con el ratón. \n" +" Hacer varios tirones con el ratón hasta que quede satisfecho. \n" +" Cuando haya terminado, seleccione otra área o pulse [Hecho]." + +#: f.transform.cc:2859 fotoxx-12.01.cc:261 +msgid "Warp Image (area)" +msgstr "" + +#: f.transform.cc:2864 +msgid "start warp" +msgstr "Comenzar deformación" + +#: f.transform.cc:2931 +msgid "no active Select Area" +msgstr "" + +#: f.transform.cc:3099 f.transform.cc:3362 +msgid "" +" Pull an image position using the mouse. \n" +" Make multiple mouse pulls until satisfied. \n" +" When finished, press [done]." +msgstr "" + +#: f.transform.cc:3112 fotoxx-12.01.cc:262 +msgid "Warp Image (curved)" +msgstr "" + +#: f.transform.cc:3375 fotoxx-12.01.cc:263 +msgid "Warp Image (linear)" +msgstr "" + +#: f.transform.cc:3628 +msgid "" +" Pull on an image corner using the mouse. \n" +" Make multiple mouse pulls until satisfied. \n" +" When finished, press [done]." +msgstr "" +" Tirar de un borde de la imagen utilizando el ratón. \n" +" Hacer varios tirones con el ratón hasta que quede satisfecho. \n" +" Cuando haya terminado, pulse [Hecho]." + +#: f.transform.cc:3639 fotoxx-12.01.cc:264 +msgid "Warp Image (affine)" +msgstr "" + +#: fotoxx-12.01.cc:185 +msgid "File" +msgstr "Archivo" + +#: fotoxx-12.01.cc:186 fotoxx-12.01.cc:324 +msgid "Image Gallery" +msgstr "Galería de imágenes" + +#: fotoxx-12.01.cc:187 +msgid "Clone 50/50" +msgstr "" + +#: fotoxx-12.01.cc:188 +msgid "Clone Overlay" +msgstr "" + +#: fotoxx-12.01.cc:190 +msgid "Open in New Window" +msgstr "" + +#: fotoxx-12.01.cc:191 fotoxx-12.01.cc:326 +msgid "Open Previous File" +msgstr "Abrir archivo anterior" + +#: fotoxx-12.01.cc:192 +msgid "Open Recent File" +msgstr "Abrir archivo reciente" + +#: fotoxx-12.01.cc:193 fotoxx-12.01.cc:334 +msgid "Save to Same File" +msgstr "Guardar en el mismo archivo" + +#: fotoxx-12.01.cc:194 fotoxx-12.01.cc:335 +msgid "Save to New Version" +msgstr "" + +#: fotoxx-12.01.cc:195 fotoxx-12.01.cc:336 +msgid "Save to New File" +msgstr "Guardar en un archivo nuevo" + +#: fotoxx-12.01.cc:197 +msgid "Trash Image File" +msgstr "Mover imagen a la papelera" + +#: fotoxx-12.01.cc:199 +msgid "Batch Rename Files" +msgstr "" + +#: fotoxx-12.01.cc:200 +msgid "Print Image File" +msgstr "Imprimir archivo de imagen" + +#: fotoxx-12.01.cc:201 fotoxx-12.01.cc:340 +msgid "Quit fotoxx" +msgstr "Salir de Fotoxx" + +#: fotoxx-12.01.cc:203 +msgid "Tools" +msgstr "Herramientas" + +#: fotoxx-12.01.cc:206 +msgid "Batch Convert" +msgstr "" + +#: fotoxx-12.01.cc:207 +msgid "Convert RAW files" +msgstr "Convetir múltiples archivos RAW" + +#: fotoxx-12.01.cc:212 +msgid "Burn Images to CD/DVD" +msgstr "Grabar imágenes en un CD/DVD" + +#: fotoxx-12.01.cc:214 +msgid "Check Monitor" +msgstr "Comprobar monitor" + +#: fotoxx-12.01.cc:217 +msgid "Change Language" +msgstr "Cambiar el idioma" + +#: fotoxx-12.01.cc:219 +msgid "Menu and Launcher" +msgstr "" + +#: fotoxx-12.01.cc:220 +msgid "User Settings" +msgstr "" + +#: fotoxx-12.01.cc:221 +msgid "Memory Usage" +msgstr "" + +#: fotoxx-12.01.cc:224 +msgid "Edit Caption/Comments" +msgstr "" + +#: fotoxx-12.01.cc:229 +msgid "View Info (short)" +msgstr "" + +#: fotoxx-12.01.cc:230 +msgid "View Info (long)" +msgstr "" + +#: fotoxx-12.01.cc:233 +msgid "Search Images" +msgstr "" + +#: fotoxx-12.01.cc:234 +msgid "Search Metadata" +msgstr "" + +#: fotoxx-12.01.cc:236 fotoxx-12.01.cc:237 fotoxx.h:786 +msgid "Select" +msgstr "" + +#: fotoxx-12.01.cc:238 fotoxx.h:788 +msgid "Show" +msgstr "Mostrar" + +#: fotoxx-12.01.cc:239 fotoxx.h:761 +msgid "Hide" +msgstr "Ocultar" + +#: fotoxx-12.01.cc:240 fotoxx.h:752 +msgid "Enable" +msgstr "" + +#: fotoxx-12.01.cc:241 fotoxx.h:748 +msgid "Disable" +msgstr "Desactivar" + +#: fotoxx-12.01.cc:242 fotoxx.h:763 +msgid "Invert" +msgstr "Invertir" + +#: fotoxx-12.01.cc:243 fotoxx.h:796 +msgid "Unselect" +msgstr "" + +#: fotoxx-12.01.cc:244 fotoxx.h:743 +msgid "Copy" +msgstr "" + +#: fotoxx-12.01.cc:245 fotoxx.h:771 +msgid "Paste" +msgstr "" + +#: fotoxx-12.01.cc:247 fotoxx-12.01.cc:334 fotoxx.h:783 +msgid "Save" +msgstr "Guardar" + +#: fotoxx-12.01.cc:249 +msgid "Select and Edit" +msgstr "" + +#: fotoxx-12.01.cc:251 +msgid "Transform" +msgstr "" + +#: fotoxx-12.01.cc:254 +msgid "Auto-Trim Image" +msgstr "" + +#: fotoxx-12.01.cc:266 +msgid "Retouch" +msgstr "Retocar" + +#: fotoxx-12.01.cc:267 +msgid "Brightness/Color" +msgstr "Ajustar brillo y color" + +#: fotoxx-12.01.cc:268 +msgid "Gamma Curves" +msgstr "" + +#: fotoxx-12.01.cc:269 +msgid "Expand Brightness" +msgstr "" + +#: fotoxx-12.01.cc:270 +msgid "Flatten Brightness" +msgstr "Distribuir el brillo uniformemente" + +#: fotoxx-12.01.cc:271 +msgid "Brightness Ramp" +msgstr "" + +#: fotoxx-12.01.cc:273 +msgid "White Balance" +msgstr "Balance de blanco" + +#: fotoxx-12.01.cc:274 +msgid "Match Colors" +msgstr "" + +#: fotoxx-12.01.cc:277 +msgid "Red Eyes" +msgstr "Ojos rojos" + +#: fotoxx-12.01.cc:278 +msgid "Blur Image" +msgstr "Imagen borrosa" + +#: fotoxx-12.01.cc:280 +msgid "Reduce Noise" +msgstr "Reducción de ruido" + +#: fotoxx-12.01.cc:286 +msgid "Art" +msgstr "Arte" + +#: fotoxx-12.01.cc:287 +msgid "Color Depth" +msgstr "Profundidad de color" + +#: fotoxx-12.01.cc:288 +msgid "Drawing" +msgstr "" + +#: fotoxx-12.01.cc:289 +msgid "Outlines" +msgstr "" + +#: fotoxx-12.01.cc:290 +msgid "Embossing" +msgstr "" + +#: fotoxx-12.01.cc:291 +msgid "Tiles" +msgstr "" + +#: fotoxx-12.01.cc:292 +msgid "Dots" +msgstr "" + +#: fotoxx-12.01.cc:293 +msgid "Painting" +msgstr "" + +#: fotoxx-12.01.cc:295 +msgid "Combine" +msgstr "Combinar" + +#: fotoxx-12.01.cc:296 +msgid "High Dynamic Range" +msgstr "" + +#: fotoxx-12.01.cc:297 +msgid "High Depth of Field" +msgstr "" + +#: fotoxx-12.01.cc:298 +msgid "Stack / Paint" +msgstr "" + +#: fotoxx-12.01.cc:299 +msgid "Stack / Noise" +msgstr "" + +#: fotoxx-12.01.cc:300 +msgid "Panorama" +msgstr "Panoramica" + +#: fotoxx-12.01.cc:301 +msgid "Vertical Panorama" +msgstr "" + +#: fotoxx-12.01.cc:304 +msgid "Edit Plugins" +msgstr "" + +#: fotoxx-12.01.cc:313 fotoxx-12.01.cc:341 fotoxx-12.01.cc:3026 +msgid "Help" +msgstr "Ayuda" + +#: fotoxx-12.01.cc:314 fotoxx-12.01.cc:3016 +msgid "About" +msgstr "Acerca de" + +#: fotoxx-12.01.cc:315 fotoxx-12.01.cc:3020 +msgid "User Guide" +msgstr "Guía de usuario" + +#: fotoxx-12.01.cc:316 fotoxx-12.01.cc:3023 +msgid "User Guide Changes" +msgstr "" + +#: fotoxx-12.01.cc:317 fotoxx-12.01.cc:3032 +msgid "Edit Functions Summary" +msgstr "" + +#: fotoxx-12.01.cc:318 fotoxx-12.01.cc:3035 +msgid "Change Log" +msgstr "Editar el registro" + +#: fotoxx-12.01.cc:319 fotoxx-12.01.cc:3038 +msgid "Translations" +msgstr "" + +#: fotoxx-12.01.cc:320 fotoxx-12.01.cc:3041 +msgid "Home Page" +msgstr "Página de inicio" + +#: fotoxx-12.01.cc:324 +msgid "Gallery" +msgstr "Galería" + +#: fotoxx-12.01.cc:327 fotoxx.h:767 +msgid "Next" +msgstr "Siguiente" + +#: fotoxx-12.01.cc:327 +msgid "Open Next File" +msgstr "Abrir siguiente archivo" + +#: fotoxx-12.01.cc:328 +msgid "Zoom-in (bigger)" +msgstr "Zoom ampliar" + +#: fotoxx-12.01.cc:329 +msgid "Zoom-out (smaller)" +msgstr "Zoom reducir" + +#: fotoxx-12.01.cc:330 fotoxx.h:794 +msgid "Undo" +msgstr "Deshacer" + +#: fotoxx-12.01.cc:330 +msgid "Undo One Edit" +msgstr "Deshacer un paso" + +#: fotoxx-12.01.cc:331 fotoxx.h:779 +msgid "Redo" +msgstr "Rehacer" + +#: fotoxx-12.01.cc:331 +msgid "Redo One Edit" +msgstr "Rehacer un paso" + +#: fotoxx-12.01.cc:335 +msgid "Save+V" +msgstr "" + +#: fotoxx-12.01.cc:336 +msgid "Save+F" +msgstr "" + +#: fotoxx-12.01.cc:337 +msgid "Move Image to Trash" +msgstr "Enviar la imagen a la papelera" + +#: fotoxx-12.01.cc:337 +msgid "Trash" +msgstr "Papelera" + +#: fotoxx-12.01.cc:340 +msgid "Quit" +msgstr "Salir" + +#: fotoxx-12.01.cc:341 +msgid "Fotoxx Essentials" +msgstr "" + +#: fotoxx-12.01.cc:448 +msgid "first time startup" +msgstr "" + +#: fotoxx-12.01.cc:1944 +msgid "Exceed 50 anchor points" +msgstr "Se exceden los 50 puntos de anclaje" + +#: fotoxx-12.01.cc:2129 +msgid "load curve from a file" +msgstr "" + +#: fotoxx-12.01.cc:2182 +msgid "curve file is invalid" +msgstr "" + +#: fotoxx-12.01.cc:2187 +msgid "curve file has different no. of curves" +msgstr "" + +#: fotoxx-12.01.cc:2202 +msgid "save curve to a file" +msgstr "" + +#: fotoxx-12.01.cc:2337 +msgid "cannot parallel edit" +msgstr "" + +#: fotoxx-12.01.cc:2347 +msgid "" +"exiftool is not installed \n" +"edited images will lose EXIF data" +msgstr "" +"El paquete «exiftool» no está instalado \n" +"al editar las imagenes se perderan los datos EXIF" + +#: fotoxx-12.01.cc:2353 +msgid "Too many edits, please save image" +msgstr "" + +#: fotoxx-12.01.cc:2358 +msgid "" +"Select area cannot be kept.\n" +"Continue?" +msgstr "" +"No se puede conservar la selección de área.\n" +"¿Continuar?" + +#: fotoxx-12.01.cc:2366 +msgid "" +"Select area not active.\n" +"Continue?" +msgstr "" + +#: fotoxx-12.01.cc:2837 +msgid "Discard edits?" +msgstr "" + +#: fotoxx-12.01.cc:2838 +msgid "" +"This action will discard current edits.\n" +"Continue to discard edits.\n" +"Go Back to keep edits." +msgstr "" + +#: fotoxx-12.01.cc:2841 +msgid "Continue" +msgstr "" + +#: fotoxx-12.01.cc:2842 +msgid "Go Back" +msgstr "" + +#: fotoxx-12.01.cc:3659 +msgid "cannot open thumbnail file" +msgstr "" + +#: fotoxx-12.01.cc:3870 fotoxx-12.01.cc:3992 +msgid "TIFF open failure" +msgstr "" + +#: fotoxx-12.01.cc:3886 +#, c-format +msgid "TIFF bits/color=%d not supported" +msgstr "" + +#: fotoxx-12.01.cc:3901 fotoxx-12.01.cc:3939 +msgid "TIFF read failure" +msgstr "" + +#: fotoxx-12.01.cc:4051 +msgid "TIFF write failure" +msgstr "" + +#: fotoxx-12.01.cc:4071 +msgid "file type not supported" +msgstr "" + +#: fotoxx-12.01.cc:4178 +msgid "pixbuf write failure" +msgstr "" + +#: fotoxx.h:728 +msgid "absolute" +msgstr "" + +#: fotoxx.h:730 +msgid "Add All" +msgstr "Añadir todo" + +#: fotoxx.h:732 +msgid "Amount" +msgstr "" + +#: fotoxx.h:733 +msgid "Apply" +msgstr "Aplicar" + +#: fotoxx.h:734 +msgid "Black" +msgstr "" + +#: fotoxx.h:735 +msgid "Blend Width" +msgstr "Mezclar por ancho" + +#: fotoxx.h:737 +msgid "Brightness" +msgstr "Brillo" + +#: fotoxx.h:738 +msgid "Browse" +msgstr "" + +#: fotoxx.h:739 +msgid "Cancel" +msgstr "Cancelar" + +#: fotoxx.h:740 +msgid "Clear" +msgstr "Limpiar" + +#: fotoxx.h:742 +msgid "Commit" +msgstr "" + +#: fotoxx.h:744 +msgid "Curve File:" +msgstr "" + +#: fotoxx.h:745 +msgid "Cut" +msgstr "" + +#: fotoxx.h:746 +msgid "Darker Areas" +msgstr "Oscurecer áreas" + +#: fotoxx.h:747 +msgid "Delete" +msgstr "Borrar" + +#: fotoxx.h:749 +#, c-format +msgid "" +"Discard special gallery list? \n" +" %s" +msgstr "" + +#: fotoxx.h:750 +msgid "Done" +msgstr "Hecho" + +#: fotoxx.h:751 +msgid "Edit" +msgstr "Editar" + +#: fotoxx.h:753 +msgid "Erase" +msgstr "" + +#: fotoxx.h:754 +msgid "package libimage-exiftool-perl is required" +msgstr "" + +#: fotoxx.h:755 +msgid "Fetch" +msgstr "" + +#: fotoxx.h:756 +msgid "Finish" +msgstr "Terminar" + +#: fotoxx.h:757 +msgid "Font" +msgstr "" + +#: fotoxx.h:759 +msgid "Height" +msgstr "Altura" + +#: fotoxx.h:760 +msgid "histogram" +msgstr "" + +#: fotoxx.h:762 +msgid "Insert" +msgstr "Insertar" + +#: fotoxx.h:764 +msgid "Lighter Areas" +msgstr "Iluminar áreas" + +#: fotoxx.h:765 +msgid "limit" +msgstr "" + +#: fotoxx.h:766 +msgid "New" +msgstr "" + +#: fotoxx.h:768 +msgid "OK" +msgstr "Conforme" + +#: fotoxx.h:772 +msgid "Pause" +msgstr "" + +#: fotoxx.h:773 +msgid "Percent" +msgstr "Porcentaje" + +#: fotoxx.h:774 +msgid "Presets" +msgstr "Predefinidos" + +#: fotoxx.h:775 +msgid "Proceed" +msgstr "Proceder" + +#: fotoxx.h:777 +msgid "range" +msgstr "" + +#: fotoxx.h:780 +msgid "Reduce" +msgstr "Reducir" + +#: fotoxx.h:782 +msgid "Reset" +msgstr "" + +#: fotoxx.h:784 +msgid "Unknown file type, save as tiff/jpeg/png to edit" +msgstr "Tipo de fichero desconocido, guarde como tiff/jpeg/png para editarlo" + +#: fotoxx.h:785 +msgid "Search" +msgstr "Buscar" + +#: fotoxx.h:789 +msgid "Start" +msgstr "Comenzar" + +#: fotoxx.h:790 +msgid "Threshold" +msgstr "" + +#: fotoxx.h:791 +#, c-format +msgid "exceed %d files" +msgstr "" + +#: fotoxx.h:792 +msgid "Undo All" +msgstr "Deshacer todo" + +#: fotoxx.h:793 +msgid "Undo Last" +msgstr "Deshacer el último" + +#: fotoxx.h:795 +msgid "Unfinish" +msgstr "" + +#: fotoxx.h:797 +msgid "View" +msgstr "" + +#: fotoxx.h:798 +msgid "White" +msgstr "" + +#: fotoxx.h:799 +msgid "Width" +msgstr "Ancho" + +#: zfuncs.cc:3252 +#, c-format +msgid "help file not found: %s" +msgstr "Archivo de ayuda no encontrado: %s" + +#: zfuncs.cc:3664 zfuncs.cc:7315 +#, c-format +msgid "cannot open file %s" +msgstr "No puedo abrir el archivo %s" + +#: zfuncs.cc:3697 +msgid "save screen to file" +msgstr "Guardar pantalla a archivo" + +#: zfuncs.cc:6222 +msgid "No" +msgstr "" + +#: zfuncs.cc:6222 +msgid "Yes" +msgstr "" + +#: zfuncs.cc:6447 +msgid "open" +msgstr "Abrir" + +#: zfuncs.cc:6452 +msgid "choose" +msgstr "" + +#: zfuncs.cc:6457 +msgid "save" +msgstr "Guardar" + +#: zfuncs.cc:6463 +msgid "open folder" +msgstr "Abrir carpeta" + +#: zfuncs.cc:6468 +msgid "create folder" +msgstr "Crear carpeta" + +#: zfuncs.cc:6474 +msgid "hidden" +msgstr "Ocultar" + +#: zfuncs.cc:6535 +msgid "JPG quality 0-100" +msgstr "Calidad de JPG 0-100" + +#: zfuncs.cc:6728 zfuncs.cc:6741 +msgid "margins" +msgstr "" + +#: zfuncs.cc:6737 +msgid "top" +msgstr "" + +#: zfuncs.cc:6738 +msgid "bottom" +msgstr "" + +#: zfuncs.cc:6739 +msgid "left" +msgstr "" + +#: zfuncs.cc:6740 +msgid "right" +msgstr "" + +#: zfuncs.cc:7202 +msgid "" +"Initial parameters file created. \n" +"Inspect and revise if necessary." +msgstr "" +"Parámetros iniciales creados. \n" +"Revíselos si lo desea." + +#: zfuncs.cc:7218 +msgid "load parameters from a file" +msgstr "Cargar parámetros desde archivo" + +#: zfuncs.cc:7287 +msgid "save parameters to a file" +msgstr "Guardar parámetros a un archivo" + +#: zfuncs.cc:7425 zfuncs.cc:7431 zfuncs.cc:7437 zfuncs.cc:7443 +msgid "edit parameters" +msgstr "Editar parámetros" + +#: zfuncs.cc:7426 zfuncs.cc:7432 +msgid "" +"list\n" +"all" +msgstr "" +"Listar\n" +"Todo" + +#: zfuncs.cc:7426 zfuncs.cc:7432 zfuncs.cc:7438 zfuncs.cc:7444 +msgid "" +"load\n" +"file" +msgstr "" +"Cargar\n" +"Archivo" + +#: zfuncs.cc:7426 zfuncs.cc:7432 zfuncs.cc:7438 zfuncs.cc:7444 +msgid "" +"save\n" +"file" +msgstr "" +"Guardar\n" +"Archivo" + +#: zfuncs.cc:7427 zfuncs.cc:7439 +msgid "" +"add\n" +"new" +msgstr "" +"Añadir\n" +"Nuevo" + +#: zfuncs.cc:7427 zfuncs.cc:7433 zfuncs.cc:7439 zfuncs.cc:7445 +msgid "apply" +msgstr "Aplicar" + +#: zfuncs.cc:7479 +msgid "apply?" +msgstr "¿Aplicar?" + +#: zfuncs.cc:7536 +msgid "(new parm name)" +msgstr "(Nuevo parámetro)" + +#: zfuncs.cc:7536 +msgid "add parameter" +msgstr "Añadir parámetro" + +#~ msgid "Brightness Graph" +#~ msgstr "Gráfica de brillo" + +#~ msgid "radius" +#~ msgstr "Radio" + +#~ msgid "Search results file error %s" +#~ msgstr "Error en los resultados de la búsqueda %s" + +#~ msgid "Select area first" +#~ msgstr "Debe seleccionar primero el área" + +#~ msgid "close thumbnail window" +#~ msgstr "Cerrar Índice de miniaturas" + +#~ msgid "file" +#~ msgstr "Archivo" + +#~ msgid "folder" +#~ msgstr "carpeta" + +#~ msgid "jump to specific file" +#~ msgstr "Cambia a un archivo específico" + +#~ msgid "open a directory" +#~ msgstr "Abrir un directorio" + +#~ msgid "select new folder" +#~ msgstr "Seleccionar nueva carpeta" + +#~ msgid "xdg-utils package not installed" +#~ msgstr "El paquete «xdg-utils» no está instalado" + +#~ msgid "open a file" +#~ msgstr "Abrir un fichero" + +#~ msgid "Time Interval" +#~ msgstr "Intervalo de tiempo" + +#~ msgid "Clone fotoxx" +#~ msgstr "Clonar Fotoxx" + +#~ msgid "Save As" +#~ msgstr "Guardar como" + +#~ msgid "Create Launcher" +#~ msgstr "Crear un lanzador" + +#~ msgid "horizontal unbend" +#~ msgstr "Enderezamiento horizontal" + +#~ msgid "vertical unbend" +#~ msgstr "Enderezamiento vertical" + +#~ msgid "target group area" +#~ msgstr "Área de grupo de destino" + +#~ msgid "Area" +#~ msgstr "Área" + +#~ msgid "HDF" +#~ msgstr "HDF" + +#~ msgid "HDR" +#~ msgstr "HDR" + +#~ msgid "/path*/file*" +#~ msgstr "/ruta*/archivo*" + +#~ msgid "All EXIF data" +#~ msgstr "Todos los datos EXIF" + +#~ msgid "Basic EXIF data" +#~ msgstr "Datos EXIF básicos" + +#~ msgid "Resume" +#~ msgstr "Reanudar" + +#~ msgid "Search Tags" +#~ msgstr "Buscar etiquetas" + +#~ msgid "Set Tile and Gap Size" +#~ msgstr "Configurar mosaico y tamaño de la separación" + +#~ msgid "Suspend" +#~ msgstr "Suspender" + +#~ msgid "Tags" +#~ msgstr "Etiquetas" + +#~ msgid "match all tags" +#~ msgstr "Elegir todas las etiquetas" + +#~ msgid "match any tag" +#~ msgstr "Elegir cualquier etiqueta" + +#~ msgid "" +#~ " Pull on an image edge using the mouse. \n" +#~ " Make multiple mouse pulls until satisfied. \n" +#~ " When finished, press [done]." +#~ msgstr "" +#~ " Tirar de un borde de la imagen utilizando el ratón. \n" +#~ " Hacer varios tirones con el ratón hasta que quede satisfecho. \n" +#~ " Cuando haya terminado, pulse [Hecho]." + +#~ msgid "Warp Area" +#~ msgstr "Deformación de área" + +#~ msgid "Warp Image in Selected Area" +#~ msgstr "Deformar imagen en el área seleccionada" + +#~ msgid "color intensity" +#~ msgstr "Intensidad de color" + +#~ msgid "Burn" +#~ msgstr "Grabar" + +#~ msgid "Fix Image Perspective" +#~ msgstr "Fijar imagen en perspectiva" + +#~ msgid "add tags" +#~ msgstr "Etiquetas asignadas" + +#~ msgid "color range" +#~ msgstr "Rango de color" + +#~ msgid "" +#~ "\n" +#~ " Match Brightness and Color" +#~ msgstr "" +#~ "\n" +#~ " Ensamblar la luminosidad y el color" + +#~ msgid "Auto" +#~ msgstr "Auto" + +#~ msgid "Auto-search lens mm and bow" +#~ msgstr "Busqueda automática de lente mm y curva" + +#~ msgid "" +#~ "Drag right image into rough alignment with left \n" +#~ " to rotate, drag right edge up or down" +#~ msgstr "" +#~ "Arrastre la imagen derecha para alinearla con la de la izquierda \n" +#~ " para rotarla, arrastre del borde hacia arriba o abajo" + +#~ msgid "Match Images" +#~ msgstr "Ensamblar las imágenes" + +#~ msgid "Merge the images together" +#~ msgstr "Mezclar las imágenes en conjunto" + +#~ msgid "Package ufraw required for this function" +#~ msgstr "Se necesita la aplicación «ufraw» para esta función" + +#~ msgid "Retouch Image" +#~ msgstr "Retoque de imagen" + +#~ msgid "Select image to combine" +#~ msgstr "Seleccionar imagen a combinar" + +#~ msgid "" +#~ "\n" +#~ " brightness \n" +#~ " level" +#~ msgstr "" +#~ "\n" +#~ " Brillo \n" +#~ " Nivel" + +#~ msgid "" +#~ " left: no RGB spread (gray) \n" +#~ " middle: normal (unmodified) \n" +#~ " right: maximum RGB spread" +#~ msgstr "" +#~ "izquierda: sin rango RGB (gris) \n" +#~ " centro: normal (sin modificar) \n" +#~ " derecha: rango máximo RGB" + +#~ msgid "" +#~ " left: no color (grey) \n" +#~ " middle: normal (unmodified) \n" +#~ " right: maximum color" +#~ msgstr "" +#~ "izquierda: sin color (gris) \n" +#~ " centro: normal (sin modificar) \n" +#~ " derecha: máximo color" + +#~ msgid " adjust red" +#~ msgstr " Ajuste rojo" + +#~ msgid " blue" +#~ msgstr " Azul" + +#~ msgid " green" +#~ msgstr " Verde" + +#~ msgid "" +#~ " Set color depth to 1-8 bits per color. \n" +#~ " Press [apply] to update the image." +#~ msgstr "" +#~ " Establece la profundidad de color a 1-8 bits por color, \n" +#~ " entonces presiona [Aplicar] para actualizar la imagen." + +#~ msgid " color balance blue " +#~ msgstr " balance de color azul" + +#~ msgid " color balance green " +#~ msgstr " balance de color verde" + +#~ msgid " color balance red " +#~ msgstr " balance de color rojo" + +#~ msgid "2nd file is not compatible with 1st" +#~ msgstr "Segundo archivo no compatible con el primero" + +#~ msgid "2nd image not same size as 1st image" +#~ msgstr "La 2ª imagen no tiene el mismo tamaño que la 1ª" + +#~ msgid "Adjust Saturation (RGB spread)" +#~ msgstr "Ajuste de saturación (rango RGB)" + +#~ msgid "Assigned tags file error: %s" +#~ msgstr "Error al asignar etiquetas de archivo: %s" + +#~ msgid "Bend" +#~ msgstr "Mezcla" + +#, fuzzy +#~ msgid "Blend Area Edges" +#~ msgstr "Radio de desenfoque" + +#~ msgid "Brightness/Contrast/Color" +#~ msgstr "Brillo/Contraste/Color" + +#~ msgid "Brightness/Whiteness" +#~ msgstr "Ajustar brillo / claridad" + +#~ msgid "Build Tags Index" +#~ msgstr "Construir índice de etiquetas" + +#~ msgid "Clear Select Area" +#~ msgstr "Limpiar área seleccionada" + +#~ msgid "Color Intensity" +#~ msgstr "Intensidad de color" + +#~ msgid "Composite Images" +#~ msgstr "Composición de imágenes" + +#~ msgid "Convert multiple RAWs" +#~ msgstr "Convertir múltiples RAW" + +#~ msgid "" +#~ "Convert raw file to 48-bit tiff format? \n" +#~ " (this may take a while) " +#~ msgstr "" +#~ "¿Convertir archivos RAW a formato tiff de 48 bits?\n" +#~ " (esto puede tardar un poco)" + +#~ msgid "Delete Area" +#~ msgstr "Borrar área" + +#~ msgid "Delete selected area?" +#~ msgstr "¿Borrar el área seleccionada?" + +#~ msgid "Dimensions" +#~ msgstr "Dimensiones" + +#~ msgid "" +#~ "Distance calculation needs a long time.\n" +#~ " Do you want to continue?" +#~ msgstr "" +#~ "El cálculo de la distancia necesita bastante tiempo.\n" +#~ " ¿Desea continuar?" + +#~ msgid "Distortion" +#~ msgstr "Distorsión" + +#~ msgid "" +#~ "Drag middle to move \n" +#~ "Drag corners to resize" +#~ msgstr "" +#~ "Arrastre desde el interior para mover \n" +#~ "Arrastre las esquinas para redimensionar" + +#~ msgid "Edge Calc" +#~ msgstr "Calcular el borde" + +#~ msgid "Error Log" +#~ msgstr "Registro de errores" + +#~ msgid "FREEIMAGE error: %s" +#~ msgstr "Error en FREEIMAGE: %s" + +#~ msgid "FREEIMAGE unknown error" +#~ msgstr "Error desconocido en FREEIMAGE " + +#, fuzzy +#~ msgid "Flash" +#~ msgstr "Papelera" + +#, fuzzy +#~ msgid "FreeImage" +#~ msgstr "Redimensionar imagen" + +#~ msgid "HDR Image Weights" +#~ msgstr "Peso de la imagen HDR" + +#~ msgid "Hide Area" +#~ msgstr "Ocultar área" + +#~ msgid "Image Weights per Brightness Level" +#~ msgstr "Peso de la imagen por nivel de brillo" + +#~ msgid "Index" +#~ msgstr "Índice" + +#~ msgid "Index (thumbnails)" +#~ msgstr "Índice (miniaturas)" + +#~ msgid "Index Tags and Thumbs" +#~ msgstr "Sincronizar etiquetas y miniaturas" + +#~ msgid "Input Images" +#~ msgstr "Imágenes de entrada" + +#~ msgid "Invert Area" +#~ msgstr "Invertir área" + +#~ msgid "" +#~ "Left click/drag: add to selected area. \n" +#~ "Right click: remove prior selection(s). \n" +#~ "Color range: add more or less at once." +#~ msgstr "" +#~ "Hacer clic en el botón izquierdo y arrastrar: añadir al área " +#~ "seleccionada. \n" +#~ "Hacer clic en botón derecho: quitar la(s) selección(es) previa(s). \n" +#~ "Gama de colores: añadir más o menos a la vez." + +#~ msgid "Make HDF Image" +#~ msgstr "Hacer imagen HDF" + +#~ msgid "Make HDR Image" +#~ msgstr "Hacer imagen HDR" + +#~ msgid "No assigned tags index file" +#~ msgstr "Etiquetas sin asignar al archivo de índice" + +#, fuzzy +#~ msgid "Outline Image Area for Following Edits" +#~ msgstr "Área de la imagen para ediciones siguientes" + +#~ msgid "Output Image" +#~ msgstr "Imagen de salida" + +#~ msgid "Package exiftool is missing" +#~ msgstr "No se encuentra el paquete «exiftool»" + +#~ msgid "Paint Pixels" +#~ msgstr "Pintar píxeles" + +#~ msgid "Print" +#~ msgstr "Imprimir" + +#~ msgid "RAW file template" +#~ msgstr "Plantilla de archivo RAW" + +#~ msgid "README" +#~ msgstr "LEAME" + +#~ msgid "RGB Spread" +#~ msgstr "Rango RGB" + +#~ msgid "RGB spread" +#~ msgstr "Rango RGB" + +#~ msgid "Rotate" +#~ msgstr "Rotar" + +#~ msgid "Save Image as File" +#~ msgstr "Guardar imagen como archivo" + +#~ msgid "Select Area -color" +#~ msgstr "Seleccionar área -color" + +#~ msgid "Select Area -mouse" +#~ msgstr "Seleccionar área -ratón" + +#~ msgid "" +#~ "Select area is not finished.\n" +#~ "Continue without using it?" +#~ msgstr "" +#~ "No se completó la selección de área.\n" +#~ "¿Continuar sin usarla?" + +#~ msgid "Sharp" +#~ msgstr "Enfoque" + +#~ msgid "Show Area" +#~ msgstr "Mostrar área" + +#, fuzzy +#~ msgid "Simulat Mosaic" +#~ msgstr "Simular repujado" + +#, fuzzy +#~ msgid "Simulate Mosaic" +#~ msgstr "Simular repujado" + +#~ msgid "Simulate embossing" +#~ msgstr "Simular un repujado" + +#~ msgid "Special Art Effects" +#~ msgstr "Efectos artísticos especiales" + +#~ msgid "Thumbnail Index" +#~ msgstr "Índice de miniaturas" + +#~ msgid "Too many points" +#~ msgstr "Demasiados puntos" + +#~ msgid "Too many tags: %d" +#~ msgstr "Demasiadas etiquetas: %d" + +#~ msgid "Too many undo buffers, please save image" +#~ msgstr "Demasiados «deshacer» en el búfer, guarde la imagen" + +#~ msgid "Total tags exceed %d characters" +#~ msgstr "El número total de etiquetas excedió en %d caracteres" + +#~ msgid "Tune Image" +#~ msgstr "Afinar la imagen" + +#~ msgid "Unable to copy EXIF data" +#~ msgstr "No se pueden copiar los datos EXIF" + +#, fuzzy +#~ msgid "Unable to replace file" +#~ msgstr "No se puede guardar la imagen" + +#~ msgid "Unable to save image" +#~ msgstr "No se puede guardar la imagen" + +#~ msgid "Unable to save image: %s" +#~ msgstr "No se puede guardar la imagen: %s" + +#~ msgid "Warp" +#~ msgstr "Deformar" + +#~ msgid "Warp Global" +#~ msgstr "Deformación de la imagen" + +#~ msgid "Zoom+" +#~ msgstr "Zoom+" + +#~ msgid "Zoom-" +#~ msgstr "Zoom-" + +#~ msgid "adjust brightness / whiteness" +#~ msgstr "Ajustar brillo / claridad" + +#~ msgid "assigned tags" +#~ msgstr "Etiquetas asignadas" + +#~ msgid "bigger image" +#~ msgstr "Image más grande" + +#~ msgid "blend" +#~ msgstr "Mezcla" + +#~ msgid "blur radius" +#~ msgstr "Radio de desenfoque" + +#~ msgid "brightness distribution" +#~ msgstr "Distribuir el brillo" + +#~ msgid "" +#~ "cannot create %s \n" +#~ " %s" +#~ msgstr "" +#~ "No se puede crear %s \n" +#~ " %s" + +#~ msgid "click or drag trim margins" +#~ msgstr "Haz clic o arrastra el borde" + +#~ msgid "color balance" +#~ msgstr "Balance de color" + +#~ msgid "computing" +#~ msgstr "computing" + +#~ msgid "date range (yyyymmdd)" +#~ msgstr "Formato de fecha (aaaammdd)" + +#~ msgid "defog" +#~ msgstr "Desempañar" + +#, fuzzy +#~ msgid "edge calculation missing" +#~ msgstr "Necesita calcular el borde" + +#~ msgid "exiftool is required to create tags" +#~ msgstr "Se necesita «exiftool» para cear etiquetas" + +#~ msgid "exiftool is required to generate tags index" +#~ msgstr "Se necesita «exiftool» para generar el índice de etiquetas" + +#~ msgid "exiv2 package is required" +#~ msgstr "Se requiere el paquete «exiv2»" + +#~ msgid "" +#~ "file cannot be read: \n" +#~ " %s" +#~ msgstr "" +#~ "No se puede leer el archivo: \n" +#~ " %s" + +#~ msgid "graph" +#~ msgstr "Gráfica" + +#~ msgid "image format error: %s" +#~ msgstr "Error en el formato de la imagen: %s" + +#~ msgid "image not 8 or 16 bits/color: %s" +#~ msgstr "La imagen %s no tiene 8 o 16 bits/color" + +#~ msgid "input image 2" +#~ msgstr "Elegir imagen 2" + +#~ msgid "kill" +#~ msgstr "Cerrar" + +#~ msgid "kill running function" +#~ msgstr "Cerrar función en marcha" + +#~ msgid "open RAW file" +#~ msgstr "Abrir archivo RAW" + +#~ msgid "open image file" +#~ msgstr "Abrir archivo" + +#~ msgid "open new image file" +#~ msgstr "Abrir nuevo archivo" + +#~ msgid "photo date (yyyymmdd)" +#~ msgstr "Fecha de la foto (aaaammdd)" + +#~ msgid "photo stars" +#~ msgstr "Estrellas" + +#~ msgid "prior function still running" +#~ msgstr "Función anterior todavía en marcha" + +#~ msgid "quit" +#~ msgstr "Salir" + +#, fuzzy +#~ msgid "radius limit" +#~ msgstr "Radio" + +#~ msgid "recently added" +#~ msgstr "Recientemente añadido" + +#~ msgid "red" +#~ msgstr "Rojo" + +#~ msgid "redo image changes" +#~ msgstr "Rehacer cambios en imagen" + +#~ msgid "resize image" +#~ msgstr "Redimensionar imagen" + +#~ msgid "rotate image" +#~ msgstr "Rotar imagen" + +#~ msgid "set RGB spread" +#~ msgstr "Establece el rango RGB" + +#, fuzzy +#~ msgid "set blend radius" +#~ msgstr "Establecer radio de desenfoque" + +#~ msgid "set color intensity" +#~ msgstr "Establecer intensidad de color" + +#~ msgid "sharpen image" +#~ msgstr "Enfoque de imagen" + +#, fuzzy +#~ msgid "this area cannot be processed" +#~ msgstr "" +#~ "No se puede conservar la selección de área.\n" +#~ "¿Continuar?" + +#~ msgid "toolbar::save" +#~ msgstr "Guardar" + +#~ msgid "trim image" +#~ msgstr "Recortar imagen" + +#~ msgid "unbend panorama image" +#~ msgstr "Enderezar imagen panorámica" + +#~ msgid "undo image changes" +#~ msgstr "Deshacer cambios en la imagen" + +#~ msgid "unknown image format" +#~ msgstr "Formato de imagen desconocido" + +#~ msgid "whiteness" +#~ msgstr "Aclarar" + +#~ msgid "Discard modifications?" +#~ msgstr "¿Descartar modificaciones?" + +#~ msgid "" +#~ "Rename failed \n" +#~ " %s" +#~ msgstr "" +#~ "Falló el renombrado \n" +#~ " %s" + +#~ msgid "Translate" +#~ msgstr "Traducciones" + +#~ msgid "select new file" +#~ msgstr "Seleccionar archivo nuevo" + +#~ msgid "lens name" +#~ msgstr "Nombre de la lente" + +#~ msgid "Lens Parameters" +#~ msgstr "Parámetros de óptica" diff -Nru fotoxx-11.11.1/locales/fotoxx-fr.po fotoxx-12.01.2/locales/fotoxx-fr.po --- fotoxx-11.11.1/locales/fotoxx-fr.po 1970-01-01 00:00:00.000000000 +0000 +++ fotoxx-12.01.2/locales/fotoxx-fr.po 2012-01-04 08:47:11.000000000 +0000 @@ -0,0 +1,2878 @@ +# translation of fotoxx_merge.po to +# mico , 2008. +# Stanislas Zeller , 2008, 2009, 2010, 2011. +# translation of fotoxx.po to +# #-#-#-#-# fotoxx.po (messages) #-#-#-#-# +# French translations for home package. +# Copyright (C) 2008 THE home'S COPYRIGHT HOLDER +# This file is distributed under the same license as the home package. +msgid "" +msgstr "" +"Project-Id-Version: fotoxx_merge\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-12-31 21:05+0100\n" +"PO-Revision-Date: 2011-01-05 17:07+0100\n" +"Last-Translator: Stanislas Zeller \n" +"Language-Team: \n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: KBabel 1.11.4\n" + +#: f.art.cc:47 +msgid "Set color depth to 1-16 bits" +msgstr "" +"Configurer la profondeur de \n" +"couleurs de 1 à 16 bits." + +#: f.art.cc:57 +msgid "Set Color Depth" +msgstr "Configurer la profondeur de couleurs" + +#: f.art.cc:171 +msgid "Simulate Drawing" +msgstr "Simuler un dessin" + +#: f.art.cc:213 f.retouch.cc:1759 f.retouch.cc:5991 +msgid "contrast" +msgstr "Contraste" + +#: f.art.cc:215 +msgid "outlines" +msgstr "Contours" + +#: f.art.cc:220 +msgid "pencil" +msgstr "Crayon" + +#: f.art.cc:221 +msgid "chalk" +msgstr "Craie" + +#: f.art.cc:381 +msgid "Add Image Outlines" +msgstr "" + +#: f.art.cc:394 +msgid "outline threshold" +msgstr "" + +#: f.art.cc:397 +msgid "outline width" +msgstr "" + +#: f.art.cc:400 +msgid "image brightness" +msgstr "" + +#: f.art.cc:611 +msgid "Simulate Embossing" +msgstr "Simuler un gaufrage" + +#: f.art.cc:626 +msgid "depth" +msgstr "Profondeur" + +#: f.art.cc:628 f.file.cc:919 f.retouch.cc:6692 +msgid "color" +msgstr "Couleur" + +#: f.art.cc:821 +msgid "Simulate Tiles" +msgstr "Simuler des tuiles" + +#: f.art.cc:825 +msgid "tile size" +msgstr "Taille de la tuile" + +#: f.art.cc:829 +msgid "tile gap" +msgstr "Espace entre les tuiles" + +#: f.art.cc:1003 +msgid "Convert Image to Dots" +msgstr "Convertir l'image en points" + +#: f.art.cc:1007 +msgid "dot size" +msgstr "Taille du point" + +#: f.art.cc:1222 +msgid "Simulate Painting" +msgstr "Simuler une peinture" + +#: f.art.cc:1226 +msgid "color depth" +msgstr "Profondeur de couleurs" + +#: f.art.cc:1230 +msgid "patch area goal" +msgstr "" + +#: f.art.cc:1234 +msgid "req. color match" +msgstr "Correspondance de couleurs requise" + +#: f.art.cc:1238 +msgid "borders" +msgstr "Contours" + +#: f.comp.cc:1956 f.comp.cc:1961 f.comp.cc:2582 f.comp.cc:2587 f.comp.cc:3266 +#: f.comp.cc:3271 f.comp.cc:3816 f.comp.cc:3821 +msgid "Select 2 to 9 files" +msgstr "Sélectionner 2 à 9 fichiers" + +#: f.comp.cc:1982 f.comp.cc:2608 f.comp.cc:3292 f.comp.cc:3842 +msgid "Images are not all the same size" +msgstr "Les images ne sont pas toutes de la même taille" + +#: f.comp.cc:2321 +msgid "Adjust Image Contributions" +msgstr "Ajuster les recouvrements de l'image" + +#: f.comp.cc:2324 f.retouch.cc:886 +msgid "dark pixels" +msgstr "Pixels sombres" + +#: f.comp.cc:2326 +msgid "light pixels" +msgstr "Pixels lumineux" + +#: f.comp.cc:2328 f.info.cc:159 +msgid "file:" +msgstr "Fichier : " + +#: f.comp.cc:2843 +msgid "Paint and Warp Image" +msgstr "" + +#: f.comp.cc:2846 f.comp.cc:3520 f.comp.cc:4959 f.comp.cc:5705 +msgid "image" +msgstr "image" + +#: f.comp.cc:2850 f.retouch.cc:6696 +msgid "paint" +msgstr "Peinture" + +#: f.comp.cc:2851 +msgid "warp" +msgstr "Déformer" + +#: f.comp.cc:3518 +msgid "Select and Paint Image" +msgstr "" + +#: f.comp.cc:4031 +msgid "Adjust Pixel Composition" +msgstr "" + +#: f.comp.cc:4283 f.comp.cc:4288 f.comp.cc:5173 f.comp.cc:5178 +msgid "Select 2 to 4 files" +msgstr "Sélectionner 2 à 4 fichiers" + +#: f.comp.cc:4361 +msgid "" +"Drag images into rough alignment.\n" +"To rotate, drag from lower edge." +msgstr "" + +#: f.comp.cc:4363 +msgid "Search for lens mm and bow" +msgstr "Rechercher les valeurs « lens mm / bow »" + +#: f.comp.cc:4409 f.comp.cc:5298 +msgid "Pre-align Images" +msgstr "Images pré alignées" + +#: f.comp.cc:4413 f.comp.cc:5302 +msgid "lens mm" +msgstr "Longueur de la focale (lens_mm)" + +#: f.comp.cc:4417 f.comp.cc:5306 +msgid "lens bow" +msgstr "Courbe d'objectif (lens_bow)" + +#: f.comp.cc:4419 f.comp.cc:5308 +msgid "Resize" +msgstr "Redimensionner" + +#: f.comp.cc:4420 f.comp.cc:5309 +msgid "resize window" +msgstr "Redimensionner la fenêtre" + +#: f.comp.cc:4457 +msgid "use two images only" +msgstr "N'utilisez seulement que deux images" + +#: f.comp.cc:4478 f.comp.cc:4676 f.comp.cc:4875 f.comp.cc:5357 f.comp.cc:5620 +msgid "Too little overlap, cannot align" +msgstr "Trop de chevauchements, impossible d'aligner." + +#: f.comp.cc:4950 f.comp.cc:5696 +msgid "Match Brightness and Color" +msgstr "Correspondance de la luminosité et de la couleur" + +#: f.comp.cc:4974 f.comp.cc:5720 +msgid "auto color" +msgstr "Couleur auto." + +#: f.comp.cc:4975 f.comp.cc:5721 +msgid "file color" +msgstr "Couleur du fichier" + +#: f.comp.cc:5251 +msgid "" +"Drag images into rough alignment.\n" +"To rotate, drag from right edge." +msgstr "" + +#: f.file.cc:169 f.file.cc:341 fotoxx-12.01.cc:189 fotoxx-12.01.cc:325 +msgid "Open Image File" +msgstr "Ouvrir une image" + +#: f.file.cc:321 fotoxx-12.01.cc:2862 +msgid "prior function still active" +msgstr "" + +#: f.file.cc:503 +msgid "Overwrite original file?" +msgstr "" + +#: f.file.cc:504 +msgid "Do not warn again" +msgstr "" + +#: f.file.cc:520 +msgid "Warning" +msgstr "" + +#: f.file.cc:643 +msgid "Save File" +msgstr "Enregistrer le fichier" + +#: f.file.cc:666 zfuncs.cc:6478 +msgid "quality" +msgstr "Qualité" + +#: f.file.cc:668 +msgid "make current" +msgstr "" + +#: f.file.cc:725 +msgid "jpeg quality must be 1-100" +msgstr "La qualité du JPEG doit être compris entre 1 et 100" + +#: f.file.cc:747 +#, c-format +msgid "" +"Overwrite file? \n" +" %s" +msgstr "" +"Écraser le fichier ? \n" +" %s" + +#: f.file.cc:903 fotoxx-12.01.cc:196 +msgid "Create Blank Image" +msgstr "Créer une image vide" + +#: f.file.cc:905 +msgid "file name" +msgstr "" + +#: f.file.cc:910 f.transform.cc:353 +msgid "width" +msgstr "Largeur" + +#: f.file.cc:913 f.tools.cc:477 f.transform.cc:356 +msgid "height" +msgstr "Hauteur" + +#: f.file.cc:1033 +msgid "" +"Linux standard trash is not supported. \n" +"Desktop trash folder will be created." +msgstr "" +"La corbeille standard Linux n'est pas prise ne charge? \n" +"Un dossier corbeille sera créé." + +#: f.file.cc:1051 +msgid "Move read-only file to trash?" +msgstr "Déplacer le fichier en lecture-seule vers la corbeille ?" + +#: f.file.cc:1077 +#, c-format +msgid "Cannot create trash folder: %s" +msgstr "Impossible de créer le dossier corbeille : %s" + +#: f.file.cc:1085 f.file.cc:1091 zfuncs.cc:3356 +#, c-format +msgid "error: %s" +msgstr "Erreur : %s" + +#: f.file.cc:1136 fotoxx-12.01.cc:198 +msgid "Rename Image File" +msgstr "Renommer l'image" + +#: f.file.cc:1141 +msgid "old name" +msgstr "Ancien nom" + +#: f.file.cc:1142 +msgid "rename to" +msgstr "Renommer en" + +#: f.file.cc:1143 +msgid "previous" +msgstr "Préc." + +#: f.file.cc:1229 +msgid "The target file already exists" +msgstr "Le fichier cible existe toujours" + +#: f.file.cc:1237 +#, c-format +msgid "" +"Rename failed: \n" +" %s" +msgstr "" + +#: f.file.cc:1285 +msgid "Batch Rename" +msgstr "Renommer par lot" + +#: f.file.cc:1288 f.file.cc:1340 f.info.cc:1519 f.info.cc:1773 f.tools.cc:543 +#: f.tools.cc:2990 +#, c-format +msgid "%d files selected" +msgstr "" + +#: f.file.cc:1290 +msgid "new base name" +msgstr "Nouveau nom" + +#: f.file.cc:1293 +msgid "starting sequence" +msgstr "Commence par" + +#: f.file.cc:1295 +msgid "increment" +msgstr "Incrémente de" + +#: f.file.cc:1316 +msgid "select files to rename" +msgstr "Sélectionner les fichiers à renommer" + +#: f.file.cc:1321 +msgid "base name / sequence / increment not reasonable" +msgstr "Une valeur est obligatoire" + +#: f.file.cc:1380 +msgid "new file already exists:" +msgstr "Un nouveau fichier existe toujours : " + +#: f.file.cc:1388 +msgid "filespec too long:" +msgstr "Le fichier « filespec » est trop long" + +#: f.file.cc:1399 +msgid "Rename failed:" +msgstr "Le renommage a échoué : " + +#: f.file.cc:1660 fotoxx.h:729 +msgid "Add" +msgstr "" + +#: f.file.cc:1660 fotoxx.h:781 +msgid "Remove" +msgstr "" + +#: f.file.cc:1662 +msgid "menu name" +msgstr "" + +#: f.file.cc:1733 f.file.cc:1754 +msgid "Restart Fotoxx to update plugin menu" +msgstr "" + +#: f.info.cc:70 +msgid "Edit Caption and Comments" +msgstr "" + +#: f.info.cc:156 fotoxx-12.01.cc:225 +msgid "Edit Tags" +msgstr "Modifier les étiquettes" + +#: f.info.cc:163 +msgid "image date (yyyymmdd)" +msgstr "Date (aaaa-mm-jj)" + +#: f.info.cc:165 +msgid "use last" +msgstr "Dernière utilisation" + +#: f.info.cc:168 +msgid "image stars" +msgstr "Note de l'image" + +#: f.info.cc:186 +msgid "current tags" +msgstr "Étiquettes actuelles" + +#: f.info.cc:191 +msgid "recent tags" +msgstr "Étiquettes récentes" + +#: f.info.cc:196 f.info.cc:358 f.info.cc:1368 f.info.cc:2384 +msgid "defined tags" +msgstr "Définir les étiquettes" + +#: f.info.cc:345 fotoxx-12.01.cc:226 +msgid "Manage Tags" +msgstr "" + +#: f.info.cc:348 +msgid "category" +msgstr "Catégorie" + +#: f.info.cc:351 +msgid "tag" +msgstr "Étiquette" + +#: f.info.cc:354 +msgid "create" +msgstr "Créer" + +#: f.info.cc:355 f.navi.cc:1421 +msgid "delete" +msgstr "Supprimer" + +#: f.info.cc:1235 f.info.cc:1319 +#, c-format +msgid "search index file error: %s" +msgstr "" + +#: f.info.cc:1351 fotoxx-12.01.cc:227 +msgid "Batch Add Tags" +msgstr "Ajouter des étiquettes par lot" + +#: f.info.cc:1354 +msgid "tags to add" +msgstr "Étiquettes à ajouter" + +#: f.info.cc:1359 +msgid "create tag" +msgstr "Créer une étiquette" + +#: f.info.cc:1415 f.info.cc:1608 +#, c-format +msgid "" +"%s \n" +" too many tags" +msgstr "" +"%s \n" +" trop d'étiquettes" + +#: f.info.cc:1553 fotoxx-12.01.cc:228 +msgid "Batch Delete Tag" +msgstr "Supprimer des étiquettes par lot" + +#: f.info.cc:1556 +msgid "tag to remove" +msgstr "Étiquette à supprimer" + +#: f.info.cc:1560 +msgid "optional replacement" +msgstr "Remplacement optionnel" + +#: f.info.cc:1565 f.tools.cc:2943 +msgid "0 files selected" +msgstr "" + +#: f.info.cc:1568 +msgid "search all files" +msgstr "Rechercher tous les fichiers" + +#: f.info.cc:1653 +msgid "no files selected" +msgstr "Aucun fichiers sélectionnés" + +#: f.info.cc:1659 +msgid "no tag specified" +msgstr "Aucune étiquettes spécifiées" + +#: f.info.cc:1683 f.info.cc:1712 +msgid "specify tag" +msgstr "Étiquette spécifique" + +#: f.info.cc:1821 +msgid "View Info" +msgstr "Afficher les informations" + +#: f.info.cc:1889 fotoxx-12.01.cc:231 +msgid "Edit Info" +msgstr "Modifier les informations" + +#: f.info.cc:1987 fotoxx-12.01.cc:232 +msgid "Delete Info" +msgstr "Supprimer les informations" + +#: f.info.cc:1989 fotoxx.h:731 +msgid "All" +msgstr "Tout" + +#: f.info.cc:1990 +msgid "One Key:" +msgstr "Une touche : " + +#: f.info.cc:2343 +msgid "Search Tags, Comments, File Names" +msgstr "Rechercher les étiquettes, commentaires et noms de fichiers" + +#: f.info.cc:2350 +msgid "date range" +msgstr "Date entre : " + +#: f.info.cc:2351 +msgid "stars range" +msgstr "Note entre : " + +#: f.info.cc:2352 +msgid "search tags" +msgstr "Rechercher" + +#: f.info.cc:2353 +msgid "search text" +msgstr "Rechercher le texte" + +#: f.info.cc:2354 +msgid "file names" +msgstr "Noms des fichiers" + +#: f.info.cc:2359 +msgid "(yyyymmdd)" +msgstr "" + +#: f.info.cc:2365 +msgid "all/any" +msgstr "" + +#: f.info.cc:2702 +msgid "No matching images found" +msgstr "Aucuns résultats pour cette recherche" + +#: f.info.cc:2706 f.info.cc:3059 +msgid "No search index file present" +msgstr "" + +#: f.info.cc:2777 +msgid "Additional Items for Report" +msgstr "" + +#: f.navi.cc:188 f.navi.cc:576 f.navi.cc:706 f.navi.cc:707 f.navi.cc:709 +msgid "bigger" +msgstr "Plus gros" + +#: f.navi.cc:188 +msgid "increase thumbnail size" +msgstr "Augmenter la taille des miniatures" + +#: f.navi.cc:189 +msgid "reduce thumbnail size" +msgstr "Réduire la taille des miniatures" + +#: f.navi.cc:189 f.navi.cc:586 f.navi.cc:708 f.navi.cc:710 +msgid "smaller" +msgstr "Plus petit" + +#: f.navi.cc:190 f.navi.cc:600 +msgid "parent" +msgstr "" + +#: f.navi.cc:190 +msgid "parent directory" +msgstr "" + +#: f.navi.cc:191 f.navi.cc:625 f.navi.cc:717 +msgid "first page" +msgstr "Première page" + +#: f.navi.cc:191 +msgid "jump to first file" +msgstr "Aller au premier fichier" + +#: f.navi.cc:192 f.navi.cc:623 f.navi.cc:712 f.navi.cc:719 +msgid "prev page" +msgstr "Page précé." + +#: f.navi.cc:192 +msgid "previous page" +msgstr "Page précédente" + +#: f.navi.cc:193 f.navi.cc:621 f.navi.cc:714 +msgid "prev row" +msgstr "Ligne précé." + +#: f.navi.cc:193 +msgid "previous row" +msgstr "Ligne précédente" + +#: f.navi.cc:194 f.navi.cc:622 f.navi.cc:715 +msgid "next row" +msgstr "Ligne suiv." + +#: f.navi.cc:195 f.navi.cc:624 f.navi.cc:713 f.navi.cc:720 +msgid "next page" +msgstr "Page suiv." + +#: f.navi.cc:195 +msgid "ttip::next page" +msgstr "" + +#: f.navi.cc:196 +msgid "jump to last file" +msgstr "Aller au dernier fichier" + +#: f.navi.cc:196 f.navi.cc:626 f.navi.cc:718 +msgid "last page" +msgstr "Dernière page" + +#: f.navi.cc:197 f.navi.cc:571 +msgid "close" +msgstr "Fermer" + +#: f.navi.cc:197 +msgid "close image gallery" +msgstr "Fermer la fenêtre des miniatures" + +#: f.navi.cc:1413 fotoxx.h:787 +msgid "Select Files" +msgstr "Sélectionner les fichiers" + +#: f.navi.cc:1413 zfuncs.cc:6296 zfuncs.cc:6332 zfuncs.cc:6485 zfuncs.cc:6728 +#: zfuncs.cc:7427 zfuncs.cc:7433 zfuncs.cc:7439 zfuncs.cc:7445 +msgid "cancel" +msgstr "Annuler" + +#: f.navi.cc:1413 zfuncs.cc:6728 +msgid "done" +msgstr "Terminé" + +#: f.navi.cc:1422 +msgid "insert" +msgstr "" + +#: f.navi.cc:1423 +msgid "add all" +msgstr "" + +#: f.retouch.cc:55 +msgid "Adjust Brightness and Color" +msgstr "Ajuster la luminosité et la couleur" + +#: f.retouch.cc:110 +msgid "small-steps" +msgstr "" + +#: f.retouch.cc:119 +msgid "color saturation" +msgstr "Saturation des couleurs" + +#: f.retouch.cc:126 +msgid " reset 1 " +msgstr "Réinit. 1x" + +#: f.retouch.cc:127 +msgid "reset all" +msgstr "Tout réinitialiser" + +#: f.retouch.cc:599 +msgid "adjust image gamma" +msgstr "" + +#: f.retouch.cc:885 +msgid "Expand Brightness Range" +msgstr "Améliorer la plage de luminosité" + +#: f.retouch.cc:887 +msgid "bright pixels" +msgstr "Pixels lumineux" + +#: f.retouch.cc:1058 +msgid "Flatten Brightness Distribution" +msgstr "Distribution aplanie de la luminosité" + +#: f.retouch.cc:1072 +msgid "Flatten" +msgstr "Aplanir" + +#: f.retouch.cc:1334 +msgid "Ramp brightness across image" +msgstr "Corriger la luminosité dans des parties de l'image" + +#: f.retouch.cc:1730 fotoxx-12.01.cc:272 +msgid "Tone Mapping" +msgstr "Tone Mapping" + +#: f.retouch.cc:1758 +msgid "low" +msgstr "" + +#: f.retouch.cc:1760 +msgid "high" +msgstr "" + +#: f.retouch.cc:1763 +msgid "Amplify" +msgstr "" + +#: f.retouch.cc:2069 +msgid "Adjust White Balance" +msgstr "Ajuster la balance des blancs" + +#: f.retouch.cc:2070 +msgid "Click white or gray image location" +msgstr "Cliquez sur une couleur de l'image" + +#: f.retouch.cc:2278 +msgid "Color Match Images" +msgstr "" + +#: f.retouch.cc:2307 +msgid "mouse radius for color sample" +msgstr "" + +#: f.retouch.cc:2309 f.retouch.cc:2314 fotoxx-12.01.cc:246 fotoxx-12.01.cc:325 +#: fotoxx.h:769 +msgid "Open" +msgstr "Ouvrir" + +#: f.retouch.cc:2310 +msgid "image for source color" +msgstr "" + +#: f.retouch.cc:2312 +msgid "click on image to get source color" +msgstr "" + +#: f.retouch.cc:2315 +msgid "image to set matching color" +msgstr "" + +#: f.retouch.cc:2317 +msgid "click on image to set matching color" +msgstr "" + +#: f.retouch.cc:2372 +msgid "select source image color first" +msgstr "" + +#: f.retouch.cc:2584 +msgid "Add standard bias" +msgstr "" + +#: f.retouch.cc:2591 +msgid "+Brightness -Density" +msgstr "" + +#: f.retouch.cc:2592 +msgid "+Red -Cyan" +msgstr "" + +#: f.retouch.cc:2593 +msgid "+Green -Magenta" +msgstr "" + +#: f.retouch.cc:2594 +msgid "+Blue -Yellow" +msgstr "" + +#: f.retouch.cc:2599 +msgid "Contrast" +msgstr "" + +#: f.retouch.cc:2600 fotoxx.h:778 +msgid "Red" +msgstr "Rouge" + +#: f.retouch.cc:2601 fotoxx.h:758 +msgid "Green" +msgstr "Vert" + +#: f.retouch.cc:2602 fotoxx.h:736 +msgid "Blue" +msgstr "Bleu" + +#: f.retouch.cc:2730 +msgid "Load DRGB parameters" +msgstr "" + +#: f.retouch.cc:2732 f.retouch.cc:2804 f.retouch.cc:6102 f.retouch.cc:6198 +msgid "File:" +msgstr "" + +#: f.retouch.cc:2751 f.retouch.cc:2824 +msgid "DRGB parameters file" +msgstr "" + +#: f.retouch.cc:2769 f.retouch.cc:6142 +msgid "file not found" +msgstr "" + +#: f.retouch.cc:2802 +msgid "Save DRGB parameters" +msgstr "" + +#: f.retouch.cc:3034 f.tools.cc:2404 +msgid "Click image to select pixels." +msgstr "" + +#: f.retouch.cc:3072 fotoxx-12.01.cc:276 +msgid "Revise RGB" +msgstr "" + +#: f.retouch.cc:3084 +msgid "Metric:" +msgstr "" + +#: f.retouch.cc:3139 +msgid "Blend" +msgstr "" + +#: f.retouch.cc:3519 +msgid "" +"Method 1:\n" +" Left-click on red-eye to darken.\n" +"Method 2:\n" +" Drag down and right to enclose red-eye.\n" +" Left-click on red-eye to darken.\n" +"Undo red-eye:\n" +" Right-click on red-eye." +msgstr "" +"Méthode n°1 : \n" +"- Faites un clic-gauche sur l'œil rouge pour l'assombrir. \n" +"Méthode n°2 : \n" +"- Tirer le pointeur en bas vers la droite pour l'enfermer. \n" +"- Pour annuler : faite un clic-droit sur l'œil rouge." + +#: f.retouch.cc:3534 +msgid "Red Eye Reduction" +msgstr "Réduction des yeux rouges" + +#: f.retouch.cc:3968 +msgid "Set Blur Radius" +msgstr "Configurer le radius flou" + +#: f.retouch.cc:4195 fotoxx-12.01.cc:279 +msgid "Sharpen Image" +msgstr "Netteté" + +#: f.retouch.cc:4202 +msgid "edge detection" +msgstr "Détection des bords" + +#: f.retouch.cc:4203 +msgid "cycles" +msgstr "Cycles" + +#: f.retouch.cc:4204 +msgid "reduce" +msgstr "Réduire" + +#: f.retouch.cc:4215 +msgid "unsharp mask" +msgstr "Masque flou" + +#: f.retouch.cc:4228 +msgid "brightness gradient" +msgstr "Gradient de luminosité" + +#: f.retouch.cc:4634 +msgid "" +" Press the reduce button to \n" +" reduce noise in small steps. \n" +" Use undo to start over." +msgstr "" +" Appuyer sur [Réduire] pour atténuer \n" +" le bruit par petites étapes. \n" +" Utilisez [Undo] pour annuler." + +#: f.retouch.cc:4645 +msgid "Noise Reduction" +msgstr "Réduction du bruit" + +#: f.retouch.cc:4650 +msgid "algorithm" +msgstr "Algorithme" + +#: f.retouch.cc:4657 +msgid "flatten outliers by color (1)" +msgstr "Aplanir les extrêmes par couleur (1)" + +#: f.retouch.cc:4658 +msgid "flatten outliers by color (2)" +msgstr "Aplanir les extrêmes par couleur (2)" + +#: f.retouch.cc:4659 +msgid "set median brightness by color" +msgstr "Ajuster la luminosité médiane par couleur" + +#: f.retouch.cc:4660 f.retouch.cc:4661 +msgid "top hat filter by color" +msgstr "Filtre TopHat par couleur" + +#: f.retouch.cc:4976 +msgid "" +"1. Drag mouse to select. \n" +"2. Erase. 3. Repeat. " +msgstr "" + +#: f.retouch.cc:4998 fotoxx-12.01.cc:281 +msgid "Smart Erase" +msgstr "" + +#: f.retouch.cc:5003 fotoxx.h:776 +msgid "Radius" +msgstr "Radius" + +#: f.retouch.cc:5005 +msgid "Blur" +msgstr "" + +#: f.retouch.cc:5008 +msgid "New Area" +msgstr "" + +#: f.retouch.cc:5379 fotoxx-12.01.cc:282 +msgid "Remove Dust" +msgstr "" + +#: f.retouch.cc:5383 +msgid "spot size limit" +msgstr "" + +#: f.retouch.cc:5386 +msgid "max. brightness" +msgstr "" + +#: f.retouch.cc:5389 +msgid "min. contrast" +msgstr "" + +#: f.retouch.cc:5983 fotoxx-12.01.cc:283 +msgid "Fix Stuck Pixels" +msgstr "" + +#: f.retouch.cc:5989 +msgid "pixel group" +msgstr "" + +#: f.retouch.cc:5990 +msgid "circle color" +msgstr "" + +#: f.retouch.cc:6100 +msgid "Load Stuck Pixels" +msgstr "" + +#: f.retouch.cc:6124 f.retouch.cc:6220 +msgid "Stuck Pixels file" +msgstr "" + +#: f.retouch.cc:6164 +msgid "file format error" +msgstr "" + +#: f.retouch.cc:6192 +msgid "there are zero stuck pixels" +msgstr "" + +#: f.retouch.cc:6196 +msgid "Save Stuck Pixels" +msgstr "" + +#: f.retouch.cc:6686 +#, c-format +msgid "Undo Memory %d%c" +msgstr "Annuler la mémoire %d%c" + +#: f.retouch.cc:6688 fotoxx-12.01.cc:284 +msgid "Edit Pixels" +msgstr "Modifier les pixels" + +#: f.retouch.cc:6695 +msgid "pick" +msgstr "Sélection" + +#: f.retouch.cc:6697 +msgid "erase" +msgstr "Supprimer" + +#: f.retouch.cc:6705 +msgid "paintbrush radius" +msgstr "Radius du pinceau" + +#: f.retouch.cc:6706 +msgid "transparency center" +msgstr "Centre de transparence" + +#: f.retouch.cc:6707 +msgid "transparency edge" +msgstr "Bord de transparence" + +#: f.retouch.cc:6972 +msgid "" +"Undo memory limit has been reached. \n" +"Save work with [done], then resume editing." +msgstr "" +"L'annulation de la limite de mémoire a été atteinte. \n" +"Enregistrer votre création avec le bouton [Ok], et résumer \n" +"ensuite la modification." + +#: f.select.cc:54 f.select.cc:2461 +msgid "Select Area for Edits" +msgstr "Sélectionner une zone à modifier" + +#: f.select.cc:55 f.select.cc:2462 +msgid "Press F1 for help" +msgstr "" + +#: f.select.cc:64 +msgid "" +"Select Area not supported \n" +"by this edit function" +msgstr "" + +#: f.select.cc:103 f.tools.cc:901 +msgid "rectangle" +msgstr "" + +#: f.select.cc:104 f.tools.cc:902 +msgid "ellipse" +msgstr "" + +#: f.select.cc:110 +msgid "draw: freehand" +msgstr "Dessiner : main levée" + +#: f.select.cc:111 +msgid "draw: follow edge" +msgstr "Dessiner : suivre les contours" + +#: f.select.cc:114 +msgid "select by mouse" +msgstr "" + +#: f.select.cc:116 f.select.cc:2496 +msgid "mouse radius" +msgstr "" + +#: f.select.cc:120 +msgid "match mouse color" +msgstr "" + +#: f.select.cc:124 +msgid "search range" +msgstr "" + +#: f.select.cc:126 +msgid "firewall" +msgstr "" + +#: f.select.cc:326 f.select.cc:467 +#, c-format +msgid "exceed %d edits" +msgstr "Dépasse de %d modifications" + +#: f.select.cc:1021 +msgid "" +"Click one time inside each enclosed area \n" +"(possible gaps in the outline will be found). \n" +"Press F1 for help." +msgstr "" + +#: f.select.cc:1078 +msgid "finish area" +msgstr "Cloturer la zone" + +#: f.select.cc:1113 +msgid "searching" +msgstr "Rechercher" + +#: f.select.cc:1185 +msgid "outline has a gap" +msgstr "" + +#: f.select.cc:1189 +msgid "success" +msgstr "Terminé avec succès" + +#: f.select.cc:1440 f.select.cc:1470 +msgid "the area is not finished" +msgstr "La zone n'est pas bouclée" + +#: f.select.cc:1563 +msgid "Edge calculation in progress" +msgstr "Calcul des bords en cours" + +#: f.select.cc:1572 +msgid "Area Edge Calc" +msgstr "Calcul du bord de la zone" + +#: f.select.cc:1863 +msgid "position with mouse click/drag" +msgstr "Position avec un clic / glisser" + +#: f.select.cc:1887 +msgid "Paste Image" +msgstr "Coller l'image" + +#: f.select.cc:1901 +msgid "angle" +msgstr "" + +#: f.select.cc:2160 +msgid "load select area from a file" +msgstr "Charger la zone sélectionnée à partir d'un fichier" + +#: f.select.cc:2194 +msgid "cannot open .tiff and .info files" +msgstr "" + +#: f.select.cc:2213 +msgid "save select area to a file" +msgstr "" + +#: f.select.cc:2248 fotoxx-12.01.cc:248 +msgid "Select Whole Image" +msgstr "Sélectionner toute l'image" + +#: f.select.cc:2249 +msgid "Edit Function Amplifier" +msgstr "Modifier l'amplitude" + +#: f.select.cc:2463 +msgid "Edit function must be active" +msgstr "" + +#: f.select.cc:2499 +msgid "power: center" +msgstr "" + +#: f.select.cc:2501 +msgid "edge" +msgstr "" + +#: f.select.cc:2504 +msgid "reset area" +msgstr "" + +#: f.tools.cc:42 +msgid "" +"When editing a collection, right-click \n" +"an image or thumbnail to add or remove." +msgstr "" + +#: f.tools.cc:70 fotoxx-12.01.cc:204 +msgid "Manage Collections" +msgstr "" + +#: f.tools.cc:85 +msgid "Start new collection" +msgstr "" + +#: f.tools.cc:87 +msgid "Edit a collection" +msgstr "" + +#: f.tools.cc:89 +msgid "View a collection" +msgstr "" + +#: f.tools.cc:91 +msgid "Delete a collection" +msgstr "" + +#: f.tools.cc:95 +msgid "Editing:" +msgstr "" + +#: f.tools.cc:99 +msgid "Action:" +msgstr "" + +#: f.tools.cc:133 +msgid "New Collection" +msgstr "" + +#: f.tools.cc:156 +msgid "Edit Collection" +msgstr "" + +#: f.tools.cc:172 +msgid "View Collection" +msgstr "" + +#: f.tools.cc:193 +msgid "Delete Collection" +msgstr "" + +#: f.tools.cc:196 +#, c-format +msgid "delete %s ?" +msgstr "" + +#: f.tools.cc:223 +#, c-format +msgid "add image to collection: %s" +msgstr "" + +#: f.tools.cc:225 f.tools.cc:270 +msgid "remove image from collection" +msgstr "" + +#: f.tools.cc:226 f.tools.cc:271 f.tools.cc:298 +msgid "remove and save image" +msgstr "" + +#: f.tools.cc:227 f.tools.cc:316 +msgid "insert saved images here" +msgstr "" + +#: f.tools.cc:256 +msgid "add image to collection" +msgstr "" + +#: f.tools.cc:301 +msgid "too many saved files" +msgstr "" + +#: f.tools.cc:373 fotoxx-12.01.cc:205 +msgid "Move Collections" +msgstr "" + +#: f.tools.cc:375 +msgid "old top directory" +msgstr "" + +#: f.tools.cc:378 +msgid "new top directory" +msgstr "" + +#: f.tools.cc:434 +msgid "completed" +msgstr "Complété" + +#: f.tools.cc:467 +msgid "Batch Convert/Resize/Export" +msgstr "" + +#: f.tools.cc:474 +msgid "new max. width" +msgstr "Nouvelle largeur max." + +#: f.tools.cc:481 +msgid "new file type" +msgstr "" + +#: f.tools.cc:482 +msgid "same" +msgstr "" + +#: f.tools.cc:490 +msgid "replace originals" +msgstr "Remplacer les originaux" + +#: f.tools.cc:491 +msgid "export to location" +msgstr "Exporter vers l'emplacement" + +#: f.tools.cc:492 +msgid "remove EXIF" +msgstr "" + +#: f.tools.cc:549 +msgid "Select directory" +msgstr "Sélectionner un dossier" + +#: f.tools.cc:583 +#, c-format +msgid "replace original files? (max. %d x %d)" +msgstr "Remplacer les fichiers originaux ? (max. %d x %d)" + +#: f.tools.cc:590 +#, c-format +msgid "" +"copy files? (max. %d x %d) \n" +" to location %s" +msgstr "" +"Copier les fichiers ? (max. %d x %d) \n" +"vers l'emplacement %s" + +#: f.tools.cc:601 +msgid "location is not a valid directory" +msgstr "L'emplacement n'est pas un dossier valable" + +#: f.tools.cc:608 f.tools.cc:3007 +#, c-format +msgid "max. size %d x %d is not reasonable" +msgstr "La taille max. « %d x %d » est trop grande" + +#: f.tools.cc:654 +msgid "*** file already exists" +msgstr "" + +#: f.tools.cc:662 +msgid "*** file type not supported" +msgstr "" + +#: f.tools.cc:741 +msgid "Program ufraw-batch is required" +msgstr "Le logiciel « ufraw-batch » est requis." + +#: f.tools.cc:751 fotoxx.h:770 +msgid "Open RAW File" +msgstr "Ouvrir une image RAW" + +#: f.tools.cc:764 +msgid "Select RAW files to convert" +msgstr "Sélectionner des fichiers RAW à convertir" + +#: f.tools.cc:769 +msgid "Choose file type" +msgstr "" + +#: f.tools.cc:888 +msgid "Press ESC to exit slide show" +msgstr "" + +#: f.tools.cc:889 +msgid "show only latest file versions" +msgstr "" + +#: f.tools.cc:893 +msgid "arrow keys" +msgstr "Touche « flèches »" + +#: f.tools.cc:894 +msgid "instant" +msgstr "" + +#: f.tools.cc:895 +msgid "fade-in" +msgstr "" + +#: f.tools.cc:896 +msgid "roll-right" +msgstr "" + +#: f.tools.cc:897 +msgid "roll-down" +msgstr "" + +#: f.tools.cc:898 +msgid "shift-left" +msgstr "" + +#: f.tools.cc:899 +msgid "venetian" +msgstr "Vénitien" + +#: f.tools.cc:900 +msgid "grate" +msgstr "" + +#: f.tools.cc:903 +msgid "radar" +msgstr "" + +#: f.tools.cc:904 +msgid "jaws" +msgstr "" + +#: f.tools.cc:911 fotoxx-12.01.cc:208 +msgid "Slide Show" +msgstr "Diaporama" + +#: f.tools.cc:915 +msgid "seconds" +msgstr "Secondes" + +#: f.tools.cc:919 +msgid "music file" +msgstr "" + +#: f.tools.cc:923 +msgid "transitions" +msgstr "" + +#: f.tools.cc:1040 +msgid "Select music file or playlist" +msgstr "" + +#: f.tools.cc:1727 +msgid "Sync Files is already running" +msgstr "" + +#: f.tools.cc:1778 +msgid "" +"Run Tools > Synchronize Files so that gallery windows \n" +"will be fast and Search Images will work correctly. \n" +"You can view (not edit) images while synchronize runs." +msgstr "" + +#: f.tools.cc:1812 +msgid "no top image directory is defined" +msgstr "" + +#: f.tools.cc:1818 +msgid "top image directory is invalid" +msgstr "" + +#: f.tools.cc:1823 +msgid "no search index file is present" +msgstr "" + +#: f.tools.cc:1837 +msgid "new/modified files are present" +msgstr "" + +#: f.tools.cc:1844 +msgid "no new files found" +msgstr "" + +#: f.tools.cc:1859 fotoxx-12.01.cc:209 +msgid "Synchronize Files" +msgstr "" + +#: f.tools.cc:1861 +msgid "Top Image Directory:" +msgstr "Dossier d'images parent : " + +#: f.tools.cc:1883 +msgid "" +"file sync is necessary.\n" +"cancel anyway?" +msgstr "" + +#: f.tools.cc:1896 +msgid "top directory is invalid" +msgstr "" + +#: f.tools.cc:2292 +msgid "Select top image directory" +msgstr "Sélectionner le dossier d'images racine" + +#: f.tools.cc:2429 fotoxx-12.01.cc:210 +msgid "Show RGB" +msgstr "Afficher les couleurs RVB" + +#: f.tools.cc:2719 fotoxx-12.01.cc:211 +msgid "Grid Lines" +msgstr "Grille" + +#: f.tools.cc:2728 +msgid "x-spacing" +msgstr "" + +#: f.tools.cc:2729 +msgid "x-count" +msgstr "" + +#: f.tools.cc:2730 +msgid "x-enable" +msgstr "" + +#: f.tools.cc:2736 +msgid "y-spacing" +msgstr "" + +#: f.tools.cc:2737 +msgid "y-count" +msgstr "" + +#: f.tools.cc:2738 +msgid "y-enable" +msgstr "" + +#: f.tools.cc:2745 +msgid "x-offset" +msgstr "" + +#: f.tools.cc:2749 +msgid "y-offset" +msgstr "" + +#: f.tools.cc:2940 fotoxx-12.01.cc:213 +msgid "E-mail Images" +msgstr "Envoyer les images par adresse électronique" + +#: f.tools.cc:2947 +msgid "max. width" +msgstr "Largeur max." + +#: f.tools.cc:2948 +msgid "max. height" +msgstr "Hauteur max." + +#: f.tools.cc:3093 +msgid "too many files" +msgstr "Trop de fichiers" + +#: f.tools.cc:3134 +msgid "" +"Brightness should show a gradual ramp \n" +"extending all the way to the edges." +msgstr "" + +#: f.tools.cc:3174 +msgid "Monitor Check" +msgstr "" + +#: f.tools.cc:3232 fotoxx-12.01.cc:215 +msgid "Monitor Gamma" +msgstr "" + +#: f.tools.cc:3294 fotoxx-12.01.cc:216 +msgid "Brightness Distribution" +msgstr "Distribution de la luminosité" + +#: f.tools.cc:3432 +msgid "Available Translations" +msgstr "Traductions disponibles" + +#: f.tools.cc:3436 +msgid "Set Language" +msgstr "Changer de langue" + +#: f.tools.cc:3502 +msgid "Make Launcher" +msgstr "" + +#: f.tools.cc:3540 +msgid "Settings" +msgstr "" + +#: f.tools.cc:3545 +msgid "Startup Display" +msgstr "" + +#: f.tools.cc:3547 +msgid "Recent Files Gallery" +msgstr "" + +#: f.tools.cc:3548 +msgid "Previous Image Viewed" +msgstr "" + +#: f.tools.cc:3549 +msgid "Blank Window" +msgstr "" + +#: f.tools.cc:3551 +msgid "Directory Gallery" +msgstr "" + +#: f.tools.cc:3556 +msgid "Image File" +msgstr "" + +#: f.tools.cc:3562 +msgid "Toolbar Style" +msgstr "" + +#: f.tools.cc:3563 f.transform.cc:1300 +msgid "Text" +msgstr "Texte" + +#: f.tools.cc:3564 +msgid "Icons" +msgstr "" + +#: f.tools.cc:3565 +msgid "Both" +msgstr "" + +#: f.tools.cc:3568 +msgid "Warn Overwrite" +msgstr "" + +#: f.tools.cc:3639 +msgid "startup directory is invalid" +msgstr "" + +#: f.tools.cc:3650 +msgid "startup file is invalid" +msgstr "" + +#: f.tools.cc:3707 +msgid "Select startup directory" +msgstr "" + +#: f.tools.cc:3715 +msgid "Select startup image file" +msgstr "" + +#: f.transform.cc:50 +msgid "Use buttons or drag right edge with mouse" +msgstr "Utilisez les boutons ou glissez le bord droit avec la souris" + +#: f.transform.cc:60 fotoxx-12.01.cc:252 +msgid "Rotate Image" +msgstr "Pivoter l'image" + +#: f.transform.cc:64 +msgid "degrees" +msgstr "Degrés" + +#: f.transform.cc:80 f.transform.cc:124 +msgid "Trim" +msgstr "Rogner" + +#: f.transform.cc:81 f.transform.cc:2289 f.transform.cc:3120 +#: f.transform.cc:3383 f.transform.cc:3644 +msgid "Grid" +msgstr "" + +#: f.transform.cc:123 +msgid "Undo Trim" +msgstr "Annuler Rogner" + +#: f.transform.cc:139 +#, c-format +msgid "degrees: %.1f" +msgstr "Degrés :  %.1f" + +#: f.transform.cc:286 +msgid "gold" +msgstr "" + +#: f.transform.cc:334 +msgid "Drag middle to move, drag corners to resize." +msgstr "" +"Glissez le centre pour déplacer, glissez les coins pour redimensionner." + +#: f.transform.cc:348 fotoxx-12.01.cc:253 +msgid "Trim Image" +msgstr "Rogner" + +#: f.transform.cc:348 +msgid "customize" +msgstr "Personnaliser" + +#: f.transform.cc:359 +msgid "ratio" +msgstr "" + +#: f.transform.cc:363 +msgid "Lock Ratio" +msgstr "Verrouiller les proportions" + +#: f.transform.cc:368 +msgid "invert" +msgstr "inverser" + +#: f.transform.cc:890 +msgid "Trim Buttons" +msgstr "" + +#: f.transform.cc:1064 +msgid "Lock aspect ratio" +msgstr "Verrouiller les proportions" + +#: f.transform.cc:1072 fotoxx-12.01.cc:255 +msgid "Resize Image" +msgstr "Redimensionner l'image" + +#: f.transform.cc:1095 fotoxx-12.01.cc:326 +msgid "Prev" +msgstr "Préc." + +#: f.transform.cc:1245 +msgid "" +"Enter text, click/drag on image.\n" +"Right click to remove" +msgstr "" +"Saisissez du texte, cliquez et glissez sur l'image.\n" +"Un clic-droit supprime le texte." + +#: f.transform.cc:1294 fotoxx-12.01.cc:256 +msgid "Annotate Image" +msgstr "Annoter l'image" + +#: f.transform.cc:1307 +msgid "Size" +msgstr "Taille" + +#: f.transform.cc:1310 +msgid "Angle" +msgstr "Angle" + +#: f.transform.cc:1321 fotoxx.h:741 +msgid "Color" +msgstr "Couleur" + +#: f.transform.cc:1322 +msgid "Transparency" +msgstr "Transparence" + +#: f.transform.cc:1325 +msgid "text" +msgstr "" + +#: f.transform.cc:1330 +msgid "backing" +msgstr "" + +#: f.transform.cc:1333 +msgid "" +"Outline\n" +" Width" +msgstr "" + +#: f.transform.cc:1335 +msgid "outline" +msgstr "" + +#: f.transform.cc:1342 +msgid "Annotation File:" +msgstr "Annoter le fichier" + +#: f.transform.cc:1416 +msgid "select font" +msgstr "Sélectionner la police" + +#: f.transform.cc:2045 fotoxx-12.01.cc:257 +msgid "Flip Image" +msgstr "Retourner l'image" + +#: f.transform.cc:2049 f.transform.cc:2281 +msgid "horizontal" +msgstr "Horizontal" + +#: f.transform.cc:2050 f.transform.cc:2280 +msgid "vertical" +msgstr "Vertical" + +#: f.transform.cc:2155 fotoxx-12.01.cc:258 +msgid "Make Negative" +msgstr "Négatif" + +#: f.transform.cc:2158 +msgid "black/white positive" +msgstr "" + +#: f.transform.cc:2159 +msgid "black/white negative" +msgstr "" + +#: f.transform.cc:2160 +msgid "color positive" +msgstr "" + +#: f.transform.cc:2161 +msgid "color negative" +msgstr "" + +#: f.transform.cc:2272 fotoxx-12.01.cc:259 +msgid "Unbend Image" +msgstr "Redresser" + +#: f.transform.cc:2282 +msgid "linear" +msgstr "" + +#: f.transform.cc:2285 +msgid "curved" +msgstr "" + +#: f.transform.cc:2544 +msgid "" +" Click the four corners of a tetragon area. Press [apply]. \n" +" The image is warped to make the tetragon into a rectangle." +msgstr "" + +#: f.transform.cc:2556 fotoxx-12.01.cc:260 +msgid "Keystone Correction" +msgstr "" + +#: f.transform.cc:2724 +msgid "must have 4 corners" +msgstr "" + +#: f.transform.cc:2847 +msgid "" +" Select an area to warp using select area function. \n" +" Press [start warp] and pull area with mouse. \n" +" Make multiple mouse pulls until satisfied. \n" +" When finished, select another area or press [done]." +msgstr "" +"Sélectionner une zone à déformer en utilisant dans \n" +"le menu Édition / Édition de la zone / Sélectionner une zone. \n" +"Appuyer sur [Commencer] et étirez la zone avec la souris. \n" +"Effectuez des déformations jusqu'à satisfaction. \n" +"Ensuite, sélectionnez une autre zone ou cliquez sur [Ok]." + +#: f.transform.cc:2859 fotoxx-12.01.cc:261 +msgid "Warp Image (area)" +msgstr "Déformer l'image (zone)" + +#: f.transform.cc:2864 +msgid "start warp" +msgstr "Commencer" + +#: f.transform.cc:2931 +msgid "no active Select Area" +msgstr "" + +#: f.transform.cc:3099 f.transform.cc:3362 +msgid "" +" Pull an image position using the mouse. \n" +" Make multiple mouse pulls until satisfied. \n" +" When finished, press [done]." +msgstr "" +" Tirez l'image en utilisant la souris. \n" +" Effectuez plusieurs fois le processus \n" +" jusqu'à satisfaction et cliquez sur [Ok] \n" +" pour terminer." + +#: f.transform.cc:3112 fotoxx-12.01.cc:262 +msgid "Warp Image (curved)" +msgstr "Déformer l'image (courbé)" + +#: f.transform.cc:3375 fotoxx-12.01.cc:263 +msgid "Warp Image (linear)" +msgstr "Déformer l'image (linéaire)" + +#: f.transform.cc:3628 +msgid "" +" Pull on an image corner using the mouse. \n" +" Make multiple mouse pulls until satisfied. \n" +" When finished, press [done]." +msgstr "" +"Tirez un bord de l'image en utilisant la souris. \n" +"Répétez plusieurs fois l'opération jusqu'à satisfaction. \n" +"Une fois terminé, appuyez sur [Ok]." + +#: f.transform.cc:3639 fotoxx-12.01.cc:264 +msgid "Warp Image (affine)" +msgstr "Déformer l'image (affiné)" + +#: fotoxx-12.01.cc:185 +msgid "File" +msgstr "Fichier" + +#: fotoxx-12.01.cc:186 fotoxx-12.01.cc:324 +msgid "Image Gallery" +msgstr "Parcourir les miniatures" + +#: fotoxx-12.01.cc:187 +msgid "Clone 50/50" +msgstr "" + +#: fotoxx-12.01.cc:188 +msgid "Clone Overlay" +msgstr "" + +#: fotoxx-12.01.cc:190 +msgid "Open in New Window" +msgstr "" + +#: fotoxx-12.01.cc:191 fotoxx-12.01.cc:326 +msgid "Open Previous File" +msgstr "Afficher l'image précédente" + +#: fotoxx-12.01.cc:192 +msgid "Open Recent File" +msgstr "Ouvrir un fichier récent" + +#: fotoxx-12.01.cc:193 fotoxx-12.01.cc:334 +msgid "Save to Same File" +msgstr "Enregistrer" + +#: fotoxx-12.01.cc:194 fotoxx-12.01.cc:335 +msgid "Save to New Version" +msgstr "" + +#: fotoxx-12.01.cc:195 fotoxx-12.01.cc:336 +msgid "Save to New File" +msgstr "Enregistrer sous" + +#: fotoxx-12.01.cc:197 +msgid "Trash Image File" +msgstr "Supprimer l'image" + +#: fotoxx-12.01.cc:199 +msgid "Batch Rename Files" +msgstr "Renommer des fichiers par lot" + +#: fotoxx-12.01.cc:200 +msgid "Print Image File" +msgstr "Imprimer une image" + +#: fotoxx-12.01.cc:201 fotoxx-12.01.cc:340 +msgid "Quit fotoxx" +msgstr "Quitter Fotoxx" + +#: fotoxx-12.01.cc:203 +msgid "Tools" +msgstr "Outils" + +#: fotoxx-12.01.cc:206 +msgid "Batch Convert" +msgstr "" + +#: fotoxx-12.01.cc:207 +msgid "Convert RAW files" +msgstr "Convertir des fichiers RAW" + +#: fotoxx-12.01.cc:212 +msgid "Burn Images to CD/DVD" +msgstr "Graver les images vers un CD / DVD" + +#: fotoxx-12.01.cc:214 +msgid "Check Monitor" +msgstr "Vérifier l'écran" + +#: fotoxx-12.01.cc:217 +msgid "Change Language" +msgstr "Changer de langue" + +#: fotoxx-12.01.cc:219 +msgid "Menu and Launcher" +msgstr "" + +#: fotoxx-12.01.cc:220 +msgid "User Settings" +msgstr "" + +#: fotoxx-12.01.cc:221 +msgid "Memory Usage" +msgstr "" + +#: fotoxx-12.01.cc:224 +msgid "Edit Caption/Comments" +msgstr "" + +#: fotoxx-12.01.cc:229 +msgid "View Info (short)" +msgstr "Afficher les informations (résumé)" + +#: fotoxx-12.01.cc:230 +msgid "View Info (long)" +msgstr "Afficher les informations (complet)" + +#: fotoxx-12.01.cc:233 +msgid "Search Images" +msgstr "Rechercher des images" + +#: fotoxx-12.01.cc:234 +msgid "Search Metadata" +msgstr "" + +#: fotoxx-12.01.cc:236 fotoxx-12.01.cc:237 fotoxx.h:786 +msgid "Select" +msgstr "Sélectionner" + +#: fotoxx-12.01.cc:238 fotoxx.h:788 +msgid "Show" +msgstr "Afficher" + +#: fotoxx-12.01.cc:239 fotoxx.h:761 +msgid "Hide" +msgstr "Cacher" + +#: fotoxx-12.01.cc:240 fotoxx.h:752 +msgid "Enable" +msgstr "Activer" + +#: fotoxx-12.01.cc:241 fotoxx.h:748 +msgid "Disable" +msgstr "Désactiver" + +#: fotoxx-12.01.cc:242 fotoxx.h:763 +msgid "Invert" +msgstr "Inverser" + +#: fotoxx-12.01.cc:243 fotoxx.h:796 +msgid "Unselect" +msgstr "" + +#: fotoxx-12.01.cc:244 fotoxx.h:743 +msgid "Copy" +msgstr "Copier" + +#: fotoxx-12.01.cc:245 fotoxx.h:771 +msgid "Paste" +msgstr "Coller" + +#: fotoxx-12.01.cc:247 fotoxx-12.01.cc:334 fotoxx.h:783 +msgid "Save" +msgstr "Enreg." + +#: fotoxx-12.01.cc:249 +msgid "Select and Edit" +msgstr "" + +#: fotoxx-12.01.cc:251 +msgid "Transform" +msgstr "Transformer" + +#: fotoxx-12.01.cc:254 +msgid "Auto-Trim Image" +msgstr "" + +#: fotoxx-12.01.cc:266 +msgid "Retouch" +msgstr "Retoucher" + +#: fotoxx-12.01.cc:267 +msgid "Brightness/Color" +msgstr "Luminosité et couleur" + +#: fotoxx-12.01.cc:268 +msgid "Gamma Curves" +msgstr "" + +#: fotoxx-12.01.cc:269 +msgid "Expand Brightness" +msgstr "Améliorer la luminosité" + +#: fotoxx-12.01.cc:270 +msgid "Flatten Brightness" +msgstr "Luminosité aplanie" + +#: fotoxx-12.01.cc:271 +msgid "Brightness Ramp" +msgstr "Luminosité : correction" + +#: fotoxx-12.01.cc:273 +msgid "White Balance" +msgstr "Balance des blancs" + +#: fotoxx-12.01.cc:274 +msgid "Match Colors" +msgstr "" + +#: fotoxx-12.01.cc:277 +msgid "Red Eyes" +msgstr "Yeux rouges" + +#: fotoxx-12.01.cc:278 +msgid "Blur Image" +msgstr "Flou" + +#: fotoxx-12.01.cc:280 +msgid "Reduce Noise" +msgstr "Réduction du bruit" + +#: fotoxx-12.01.cc:286 +msgid "Art" +msgstr "Art" + +#: fotoxx-12.01.cc:287 +msgid "Color Depth" +msgstr "Profondeur de couleurs" + +#: fotoxx-12.01.cc:288 +msgid "Drawing" +msgstr "Dessin" + +#: fotoxx-12.01.cc:289 +msgid "Outlines" +msgstr "" + +#: fotoxx-12.01.cc:290 +msgid "Embossing" +msgstr "Gaufrage" + +#: fotoxx-12.01.cc:291 +msgid "Tiles" +msgstr "Tuiles" + +#: fotoxx-12.01.cc:292 +msgid "Dots" +msgstr "Points" + +#: fotoxx-12.01.cc:293 +msgid "Painting" +msgstr "Peinture" + +#: fotoxx-12.01.cc:295 +msgid "Combine" +msgstr "Combiner" + +#: fotoxx-12.01.cc:296 +msgid "High Dynamic Range" +msgstr "" + +#: fotoxx-12.01.cc:297 +msgid "High Depth of Field" +msgstr "" + +#: fotoxx-12.01.cc:298 +msgid "Stack / Paint" +msgstr "" + +#: fotoxx-12.01.cc:299 +msgid "Stack / Noise" +msgstr "" + +#: fotoxx-12.01.cc:300 +msgid "Panorama" +msgstr "Panorama" + +#: fotoxx-12.01.cc:301 +msgid "Vertical Panorama" +msgstr "" + +#: fotoxx-12.01.cc:304 +msgid "Edit Plugins" +msgstr "" + +#: fotoxx-12.01.cc:313 fotoxx-12.01.cc:341 fotoxx-12.01.cc:3026 +msgid "Help" +msgstr "Aide" + +#: fotoxx-12.01.cc:314 fotoxx-12.01.cc:3016 +msgid "About" +msgstr "Á propos" + +#: fotoxx-12.01.cc:315 fotoxx-12.01.cc:3020 +msgid "User Guide" +msgstr "Documentation" + +#: fotoxx-12.01.cc:316 fotoxx-12.01.cc:3023 +msgid "User Guide Changes" +msgstr "" + +#: fotoxx-12.01.cc:317 fotoxx-12.01.cc:3032 +msgid "Edit Functions Summary" +msgstr "" + +#: fotoxx-12.01.cc:318 fotoxx-12.01.cc:3035 +msgid "Change Log" +msgstr "Modifications" + +#: fotoxx-12.01.cc:319 fotoxx-12.01.cc:3038 +msgid "Translations" +msgstr "" + +#: fotoxx-12.01.cc:320 fotoxx-12.01.cc:3041 +msgid "Home Page" +msgstr "Site web" + +#: fotoxx-12.01.cc:324 +msgid "Gallery" +msgstr "Miniatures" + +#: fotoxx-12.01.cc:327 fotoxx.h:767 +msgid "Next" +msgstr "Suiv." + +#: fotoxx-12.01.cc:327 +msgid "Open Next File" +msgstr "Afficher l'image suivante" + +#: fotoxx-12.01.cc:328 +msgid "Zoom-in (bigger)" +msgstr "Agrandir" + +#: fotoxx-12.01.cc:329 +msgid "Zoom-out (smaller)" +msgstr "Réduire" + +#: fotoxx-12.01.cc:330 fotoxx.h:794 +msgid "Undo" +msgstr "Undo" + +#: fotoxx-12.01.cc:330 +msgid "Undo One Edit" +msgstr "Annuler une modification" + +#: fotoxx-12.01.cc:331 fotoxx.h:779 +msgid "Redo" +msgstr "Redo" + +#: fotoxx-12.01.cc:331 +msgid "Redo One Edit" +msgstr "Rétablir une modification" + +#: fotoxx-12.01.cc:335 +msgid "Save+V" +msgstr "" + +#: fotoxx-12.01.cc:336 +msgid "Save+F" +msgstr "" + +#: fotoxx-12.01.cc:337 +msgid "Move Image to Trash" +msgstr "Déplacer l'image vers la corbeille" + +#: fotoxx-12.01.cc:337 +msgid "Trash" +msgstr "Suppr." + +#: fotoxx-12.01.cc:340 +msgid "Quit" +msgstr "Quit." + +#: fotoxx-12.01.cc:341 +msgid "Fotoxx Essentials" +msgstr "Guide de l'utilisateur" + +#: fotoxx-12.01.cc:448 +msgid "first time startup" +msgstr "" + +#: fotoxx-12.01.cc:1944 +msgid "Exceed 50 anchor points" +msgstr "Dépasse de 50 points d'ancrage" + +#: fotoxx-12.01.cc:2129 +msgid "load curve from a file" +msgstr "" + +#: fotoxx-12.01.cc:2182 +msgid "curve file is invalid" +msgstr "" + +#: fotoxx-12.01.cc:2187 +msgid "curve file has different no. of curves" +msgstr "" + +#: fotoxx-12.01.cc:2202 +msgid "save curve to a file" +msgstr "" + +#: fotoxx-12.01.cc:2337 +msgid "cannot parallel edit" +msgstr "" + +#: fotoxx-12.01.cc:2347 +msgid "" +"exiftool is not installed \n" +"edited images will lose EXIF data" +msgstr "" +"Le paquetage « exiftool » n'est pas installé \n" +"Les images modifiées perdront leurs données Exif" + +#: fotoxx-12.01.cc:2353 +msgid "Too many edits, please save image" +msgstr "Trop de modifications, veuillez enregistrer l'image" + +#: fotoxx-12.01.cc:2358 +msgid "" +"Select area cannot be kept.\n" +"Continue?" +msgstr "" +"Impossible de conserver la sélection de la zone.\n" +"Voulez-vous continuer ?" + +#: fotoxx-12.01.cc:2366 +msgid "" +"Select area not active.\n" +"Continue?" +msgstr "" +"La zone sélectionnée n'est \n" +"pas active. Continuer ?" + +#: fotoxx-12.01.cc:2837 +msgid "Discard edits?" +msgstr "" + +#: fotoxx-12.01.cc:2838 +msgid "" +"This action will discard current edits.\n" +"Continue to discard edits.\n" +"Go Back to keep edits." +msgstr "" + +#: fotoxx-12.01.cc:2841 +msgid "Continue" +msgstr "" + +#: fotoxx-12.01.cc:2842 +msgid "Go Back" +msgstr "" + +#: fotoxx-12.01.cc:3659 +msgid "cannot open thumbnail file" +msgstr "Impossible d'ouvrir le fichier de miniatures" + +#: fotoxx-12.01.cc:3870 fotoxx-12.01.cc:3992 +msgid "TIFF open failure" +msgstr "Impossible d'ouvrir le fichier TIFF" + +#: fotoxx-12.01.cc:3886 +#, c-format +msgid "TIFF bits/color=%d not supported" +msgstr "TIFF bits/color=%d n'est pas pris en charge" + +#: fotoxx-12.01.cc:3901 fotoxx-12.01.cc:3939 +msgid "TIFF read failure" +msgstr "Impossible de lire le fichier TIFF" + +#: fotoxx-12.01.cc:4051 +msgid "TIFF write failure" +msgstr "Impossible d'écrire le fichier TIFF" + +#: fotoxx-12.01.cc:4071 +msgid "file type not supported" +msgstr "Ce type de fichier n'est pas pris en charge" + +#: fotoxx-12.01.cc:4178 +msgid "pixbuf write failure" +msgstr "Échec d'écriture pixbuf" + +#: fotoxx.h:728 +msgid "absolute" +msgstr "" + +#: fotoxx.h:730 +msgid "Add All" +msgstr "Tout ajouter" + +#: fotoxx.h:732 +msgid "Amount" +msgstr "Quantité" + +#: fotoxx.h:733 +msgid "Apply" +msgstr "Appliquer" + +#: fotoxx.h:734 +msgid "Black" +msgstr "" + +#: fotoxx.h:735 +msgid "Blend Width" +msgstr "Largeur du mélange" + +#: fotoxx.h:737 +msgid "Brightness" +msgstr "Luminosité" + +#: fotoxx.h:738 +msgid "Browse" +msgstr "Naviguer" + +#: fotoxx.h:739 +msgid "Cancel" +msgstr "Annuler" + +#: fotoxx.h:740 +msgid "Clear" +msgstr "Effacer" + +#: fotoxx.h:742 +msgid "Commit" +msgstr "" + +#: fotoxx.h:744 +msgid "Curve File:" +msgstr "" + +#: fotoxx.h:745 +msgid "Cut" +msgstr "" + +#: fotoxx.h:746 +msgid "Darker Areas" +msgstr "Zones sombres" + +#: fotoxx.h:747 +msgid "Delete" +msgstr "Supprimer" + +#: fotoxx.h:749 +#, c-format +msgid "" +"Discard special gallery list? \n" +" %s" +msgstr "" + +#: fotoxx.h:750 +msgid "Done" +msgstr "Ok" + +#: fotoxx.h:751 +msgid "Edit" +msgstr "Modifier" + +#: fotoxx.h:753 +msgid "Erase" +msgstr "" + +#: fotoxx.h:754 +msgid "package libimage-exiftool-perl is required" +msgstr "Le paquetage « libimage-exiftool-perl » est requis" + +#: fotoxx.h:755 +msgid "Fetch" +msgstr "Réception" + +#: fotoxx.h:756 +msgid "Finish" +msgstr "Terminer" + +#: fotoxx.h:757 +msgid "Font" +msgstr "Police" + +#: fotoxx.h:759 +msgid "Height" +msgstr "Hauteur" + +#: fotoxx.h:760 +msgid "histogram" +msgstr "Histogramme" + +#: fotoxx.h:762 +msgid "Insert" +msgstr "Insérer" + +#: fotoxx.h:764 +msgid "Lighter Areas" +msgstr "Zones lumineuses" + +#: fotoxx.h:765 +msgid "limit" +msgstr "Limiter" + +#: fotoxx.h:766 +msgid "New" +msgstr "" + +#: fotoxx.h:768 +msgid "OK" +msgstr "Ok" + +#: fotoxx.h:772 +msgid "Pause" +msgstr "Pause" + +#: fotoxx.h:773 +msgid "Percent" +msgstr "pourcentage" + +#: fotoxx.h:774 +msgid "Presets" +msgstr "Réglages" + +#: fotoxx.h:775 +msgid "Proceed" +msgstr "Traiter" + +#: fotoxx.h:777 +msgid "range" +msgstr "Plage" + +#: fotoxx.h:780 +msgid "Reduce" +msgstr "Réduire" + +#: fotoxx.h:782 +msgid "Reset" +msgstr "" + +#: fotoxx.h:784 +msgid "Unknown file type, save as tiff/jpeg/png to edit" +msgstr "" +"Type de fichier inconnu. Enregistrez le au format TIFF/JPEG/PNG pour le " +"modifier" + +#: fotoxx.h:785 +msgid "Search" +msgstr "Rechercher" + +#: fotoxx.h:789 +msgid "Start" +msgstr "Démarrer" + +#: fotoxx.h:790 +msgid "Threshold" +msgstr "Seuil" + +#: fotoxx.h:791 +#, c-format +msgid "exceed %d files" +msgstr "" + +#: fotoxx.h:792 +msgid "Undo All" +msgstr "Tout annuler" + +#: fotoxx.h:793 +msgid "Undo Last" +msgstr "Annul. préc." + +#: fotoxx.h:795 +msgid "Unfinish" +msgstr "" + +#: fotoxx.h:797 +msgid "View" +msgstr "" + +#: fotoxx.h:798 +msgid "White" +msgstr "" + +#: fotoxx.h:799 +msgid "Width" +msgstr "Largeur" + +#: zfuncs.cc:3252 +#, c-format +msgid "help file not found: %s" +msgstr "impossible de trouver le fichier d'aide : %s" + +#: zfuncs.cc:3664 zfuncs.cc:7315 +#, c-format +msgid "cannot open file %s" +msgstr "Impossible d'ouvrir le fichier %s" + +#: zfuncs.cc:3697 +msgid "save screen to file" +msgstr "Enregistrer l'écran dans un fichier" + +#: zfuncs.cc:6222 +msgid "No" +msgstr "" + +#: zfuncs.cc:6222 +msgid "Yes" +msgstr "" + +#: zfuncs.cc:6447 +msgid "open" +msgstr "Ouvrir" + +#: zfuncs.cc:6452 +msgid "choose" +msgstr "" + +#: zfuncs.cc:6457 +msgid "save" +msgstr "Enregistrer" + +#: zfuncs.cc:6463 +msgid "open folder" +msgstr "Ouvrir" + +#: zfuncs.cc:6468 +msgid "create folder" +msgstr "Créer un dossier" + +#: zfuncs.cc:6474 +msgid "hidden" +msgstr "Caché" + +#: zfuncs.cc:6535 +msgid "JPG quality 0-100" +msgstr "Qualité JPG 0-100" + +#: zfuncs.cc:6728 zfuncs.cc:6741 +msgid "margins" +msgstr "" + +#: zfuncs.cc:6737 +msgid "top" +msgstr "" + +#: zfuncs.cc:6738 +msgid "bottom" +msgstr "" + +#: zfuncs.cc:6739 +msgid "left" +msgstr "" + +#: zfuncs.cc:6740 +msgid "right" +msgstr "" + +#: zfuncs.cc:7202 +msgid "" +"Initial parameters file created. \n" +"Inspect and revise if necessary." +msgstr "" +"Le fichier des paramètres initiaux a été crée. \n" +"Vérifier et corriger si nécessaire." + +#: zfuncs.cc:7218 +msgid "load parameters from a file" +msgstr "Charger les paramètres à partir d'un fichier" + +#: zfuncs.cc:7287 +msgid "save parameters to a file" +msgstr "Enregistrer les paramètres dans un fichier" + +#: zfuncs.cc:7425 zfuncs.cc:7431 zfuncs.cc:7437 zfuncs.cc:7443 +msgid "edit parameters" +msgstr "Éditer les paramètres" + +#: zfuncs.cc:7426 zfuncs.cc:7432 +msgid "" +"list\n" +"all" +msgstr "" +"Lister\n" +"Tous" + +#: zfuncs.cc:7426 zfuncs.cc:7432 zfuncs.cc:7438 zfuncs.cc:7444 +msgid "" +"load\n" +"file" +msgstr "" +"Charger\n" +"Fichier" + +#: zfuncs.cc:7426 zfuncs.cc:7432 zfuncs.cc:7438 zfuncs.cc:7444 +msgid "" +"save\n" +"file" +msgstr "" +"Enreg.\n" +"Fichier" + +#: zfuncs.cc:7427 zfuncs.cc:7439 +msgid "" +"add\n" +"new" +msgstr "" +"Ajouter\n" +"Nouveau" + +#: zfuncs.cc:7427 zfuncs.cc:7433 zfuncs.cc:7439 zfuncs.cc:7445 +msgid "apply" +msgstr "Appliquer" + +#: zfuncs.cc:7479 +msgid "apply?" +msgstr "Appliquer ?" + +#: zfuncs.cc:7536 +msgid "(new parm name)" +msgstr "(Nouveaux paramètres)" + +#: zfuncs.cc:7536 +msgid "add parameter" +msgstr "Ajouter le paramètre" + +#~ msgid "Brightness Graph" +#~ msgstr "Diagramme de luminosité" + +#~ msgid "radius" +#~ msgstr "Radius" + +#~ msgid "match" +#~ msgstr "Correspondance" + +#~ msgid "Search results file error %s" +#~ msgstr "Erreur de fichier des résultats recherchés %s" + +#~ msgid "Batch Resize" +#~ msgstr "Redimensionner par lot" + +#~ msgid "new max. height" +#~ msgstr "Nouvelle hauteur max." + +#~ msgid "copy EXIF" +#~ msgstr "Copier les données EXIF" + +#~ msgid "new file already exists" +#~ msgstr "Un nouveau fichier existe toujours" + +#~ msgid "Select area first" +#~ msgstr "Sélectionnez une zone en premier." + +#~ msgid "Translate" +#~ msgstr "Traduire" + +#~ msgid "full rebuild" +#~ msgstr "Reconstruction complète" + +#~ msgid "incremental" +#~ msgstr "Incrémental" + +#~ msgid "" +#~ "Rename failed \n" +#~ " %s" +#~ msgstr "" +#~ "Le renommage a échoué \n" +#~ " %s" + +#~ msgid "transition" +#~ msgstr "Transition" + +#~ msgid "Discard modifications?" +#~ msgstr "Annuler les modifications ?" + +#~ msgid "Edit Comments" +#~ msgstr "Modifier les commentaires" + +#~ msgid "Edit Caption" +#~ msgstr "Modifier la légende" + +#~ msgid "new tags index will now be created" +#~ msgstr "" +#~ "Le nouveau fichier d'indexation des étiquettes \n" +#~ "va maintenant être créé." + +#~ msgid "cannot read .dist file" +#~ msgstr "Impossible de lire le fichier .dist" + +#~ msgid "" +#~ "New tags file already exists! \n" +#~ "Proceed anyway?" +#~ msgstr "" +#~ "Le fichier des nouvelles étiquettes existe toujours ! \n" +#~ "Voulez vous continuer le processus ?" + +#~ msgid "" +#~ "Convert tags to new standard now? \n" +#~ "Are your image files backed-up?" +#~ msgstr "" +#~ "Convertir maintenant les étiquettes vers le nouveau standard ? \n" +#~ "Vos images sont-elles sauvegardées ?" + +#~ msgid "Convert tags to new standard" +#~ msgstr "Convertir les étiquettes vers le nouveau standard" + +#~ msgid "Convert Tags !!!" +#~ msgstr "Convertir les étiquettes !!!" + +#~ msgid "tags index file error: %s" +#~ msgstr "" +#~ "Le fichier d'indexation des étiquettes \n" +#~ "retourne une erreur : %s" + +#~ msgid "save select area as a file" +#~ msgstr "Enregistrer la zone sélectionnée en tant que fichier" + +#~ msgid "manage tags" +#~ msgstr "Gérer les étiquettes" + +#~ msgid "brightness to clip (percent)" +#~ msgstr "Luminosité à remplir (pourcentage)" + +#~ msgid "Use F1 for context help" +#~ msgstr "Utiliser F1 pour l'aide contextuel" + +#~ msgid "Stack" +#~ msgstr "Empiler" + +#~ msgid "Rebuild Tags Index" +#~ msgstr "Reconstruire l'index des étiquettes" + +#~ msgid "No tags index file" +#~ msgstr "Le fichier d'indexation des étiquettes n'existe pas." + +#~ msgid "HDR" +#~ msgstr "HDR" + +#~ msgid "HDF" +#~ msgstr "HDF" + +#~ msgid "Constrain" +#~ msgstr "Contraindre" + +#~ msgid "Area" +#~ msgstr "Zone" + +#~ msgid "target group area" +#~ msgstr "Zone du groupe cible" + +#~ msgid "vertical unbend" +#~ msgstr "Axe vertical" + +#~ msgid "select by mouse:" +#~ msgstr "Sélection avec la souris : " + +#~ msgid "select by color:" +#~ msgstr "Sélection par couleurs : " + +#~ msgid "press ESC to exit" +#~ msgstr "Appuyer sur « Échap » pour quitter" + +#~ msgid "horizontal unbend" +#~ msgstr "Axe horizontal" + +#~ msgid "Rebuild Thumbnails" +#~ msgstr "Reconstruire les miniatures" + +#~ msgid "Font Colors" +#~ msgstr "Couleur de la police" + +#~ msgid "area outline has a hole" +#~ msgstr "Le contour de la zone a un trou" + +#~ msgid "Create Launcher" +#~ msgstr "Créer un lanceur" + +#~ msgid "make new version" +#~ msgstr "Créer une nouvelle version" + +#~ msgid "click on window to show RGB" +#~ msgstr "Cliquez sur la fenêtre pour afficher les couleurs RVB" + +#~ msgid "Save As" +#~ msgstr "Enreg. sous" + +#~ msgid "Clone fotoxx" +#~ msgstr "Cloner Fotoxx" + +#~ msgid "random" +#~ msgstr "Aléatoire" + +#~ msgid "Whole Image" +#~ msgstr "Toute l'image" + +#~ msgid "Time Interval" +#~ msgstr "Intervalle de temps" + +#~ msgid "print" +#~ msgstr "Imprimer" + +#~ msgid "printer ID" +#~ msgstr "ID de l'imprimante" + +#~ msgid "paper format" +#~ msgstr "Format de papier" + +#~ msgid "portrait" +#~ msgstr "Portrait" + +#~ msgid "landscape" +#~ msgstr "Paysage" + +#~ msgid "paper format is crazy" +#~ msgstr "Format de papier erroné" + +#~ msgid "open a file" +#~ msgstr "Ouvrir un fichier" + +#~ msgid "select new folder" +#~ msgstr "Sélectionner un nouveau dossier" + +#~ msgid "open a directory" +#~ msgstr "Ouvrir un dossier" + +#~ msgid "folder" +#~ msgstr "Dossier" + +#~ msgid "select new file" +#~ msgstr "Sélectionner un nouveau fichier" + +#~ msgid "lens name" +#~ msgstr "nom de la focale" + +#~ msgid "my mouse" +#~ msgstr "Ma souris" + +#~ msgid "Lens Parameters" +#~ msgstr "Configuration de l'objectif" diff -Nru fotoxx-11.11.1/locales/fotoxx-gl.po fotoxx-12.01.2/locales/fotoxx-gl.po --- fotoxx-11.11.1/locales/fotoxx-gl.po 1970-01-01 00:00:00.000000000 +0000 +++ fotoxx-12.01.2/locales/fotoxx-gl.po 2012-01-04 08:47:11.000000000 +0000 @@ -0,0 +1,3288 @@ +# Galician translations for home package. +# Copyright (C) 2008 THE home'S COPYRIGHT HOLDER +# This file is distributed under the same license as the home package. +# mico , 2008. +# +msgid "" +msgstr "" +"Project-Id-Version: fotoxx-6.9.2\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-12-31 21:05+0100\n" +"PO-Revision-Date: 2009-11-04 23:34+0100\n" +"Last-Translator: Miguel Anxo Bouzada \n" +"Language-Team: GALPon MiniNo \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Poedit-Language: Galician\n" +"X-Poedit-Country: SPAIN\n" + +#: f.art.cc:47 +msgid "Set color depth to 1-16 bits" +msgstr " Establecer a profundidade de cor 1-16 bits" + +#: f.art.cc:57 +msgid "Set Color Depth" +msgstr "Axustar a profundidade da cor" + +#: f.art.cc:171 +msgid "Simulate Drawing" +msgstr "Semellar un debuxo" + +#: f.art.cc:213 f.retouch.cc:1759 f.retouch.cc:5991 +msgid "contrast" +msgstr "Contraste" + +#: f.art.cc:215 +msgid "outlines" +msgstr "Bordos" + +#: f.art.cc:220 +msgid "pencil" +msgstr "Lapis" + +#: f.art.cc:221 +msgid "chalk" +msgstr "Xiz" + +#: f.art.cc:381 +msgid "Add Image Outlines" +msgstr "" + +#: f.art.cc:394 +msgid "outline threshold" +msgstr "" + +#: f.art.cc:397 +msgid "outline width" +msgstr "" + +#: f.art.cc:400 +msgid "image brightness" +msgstr "" + +#: f.art.cc:611 +msgid "Simulate Embossing" +msgstr "Semellar un repuxado" + +#: f.art.cc:626 +msgid "depth" +msgstr "Profundidade" + +#: f.art.cc:628 f.file.cc:919 f.retouch.cc:6692 +msgid "color" +msgstr "Cor" + +#: f.art.cc:821 +msgid "Simulate Tiles" +msgstr "Semellar un mosaicos" + +#: f.art.cc:825 +msgid "tile size" +msgstr "Tamaño do mosaico" + +#: f.art.cc:829 +msgid "tile gap" +msgstr "Separación do mosaico" + +#: f.art.cc:1003 +msgid "Convert Image to Dots" +msgstr "" + +#: f.art.cc:1007 +msgid "dot size" +msgstr "" + +#: f.art.cc:1222 +msgid "Simulate Painting" +msgstr "Semellar unha pintura" + +#: f.art.cc:1226 +msgid "color depth" +msgstr "Profundidade da cor" + +#: f.art.cc:1230 +msgid "patch area goal" +msgstr "" + +#: f.art.cc:1234 +msgid "req. color match" +msgstr "Correspondencia de cor requerida" + +#: f.art.cc:1238 +msgid "borders" +msgstr "Bordos" + +#: f.comp.cc:1956 f.comp.cc:1961 f.comp.cc:2582 f.comp.cc:2587 f.comp.cc:3266 +#: f.comp.cc:3271 f.comp.cc:3816 f.comp.cc:3821 +msgid "Select 2 to 9 files" +msgstr "" + +#: f.comp.cc:1982 f.comp.cc:2608 f.comp.cc:3292 f.comp.cc:3842 +msgid "Images are not all the same size" +msgstr "" + +#: f.comp.cc:2321 +msgid "Adjust Image Contributions" +msgstr "" + +#: f.comp.cc:2324 f.retouch.cc:886 +msgid "dark pixels" +msgstr "" + +#: f.comp.cc:2326 +msgid "light pixels" +msgstr "" + +#: f.comp.cc:2328 f.info.cc:159 +msgid "file:" +msgstr "Ficheiro:" + +#: f.comp.cc:2843 +msgid "Paint and Warp Image" +msgstr "" + +#: f.comp.cc:2846 f.comp.cc:3520 f.comp.cc:4959 f.comp.cc:5705 +msgid "image" +msgstr "" + +#: f.comp.cc:2850 f.retouch.cc:6696 +msgid "paint" +msgstr "Pintar" + +#: f.comp.cc:2851 +msgid "warp" +msgstr "" + +#: f.comp.cc:3518 +msgid "Select and Paint Image" +msgstr "" + +#: f.comp.cc:4031 +msgid "Adjust Pixel Composition" +msgstr "" + +#: f.comp.cc:4283 f.comp.cc:4288 f.comp.cc:5173 f.comp.cc:5178 +msgid "Select 2 to 4 files" +msgstr "" + +#: f.comp.cc:4361 +msgid "" +"Drag images into rough alignment.\n" +"To rotate, drag from lower edge." +msgstr "" + +#: f.comp.cc:4363 +msgid "Search for lens mm and bow" +msgstr "" + +#: f.comp.cc:4409 f.comp.cc:5298 +msgid "Pre-align Images" +msgstr "Pre-aliñar imaxes" + +#: f.comp.cc:4413 f.comp.cc:5302 +msgid "lens mm" +msgstr "Lonxitude focal (mm)" + +#: f.comp.cc:4417 f.comp.cc:5306 +msgid "lens bow" +msgstr "Curvatura da lente" + +#: f.comp.cc:4419 f.comp.cc:5308 +msgid "Resize" +msgstr "" + +#: f.comp.cc:4420 f.comp.cc:5309 +msgid "resize window" +msgstr "" + +#: f.comp.cc:4457 +msgid "use two images only" +msgstr "" + +#: f.comp.cc:4478 f.comp.cc:4676 f.comp.cc:4875 f.comp.cc:5357 f.comp.cc:5620 +msgid "Too little overlap, cannot align" +msgstr "Solapamento moi pequeno, non se pode aliñar" + +#: f.comp.cc:4950 f.comp.cc:5696 +msgid "Match Brightness and Color" +msgstr "" + +#: f.comp.cc:4974 f.comp.cc:5720 +msgid "auto color" +msgstr "" + +#: f.comp.cc:4975 f.comp.cc:5721 +msgid "file color" +msgstr "" + +#: f.comp.cc:5251 +msgid "" +"Drag images into rough alignment.\n" +"To rotate, drag from right edge." +msgstr "" + +#: f.file.cc:169 f.file.cc:341 fotoxx-12.01.cc:189 fotoxx-12.01.cc:325 +msgid "Open Image File" +msgstr "Abrir ficheiro de imaxe" + +#: f.file.cc:321 fotoxx-12.01.cc:2862 +msgid "prior function still active" +msgstr "" + +#: f.file.cc:503 +msgid "Overwrite original file?" +msgstr "" + +#: f.file.cc:504 +msgid "Do not warn again" +msgstr "" + +#: f.file.cc:520 +msgid "Warning" +msgstr "" + +#: f.file.cc:643 +msgid "Save File" +msgstr "Gardar o ficheiro" + +#: f.file.cc:666 zfuncs.cc:6478 +msgid "quality" +msgstr "" + +#: f.file.cc:668 +msgid "make current" +msgstr "" + +#: f.file.cc:725 +msgid "jpeg quality must be 1-100" +msgstr "" + +#: f.file.cc:747 +#, c-format +msgid "" +"Overwrite file? \n" +" %s" +msgstr "" +"Sobrescribir ficheiro? \n" +" %s" + +#: f.file.cc:903 fotoxx-12.01.cc:196 +msgid "Create Blank Image" +msgstr "" + +#: f.file.cc:905 +msgid "file name" +msgstr "" + +#: f.file.cc:910 f.transform.cc:353 +msgid "width" +msgstr "" + +#: f.file.cc:913 f.tools.cc:477 f.transform.cc:356 +msgid "height" +msgstr "" + +#: f.file.cc:1033 +msgid "" +"Linux standard trash is not supported. \n" +"Desktop trash folder will be created." +msgstr "" + +#: f.file.cc:1051 +msgid "Move read-only file to trash?" +msgstr "Enviar o ficheiro de só lectura ao lixo?" + +#: f.file.cc:1077 +#, c-format +msgid "Cannot create trash folder: %s" +msgstr "Non se pode crear o cesto do lixo: %s" + +#: f.file.cc:1085 f.file.cc:1091 zfuncs.cc:3356 +#, c-format +msgid "error: %s" +msgstr "erro: %s" + +#: f.file.cc:1136 fotoxx-12.01.cc:198 +msgid "Rename Image File" +msgstr "Renomear ficheiro de imaxe" + +#: f.file.cc:1141 +msgid "old name" +msgstr "Nome antigo" + +#: f.file.cc:1142 +msgid "rename to" +msgstr "Renomear como" + +#: f.file.cc:1143 +msgid "previous" +msgstr "Anterior" + +#: f.file.cc:1229 +msgid "The target file already exists" +msgstr "O ficheiro de destino xa existe" + +#: f.file.cc:1237 +#, c-format +msgid "" +"Rename failed: \n" +" %s" +msgstr "" + +#: f.file.cc:1285 +msgid "Batch Rename" +msgstr "" + +#: f.file.cc:1288 f.file.cc:1340 f.info.cc:1519 f.info.cc:1773 f.tools.cc:543 +#: f.tools.cc:2990 +#, c-format +msgid "%d files selected" +msgstr "" + +#: f.file.cc:1290 +msgid "new base name" +msgstr "" + +#: f.file.cc:1293 +msgid "starting sequence" +msgstr "" + +#: f.file.cc:1295 +msgid "increment" +msgstr "" + +#: f.file.cc:1316 +msgid "select files to rename" +msgstr "" + +#: f.file.cc:1321 +msgid "base name / sequence / increment not reasonable" +msgstr "" + +#: f.file.cc:1380 +msgid "new file already exists:" +msgstr "" + +#: f.file.cc:1388 +msgid "filespec too long:" +msgstr "" + +#: f.file.cc:1399 +msgid "Rename failed:" +msgstr "" + +#: f.file.cc:1660 fotoxx.h:729 +msgid "Add" +msgstr "" + +#: f.file.cc:1660 fotoxx.h:781 +msgid "Remove" +msgstr "" + +#: f.file.cc:1662 +msgid "menu name" +msgstr "" + +#: f.file.cc:1733 f.file.cc:1754 +msgid "Restart Fotoxx to update plugin menu" +msgstr "" + +#: f.info.cc:70 +msgid "Edit Caption and Comments" +msgstr "" + +#: f.info.cc:156 fotoxx-12.01.cc:225 +msgid "Edit Tags" +msgstr "Editar etiquetas" + +#: f.info.cc:163 +msgid "image date (yyyymmdd)" +msgstr "Data da imaxe (aaaammdd)" + +#: f.info.cc:165 +msgid "use last" +msgstr "Usar o último" + +#: f.info.cc:168 +msgid "image stars" +msgstr "Imaxe estrela" + +#: f.info.cc:186 +msgid "current tags" +msgstr "Etiquetas actuais" + +#: f.info.cc:191 +msgid "recent tags" +msgstr "" + +#: f.info.cc:196 f.info.cc:358 f.info.cc:1368 f.info.cc:2384 +msgid "defined tags" +msgstr "" + +#: f.info.cc:345 fotoxx-12.01.cc:226 +msgid "Manage Tags" +msgstr "" + +#: f.info.cc:348 +msgid "category" +msgstr "" + +#: f.info.cc:351 +msgid "tag" +msgstr "" + +#: f.info.cc:354 +msgid "create" +msgstr "" + +#: f.info.cc:355 f.navi.cc:1421 +msgid "delete" +msgstr "Borrar" + +#: f.info.cc:1235 f.info.cc:1319 +#, c-format +msgid "search index file error: %s" +msgstr "" + +#: f.info.cc:1351 fotoxx-12.01.cc:227 +msgid "Batch Add Tags" +msgstr "" + +#: f.info.cc:1354 +msgid "tags to add" +msgstr "" + +#: f.info.cc:1359 +msgid "create tag" +msgstr "Crear etiqueta" + +#: f.info.cc:1415 f.info.cc:1608 +#, c-format +msgid "" +"%s \n" +" too many tags" +msgstr "" + +#: f.info.cc:1553 fotoxx-12.01.cc:228 +msgid "Batch Delete Tag" +msgstr "" + +#: f.info.cc:1556 +msgid "tag to remove" +msgstr "" + +#: f.info.cc:1560 +msgid "optional replacement" +msgstr "" + +#: f.info.cc:1565 f.tools.cc:2943 +msgid "0 files selected" +msgstr "" + +#: f.info.cc:1568 +msgid "search all files" +msgstr "" + +#: f.info.cc:1653 +msgid "no files selected" +msgstr "" + +#: f.info.cc:1659 +msgid "no tag specified" +msgstr "" + +#: f.info.cc:1683 f.info.cc:1712 +msgid "specify tag" +msgstr "" + +#: f.info.cc:1821 +msgid "View Info" +msgstr "" + +#: f.info.cc:1889 fotoxx-12.01.cc:231 +msgid "Edit Info" +msgstr "" + +#: f.info.cc:1987 fotoxx-12.01.cc:232 +msgid "Delete Info" +msgstr "" + +#: f.info.cc:1989 fotoxx.h:731 +msgid "All" +msgstr "" + +#: f.info.cc:1990 +msgid "One Key:" +msgstr "" + +#: f.info.cc:2343 +msgid "Search Tags, Comments, File Names" +msgstr "" + +#: f.info.cc:2350 +msgid "date range" +msgstr "Formato da data" + +#: f.info.cc:2351 +msgid "stars range" +msgstr "Rango de estrelas" + +#: f.info.cc:2352 +msgid "search tags" +msgstr "Buscar" + +#: f.info.cc:2353 +msgid "search text" +msgstr "" + +#: f.info.cc:2354 +msgid "file names" +msgstr "" + +#: f.info.cc:2359 +msgid "(yyyymmdd)" +msgstr "" + +#: f.info.cc:2365 +msgid "all/any" +msgstr "" + +#: f.info.cc:2702 +msgid "No matching images found" +msgstr "Non se atoparon imaxes" + +#: f.info.cc:2706 f.info.cc:3059 +msgid "No search index file present" +msgstr "" + +#: f.info.cc:2777 +msgid "Additional Items for Report" +msgstr "" + +#: f.navi.cc:188 f.navi.cc:576 f.navi.cc:706 f.navi.cc:707 f.navi.cc:709 +msgid "bigger" +msgstr "Maior" + +#: f.navi.cc:188 +msgid "increase thumbnail size" +msgstr "Aumentar o tamaño da miniatura" + +#: f.navi.cc:189 +msgid "reduce thumbnail size" +msgstr "Reducir tamaño da miniatura" + +#: f.navi.cc:189 f.navi.cc:586 f.navi.cc:708 f.navi.cc:710 +msgid "smaller" +msgstr "Menor" + +#: f.navi.cc:190 f.navi.cc:600 +msgid "parent" +msgstr "" + +#: f.navi.cc:190 +msgid "parent directory" +msgstr "" + +#: f.navi.cc:191 f.navi.cc:625 f.navi.cc:717 +msgid "first page" +msgstr "Primeira páxina" + +#: f.navi.cc:191 +msgid "jump to first file" +msgstr "Cambiar ao primeiro ficheiro" + +#: f.navi.cc:192 f.navi.cc:623 f.navi.cc:712 f.navi.cc:719 +msgid "prev page" +msgstr "Páxina anterior" + +#: f.navi.cc:192 +msgid "previous page" +msgstr "Páxina anterior" + +#: f.navi.cc:193 f.navi.cc:621 f.navi.cc:714 +msgid "prev row" +msgstr "fila anterior" + +#: f.navi.cc:193 +msgid "previous row" +msgstr "Fila anterior" + +#: f.navi.cc:194 f.navi.cc:622 f.navi.cc:715 +msgid "next row" +msgstr "Seguinte fila" + +#: f.navi.cc:195 f.navi.cc:624 f.navi.cc:713 f.navi.cc:720 +msgid "next page" +msgstr "Páxina seguinte" + +#: f.navi.cc:195 +msgid "ttip::next page" +msgstr "" + +#: f.navi.cc:196 +msgid "jump to last file" +msgstr "Cambiar ao último ficheiro" + +#: f.navi.cc:196 f.navi.cc:626 f.navi.cc:718 +msgid "last page" +msgstr "Última páxina" + +#: f.navi.cc:197 f.navi.cc:571 +msgid "close" +msgstr "Pechar" + +#: f.navi.cc:197 +msgid "close image gallery" +msgstr "Pechar a galería de imaxes" + +#: f.navi.cc:1413 fotoxx.h:787 +msgid "Select Files" +msgstr "" + +#: f.navi.cc:1413 zfuncs.cc:6296 zfuncs.cc:6332 zfuncs.cc:6485 zfuncs.cc:6728 +#: zfuncs.cc:7427 zfuncs.cc:7433 zfuncs.cc:7439 zfuncs.cc:7445 +msgid "cancel" +msgstr "Cancelar" + +#: f.navi.cc:1413 zfuncs.cc:6728 +msgid "done" +msgstr "" + +#: f.navi.cc:1422 +msgid "insert" +msgstr "Inserir" + +#: f.navi.cc:1423 +msgid "add all" +msgstr "" + +#: f.retouch.cc:55 +msgid "Adjust Brightness and Color" +msgstr "Axustar brillo e cor" + +#: f.retouch.cc:110 +msgid "small-steps" +msgstr "" + +#: f.retouch.cc:119 +msgid "color saturation" +msgstr "Saturación da cor" + +#: f.retouch.cc:126 +msgid " reset 1 " +msgstr " Restablecer 1" + +#: f.retouch.cc:127 +msgid "reset all" +msgstr "Restablecer todo" + +#: f.retouch.cc:599 +msgid "adjust image gamma" +msgstr "" + +#: f.retouch.cc:885 +msgid "Expand Brightness Range" +msgstr "" + +#: f.retouch.cc:887 +msgid "bright pixels" +msgstr "" + +#: f.retouch.cc:1058 +msgid "Flatten Brightness Distribution" +msgstr "Distribuir o brillo uniformemente" + +#: f.retouch.cc:1072 +msgid "Flatten" +msgstr "Aplanar" + +#: f.retouch.cc:1334 +msgid "Ramp brightness across image" +msgstr "" + +#: f.retouch.cc:1730 fotoxx-12.01.cc:272 +msgid "Tone Mapping" +msgstr "" + +#: f.retouch.cc:1758 +msgid "low" +msgstr "" + +#: f.retouch.cc:1760 +msgid "high" +msgstr "" + +#: f.retouch.cc:1763 +msgid "Amplify" +msgstr "" + +#: f.retouch.cc:2069 +msgid "Adjust White Balance" +msgstr "Axustar o balance de branco" + +#: f.retouch.cc:2070 +msgid "Click white or gray image location" +msgstr "Faga clic na ubicación da imaxe en branco ou gris" + +#: f.retouch.cc:2278 +msgid "Color Match Images" +msgstr "" + +#: f.retouch.cc:2307 +msgid "mouse radius for color sample" +msgstr "" + +#: f.retouch.cc:2309 f.retouch.cc:2314 fotoxx-12.01.cc:246 fotoxx-12.01.cc:325 +#: fotoxx.h:769 +msgid "Open" +msgstr "Abrir" + +#: f.retouch.cc:2310 +msgid "image for source color" +msgstr "" + +#: f.retouch.cc:2312 +msgid "click on image to get source color" +msgstr "" + +#: f.retouch.cc:2315 +msgid "image to set matching color" +msgstr "" + +#: f.retouch.cc:2317 +msgid "click on image to set matching color" +msgstr "" + +#: f.retouch.cc:2372 +msgid "select source image color first" +msgstr "" + +#: f.retouch.cc:2584 +msgid "Add standard bias" +msgstr "" + +#: f.retouch.cc:2591 +msgid "+Brightness -Density" +msgstr "" + +#: f.retouch.cc:2592 +msgid "+Red -Cyan" +msgstr "" + +#: f.retouch.cc:2593 +msgid "+Green -Magenta" +msgstr "" + +#: f.retouch.cc:2594 +msgid "+Blue -Yellow" +msgstr "" + +#: f.retouch.cc:2599 +msgid "Contrast" +msgstr "" + +#: f.retouch.cc:2600 fotoxx.h:778 +msgid "Red" +msgstr "Vermello" + +#: f.retouch.cc:2601 fotoxx.h:758 +msgid "Green" +msgstr "Verde" + +#: f.retouch.cc:2602 fotoxx.h:736 +msgid "Blue" +msgstr "Azul" + +#: f.retouch.cc:2730 +msgid "Load DRGB parameters" +msgstr "" + +#: f.retouch.cc:2732 f.retouch.cc:2804 f.retouch.cc:6102 f.retouch.cc:6198 +msgid "File:" +msgstr "" + +#: f.retouch.cc:2751 f.retouch.cc:2824 +msgid "DRGB parameters file" +msgstr "" + +#: f.retouch.cc:2769 f.retouch.cc:6142 +msgid "file not found" +msgstr "" + +#: f.retouch.cc:2802 +msgid "Save DRGB parameters" +msgstr "" + +#: f.retouch.cc:3034 f.tools.cc:2404 +msgid "Click image to select pixels." +msgstr "" + +#: f.retouch.cc:3072 fotoxx-12.01.cc:276 +msgid "Revise RGB" +msgstr "" + +#: f.retouch.cc:3084 +msgid "Metric:" +msgstr "" + +#: f.retouch.cc:3139 +msgid "Blend" +msgstr "" + +#: f.retouch.cc:3519 +msgid "" +"Method 1:\n" +" Left-click on red-eye to darken.\n" +"Method 2:\n" +" Drag down and right to enclose red-eye.\n" +" Left-click on red-eye to darken.\n" +"Undo red-eye:\n" +" Right-click on red-eye." +msgstr "" +"Método 1:\n" +" Clic-esquerdo no ollo vermello pra escurecer.\n" +"Método 2:\n" +" Pica e arrastra a dereita para delimitar o ollo vermello.\n" +" Clic-esquerdo para escurecer o ollo vermello.\n" +"Desfacer ollos vermellos:\n" +" Clic-dereito no ollo vermello." + +#: f.retouch.cc:3534 +msgid "Red Eye Reduction" +msgstr "Redución de ollos vermellos" + +#: f.retouch.cc:3968 +msgid "Set Blur Radius" +msgstr "Definir o radio do desenfoque" + +#: f.retouch.cc:4195 fotoxx-12.01.cc:279 +msgid "Sharpen Image" +msgstr "Enfocar a imaxe" + +#: f.retouch.cc:4202 +msgid "edge detection" +msgstr "Detección de bordos" + +#: f.retouch.cc:4203 +msgid "cycles" +msgstr "Ciclos" + +#: f.retouch.cc:4204 +msgid "reduce" +msgstr "Reducir" + +#: f.retouch.cc:4215 +msgid "unsharp mask" +msgstr "Máscara de desenfoque" + +#: f.retouch.cc:4228 +msgid "brightness gradient" +msgstr "" + +#: f.retouch.cc:4634 +msgid "" +" Press the reduce button to \n" +" reduce noise in small steps. \n" +" Use undo to start over." +msgstr "" +" Prema o boton Reducir para \n" +" reducir o ruido en pequenos pasos. \n" +" Use Desfacer para comezar de novo." + +#: f.retouch.cc:4645 +msgid "Noise Reduction" +msgstr "Reducción de ruido" + +#: f.retouch.cc:4650 +msgid "algorithm" +msgstr "Algoritmo" + +#: f.retouch.cc:4657 +msgid "flatten outliers by color (1)" +msgstr "Aplanar os valores extremos de cor (1)" + +#: f.retouch.cc:4658 +msgid "flatten outliers by color (2)" +msgstr "Aplanar os valores extremos de cor (2)" + +#: f.retouch.cc:4659 +msgid "set median brightness by color" +msgstr "Configurar a mediana de brillo por cor" + +#: f.retouch.cc:4660 f.retouch.cc:4661 +msgid "top hat filter by color" +msgstr "Filtro de cor «sombreiro de copa (Top-hat)»" + +#: f.retouch.cc:4976 +msgid "" +"1. Drag mouse to select. \n" +"2. Erase. 3. Repeat. " +msgstr "" + +#: f.retouch.cc:4998 fotoxx-12.01.cc:281 +msgid "Smart Erase" +msgstr "" + +#: f.retouch.cc:5003 fotoxx.h:776 +msgid "Radius" +msgstr "Radio" + +#: f.retouch.cc:5005 +msgid "Blur" +msgstr "" + +#: f.retouch.cc:5008 +msgid "New Area" +msgstr "" + +#: f.retouch.cc:5379 fotoxx-12.01.cc:282 +msgid "Remove Dust" +msgstr "" + +#: f.retouch.cc:5383 +msgid "spot size limit" +msgstr "" + +#: f.retouch.cc:5386 +msgid "max. brightness" +msgstr "" + +#: f.retouch.cc:5389 +msgid "min. contrast" +msgstr "" + +#: f.retouch.cc:5983 fotoxx-12.01.cc:283 +msgid "Fix Stuck Pixels" +msgstr "" + +#: f.retouch.cc:5989 +msgid "pixel group" +msgstr "" + +#: f.retouch.cc:5990 +msgid "circle color" +msgstr "" + +#: f.retouch.cc:6100 +msgid "Load Stuck Pixels" +msgstr "" + +#: f.retouch.cc:6124 f.retouch.cc:6220 +msgid "Stuck Pixels file" +msgstr "" + +#: f.retouch.cc:6164 +msgid "file format error" +msgstr "" + +#: f.retouch.cc:6192 +msgid "there are zero stuck pixels" +msgstr "" + +#: f.retouch.cc:6196 +msgid "Save Stuck Pixels" +msgstr "" + +#: f.retouch.cc:6686 +#, c-format +msgid "Undo Memory %d%c" +msgstr "Memoria de desfacer %d%c" + +#: f.retouch.cc:6688 fotoxx-12.01.cc:284 +msgid "Edit Pixels" +msgstr "Editar píxeles" + +#: f.retouch.cc:6695 +msgid "pick" +msgstr "Recoller" + +#: f.retouch.cc:6697 +msgid "erase" +msgstr "Borrar" + +#: f.retouch.cc:6705 +msgid "paintbrush radius" +msgstr "Radio do pincel" + +#: f.retouch.cc:6706 +msgid "transparency center" +msgstr "Centro da transparencia" + +#: f.retouch.cc:6707 +msgid "transparency edge" +msgstr "Bordo da transparencia" + +#: f.retouch.cc:6972 +msgid "" +"Undo memory limit has been reached. \n" +"Save work with [done], then resume editing." +msgstr "" +"Acadouse o límite de memoria de desfacer. \n" +"Garde o traballo con [Feito], e despois retome a edición." + +#: f.select.cc:54 f.select.cc:2461 +msgid "Select Area for Edits" +msgstr "" + +#: f.select.cc:55 f.select.cc:2462 +msgid "Press F1 for help" +msgstr "" + +#: f.select.cc:64 +msgid "" +"Select Area not supported \n" +"by this edit function" +msgstr "" + +#: f.select.cc:103 f.tools.cc:901 +msgid "rectangle" +msgstr "" + +#: f.select.cc:104 f.tools.cc:902 +msgid "ellipse" +msgstr "" + +#: f.select.cc:110 +msgid "draw: freehand" +msgstr "" + +#: f.select.cc:111 +msgid "draw: follow edge" +msgstr "" + +#: f.select.cc:114 +msgid "select by mouse" +msgstr "" + +#: f.select.cc:116 f.select.cc:2496 +msgid "mouse radius" +msgstr "" + +#: f.select.cc:120 +msgid "match mouse color" +msgstr "" + +#: f.select.cc:124 +msgid "search range" +msgstr "" + +#: f.select.cc:126 +msgid "firewall" +msgstr "" + +#: f.select.cc:326 f.select.cc:467 +#, c-format +msgid "exceed %d edits" +msgstr "" + +#: f.select.cc:1021 +msgid "" +"Click one time inside each enclosed area \n" +"(possible gaps in the outline will be found). \n" +"Press F1 for help." +msgstr "" + +#: f.select.cc:1078 +msgid "finish area" +msgstr "" + +#: f.select.cc:1113 +msgid "searching" +msgstr "" + +#: f.select.cc:1185 +msgid "outline has a gap" +msgstr "" + +#: f.select.cc:1189 +msgid "success" +msgstr "" + +#: f.select.cc:1440 f.select.cc:1470 +msgid "the area is not finished" +msgstr "" + +#: f.select.cc:1563 +msgid "Edge calculation in progress" +msgstr "Precisa calcular o bordo" + +#: f.select.cc:1572 +msgid "Area Edge Calc" +msgstr "Calcular a área do bordo" + +#: f.select.cc:1863 +msgid "position with mouse click/drag" +msgstr "" + +#: f.select.cc:1887 +msgid "Paste Image" +msgstr "" + +#: f.select.cc:1901 +msgid "angle" +msgstr "" + +#: f.select.cc:2160 +msgid "load select area from a file" +msgstr "" + +#: f.select.cc:2194 +msgid "cannot open .tiff and .info files" +msgstr "" + +#: f.select.cc:2213 +msgid "save select area to a file" +msgstr "" + +#: f.select.cc:2248 fotoxx-12.01.cc:248 +msgid "Select Whole Image" +msgstr "" + +#: f.select.cc:2249 +msgid "Edit Function Amplifier" +msgstr "" + +#: f.select.cc:2463 +msgid "Edit function must be active" +msgstr "" + +#: f.select.cc:2499 +msgid "power: center" +msgstr "" + +#: f.select.cc:2501 +msgid "edge" +msgstr "" + +#: f.select.cc:2504 +msgid "reset area" +msgstr "" + +#: f.tools.cc:42 +msgid "" +"When editing a collection, right-click \n" +"an image or thumbnail to add or remove." +msgstr "" + +#: f.tools.cc:70 fotoxx-12.01.cc:204 +msgid "Manage Collections" +msgstr "" + +#: f.tools.cc:85 +msgid "Start new collection" +msgstr "" + +#: f.tools.cc:87 +msgid "Edit a collection" +msgstr "" + +#: f.tools.cc:89 +msgid "View a collection" +msgstr "" + +#: f.tools.cc:91 +msgid "Delete a collection" +msgstr "" + +#: f.tools.cc:95 +msgid "Editing:" +msgstr "" + +#: f.tools.cc:99 +msgid "Action:" +msgstr "" + +#: f.tools.cc:133 +msgid "New Collection" +msgstr "" + +#: f.tools.cc:156 +msgid "Edit Collection" +msgstr "" + +#: f.tools.cc:172 +msgid "View Collection" +msgstr "" + +#: f.tools.cc:193 +msgid "Delete Collection" +msgstr "" + +#: f.tools.cc:196 +#, c-format +msgid "delete %s ?" +msgstr "" + +#: f.tools.cc:223 +#, c-format +msgid "add image to collection: %s" +msgstr "" + +#: f.tools.cc:225 f.tools.cc:270 +msgid "remove image from collection" +msgstr "" + +#: f.tools.cc:226 f.tools.cc:271 f.tools.cc:298 +msgid "remove and save image" +msgstr "" + +#: f.tools.cc:227 f.tools.cc:316 +msgid "insert saved images here" +msgstr "" + +#: f.tools.cc:256 +msgid "add image to collection" +msgstr "" + +#: f.tools.cc:301 +msgid "too many saved files" +msgstr "" + +#: f.tools.cc:373 fotoxx-12.01.cc:205 +msgid "Move Collections" +msgstr "" + +#: f.tools.cc:375 +msgid "old top directory" +msgstr "" + +#: f.tools.cc:378 +msgid "new top directory" +msgstr "" + +#: f.tools.cc:434 +msgid "completed" +msgstr "" + +#: f.tools.cc:467 +msgid "Batch Convert/Resize/Export" +msgstr "" + +#: f.tools.cc:474 +msgid "new max. width" +msgstr "" + +#: f.tools.cc:481 +msgid "new file type" +msgstr "" + +#: f.tools.cc:482 +msgid "same" +msgstr "" + +#: f.tools.cc:490 +msgid "replace originals" +msgstr "" + +#: f.tools.cc:491 +msgid "export to location" +msgstr "" + +#: f.tools.cc:492 +msgid "remove EXIF" +msgstr "" + +#: f.tools.cc:549 +msgid "Select directory" +msgstr "" + +#: f.tools.cc:583 +#, c-format +msgid "replace original files? (max. %d x %d)" +msgstr "" + +#: f.tools.cc:590 +#, c-format +msgid "" +"copy files? (max. %d x %d) \n" +" to location %s" +msgstr "" + +#: f.tools.cc:601 +msgid "location is not a valid directory" +msgstr "" + +#: f.tools.cc:608 f.tools.cc:3007 +#, c-format +msgid "max. size %d x %d is not reasonable" +msgstr "" + +#: f.tools.cc:654 +msgid "*** file already exists" +msgstr "" + +#: f.tools.cc:662 +msgid "*** file type not supported" +msgstr "" + +#: f.tools.cc:741 +msgid "Program ufraw-batch is required" +msgstr "" + +#: f.tools.cc:751 fotoxx.h:770 +msgid "Open RAW File" +msgstr "Abrir ficheiro RAW" + +#: f.tools.cc:764 +msgid "Select RAW files to convert" +msgstr "" + +#: f.tools.cc:769 +msgid "Choose file type" +msgstr "" + +#: f.tools.cc:888 +msgid "Press ESC to exit slide show" +msgstr "" + +#: f.tools.cc:889 +msgid "show only latest file versions" +msgstr "" + +#: f.tools.cc:893 +msgid "arrow keys" +msgstr "" + +#: f.tools.cc:894 +msgid "instant" +msgstr "" + +#: f.tools.cc:895 +msgid "fade-in" +msgstr "" + +#: f.tools.cc:896 +msgid "roll-right" +msgstr "" + +#: f.tools.cc:897 +msgid "roll-down" +msgstr "" + +#: f.tools.cc:898 +msgid "shift-left" +msgstr "" + +#: f.tools.cc:899 +msgid "venetian" +msgstr "" + +#: f.tools.cc:900 +msgid "grate" +msgstr "" + +#: f.tools.cc:903 +msgid "radar" +msgstr "" + +#: f.tools.cc:904 +msgid "jaws" +msgstr "" + +#: f.tools.cc:911 fotoxx-12.01.cc:208 +msgid "Slide Show" +msgstr "Diaporama" + +#: f.tools.cc:915 +msgid "seconds" +msgstr "segundos" + +#: f.tools.cc:919 +msgid "music file" +msgstr "" + +#: f.tools.cc:923 +msgid "transitions" +msgstr "" + +#: f.tools.cc:1040 +msgid "Select music file or playlist" +msgstr "" + +#: f.tools.cc:1727 +msgid "Sync Files is already running" +msgstr "" + +#: f.tools.cc:1778 +msgid "" +"Run Tools > Synchronize Files so that gallery windows \n" +"will be fast and Search Images will work correctly. \n" +"You can view (not edit) images while synchronize runs." +msgstr "" + +#: f.tools.cc:1812 +msgid "no top image directory is defined" +msgstr "" + +#: f.tools.cc:1818 +msgid "top image directory is invalid" +msgstr "" + +#: f.tools.cc:1823 +msgid "no search index file is present" +msgstr "" + +#: f.tools.cc:1837 +msgid "new/modified files are present" +msgstr "" + +#: f.tools.cc:1844 +msgid "no new files found" +msgstr "" + +#: f.tools.cc:1859 fotoxx-12.01.cc:209 +msgid "Synchronize Files" +msgstr "" + +#: f.tools.cc:1861 +msgid "Top Image Directory:" +msgstr "" + +#: f.tools.cc:1883 +msgid "" +"file sync is necessary.\n" +"cancel anyway?" +msgstr "" + +#: f.tools.cc:1896 +msgid "top directory is invalid" +msgstr "" + +#: f.tools.cc:2292 +msgid "Select top image directory" +msgstr "Seleccionar o directório raíz de imaxes" + +#: f.tools.cc:2429 fotoxx-12.01.cc:210 +msgid "Show RGB" +msgstr "Amosar RGB" + +#: f.tools.cc:2719 fotoxx-12.01.cc:211 +msgid "Grid Lines" +msgstr "" + +#: f.tools.cc:2728 +msgid "x-spacing" +msgstr "" + +#: f.tools.cc:2729 +msgid "x-count" +msgstr "" + +#: f.tools.cc:2730 +msgid "x-enable" +msgstr "" + +#: f.tools.cc:2736 +msgid "y-spacing" +msgstr "" + +#: f.tools.cc:2737 +msgid "y-count" +msgstr "" + +#: f.tools.cc:2738 +msgid "y-enable" +msgstr "" + +#: f.tools.cc:2745 +msgid "x-offset" +msgstr "" + +#: f.tools.cc:2749 +msgid "y-offset" +msgstr "" + +#: f.tools.cc:2940 fotoxx-12.01.cc:213 +msgid "E-mail Images" +msgstr "" + +#: f.tools.cc:2947 +msgid "max. width" +msgstr "" + +#: f.tools.cc:2948 +msgid "max. height" +msgstr "" + +#: f.tools.cc:3093 +msgid "too many files" +msgstr "" + +#: f.tools.cc:3134 +msgid "" +"Brightness should show a gradual ramp \n" +"extending all the way to the edges." +msgstr "" + +#: f.tools.cc:3174 +msgid "Monitor Check" +msgstr "" + +#: f.tools.cc:3232 fotoxx-12.01.cc:215 +msgid "Monitor Gamma" +msgstr "" + +#: f.tools.cc:3294 fotoxx-12.01.cc:216 +msgid "Brightness Distribution" +msgstr "Distribuir o brillo" + +#: f.tools.cc:3432 +msgid "Available Translations" +msgstr "Traducións dispoñibles" + +#: f.tools.cc:3436 +msgid "Set Language" +msgstr "Seleccionar o idioma" + +#: f.tools.cc:3502 +msgid "Make Launcher" +msgstr "" + +#: f.tools.cc:3540 +msgid "Settings" +msgstr "" + +#: f.tools.cc:3545 +msgid "Startup Display" +msgstr "" + +#: f.tools.cc:3547 +msgid "Recent Files Gallery" +msgstr "" + +#: f.tools.cc:3548 +msgid "Previous Image Viewed" +msgstr "" + +#: f.tools.cc:3549 +msgid "Blank Window" +msgstr "" + +#: f.tools.cc:3551 +msgid "Directory Gallery" +msgstr "" + +#: f.tools.cc:3556 +msgid "Image File" +msgstr "" + +#: f.tools.cc:3562 +msgid "Toolbar Style" +msgstr "" + +#: f.tools.cc:3563 f.transform.cc:1300 +msgid "Text" +msgstr "" + +#: f.tools.cc:3564 +msgid "Icons" +msgstr "" + +#: f.tools.cc:3565 +msgid "Both" +msgstr "" + +#: f.tools.cc:3568 +msgid "Warn Overwrite" +msgstr "" + +#: f.tools.cc:3639 +msgid "startup directory is invalid" +msgstr "" + +#: f.tools.cc:3650 +msgid "startup file is invalid" +msgstr "" + +#: f.tools.cc:3707 +msgid "Select startup directory" +msgstr "" + +#: f.tools.cc:3715 +msgid "Select startup image file" +msgstr "" + +#: f.transform.cc:50 +msgid "Use buttons or drag right edge with mouse" +msgstr "Utilice os botóns ou arrastre o bordo dereito co rato" + +#: f.transform.cc:60 fotoxx-12.01.cc:252 +msgid "Rotate Image" +msgstr "Xirar a imaxe" + +#: f.transform.cc:64 +msgid "degrees" +msgstr "Graos" + +#: f.transform.cc:80 f.transform.cc:124 +msgid "Trim" +msgstr "Recortar" + +#: f.transform.cc:81 f.transform.cc:2289 f.transform.cc:3120 +#: f.transform.cc:3383 f.transform.cc:3644 +msgid "Grid" +msgstr "" + +#: f.transform.cc:123 +msgid "Undo Trim" +msgstr "Desfacer recortar" + +#: f.transform.cc:139 +#, c-format +msgid "degrees: %.1f" +msgstr "Graos: %.1f" + +#: f.transform.cc:286 +msgid "gold" +msgstr "" + +#: f.transform.cc:334 +msgid "Drag middle to move, drag corners to resize." +msgstr "" + +#: f.transform.cc:348 fotoxx-12.01.cc:253 +msgid "Trim Image" +msgstr "Recortar a imaxe" + +#: f.transform.cc:348 +msgid "customize" +msgstr "" + +#: f.transform.cc:359 +msgid "ratio" +msgstr "" + +#: f.transform.cc:363 +msgid "Lock Ratio" +msgstr "Bloquear a relación" + +#: f.transform.cc:368 +msgid "invert" +msgstr "" + +#: f.transform.cc:890 +msgid "Trim Buttons" +msgstr "" + +#: f.transform.cc:1064 +msgid "Lock aspect ratio" +msgstr "Bloquear a relación de aspecto" + +#: f.transform.cc:1072 fotoxx-12.01.cc:255 +msgid "Resize Image" +msgstr "Redimensionar a imaxe" + +#: f.transform.cc:1095 fotoxx-12.01.cc:326 +msgid "Prev" +msgstr "Anterior" + +#: f.transform.cc:1245 +msgid "" +"Enter text, click/drag on image.\n" +"Right click to remove" +msgstr "" + +#: f.transform.cc:1294 fotoxx-12.01.cc:256 +msgid "Annotate Image" +msgstr "" + +#: f.transform.cc:1307 +msgid "Size" +msgstr "Tamaño" + +#: f.transform.cc:1310 +msgid "Angle" +msgstr "" + +#: f.transform.cc:1321 fotoxx.h:741 +msgid "Color" +msgstr "" + +#: f.transform.cc:1322 +msgid "Transparency" +msgstr "" + +#: f.transform.cc:1325 +msgid "text" +msgstr "" + +#: f.transform.cc:1330 +msgid "backing" +msgstr "" + +#: f.transform.cc:1333 +msgid "" +"Outline\n" +" Width" +msgstr "" + +#: f.transform.cc:1335 +msgid "outline" +msgstr "" + +#: f.transform.cc:1342 +msgid "Annotation File:" +msgstr "" + +#: f.transform.cc:1416 +msgid "select font" +msgstr "" + +#: f.transform.cc:2045 fotoxx-12.01.cc:257 +msgid "Flip Image" +msgstr "" + +#: f.transform.cc:2049 f.transform.cc:2281 +msgid "horizontal" +msgstr "Horizontal" + +#: f.transform.cc:2050 f.transform.cc:2280 +msgid "vertical" +msgstr "Vertical" + +#: f.transform.cc:2155 fotoxx-12.01.cc:258 +msgid "Make Negative" +msgstr "" + +#: f.transform.cc:2158 +msgid "black/white positive" +msgstr "" + +#: f.transform.cc:2159 +msgid "black/white negative" +msgstr "" + +#: f.transform.cc:2160 +msgid "color positive" +msgstr "" + +#: f.transform.cc:2161 +msgid "color negative" +msgstr "" + +#: f.transform.cc:2272 fotoxx-12.01.cc:259 +msgid "Unbend Image" +msgstr "Endereitar a imaxe" + +#: f.transform.cc:2282 +msgid "linear" +msgstr "" + +#: f.transform.cc:2285 +msgid "curved" +msgstr "" + +#: f.transform.cc:2544 +msgid "" +" Click the four corners of a tetragon area. Press [apply]. \n" +" The image is warped to make the tetragon into a rectangle." +msgstr "" + +#: f.transform.cc:2556 fotoxx-12.01.cc:260 +msgid "Keystone Correction" +msgstr "" + +#: f.transform.cc:2724 +msgid "must have 4 corners" +msgstr "" + +#: f.transform.cc:2847 +msgid "" +" Select an area to warp using select area function. \n" +" Press [start warp] and pull area with mouse. \n" +" Make multiple mouse pulls until satisfied. \n" +" When finished, select another area or press [done]." +msgstr "" +"Seleccione unha área para deformar utilizando o boton [Seleccionar]. \n" +"Prema [Comezar deformación] e empuxe da área co rato. \n" +"Facer varios empuxóns co rato até que quede satisfeito. \n" +"Cando teña rematado, seleccione outra área ou prema [Feito]." + +#: f.transform.cc:2859 fotoxx-12.01.cc:261 +msgid "Warp Image (area)" +msgstr "" + +#: f.transform.cc:2864 +msgid "start warp" +msgstr "Comezar deformación" + +#: f.transform.cc:2931 +msgid "no active Select Area" +msgstr "" + +#: f.transform.cc:3099 f.transform.cc:3362 +msgid "" +" Pull an image position using the mouse. \n" +" Make multiple mouse pulls until satisfied. \n" +" When finished, press [done]." +msgstr "" + +#: f.transform.cc:3112 fotoxx-12.01.cc:262 +msgid "Warp Image (curved)" +msgstr "" + +#: f.transform.cc:3375 fotoxx-12.01.cc:263 +msgid "Warp Image (linear)" +msgstr "" + +#: f.transform.cc:3628 +msgid "" +" Pull on an image corner using the mouse. \n" +" Make multiple mouse pulls until satisfied. \n" +" When finished, press [done]." +msgstr "" +" Tirar dun bordo da imaxe empregando o rato. \n" +" Facer varios empuxóns co rato até que quede satisfeito. \n" +" Cando teña rematado, seleccione outra área ou prema [Feito]." + +#: f.transform.cc:3639 fotoxx-12.01.cc:264 +msgid "Warp Image (affine)" +msgstr "" + +#: fotoxx-12.01.cc:185 +msgid "File" +msgstr "Ficheiro" + +#: fotoxx-12.01.cc:186 fotoxx-12.01.cc:324 +msgid "Image Gallery" +msgstr "Galería de imaxes" + +#: fotoxx-12.01.cc:187 +msgid "Clone 50/50" +msgstr "" + +#: fotoxx-12.01.cc:188 +msgid "Clone Overlay" +msgstr "" + +#: fotoxx-12.01.cc:190 +msgid "Open in New Window" +msgstr "" + +#: fotoxx-12.01.cc:191 fotoxx-12.01.cc:326 +msgid "Open Previous File" +msgstr "Abrir o ficheiro anterior" + +#: fotoxx-12.01.cc:192 +msgid "Open Recent File" +msgstr "Abrir ficheiro recente" + +#: fotoxx-12.01.cc:193 fotoxx-12.01.cc:334 +msgid "Save to Same File" +msgstr "Gardar no mesmo ficheiro" + +#: fotoxx-12.01.cc:194 fotoxx-12.01.cc:335 +msgid "Save to New Version" +msgstr "" + +#: fotoxx-12.01.cc:195 fotoxx-12.01.cc:336 +msgid "Save to New File" +msgstr "Gardar nun ficheiro novo" + +#: fotoxx-12.01.cc:197 +msgid "Trash Image File" +msgstr "Mover imaxe ao lixo" + +#: fotoxx-12.01.cc:199 +msgid "Batch Rename Files" +msgstr "" + +#: fotoxx-12.01.cc:200 +msgid "Print Image File" +msgstr "Imprimir ficheiro de imaxe" + +#: fotoxx-12.01.cc:201 fotoxx-12.01.cc:340 +msgid "Quit fotoxx" +msgstr "Saír de Fotoxx" + +#: fotoxx-12.01.cc:203 +msgid "Tools" +msgstr "Ferramentas" + +#: fotoxx-12.01.cc:206 +msgid "Batch Convert" +msgstr "" + +#: fotoxx-12.01.cc:207 +msgid "Convert RAW files" +msgstr "" + +#: fotoxx-12.01.cc:212 +msgid "Burn Images to CD/DVD" +msgstr "Gravar imaxes nun CD/DVD" + +#: fotoxx-12.01.cc:214 +msgid "Check Monitor" +msgstr "Comprobar monitor" + +#: fotoxx-12.01.cc:217 +msgid "Change Language" +msgstr "Cambiar o idioma" + +#: fotoxx-12.01.cc:219 +msgid "Menu and Launcher" +msgstr "" + +#: fotoxx-12.01.cc:220 +msgid "User Settings" +msgstr "" + +#: fotoxx-12.01.cc:221 +msgid "Memory Usage" +msgstr "" + +#: fotoxx-12.01.cc:224 +msgid "Edit Caption/Comments" +msgstr "" + +#: fotoxx-12.01.cc:229 +msgid "View Info (short)" +msgstr "" + +#: fotoxx-12.01.cc:230 +msgid "View Info (long)" +msgstr "" + +#: fotoxx-12.01.cc:233 +msgid "Search Images" +msgstr "" + +#: fotoxx-12.01.cc:234 +msgid "Search Metadata" +msgstr "" + +#: fotoxx-12.01.cc:236 fotoxx-12.01.cc:237 fotoxx.h:786 +msgid "Select" +msgstr "" + +#: fotoxx-12.01.cc:238 fotoxx.h:788 +msgid "Show" +msgstr "Amosar" + +#: fotoxx-12.01.cc:239 fotoxx.h:761 +msgid "Hide" +msgstr "Agochar" + +#: fotoxx-12.01.cc:240 fotoxx.h:752 +msgid "Enable" +msgstr "" + +#: fotoxx-12.01.cc:241 fotoxx.h:748 +msgid "Disable" +msgstr "" + +#: fotoxx-12.01.cc:242 fotoxx.h:763 +msgid "Invert" +msgstr "Inverter" + +#: fotoxx-12.01.cc:243 fotoxx.h:796 +msgid "Unselect" +msgstr "" + +#: fotoxx-12.01.cc:244 fotoxx.h:743 +msgid "Copy" +msgstr "" + +#: fotoxx-12.01.cc:245 fotoxx.h:771 +msgid "Paste" +msgstr "" + +#: fotoxx-12.01.cc:247 fotoxx-12.01.cc:334 fotoxx.h:783 +msgid "Save" +msgstr "Gardar" + +#: fotoxx-12.01.cc:249 +msgid "Select and Edit" +msgstr "" + +#: fotoxx-12.01.cc:251 +msgid "Transform" +msgstr "" + +#: fotoxx-12.01.cc:254 +msgid "Auto-Trim Image" +msgstr "" + +#: fotoxx-12.01.cc:266 +msgid "Retouch" +msgstr "Retocar" + +#: fotoxx-12.01.cc:267 +msgid "Brightness/Color" +msgstr "Axustar brillo e cor" + +#: fotoxx-12.01.cc:268 +msgid "Gamma Curves" +msgstr "" + +#: fotoxx-12.01.cc:269 +msgid "Expand Brightness" +msgstr "" + +#: fotoxx-12.01.cc:270 +msgid "Flatten Brightness" +msgstr "Distribuir o brillo uniformemente" + +#: fotoxx-12.01.cc:271 +msgid "Brightness Ramp" +msgstr "" + +#: fotoxx-12.01.cc:273 +msgid "White Balance" +msgstr "Balance de branco" + +#: fotoxx-12.01.cc:274 +msgid "Match Colors" +msgstr "" + +#: fotoxx-12.01.cc:277 +msgid "Red Eyes" +msgstr "Ollos vermellos" + +#: fotoxx-12.01.cc:278 +msgid "Blur Image" +msgstr "Imaxe borrosa" + +#: fotoxx-12.01.cc:280 +msgid "Reduce Noise" +msgstr "Redución de ruido" + +#: fotoxx-12.01.cc:286 +msgid "Art" +msgstr "Arte" + +#: fotoxx-12.01.cc:287 +msgid "Color Depth" +msgstr "Profundidade da cor" + +#: fotoxx-12.01.cc:288 +msgid "Drawing" +msgstr "" + +#: fotoxx-12.01.cc:289 +msgid "Outlines" +msgstr "" + +#: fotoxx-12.01.cc:290 +msgid "Embossing" +msgstr "" + +#: fotoxx-12.01.cc:291 +msgid "Tiles" +msgstr "" + +#: fotoxx-12.01.cc:292 +msgid "Dots" +msgstr "" + +#: fotoxx-12.01.cc:293 +msgid "Painting" +msgstr "" + +#: fotoxx-12.01.cc:295 +msgid "Combine" +msgstr "Combinar" + +#: fotoxx-12.01.cc:296 +msgid "High Dynamic Range" +msgstr "" + +#: fotoxx-12.01.cc:297 +msgid "High Depth of Field" +msgstr "" + +#: fotoxx-12.01.cc:298 +msgid "Stack / Paint" +msgstr "" + +#: fotoxx-12.01.cc:299 +msgid "Stack / Noise" +msgstr "" + +#: fotoxx-12.01.cc:300 +msgid "Panorama" +msgstr "Panoramica" + +#: fotoxx-12.01.cc:301 +msgid "Vertical Panorama" +msgstr "" + +#: fotoxx-12.01.cc:304 +msgid "Edit Plugins" +msgstr "" + +#: fotoxx-12.01.cc:313 fotoxx-12.01.cc:341 fotoxx-12.01.cc:3026 +msgid "Help" +msgstr "Axuda" + +#: fotoxx-12.01.cc:314 fotoxx-12.01.cc:3016 +msgid "About" +msgstr "Acerca de..." + +#: fotoxx-12.01.cc:315 fotoxx-12.01.cc:3020 +msgid "User Guide" +msgstr "Guía do usuario" + +#: fotoxx-12.01.cc:316 fotoxx-12.01.cc:3023 +msgid "User Guide Changes" +msgstr "" + +#: fotoxx-12.01.cc:317 fotoxx-12.01.cc:3032 +msgid "Edit Functions Summary" +msgstr "" + +#: fotoxx-12.01.cc:318 fotoxx-12.01.cc:3035 +msgid "Change Log" +msgstr "Editar o rexistro" + +#: fotoxx-12.01.cc:319 fotoxx-12.01.cc:3038 +msgid "Translations" +msgstr "" + +#: fotoxx-12.01.cc:320 fotoxx-12.01.cc:3041 +msgid "Home Page" +msgstr "Páxina de inicio" + +#: fotoxx-12.01.cc:324 +msgid "Gallery" +msgstr "Galería" + +#: fotoxx-12.01.cc:327 fotoxx.h:767 +msgid "Next" +msgstr "Seguinte" + +#: fotoxx-12.01.cc:327 +msgid "Open Next File" +msgstr "Abrir o ficheiro seguinte" + +#: fotoxx-12.01.cc:328 +msgid "Zoom-in (bigger)" +msgstr "Zoom ampliar" + +#: fotoxx-12.01.cc:329 +msgid "Zoom-out (smaller)" +msgstr "Zoom reducir" + +#: fotoxx-12.01.cc:330 fotoxx.h:794 +msgid "Undo" +msgstr "Desfacer" + +#: fotoxx-12.01.cc:330 +msgid "Undo One Edit" +msgstr "Desfacer un paso" + +#: fotoxx-12.01.cc:331 fotoxx.h:779 +msgid "Redo" +msgstr "Refacer" + +#: fotoxx-12.01.cc:331 +msgid "Redo One Edit" +msgstr "Refacer un paso" + +#: fotoxx-12.01.cc:335 +msgid "Save+V" +msgstr "" + +#: fotoxx-12.01.cc:336 +msgid "Save+F" +msgstr "" + +#: fotoxx-12.01.cc:337 +msgid "Move Image to Trash" +msgstr "Enviar a imaxe ao lixo" + +#: fotoxx-12.01.cc:337 +msgid "Trash" +msgstr "Lixo" + +#: fotoxx-12.01.cc:340 +msgid "Quit" +msgstr "Sair" + +#: fotoxx-12.01.cc:341 +msgid "Fotoxx Essentials" +msgstr "" + +#: fotoxx-12.01.cc:448 +msgid "first time startup" +msgstr "" + +#: fotoxx-12.01.cc:1944 +msgid "Exceed 50 anchor points" +msgstr "Excédense os 50 puntos de ancoraxe" + +#: fotoxx-12.01.cc:2129 +msgid "load curve from a file" +msgstr "" + +#: fotoxx-12.01.cc:2182 +msgid "curve file is invalid" +msgstr "" + +#: fotoxx-12.01.cc:2187 +msgid "curve file has different no. of curves" +msgstr "" + +#: fotoxx-12.01.cc:2202 +msgid "save curve to a file" +msgstr "" + +#: fotoxx-12.01.cc:2337 +msgid "cannot parallel edit" +msgstr "" + +#: fotoxx-12.01.cc:2347 +msgid "" +"exiftool is not installed \n" +"edited images will lose EXIF data" +msgstr "" +"O paquete «exiftool» non está instalado \n" +"ao editar as imaxes perderánse os datos EXIF" + +#: fotoxx-12.01.cc:2353 +msgid "Too many edits, please save image" +msgstr "" + +#: fotoxx-12.01.cc:2358 +msgid "" +"Select area cannot be kept.\n" +"Continue?" +msgstr "" +"Non se pode conservar a selección de área.\n" +"Continuar?" + +#: fotoxx-12.01.cc:2366 +msgid "" +"Select area not active.\n" +"Continue?" +msgstr "" + +#: fotoxx-12.01.cc:2837 +msgid "Discard edits?" +msgstr "" + +#: fotoxx-12.01.cc:2838 +msgid "" +"This action will discard current edits.\n" +"Continue to discard edits.\n" +"Go Back to keep edits." +msgstr "" + +#: fotoxx-12.01.cc:2841 +msgid "Continue" +msgstr "" + +#: fotoxx-12.01.cc:2842 +msgid "Go Back" +msgstr "" + +#: fotoxx-12.01.cc:3659 +msgid "cannot open thumbnail file" +msgstr "" + +#: fotoxx-12.01.cc:3870 fotoxx-12.01.cc:3992 +msgid "TIFF open failure" +msgstr "" + +#: fotoxx-12.01.cc:3886 +#, c-format +msgid "TIFF bits/color=%d not supported" +msgstr "" + +#: fotoxx-12.01.cc:3901 fotoxx-12.01.cc:3939 +msgid "TIFF read failure" +msgstr "" + +#: fotoxx-12.01.cc:4051 +msgid "TIFF write failure" +msgstr "" + +#: fotoxx-12.01.cc:4071 +msgid "file type not supported" +msgstr "" + +#: fotoxx-12.01.cc:4178 +msgid "pixbuf write failure" +msgstr "" + +#: fotoxx.h:728 +msgid "absolute" +msgstr "" + +#: fotoxx.h:730 +msgid "Add All" +msgstr "Engadir todo" + +#: fotoxx.h:732 +msgid "Amount" +msgstr "" + +#: fotoxx.h:733 +msgid "Apply" +msgstr "Aplicar" + +#: fotoxx.h:734 +msgid "Black" +msgstr "" + +#: fotoxx.h:735 +msgid "Blend Width" +msgstr "Misturar por anchura" + +#: fotoxx.h:737 +msgid "Brightness" +msgstr "Brillo" + +#: fotoxx.h:738 +msgid "Browse" +msgstr "" + +#: fotoxx.h:739 +msgid "Cancel" +msgstr "Cancelar" + +#: fotoxx.h:740 +msgid "Clear" +msgstr "Limpar" + +#: fotoxx.h:742 +msgid "Commit" +msgstr "" + +#: fotoxx.h:744 +msgid "Curve File:" +msgstr "" + +#: fotoxx.h:745 +msgid "Cut" +msgstr "" + +#: fotoxx.h:746 +msgid "Darker Areas" +msgstr "Escurecer áreas" + +#: fotoxx.h:747 +msgid "Delete" +msgstr "Borrar" + +#: fotoxx.h:749 +#, c-format +msgid "" +"Discard special gallery list? \n" +" %s" +msgstr "" + +#: fotoxx.h:750 +msgid "Done" +msgstr "Feito" + +#: fotoxx.h:751 +msgid "Edit" +msgstr "Editar" + +#: fotoxx.h:753 +msgid "Erase" +msgstr "" + +#: fotoxx.h:754 +msgid "package libimage-exiftool-perl is required" +msgstr "" + +#: fotoxx.h:755 +msgid "Fetch" +msgstr "" + +#: fotoxx.h:756 +msgid "Finish" +msgstr "Terminar" + +#: fotoxx.h:757 +msgid "Font" +msgstr "" + +#: fotoxx.h:759 +msgid "Height" +msgstr "Altura" + +#: fotoxx.h:760 +msgid "histogram" +msgstr "" + +#: fotoxx.h:762 +msgid "Insert" +msgstr "Inserir" + +#: fotoxx.h:764 +msgid "Lighter Areas" +msgstr "Iluminar áreas" + +#: fotoxx.h:765 +msgid "limit" +msgstr "" + +#: fotoxx.h:766 +msgid "New" +msgstr "" + +#: fotoxx.h:768 +msgid "OK" +msgstr "Conforme" + +#: fotoxx.h:772 +msgid "Pause" +msgstr "" + +#: fotoxx.h:773 +msgid "Percent" +msgstr "Porcentaxe" + +#: fotoxx.h:774 +msgid "Presets" +msgstr "Predefinidos" + +#: fotoxx.h:775 +msgid "Proceed" +msgstr "Proceder" + +#: fotoxx.h:777 +msgid "range" +msgstr "" + +#: fotoxx.h:780 +msgid "Reduce" +msgstr "Reducir" + +#: fotoxx.h:782 +msgid "Reset" +msgstr "" + +#: fotoxx.h:784 +msgid "Unknown file type, save as tiff/jpeg/png to edit" +msgstr "Tipo de ficheiro descoñecido. gardeo como tiff/jpeg/png para editalo" + +#: fotoxx.h:785 +msgid "Search" +msgstr "Buscar" + +#: fotoxx.h:789 +msgid "Start" +msgstr "Comezar" + +#: fotoxx.h:790 +msgid "Threshold" +msgstr "" + +#: fotoxx.h:791 +#, c-format +msgid "exceed %d files" +msgstr "" + +#: fotoxx.h:792 +msgid "Undo All" +msgstr "Desfacer todo" + +#: fotoxx.h:793 +msgid "Undo Last" +msgstr "Desfacer o último" + +#: fotoxx.h:795 +msgid "Unfinish" +msgstr "" + +#: fotoxx.h:797 +msgid "View" +msgstr "" + +#: fotoxx.h:798 +msgid "White" +msgstr "" + +#: fotoxx.h:799 +msgid "Width" +msgstr "Anchura" + +#: zfuncs.cc:3252 +#, c-format +msgid "help file not found: %s" +msgstr "O ficheiro de axuda non se atopa: %s" + +#: zfuncs.cc:3664 zfuncs.cc:7315 +#, c-format +msgid "cannot open file %s" +msgstr "Non se pode abrir o ficheiro %s" + +#: zfuncs.cc:3697 +msgid "save screen to file" +msgstr "Gardar pantalla nun ficheiro" + +#: zfuncs.cc:6222 +msgid "No" +msgstr "" + +#: zfuncs.cc:6222 +msgid "Yes" +msgstr "" + +#: zfuncs.cc:6447 +msgid "open" +msgstr "Abrir" + +#: zfuncs.cc:6452 +msgid "choose" +msgstr "" + +#: zfuncs.cc:6457 +msgid "save" +msgstr "Gardar" + +#: zfuncs.cc:6463 +msgid "open folder" +msgstr "Abrir cartafol" + +#: zfuncs.cc:6468 +msgid "create folder" +msgstr "Crear cartafol" + +#: zfuncs.cc:6474 +msgid "hidden" +msgstr "Agochar" + +#: zfuncs.cc:6535 +msgid "JPG quality 0-100" +msgstr "Calidade de JPG 0-100" + +#: zfuncs.cc:6728 zfuncs.cc:6741 +msgid "margins" +msgstr "" + +#: zfuncs.cc:6737 +msgid "top" +msgstr "" + +#: zfuncs.cc:6738 +msgid "bottom" +msgstr "" + +#: zfuncs.cc:6739 +msgid "left" +msgstr "" + +#: zfuncs.cc:6740 +msgid "right" +msgstr "" + +#: zfuncs.cc:7202 +msgid "" +"Initial parameters file created. \n" +"Inspect and revise if necessary." +msgstr "" +"Parámetros iniciais creados. \n" +"Revíseseos se o desexa." + +#: zfuncs.cc:7218 +msgid "load parameters from a file" +msgstr "Cargar parámetros desde ficheiro" + +#: zfuncs.cc:7287 +msgid "save parameters to a file" +msgstr "Gardar parámetros nun ficheiro" + +#: zfuncs.cc:7425 zfuncs.cc:7431 zfuncs.cc:7437 zfuncs.cc:7443 +msgid "edit parameters" +msgstr "Editar parámetros" + +#: zfuncs.cc:7426 zfuncs.cc:7432 +msgid "" +"list\n" +"all" +msgstr "" +"Listar\n" +"todo" + +#: zfuncs.cc:7426 zfuncs.cc:7432 zfuncs.cc:7438 zfuncs.cc:7444 +msgid "" +"load\n" +"file" +msgstr "" +"Cargar\n" +"ficheiro" + +#: zfuncs.cc:7426 zfuncs.cc:7432 zfuncs.cc:7438 zfuncs.cc:7444 +msgid "" +"save\n" +"file" +msgstr "" +"Gardar\n" +"ficheiro" + +#: zfuncs.cc:7427 zfuncs.cc:7439 +msgid "" +"add\n" +"new" +msgstr "" +"Engadir\n" +"Novo" + +#: zfuncs.cc:7427 zfuncs.cc:7433 zfuncs.cc:7439 zfuncs.cc:7445 +msgid "apply" +msgstr "Aplicar" + +#: zfuncs.cc:7479 +msgid "apply?" +msgstr "Aplicar?" + +#: zfuncs.cc:7536 +msgid "(new parm name)" +msgstr "(Novo parámetro)" + +#: zfuncs.cc:7536 +msgid "add parameter" +msgstr "Engadir parámetro" + +#~ msgid "Brightness Graph" +#~ msgstr "Gráfica de brillo" + +#~ msgid "radius" +#~ msgstr "Radio" + +#~ msgid "Search results file error %s" +#~ msgstr "Erro nos resultados da busca %s" + +#~ msgid "Select area first" +#~ msgstr "Debe seleccionar primeiro a área" + +#~ msgid "Translate" +#~ msgstr "Traducións" + +#~ msgid "" +#~ "Rename failed \n" +#~ " %s" +#~ msgstr "" +#~ "Fallou o renomeado \n" +#~ " %s" + +#~ msgid "Discard modifications?" +#~ msgstr "Desbotar as modificacións?" + +#~ msgid "whiteness" +#~ msgstr "Claridade" + +#~ msgid "unknown image format" +#~ msgstr "Formato de imaxe descoñecido" + +#~ msgid "undo image changes" +#~ msgstr "Desfacer os cambios na imaxe" + +#~ msgid "unbend panorama image" +#~ msgstr "Corrixir perspectiva panorámica" + +#~ msgid "trim image" +#~ msgstr "Recortar a imaxe" + +#~ msgid "toolbar::save" +#~ msgstr "Gardar" + +#, fuzzy +#~ msgid "this area cannot be processed" +#~ msgstr "" +#~ "Non se pode conservar a selección de área.\n" +#~ "Continuar?" + +#~ msgid "tags exceed %d characters" +#~ msgstr "As etiquetas do ficheiro exceden de %d caracteres" + +#~ msgid "sharpen image" +#~ msgstr "Enfocar a imaxe" + +#~ msgid "set color intensity" +#~ msgstr "Definir a intensidade da cor" + +#, fuzzy +#~ msgid "set blend radius" +#~ msgstr "Definir o radio do desenfoque" + +#~ msgid "set RGB spread" +#~ msgstr "Establece o rango RGB" + +#~ msgid "rotate image" +#~ msgstr "Xirar a imaxe" + +#~ msgid "resize image" +#~ msgstr "Redimensionar a imaxe" + +#~ msgid "redo image changes" +#~ msgstr "Refacer os cambios na imaxe" + +#~ msgid "red" +#~ msgstr "Vermello" + +#~ msgid "recently added" +#~ msgstr "Engadido recentemente" + +#, fuzzy +#~ msgid "radius limit" +#~ msgstr "Radio" + +#~ msgid "quit" +#~ msgstr "Sair" + +#~ msgid "prior function still running" +#~ msgstr "A función principal esta aínda traballando" + +#~ msgid "photo stars" +#~ msgstr "Estrelas" + +#~ msgid "photo date (yyyymmdd)" +#~ msgstr "Data da foto (aaaammdd)" + +#~ msgid "open new image file" +#~ msgstr "Abrir unha nova imaxe" + +#~ msgid "open image file" +#~ msgstr "Abrir ficheiro" + +#~ msgid "open RAW file" +#~ msgstr "Abrir ficheiro en bruto" + +#~ msgid "kill running function" +#~ msgstr "Pechar a función actual" + +#~ msgid "kill" +#~ msgstr "Pechar" + +#~ msgid "input image 2" +#~ msgstr "Elixir imaxe 2" + +#~ msgid "image not 8 or 16 bits/color: %s" +#~ msgstr "A imaxe %s non ten 8 ou 16 bits/color" + +#~ msgid "image format error: %s" +#~ msgstr "Erro no formato da imaxe: %s" + +#~ msgid "graph" +#~ msgstr "gráfico" + +#~ msgid "" +#~ "file cannot be read: \n" +#~ " %s" +#~ msgstr "" +#~ "Non se pode ler o ficheiro: \n" +#~ " %s" + +#~ msgid "exiv2 package is required" +#~ msgstr "Precisase o paquete exiv2" + +#~ msgid "exiftool is required to generate tags index" +#~ msgstr "Precisase «exiftool» para xerar o índice de etiquetas" + +#~ msgid "exiftool is required to create tags" +#~ msgstr "Precisase «exiftool» para cear etiquetas" + +#, fuzzy +#~ msgid "edge calculation missing" +#~ msgstr "Precisa calcular o bordo" + +#~ msgid "defog" +#~ msgstr "desembazar" + +#~ msgid "date range (yyyymmdd)" +#~ msgstr "Formato da data (aaaammdd)" + +#~ msgid "computing" +#~ msgstr "computing" + +#~ msgid "color balance" +#~ msgstr "Balance da cor" + +#~ msgid "click or drag trim margins" +#~ msgstr "Faga clic na imaxe ou arrastre o bordo" + +#~ msgid "" +#~ "cannot create %s \n" +#~ " %s" +#~ msgstr "" +#~ "Non se pode crear %s \n" +#~ " %s" + +#~ msgid "brightness distribution" +#~ msgstr "Distribuir o brillo" + +#~ msgid "blur radius" +#~ msgstr "Radio de desenfoque" + +#~ msgid "blend" +#~ msgstr "Mestura" + +#~ msgid "bigger image" +#~ msgstr "Imaxe máis grande" + +#~ msgid "assigned tags" +#~ msgstr "Etiquetas asignadas" + +#~ msgid "adjust brightness / whiteness" +#~ msgstr "Axustar brillo / claridade" + +#~ msgid "Zoom-" +#~ msgstr "Zoom-" + +#~ msgid "Zoom+" +#~ msgstr "Zoom+" + +#~ msgid "Warp Global" +#~ msgstr "Deformación da imaxe" + +#~ msgid "Warp" +#~ msgstr "Deformar" + +#~ msgid "Unable to save image: %s" +#~ msgstr "Non se pode gardar a imaxe: %s" + +#~ msgid "Unable to save image" +#~ msgstr "Non se pode gardar a imaxe" + +#, fuzzy +#~ msgid "Unable to replace file" +#~ msgstr "Non se pode gardar a imaxe" + +#~ msgid "Unable to copy EXIF data" +#~ msgstr "Non se poden copiar os datos EXIF" + +#~ msgid "Tune Image" +#~ msgstr "Afinar a imaxe" + +#~ msgid "Total tags exceed %d characters" +#~ msgstr "O número total de etiquetas excedeu en %d caracteres" + +#~ msgid "Too many undo buffers, please save image" +#~ msgstr "Demasiados «desfacer» no bufer, garde a imaxe" + +#~ msgid "Too many tags: %d" +#~ msgstr "Demasiadas etiquetas: %d" + +#~ msgid "Too many points" +#~ msgstr "Demasiados puntos" + +#~ msgid "Thumbnail Index" +#~ msgstr "Índice de miniaturas" + +#~ msgid "Special Art Effects" +#~ msgstr "Efectos artísticos especiales" + +#~ msgid "Simulate embossing" +#~ msgstr "Semellar un repuxado" + +#, fuzzy +#~ msgid "Simulate Mosaic" +#~ msgstr "Simular repuxado" + +#, fuzzy +#~ msgid "Simulat Mosaic" +#~ msgstr "Simular repuxado" + +#~ msgid "Show Area" +#~ msgstr "Amosar área" + +#~ msgid "Sharp" +#~ msgstr "Enfoque" + +#~ msgid "" +#~ "Select area is not finished.\n" +#~ "Continue without using it?" +#~ msgstr "" +#~ "Non se completou a selección de área.\n" +#~ "Continuar sen usala?" + +#~ msgid "Select Area -mouse" +#~ msgstr "Seleccionar área -rato" + +#~ msgid "Select Area -color" +#~ msgstr "Seleccionar área -cor" + +#~ msgid "Save Image as File" +#~ msgstr "Gardar a imaxe como ficheiro" + +#~ msgid "Rotate" +#~ msgstr "Xirar" + +#~ msgid "RGB spread" +#~ msgstr "Rango RGB" + +#~ msgid "RGB Spread" +#~ msgstr "Rango RGB" + +#~ msgid "README" +#~ msgstr "LEAME" + +#~ msgid "RAW file template" +#~ msgstr "Plantilla de ficheiro RAW" + +#~ msgid "Print" +#~ msgstr "Imprimir" + +#~ msgid "Paint Pixels" +#~ msgstr "Pintar píxeles" + +#~ msgid "Package exiftool is missing" +#~ msgstr "Non se atopa o paquete «exiftool»" + +#~ msgid "Output Image" +#~ msgstr "Imaxe de saída" + +#, fuzzy +#~ msgid "Outline Image Area for Following Edits" +#~ msgstr "Área da imaxe para ediciós seguintes" + +#~ msgid "No assigned tags index file" +#~ msgstr "Etiquetas sen asignar ao ficheiro de índice" + +#~ msgid "Make HDR Image" +#~ msgstr "Facer imaxe HDR" + +#~ msgid "Make HDF Image" +#~ msgstr "Facer imaxe HDF" + +#~ msgid "" +#~ "Left click/drag: add to selected area. \n" +#~ "Right click: remove prior selection(s). \n" +#~ "Color range: add more or less at once." +#~ msgstr "" +#~ "Facer clic no botón esquerdo e arrastrar: engadir á área seleccionada. \n" +#~ "Facer clic no botón dereito: quitar a(s) selección(s) previa(s). \n" +#~ "Gama de cores: engadir máis o menos de vez." + +#~ msgid "Invert Area" +#~ msgstr "Inverter área" + +#~ msgid "Input Images" +#~ msgstr "Imaxes de entrada" + +#~ msgid "Index Tags and Thumbs" +#~ msgstr "Sincronizar etiquetas e miniaturas" + +#~ msgid "Index (thumbnails)" +#~ msgstr "Índice (miniaturas)" + +#~ msgid "Index" +#~ msgstr "Índice" + +#~ msgid "Image Weights per Brightness Level" +#~ msgstr "Peso da imaxe por nivel de brillo" + +#~ msgid "Hide Area" +#~ msgstr "Agochar área" + +#~ msgid "HDR Image Weights" +#~ msgstr "Peso da imaxe HDR" + +#, fuzzy +#~ msgid "FreeImage" +#~ msgstr "Redimensionar a imaxe" + +#, fuzzy +#~ msgid "Flash" +#~ msgstr "Lixo" + +#~ msgid "FREEIMAGE unknown error" +#~ msgstr "Erro descoñecido en FREEIMAGE" + +#~ msgid "FREEIMAGE error: %s" +#~ msgstr "Erro en FREEIMAGE: %s" + +#~ msgid "Error Log" +#~ msgstr "Rexistro de erros" + +#~ msgid "Edge Calc" +#~ msgstr "Calcular o bordo" + +#~ msgid "" +#~ "Drag middle to move \n" +#~ "Drag corners to resize" +#~ msgstr "" +#~ "Arrastre desde o interior para mover \n" +#~ "Arrastre os cantos para redimensionar" + +#, fuzzy +#~ msgid "" +#~ "Drag and click to enclose an area.\n" +#~ "Use right click to undo prior." +#~ msgstr "" +#~ "Use o rato, arrastre e faga clic para pechar unha área \n" +#~ "e o botón dereito para desfacer." + +#~ msgid "Distortion" +#~ msgstr "Distorsión" + +#~ msgid "" +#~ "Distance calculation needs a long time.\n" +#~ " Do you want to continue?" +#~ msgstr "" +#~ "O cálculo da distancia necesita bastante tempo.\n" +#~ " Desexa continuar?" + +#~ msgid "Dimensions" +#~ msgstr "Dimensións" + +#~ msgid "Delete selected area?" +#~ msgstr "Borrar a área seleccionada?" + +#~ msgid "Delete Area" +#~ msgstr "Borar a área" + +#~ msgid "" +#~ "Convert raw file to 48-bit tiff format? \n" +#~ " (this may take a while) " +#~ msgstr "" +#~ "Converter ficheiros RAW a formato tiff de 48 bits?\n" +#~ " (isto pode tardar un pouco)" + +#~ msgid "Convert multiple RAWs" +#~ msgstr "Converter múltiples RAW" + +#~ msgid "Composite Images" +#~ msgstr "Composición de imaxes" + +#~ msgid "Color Intensity" +#~ msgstr "Intensidade da cor" + +#~ msgid "Clear Select Area" +#~ msgstr "Limpar área seleccionada" + +#~ msgid "Build Tags Index" +#~ msgstr "Construir índice de etiquetas" + +#~ msgid "Brightness/Whiteness" +#~ msgstr "Axustar brillo / claridade" + +#~ msgid "Brightness/Contrast/Color" +#~ msgstr "Brillo/Contraste/Cor" + +#, fuzzy +#~ msgid "Blend Area Edges" +#~ msgstr "Radio de desenfoque" + +#~ msgid "Bend" +#~ msgstr "Mestura" + +#~ msgid "Assigned tags file error: %s" +#~ msgstr "Erro ao asignar etiquetas de ficheiro: %s" + +#~ msgid "Adjust Saturation (RGB spread)" +#~ msgstr "Ajuste de saturación (rango RGB)" + +#~ msgid "2nd image not same size as 1st image" +#~ msgstr "A 2ª imaxe non ten o mesmo tamaño que a 1ª" + +#~ msgid "2nd file is not compatible with 1st" +#~ msgstr "O segundo ficheiro non é compatible co primeiro" + +#~ msgid " color balance red " +#~ msgstr " balance da cor vermello" + +#~ msgid " color balance green " +#~ msgstr " balance da cor verde" + +#~ msgid " color balance blue " +#~ msgstr " balance da cor azul" + +#~ msgid "" +#~ " Set color depth to 1-8 bits per color. \n" +#~ " Press [apply] to update the image." +#~ msgstr "" +#~ " Establece a profundidade de cor a 1-8 bits por cor, \n" +#~ " despois prema [Aplicar] para actualizar a imaxe." + +#~ msgid " green" +#~ msgstr " Verde" + +#~ msgid " blue" +#~ msgstr " Azul" + +#~ msgid " adjust red" +#~ msgstr " Axuste vermello" + +#~ msgid "" +#~ " left: no color (grey) \n" +#~ " middle: normal (unmodified) \n" +#~ " right: maximum color" +#~ msgstr "" +#~ "esquerda: sen rango RGB (gris) \n" +#~ " centro: normal (sen modificar) \n" +#~ " dereita: rango máximo RGB" + +#~ msgid "" +#~ " left: no RGB spread (gray) \n" +#~ " middle: normal (unmodified) \n" +#~ " right: maximum RGB spread" +#~ msgstr "" +#~ "esquerda: sen cor (gris) \n" +#~ " centro: normal (sen modificar) \n" +#~ " dereita: máximo cor" + +#~ msgid "" +#~ "\n" +#~ " brightness \n" +#~ " level" +#~ msgstr "" +#~ "\n" +#~ " Brillo \n" +#~ " Nivel" + +#~ msgid "Select image to combine" +#~ msgstr "Seleccionar unha imaxe para combinar" + +#~ msgid "Retouch Image" +#~ msgstr "Retoque de imaxe" + +#~ msgid "Package ufraw required for this function" +#~ msgstr "Precisase o aplicativo «ufraw» para esta función" + +#~ msgid "Merge the images together" +#~ msgstr "Misturar as imaxes en conxunto" + +#~ msgid "Match Images" +#~ msgstr "Ensamblar as imaxes" + +#~ msgid "" +#~ "Drag right image into rough alignment with left \n" +#~ " to rotate, drag right edge up or down" +#~ msgstr "" +#~ "Arrastre a imaxe dereita para aliñala coa da esquerda \n" +#~ " para xirala, arrastre o bordo dereito cara arriba ou abaixo" + +#~ msgid "Auto-search lens mm and bow" +#~ msgstr "Buscar automaticamente o lente (mm) e a curva" + +#~ msgid "Auto" +#~ msgstr "Auto" + +#~ msgid "" +#~ "\n" +#~ " Match Brightness and Color" +#~ msgstr "" +#~ "\n" +#~ " Ensamblar a luminosidade e a cor" + +#~ msgid "color range" +#~ msgstr "Rango da cor" + +#~ msgid "add tags" +#~ msgstr "Etiquetas asignadas" + +#~ msgid "Fix Image Perspective" +#~ msgstr "Fixar a imaxe en perspectiva" + +#~ msgid "Burn" +#~ msgstr "Gravar" + +#~ msgid "color intensity" +#~ msgstr "Intensidade da cor" + +#~ msgid "Warp Image in Selected Area" +#~ msgstr "Deformar imaxe na área seleccionada" + +#~ msgid "Warp Area" +#~ msgstr "Deformación de área" + +#~ msgid "" +#~ " Pull on an image edge using the mouse. \n" +#~ " Make multiple mouse pulls until satisfied. \n" +#~ " When finished, press [done]." +#~ msgstr "" +#~ " Tirar dun bordo da imaxe empregando o rato. \n" +#~ " Facer varios empuxóns co rato até que quede satisfeito. \n" +#~ " Cando teña rematado, seleccione outra área ou prema [Feito]." + +#~ msgid "match any tag" +#~ msgstr "Elexir calquer etiqueta" + +#~ msgid "match all tags" +#~ msgstr "Elexir todas as etiquetas" + +#~ msgid "Tags" +#~ msgstr "Etiquetas" + +#~ msgid "Suspend" +#~ msgstr "Suspender" + +#~ msgid "Set Tile and Gap Size" +#~ msgstr "Axustar mosaico e tamaño da separación" + +#~ msgid "Search Tags" +#~ msgstr "Buscar etiquetas" + +#~ msgid "Resume" +#~ msgstr "Retomar" + +#~ msgid "Basic EXIF data" +#~ msgstr "Datos EXIF básicos" + +#~ msgid "All EXIF data" +#~ msgstr "Todos os datos EXIF" + +#~ msgid "/path*/file*" +#~ msgstr "/ruta*/ficheiro*" + +#~ msgid "HDR" +#~ msgstr "HDR" + +#~ msgid "HDF" +#~ msgstr "HDF" + +#~ msgid "Area" +#~ msgstr "Área" + +#~ msgid "target group area" +#~ msgstr "Área do grupo de destino" + +#~ msgid "vertical unbend" +#~ msgstr "Enderezamento vertical" + +#~ msgid "horizontal unbend" +#~ msgstr "Enderezamento horizontal" + +#~ msgid "Create Launcher" +#~ msgstr "Crear un lanzador" + +#~ msgid "Save As" +#~ msgstr "Gardar como" + +#~ msgid "Clone fotoxx" +#~ msgstr "Clonar Fotoxx" + +#~ msgid "Time Interval" +#~ msgstr "Intervalo de tempo" + +#~ msgid "open a file" +#~ msgstr "Abrir un ficheiro" + +#~ msgid "xdg-utils package not installed" +#~ msgstr "O paquete «xdg-utils» non está instalado" + +#~ msgid "select new folder" +#~ msgstr "Seleccionar novo cartafol" + +#~ msgid "open a directory" +#~ msgstr "Abrir un novo directório" + +#~ msgid "jump to specific file" +#~ msgstr "Cambia a un ficheiro específico" + +#~ msgid "folder" +#~ msgstr "Cartafol" + +#~ msgid "file" +#~ msgstr "Ficheiro" + +#~ msgid "close thumbnail window" +#~ msgstr "Pechar Índice de miniaturas" + +#~ msgid "select new file" +#~ msgstr "Seleccionar ficheiro novo" + +#~ msgid "lens name" +#~ msgstr "Nome da lente" + +#~ msgid "Lens Parameters" +#~ msgstr "Parámetros da óptica" diff -Nru fotoxx-11.11.1/locales/fotoxx-it.po fotoxx-12.01.2/locales/fotoxx-it.po --- fotoxx-11.11.1/locales/fotoxx-it.po 1970-01-01 00:00:00.000000000 +0000 +++ fotoxx-12.01.2/locales/fotoxx-it.po 2012-01-04 08:47:11.000000000 +0000 @@ -0,0 +1,2708 @@ +# translation of fotoxx.po to italian +# Eugenio Baldi , 2009. +# (revisione) Doriano Blengino , 2011 +# #-#-#-#-# fotoxx.po (messages) #-#-#-#-# +# Italian translations for home package. +# Copyright (C) 2008 THE home'S COPYRIGHT HOLDER +# This file is distributed under the same license as the home package. +msgid "" +msgstr "" +"Project-Id-Version: fotoxx\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2012-01-04 02:54+0100\n" +"PO-Revision-Date: 2010-06-03 16:14+0100\n" +"Language-Team: italiano \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#: f.art.cc:47 +msgid "Set color depth to 1-16 bits" +msgstr "Impostare la profondità del colore da 1 a 16 bit" + +#: f.art.cc:57 +msgid "Set Color Depth" +msgstr "Imposta la profondità di colore" + +#: f.art.cc:171 +msgid "Simulate Drawing" +msgstr "Simula disegno" + +#: f.art.cc:213 f.retouch.cc:1759 f.retouch.cc:5991 +msgid "contrast" +msgstr "Contrasto" + +#: f.art.cc:215 +msgid "outlines" +msgstr "Contorni" + +#: f.art.cc:220 +msgid "pencil" +msgstr "Matita" + +#: f.art.cc:221 +msgid "chalk" +msgstr "Gessetto" + +#: f.art.cc:381 +msgid "Add Image Outlines" +msgstr "Aggiunta contorni" + +#: f.art.cc:394 +msgid "outline threshold" +msgstr "Soglia del contorno" + +#: f.art.cc:397 +msgid "outline width" +msgstr "Spessore contorno" + +#: f.art.cc:400 +msgid "image brightness" +msgstr "Luminosità immagine" + +#: f.art.cc:611 +msgid "Simulate Embossing" +msgstr "Simula un bassorilievo" + +#: f.art.cc:626 +msgid "depth" +msgstr "Profondità" + +#: f.art.cc:628 f.file.cc:921 f.retouch.cc:6692 +msgid "color" +msgstr "Colore" + +#: f.art.cc:821 +msgid "Simulate Tiles" +msgstr "Simula un mosaico" + +#: f.art.cc:825 +msgid "tile size" +msgstr "Dimensione tessere" + +#: f.art.cc:829 +msgid "tile gap" +msgstr "Distanza fra tessere" + +#: f.art.cc:1003 +msgid "Convert Image to Dots" +msgstr "Converti immagine in punti" + +#: f.art.cc:1007 +msgid "dot size" +msgstr "Dimensione punto" + +#: f.art.cc:1222 +msgid "Simulate Painting" +msgstr "Simula un dipinto" + +#: f.art.cc:1226 +msgid "color depth" +msgstr "Profondità di colore" + +#: f.art.cc:1230 +msgid "patch area goal" +msgstr "Fattore artistico" + +#: f.art.cc:1234 +msgid "req. color match" +msgstr "Precisione colori" + +#: f.art.cc:1238 +msgid "borders" +msgstr "Contorni" + +#: f.comp.cc:1956 f.comp.cc:1961 f.comp.cc:2582 f.comp.cc:2587 f.comp.cc:3266 +#: f.comp.cc:3271 f.comp.cc:3816 f.comp.cc:3821 +msgid "Select 2 to 9 files" +msgstr "Selezionare da 2 a 9 file" + +#: f.comp.cc:1982 f.comp.cc:2608 f.comp.cc:3292 f.comp.cc:3842 +msgid "Images are not all the same size" +msgstr "Le immagini non hanno la stessa dimensione" + +#: f.comp.cc:2321 +msgid "Adjust Image Contributions" +msgstr "Regola contributi immagine" + +#: f.comp.cc:2324 f.retouch.cc:886 +msgid "dark pixels" +msgstr "Pixel scuri" + +#: f.comp.cc:2326 +msgid "light pixels" +msgstr "Pixel luminosi" + +#: f.comp.cc:2328 f.info.cc:159 +msgid "file:" +msgstr "File:" + +#: f.comp.cc:2843 +msgid "Paint and Warp Image" +msgstr "Dipingi e deforma immagine" + +#: f.comp.cc:2846 f.comp.cc:3520 f.comp.cc:4959 f.comp.cc:5705 +msgid "image" +msgstr "immagine" + +#: f.comp.cc:2850 f.retouch.cc:6696 +msgid "paint" +msgstr "Dipingi" + +#: f.comp.cc:2851 +msgid "warp" +msgstr "Deforma" + +#: f.comp.cc:3518 +msgid "Select and Paint Image" +msgstr "Seleziona e dipingi" + +#: f.comp.cc:4031 +msgid "Adjust Pixel Composition" +msgstr "Regola la composizione dei pixel" + +#: f.comp.cc:4283 f.comp.cc:4288 f.comp.cc:5173 f.comp.cc:5178 +msgid "Select 2 to 4 files" +msgstr "Selezionare da 2 a 4 file" + +#: f.comp.cc:4361 +msgid "" +"Drag images into rough alignment.\n" +"To rotate, drag from lower edge." +msgstr "" +"Trascinare le immagini a un allineamento approssimativo.\n" +"Per ruotarle, trascinare il bordo inferiore." + +#: f.comp.cc:4363 +msgid "Search for lens mm and bow" +msgstr "Ricerca per mm e curvatura lenti" + +#: f.comp.cc:4409 f.comp.cc:5298 +msgid "Pre-align Images" +msgstr "Pre-allineamento immagini" + +#: f.comp.cc:4413 f.comp.cc:5302 +msgid "lens mm" +msgstr "mm lente" + +#: f.comp.cc:4417 f.comp.cc:5306 +msgid "lens bow" +msgstr "curvatura lente" + +#: f.comp.cc:4419 f.comp.cc:5308 +msgid "Resize" +msgstr "Ridimensiona" + +#: f.comp.cc:4420 f.comp.cc:5309 +msgid "resize window" +msgstr "Ridimensiona finestra" + +#: f.comp.cc:4457 +msgid "use two images only" +msgstr "Utilizzare solo due immagini" + +#: f.comp.cc:4478 f.comp.cc:4676 f.comp.cc:4875 f.comp.cc:5357 f.comp.cc:5620 +msgid "Too little overlap, cannot align" +msgstr "Troppo poca sovrapposizione, impossibile allineare" + +#: f.comp.cc:4950 f.comp.cc:5696 +msgid "Match Brightness and Color" +msgstr "Allinea luminosità e colore" + +#: f.comp.cc:4974 f.comp.cc:5720 +msgid "auto color" +msgstr "colore automatico" + +#: f.comp.cc:4975 f.comp.cc:5721 +msgid "file color" +msgstr "file colore" + +#: f.comp.cc:5251 +msgid "" +"Drag images into rough alignment.\n" +"To rotate, drag from right edge." +msgstr "" +"Trascinare le immagini a un allineamento approssimativo.\n" +"Per ruotarle, trascinare il bordo destro." + +#: f.file.cc:169 f.file.cc:341 fotoxx-12.01.1.cc:188 fotoxx-12.01.1.cc:324 +msgid "Open Image File" +msgstr "Apri immagine" + +#: f.file.cc:321 fotoxx-12.01.1.cc:2861 +msgid "prior function still active" +msgstr "" +"Una funzione interattiva è ancora in uso\n" +"Terminare tale funzione e riprovare." + +#: f.file.cc:503 +msgid "Overwrite original file?" +msgstr "Sovrascrivere il file originale?" + +#: f.file.cc:504 +msgid "Do not warn again" +msgstr "Non chiedere di nuovo" + +#: f.file.cc:520 +msgid "Warning" +msgstr "Attenzione" + +#: f.file.cc:643 +msgid "Save File" +msgstr "Salva file" + +#: f.file.cc:666 zfuncs.cc:6478 +msgid "quality" +msgstr "Qualità" + +#: f.file.cc:668 +msgid "make current" +msgstr "Rendi corrente" + +#: f.file.cc:725 +msgid "jpeg quality must be 1-100" +msgstr "la qualità jpeg deve essere 1-100" + +#: f.file.cc:747 +#, c-format +msgid "" +"Overwrite file? \n" +" %s" +msgstr "" +"Sovrascrivere il file? \n" +" %s" + +#: f.file.cc:905 fotoxx-12.01.1.cc:195 +msgid "Create Blank Image" +msgstr "Crea immagine vuota" + +#: f.file.cc:907 +msgid "file name" +msgstr "Nome file" + +#: f.file.cc:912 f.transform.cc:353 +msgid "width" +msgstr "larghezza" + +#: f.file.cc:915 f.tools.cc:477 f.transform.cc:356 +msgid "height" +msgstr "altezza" + +#: f.file.cc:1035 +msgid "" +"Linux standard trash is not supported. \n" +"Desktop trash folder will be created." +msgstr "" +"Non è supportato il cestino strandard di Linux. \n" +"Sarà creata una cartella/cestino dedicata." + +#: f.file.cc:1053 +msgid "Move read-only file to trash?" +msgstr "Spostare il file in sola lettura nel cestino ?" + +#: f.file.cc:1079 +#, c-format +msgid "Cannot create trash folder: %s" +msgstr "Impossible creare il cestino: %s" + +#: f.file.cc:1087 f.file.cc:1093 zfuncs.cc:3356 +#, c-format +msgid "error: %s" +msgstr "errore: %s" + +#: f.file.cc:1138 fotoxx-12.01.1.cc:197 +msgid "Rename Image File" +msgstr "Rinomina immagine" + +#: f.file.cc:1143 +msgid "old name" +msgstr "Vecchio nome" + +#: f.file.cc:1144 +msgid "rename to" +msgstr "Rinominare in" + +#: f.file.cc:1145 +msgid "previous" +msgstr "Precedente" + +#: f.file.cc:1231 +msgid "The target file already exists" +msgstr "Il file di destinazione esiste già" + +#: f.file.cc:1239 +#, c-format +msgid "" +"Rename failed: \n" +" %s" +msgstr "" +"Rinominazione fallita: \n" +" %s" + +#: f.file.cc:1287 +msgid "Batch Rename" +msgstr "Rinomina più immagini" + +#: f.file.cc:1290 f.file.cc:1342 f.info.cc:1519 f.info.cc:1773 f.tools.cc:543 +#: f.tools.cc:2990 +#, c-format +msgid "%d files selected" +msgstr "%d file selezionati" + +#: f.file.cc:1292 +msgid "new base name" +msgstr "Nuovo nome" + +#: f.file.cc:1295 +msgid "starting sequence" +msgstr "inizio sequenza" + +#: f.file.cc:1297 +msgid "increment" +msgstr "incremento" + +#: f.file.cc:1318 +msgid "select files to rename" +msgstr "scegliere i file da rinominare" + +#: f.file.cc:1323 +msgid "base name / sequence / increment not reasonable" +msgstr "nome principale / sequenza / incremento non ragionevole" + +#: f.file.cc:1382 +msgid "new file already exists:" +msgstr "Nuovo file già esistente:" + +#: f.file.cc:1390 +msgid "filespec too long:" +msgstr "Nome file troppo lungo:" + +#: f.file.cc:1401 +msgid "Rename failed:" +msgstr "Rinominazione fallita:" + +#: f.file.cc:1662 fotoxx.h:729 +msgid "Add" +msgstr "Aggiungi" + +#: f.file.cc:1662 fotoxx.h:781 +msgid "Remove" +msgstr "Elimina" + +#: f.file.cc:1664 +msgid "menu name" +msgstr "Nome nel menù" + +#: f.file.cc:1735 f.file.cc:1756 +msgid "Restart Fotoxx to update plugin menu" +msgstr "Riavviare fotoxx per aggiornare il menù Plugins" + +#: f.info.cc:70 +msgid "Edit Caption and Comments" +msgstr "Modifica titolo e commenti" + +#: f.info.cc:156 fotoxx-12.01.1.cc:224 +msgid "Edit Tags" +msgstr "Modifica etichette" + +#: f.info.cc:163 +msgid "image date (yyyymmdd)" +msgstr "Data immagine (aaaammgg)" + +#: f.info.cc:165 +msgid "use last" +msgstr "Utilizza ultima" + +#: f.info.cc:168 +msgid "image stars" +msgstr "Voto dell'immagine" + +#: f.info.cc:186 +msgid "current tags" +msgstr "Etichette attuali:" + +#: f.info.cc:191 +msgid "recent tags" +msgstr "Etichette recenti:" + +#: f.info.cc:196 f.info.cc:358 f.info.cc:1368 f.info.cc:2384 +msgid "defined tags" +msgstr "Etichette definite:" + +#: f.info.cc:345 fotoxx-12.01.1.cc:225 +msgid "Manage Tags" +msgstr "Gestione etichette" + +#: f.info.cc:348 +msgid "category" +msgstr "Categoria" + +#: f.info.cc:351 +msgid "tag" +msgstr "Etichetta" + +#: f.info.cc:354 +msgid "create" +msgstr "Crea" + +#: f.info.cc:355 f.navi.cc:1421 +msgid "delete" +msgstr "Elimina" + +#: f.info.cc:1235 f.info.cc:1319 +#, c-format +msgid "search index file error: %s" +msgstr "Errore nel file indice di ricerca: %s" + +#: f.info.cc:1351 fotoxx-12.01.1.cc:226 +msgid "Batch Add Tags" +msgstr "Aggiungi etichette a più immagini" + +#: f.info.cc:1354 +msgid "tags to add" +msgstr "Etichette da aggiungere" + +#: f.info.cc:1359 +msgid "create tag" +msgstr "Crea etichetta" + +#: f.info.cc:1415 f.info.cc:1608 +#, c-format +msgid "" +"%s \n" +" too many tags" +msgstr "" +"%s \n" +" troppe etichette" + +#: f.info.cc:1553 fotoxx-12.01.1.cc:227 +msgid "Batch Delete Tag" +msgstr "Cancellazione in blocco di etichette" + +#: f.info.cc:1556 +msgid "tag to remove" +msgstr "Etichetta da rimuovere" + +#: f.info.cc:1560 +msgid "optional replacement" +msgstr "Sostituzione opzionale" + +#: f.info.cc:1565 f.tools.cc:2943 +msgid "0 files selected" +msgstr "0 file selezionati" + +#: f.info.cc:1568 +msgid "search all files" +msgstr "Cerca in tutti i file" + +#: f.info.cc:1653 +msgid "no files selected" +msgstr "Nessun file selezionato" + +#: f.info.cc:1659 +msgid "no tag specified" +msgstr "Nessuna etichetta specificata" + +#: f.info.cc:1683 f.info.cc:1712 +msgid "specify tag" +msgstr "Specificare etichetta" + +#: f.info.cc:1821 +msgid "View Info" +msgstr "Informazioni immagine" + +#: f.info.cc:1889 fotoxx-12.01.1.cc:230 +msgid "Edit Info" +msgstr "Modifica informazioni" + +#: f.info.cc:1987 fotoxx-12.01.1.cc:231 +msgid "Delete Info" +msgstr "Elimina informazioni" + +#: f.info.cc:1989 fotoxx.h:731 +msgid "All" +msgstr "Tutto" + +#: f.info.cc:1990 +msgid "One Key:" +msgstr "Una chiave:" + +#: f.info.cc:2343 +msgid "Search Tags, Comments, File Names" +msgstr "Cerca in etichette, commenti e nomi file" + +#: f.info.cc:2350 +msgid "date range" +msgstr "Intervallo date: " + +#: f.info.cc:2351 +msgid "stars range" +msgstr "Voto da/a:" + +#: f.info.cc:2352 +msgid "search tags" +msgstr "Cerca etichette" + +#: f.info.cc:2353 +msgid "search text" +msgstr "Cerca testo" + +#: f.info.cc:2354 +msgid "file names" +msgstr "Nomi di file" + +#: f.info.cc:2359 +msgid "(yyyymmdd)" +msgstr "(aaaammgg)" + +#: f.info.cc:2365 +msgid "all/any" +msgstr "Tutte/Qualsiasi" + +#: f.info.cc:2702 +msgid "No matching images found" +msgstr "Nessuna immagine soddisfa la ricerca" + +#: f.info.cc:2706 f.info.cc:3059 +msgid "No search index file present" +msgstr "File per la ricerca indicizzata non esistente." + +#: f.info.cc:2777 +msgid "Additional Items for Report" +msgstr "" + +#: f.navi.cc:188 f.navi.cc:576 f.navi.cc:706 f.navi.cc:707 f.navi.cc:709 +msgid "bigger" +msgstr "Aumenta" + +#: f.navi.cc:188 +msgid "increase thumbnail size" +msgstr "Aumenta la dimensione delle miniature" + +#: f.navi.cc:189 +msgid "reduce thumbnail size" +msgstr "Riduci la dimensione delle miniature" + +#: f.navi.cc:189 f.navi.cc:586 f.navi.cc:708 f.navi.cc:710 +msgid "smaller" +msgstr "Riduci" + +#: f.navi.cc:190 f.navi.cc:600 +msgid "parent" +msgstr "Superiore" + +#: f.navi.cc:190 +msgid "parent directory" +msgstr "Cartella superiore" + +#: f.navi.cc:191 f.navi.cc:625 f.navi.cc:717 +msgid "first page" +msgstr "Prima pagina" + +#: f.navi.cc:191 +msgid "jump to first file" +msgstr "Passa al primo file" + +#: f.navi.cc:192 f.navi.cc:623 f.navi.cc:712 f.navi.cc:719 +msgid "prev page" +msgstr "Pagina prec." + +#: f.navi.cc:192 +msgid "previous page" +msgstr "Pagina precedente" + +#: f.navi.cc:193 f.navi.cc:621 f.navi.cc:714 +msgid "prev row" +msgstr "Riga prec." + +#: f.navi.cc:193 +msgid "previous row" +msgstr "Riga precedente" + +#: f.navi.cc:194 f.navi.cc:622 f.navi.cc:715 +msgid "next row" +msgstr "Riga successiva" + +#: f.navi.cc:195 f.navi.cc:624 f.navi.cc:713 f.navi.cc:720 +msgid "next page" +msgstr "Pagina successiva" + +#: f.navi.cc:195 +msgid "ttip::next page" +msgstr "Pagina successiva" + +#: f.navi.cc:196 +msgid "jump to last file" +msgstr "Passa all'ultimo file" + +#: f.navi.cc:196 f.navi.cc:626 f.navi.cc:718 +msgid "last page" +msgstr "Ultima pagina" + +#: f.navi.cc:197 f.navi.cc:571 +msgid "close" +msgstr "Chiudi" + +#: f.navi.cc:197 +msgid "close image gallery" +msgstr "Chiudi galleria immagini" + +#: f.navi.cc:1413 fotoxx.h:787 +msgid "Select Files" +msgstr "Selezionare i file" + +#: f.navi.cc:1413 zfuncs.cc:6296 zfuncs.cc:6332 zfuncs.cc:6485 zfuncs.cc:6728 +#: zfuncs.cc:7427 zfuncs.cc:7433 zfuncs.cc:7439 zfuncs.cc:7445 +msgid "cancel" +msgstr "Annulla" + +#: f.navi.cc:1413 zfuncs.cc:6728 +msgid "done" +msgstr "Fatto" + +#: f.navi.cc:1422 +msgid "insert" +msgstr "Inserisci" + +#: f.navi.cc:1423 +msgid "add all" +msgstr "Aggiungi tutti" + +#: f.retouch.cc:55 +msgid "Adjust Brightness and Color" +msgstr "Regola luminosità e colore" + +#: f.retouch.cc:110 +msgid "small-steps" +msgstr "Controllo fine" + +#: f.retouch.cc:119 +msgid "color saturation" +msgstr "Saturazione" + +#: f.retouch.cc:126 +msgid " reset 1 " +msgstr "Azzera" + +#: f.retouch.cc:127 +msgid "reset all" +msgstr "Azzera tutte" + +#: f.retouch.cc:599 +msgid "adjust image gamma" +msgstr "Regola gamma" + +#: f.retouch.cc:885 +msgid "Expand Brightness Range" +msgstr "Espandi escursione di luminosità" + +#: f.retouch.cc:887 +msgid "bright pixels" +msgstr "Pixel chiari" + +#: f.retouch.cc:1058 +msgid "Flatten Brightness Distribution" +msgstr "Distribuisci luminosità" + +#: f.retouch.cc:1072 +msgid "Flatten" +msgstr "Quantità" + +#: f.retouch.cc:1334 +msgid "Ramp brightness across image" +msgstr "Rampe di luce" + +#: f.retouch.cc:1730 fotoxx-12.01.1.cc:271 +msgid "Tone Mapping" +msgstr "Mappa tonalità" + +#: f.retouch.cc:1758 +msgid "low" +msgstr "basso" + +#: f.retouch.cc:1760 +msgid "high" +msgstr "alto" + +#: f.retouch.cc:1763 +msgid "Amplify" +msgstr "Amplificazione" + +#: f.retouch.cc:2069 +msgid "Adjust White Balance" +msgstr "Bilanciamento del bianco" + +#: f.retouch.cc:2070 +msgid "Click white or gray image location" +msgstr "Cliccare un punto [che dovrebbe essere] bianco o grigio" + +#: f.retouch.cc:2278 +msgid "Color Match Images" +msgstr "Trasfrisci colore" + +#: f.retouch.cc:2307 +msgid "mouse radius for color sample" +msgstr "Raggio di prelievo del colore" + +#: f.retouch.cc:2309 f.retouch.cc:2314 fotoxx-12.01.1.cc:245 +#: fotoxx-12.01.1.cc:324 fotoxx.h:769 +msgid "Open" +msgstr "Apri" + +#: f.retouch.cc:2310 +msgid "image for source color" +msgstr "l'immagine di riferimento" + +#: f.retouch.cc:2312 +msgid "click on image to get source color" +msgstr "Cliccare nell'immagine per prelevare il colore" + +#: f.retouch.cc:2315 +msgid "image to set matching color" +msgstr "l'immagine a cui impostare il colore" + +#: f.retouch.cc:2317 +msgid "click on image to set matching color" +msgstr "Cliccare nell'immagine per allineare il colore" + +#: f.retouch.cc:2372 +msgid "select source image color first" +msgstr "Selezionare prima l'immagine di riferimento" + +#: f.retouch.cc:2584 +msgid "Add standard bias" +msgstr "" + +#: f.retouch.cc:2591 +msgid "+Brightness -Density" +msgstr "" + +#: f.retouch.cc:2592 +msgid "+Red -Cyan" +msgstr "" + +#: f.retouch.cc:2593 +msgid "+Green -Magenta" +msgstr "" + +#: f.retouch.cc:2594 +msgid "+Blue -Yellow" +msgstr "" + +#: f.retouch.cc:2599 +msgid "Contrast" +msgstr "" + +#: f.retouch.cc:2600 fotoxx.h:778 +msgid "Red" +msgstr "Rosso" + +#: f.retouch.cc:2601 fotoxx.h:758 +msgid "Green" +msgstr "Verde" + +#: f.retouch.cc:2602 fotoxx.h:736 +msgid "Blue" +msgstr "Blu" + +#: f.retouch.cc:2730 +msgid "Load DRGB parameters" +msgstr "" + +#: f.retouch.cc:2732 f.retouch.cc:2804 f.retouch.cc:6102 f.retouch.cc:6198 +msgid "File:" +msgstr "File:" + +#: f.retouch.cc:2751 f.retouch.cc:2824 +msgid "DRGB parameters file" +msgstr "" + +#: f.retouch.cc:2769 f.retouch.cc:6142 +msgid "file not found" +msgstr "File non trovato" + +#: f.retouch.cc:2802 +msgid "Save DRGB parameters" +msgstr "" + +#: f.retouch.cc:3034 f.tools.cc:2404 +msgid "Click image to select pixels." +msgstr "Cliccare l'immagine per selezionare i pixel" + +#: f.retouch.cc:3072 fotoxx-12.01.1.cc:275 +msgid "Revise RGB" +msgstr "Edita RGB" + +#: f.retouch.cc:3084 +msgid "Metric:" +msgstr "Metrica" + +#: f.retouch.cc:3139 +msgid "Blend" +msgstr "Mescola" + +#: f.retouch.cc:3519 +msgid "" +"Method 1:\n" +" Left-click on red-eye to darken.\n" +"Method 2:\n" +" Drag down and right to enclose red-eye.\n" +" Left-click on red-eye to darken.\n" +"Undo red-eye:\n" +" Right-click on red-eye." +msgstr "" +"Metodo 1:\n" +" - Cliccare col pulsante sinistro sull'occhio rosso per scurirlo.\n" +"Metodo 2:\n" +" - Trascinare verso destra e in basso per circondare l'occhio rosso. \n" +" - Cliccare col pulsante sinistro sull'occhio rosso per scurirlo. \n" +"Per annullare:\n" +" - Cliccare col pulsante destro sull'occhio rosso." + +#: f.retouch.cc:3534 +msgid "Red Eye Reduction" +msgstr "Riduzione occhi rossi" + +#: f.retouch.cc:3968 +msgid "Set Blur Radius" +msgstr "Sfuocatura: imposta raggio" + +#: f.retouch.cc:4195 fotoxx-12.01.1.cc:278 +msgid "Sharpen Image" +msgstr "Contrasta" + +#: f.retouch.cc:4202 +msgid "edge detection" +msgstr "Riconoscimento dei bordi" + +#: f.retouch.cc:4203 +msgid "cycles" +msgstr "Cicli" + +#: f.retouch.cc:4204 +msgid "reduce" +msgstr "Riduci" + +#: f.retouch.cc:4215 +msgid "unsharp mask" +msgstr "Maschera di contrasto" + +#: f.retouch.cc:4228 +msgid "brightness gradient" +msgstr "Gradiente di luminosità" + +#: f.retouch.cc:4634 +msgid "" +" Press the reduce button to \n" +" reduce noise in small steps. \n" +" Use undo to start over." +msgstr "" +" Cliccare [Ridurre] per ridurre il disturbo \n" +" a piccoli passi. \n" +" Usare [Annulla] per ricominciare." + +#: f.retouch.cc:4645 +msgid "Noise Reduction" +msgstr "Riduzione disturbo" + +#: f.retouch.cc:4650 +msgid "algorithm" +msgstr "Algoritmo:" + +#: f.retouch.cc:4657 +msgid "flatten outliers by color (1)" +msgstr "Appiattimento estremi per colore (1)" + +#: f.retouch.cc:4658 +msgid "flatten outliers by color (2)" +msgstr "Appiattimento estremi per colore (2)" + +#: f.retouch.cc:4659 +msgid "set median brightness by color" +msgstr "Impostazione luminosità media per colore" + +#: f.retouch.cc:4660 f.retouch.cc:4661 +msgid "top hat filter by color" +msgstr "Filtro \"top hat\" per colore" + +#: f.retouch.cc:4976 +msgid "" +"1. Drag mouse to select. \n" +"2. Erase. 3. Repeat. " +msgstr "" +"1. Trascinare per selezionare. \n" +"2. Cancellare. 3. Ripetere. " + +#: f.retouch.cc:4998 fotoxx-12.01.1.cc:280 +msgid "Smart Erase" +msgstr "Cancellazione intelligente" + +#: f.retouch.cc:5003 fotoxx.h:776 +msgid "Radius" +msgstr "Raggio" + +#: f.retouch.cc:5005 +msgid "Blur" +msgstr "Sfuoca" + +#: f.retouch.cc:5008 +msgid "New Area" +msgstr "Nuova area" + +#: f.retouch.cc:5379 fotoxx-12.01.1.cc:281 +msgid "Remove Dust" +msgstr "Rimozione polvere" + +#: f.retouch.cc:5383 +msgid "spot size limit" +msgstr "Raggio max della polvere" + +#: f.retouch.cc:5386 +msgid "max. brightness" +msgstr "Luminosità massima" + +#: f.retouch.cc:5389 +msgid "min. contrast" +msgstr "Contrasto minimo" + +#: f.retouch.cc:5983 fotoxx-12.01.1.cc:282 +msgid "Fix Stuck Pixels" +msgstr "Correggi pixel difettosi" + +#: f.retouch.cc:5989 +msgid "pixel group" +msgstr "Gruppo di pixel:" + +#: f.retouch.cc:5990 +msgid "circle color" +msgstr "Colore circolo:" + +#: f.retouch.cc:6100 +msgid "Load Stuck Pixels" +msgstr "Carica posizioni" + +#: f.retouch.cc:6124 f.retouch.cc:6220 +msgid "Stuck Pixels file" +msgstr "File di posizioni dei pixel rovinati" + +#: f.retouch.cc:6164 +msgid "file format error" +msgstr "Formato file errato" + +#: f.retouch.cc:6192 +msgid "there are zero stuck pixels" +msgstr "Non ci sono pixel difettosi" + +#: f.retouch.cc:6196 +msgid "Save Stuck Pixels" +msgstr "Salva posizioni" + +#: f.retouch.cc:6686 +#, c-format +msgid "Undo Memory %d%c" +msgstr "Memoria per Annulla %d%c" + +#: f.retouch.cc:6688 fotoxx-12.01.1.cc:283 +msgid "Edit Pixels" +msgstr "Modifica pixel" + +#: f.retouch.cc:6695 +msgid "pick" +msgstr "Seleziona" + +#: f.retouch.cc:6697 +msgid "erase" +msgstr "Cancella" + +#: f.retouch.cc:6705 +msgid "paintbrush radius" +msgstr "Raggio del pennello:" + +#: f.retouch.cc:6706 +msgid "transparency center" +msgstr "Trasparenza al centro:" + +#: f.retouch.cc:6707 +msgid "transparency edge" +msgstr "Trasparenza al bordo:" + +#: f.retouch.cc:6972 +msgid "" +"Undo memory limit has been reached. \n" +"Save work with [done], then resume editing." +msgstr "" +"Il limite della memoria per Annulla è stato raggiunto. \n" +"Salvare il lavoro con [Fatto], e riprendere le modifiche." + +#: f.select.cc:54 f.select.cc:2461 +msgid "Select Area for Edits" +msgstr "Seleziona area per modifiche" + +#: f.select.cc:55 f.select.cc:2462 +msgid "Press F1 for help" +msgstr "Premere F1 per l'aiuto" + +#: f.select.cc:64 +msgid "" +"Select Area not supported \n" +"by this edit function" +msgstr "" +"Questa funzione non supporta \n" +"aree di selezione." + +#: f.select.cc:103 f.tools.cc:901 +msgid "rectangle" +msgstr "Rettangolo" + +#: f.select.cc:104 f.tools.cc:902 +msgid "ellipse" +msgstr "Ellisse" + +#: f.select.cc:110 +msgid "draw: freehand" +msgstr "Disegno: mano libera" + +#: f.select.cc:111 +msgid "draw: follow edge" +msgstr "Disegno: segui bordi" + +#: f.select.cc:114 +msgid "select by mouse" +msgstr "Selezione col mouse: " + +#: f.select.cc:116 f.select.cc:2496 +msgid "mouse radius" +msgstr "Raggio del mouse:" + +#: f.select.cc:120 +msgid "match mouse color" +msgstr "Corrispondenza colore:" + +#: f.select.cc:124 +msgid "search range" +msgstr "Distanza di ricerca:" + +#: f.select.cc:126 +msgid "firewall" +msgstr "confinamento" + +#: f.select.cc:326 f.select.cc:467 +#, c-format +msgid "exceed %d edits" +msgstr "superate %d modifiche" + +#: f.select.cc:1021 +msgid "" +"Click one time inside each enclosed area \n" +"(possible gaps in the outline will be found). \n" +"Press F1 for help." +msgstr "" +"Cliccare ogni singola area chiusa: \n" +"eventuali interruzioni nel contorno saranno rilevate. \n" +"Premere F1 per l'aiuto" + +#: f.select.cc:1078 +msgid "finish area" +msgstr "Finisci area" + +#: f.select.cc:1113 +msgid "searching" +msgstr "in ricerca" + +#: f.select.cc:1185 +msgid "outline has a gap" +msgstr "il contorno è interrotto" + +#: f.select.cc:1189 +msgid "success" +msgstr "Successo" + +#: f.select.cc:1440 f.select.cc:1470 +msgid "the area is not finished" +msgstr "L'area non è chiusa" + +#: f.select.cc:1563 +msgid "Edge calculation in progress" +msgstr "Ricalcolo bordo in corso" + +#: f.select.cc:1572 +msgid "Area Edge Calc" +msgstr "Calcolo area delimitata" + +#: f.select.cc:1863 +msgid "position with mouse click/drag" +msgstr "posizione con clic o trascinamento" + +#: f.select.cc:1887 +msgid "Paste Image" +msgstr "Incolla immagine" + +#: f.select.cc:1901 +msgid "angle" +msgstr "angolo" + +#: f.select.cc:2160 +msgid "load select area from a file" +msgstr "carica l'area di selezione da file" + +#: f.select.cc:2194 +msgid "cannot open .tiff and .info files" +msgstr "impossibile aprire i file .tiff e .info" + +#: f.select.cc:2213 +msgid "save select area to a file" +msgstr "salva area in un file" + +#: f.select.cc:2248 fotoxx-12.01.1.cc:247 +msgid "Select Whole Image" +msgstr "Immagine intera" + +#: f.select.cc:2249 +msgid "Edit Function Amplifier" +msgstr "Regola amplificazione di funzione" + +#: f.select.cc:2463 +msgid "Edit function must be active" +msgstr "" + +#: f.select.cc:2499 +msgid "power: center" +msgstr "Forza: centro:" + +#: f.select.cc:2501 +msgid "edge" +msgstr "bordo:" + +#: f.select.cc:2504 +msgid "reset area" +msgstr "Azzera area" + +#: f.tools.cc:42 +msgid "" +"When editing a collection, right-click \n" +"an image or thumbnail to add or remove." +msgstr "" +"Nella gestione di collezioni, usare un clic destro \n" +"su immagini e miniature per agguingere o eliminare." + +#: f.tools.cc:70 fotoxx-12.01.1.cc:203 +msgid "Manage Collections" +msgstr "Gestione collezioni" + +#: f.tools.cc:85 +msgid "Start new collection" +msgstr "Crea una collezione nuova" + +#: f.tools.cc:87 +msgid "Edit a collection" +msgstr "Modificare una collezione" + +#: f.tools.cc:89 +msgid "View a collection" +msgstr "Visualizzare una collezione" + +#: f.tools.cc:91 +msgid "Delete a collection" +msgstr "Eliminare un collezione" + +#: f.tools.cc:95 +msgid "Editing:" +msgstr "Modifica di:" + +#: f.tools.cc:99 +msgid "Action:" +msgstr "Azione:" + +#: f.tools.cc:133 +msgid "New Collection" +msgstr "Nuova collezione" + +#: f.tools.cc:156 +msgid "Edit Collection" +msgstr "Modifica collezione" + +#: f.tools.cc:172 +msgid "View Collection" +msgstr "Vista collezione" + +#: f.tools.cc:193 +msgid "Delete Collection" +msgstr "Elimina collezione" + +#: f.tools.cc:196 +#, c-format +msgid "delete %s ?" +msgstr "Eliminare %s?" + +#: f.tools.cc:223 +#, c-format +msgid "add image to collection: %s" +msgstr "Aggiungi immagine alla collezione %s" + +#: f.tools.cc:225 f.tools.cc:270 +msgid "remove image from collection" +msgstr "Rimuovi immagine dalla collezione" + +#: f.tools.cc:226 f.tools.cc:271 f.tools.cc:298 +msgid "remove and save image" +msgstr "Rimuovi immagine e ricordala" + +#: f.tools.cc:227 f.tools.cc:316 +msgid "insert saved images here" +msgstr "Inserisci qui le immagini ricordate" + +#: f.tools.cc:256 +msgid "add image to collection" +msgstr "Aggiungi immagine alla collezione" + +#: f.tools.cc:301 +msgid "too many saved files" +msgstr "Troppi file da ricordare" + +#: f.tools.cc:373 fotoxx-12.01.1.cc:204 +msgid "Move Collections" +msgstr "Sposta collezioni" + +#: f.tools.cc:375 +msgid "old top directory" +msgstr "Vecchia cartella principale" + +#: f.tools.cc:378 +msgid "new top directory" +msgstr "Nuova cartella principale" + +#: f.tools.cc:434 +msgid "completed" +msgstr "Completato" + +#: f.tools.cc:467 +msgid "Batch Convert/Resize/Export" +msgstr "Converti/ridimensiona/esporta in blocco" + +#: f.tools.cc:474 +msgid "new max. width" +msgstr "Nuova larghezza max:" + +#: f.tools.cc:481 +msgid "new file type" +msgstr "Nuovo tipo di file" + +#: f.tools.cc:482 +msgid "same" +msgstr "uguale" + +#: f.tools.cc:490 +msgid "replace originals" +msgstr "Sostituisci gli originali" + +#: f.tools.cc:491 +msgid "export to location" +msgstr "Esporta altrove" + +#: f.tools.cc:492 +msgid "remove EXIF" +msgstr "Elimina EXIF" + +#: f.tools.cc:549 +msgid "Select directory" +msgstr "Seleziona cartella" + +#: f.tools.cc:583 +#, c-format +msgid "replace original files? (max. %d x %d)" +msgstr "Sostituire i file originali? (max. %d x %d)" + +#: f.tools.cc:590 +#, c-format +msgid "" +"copy files? (max. %d x %d) \n" +" to location %s" +msgstr "" +"Copiare i file? (max. %d x %d) \n" +" nella posizione %s" + +#: f.tools.cc:601 +msgid "location is not a valid directory" +msgstr "La posizione non è una cartella valida" + +#: f.tools.cc:608 f.tools.cc:3007 +#, c-format +msgid "max. size %d x %d is not reasonable" +msgstr "Dimensioni massime %d x %d non ragionevoli" + +#: f.tools.cc:654 +msgid "*** file already exists" +msgstr "*** file già esistente" + +#: f.tools.cc:662 +msgid "*** file type not supported" +msgstr "*** tipo di file non gestito" + +#: f.tools.cc:741 +msgid "Program ufraw-batch is required" +msgstr "E' richiesto il programma ufraw-batch" + +#: f.tools.cc:751 fotoxx.h:770 +msgid "Open RAW File" +msgstr "Apri file RAW" + +#: f.tools.cc:764 +msgid "Select RAW files to convert" +msgstr "Scegliere i file RAW da convertire" + +#: f.tools.cc:769 +msgid "Choose file type" +msgstr "Scegliere il tipo di file" + +#: f.tools.cc:888 +msgid "Press ESC to exit slide show" +msgstr "Premere ESC per terminare lo slide show" + +#: f.tools.cc:889 +msgid "show only latest file versions" +msgstr "Mostra solo le ultime versioni" + +#: f.tools.cc:893 +msgid "arrow keys" +msgstr "Manuale: tasti freccia" + +#: f.tools.cc:894 +msgid "instant" +msgstr "Istantanea" + +#: f.tools.cc:895 +msgid "fade-in" +msgstr "Dissolvenza" + +#: f.tools.cc:896 +msgid "roll-right" +msgstr "Tenda sx-dx" + +#: f.tools.cc:897 +msgid "roll-down" +msgstr "Tenda su-giù" + +#: f.tools.cc:898 +msgid "shift-left" +msgstr "Scorrimento a sinistra" + +#: f.tools.cc:899 +msgid "venetian" +msgstr "Veneziana" + +#: f.tools.cc:900 +msgid "grate" +msgstr "Quadrettoni" + +#: f.tools.cc:903 +msgid "radar" +msgstr "Radar" + +#: f.tools.cc:904 +msgid "jaws" +msgstr "Ganasce" + +#: f.tools.cc:911 fotoxx-12.01.1.cc:207 +msgid "Slide Show" +msgstr "Slideshow" + +#: f.tools.cc:915 +msgid "seconds" +msgstr "secondi" + +#: f.tools.cc:919 +msgid "music file" +msgstr "File musicale" + +#: f.tools.cc:923 +msgid "transitions" +msgstr "Transizioni" + +#: f.tools.cc:1040 +msgid "Select music file or playlist" +msgstr "Selezionare file musicale o playlist" + +#: f.tools.cc:1727 +msgid "Sync Files is already running" +msgstr "Sincronizzazione file già attiva" + +#: f.tools.cc:1778 +msgid "" +"Run Tools > Synchronize Files so that gallery windows \n" +"will be fast and Search Images will work correctly. \n" +"You can view (not edit) images while synchronize runs." +msgstr "" +"Eseguire [Strumenti > Sincronizza file] affinché le gallerie \n" +"di miniature siano veloci e la Ricerca immagini funzioni. \n" +"Si possono vedere le immagini, ma non manipolare, mentre il processo gira." + +#: f.tools.cc:1812 +msgid "no top image directory is defined" +msgstr "Nessuna cartella d'immagini principale è definita" + +#: f.tools.cc:1818 +msgid "top image directory is invalid" +msgstr "Cartella d'immagini principale non valida" + +#: f.tools.cc:1823 +msgid "no search index file is present" +msgstr "Non esiste un file indice per la ricerca" + +#: f.tools.cc:1837 +msgid "new/modified files are present" +msgstr "Sono presenti file nuovi o modificati" + +#: f.tools.cc:1844 +msgid "no new files found" +msgstr "nessun nuovo file trovato" + +#: f.tools.cc:1859 fotoxx-12.01.1.cc:208 +msgid "Synchronize Files" +msgstr "Sincronizza file" + +#: f.tools.cc:1861 +msgid "Top Image Directory:" +msgstr "Cartella immagini principale:" + +#: f.tools.cc:1883 +msgid "" +"file sync is necessary.\n" +"cancel anyway?" +msgstr "" + +#: f.tools.cc:1896 +msgid "top directory is invalid" +msgstr "La cartella principale non è valida" + +#: f.tools.cc:2292 +msgid "Select top image directory" +msgstr "Scegliere la cartella principale delle immagini" + +#: f.tools.cc:2429 fotoxx-12.01.1.cc:209 +msgid "Show RGB" +msgstr "Esplora componenti RGB" + +#: f.tools.cc:2719 fotoxx-12.01.1.cc:210 +msgid "Grid Lines" +msgstr "Linee griglia" + +#: f.tools.cc:2728 +msgid "x-spacing" +msgstr "Passo X:" + +#: f.tools.cc:2729 +msgid "x-count" +msgstr "Num. barre X:" + +#: f.tools.cc:2730 +msgid "x-enable" +msgstr "Abilita X:" + +#: f.tools.cc:2736 +msgid "y-spacing" +msgstr "Passo Y:" + +#: f.tools.cc:2737 +msgid "y-count" +msgstr "Num. righe Y:" + +#: f.tools.cc:2738 +msgid "y-enable" +msgstr "Abilita Y:" + +#: f.tools.cc:2745 +msgid "x-offset" +msgstr "Origine X:" + +#: f.tools.cc:2749 +msgid "y-offset" +msgstr "Origine Y:" + +#: f.tools.cc:2940 fotoxx-12.01.1.cc:212 +msgid "E-mail Images" +msgstr "Spedisci immagini via e-mail" + +#: f.tools.cc:2947 +msgid "max. width" +msgstr "Larghezza max:" + +#: f.tools.cc:2948 +msgid "max. height" +msgstr "Altezza max:" + +#: f.tools.cc:3093 +msgid "too many files" +msgstr "Troppi file" + +#: f.tools.cc:3134 +msgid "" +"Brightness should show a gradual ramp \n" +"extending all the way to the edges." +msgstr "" +"Le barre dovrebbero mostrare una gradualità\n" +"in tutta la loro estensione." + +#: f.tools.cc:3174 +msgid "Monitor Check" +msgstr "Verifica schermo" + +#: f.tools.cc:3232 fotoxx-12.01.1.cc:214 +msgid "Monitor Gamma" +msgstr "Gamma dello schermo" + +#: f.tools.cc:3294 fotoxx-12.01.1.cc:215 +msgid "Brightness Distribution" +msgstr "Distribuzione della luminosità" + +#: f.tools.cc:3432 +msgid "Available Translations" +msgstr "Traduzioni disponibili" + +#: f.tools.cc:3436 +msgid "Set Language" +msgstr "Cambia lingua" + +#: f.tools.cc:3502 +msgid "Make Launcher" +msgstr "Crea lanciatore" + +#: f.tools.cc:3540 +msgid "Settings" +msgstr "" + +#: f.tools.cc:3545 +msgid "Startup Display" +msgstr "" + +#: f.tools.cc:3547 +msgid "Recent Files Gallery" +msgstr "" + +#: f.tools.cc:3548 +msgid "Previous Image Viewed" +msgstr "" + +#: f.tools.cc:3549 +msgid "Blank Window" +msgstr "" + +#: f.tools.cc:3551 +msgid "Directory Gallery" +msgstr "" + +#: f.tools.cc:3556 +msgid "Image File" +msgstr "" + +#: f.tools.cc:3562 +msgid "Toolbar Style" +msgstr "Stile barra strumenti" + +#: f.tools.cc:3563 f.transform.cc:1300 +msgid "Text" +msgstr "Testo" + +#: f.tools.cc:3564 +msgid "Icons" +msgstr "" + +#: f.tools.cc:3565 +msgid "Both" +msgstr "" + +#: f.tools.cc:3568 +msgid "Warn Overwrite" +msgstr "" + +#: f.tools.cc:3639 +msgid "startup directory is invalid" +msgstr "" + +#: f.tools.cc:3650 +msgid "startup file is invalid" +msgstr "" + +#: f.tools.cc:3707 +msgid "Select startup directory" +msgstr "" + +#: f.tools.cc:3715 +msgid "Select startup image file" +msgstr "" + +#: f.transform.cc:50 +msgid "Use buttons or drag right edge with mouse" +msgstr "Usa i bottoni o trascina il margine destro con il mouse" + +#: f.transform.cc:60 fotoxx-12.01.1.cc:251 +msgid "Rotate Image" +msgstr "Ruota" + +#: f.transform.cc:64 +msgid "degrees" +msgstr "Gradi" + +#: f.transform.cc:80 f.transform.cc:124 +msgid "Trim" +msgstr "Ritaglia" + +#: f.transform.cc:81 f.transform.cc:2289 f.transform.cc:3120 +#: f.transform.cc:3383 f.transform.cc:3644 +msgid "Grid" +msgstr "Griglia" + +#: f.transform.cc:123 +msgid "Undo Trim" +msgstr "Annulla ritaglio" + +#: f.transform.cc:139 +#, c-format +msgid "degrees: %.1f" +msgstr "Gradi : %.1f" + +#: f.transform.cc:286 +msgid "gold" +msgstr "Gold" + +#: f.transform.cc:334 +msgid "Drag middle to move, drag corners to resize." +msgstr "Trascinare il centro per spostare, e i lati per ridimensionare." + +#: f.transform.cc:348 fotoxx-12.01.1.cc:252 +msgid "Trim Image" +msgstr "Ritaglia" + +#: f.transform.cc:348 +msgid "customize" +msgstr "Personalizza" + +#: f.transform.cc:359 +msgid "ratio" +msgstr "Rapporto:" + +#: f.transform.cc:363 +msgid "Lock Ratio" +msgstr "Blocca proporzioni" + +#: f.transform.cc:368 +msgid "invert" +msgstr "Inverti" + +#: f.transform.cc:890 +msgid "Trim Buttons" +msgstr "Pulsanti di taglio" + +#: f.transform.cc:1064 +msgid "Lock aspect ratio" +msgstr "Blocca proporzioni" + +#: f.transform.cc:1072 fotoxx-12.01.1.cc:254 +msgid "Resize Image" +msgstr "Ridimensiona" + +#: f.transform.cc:1095 fotoxx-12.01.1.cc:325 +msgid "Prev" +msgstr "Prec." + +#: f.transform.cc:1245 +msgid "" +"Enter text, click/drag on image.\n" +"Right click to remove" +msgstr "" +"Impostare il testo e cliccare/trascinare nell'immagine.\n" +"Clic destro per rimuovere" + +#: f.transform.cc:1294 fotoxx-12.01.1.cc:255 +msgid "Annotate Image" +msgstr "Inserisci testo" + +#: f.transform.cc:1307 +msgid "Size" +msgstr "Dimensione:" + +#: f.transform.cc:1310 +msgid "Angle" +msgstr "Angolo:" + +#: f.transform.cc:1321 fotoxx.h:741 +msgid "Color" +msgstr "Colore:" + +#: f.transform.cc:1322 +msgid "Transparency" +msgstr "Trasparenza:" + +#: f.transform.cc:1325 +msgid "text" +msgstr "Testo" + +#: f.transform.cc:1330 +msgid "backing" +msgstr "Sfondo" + +#: f.transform.cc:1333 +msgid "" +"Outline\n" +" Width" +msgstr "Spessore contorno:" + +#: f.transform.cc:1335 +msgid "outline" +msgstr "Contorno" + +#: f.transform.cc:1342 +msgid "Annotation File:" +msgstr "File annotazioni:" + +#: f.transform.cc:1416 +msgid "select font" +msgstr "Scegliere il font" + +#: f.transform.cc:2045 fotoxx-12.01.1.cc:256 +msgid "Flip Image" +msgstr "Rifletti/specchia" + +#: f.transform.cc:2049 f.transform.cc:2281 +msgid "horizontal" +msgstr "Orizzontale" + +#: f.transform.cc:2050 f.transform.cc:2280 +msgid "vertical" +msgstr "Verticale" + +#: f.transform.cc:2155 fotoxx-12.01.1.cc:257 +msgid "Make Negative" +msgstr "Genera negativo" + +#: f.transform.cc:2158 +msgid "black/white positive" +msgstr "Bianco e nero, positivo" + +#: f.transform.cc:2159 +msgid "black/white negative" +msgstr "Bianco e nero, negativo" + +#: f.transform.cc:2160 +msgid "color positive" +msgstr "A colori, positivo" + +#: f.transform.cc:2161 +msgid "color negative" +msgstr "A colori, negativo" + +#: f.transform.cc:2272 fotoxx-12.01.1.cc:258 +msgid "Unbend Image" +msgstr "Correggi deformazioni obbiettivo" + +#: f.transform.cc:2282 +msgid "linear" +msgstr "Lineare" + +#: f.transform.cc:2285 +msgid "curved" +msgstr "Curvato" + +#: f.transform.cc:2544 +msgid "" +" Click the four corners of a tetragon area. Press [apply]. \n" +" The image is warped to make the tetragon into a rectangle." +msgstr "" +" Cliccare gli angoli di un'area trapezoidale; cliccare [Applica]. \n" +" L'immagine si deformerà per trasformare il trapezio in un rettangolo." + +#: f.transform.cc:2556 fotoxx-12.01.1.cc:259 +msgid "Keystone Correction" +msgstr "Correzione quadrangolare" + +#: f.transform.cc:2724 +msgid "must have 4 corners" +msgstr "Occorrono 4 angoli." + +#: f.transform.cc:2847 +msgid "" +" Select an area to warp using select area function. \n" +" Press [start warp] and pull area with mouse. \n" +" Make multiple mouse pulls until satisfied. \n" +" When finished, select another area or press [done]." +msgstr "" +"Selezionare un'area da deformare utilizzando la funzione del menu. \n" +"Premere [Avvia deformazione] e trascinare con il mouse.\n" +"Trascinare più volte se necessario.\n" +"Quando terminato, selezionare un'altra zona o premere [Fatto]. " + +#: f.transform.cc:2859 fotoxx-12.01.1.cc:260 +msgid "Warp Image (area)" +msgstr "Deforma area" + +#: f.transform.cc:2864 +msgid "start warp" +msgstr "Avvia deformazione" + +#: f.transform.cc:2931 +msgid "no active Select Area" +msgstr "Area di selezione non attiva" + +#: f.transform.cc:3099 f.transform.cc:3362 +msgid "" +" Pull an image position using the mouse. \n" +" Make multiple mouse pulls until satisfied. \n" +" When finished, press [done]." +msgstr "" +" Trascinare un punto dell'immagine con il mouse. \n" +" Eseguire diversi trascinamenti fino al completamento. \n" +" Quando finito, premere [Fatto]." + +#: f.transform.cc:3112 fotoxx-12.01.1.cc:261 +msgid "Warp Image (curved)" +msgstr "Deforma a curva" + +#: f.transform.cc:3375 fotoxx-12.01.1.cc:262 +msgid "Warp Image (linear)" +msgstr "Deforma a linea" + +#: f.transform.cc:3628 +msgid "" +" Pull on an image corner using the mouse. \n" +" Make multiple mouse pulls until satisfied. \n" +" When finished, press [done]." +msgstr "" +"Trascinare angoli o lati dell'immagine con il mouse. \n" +"Ripetere l'operazione se richiesto.\n" +"Una volta finito, premere [Fatto]." + +#: f.transform.cc:3639 fotoxx-12.01.1.cc:263 +msgid "Warp Image (affine)" +msgstr "Deforma specularmente" + +#: fotoxx-12.01.1.cc:184 +msgid "File" +msgstr "File" + +#: fotoxx-12.01.1.cc:185 fotoxx-12.01.1.cc:323 +msgid "Image Gallery" +msgstr "Galleria immagini" + +#: fotoxx-12.01.1.cc:186 +msgid "Clone 50/50" +msgstr "Clona (50/50)" + +#: fotoxx-12.01.1.cc:187 +msgid "Clone Overlay" +msgstr "Clona (sovrapposta)" + +#: fotoxx-12.01.1.cc:189 +msgid "Open in New Window" +msgstr "Apri in nuova finestra" + +#: fotoxx-12.01.1.cc:190 fotoxx-12.01.1.cc:325 +msgid "Open Previous File" +msgstr "Apri l'immagine precedente" + +#: fotoxx-12.01.1.cc:191 +msgid "Open Recent File" +msgstr "Immagini recenti" + +#: fotoxx-12.01.1.cc:192 fotoxx-12.01.1.cc:333 +msgid "Save to Same File" +msgstr "Salva (sovrascrivi)" + +#: fotoxx-12.01.1.cc:193 fotoxx-12.01.1.cc:334 +msgid "Save to New Version" +msgstr "Salva con nuova versione" + +#: fotoxx-12.01.1.cc:194 fotoxx-12.01.1.cc:335 +msgid "Save to New File" +msgstr "Salva in un file nuovo" + +#: fotoxx-12.01.1.cc:196 +msgid "Trash Image File" +msgstr "Cestina l'immagine" + +#: fotoxx-12.01.1.cc:198 +msgid "Batch Rename Files" +msgstr "Rinomina più immagini" + +#: fotoxx-12.01.1.cc:199 +msgid "Print Image File" +msgstr "Stampa immagine" + +#: fotoxx-12.01.1.cc:200 fotoxx-12.01.1.cc:339 +msgid "Quit fotoxx" +msgstr "Termina Fotoxx" + +#: fotoxx-12.01.1.cc:202 +msgid "Tools" +msgstr "Strumenti" + +#: fotoxx-12.01.1.cc:205 +msgid "Batch Convert" +msgstr "Converti più immagini" + +#: fotoxx-12.01.1.cc:206 +msgid "Convert RAW files" +msgstr "Converti immagini RAW" + +#: fotoxx-12.01.1.cc:211 +msgid "Burn Images to CD/DVD" +msgstr "Masterizza immagini su CD/DVD" + +#: fotoxx-12.01.1.cc:213 +msgid "Check Monitor" +msgstr "Verifica schermo" + +#: fotoxx-12.01.1.cc:216 +msgid "Change Language" +msgstr "Cambia lingua del programma" + +#: fotoxx-12.01.1.cc:218 +msgid "Menu and Launcher" +msgstr "Crea menù/lanciatore" + +#: fotoxx-12.01.1.cc:219 +msgid "User Settings" +msgstr "" + +#: fotoxx-12.01.1.cc:220 +msgid "Memory Usage" +msgstr "Mostra uso memoria (in console)" + +#: fotoxx-12.01.1.cc:223 +msgid "Edit Caption/Comments" +msgstr "Modifica titolo/commenti" + +#: fotoxx-12.01.1.cc:228 +msgid "View Info (short)" +msgstr "Informazioni brevi" + +#: fotoxx-12.01.1.cc:229 +msgid "View Info (long)" +msgstr "Informazioni estese" + +#: fotoxx-12.01.1.cc:232 +msgid "Search Images" +msgstr "Ricerca immagini" + +#: fotoxx-12.01.1.cc:233 +msgid "Search Metadata" +msgstr "" + +#: fotoxx-12.01.1.cc:235 fotoxx-12.01.1.cc:236 fotoxx.h:786 +msgid "Select" +msgstr "Seleziona" + +#: fotoxx-12.01.1.cc:237 fotoxx.h:788 +msgid "Show" +msgstr "Visualizza" + +#: fotoxx-12.01.1.cc:238 fotoxx.h:761 +msgid "Hide" +msgstr "Nascondi" + +#: fotoxx-12.01.1.cc:239 fotoxx.h:752 +msgid "Enable" +msgstr "Abilita" + +#: fotoxx-12.01.1.cc:240 fotoxx.h:748 +msgid "Disable" +msgstr "Disabilita" + +#: fotoxx-12.01.1.cc:241 fotoxx.h:763 +msgid "Invert" +msgstr "Inverti" + +#: fotoxx-12.01.1.cc:242 fotoxx.h:796 +msgid "Unselect" +msgstr "Deseleziona" + +#: fotoxx-12.01.1.cc:243 fotoxx.h:743 +msgid "Copy" +msgstr "Copia" + +#: fotoxx-12.01.1.cc:244 fotoxx.h:771 +msgid "Paste" +msgstr "Incolla" + +#: fotoxx-12.01.1.cc:246 fotoxx-12.01.1.cc:333 fotoxx.h:783 +msgid "Save" +msgstr "Salva" + +#: fotoxx-12.01.1.cc:248 +msgid "Select and Edit" +msgstr "Seleziona e modifica" + +#: fotoxx-12.01.1.cc:250 +msgid "Transform" +msgstr "Trasforma" + +#: fotoxx-12.01.1.cc:253 +msgid "Auto-Trim Image" +msgstr "Ritaglia automaticamente" + +#: fotoxx-12.01.1.cc:265 +msgid "Retouch" +msgstr "Ritocco" + +#: fotoxx-12.01.1.cc:266 +msgid "Brightness/Color" +msgstr "Luminosità e colore" + +#: fotoxx-12.01.1.cc:267 +msgid "Gamma Curves" +msgstr "Curve Gamma" + +#: fotoxx-12.01.1.cc:268 +msgid "Expand Brightness" +msgstr "Espandi luminosità" + +#: fotoxx-12.01.1.cc:269 +msgid "Flatten Brightness" +msgstr "Normalizza luminosità" + +#: fotoxx-12.01.1.cc:270 +msgid "Brightness Ramp" +msgstr "Rampe di luce/colore" + +#: fotoxx-12.01.1.cc:272 +msgid "White Balance" +msgstr "Bilanciamento del bianco" + +#: fotoxx-12.01.1.cc:273 +msgid "Match Colors" +msgstr "Trasferisci colore" + +#: fotoxx-12.01.1.cc:276 +msgid "Red Eyes" +msgstr "Rimuovi occhi rossi" + +#: fotoxx-12.01.1.cc:277 +msgid "Blur Image" +msgstr "Sfuoca" + +#: fotoxx-12.01.1.cc:279 +msgid "Reduce Noise" +msgstr "Riduci disturbo" + +#: fotoxx-12.01.1.cc:285 +msgid "Art" +msgstr "Arte" + +#: fotoxx-12.01.1.cc:286 +msgid "Color Depth" +msgstr "Profondità di colore" + +#: fotoxx-12.01.1.cc:287 +msgid "Drawing" +msgstr "Disegno" + +#: fotoxx-12.01.1.cc:288 +msgid "Outlines" +msgstr "Contorni" + +#: fotoxx-12.01.1.cc:289 +msgid "Embossing" +msgstr "Bassorilievo" + +#: fotoxx-12.01.1.cc:290 +msgid "Tiles" +msgstr "Mosaico" + +#: fotoxx-12.01.1.cc:291 +msgid "Dots" +msgstr "Puntinismo" + +#: fotoxx-12.01.1.cc:292 +msgid "Painting" +msgstr "Dipinto" + +#: fotoxx-12.01.1.cc:294 +msgid "Combine" +msgstr "Combina" + +#: fotoxx-12.01.1.cc:295 +msgid "High Dynamic Range" +msgstr "Combina immagini (alta dinamica - HDR)" + +#: fotoxx-12.01.1.cc:296 +msgid "High Depth of Field" +msgstr "Combina immagini (grande profondità - HDF)" + +#: fotoxx-12.01.1.cc:297 +msgid "Stack / Paint" +msgstr "Sovrapponi (interattivo con mouse)" + +#: fotoxx-12.01.1.cc:298 +msgid "Stack / Noise" +msgstr "Sovrapponi (rimozione disturbo)" + +#: fotoxx-12.01.1.cc:299 +msgid "Panorama" +msgstr "Crea un panorama" + +#: fotoxx-12.01.1.cc:300 +msgid "Vertical Panorama" +msgstr "Panorama verticale" + +#: fotoxx-12.01.1.cc:303 +msgid "Edit Plugins" +msgstr "Gestione plug-in" + +#: fotoxx-12.01.1.cc:312 fotoxx-12.01.1.cc:340 fotoxx-12.01.1.cc:3025 +msgid "Help" +msgstr "Aiuto" + +#: fotoxx-12.01.1.cc:313 fotoxx-12.01.1.cc:3015 +msgid "About" +msgstr "Info" + +#: fotoxx-12.01.1.cc:314 fotoxx-12.01.1.cc:3019 +msgid "User Guide" +msgstr "Guida utente" + +#: fotoxx-12.01.1.cc:315 fotoxx-12.01.1.cc:3022 +msgid "User Guide Changes" +msgstr "Cronistoria della guida utente" + +#: fotoxx-12.01.1.cc:316 fotoxx-12.01.1.cc:3031 +msgid "Edit Functions Summary" +msgstr "Sommario funzioni" + +#: fotoxx-12.01.1.cc:317 fotoxx-12.01.1.cc:3034 +msgid "Change Log" +msgstr "Cronistoria delle modifiche" + +#: fotoxx-12.01.1.cc:318 fotoxx-12.01.1.cc:3037 +msgid "Translations" +msgstr "Traduzioni" + +#: fotoxx-12.01.1.cc:319 fotoxx-12.01.1.cc:3040 +msgid "Home Page" +msgstr "Sito WEB" + +#: fotoxx-12.01.1.cc:323 +msgid "Gallery" +msgstr "Miniature" + +#: fotoxx-12.01.1.cc:326 fotoxx.h:767 +msgid "Next" +msgstr "Prossima" + +#: fotoxx-12.01.1.cc:326 +msgid "Open Next File" +msgstr "Apri l'immagine successiva" + +#: fotoxx-12.01.1.cc:327 +msgid "Zoom-in (bigger)" +msgstr "Ingrandisci" + +#: fotoxx-12.01.1.cc:328 +msgid "Zoom-out (smaller)" +msgstr "Riduci" + +#: fotoxx-12.01.1.cc:329 fotoxx.h:794 +msgid "Undo" +msgstr "Annulla" + +#: fotoxx-12.01.1.cc:329 +msgid "Undo One Edit" +msgstr "Annulla ultimo" + +#: fotoxx-12.01.1.cc:330 fotoxx.h:779 +msgid "Redo" +msgstr "Ripeti" + +#: fotoxx-12.01.1.cc:330 +msgid "Redo One Edit" +msgstr "Ripeti ultimo" + +#: fotoxx-12.01.1.cc:334 +msgid "Save+V" +msgstr "Salva+V" + +#: fotoxx-12.01.1.cc:335 +msgid "Save+F" +msgstr "Salva>N" + +#: fotoxx-12.01.1.cc:336 +msgid "Move Image to Trash" +msgstr "Cestina immagine" + +#: fotoxx-12.01.1.cc:336 +msgid "Trash" +msgstr "Cestina" + +#: fotoxx-12.01.1.cc:339 +msgid "Quit" +msgstr "Uscita" + +#: fotoxx-12.01.1.cc:340 +msgid "Fotoxx Essentials" +msgstr "Informazioni principali su Fotoxx" + +#: fotoxx-12.01.1.cc:447 +msgid "first time startup" +msgstr "Prima esecuzione" + +#: fotoxx-12.01.1.cc:1943 +msgid "Exceed 50 anchor points" +msgstr "Superati 50 punti di ancoraggio" + +#: fotoxx-12.01.1.cc:2128 +msgid "load curve from a file" +msgstr "carica curva da file" + +#: fotoxx-12.01.1.cc:2181 +msgid "curve file is invalid" +msgstr "File di curve non valido" + +#: fotoxx-12.01.1.cc:2186 +msgid "curve file has different no. of curves" +msgstr "Il file di curve ha un numero diverso di curve" + +#: fotoxx-12.01.1.cc:2201 +msgid "save curve to a file" +msgstr "salva curva in un file" + +#: fotoxx-12.01.1.cc:2336 +msgid "cannot parallel edit" +msgstr "Non si possono fare editazioni concorrenti" + +#: fotoxx-12.01.1.cc:2346 +msgid "" +"exiftool is not installed \n" +"edited images will lose EXIF data" +msgstr "" +"Il pacchetto exiftool non è installato.\n" +"Le immagini modificate perderanno le informazioni Exif." + +#: fotoxx-12.01.1.cc:2352 +msgid "Too many edits, please save image" +msgstr "Troppe modifiche: salvare l'immagine" + +#: fotoxx-12.01.1.cc:2357 +msgid "" +"Select area cannot be kept.\n" +"Continue?" +msgstr "" +"L'area selezionata non può essere mantenuta.\n" +"Continuare?" + +#: fotoxx-12.01.1.cc:2365 +msgid "" +"Select area not active.\n" +"Continue?" +msgstr "" +"Selezione di area non attiva.\n" +"Continuare?" + +#: fotoxx-12.01.1.cc:2836 +msgid "Discard edits?" +msgstr "Scartare le modifiche?" + +#: fotoxx-12.01.1.cc:2837 +msgid "" +"This action will discard current edits.\n" +"Continue to discard edits.\n" +"Go Back to keep edits." +msgstr "" +"Questo annullerà le modifiche correnti.\n" +"[Continua] per confermare la perdita,\n" +"[Indietro] per rinunciare e mantenerle." + +#: fotoxx-12.01.1.cc:2840 +msgid "Continue" +msgstr "Continua" + +#: fotoxx-12.01.1.cc:2841 +msgid "Go Back" +msgstr "Indietro" + +#: fotoxx-12.01.1.cc:3658 +msgid "cannot open thumbnail file" +msgstr "Impossibile aprire il file delle anteprime" + +#: fotoxx-12.01.1.cc:3869 fotoxx-12.01.1.cc:3991 +msgid "TIFF open failure" +msgstr "Apertura TIFF fallita" + +#: fotoxx-12.01.1.cc:3885 +#, c-format +msgid "TIFF bits/color=%d not supported" +msgstr "TIFF bit/colore=%d non supportati" + +#: fotoxx-12.01.1.cc:3900 fotoxx-12.01.1.cc:3938 +msgid "TIFF read failure" +msgstr "Lettura TIFF fallita" + +#: fotoxx-12.01.1.cc:4050 +msgid "TIFF write failure" +msgstr "Scrittura TIFF fallita" + +#: fotoxx-12.01.1.cc:4070 +msgid "file type not supported" +msgstr "Tipo di file non supportato" + +#: fotoxx-12.01.1.cc:4177 +msgid "pixbuf write failure" +msgstr "Scrittura pixbuf fallita" + +#: fotoxx.h:728 +msgid "absolute" +msgstr "Assoluto" + +#: fotoxx.h:730 +msgid "Add All" +msgstr "Aggiungere tutto" + +#: fotoxx.h:732 +msgid "Amount" +msgstr "Quantità" + +#: fotoxx.h:733 +msgid "Apply" +msgstr "Applica" + +#: fotoxx.h:734 +msgid "Black" +msgstr "Nero" + +#: fotoxx.h:735 +msgid "Blend Width" +msgstr "Larghezza di sfumatura" + +#: fotoxx.h:737 +msgid "Brightness" +msgstr "Luminosità" + +#: fotoxx.h:738 +msgid "Browse" +msgstr "Sfoglia" + +#: fotoxx.h:739 +msgid "Cancel" +msgstr "Annulla" + +#: fotoxx.h:740 +msgid "Clear" +msgstr "Pulisci" + +#: fotoxx.h:742 +msgid "Commit" +msgstr "Esegui" + +#: fotoxx.h:744 +msgid "Curve File:" +msgstr "File di curve:" + +#: fotoxx.h:745 +msgid "Cut" +msgstr "Taglia" + +#: fotoxx.h:746 +msgid "Darker Areas" +msgstr "Aree scure" + +#: fotoxx.h:747 +msgid "Delete" +msgstr "Elimina" + +#: fotoxx.h:749 +#, c-format +msgid "" +"Discard special gallery list? \n" +" %s" +msgstr "" +"Annullare la lista della galleria speciale? \n" +" %s" + +#: fotoxx.h:750 +msgid "Done" +msgstr "Fatto" + +#: fotoxx.h:751 +msgid "Edit" +msgstr "Modifica" + +#: fotoxx.h:753 +msgid "Erase" +msgstr "Esegui cancellatura" + +#: fotoxx.h:754 +msgid "package libimage-exiftool-perl is required" +msgstr "è necessario il pacchetto libimage-exiftool-perl" + +#: fotoxx.h:755 +msgid "Fetch" +msgstr "Prendi" + +#: fotoxx.h:756 +msgid "Finish" +msgstr "Termina" + +#: fotoxx.h:757 +msgid "Font" +msgstr "Font" + +#: fotoxx.h:759 +msgid "Height" +msgstr "Altezza" + +#: fotoxx.h:760 +msgid "histogram" +msgstr "Istogramma" + +#: fotoxx.h:762 +msgid "Insert" +msgstr "Incolla" + +#: fotoxx.h:764 +msgid "Lighter Areas" +msgstr "Aree luminose" + +#: fotoxx.h:765 +msgid "limit" +msgstr "limite" + +#: fotoxx.h:766 +msgid "New" +msgstr "Nuovo" + +#: fotoxx.h:768 +msgid "OK" +msgstr "Ok" + +#: fotoxx.h:772 +msgid "Pause" +msgstr "Sospendi" + +#: fotoxx.h:773 +msgid "Percent" +msgstr "Percentuale" + +#: fotoxx.h:774 +msgid "Presets" +msgstr "Fisse: " + +#: fotoxx.h:775 +msgid "Proceed" +msgstr "Prosegui" + +#: fotoxx.h:777 +msgid "range" +msgstr "intervallo" + +#: fotoxx.h:780 +msgid "Reduce" +msgstr "Ridurre" + +#: fotoxx.h:782 +msgid "Reset" +msgstr "Azzera" + +#: fotoxx.h:784 +msgid "Unknown file type, save as tiff/jpeg/png to edit" +msgstr "Tipo di file sconosciuto. Salvarlo come TIFF/JPEG/PNG per modificarlo" + +#: fotoxx.h:785 +msgid "Search" +msgstr "Ricerca" + +#: fotoxx.h:789 +msgid "Start" +msgstr "Inizio" + +#: fotoxx.h:790 +msgid "Threshold" +msgstr "Soglia" + +#: fotoxx.h:791 +#, c-format +msgid "exceed %d files" +msgstr "" + +#: fotoxx.h:792 +msgid "Undo All" +msgstr "Annulla tutto" + +#: fotoxx.h:793 +msgid "Undo Last" +msgstr "Annulla ultimo" + +#: fotoxx.h:795 +msgid "Unfinish" +msgstr "Ricomincia" + +#: fotoxx.h:797 +msgid "View" +msgstr "Vista" + +#: fotoxx.h:798 +msgid "White" +msgstr "Bianco" + +#: fotoxx.h:799 +msgid "Width" +msgstr "Larghezza" + +#: zfuncs.cc:3252 +#, c-format +msgid "help file not found: %s" +msgstr "File di aiuto non trovato: %s" + +#: zfuncs.cc:3664 zfuncs.cc:7315 +#, c-format +msgid "cannot open file %s" +msgstr "non è possibile aprire il file %s" + +#: zfuncs.cc:3697 +msgid "save screen to file" +msgstr "Salva schermo in un file" + +#: zfuncs.cc:6222 +msgid "No" +msgstr "No" + +#: zfuncs.cc:6222 +msgid "Yes" +msgstr "Si" + +#: zfuncs.cc:6447 +msgid "open" +msgstr "Apri" + +#: zfuncs.cc:6452 +msgid "choose" +msgstr "Scegli" + +#: zfuncs.cc:6457 +msgid "save" +msgstr "Salva" + +#: zfuncs.cc:6463 +msgid "open folder" +msgstr "Apri cartella" + +#: zfuncs.cc:6468 +msgid "create folder" +msgstr "Crea cartella" + +#: zfuncs.cc:6474 +msgid "hidden" +msgstr "Nascosto" + +#: zfuncs.cc:6535 +msgid "JPG quality 0-100" +msgstr "Qualità JPG 0-100" + +#: zfuncs.cc:6728 zfuncs.cc:6741 +msgid "margins" +msgstr "Margini" + +#: zfuncs.cc:6737 +msgid "top" +msgstr "Alto" + +#: zfuncs.cc:6738 +msgid "bottom" +msgstr "Basso" + +#: zfuncs.cc:6739 +msgid "left" +msgstr "Sinistra" + +#: zfuncs.cc:6740 +msgid "right" +msgstr "Destra" + +#: zfuncs.cc:7202 +msgid "" +"Initial parameters file created. \n" +"Inspect and revise if necessary." +msgstr "" +"Il primo file di parametri è stato creato. \n" +"Verificare e correggere se necessario." + +#: zfuncs.cc:7218 +msgid "load parameters from a file" +msgstr "Carica i parametri da un file" + +#: zfuncs.cc:7287 +msgid "save parameters to a file" +msgstr "Salva parametri in un file" + +#: zfuncs.cc:7425 zfuncs.cc:7431 zfuncs.cc:7437 zfuncs.cc:7443 +msgid "edit parameters" +msgstr "Modifica parametri" + +#: zfuncs.cc:7426 zfuncs.cc:7432 +msgid "" +"list\n" +"all" +msgstr "" +"elenca\n" +"tutti" + +#: zfuncs.cc:7426 zfuncs.cc:7432 zfuncs.cc:7438 zfuncs.cc:7444 +msgid "" +"load\n" +"file" +msgstr "" +"Carica\n" +"file" + +#: zfuncs.cc:7426 zfuncs.cc:7432 zfuncs.cc:7438 zfuncs.cc:7444 +msgid "" +"save\n" +"file" +msgstr "" +"Salva\n" +"file" + +#: zfuncs.cc:7427 zfuncs.cc:7439 +msgid "" +"add\n" +"new" +msgstr "" +"Aggiungi\n" +"nuovo" + +#: zfuncs.cc:7427 zfuncs.cc:7433 zfuncs.cc:7439 zfuncs.cc:7445 +msgid "apply" +msgstr "Applica" + +#: zfuncs.cc:7479 +msgid "apply?" +msgstr "Applicare?" + +#: zfuncs.cc:7536 +msgid "(new parm name)" +msgstr "(nome nuovo parametro)" + +#: zfuncs.cc:7536 +msgid "add parameter" +msgstr "Aggiungi parametro" + +#~ msgid "start edit function first" +#~ msgstr "Richiamare prima una funzione di modifica (Ritocco, Trasforma...)" + +#~ msgid "file sync is mandatory" +#~ msgstr "'Sincronizza file' è obbligatorio" + +#~ msgid "Lens Parameters" +#~ msgstr "Parametri dell'obbiettivo" + +#~ msgid "lens name" +#~ msgstr "Nome lente" + +#~ msgid "icons" +#~ msgstr "Icone" + +#~ msgid "both" +#~ msgstr "Entrambi" + +#~ msgid "my mouse" +#~ msgstr "Abilita mouse" + +#~ msgid "select new file" +#~ msgstr "Scegliere un nuovo file" diff -Nru fotoxx-11.11.1/locales/fotoxx-nl.po fotoxx-12.01.2/locales/fotoxx-nl.po --- fotoxx-11.11.1/locales/fotoxx-nl.po 1970-01-01 00:00:00.000000000 +0000 +++ fotoxx-12.01.2/locales/fotoxx-nl.po 2012-01-04 08:47:11.000000000 +0000 @@ -0,0 +1,3213 @@ +# Translation of fotoxx.po to dutch (nl) +# Translated by: Arthur Kalverboer , jun 2011. +# +msgid "" +msgstr "" +"Project-Id-Version: fotoxx 6.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-12-31 21:05+0100\n" +"PO-Revision-Date: 2009-03-06 09:57+0100\n" +"Last-Translator: Arthur\n" +"Language-Team: Dutch\n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: f.art.cc:47 +msgid "Set color depth to 1-16 bits" +msgstr "Instellen kleurdiepte op 1-16 bits" + +#: f.art.cc:57 +msgid "Set Color Depth" +msgstr "Instellen kleurdiepte" + +#: f.art.cc:171 +msgid "Simulate Drawing" +msgstr "Tekenen nabootsen" + +#: f.art.cc:213 f.retouch.cc:1759 f.retouch.cc:5991 +msgid "contrast" +msgstr "contrast" + +#: f.art.cc:215 +msgid "outlines" +msgstr "contouren" + +#: f.art.cc:220 +msgid "pencil" +msgstr "potlood" + +#: f.art.cc:221 +msgid "chalk" +msgstr "krijt" + +#: f.art.cc:381 +msgid "Add Image Outlines" +msgstr "Toevoegen afbeeldings contouren" + +#: f.art.cc:394 +msgid "outline threshold" +msgstr "contour drempel" + +#: f.art.cc:397 +msgid "outline width" +msgstr "contour breedte" + +#: f.art.cc:400 +msgid "image brightness" +msgstr "helderheid afbeelding" + +#: f.art.cc:611 +msgid "Simulate Embossing" +msgstr "Reliefdruk nabootsen" + +#: f.art.cc:626 +msgid "depth" +msgstr "diepte" + +#: f.art.cc:628 f.file.cc:919 f.retouch.cc:6692 +msgid "color" +msgstr "kleur" + +#: f.art.cc:821 +msgid "Simulate Tiles" +msgstr "Tegels nabootsen" + +#: f.art.cc:825 +msgid "tile size" +msgstr "tegelgrootte" + +#: f.art.cc:829 +msgid "tile gap" +msgstr "voegbreedte" + +#: f.art.cc:1003 +msgid "Convert Image to Dots" +msgstr "Converteer naar krantendruk" + +#: f.art.cc:1007 +msgid "dot size" +msgstr "stip grootte" + +#: f.art.cc:1222 +msgid "Simulate Painting" +msgstr "Verven nabootsen" + +#: f.art.cc:1226 +msgid "color depth" +msgstr "kleurdiepte" + +#: f.art.cc:1230 +msgid "patch area goal" +msgstr "" + +#: f.art.cc:1234 +msgid "req. color match" +msgstr "kleur aanpassing" + +#: f.art.cc:1238 +msgid "borders" +msgstr "randen" + +#: f.comp.cc:1956 f.comp.cc:1961 f.comp.cc:2582 f.comp.cc:2587 f.comp.cc:3266 +#: f.comp.cc:3271 f.comp.cc:3816 f.comp.cc:3821 +msgid "Select 2 to 9 files" +msgstr "Selecteer 2 tot 9 bestanden" + +#: f.comp.cc:1982 f.comp.cc:2608 f.comp.cc:3292 f.comp.cc:3842 +msgid "Images are not all the same size" +msgstr "Afbeeldingen hebben niet dezelfde grootte" + +#: f.comp.cc:2321 +msgid "Adjust Image Contributions" +msgstr "Instellen helderheidsbijdragen per afbeelding" + +#: f.comp.cc:2324 f.retouch.cc:886 +msgid "dark pixels" +msgstr "donkere pixels" + +#: f.comp.cc:2326 +msgid "light pixels" +msgstr "heldere pixels" + +#: f.comp.cc:2328 f.info.cc:159 +msgid "file:" +msgstr "bestand:" + +#: f.comp.cc:2843 +msgid "Paint and Warp Image" +msgstr "Verven en kromtrekken afbeelding" + +#: f.comp.cc:2846 f.comp.cc:3520 f.comp.cc:4959 f.comp.cc:5705 +msgid "image" +msgstr "afbeelding" + +#: f.comp.cc:2850 f.retouch.cc:6696 +msgid "paint" +msgstr "verven" + +#: f.comp.cc:2851 +msgid "warp" +msgstr "kromtrekken" + +#: f.comp.cc:3518 +msgid "Select and Paint Image" +msgstr "Selecteer en verf afbeelding" + +#: f.comp.cc:4031 +msgid "Adjust Pixel Composition" +msgstr "Instellen Pixel Samenstelling" + +#: f.comp.cc:4283 f.comp.cc:4288 f.comp.cc:5173 f.comp.cc:5178 +msgid "Select 2 to 4 files" +msgstr "Selecteer 2 tot 4 bestanden" + +#: f.comp.cc:4361 +msgid "" +"Drag images into rough alignment.\n" +"To rotate, drag from lower edge." +msgstr "" +"Sleep afbeeldingen ruwweg aansluitend.\n" +"Om te draaien, sleep de onderste rand." + +#: f.comp.cc:4363 +msgid "Search for lens mm and bow" +msgstr "Zoeken naar brandpuntsafstand en kromming" + +#: f.comp.cc:4409 f.comp.cc:5298 +msgid "Pre-align Images" +msgstr "Afbeelding globaal positioneren" + +#: f.comp.cc:4413 f.comp.cc:5302 +msgid "lens mm" +msgstr "brandpuntsafstand mm" + +#: f.comp.cc:4417 f.comp.cc:5306 +msgid "lens bow" +msgstr "lenskromming" + +#: f.comp.cc:4419 f.comp.cc:5308 +msgid "Resize" +msgstr "Grootte wijzigen" + +#: f.comp.cc:4420 f.comp.cc:5309 +msgid "resize window" +msgstr "venstergrootte wijzigen" + +#: f.comp.cc:4457 +msgid "use two images only" +msgstr "gebruik slechts twee afbeeldingen" + +#: f.comp.cc:4478 f.comp.cc:4676 f.comp.cc:4875 f.comp.cc:5357 f.comp.cc:5620 +msgid "Too little overlap, cannot align" +msgstr "Te weinig overlap, uitlijnen niet mogelijk" + +#: f.comp.cc:4950 f.comp.cc:5696 +msgid "Match Brightness and Color" +msgstr "Match helderheid en kleur" + +#: f.comp.cc:4974 f.comp.cc:5720 +msgid "auto color" +msgstr "auto kleur" + +#: f.comp.cc:4975 f.comp.cc:5721 +msgid "file color" +msgstr "bestand kleur" + +#: f.comp.cc:5251 +msgid "" +"Drag images into rough alignment.\n" +"To rotate, drag from right edge." +msgstr "" +"Sleep afbeeldingen ruwweg aansluitend.\n" +"Om te draaien, sleep de rechter rand." + +#: f.file.cc:169 f.file.cc:341 fotoxx-12.01.cc:189 fotoxx-12.01.cc:325 +msgid "Open Image File" +msgstr "Openen..." + +#: f.file.cc:321 fotoxx-12.01.cc:2862 +msgid "prior function still active" +msgstr "vorige functie nog actief" + +#: f.file.cc:503 +msgid "Overwrite original file?" +msgstr "" + +#: f.file.cc:504 +msgid "Do not warn again" +msgstr "" + +#: f.file.cc:520 +msgid "Warning" +msgstr "" + +#: f.file.cc:643 +msgid "Save File" +msgstr "Bestand opslaan" + +#: f.file.cc:666 zfuncs.cc:6478 +msgid "quality" +msgstr "kwaliteit" + +#: f.file.cc:668 +msgid "make current" +msgstr "" + +#: f.file.cc:725 +msgid "jpeg quality must be 1-100" +msgstr "jpeg kwaliteit moet 1-100 zijn" + +#: f.file.cc:747 +#, c-format +msgid "" +"Overwrite file? \n" +" %s" +msgstr "" +"Bestand overschrijven? \n" +" %s" + +#: f.file.cc:903 fotoxx-12.01.cc:196 +msgid "Create Blank Image" +msgstr "Lege afbeelding maken" + +#: f.file.cc:905 +msgid "file name" +msgstr "" + +#: f.file.cc:910 f.transform.cc:353 +msgid "width" +msgstr "breedte" + +#: f.file.cc:913 f.tools.cc:477 f.transform.cc:356 +msgid "height" +msgstr "hoogte" + +#: f.file.cc:1033 +msgid "" +"Linux standard trash is not supported. \n" +"Desktop trash folder will be created." +msgstr "" +"Linux standaard prullenbak wordt niet ondersteund. \n" +"Desktop prullenbak zal worden aangemaakt." + +#: f.file.cc:1051 +msgid "Move read-only file to trash?" +msgstr "Alleen-lezen bestand naar prullenbak?" + +#: f.file.cc:1077 +#, c-format +msgid "Cannot create trash folder: %s" +msgstr "Kan niet map voor prullenbak maken: %s" + +#: f.file.cc:1085 f.file.cc:1091 zfuncs.cc:3356 +#, c-format +msgid "error: %s" +msgstr "fout: %s" + +#: f.file.cc:1136 fotoxx-12.01.cc:198 +msgid "Rename Image File" +msgstr "Hernoemen bestand..." + +#: f.file.cc:1141 +msgid "old name" +msgstr "oude naam" + +#: f.file.cc:1142 +msgid "rename to" +msgstr "hernoemen naar" + +#: f.file.cc:1143 +msgid "previous" +msgstr "vorige" + +#: f.file.cc:1229 +msgid "The target file already exists" +msgstr "Doelbestand bestaat reeds" + +#: f.file.cc:1237 +#, c-format +msgid "" +"Rename failed: \n" +" %s" +msgstr "" + +#: f.file.cc:1285 +msgid "Batch Rename" +msgstr "Batchgewijs hernoemen" + +#: f.file.cc:1288 f.file.cc:1340 f.info.cc:1519 f.info.cc:1773 f.tools.cc:543 +#: f.tools.cc:2990 +#, c-format +msgid "%d files selected" +msgstr "" + +#: f.file.cc:1290 +msgid "new base name" +msgstr "nieuwe basisnaam" + +#: f.file.cc:1293 +msgid "starting sequence" +msgstr "start volgnummer" + +#: f.file.cc:1295 +msgid "increment" +msgstr "toename" + +#: f.file.cc:1316 +msgid "select files to rename" +msgstr "bestanden selecteren om te hernoemen" + +#: f.file.cc:1321 +msgid "base name / sequence / increment not reasonable" +msgstr "basisnaam / volgorde / toename niet zinvol" + +#: f.file.cc:1380 +msgid "new file already exists:" +msgstr "nieuw bestand bestaat reeds:" + +#: f.file.cc:1388 +msgid "filespec too long:" +msgstr "bestandsnaam te lang:" + +#: f.file.cc:1399 +msgid "Rename failed:" +msgstr "Hernoemen mislukt:" + +#: f.file.cc:1660 fotoxx.h:729 +msgid "Add" +msgstr "Toevoegen" + +#: f.file.cc:1660 fotoxx.h:781 +msgid "Remove" +msgstr "Verwijderen" + +#: f.file.cc:1662 +msgid "menu name" +msgstr "" + +#: f.file.cc:1733 f.file.cc:1754 +msgid "Restart Fotoxx to update plugin menu" +msgstr "Herstart Fotoxx om plugin menu aan te passen" + +#: f.info.cc:70 +msgid "Edit Caption and Comments" +msgstr "" + +#: f.info.cc:156 fotoxx-12.01.cc:225 +msgid "Edit Tags" +msgstr "Tags aanpassen" + +#: f.info.cc:163 +msgid "image date (yyyymmdd)" +msgstr "datum (jjjjmmdd)" + +#: f.info.cc:165 +msgid "use last" +msgstr "laatste gebruiken" + +#: f.info.cc:168 +msgid "image stars" +msgstr "afbeelding sterren" + +#: f.info.cc:186 +msgid "current tags" +msgstr "huidige tags" + +#: f.info.cc:191 +msgid "recent tags" +msgstr "recente tags" + +#: f.info.cc:196 f.info.cc:358 f.info.cc:1368 f.info.cc:2384 +msgid "defined tags" +msgstr "gedefineerde tags" + +#: f.info.cc:345 fotoxx-12.01.cc:226 +msgid "Manage Tags" +msgstr "Tags beheren" + +#: f.info.cc:348 +msgid "category" +msgstr "categorie" + +#: f.info.cc:351 +msgid "tag" +msgstr "tag" + +#: f.info.cc:354 +msgid "create" +msgstr "maken" + +#: f.info.cc:355 f.navi.cc:1421 +msgid "delete" +msgstr "verwijder" + +#: f.info.cc:1235 f.info.cc:1319 +#, c-format +msgid "search index file error: %s" +msgstr "zoekindex bestandsfout: %s" + +#: f.info.cc:1351 fotoxx-12.01.cc:227 +msgid "Batch Add Tags" +msgstr "Batchgewijs tags toevoegen" + +#: f.info.cc:1354 +msgid "tags to add" +msgstr "tags om toe te voegen" + +#: f.info.cc:1359 +msgid "create tag" +msgstr "tag maken" + +#: f.info.cc:1415 f.info.cc:1608 +#, c-format +msgid "" +"%s \n" +" too many tags" +msgstr "" +"%s \n" +" te veel tags" + +#: f.info.cc:1553 fotoxx-12.01.cc:228 +msgid "Batch Delete Tag" +msgstr "Batchgewijs tags verwijderen" + +#: f.info.cc:1556 +msgid "tag to remove" +msgstr "tag om te verwijderen" + +#: f.info.cc:1560 +msgid "optional replacement" +msgstr "optionele herplaatsing" + +#: f.info.cc:1565 f.tools.cc:2943 +msgid "0 files selected" +msgstr "" + +#: f.info.cc:1568 +msgid "search all files" +msgstr "doorzoek alle bestanden" + +#: f.info.cc:1653 +msgid "no files selected" +msgstr "geen bestanden geselecteerd" + +#: f.info.cc:1659 +msgid "no tag specified" +msgstr "geen tag gespecificeerd" + +#: f.info.cc:1683 f.info.cc:1712 +msgid "specify tag" +msgstr "specificeer tag" + +#: f.info.cc:1821 +msgid "View Info" +msgstr "Tonen info" + +#: f.info.cc:1889 fotoxx-12.01.cc:231 +msgid "Edit Info" +msgstr "Info aanpassen" + +#: f.info.cc:1987 fotoxx-12.01.cc:232 +msgid "Delete Info" +msgstr "Info verwijderen" + +#: f.info.cc:1989 fotoxx.h:731 +msgid "All" +msgstr "Alles" + +#: f.info.cc:1990 +msgid "One Key:" +msgstr "Sleutel:" + +#: f.info.cc:2343 +msgid "Search Tags, Comments, File Names" +msgstr "Tags, commentaar, bestanden doorzoeken" + +#: f.info.cc:2350 +msgid "date range" +msgstr "datum van/tot" + +#: f.info.cc:2351 +msgid "stars range" +msgstr "sterren van/tot" + +#: f.info.cc:2352 +msgid "search tags" +msgstr "doorzoeken tags" + +#: f.info.cc:2353 +msgid "search text" +msgstr "doorzoeken tekst" + +#: f.info.cc:2354 +msgid "file names" +msgstr "bestandsnamen" + +#: f.info.cc:2359 +msgid "(yyyymmdd)" +msgstr "" + +#: f.info.cc:2365 +msgid "all/any" +msgstr "" + +#: f.info.cc:2702 +msgid "No matching images found" +msgstr "Geen overeenkomende afbeeldingen gevonden" + +#: f.info.cc:2706 f.info.cc:3059 +msgid "No search index file present" +msgstr "Zoekindex bestand niet aanwezig" + +#: f.info.cc:2777 +msgid "Additional Items for Report" +msgstr "" + +#: f.navi.cc:188 f.navi.cc:576 f.navi.cc:706 f.navi.cc:707 f.navi.cc:709 +msgid "bigger" +msgstr "groter" + +#: f.navi.cc:188 +msgid "increase thumbnail size" +msgstr "vergroten miniaturen" + +#: f.navi.cc:189 +msgid "reduce thumbnail size" +msgstr "verkleinen miniaturen" + +#: f.navi.cc:189 f.navi.cc:586 f.navi.cc:708 f.navi.cc:710 +msgid "smaller" +msgstr "kleiner" + +#: f.navi.cc:190 f.navi.cc:600 +msgid "parent" +msgstr "moeder" + +#: f.navi.cc:190 +msgid "parent directory" +msgstr "bovenliggende map" + +#: f.navi.cc:191 f.navi.cc:625 f.navi.cc:717 +msgid "first page" +msgstr "eerste pagina" + +#: f.navi.cc:191 +msgid "jump to first file" +msgstr "spring naar eerste bestand" + +#: f.navi.cc:192 f.navi.cc:623 f.navi.cc:712 f.navi.cc:719 +msgid "prev page" +msgstr "vorige pagina" + +#: f.navi.cc:192 +msgid "previous page" +msgstr "vorige pagina" + +#: f.navi.cc:193 f.navi.cc:621 f.navi.cc:714 +msgid "prev row" +msgstr "vorige rij" + +#: f.navi.cc:193 +msgid "previous row" +msgstr "vorige rij" + +#: f.navi.cc:194 f.navi.cc:622 f.navi.cc:715 +msgid "next row" +msgstr "volgende rij" + +#: f.navi.cc:195 f.navi.cc:624 f.navi.cc:713 f.navi.cc:720 +msgid "next page" +msgstr "volgende pagina" + +#: f.navi.cc:195 +msgid "ttip::next page" +msgstr "" + +#: f.navi.cc:196 +msgid "jump to last file" +msgstr "spring naar laatste bestand" + +#: f.navi.cc:196 f.navi.cc:626 f.navi.cc:718 +msgid "last page" +msgstr "laatste pagina" + +#: f.navi.cc:197 f.navi.cc:571 +msgid "close" +msgstr "sluiten" + +#: f.navi.cc:197 +msgid "close image gallery" +msgstr "sluiten afbeeldingsgalerie" + +#: f.navi.cc:1413 fotoxx.h:787 +msgid "Select Files" +msgstr "Selecteer bestanden" + +#: f.navi.cc:1413 zfuncs.cc:6296 zfuncs.cc:6332 zfuncs.cc:6485 zfuncs.cc:6728 +#: zfuncs.cc:7427 zfuncs.cc:7433 zfuncs.cc:7439 zfuncs.cc:7445 +msgid "cancel" +msgstr "Annuleren" + +#: f.navi.cc:1413 zfuncs.cc:6728 +msgid "done" +msgstr "klaar" + +#: f.navi.cc:1422 +msgid "insert" +msgstr "invoegen" + +#: f.navi.cc:1423 +msgid "add all" +msgstr "alles toevoegen" + +#: f.retouch.cc:55 +msgid "Adjust Brightness and Color" +msgstr "Instellen helderheid en kleur" + +#: f.retouch.cc:110 +msgid "small-steps" +msgstr "" + +#: f.retouch.cc:119 +msgid "color saturation" +msgstr "kleurverzadiging" + +#: f.retouch.cc:126 +msgid " reset 1 " +msgstr " herstel 1" + +#: f.retouch.cc:127 +msgid "reset all" +msgstr "alles terugzetten" + +#: f.retouch.cc:599 +msgid "adjust image gamma" +msgstr "" + +#: f.retouch.cc:885 +msgid "Expand Brightness Range" +msgstr "Helderheidsbereik vergroten" + +#: f.retouch.cc:887 +msgid "bright pixels" +msgstr "lichte pixels" + +#: f.retouch.cc:1058 +msgid "Flatten Brightness Distribution" +msgstr "Helderheidsverdeling afvlakken" + +#: f.retouch.cc:1072 +msgid "Flatten" +msgstr "afvlakken" + +#: f.retouch.cc:1334 +msgid "Ramp brightness across image" +msgstr "Helderheidsverspreiding horizontaal/verticaal" + +#: f.retouch.cc:1730 fotoxx-12.01.cc:272 +msgid "Tone Mapping" +msgstr "Tone mapping instellen" + +#: f.retouch.cc:1758 +msgid "low" +msgstr "" + +#: f.retouch.cc:1760 +msgid "high" +msgstr "" + +#: f.retouch.cc:1763 +msgid "Amplify" +msgstr "Versterken" + +#: f.retouch.cc:2069 +msgid "Adjust White Balance" +msgstr "Instellen witbalans" + +#: f.retouch.cc:2070 +msgid "Click white or gray image location" +msgstr "Klik op een witte of grijze locatie in de afbeelding" + +#: f.retouch.cc:2278 +msgid "Color Match Images" +msgstr "" + +#: f.retouch.cc:2307 +msgid "mouse radius for color sample" +msgstr "" + +#: f.retouch.cc:2309 f.retouch.cc:2314 fotoxx-12.01.cc:246 fotoxx-12.01.cc:325 +#: fotoxx.h:769 +msgid "Open" +msgstr "Openen" + +#: f.retouch.cc:2310 +msgid "image for source color" +msgstr "" + +#: f.retouch.cc:2312 +msgid "click on image to get source color" +msgstr "" + +#: f.retouch.cc:2315 +msgid "image to set matching color" +msgstr "" + +#: f.retouch.cc:2317 +msgid "click on image to set matching color" +msgstr "" + +#: f.retouch.cc:2372 +msgid "select source image color first" +msgstr "" + +#: f.retouch.cc:2584 +msgid "Add standard bias" +msgstr "" + +#: f.retouch.cc:2591 +msgid "+Brightness -Density" +msgstr "" + +#: f.retouch.cc:2592 +msgid "+Red -Cyan" +msgstr "" + +#: f.retouch.cc:2593 +msgid "+Green -Magenta" +msgstr "" + +#: f.retouch.cc:2594 +msgid "+Blue -Yellow" +msgstr "" + +#: f.retouch.cc:2599 +msgid "Contrast" +msgstr "" + +#: f.retouch.cc:2600 fotoxx.h:778 +msgid "Red" +msgstr "rood" + +#: f.retouch.cc:2601 fotoxx.h:758 +msgid "Green" +msgstr "groen" + +#: f.retouch.cc:2602 fotoxx.h:736 +msgid "Blue" +msgstr "blauw" + +#: f.retouch.cc:2730 +msgid "Load DRGB parameters" +msgstr "" + +#: f.retouch.cc:2732 f.retouch.cc:2804 f.retouch.cc:6102 f.retouch.cc:6198 +msgid "File:" +msgstr "" + +#: f.retouch.cc:2751 f.retouch.cc:2824 +msgid "DRGB parameters file" +msgstr "" + +#: f.retouch.cc:2769 f.retouch.cc:6142 +msgid "file not found" +msgstr "" + +#: f.retouch.cc:2802 +msgid "Save DRGB parameters" +msgstr "" + +#: f.retouch.cc:3034 f.tools.cc:2404 +msgid "Click image to select pixels." +msgstr "" + +#: f.retouch.cc:3072 fotoxx-12.01.cc:276 +msgid "Revise RGB" +msgstr "" + +#: f.retouch.cc:3084 +msgid "Metric:" +msgstr "" + +#: f.retouch.cc:3139 +msgid "Blend" +msgstr "" + +#: f.retouch.cc:3519 +msgid "" +"Method 1:\n" +" Left-click on red-eye to darken.\n" +"Method 2:\n" +" Drag down and right to enclose red-eye.\n" +" Left-click on red-eye to darken.\n" +"Undo red-eye:\n" +" Right-click on red-eye." +msgstr "" +"Methode 1:\n" +" Linkerklik in het rode oog om te corrigeren.\n" +"Methode 2:\n" +" Sleep met de muis naar rechts om het rode oog te markeren.\n" +" Linkerklik in het rode oog om te corrigeren.\n" +"Ongedaan maken:\n" +" Rechterklik in het rode oog." + +#: f.retouch.cc:3534 +msgid "Red Eye Reduction" +msgstr "Rode ogen correctie" + +#: f.retouch.cc:3968 +msgid "Set Blur Radius" +msgstr "Instellen straal om te vervagen" + +#: f.retouch.cc:4195 fotoxx-12.01.cc:279 +msgid "Sharpen Image" +msgstr "Afbeelding verscherpen" + +#: f.retouch.cc:4202 +msgid "edge detection" +msgstr "rand herkenning" + +#: f.retouch.cc:4203 +msgid "cycles" +msgstr "cycli" + +#: f.retouch.cc:4204 +msgid "reduce" +msgstr "verminderen" + +#: f.retouch.cc:4215 +msgid "unsharp mask" +msgstr "unsharp masking" + +#: f.retouch.cc:4228 +msgid "brightness gradient" +msgstr "helderheids gradient" + +#: f.retouch.cc:4634 +msgid "" +" Press the reduce button to \n" +" reduce noise in small steps. \n" +" Use undo to start over." +msgstr "" +" Druk [verminderen] om ruis in \n" +" kleine stappen te verminderen. \n" +" Druk [Annuleren] om ongedaan te maken." + +#: f.retouch.cc:4645 +msgid "Noise Reduction" +msgstr "Ruis vermindering" + +#: f.retouch.cc:4650 +msgid "algorithm" +msgstr "algoritme" + +#: f.retouch.cc:4657 +msgid "flatten outliers by color (1)" +msgstr "afzonderlijk deel afvlakken met kleur (1)" + +#: f.retouch.cc:4658 +msgid "flatten outliers by color (2)" +msgstr "afzonderlijk deel afvlakken met kleur (2)" + +#: f.retouch.cc:4659 +msgid "set median brightness by color" +msgstr "instellen mediane helderheid per kleur" + +#: f.retouch.cc:4660 f.retouch.cc:4661 +msgid "top hat filter by color" +msgstr "tophat filter voor kleur" + +#: f.retouch.cc:4976 +msgid "" +"1. Drag mouse to select. \n" +"2. Erase. 3. Repeat. " +msgstr "" +"1. Sleep met de muis om uitsnede te definieren. \n" +"2. Druk [verwijderen]. \n" +"3. Herhaal met nieuwe uitsnede. " + +#: f.retouch.cc:4998 fotoxx-12.01.cc:281 +msgid "Smart Erase" +msgstr "Slim verwijderen" + +#: f.retouch.cc:5003 fotoxx.h:776 +msgid "Radius" +msgstr "straal" + +#: f.retouch.cc:5005 +msgid "Blur" +msgstr "Vervagen" + +#: f.retouch.cc:5008 +msgid "New Area" +msgstr "Nieuwe uitsnede" + +#: f.retouch.cc:5379 fotoxx-12.01.cc:282 +msgid "Remove Dust" +msgstr "Stofspikkels verwijderen" + +#: f.retouch.cc:5383 +msgid "spot size limit" +msgstr "stip grootte limiet" + +#: f.retouch.cc:5386 +msgid "max. brightness" +msgstr "max. helderheid" + +#: f.retouch.cc:5389 +msgid "min. contrast" +msgstr "min. contrast" + +#: f.retouch.cc:5983 fotoxx-12.01.cc:283 +msgid "Fix Stuck Pixels" +msgstr "" + +#: f.retouch.cc:5989 +msgid "pixel group" +msgstr "" + +#: f.retouch.cc:5990 +msgid "circle color" +msgstr "" + +#: f.retouch.cc:6100 +msgid "Load Stuck Pixels" +msgstr "" + +#: f.retouch.cc:6124 f.retouch.cc:6220 +msgid "Stuck Pixels file" +msgstr "" + +#: f.retouch.cc:6164 +msgid "file format error" +msgstr "" + +#: f.retouch.cc:6192 +msgid "there are zero stuck pixels" +msgstr "" + +#: f.retouch.cc:6196 +msgid "Save Stuck Pixels" +msgstr "" + +#: f.retouch.cc:6686 +#, c-format +msgid "Undo Memory %d%c" +msgstr "Geheugen voor ongedaan maken %d%c" + +#: f.retouch.cc:6688 fotoxx-12.01.cc:284 +msgid "Edit Pixels" +msgstr "Verven met penseel" + +#: f.retouch.cc:6695 +msgid "pick" +msgstr "kiezen" + +#: f.retouch.cc:6697 +msgid "erase" +msgstr "verwijderen" + +#: f.retouch.cc:6705 +msgid "paintbrush radius" +msgstr "straal penseelcirkel" + +#: f.retouch.cc:6706 +msgid "transparency center" +msgstr "doorzichtigheid midden" + +#: f.retouch.cc:6707 +msgid "transparency edge" +msgstr "doorzichtigheid rand" + +#: f.retouch.cc:6972 +msgid "" +"Undo memory limit has been reached. \n" +"Save work with [done], then resume editing." +msgstr "" +"Ongedaan maken geheugen limiet bereikt. \n" +"Bewerkingen opslaan met [Klaar], daarna doorgaan." + +#: f.select.cc:54 f.select.cc:2461 +msgid "Select Area for Edits" +msgstr "Selecteer uitsnede om te bewerken" + +#: f.select.cc:55 f.select.cc:2462 +msgid "Press F1 for help" +msgstr "Druk F1 voor help" + +#: f.select.cc:64 +msgid "" +"Select Area not supported \n" +"by this edit function" +msgstr "" + +#: f.select.cc:103 f.tools.cc:901 +msgid "rectangle" +msgstr "rechthoek" + +#: f.select.cc:104 f.tools.cc:902 +msgid "ellipse" +msgstr "ellips" + +#: f.select.cc:110 +msgid "draw: freehand" +msgstr "teken: met de vrije hand" + +#: f.select.cc:111 +msgid "draw: follow edge" +msgstr "teken: volg rand" + +#: f.select.cc:114 +msgid "select by mouse" +msgstr "selecteer met muis" + +#: f.select.cc:116 f.select.cc:2496 +msgid "mouse radius" +msgstr "muis straal" + +#: f.select.cc:120 +msgid "match mouse color" +msgstr "" + +#: f.select.cc:124 +msgid "search range" +msgstr "" + +#: f.select.cc:126 +msgid "firewall" +msgstr "firewall" + +#: f.select.cc:326 f.select.cc:467 +#, c-format +msgid "exceed %d edits" +msgstr "%d bewerkingen overschreden" + +#: f.select.cc:1021 +msgid "" +"Click one time inside each enclosed area \n" +"(possible gaps in the outline will be found). \n" +"Press F1 for help." +msgstr "" +"Klik eenmalig in elke uitsnede \n" +"(mogelijke gaten in de contouren worden gevonden). \n" +"Druk F1 voor help." + +#: f.select.cc:1078 +msgid "finish area" +msgstr "gereedmaken uitsnede" + +#: f.select.cc:1113 +msgid "searching" +msgstr "bezig met zoeken" + +#: f.select.cc:1185 +msgid "outline has a gap" +msgstr "contour heeft een gat" + +#: f.select.cc:1189 +msgid "success" +msgstr "succes" + +#: f.select.cc:1440 f.select.cc:1470 +msgid "the area is not finished" +msgstr "de uitsnede is niet gereed" + +#: f.select.cc:1563 +msgid "Edge calculation in progress" +msgstr "Berekening rand bezig" + +#: f.select.cc:1572 +msgid "Area Edge Calc" +msgstr "Randberekening van uitsnede" + +#: f.select.cc:1863 +msgid "position with mouse click/drag" +msgstr "positioneer met muis klik/sleep" + +#: f.select.cc:1887 +msgid "Paste Image" +msgstr "Afbeelding plakken" + +#: f.select.cc:1901 +msgid "angle" +msgstr "hoek" + +#: f.select.cc:2160 +msgid "load select area from a file" +msgstr "uitsnede-bestand laden" + +#: f.select.cc:2194 +msgid "cannot open .tiff and .info files" +msgstr "kan .tiff of .info bestanden niet openen" + +#: f.select.cc:2213 +msgid "save select area to a file" +msgstr "bewaar geselecteerde uitsnede in een bestand" + +#: f.select.cc:2248 fotoxx-12.01.cc:248 +msgid "Select Whole Image" +msgstr "Gehele afbeelding selecteren" + +#: f.select.cc:2249 +msgid "Edit Function Amplifier" +msgstr "Versterker functie wijzigen" + +#: f.select.cc:2463 +msgid "Edit function must be active" +msgstr "" + +#: f.select.cc:2499 +msgid "power: center" +msgstr "" + +#: f.select.cc:2501 +msgid "edge" +msgstr "rand" + +#: f.select.cc:2504 +msgid "reset area" +msgstr "reset uitsnede" + +#: f.tools.cc:42 +msgid "" +"When editing a collection, right-click \n" +"an image or thumbnail to add or remove." +msgstr "" + +#: f.tools.cc:70 fotoxx-12.01.cc:204 +msgid "Manage Collections" +msgstr "" + +#: f.tools.cc:85 +msgid "Start new collection" +msgstr "" + +#: f.tools.cc:87 +msgid "Edit a collection" +msgstr "" + +#: f.tools.cc:89 +msgid "View a collection" +msgstr "" + +#: f.tools.cc:91 +msgid "Delete a collection" +msgstr "" + +#: f.tools.cc:95 +msgid "Editing:" +msgstr "" + +#: f.tools.cc:99 +msgid "Action:" +msgstr "" + +#: f.tools.cc:133 +msgid "New Collection" +msgstr "" + +#: f.tools.cc:156 +msgid "Edit Collection" +msgstr "Verzameling aanpassen" + +#: f.tools.cc:172 +msgid "View Collection" +msgstr "" + +#: f.tools.cc:193 +msgid "Delete Collection" +msgstr "Verzameling verwijderen" + +#: f.tools.cc:196 +#, c-format +msgid "delete %s ?" +msgstr "" + +#: f.tools.cc:223 +#, c-format +msgid "add image to collection: %s" +msgstr "" + +#: f.tools.cc:225 f.tools.cc:270 +msgid "remove image from collection" +msgstr "" + +#: f.tools.cc:226 f.tools.cc:271 f.tools.cc:298 +msgid "remove and save image" +msgstr "" + +#: f.tools.cc:227 f.tools.cc:316 +msgid "insert saved images here" +msgstr "" + +#: f.tools.cc:256 +msgid "add image to collection" +msgstr "" + +#: f.tools.cc:301 +msgid "too many saved files" +msgstr "" + +#: f.tools.cc:373 fotoxx-12.01.cc:205 +msgid "Move Collections" +msgstr "" + +#: f.tools.cc:375 +msgid "old top directory" +msgstr "" + +#: f.tools.cc:378 +msgid "new top directory" +msgstr "" + +#: f.tools.cc:434 +msgid "completed" +msgstr "Klaar" + +#: f.tools.cc:467 +msgid "Batch Convert/Resize/Export" +msgstr "" + +#: f.tools.cc:474 +msgid "new max. width" +msgstr "nieuwe max. breedte" + +#: f.tools.cc:481 +msgid "new file type" +msgstr "" + +#: f.tools.cc:482 +msgid "same" +msgstr "" + +#: f.tools.cc:490 +msgid "replace originals" +msgstr "vervangen originelen" + +#: f.tools.cc:491 +msgid "export to location" +msgstr "exporteer naar locatie" + +#: f.tools.cc:492 +msgid "remove EXIF" +msgstr "" + +#: f.tools.cc:549 +msgid "Select directory" +msgstr "Selecteer map" + +#: f.tools.cc:583 +#, c-format +msgid "replace original files? (max. %d x %d)" +msgstr "vervangen originele bestanden? (max. %d x %d)" + +#: f.tools.cc:590 +#, c-format +msgid "" +"copy files? (max. %d x %d) \n" +" to location %s" +msgstr "" +"copieer bestanden? (max. %d x %d) \n" +" naar locatie %s" + +#: f.tools.cc:601 +msgid "location is not a valid directory" +msgstr "locatie is niet een geldige map" + +#: f.tools.cc:608 f.tools.cc:3007 +#, c-format +msgid "max. size %d x %d is not reasonable" +msgstr "max. grootte %d x %d is niet logisch" + +#: f.tools.cc:654 +msgid "*** file already exists" +msgstr "" + +#: f.tools.cc:662 +msgid "*** file type not supported" +msgstr "" + +#: f.tools.cc:741 +msgid "Program ufraw-batch is required" +msgstr "Programma ufraw-batch is vereist" + +#: f.tools.cc:751 fotoxx.h:770 +msgid "Open RAW File" +msgstr "Open RAW bestand" + +#: f.tools.cc:764 +msgid "Select RAW files to convert" +msgstr "Selecteer RAW bestanden om te converteren" + +#: f.tools.cc:769 +msgid "Choose file type" +msgstr "" + +#: f.tools.cc:888 +msgid "Press ESC to exit slide show" +msgstr "Druk ESC om diashow te stoppen" + +#: f.tools.cc:889 +msgid "show only latest file versions" +msgstr "" + +#: f.tools.cc:893 +msgid "arrow keys" +msgstr "pijltjes toetsen" + +#: f.tools.cc:894 +msgid "instant" +msgstr "" + +#: f.tools.cc:895 +msgid "fade-in" +msgstr "fade-in" + +#: f.tools.cc:896 +msgid "roll-right" +msgstr "" + +#: f.tools.cc:897 +msgid "roll-down" +msgstr "" + +#: f.tools.cc:898 +msgid "shift-left" +msgstr "schuif-links" + +#: f.tools.cc:899 +msgid "venetian" +msgstr "venetiaan" + +#: f.tools.cc:900 +msgid "grate" +msgstr "tralie" + +#: f.tools.cc:903 +msgid "radar" +msgstr "" + +#: f.tools.cc:904 +msgid "jaws" +msgstr "" + +#: f.tools.cc:911 fotoxx-12.01.cc:208 +msgid "Slide Show" +msgstr "Diashow starten" + +#: f.tools.cc:915 +msgid "seconds" +msgstr "seconden" + +#: f.tools.cc:919 +msgid "music file" +msgstr "muziek bestand" + +#: f.tools.cc:923 +msgid "transitions" +msgstr "" + +#: f.tools.cc:1040 +msgid "Select music file or playlist" +msgstr "Selecteer muziekbestand of speellijst" + +#: f.tools.cc:1727 +msgid "Sync Files is already running" +msgstr "" + +#: f.tools.cc:1778 +msgid "" +"Run Tools > Synchronize Files so that gallery windows \n" +"will be fast and Search Images will work correctly. \n" +"You can view (not edit) images while synchronize runs." +msgstr "" + +#: f.tools.cc:1812 +msgid "no top image directory is defined" +msgstr "" + +#: f.tools.cc:1818 +msgid "top image directory is invalid" +msgstr "" + +#: f.tools.cc:1823 +msgid "no search index file is present" +msgstr "" + +#: f.tools.cc:1837 +msgid "new/modified files are present" +msgstr "" + +#: f.tools.cc:1844 +msgid "no new files found" +msgstr "" + +#: f.tools.cc:1859 fotoxx-12.01.cc:209 +msgid "Synchronize Files" +msgstr "Synchroniseren bestanden" + +#: f.tools.cc:1861 +msgid "Top Image Directory:" +msgstr "Bovenliggende afbeeldingsmap" + +#: f.tools.cc:1883 +msgid "" +"file sync is necessary.\n" +"cancel anyway?" +msgstr "" + +#: f.tools.cc:1896 +msgid "top directory is invalid" +msgstr "" + +#: f.tools.cc:2292 +msgid "Select top image directory" +msgstr "Selecteer bovenliggende afbeeldingsmap" + +#: f.tools.cc:2429 fotoxx-12.01.cc:210 +msgid "Show RGB" +msgstr "RGB waarden tonen" + +#: f.tools.cc:2719 fotoxx-12.01.cc:211 +msgid "Grid Lines" +msgstr "Raster instellen" + +#: f.tools.cc:2728 +msgid "x-spacing" +msgstr "" + +#: f.tools.cc:2729 +msgid "x-count" +msgstr "" + +#: f.tools.cc:2730 +msgid "x-enable" +msgstr "" + +#: f.tools.cc:2736 +msgid "y-spacing" +msgstr "" + +#: f.tools.cc:2737 +msgid "y-count" +msgstr "" + +#: f.tools.cc:2738 +msgid "y-enable" +msgstr "" + +#: f.tools.cc:2745 +msgid "x-offset" +msgstr "" + +#: f.tools.cc:2749 +msgid "y-offset" +msgstr "" + +#: f.tools.cc:2940 fotoxx-12.01.cc:213 +msgid "E-mail Images" +msgstr "E-mail afbeeldingen maken" + +#: f.tools.cc:2947 +msgid "max. width" +msgstr "max. breedte" + +#: f.tools.cc:2948 +msgid "max. height" +msgstr "max. hoogte" + +#: f.tools.cc:3093 +msgid "too many files" +msgstr "te veel bestanden" + +#: f.tools.cc:3134 +msgid "" +"Brightness should show a gradual ramp \n" +"extending all the way to the edges." +msgstr "" +"Helderheid moet een geleidelijke verandering laten \n" +"zien, zich geheel uitstrekkend naar de randen." + +#: f.tools.cc:3174 +msgid "Monitor Check" +msgstr "Monitorkleuren controleren" + +#: f.tools.cc:3232 fotoxx-12.01.cc:215 +msgid "Monitor Gamma" +msgstr "Gammawaarde monitor" + +#: f.tools.cc:3294 fotoxx-12.01.cc:216 +msgid "Brightness Distribution" +msgstr "Helderheidshistogram" + +#: f.tools.cc:3432 +msgid "Available Translations" +msgstr "Beschikbare vertalingen" + +#: f.tools.cc:3436 +msgid "Set Language" +msgstr "Instellen taal" + +#: f.tools.cc:3502 +msgid "Make Launcher" +msgstr "" + +#: f.tools.cc:3540 +msgid "Settings" +msgstr "" + +#: f.tools.cc:3545 +msgid "Startup Display" +msgstr "" + +#: f.tools.cc:3547 +msgid "Recent Files Gallery" +msgstr "" + +#: f.tools.cc:3548 +msgid "Previous Image Viewed" +msgstr "" + +#: f.tools.cc:3549 +msgid "Blank Window" +msgstr "" + +#: f.tools.cc:3551 +msgid "Directory Gallery" +msgstr "" + +#: f.tools.cc:3556 +msgid "Image File" +msgstr "" + +#: f.tools.cc:3562 +msgid "Toolbar Style" +msgstr "Toolbar stijl" + +#: f.tools.cc:3563 f.transform.cc:1300 +msgid "Text" +msgstr "Tekst" + +#: f.tools.cc:3564 +msgid "Icons" +msgstr "" + +#: f.tools.cc:3565 +msgid "Both" +msgstr "" + +#: f.tools.cc:3568 +msgid "Warn Overwrite" +msgstr "" + +#: f.tools.cc:3639 +msgid "startup directory is invalid" +msgstr "" + +#: f.tools.cc:3650 +msgid "startup file is invalid" +msgstr "" + +#: f.tools.cc:3707 +msgid "Select startup directory" +msgstr "" + +#: f.tools.cc:3715 +msgid "Select startup image file" +msgstr "" + +#: f.transform.cc:50 +msgid "Use buttons or drag right edge with mouse" +msgstr "gebruik knoppen of sleep rechter rand met de muis" + +#: f.transform.cc:60 fotoxx-12.01.cc:252 +msgid "Rotate Image" +msgstr "Afbeelding draaien" + +#: f.transform.cc:64 +msgid "degrees" +msgstr "graden" + +#: f.transform.cc:80 f.transform.cc:124 +msgid "Trim" +msgstr "Bijsnijden" + +#: f.transform.cc:81 f.transform.cc:2289 f.transform.cc:3120 +#: f.transform.cc:3383 f.transform.cc:3644 +msgid "Grid" +msgstr "" + +#: f.transform.cc:123 +msgid "Undo Trim" +msgstr "Ongedaan maken bijsnijden" + +#: f.transform.cc:139 +#, c-format +msgid "degrees: %.1f" +msgstr "graden: %.1f" + +#: f.transform.cc:286 +msgid "gold" +msgstr "" + +#: f.transform.cc:334 +msgid "Drag middle to move, drag corners to resize." +msgstr "Sleep het midden om te verplaatsen, sleep hoeken om te vergroten." + +#: f.transform.cc:348 fotoxx-12.01.cc:253 +msgid "Trim Image" +msgstr "Afbeelding bijsnijden" + +#: f.transform.cc:348 +msgid "customize" +msgstr "Aanpassen" + +#: f.transform.cc:359 +msgid "ratio" +msgstr "" + +#: f.transform.cc:363 +msgid "Lock Ratio" +msgstr "verhoudingen behouden" + +#: f.transform.cc:368 +msgid "invert" +msgstr "omkeren" + +#: f.transform.cc:890 +msgid "Trim Buttons" +msgstr "Bijsnijd knoppen" + +#: f.transform.cc:1064 +msgid "Lock aspect ratio" +msgstr "lengte:breedte verhouding behouden" + +#: f.transform.cc:1072 fotoxx-12.01.cc:255 +msgid "Resize Image" +msgstr "Afbeeldingsgrootte wijzigen" + +#: f.transform.cc:1095 fotoxx-12.01.cc:326 +msgid "Prev" +msgstr "Voorgaande" + +#: f.transform.cc:1245 +msgid "" +"Enter text, click/drag on image.\n" +"Right click to remove" +msgstr "" +"Invoeren tekst, klik/sleep op afbeelding.\n" +"Rechter klik om te verwijderen" + +#: f.transform.cc:1294 fotoxx-12.01.cc:256 +msgid "Annotate Image" +msgstr "Annotatie bij afbeelding" + +#: f.transform.cc:1307 +msgid "Size" +msgstr "Grootte" + +#: f.transform.cc:1310 +msgid "Angle" +msgstr "Hoek" + +#: f.transform.cc:1321 fotoxx.h:741 +msgid "Color" +msgstr "Kleur" + +#: f.transform.cc:1322 +msgid "Transparency" +msgstr "Doorzichtigheid" + +#: f.transform.cc:1325 +msgid "text" +msgstr "tekst" + +#: f.transform.cc:1330 +msgid "backing" +msgstr "" + +#: f.transform.cc:1333 +msgid "" +"Outline\n" +" Width" +msgstr "" +"Contour\n" +" Breedte" + +#: f.transform.cc:1335 +msgid "outline" +msgstr "" + +#: f.transform.cc:1342 +msgid "Annotation File:" +msgstr "Annotatie bestand:" + +#: f.transform.cc:1416 +msgid "select font" +msgstr "selecteer font" + +#: f.transform.cc:2045 fotoxx-12.01.cc:257 +msgid "Flip Image" +msgstr "Afbeelding spiegelen" + +#: f.transform.cc:2049 f.transform.cc:2281 +msgid "horizontal" +msgstr "horizontaal" + +#: f.transform.cc:2050 f.transform.cc:2280 +msgid "vertical" +msgstr "verticaal" + +#: f.transform.cc:2155 fotoxx-12.01.cc:258 +msgid "Make Negative" +msgstr "Maak negatief" + +#: f.transform.cc:2158 +msgid "black/white positive" +msgstr "" + +#: f.transform.cc:2159 +msgid "black/white negative" +msgstr "" + +#: f.transform.cc:2160 +msgid "color positive" +msgstr "" + +#: f.transform.cc:2161 +msgid "color negative" +msgstr "" + +#: f.transform.cc:2272 fotoxx-12.01.cc:259 +msgid "Unbend Image" +msgstr "Afbeelding ontkrommen" + +#: f.transform.cc:2282 +msgid "linear" +msgstr "lineair" + +#: f.transform.cc:2285 +msgid "curved" +msgstr "gebogen" + +#: f.transform.cc:2544 +msgid "" +" Click the four corners of a tetragon area. Press [apply]. \n" +" The image is warped to make the tetragon into a rectangle." +msgstr "" + +#: f.transform.cc:2556 fotoxx-12.01.cc:260 +msgid "Keystone Correction" +msgstr "" + +#: f.transform.cc:2724 +msgid "must have 4 corners" +msgstr "" + +#: f.transform.cc:2847 +msgid "" +" Select an area to warp using select area function. \n" +" Press [start warp] and pull area with mouse. \n" +" Make multiple mouse pulls until satisfied. \n" +" When finished, select another area or press [done]." +msgstr "" +" Selecteer een uitsnede met menu-functie [Uitsnede selecteren]. \n" +" Druk [start kromtrekken] en sleep uitsnede met de muis. \n" +" Herhalen tot het gewenste resultaat. \n" +" Indien gereed, een andere uitsnede selecteren of druk [Klaar]." + +#: f.transform.cc:2859 fotoxx-12.01.cc:261 +msgid "Warp Image (area)" +msgstr "Afbeelding kromtrekken (uitsnede)" + +#: f.transform.cc:2864 +msgid "start warp" +msgstr "Start kromtrekken" + +#: f.transform.cc:2931 +msgid "no active Select Area" +msgstr "" + +#: f.transform.cc:3099 f.transform.cc:3362 +msgid "" +" Pull an image position using the mouse. \n" +" Make multiple mouse pulls until satisfied. \n" +" When finished, press [done]." +msgstr "" +" Sleep de plaats van een afbeelding met de muis. \n" +" Herhalen tot het gewenste resultaat. \n" +" Indien gereed, druk [Klaar]." + +#: f.transform.cc:3112 fotoxx-12.01.cc:262 +msgid "Warp Image (curved)" +msgstr "Afbeelding kromtrekken (gebogen)" + +#: f.transform.cc:3375 fotoxx-12.01.cc:263 +msgid "Warp Image (linear)" +msgstr "Afbeelding kromtrekken (lineair)" + +#: f.transform.cc:3628 +msgid "" +" Pull on an image corner using the mouse. \n" +" Make multiple mouse pulls until satisfied. \n" +" When finished, press [done]." +msgstr "" +" Sleep een hoek van de afbeelding. \n" +" Herhalen tot het gewenste resultaat. \n" +" Indien gereed, druk [Klaar]." + +#: f.transform.cc:3639 fotoxx-12.01.cc:264 +msgid "Warp Image (affine)" +msgstr "Afbeelding kromtrekken (affine)" + +#: fotoxx-12.01.cc:185 +msgid "File" +msgstr "Bestand" + +#: fotoxx-12.01.cc:186 fotoxx-12.01.cc:324 +msgid "Image Gallery" +msgstr "Afbeeldingsgalerie tonen" + +#: fotoxx-12.01.cc:187 +msgid "Clone 50/50" +msgstr "" + +#: fotoxx-12.01.cc:188 +msgid "Clone Overlay" +msgstr "" + +#: fotoxx-12.01.cc:190 +msgid "Open in New Window" +msgstr "" + +#: fotoxx-12.01.cc:191 fotoxx-12.01.cc:326 +msgid "Open Previous File" +msgstr "Open voorgaand bestand" + +#: fotoxx-12.01.cc:192 +msgid "Open Recent File" +msgstr "Onlangs geopend" + +#: fotoxx-12.01.cc:193 fotoxx-12.01.cc:334 +msgid "Save to Same File" +msgstr "Opslaan" + +#: fotoxx-12.01.cc:194 fotoxx-12.01.cc:335 +msgid "Save to New Version" +msgstr "" + +#: fotoxx-12.01.cc:195 fotoxx-12.01.cc:336 +msgid "Save to New File" +msgstr "Opslaan als ..." + +#: fotoxx-12.01.cc:197 +msgid "Trash Image File" +msgstr "Verwijderen" + +#: fotoxx-12.01.cc:199 +msgid "Batch Rename Files" +msgstr "Batchgewijs hernoemen..." + +#: fotoxx-12.01.cc:200 +msgid "Print Image File" +msgstr "Afdrukken..." + +#: fotoxx-12.01.cc:201 fotoxx-12.01.cc:340 +msgid "Quit fotoxx" +msgstr "Afsluiten" + +#: fotoxx-12.01.cc:203 +msgid "Tools" +msgstr "Gereedschap" + +#: fotoxx-12.01.cc:206 +msgid "Batch Convert" +msgstr "" + +#: fotoxx-12.01.cc:207 +msgid "Convert RAW files" +msgstr "RAW-bestanden converteren" + +#: fotoxx-12.01.cc:212 +msgid "Burn Images to CD/DVD" +msgstr "Afbeelding op CD/DVD branden" + +#: fotoxx-12.01.cc:214 +msgid "Check Monitor" +msgstr "Monitorkleuren controleren" + +#: fotoxx-12.01.cc:217 +msgid "Change Language" +msgstr "Taal veranderen" + +#: fotoxx-12.01.cc:219 +msgid "Menu and Launcher" +msgstr "" + +#: fotoxx-12.01.cc:220 +msgid "User Settings" +msgstr "" + +#: fotoxx-12.01.cc:221 +msgid "Memory Usage" +msgstr "Geheugengebruik" + +#: fotoxx-12.01.cc:224 +msgid "Edit Caption/Comments" +msgstr "" + +#: fotoxx-12.01.cc:229 +msgid "View Info (short)" +msgstr "Tonen info (kort)" + +#: fotoxx-12.01.cc:230 +msgid "View Info (long)" +msgstr "Tonen info (uitgebreid)" + +#: fotoxx-12.01.cc:233 +msgid "Search Images" +msgstr "Afbeeldingen doorzoeken" + +#: fotoxx-12.01.cc:234 +msgid "Search Metadata" +msgstr "" + +#: fotoxx-12.01.cc:236 fotoxx-12.01.cc:237 fotoxx.h:786 +msgid "Select" +msgstr "Uitsnedes selecteren" + +#: fotoxx-12.01.cc:238 fotoxx.h:788 +msgid "Show" +msgstr "Tonen" + +#: fotoxx-12.01.cc:239 fotoxx.h:761 +msgid "Hide" +msgstr "Verbergen" + +#: fotoxx-12.01.cc:240 fotoxx.h:752 +msgid "Enable" +msgstr "Uitsnede activeren" + +#: fotoxx-12.01.cc:241 fotoxx.h:748 +msgid "Disable" +msgstr "Uitsnede deactiveren" + +#: fotoxx-12.01.cc:242 fotoxx.h:763 +msgid "Invert" +msgstr "Uitsnede inverteren" + +#: fotoxx-12.01.cc:243 fotoxx.h:796 +msgid "Unselect" +msgstr "" + +#: fotoxx-12.01.cc:244 fotoxx.h:743 +msgid "Copy" +msgstr "Uitsnede copieren" + +#: fotoxx-12.01.cc:245 fotoxx.h:771 +msgid "Paste" +msgstr "Uitsnede plakken" + +#: fotoxx-12.01.cc:247 fotoxx-12.01.cc:334 fotoxx.h:783 +msgid "Save" +msgstr "Opslaan" + +#: fotoxx-12.01.cc:249 +msgid "Select and Edit" +msgstr "Selecteren en aanpassen" + +#: fotoxx-12.01.cc:251 +msgid "Transform" +msgstr "Transformeren" + +#: fotoxx-12.01.cc:254 +msgid "Auto-Trim Image" +msgstr "" + +#: fotoxx-12.01.cc:266 +msgid "Retouch" +msgstr "Retoucheren" + +#: fotoxx-12.01.cc:267 +msgid "Brightness/Color" +msgstr "Helderheid/Kleur instellen" + +#: fotoxx-12.01.cc:268 +msgid "Gamma Curves" +msgstr "" + +#: fotoxx-12.01.cc:269 +msgid "Expand Brightness" +msgstr "Helderheidsbereik vergroten" + +#: fotoxx-12.01.cc:270 +msgid "Flatten Brightness" +msgstr "Helderheidsverdeling afvlakken" + +#: fotoxx-12.01.cc:271 +msgid "Brightness Ramp" +msgstr "Helderheidsverspreiding instellen" + +#: fotoxx-12.01.cc:273 +msgid "White Balance" +msgstr "Witbalans instellen" + +#: fotoxx-12.01.cc:274 +msgid "Match Colors" +msgstr "" + +#: fotoxx-12.01.cc:277 +msgid "Red Eyes" +msgstr "Rode ogen corrigeren" + +#: fotoxx-12.01.cc:278 +msgid "Blur Image" +msgstr "Afbeelding vervagen" + +#: fotoxx-12.01.cc:280 +msgid "Reduce Noise" +msgstr "Ruis verminderen" + +#: fotoxx-12.01.cc:286 +msgid "Art" +msgstr "Creatief" + +#: fotoxx-12.01.cc:287 +msgid "Color Depth" +msgstr "Kleurdiepte instellen" + +#: fotoxx-12.01.cc:288 +msgid "Drawing" +msgstr "Tekenen" + +#: fotoxx-12.01.cc:289 +msgid "Outlines" +msgstr "Contouren" + +#: fotoxx-12.01.cc:290 +msgid "Embossing" +msgstr "Reliefdruk" + +#: fotoxx-12.01.cc:291 +msgid "Tiles" +msgstr "Tegels" + +#: fotoxx-12.01.cc:292 +msgid "Dots" +msgstr "Krantendruk" + +#: fotoxx-12.01.cc:293 +msgid "Painting" +msgstr "Verven" + +#: fotoxx-12.01.cc:295 +msgid "Combine" +msgstr "Samenvoegen" + +#: fotoxx-12.01.cc:296 +msgid "High Dynamic Range" +msgstr "Hoog dynamisch bereik (HDR)" + +#: fotoxx-12.01.cc:297 +msgid "High Depth of Field" +msgstr "Hoge scherptediepte (HDF)" + +#: fotoxx-12.01.cc:298 +msgid "Stack / Paint" +msgstr "Stapelen / Verven" + +#: fotoxx-12.01.cc:299 +msgid "Stack / Noise" +msgstr "Stapelen / Ruis verminderen" + +#: fotoxx-12.01.cc:300 +msgid "Panorama" +msgstr "Panorama maken" + +#: fotoxx-12.01.cc:301 +msgid "Vertical Panorama" +msgstr "Verticaal panorama" + +#: fotoxx-12.01.cc:304 +msgid "Edit Plugins" +msgstr "Plugins aanpassen" + +#: fotoxx-12.01.cc:313 fotoxx-12.01.cc:341 fotoxx-12.01.cc:3026 +msgid "Help" +msgstr "Help" + +#: fotoxx-12.01.cc:314 fotoxx-12.01.cc:3016 +msgid "About" +msgstr "Over fotoxx" + +#: fotoxx-12.01.cc:315 fotoxx-12.01.cc:3020 +msgid "User Guide" +msgstr "Gebruikershandleiding" + +#: fotoxx-12.01.cc:316 fotoxx-12.01.cc:3023 +msgid "User Guide Changes" +msgstr "" + +#: fotoxx-12.01.cc:317 fotoxx-12.01.cc:3032 +msgid "Edit Functions Summary" +msgstr "" + +#: fotoxx-12.01.cc:318 fotoxx-12.01.cc:3035 +msgid "Change Log" +msgstr "Veranderingslogboek" + +#: fotoxx-12.01.cc:319 fotoxx-12.01.cc:3038 +msgid "Translations" +msgstr "" + +#: fotoxx-12.01.cc:320 fotoxx-12.01.cc:3041 +msgid "Home Page" +msgstr "Homepage" + +#: fotoxx-12.01.cc:324 +msgid "Gallery" +msgstr "Galerie" + +#: fotoxx-12.01.cc:327 fotoxx.h:767 +msgid "Next" +msgstr "Volgende" + +#: fotoxx-12.01.cc:327 +msgid "Open Next File" +msgstr "Open volgend bestand" + +#: fotoxx-12.01.cc:328 +msgid "Zoom-in (bigger)" +msgstr "Zoom-in (groter)" + +#: fotoxx-12.01.cc:329 +msgid "Zoom-out (smaller)" +msgstr "Zoom-uit (kleiner)" + +#: fotoxx-12.01.cc:330 fotoxx.h:794 +msgid "Undo" +msgstr "Ongedaan maken" + +#: fotoxx-12.01.cc:330 +msgid "Undo One Edit" +msgstr "Bewerkingsstap ongedaan maken" + +#: fotoxx-12.01.cc:331 fotoxx.h:779 +msgid "Redo" +msgstr "Opnieuw" + +#: fotoxx-12.01.cc:331 +msgid "Redo One Edit" +msgstr "Bewerkingsstap opnieuw uitvoeren" + +#: fotoxx-12.01.cc:335 +msgid "Save+V" +msgstr "" + +#: fotoxx-12.01.cc:336 +msgid "Save+F" +msgstr "" + +#: fotoxx-12.01.cc:337 +msgid "Move Image to Trash" +msgstr "Afbeelding naar prullenbak" + +#: fotoxx-12.01.cc:337 +msgid "Trash" +msgstr "Opruimen" + +#: fotoxx-12.01.cc:340 +msgid "Quit" +msgstr "Afsluiten" + +#: fotoxx-12.01.cc:341 +msgid "Fotoxx Essentials" +msgstr "Fotoxx overzicht" + +#: fotoxx-12.01.cc:448 +msgid "first time startup" +msgstr "" + +#: fotoxx-12.01.cc:1944 +msgid "Exceed 50 anchor points" +msgstr "50 ankerpunten overschreden" + +#: fotoxx-12.01.cc:2129 +msgid "load curve from a file" +msgstr "laad curve vanuit bestand" + +#: fotoxx-12.01.cc:2182 +msgid "curve file is invalid" +msgstr "curve bestand is ongeldig" + +#: fotoxx-12.01.cc:2187 +msgid "curve file has different no. of curves" +msgstr "curve bestand heeft verschillend aantal curves" + +#: fotoxx-12.01.cc:2202 +msgid "save curve to a file" +msgstr "bewaar curve in een bestand" + +#: fotoxx-12.01.cc:2337 +msgid "cannot parallel edit" +msgstr "" + +#: fotoxx-12.01.cc:2347 +msgid "" +"exiftool is not installed \n" +"edited images will lose EXIF data" +msgstr "" +"EXIFtool pakket niet geinstalleerd \n" +"bewerkte afbeeldingen verliezen EXIF gegevens" + +#: fotoxx-12.01.cc:2353 +msgid "Too many edits, please save image" +msgstr "Te veel aanpassingen, graag afbeelding opslaan" + +#: fotoxx-12.01.cc:2358 +msgid "" +"Select area cannot be kept.\n" +"Continue?" +msgstr "" +"Uitsnede kan niet bewaard worden.\n" +"Doorgaan?" + +#: fotoxx-12.01.cc:2366 +msgid "" +"Select area not active.\n" +"Continue?" +msgstr "" +"Uitsnede niet actief.\n" +"Doorgaan?" + +#: fotoxx-12.01.cc:2837 +msgid "Discard edits?" +msgstr "" + +#: fotoxx-12.01.cc:2838 +msgid "" +"This action will discard current edits.\n" +"Continue to discard edits.\n" +"Go Back to keep edits." +msgstr "" + +#: fotoxx-12.01.cc:2841 +msgid "Continue" +msgstr "" + +#: fotoxx-12.01.cc:2842 +msgid "Go Back" +msgstr "" + +#: fotoxx-12.01.cc:3659 +msgid "cannot open thumbnail file" +msgstr "kan miniatuur bestand niet openen" + +#: fotoxx-12.01.cc:3870 fotoxx-12.01.cc:3992 +msgid "TIFF open failure" +msgstr "TIFF open fout" + +#: fotoxx-12.01.cc:3886 +#, c-format +msgid "TIFF bits/color=%d not supported" +msgstr "TIFF bits/kleur=%d niet ondersteund" + +#: fotoxx-12.01.cc:3901 fotoxx-12.01.cc:3939 +msgid "TIFF read failure" +msgstr "TIFF lees fout" + +#: fotoxx-12.01.cc:4051 +msgid "TIFF write failure" +msgstr "TIFF schrijf fout" + +#: fotoxx-12.01.cc:4071 +msgid "file type not supported" +msgstr "bestandstype niet ondersteund" + +#: fotoxx-12.01.cc:4178 +msgid "pixbuf write failure" +msgstr "pixbuf schrijf fout" + +#: fotoxx.h:728 +msgid "absolute" +msgstr "" + +#: fotoxx.h:730 +msgid "Add All" +msgstr "Alles toevoegen" + +#: fotoxx.h:732 +msgid "Amount" +msgstr "waarde" + +#: fotoxx.h:733 +msgid "Apply" +msgstr "Toepassen" + +#: fotoxx.h:734 +msgid "Black" +msgstr "" + +#: fotoxx.h:735 +msgid "Blend Width" +msgstr "Meng breedte" + +#: fotoxx.h:737 +msgid "Brightness" +msgstr "helderheid" + +#: fotoxx.h:738 +msgid "Browse" +msgstr "Zoeken" + +#: fotoxx.h:739 +msgid "Cancel" +msgstr "Annuleren" + +#: fotoxx.h:740 +msgid "Clear" +msgstr "Leegmaken" + +#: fotoxx.h:742 +msgid "Commit" +msgstr "" + +#: fotoxx.h:744 +msgid "Curve File:" +msgstr "Curve bestand:" + +#: fotoxx.h:745 +msgid "Cut" +msgstr "" + +#: fotoxx.h:746 +msgid "Darker Areas" +msgstr "Donkere delen" + +#: fotoxx.h:747 +msgid "Delete" +msgstr "Uitsnede verwijderen" + +#: fotoxx.h:749 +#, c-format +msgid "" +"Discard special gallery list? \n" +" %s" +msgstr "" + +#: fotoxx.h:750 +msgid "Done" +msgstr "Klaar" + +#: fotoxx.h:751 +msgid "Edit" +msgstr "Bewerken" + +#: fotoxx.h:753 +msgid "Erase" +msgstr "" + +#: fotoxx.h:754 +msgid "package libimage-exiftool-perl is required" +msgstr "pakket libimage-exiftool-perl is vereist" + +#: fotoxx.h:755 +msgid "Fetch" +msgstr "Ophalen" + +#: fotoxx.h:756 +msgid "Finish" +msgstr "Gereed" + +#: fotoxx.h:757 +msgid "Font" +msgstr "Font" + +#: fotoxx.h:759 +msgid "Height" +msgstr "hoogte" + +#: fotoxx.h:760 +msgid "histogram" +msgstr "histogram" + +#: fotoxx.h:762 +msgid "Insert" +msgstr "Invoegen" + +#: fotoxx.h:764 +msgid "Lighter Areas" +msgstr "Lichtere delen" + +#: fotoxx.h:765 +msgid "limit" +msgstr "limiet" + +#: fotoxx.h:766 +msgid "New" +msgstr "" + +#: fotoxx.h:768 +msgid "OK" +msgstr "OK" + +#: fotoxx.h:772 +msgid "Pause" +msgstr "Pauze" + +#: fotoxx.h:773 +msgid "Percent" +msgstr "percentage" + +#: fotoxx.h:774 +msgid "Presets" +msgstr "verkleiningsfactor" + +#: fotoxx.h:775 +msgid "Proceed" +msgstr "Doorgaan" + +#: fotoxx.h:777 +msgid "range" +msgstr "bereik" + +#: fotoxx.h:780 +msgid "Reduce" +msgstr "verminderen" + +#: fotoxx.h:782 +msgid "Reset" +msgstr "" + +#: fotoxx.h:784 +msgid "Unknown file type, save as tiff/jpeg/png to edit" +msgstr "Bestandstype onbekend, om te bewerken opslaan als tiff/jpeg/png" + +#: fotoxx.h:785 +msgid "Search" +msgstr "Zoeken" + +#: fotoxx.h:789 +msgid "Start" +msgstr "Starten" + +#: fotoxx.h:790 +msgid "Threshold" +msgstr "drempel" + +#: fotoxx.h:791 +#, c-format +msgid "exceed %d files" +msgstr "" + +#: fotoxx.h:792 +msgid "Undo All" +msgstr "Alles ongedaan maken" + +#: fotoxx.h:793 +msgid "Undo Last" +msgstr "Laatste ongedaan maken" + +#: fotoxx.h:795 +msgid "Unfinish" +msgstr "" + +#: fotoxx.h:797 +msgid "View" +msgstr "" + +#: fotoxx.h:798 +msgid "White" +msgstr "" + +#: fotoxx.h:799 +msgid "Width" +msgstr "breedte" + +#: zfuncs.cc:3252 +#, c-format +msgid "help file not found: %s" +msgstr "help bestand niet gevonden: %s" + +#: zfuncs.cc:3664 zfuncs.cc:7315 +#, c-format +msgid "cannot open file %s" +msgstr "kan bestand niet openen %s" + +#: zfuncs.cc:3697 +msgid "save screen to file" +msgstr "schrijf scherm naar bestand" + +#: zfuncs.cc:6222 +msgid "No" +msgstr "Nee" + +#: zfuncs.cc:6222 +msgid "Yes" +msgstr "Ja" + +#: zfuncs.cc:6447 +msgid "open" +msgstr "Openen" + +#: zfuncs.cc:6452 +msgid "choose" +msgstr "Kies" + +#: zfuncs.cc:6457 +msgid "save" +msgstr "opslaan" + +#: zfuncs.cc:6463 +msgid "open folder" +msgstr "open map" + +#: zfuncs.cc:6468 +msgid "create folder" +msgstr "aanmaken map" + +#: zfuncs.cc:6474 +msgid "hidden" +msgstr "verborgen" + +#: zfuncs.cc:6535 +msgid "JPG quality 0-100" +msgstr "JPG kwaliteit 0-100" + +#: zfuncs.cc:6728 zfuncs.cc:6741 +msgid "margins" +msgstr "" + +#: zfuncs.cc:6737 +msgid "top" +msgstr "" + +#: zfuncs.cc:6738 +msgid "bottom" +msgstr "" + +#: zfuncs.cc:6739 +msgid "left" +msgstr "" + +#: zfuncs.cc:6740 +msgid "right" +msgstr "" + +#: zfuncs.cc:7202 +msgid "" +"Initial parameters file created. \n" +"Inspect and revise if necessary." +msgstr "" +"Initieel parameter bestand wordt aangemaakt. \n" +"Zo nodig controleren en verbeteren." + +#: zfuncs.cc:7218 +msgid "load parameters from a file" +msgstr "laden parameters uit bestand" + +#: zfuncs.cc:7287 +msgid "save parameters to a file" +msgstr "schrijf parameters naar bestand" + +#: zfuncs.cc:7425 zfuncs.cc:7431 zfuncs.cc:7437 zfuncs.cc:7443 +msgid "edit parameters" +msgstr "aanpassen parameters" + +#: zfuncs.cc:7426 zfuncs.cc:7432 +msgid "" +"list\n" +"all" +msgstr "" +"opsommen\n" +"alle" + +#: zfuncs.cc:7426 zfuncs.cc:7432 zfuncs.cc:7438 zfuncs.cc:7444 +msgid "" +"load\n" +"file" +msgstr "" +"laden\n" +"bestand" + +#: zfuncs.cc:7426 zfuncs.cc:7432 zfuncs.cc:7438 zfuncs.cc:7444 +msgid "" +"save\n" +"file" +msgstr "" +"opslaan\n" +"bestand" + +#: zfuncs.cc:7427 zfuncs.cc:7439 +msgid "" +"add\n" +"new" +msgstr "" +"toevoegen\n" +"nieuw" + +#: zfuncs.cc:7427 zfuncs.cc:7433 zfuncs.cc:7439 zfuncs.cc:7445 +msgid "apply" +msgstr "toepassen" + +#: zfuncs.cc:7479 +msgid "apply?" +msgstr "toepassen?" + +#: zfuncs.cc:7536 +msgid "(new parm name)" +msgstr "(nieuwe parameter naam)" + +#: zfuncs.cc:7536 +msgid "add parameter" +msgstr "toevoegen parameter" + +#~ msgid "Brightness Graph" +#~ msgstr "Helderheidshistogram tonen" + +#~ msgid "Add Menu and Launcher" +#~ msgstr "Toevoegen Menu en Start-icon" + +#~ msgid "Batch Resize/Export" +#~ msgstr "Batchgewijs grootte wijzigen/exporteren" + +#~ msgid "select by color" +#~ msgstr "selecteer met kleur" + +#~ msgid "radius" +#~ msgstr "straal" + +#~ msgid "match" +#~ msgstr "gelijkenis" + +#~ msgid "Search results file error %s" +#~ msgstr "Zoekresultaten - bestandsfout %s" + +#~ msgid "Batch Resize" +#~ msgstr "Batchgewijs grootte wijzigen" + +#~ msgid "new max. height" +#~ msgstr "nieuwe max. hoogte" + +#~ msgid "copy EXIF" +#~ msgstr "copieer EXIF" + +#~ msgid "new file already exists" +#~ msgstr "nieuw bestand bestaat reeds" + +#~ msgid "Select area first" +#~ msgstr "Eerst uitsnede selecteren" + +#~ msgid "open a file" +#~ msgstr "open bestand" + +#~ msgid "paper format is crazy" +#~ msgstr "papier formaat zinloos" + +#~ msgid "landscape" +#~ msgstr "landscape" + +#~ msgid "portrait" +#~ msgstr "portrait" + +#~ msgid "paper format" +#~ msgstr "papier formaat" + +#~ msgid "printer ID" +#~ msgstr "printer ID" + +#~ msgid "print" +#~ msgstr "Afdrukken" + +#~ msgid "Time Interval" +#~ msgstr "Tijdsinterval" + +#~ msgid "Whole Image" +#~ msgstr "Gehele afbeelding" + +#~ msgid "random" +#~ msgstr "lukraak" + +#~ msgid "" +#~ "Click on images to remove and save, \n" +#~ "then press [Insert] to insert them." +#~ msgstr "" +#~ "Klik op afbeeldingen om te verwijderen en te bewaren, \n" +#~ "druk daarna [Invoegen] to insert them." + +#~ msgid "Clone fotoxx" +#~ msgstr "fotoxx klonen" + +#~ msgid "Save As" +#~ msgstr "Opslaan als ..." + +#~ msgid "" +#~ "Select images to add, then \n" +#~ "press [Insert] to insert them." +#~ msgstr "" +#~ "Selecteer afbeeldingen om toe te voegen, \n" +#~ "druk daarna [Toevoegen] om ze toe te voegen." + +#~ msgid "click on window to show RGB" +#~ msgstr "klik op venster om RGB waarden te tonen" + +#~ msgid "make new version" +#~ msgstr "maak nieuwe versie" + +#~ msgid "white" +#~ msgstr "wit" + +#~ msgid "black" +#~ msgstr "zwart" + +#~ msgid "Create Launcher" +#~ msgstr "Start-icon maken" + +#~ msgid "" +#~ "Search all areas for edge and inside pixels. \n" +#~ "Click inside each enclosed area in sequence." +#~ msgstr "" +#~ "Doorzoeken alle uitsnedes op randpixels en interne pixels. \n" +#~ "Klik achtereenvolgens in elke uitsnede." + +#~ msgid "area outline has a hole" +#~ msgstr "Contour van uitsnede heeft een gat" + +#~ msgid "Rebuild Thumbnails" +#~ msgstr "Opbouwen miniaturen" + +#~ msgid "horizontal unbend" +#~ msgstr "horizontaal ontkrommen" + +#~ msgid "press ESC to exit" +#~ msgstr "druk ESC om af te sluiten" + +#~ msgid "select by color:" +#~ msgstr "selecteer kleur" + +#~ msgid "select by mouse:" +#~ msgstr "selecteer muis" + +#~ msgid "vertical unbend" +#~ msgstr "verticaal ontkrommen" + +#~ msgid "target group area" +#~ msgstr "drempel groepering uitsnedes" + +#~ msgid "Area" +#~ msgstr "Uitsnede" + +#~ msgid "Constrain" +#~ msgstr "beperken" + +#~ msgid "Convert Tags !!!" +#~ msgstr "Tags converteren !!!" + +#~ msgid "Convert tags to new standard" +#~ msgstr "Tags volgens nieuwe standaard converteren" + +#~ msgid "" +#~ "Convert tags to new standard now? \n" +#~ "Are your image files backed-up?" +#~ msgstr "" +#~ "Tags nu volgens nieuwe standaard converteren? \n" +#~ "Heeft u een backup van uw afbeeldingen gemaakt?" + +#~ msgid "HDF" +#~ msgstr "HDF afbeelding maken" + +#~ msgid "HDR" +#~ msgstr "HDR afbeelding maken" + +#~ msgid "" +#~ "New tags file already exists! \n" +#~ "Proceed anyway?" +#~ msgstr "" +#~ "Nieuw tag bestand bestaat reeds! \n" +#~ "Toch doorgaan?" + +#~ msgid "No tags index file" +#~ msgstr "Geen tagindex bestand" + +#~ msgid "Rebuild Tags Index" +#~ msgstr "Opbouwen tagindex" + +#~ msgid "Stack" +#~ msgstr "Afbeeldingen stapelen" + +#~ msgid "Use F1 for context help" +#~ msgstr "Druk op F1 voor context help" + +#~ msgid "brightness to clip (percent)" +#~ msgstr "helderheidsbereik in procenten" + +#~ msgid "cannot read .dist file" +#~ msgstr "kan .dist bestand niet lezen" + +#~ msgid "manage tags" +#~ msgstr "beheren tags" + +#~ msgid "new tags index will now be created" +#~ msgstr "nieuwe tagindex zal nu worden aangemaakt" + +#~ msgid "save select area as a file" +#~ msgstr "uitsnede opslaan als bestand" + +#~ msgid "tags index file error: %s" +#~ msgstr "tagindex bestandsfout: %s" + +#~ msgid "/path*/file*" +#~ msgstr "/pad*/bestand*" + +#~ msgid "All EXIF data" +#~ msgstr "EXIF gegevens tonen" + +#~ msgid "Basic EXIF data" +#~ msgstr "EXIF basisgegevens tonen" + +#~ msgid "Delete EXIF data" +#~ msgstr "EXIF gegevens verwijderen" + +#~ msgid "EXIF data" +#~ msgstr "EXIF gegevens" + +#~ msgid "Edit EXIF data" +#~ msgstr "EXIF gegevens aanpassen" + +#~ msgid "Resume" +#~ msgstr "Hervatten" + +#~ msgid "Search Tags" +#~ msgstr "Tags doorzoeken" + +#~ msgid "Set Tile and Gap Size" +#~ msgstr "Instellen tegelparameters" + +#~ msgid "Suspend" +#~ msgstr "Onderbreken" + +#~ msgid "Tags" +#~ msgstr "Tags" + +#~ msgid "match all tags" +#~ msgstr "overeenkomend met alle tags" + +#~ msgid "match any tag" +#~ msgstr "overeenkomend met een tag" + +#~ msgid "" +#~ " Pull on an image edge using the mouse. \n" +#~ " Make multiple mouse pulls until satisfied. \n" +#~ " When finished, press [done]." +#~ msgstr "" +#~ " Sleep een rand van de afbeelding. \n" +#~ " Herhalen tot het gewenste resultaat. \n" +#~ " Indien gereed, druk [Klaar]." + +#~ msgid "Open File" +#~ msgstr "Open uitsnede-bestand" + +#~ msgid "Warp Area" +#~ msgstr "Uitsnede kromtrekken" + +#~ msgid "Warp Image" +#~ msgstr "Kromtrekken afbeelding" + +#~ msgid "Warp Image (curvy)" +#~ msgstr "Afbeelding kromtrekken (curvy)" + +#~ msgid "Warp Image in Selected Area" +#~ msgstr "Afbeelding kromtrekken in geselecteerde uitsnede" + +#~ msgid "" +#~ "position image\n" +#~ "with mouse drag" +#~ msgstr "" +#~ "afbeelding positioneren\n" +#~ "door met muis te slepen" + +#~ msgid "transparent" +#~ msgstr "doorzichtig" + +#~ msgid "Read File" +#~ msgstr "Uitsnede-bestand laden" + +#~ msgid "color intensity" +#~ msgstr "kleurintensiteit" + +#~ msgid "Burn" +#~ msgstr "Branden" + +#~ msgid "" +#~ "Convert tags to new standard now?\n" +#~ "Are your image files backed-up?" +#~ msgstr "" +#~ "Tags nu naar nieuwe standaard converteren?\n" +#~ "Heeft u een backup van uw afbeeldingen gemaakt?" + +#~ msgid "Fix Image Perspective" +#~ msgstr "Perspectief corrigeren" + +#~ msgid "TIFF colors=%d depth=%d not supported" +#~ msgstr "TIFF kleuren=%d diepte=%d niet ondersteund" + +#~ msgid "add tags" +#~ msgstr "Tags toevoegen" + +#~ msgid "browse" +#~ msgstr "doorzoeken" + +#~ msgid "color range" +#~ msgstr "kleurbereik" + +#~ msgid "" +#~ "exiftool missing, please install \n" +#~ " package libimage-exiftool-perl" +#~ msgstr "" +#~ "Programma exiftool ontbreekt, graag pakket \n" +#~ "libimage-exiftool-perl installeren" + +#~ msgid "follow edge" +#~ msgstr "rand volgen" + +#~ msgid "freehand draw" +#~ msgstr "vrij tekenen" + +#~ msgid "rename files" +#~ msgstr "hernoemen bestanden" + +#~ msgid "select files" +#~ msgstr "bestanden kiezen" + +#~ msgid "select image files to add tags" +#~ msgstr "bestanden selecteren om tags toe te voegen" + +#~ msgid "" +#~ "\n" +#~ " Match Brightness and Color" +#~ msgstr "" +#~ "\n" +#~ " Helderheid en kleur aanpassen" + +#~ msgid "Auto" +#~ msgstr "Auto" + +#~ msgid "Auto-search lens mm and bow" +#~ msgstr "auto zoeken brandpuntsafstand en lenskromming" + +#~ msgid "" +#~ "Drag right image into rough alignment with left \n" +#~ " to rotate, drag right edge up or down" +#~ msgstr "" +#~ "Sleep rechter afbeelding om te positioneren tov de linker afbeelding \n" +#~ "Om te draaien de rechterrand met de muis op of neer slepen" + +#~ msgid "Match Images" +#~ msgstr "Afbeeldingen gelijkend maken" + +#~ msgid "Merge the images together" +#~ msgstr "afbeeldingen samenvoegen" + +#~ msgid "Package ufraw required for this function" +#~ msgstr "Pakket ufraw nodig voor deze functie" + +#~ msgid "Retouch Image" +#~ msgstr "Afbeelding retoucheren" + +#~ msgid "Select 2 to 10 files to combine" +#~ msgstr "Selecteer 2-10 afbeeldingen om samen te voegen" + +#~ msgid "Select image to combine" +#~ msgstr "Selecteer afbeelding om samen te voegen" + +#~ msgid "Current file must be included" +#~ msgstr "Huidig bestand moet in selectie zijn opgenomen" + +#~ msgid "Select between 2 and 10 files to combine" +#~ msgstr "Selecteer 2 tot 10 afbeeldingen om samen te voegen" + +#~ msgid "jpeg quality" +#~ msgstr "jpeg kwaliteit" + +#~ msgid " Constraints" +#~ msgstr "Beperkingen" + +#~ msgid "" +#~ "%s \n" +#~ " tag limit exceeded" +#~ msgstr "" +#~ "%s \n" +#~ " Tag limiet overschreden" + +#~ msgid "Add or Remove Grid Lines" +#~ msgstr "Rasterlijnen toevoegen of verwijderen" + +#~ msgid "Assigned tags file error: %s" +#~ msgstr "Fout in toegewezen tagbestand %s" + +#~ msgid "Convert Tags" +#~ msgstr "Tags converteren" + +#~ msgid "" +#~ "Drag middle to move \n" +#~ "Drag corners to resize" +#~ msgstr "" +#~ "Het midden slepen om te bewegen, \n" +#~ "Hoeken slepen om grootte te wijzigen" + +#~ msgid "Index Tags" +#~ msgstr "Tags indexeren" + +#~ msgid "Index Tags and Thumbs" +#~ msgstr "Tags en Thumbs synchroniseren" + +#~ msgid "No assigned tags index file" +#~ msgstr "Geen toegewezen tagindex bestand" + +#~ msgid "Package exiftool is missing" +#~ msgstr "Pakket exiftool mist" + +#~ msgid "Tonemap: base" +#~ msgstr "Tonemap: basis" + +#~ msgid "Tonemap: gradient" +#~ msgstr "Tonemap: gradient" + +#~ msgid "Tonemap: local-1" +#~ msgstr "Tonemap: lokal-1" + +#~ msgid "Tonemap: local-2" +#~ msgstr "Tonemap: lokal-2" + +#~ msgid "Too many tags: %d" +#~ msgstr "Te veel tags: %d" + +#~ msgid "Too many undo buffers, please save image" +#~ msgstr "te veel undo-buffers, graag afbeelding opslaan" + +#~ msgid "Total tags exceed %d characters" +#~ msgstr "Aantal tags overschrijdt %d karakters" + +#~ msgid "Unable to copy EXIF data" +#~ msgstr "Kan EXIF gegevens niet copieren" + +#~ msgid "Unable to save image: %s" +#~ msgstr "Kan afbeelding niet opslaan: %s" + +#~ msgid "Warp Image (curvey)" +#~ msgstr "Afbeelding kromtrekken (curvy)" + +#~ msgid "assigned tags" +#~ msgstr "toegewezen tags" + +#~ msgid "filespec too long: %s" +#~ msgstr "bestandsnaam te lang: %s" + +#~ msgid "grid spacing" +#~ msgstr "raster grootte" + +#~ msgid "new file already exists: %s" +#~ msgstr "nieuw bestand bestaat reeds: %s" + +#~ msgid "recently added" +#~ msgstr "pas toegevoegd" + +#~ msgid "tags exceed %d characters" +#~ msgstr "tags overschrijden %d karakters" + +#~ msgid "" +#~ "Discard current gallery list? \n" +#~ " %s" +#~ msgstr "" +#~ "Vervangen huidige galerie lijst? \n" +#~ " %s" + +#~ msgid "Edit Caption" +#~ msgstr "Bijschrift aanpassen" + +#~ msgid "Edit Comments" +#~ msgstr "Commentaar aanpassen" + +#~ msgid "Discard modifications?" +#~ msgstr "Wijzigingen verwerpen?" + +#~ msgid "transition" +#~ msgstr "overgang" + +#~ msgid "" +#~ "Rename failed \n" +#~ " %s" +#~ msgstr "" +#~ "Hernoemen mislukt \n" +#~ " %s" + +#~ msgid "incremental" +#~ msgstr "toenemend" + +#~ msgid "full rebuild" +#~ msgstr "volledig herbouwen" + +#~ msgid "" +#~ "Click on image where new or saved \n" +#~ "images are to be inserted (after)." +#~ msgstr "" +#~ "Klik op de afbeelding waarna nieuwe of bewaarde \n" +#~ "afbeeldingen moeten worden toegevoegd." + +#~ msgid "Click on images to delete." +#~ msgstr "Klik op afbeeldingen om te verwijderen." + +#~ msgid "select image files" +#~ msgstr "selecteer afbeeldingsbestanden" + +#~ msgid "Insert new or saved images" +#~ msgstr "Invoegen nieuwe of bewaarde afbeeldingen" + +#~ msgid "Remove and save images" +#~ msgstr "Verwijderen en bewaren afbeeldingen" + +#~ msgid "Delete images from collection" +#~ msgstr "Afbeelding verwijderen uit verzameling" + +#~ msgid "Add new images to collection" +#~ msgstr "Nieuwe afbeeldingen toevoegen aan verzameling" + +#~ msgid "Save Collection" +#~ msgstr "Verzameling bewaren" + +#~ msgid "" +#~ "Run Tools > Synchronize Files so that gallery windows \n" +#~ "will be fast and Search Images will work correctly." +#~ msgstr "" +#~ "Kies Gereedschap > Synchroniseren bestanden zodat gallerie vensters \n" +#~ "snel zijn en Doorzoeken afbeeldingen correct zal werken." + +#~ msgid "Translate" +#~ msgstr "Vertaalinstructie" + +#~ msgid "Open Collection" +#~ msgstr "Verzameling openen" + +#~ msgid "Create Collection" +#~ msgstr "Verzameling maken" + +#~ msgid "select new file" +#~ msgstr "selecteer nieuw bestand" + +#~ msgid "both" +#~ msgstr "beide" + +#~ msgid "icons" +#~ msgstr "icons" + +#~ msgid "lens name" +#~ msgstr "lens naam" + +#~ msgid "start edit function first" +#~ msgstr "start eerst edit functie" + +#~ msgid "Lens Parameters" +#~ msgstr "Lens parameters instellen" diff -Nru fotoxx-11.11.1/locales/fotoxx-pt.po fotoxx-12.01.2/locales/fotoxx-pt.po --- fotoxx-11.11.1/locales/fotoxx-pt.po 1970-01-01 00:00:00.000000000 +0000 +++ fotoxx-12.01.2/locales/fotoxx-pt.po 2012-01-04 08:47:11.000000000 +0000 @@ -0,0 +1,3135 @@ +# Portuguese translations for home package. +# Copyright (C) 2010 THE home'S COPYRIGHT HOLDER +# This file is distributed under the same license as the home package. +# mico , 2010. +# +msgid "" +msgstr "" +"Project-Id-Version: fotoxx-10.8\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-12-31 21:05+0100\n" +"PO-Revision-Date: 2010-07-01 22:55+0200\n" +"Last-Translator: André Campos Rodovalho \n" +"Language-Team: Portuguese\n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Poedit-Language: Portuguese\n" +"X-Poedit-Country: Brazil\n" + +#: f.art.cc:47 +msgid "Set color depth to 1-16 bits" +msgstr "Configurar resolução de cor para 1-16 bits" + +#: f.art.cc:57 +msgid "Set Color Depth" +msgstr "Configurar resolução de cor" + +#: f.art.cc:171 +msgid "Simulate Drawing" +msgstr "Simular Desenho" + +#: f.art.cc:213 f.retouch.cc:1759 f.retouch.cc:5991 +msgid "contrast" +msgstr "contraste" + +#: f.art.cc:215 +msgid "outlines" +msgstr "dispersão" + +#: f.art.cc:220 +msgid "pencil" +msgstr "caneta" + +#: f.art.cc:221 +msgid "chalk" +msgstr "giz" + +#: f.art.cc:381 +msgid "Add Image Outlines" +msgstr "Adicionar contornos de imagem" + +#: f.art.cc:394 +msgid "outline threshold" +msgstr "limite de contorno" + +#: f.art.cc:397 +msgid "outline width" +msgstr "largura de contorno" + +#: f.art.cc:400 +msgid "image brightness" +msgstr "brilho de imagem" + +#: f.art.cc:611 +msgid "Simulate Embossing" +msgstr "Simular Gravação em relevo" + +#: f.art.cc:626 +msgid "depth" +msgstr "profundidade" + +#: f.art.cc:628 f.file.cc:919 f.retouch.cc:6692 +msgid "color" +msgstr "cor" + +#: f.art.cc:821 +msgid "Simulate Tiles" +msgstr "Simular Ladrilho" + +#: f.art.cc:825 +msgid "tile size" +msgstr "tamanho do ladrilho" + +#: f.art.cc:829 +msgid "tile gap" +msgstr "espaçamento dos ladrilhos" + +#: f.art.cc:1003 +msgid "Convert Image to Dots" +msgstr "Converter imagem para pontos" + +#: f.art.cc:1007 +msgid "dot size" +msgstr "tamanho do ponto" + +#: f.art.cc:1222 +msgid "Simulate Painting" +msgstr "Simular Pintura" + +#: f.art.cc:1226 +msgid "color depth" +msgstr "resolução de cor" + +#: f.art.cc:1230 +msgid "patch area goal" +msgstr "remendar área objetivo" + +#: f.art.cc:1234 +msgid "req. color match" +msgstr "correspondência de cores requeridas" + +#: f.art.cc:1238 +msgid "borders" +msgstr "bordas" + +#: f.comp.cc:1956 f.comp.cc:1961 f.comp.cc:2582 f.comp.cc:2587 f.comp.cc:3266 +#: f.comp.cc:3271 f.comp.cc:3816 f.comp.cc:3821 +msgid "Select 2 to 9 files" +msgstr "Selecionar 2 a 9 arquivos" + +#: f.comp.cc:1982 f.comp.cc:2608 f.comp.cc:3292 f.comp.cc:3842 +msgid "Images are not all the same size" +msgstr "Imagens não são todas do mesmo tamanho" + +#: f.comp.cc:2321 +msgid "Adjust Image Contributions" +msgstr "Ajustar contribuição de imagem" + +#: f.comp.cc:2324 f.retouch.cc:886 +msgid "dark pixels" +msgstr "pixels escuros" + +#: f.comp.cc:2326 +msgid "light pixels" +msgstr "pixels claros" + +#: f.comp.cc:2328 f.info.cc:159 +msgid "file:" +msgstr "arquivo:" + +#: f.comp.cc:2843 +msgid "Paint and Warp Image" +msgstr "Pintar e distorcer imagem" + +#: f.comp.cc:2846 f.comp.cc:3520 f.comp.cc:4959 f.comp.cc:5705 +msgid "image" +msgstr "imagem" + +#: f.comp.cc:2850 f.retouch.cc:6696 +msgid "paint" +msgstr "pintar" + +#: f.comp.cc:2851 +msgid "warp" +msgstr "distorção" + +#: f.comp.cc:3518 +msgid "Select and Paint Image" +msgstr "Selecionar e pintar imagem" + +#: f.comp.cc:4031 +msgid "Adjust Pixel Composition" +msgstr "Ajustar Composição do Pixel" + +#: f.comp.cc:4283 f.comp.cc:4288 f.comp.cc:5173 f.comp.cc:5178 +msgid "Select 2 to 4 files" +msgstr "Selecionar 2 a 4 arquivos" + +#: f.comp.cc:4361 +msgid "" +"Drag images into rough alignment.\n" +"To rotate, drag from lower edge." +msgstr "" +"Arraste as imagens para o alinhamento grosseiro.\n" +"Para rotacionar, arraste da borda mais abaixo." + +#: f.comp.cc:4363 +msgid "Search for lens mm and bow" +msgstr "Procurar por mm e curvatura de lente" + +#: f.comp.cc:4409 f.comp.cc:5298 +msgid "Pre-align Images" +msgstr "Pré-alinhamento de imagens" + +#: f.comp.cc:4413 f.comp.cc:5302 +msgid "lens mm" +msgstr "mm de lente" + +#: f.comp.cc:4417 f.comp.cc:5306 +msgid "lens bow" +msgstr "curvatura de lente" + +#: f.comp.cc:4419 f.comp.cc:5308 +msgid "Resize" +msgstr "Redimensionar" + +#: f.comp.cc:4420 f.comp.cc:5309 +msgid "resize window" +msgstr "redimensionar janela" + +#: f.comp.cc:4457 +msgid "use two images only" +msgstr "use duas imagens apenas" + +#: f.comp.cc:4478 f.comp.cc:4676 f.comp.cc:4875 f.comp.cc:5357 f.comp.cc:5620 +msgid "Too little overlap, cannot align" +msgstr "Baixa sobreposição, não é possível alinhar" + +#: f.comp.cc:4950 f.comp.cc:5696 +msgid "Match Brightness and Color" +msgstr "Parear Brilho e Cor" + +#: f.comp.cc:4974 f.comp.cc:5720 +msgid "auto color" +msgstr "cor automática" + +#: f.comp.cc:4975 f.comp.cc:5721 +msgid "file color" +msgstr "arquivo de cor" + +#: f.comp.cc:5251 +msgid "" +"Drag images into rough alignment.\n" +"To rotate, drag from right edge." +msgstr "" +"Arraste as imagens para o alinhamento grosseiro.\n" +"Para rotacionar, arraste pela borda a direita." + +#: f.file.cc:169 f.file.cc:341 fotoxx-12.01.cc:189 fotoxx-12.01.cc:325 +msgid "Open Image File" +msgstr "Abrir arquivo" + +#: f.file.cc:321 fotoxx-12.01.cc:2862 +msgid "prior function still active" +msgstr "função prévia ainda ativada" + +#: f.file.cc:503 +msgid "Overwrite original file?" +msgstr "" + +#: f.file.cc:504 +msgid "Do not warn again" +msgstr "" + +#: f.file.cc:520 +msgid "Warning" +msgstr "" + +#: f.file.cc:643 +msgid "Save File" +msgstr "Salvar arquivo" + +#: f.file.cc:666 zfuncs.cc:6478 +msgid "quality" +msgstr "qualidade" + +#: f.file.cc:668 +msgid "make current" +msgstr "tornar atual" + +#: f.file.cc:725 +msgid "jpeg quality must be 1-100" +msgstr "qualidade de jpeg deve estar entre 1-100" + +#: f.file.cc:747 +#, c-format +msgid "" +"Overwrite file? \n" +" %s" +msgstr "" +"Sobrescrever arquivo? \n" +" %s" + +#: f.file.cc:903 fotoxx-12.01.cc:196 +msgid "Create Blank Image" +msgstr "Criar imagem em branco" + +#: f.file.cc:905 +msgid "file name" +msgstr "nome do arquvo" + +#: f.file.cc:910 f.transform.cc:353 +msgid "width" +msgstr "largura" + +#: f.file.cc:913 f.tools.cc:477 f.transform.cc:356 +msgid "height" +msgstr "altura" + +#: f.file.cc:1033 +msgid "" +"Linux standard trash is not supported. \n" +"Desktop trash folder will be created." +msgstr "" +"Lixeira padrão Linux não suportada. \n" +"Uma pasta com lixeira será criada na Área de Trabalho." + +#: f.file.cc:1051 +msgid "Move read-only file to trash?" +msgstr "Mover arquivo de apenas leitura para lixeira?" + +#: f.file.cc:1077 +#, c-format +msgid "Cannot create trash folder: %s" +msgstr "Não foi possível criar pasta lixeira: %s" + +#: f.file.cc:1085 f.file.cc:1091 zfuncs.cc:3356 +#, c-format +msgid "error: %s" +msgstr "erro: %s" + +#: f.file.cc:1136 fotoxx-12.01.cc:198 +msgid "Rename Image File" +msgstr "Renomear arquivo" + +#: f.file.cc:1141 +msgid "old name" +msgstr "nome antigo" + +#: f.file.cc:1142 +msgid "rename to" +msgstr "renomear para" + +#: f.file.cc:1143 +msgid "previous" +msgstr "anterior" + +#: f.file.cc:1229 +msgid "The target file already exists" +msgstr "Arquivo alvo já existente" + +#: f.file.cc:1237 +#, c-format +msgid "" +"Rename failed: \n" +" %s" +msgstr "" + +#: f.file.cc:1285 +msgid "Batch Rename" +msgstr "Renomear vários" + +#: f.file.cc:1288 f.file.cc:1340 f.info.cc:1519 f.info.cc:1773 f.tools.cc:543 +#: f.tools.cc:2990 +#, c-format +msgid "%d files selected" +msgstr "%d arquivos selecionados" + +#: f.file.cc:1290 +msgid "new base name" +msgstr "novo nome de base" + +#: f.file.cc:1293 +msgid "starting sequence" +msgstr "sequência inicial" + +#: f.file.cc:1295 +msgid "increment" +msgstr "incrementar" + +#: f.file.cc:1316 +msgid "select files to rename" +msgstr "selecionar arquivos para renomear" + +#: f.file.cc:1321 +msgid "base name / sequence / increment not reasonable" +msgstr "nome base / sequencia / incremento fixo" + +#: f.file.cc:1380 +msgid "new file already exists:" +msgstr "novo arquivo já existe:" + +#: f.file.cc:1388 +msgid "filespec too long:" +msgstr "caminho de arquivo muito longo:" + +#: f.file.cc:1399 +msgid "Rename failed:" +msgstr "Renomearação falhou:" + +#: f.file.cc:1660 fotoxx.h:729 +msgid "Add" +msgstr "Adicionar" + +#: f.file.cc:1660 fotoxx.h:781 +msgid "Remove" +msgstr "Remover" + +#: f.file.cc:1662 +msgid "menu name" +msgstr "nome do menu" + +#: f.file.cc:1733 f.file.cc:1754 +msgid "Restart Fotoxx to update plugin menu" +msgstr "Reinicie o Fotoxx para atualizar o menu de plugin" + +#: f.info.cc:70 +msgid "Edit Caption and Comments" +msgstr "Editar Legenda e Comentários" + +#: f.info.cc:156 fotoxx-12.01.cc:225 +msgid "Edit Tags" +msgstr "Editar Etiquetas" + +#: f.info.cc:163 +msgid "image date (yyyymmdd)" +msgstr "data de imagem (AAAAmmDD)" + +#: f.info.cc:165 +msgid "use last" +msgstr "usar último" + +#: f.info.cc:168 +msgid "image stars" +msgstr "estrelas da imagem" + +#: f.info.cc:186 +msgid "current tags" +msgstr "etiquetas atuais" + +#: f.info.cc:191 +msgid "recent tags" +msgstr "etiquetas recentes" + +#: f.info.cc:196 f.info.cc:358 f.info.cc:1368 f.info.cc:2384 +msgid "defined tags" +msgstr "etiquetas definidas" + +#: f.info.cc:345 fotoxx-12.01.cc:226 +msgid "Manage Tags" +msgstr "Gerenciar Etiquetas" + +#: f.info.cc:348 +msgid "category" +msgstr "categoria" + +#: f.info.cc:351 +msgid "tag" +msgstr "etiqueta" + +#: f.info.cc:354 +msgid "create" +msgstr "criar" + +#: f.info.cc:355 f.navi.cc:1421 +msgid "delete" +msgstr "excluir" + +#: f.info.cc:1235 f.info.cc:1319 +#, c-format +msgid "search index file error: %s" +msgstr "busca de arquivo índice erro: %s" + +#: f.info.cc:1351 fotoxx-12.01.cc:227 +msgid "Batch Add Tags" +msgstr "Adicinar Etiquetas em vários" + +#: f.info.cc:1354 +msgid "tags to add" +msgstr "etiquetas a adicionar" + +#: f.info.cc:1359 +msgid "create tag" +msgstr "criar etiqueta" + +#: f.info.cc:1415 f.info.cc:1608 +#, c-format +msgid "" +"%s \n" +" too many tags" +msgstr "" +"%s \n" +" etiquetas demais" + +#: f.info.cc:1553 fotoxx-12.01.cc:228 +msgid "Batch Delete Tag" +msgstr "Adicionar várias Etiquetas" + +#: f.info.cc:1556 +msgid "tag to remove" +msgstr "etiquetas a remover" + +#: f.info.cc:1560 +msgid "optional replacement" +msgstr "substituição opcional" + +#: f.info.cc:1565 f.tools.cc:2943 +msgid "0 files selected" +msgstr "0 arquivos selecionados" + +#: f.info.cc:1568 +msgid "search all files" +msgstr "procurar todos arquivos" + +#: f.info.cc:1653 +msgid "no files selected" +msgstr "nenhum arquivo selecionado" + +#: f.info.cc:1659 +msgid "no tag specified" +msgstr "nenhuma etiqueta especificada" + +#: f.info.cc:1683 f.info.cc:1712 +msgid "specify tag" +msgstr "especificar etiqueta" + +#: f.info.cc:1821 +msgid "View Info" +msgstr "Ver Info" + +#: f.info.cc:1889 fotoxx-12.01.cc:231 +msgid "Edit Info" +msgstr "Editar Info" + +#: f.info.cc:1987 fotoxx-12.01.cc:232 +msgid "Delete Info" +msgstr "Excluir Info" + +#: f.info.cc:1989 fotoxx.h:731 +msgid "All" +msgstr "Todos" + +#: f.info.cc:1990 +msgid "One Key:" +msgstr "Uma chave:" + +#: f.info.cc:2343 +msgid "Search Tags, Comments, File Names" +msgstr "Procurar Etiquetas, Comentários, Nome de arquivos" + +#: f.info.cc:2350 +msgid "date range" +msgstr "variação de data" + +#: f.info.cc:2351 +msgid "stars range" +msgstr "variação de estrelas" + +#: f.info.cc:2352 +msgid "search tags" +msgstr "procurar etiquetas" + +#: f.info.cc:2353 +msgid "search text" +msgstr "procurar texto" + +#: f.info.cc:2354 +msgid "file names" +msgstr "nome de arquivos" + +#: f.info.cc:2359 +msgid "(yyyymmdd)" +msgstr "aaaammdd" + +#: f.info.cc:2365 +msgid "all/any" +msgstr "todos/qualquer" + +#: f.info.cc:2702 +msgid "No matching images found" +msgstr "Nenhuma imagem encontrada" + +#: f.info.cc:2706 f.info.cc:3059 +msgid "No search index file present" +msgstr "Não há arquivo índice" + +#: f.info.cc:2777 +msgid "Additional Items for Report" +msgstr "" + +#: f.navi.cc:188 f.navi.cc:576 f.navi.cc:706 f.navi.cc:707 f.navi.cc:709 +msgid "bigger" +msgstr "maior" + +#: f.navi.cc:188 +msgid "increase thumbnail size" +msgstr "aumentar tamanho de miniaturas" + +#: f.navi.cc:189 +msgid "reduce thumbnail size" +msgstr "reduzir tamanho de miniaturas" + +#: f.navi.cc:189 f.navi.cc:586 f.navi.cc:708 f.navi.cc:710 +msgid "smaller" +msgstr "menor" + +#: f.navi.cc:190 f.navi.cc:600 +msgid "parent" +msgstr "anterior" + +#: f.navi.cc:190 +msgid "parent directory" +msgstr "pasta anterior" + +#: f.navi.cc:191 f.navi.cc:625 f.navi.cc:717 +msgid "first page" +msgstr "primeira página" + +#: f.navi.cc:191 +msgid "jump to first file" +msgstr "pular para primeiro arquivo" + +#: f.navi.cc:192 f.navi.cc:623 f.navi.cc:712 f.navi.cc:719 +msgid "prev page" +msgstr "página ant." + +#: f.navi.cc:192 +msgid "previous page" +msgstr "página anterior" + +#: f.navi.cc:193 f.navi.cc:621 f.navi.cc:714 +msgid "prev row" +msgstr "coluna ant." + +#: f.navi.cc:193 +msgid "previous row" +msgstr "coluna anterior" + +#: f.navi.cc:194 f.navi.cc:622 f.navi.cc:715 +msgid "next row" +msgstr "próxiuma coluna" + +#: f.navi.cc:195 f.navi.cc:624 f.navi.cc:713 f.navi.cc:720 +msgid "next page" +msgstr "próxima página" + +#: f.navi.cc:195 +msgid "ttip::next page" +msgstr "" + +#: f.navi.cc:196 +msgid "jump to last file" +msgstr "pular para último arquivo" + +#: f.navi.cc:196 f.navi.cc:626 f.navi.cc:718 +msgid "last page" +msgstr "última página" + +#: f.navi.cc:197 f.navi.cc:571 +msgid "close" +msgstr "fechar" + +#: f.navi.cc:197 +msgid "close image gallery" +msgstr "fechar galeria de imagens" + +#: f.navi.cc:1413 fotoxx.h:787 +msgid "Select Files" +msgstr "Selecionar arquivos" + +#: f.navi.cc:1413 zfuncs.cc:6296 zfuncs.cc:6332 zfuncs.cc:6485 zfuncs.cc:6728 +#: zfuncs.cc:7427 zfuncs.cc:7433 zfuncs.cc:7439 zfuncs.cc:7445 +msgid "cancel" +msgstr "cancelar" + +#: f.navi.cc:1413 zfuncs.cc:6728 +msgid "done" +msgstr "pronto" + +#: f.navi.cc:1422 +msgid "insert" +msgstr "inserir" + +#: f.navi.cc:1423 +msgid "add all" +msgstr "adicionar todos" + +#: f.retouch.cc:55 +msgid "Adjust Brightness and Color" +msgstr "Ajustar Brilho e Cor" + +#: f.retouch.cc:110 +msgid "small-steps" +msgstr "pouco-a-pouco" + +#: f.retouch.cc:119 +msgid "color saturation" +msgstr "saturação de cor" + +#: f.retouch.cc:126 +msgid " reset 1 " +msgstr "reconfigurar 1" + +#: f.retouch.cc:127 +msgid "reset all" +msgstr "reconfigurar tudo" + +#: f.retouch.cc:599 +msgid "adjust image gamma" +msgstr "" + +#: f.retouch.cc:885 +msgid "Expand Brightness Range" +msgstr "Aumentar variação de Brilho" + +#: f.retouch.cc:887 +msgid "bright pixels" +msgstr "pixels brilhantes" + +#: f.retouch.cc:1058 +msgid "Flatten Brightness Distribution" +msgstr "Reduzir distribuição de Brilho" + +#: f.retouch.cc:1072 +msgid "Flatten" +msgstr "Abrandar" + +#: f.retouch.cc:1334 +msgid "Ramp brightness across image" +msgstr "Curva de Brilho sobre a imagem" + +#: f.retouch.cc:1730 fotoxx-12.01.cc:272 +msgid "Tone Mapping" +msgstr "Mapa sonoro" + +#: f.retouch.cc:1758 +msgid "low" +msgstr "baixo" + +#: f.retouch.cc:1760 +msgid "high" +msgstr "alto" + +#: f.retouch.cc:1763 +msgid "Amplify" +msgstr "Ampliar" + +#: f.retouch.cc:2069 +msgid "Adjust White Balance" +msgstr "Ajustar balanço de branco" + +#: f.retouch.cc:2070 +msgid "Click white or gray image location" +msgstr "Clique em uma área branca ou cinza da imagem" + +#: f.retouch.cc:2278 +msgid "Color Match Images" +msgstr "Imagens para mesclagem de cor" + +#: f.retouch.cc:2307 +msgid "mouse radius for color sample" +msgstr "raio do mouse para a amostra de cor" + +#: f.retouch.cc:2309 f.retouch.cc:2314 fotoxx-12.01.cc:246 fotoxx-12.01.cc:325 +#: fotoxx.h:769 +msgid "Open" +msgstr "Abrir" + +#: f.retouch.cc:2310 +msgid "image for source color" +msgstr "imagem para fonte de cor" + +#: f.retouch.cc:2312 +msgid "click on image to get source color" +msgstr "clique na imagem para obter a cor fonte" + +#: f.retouch.cc:2315 +msgid "image to set matching color" +msgstr "imagem para mesclagem de cor" + +#: f.retouch.cc:2317 +msgid "click on image to set matching color" +msgstr "clique na imagem para aplicar mesclagem de cor" + +#: f.retouch.cc:2372 +msgid "select source image color first" +msgstr "selecione imagem para fonte de cor primeiro" + +#: f.retouch.cc:2584 +msgid "Add standard bias" +msgstr "" + +#: f.retouch.cc:2591 +msgid "+Brightness -Density" +msgstr "" + +#: f.retouch.cc:2592 +msgid "+Red -Cyan" +msgstr "" + +#: f.retouch.cc:2593 +msgid "+Green -Magenta" +msgstr "" + +#: f.retouch.cc:2594 +msgid "+Blue -Yellow" +msgstr "" + +#: f.retouch.cc:2599 +msgid "Contrast" +msgstr "" + +#: f.retouch.cc:2600 fotoxx.h:778 +msgid "Red" +msgstr "Vermelho" + +#: f.retouch.cc:2601 fotoxx.h:758 +msgid "Green" +msgstr "Verde" + +#: f.retouch.cc:2602 fotoxx.h:736 +msgid "Blue" +msgstr "Azul" + +#: f.retouch.cc:2730 +msgid "Load DRGB parameters" +msgstr "" + +#: f.retouch.cc:2732 f.retouch.cc:2804 f.retouch.cc:6102 f.retouch.cc:6198 +msgid "File:" +msgstr "" + +#: f.retouch.cc:2751 f.retouch.cc:2824 +msgid "DRGB parameters file" +msgstr "" + +#: f.retouch.cc:2769 f.retouch.cc:6142 +msgid "file not found" +msgstr "" + +#: f.retouch.cc:2802 +msgid "Save DRGB parameters" +msgstr "" + +#: f.retouch.cc:3034 f.tools.cc:2404 +msgid "Click image to select pixels." +msgstr "Clique na imagem para selecionar pixels." + +#: f.retouch.cc:3072 fotoxx-12.01.cc:276 +msgid "Revise RGB" +msgstr "Revisar RGB" + +#: f.retouch.cc:3084 +msgid "Metric:" +msgstr "Métrica:" + +#: f.retouch.cc:3139 +msgid "Blend" +msgstr "Mistura" + +#: f.retouch.cc:3519 +msgid "" +"Method 1:\n" +" Left-click on red-eye to darken.\n" +"Method 2:\n" +" Drag down and right to enclose red-eye.\n" +" Left-click on red-eye to darken.\n" +"Undo red-eye:\n" +" Right-click on red-eye." +msgstr "" +"Método 1:\n" +" Clique com o botão esquerdo no olho vermelho a escurecer.\n" +"Método 2:\n" +" Arraste e solte com o botão direito enquadrando o olho vermelho.\n" +" Clique com o botão esquerdo no olho vermelho a escurecer.\n" +"Retornar ao olho vermelho:\n" +" Clique com o botão direito no olho vermelho." + +#: f.retouch.cc:3534 +msgid "Red Eye Reduction" +msgstr "Redução de olhos vermelhos" + +#: f.retouch.cc:3968 +msgid "Set Blur Radius" +msgstr "Configurar raio de desfoque" + +#: f.retouch.cc:4195 fotoxx-12.01.cc:279 +msgid "Sharpen Image" +msgstr "Aguçar" + +#: f.retouch.cc:4202 +msgid "edge detection" +msgstr "detecção de borda" + +#: f.retouch.cc:4203 +msgid "cycles" +msgstr "ciclos" + +#: f.retouch.cc:4204 +msgid "reduce" +msgstr "reduzir" + +#: f.retouch.cc:4215 +msgid "unsharp mask" +msgstr "desaguçar máscara" + +#: f.retouch.cc:4228 +msgid "brightness gradient" +msgstr "gradiente de brilho" + +#: f.retouch.cc:4634 +msgid "" +" Press the reduce button to \n" +" reduce noise in small steps. \n" +" Use undo to start over." +msgstr "" +" Precione o botão de reduzir para \n" +" reduzir o ruído pouco-a-pouco. \n" +" Use desfazer para começar novamente." + +#: f.retouch.cc:4645 +msgid "Noise Reduction" +msgstr "Redução de ruído" + +#: f.retouch.cc:4650 +msgid "algorithm" +msgstr "algoritmo" + +#: f.retouch.cc:4657 +msgid "flatten outliers by color (1)" +msgstr "aproximar dispersos por cor (1)" + +#: f.retouch.cc:4658 +msgid "flatten outliers by color (2)" +msgstr "aproximar dispersos por cor (2)" + +#: f.retouch.cc:4659 +msgid "set median brightness by color" +msgstr "configurar brilho mediano pela cor" + +#: f.retouch.cc:4660 f.retouch.cc:4661 +msgid "top hat filter by color" +msgstr "filtro cartola por cor" + +#: f.retouch.cc:4976 +msgid "" +"1. Drag mouse to select. \n" +"2. Erase. 3. Repeat. " +msgstr "" +"1. Arraste o mouse para selecionar. \n" +"2. Apague. 3. Repita. " + +#: f.retouch.cc:4998 fotoxx-12.01.cc:281 +msgid "Smart Erase" +msgstr "Apagador inteligente" + +#: f.retouch.cc:5003 fotoxx.h:776 +msgid "Radius" +msgstr "Raio" + +#: f.retouch.cc:5005 +msgid "Blur" +msgstr "Desfoque" + +#: f.retouch.cc:5008 +msgid "New Area" +msgstr "Nova Área" + +#: f.retouch.cc:5379 fotoxx-12.01.cc:282 +msgid "Remove Dust" +msgstr "Remover Sujeira" + +#: f.retouch.cc:5383 +msgid "spot size limit" +msgstr "limite de tamanho de mancha" + +#: f.retouch.cc:5386 +msgid "max. brightness" +msgstr "brilho máximo" + +#: f.retouch.cc:5389 +msgid "min. contrast" +msgstr "contraste mínimo" + +#: f.retouch.cc:5983 fotoxx-12.01.cc:283 +msgid "Fix Stuck Pixels" +msgstr "" + +#: f.retouch.cc:5989 +msgid "pixel group" +msgstr "" + +#: f.retouch.cc:5990 +msgid "circle color" +msgstr "" + +#: f.retouch.cc:6100 +msgid "Load Stuck Pixels" +msgstr "" + +#: f.retouch.cc:6124 f.retouch.cc:6220 +msgid "Stuck Pixels file" +msgstr "" + +#: f.retouch.cc:6164 +msgid "file format error" +msgstr "" + +#: f.retouch.cc:6192 +msgid "there are zero stuck pixels" +msgstr "" + +#: f.retouch.cc:6196 +msgid "Save Stuck Pixels" +msgstr "" + +#: f.retouch.cc:6686 +#, c-format +msgid "Undo Memory %d%c" +msgstr "Desfazer memória %d%c" + +#: f.retouch.cc:6688 fotoxx-12.01.cc:284 +msgid "Edit Pixels" +msgstr "Editar Pixels" + +#: f.retouch.cc:6695 +msgid "pick" +msgstr "capturar" + +#: f.retouch.cc:6697 +msgid "erase" +msgstr "apagar" + +#: f.retouch.cc:6705 +msgid "paintbrush radius" +msgstr "raio do pincel" + +#: f.retouch.cc:6706 +msgid "transparency center" +msgstr "centro de transparência" + +#: f.retouch.cc:6707 +msgid "transparency edge" +msgstr "borda de transparência" + +#: f.retouch.cc:6972 +msgid "" +"Undo memory limit has been reached. \n" +"Save work with [done], then resume editing." +msgstr "" +"Limite do histórico de modificações foi alcançado. \n" +"Salve seu trabalho clicando [pronto], e continue a editar." + +#: f.select.cc:54 f.select.cc:2461 +msgid "Select Area for Edits" +msgstr "Selecionar área para edições" + +#: f.select.cc:55 f.select.cc:2462 +msgid "Press F1 for help" +msgstr "Pressione F1 para ajuda" + +#: f.select.cc:64 +msgid "" +"Select Area not supported \n" +"by this edit function" +msgstr "" +"Seleção de Área não suportada \n" +"por esta função de edição" + +#: f.select.cc:103 f.tools.cc:901 +msgid "rectangle" +msgstr "retângulo" + +#: f.select.cc:104 f.tools.cc:902 +msgid "ellipse" +msgstr "elipse" + +#: f.select.cc:110 +msgid "draw: freehand" +msgstr "desenho: mão livre" + +#: f.select.cc:111 +msgid "draw: follow edge" +msgstr "desenho: seguir borda" + +#: f.select.cc:114 +msgid "select by mouse" +msgstr "seleção por mouse" + +#: f.select.cc:116 f.select.cc:2496 +msgid "mouse radius" +msgstr "raio do mouse" + +#: f.select.cc:120 +msgid "match mouse color" +msgstr "" + +#: f.select.cc:124 +msgid "search range" +msgstr "" + +#: f.select.cc:126 +msgid "firewall" +msgstr "firewall" + +#: f.select.cc:326 f.select.cc:467 +#, c-format +msgid "exceed %d edits" +msgstr "excedeu %d edições" + +#: f.select.cc:1021 +msgid "" +"Click one time inside each enclosed area \n" +"(possible gaps in the outline will be found). \n" +"Press F1 for help." +msgstr "" +"Clique uma vez dentro de cada área inclusa \n" +"(possíveis fendas no contorno serão encontradas). \n" +"Pressione F1 para ajuda." + +#: f.select.cc:1078 +msgid "finish area" +msgstr "finalize a área" + +#: f.select.cc:1113 +msgid "searching" +msgstr "procurando" + +#: f.select.cc:1185 +msgid "outline has a gap" +msgstr "contorno tem uma fenda" + +#: f.select.cc:1189 +msgid "success" +msgstr "sucesso" + +#: f.select.cc:1440 f.select.cc:1470 +msgid "the area is not finished" +msgstr "a área não está finalizada" + +#: f.select.cc:1563 +msgid "Edge calculation in progress" +msgstr "Cálculo de borda em andamento" + +#: f.select.cc:1572 +msgid "Area Edge Calc" +msgstr "Calc. área de borda" + +#: f.select.cc:1863 +msgid "position with mouse click/drag" +msgstr "posicione o mouse clique/arraste" + +#: f.select.cc:1887 +msgid "Paste Image" +msgstr "Colar Imagem" + +#: f.select.cc:1901 +msgid "angle" +msgstr "ângulo" + +#: f.select.cc:2160 +msgid "load select area from a file" +msgstr "carregar selecionador de área de um arquivo" + +#: f.select.cc:2194 +msgid "cannot open .tiff and .info files" +msgstr "erro ao abrir arquivo .tiff e .info" + +#: f.select.cc:2213 +msgid "save select area to a file" +msgstr "salve a área selecionada em um arquivo" + +#: f.select.cc:2248 fotoxx-12.01.cc:248 +msgid "Select Whole Image" +msgstr "Selecionar toda imagem" + +#: f.select.cc:2249 +msgid "Edit Function Amplifier" +msgstr "Editar função Amplificador" + +#: f.select.cc:2463 +msgid "Edit function must be active" +msgstr "" + +#: f.select.cc:2499 +msgid "power: center" +msgstr "alimentação: centro" + +#: f.select.cc:2501 +msgid "edge" +msgstr "borda" + +#: f.select.cc:2504 +msgid "reset area" +msgstr "redefinir área" + +#: f.tools.cc:42 +msgid "" +"When editing a collection, right-click \n" +"an image or thumbnail to add or remove." +msgstr "" + +#: f.tools.cc:70 fotoxx-12.01.cc:204 +msgid "Manage Collections" +msgstr "" + +#: f.tools.cc:85 +msgid "Start new collection" +msgstr "" + +#: f.tools.cc:87 +msgid "Edit a collection" +msgstr "" + +#: f.tools.cc:89 +msgid "View a collection" +msgstr "" + +#: f.tools.cc:91 +msgid "Delete a collection" +msgstr "" + +#: f.tools.cc:95 +msgid "Editing:" +msgstr "" + +#: f.tools.cc:99 +msgid "Action:" +msgstr "" + +#: f.tools.cc:133 +msgid "New Collection" +msgstr "" + +#: f.tools.cc:156 +msgid "Edit Collection" +msgstr "Editar Coleção" + +#: f.tools.cc:172 +msgid "View Collection" +msgstr "" + +#: f.tools.cc:193 +msgid "Delete Collection" +msgstr "Excluir Coleção" + +#: f.tools.cc:196 +#, c-format +msgid "delete %s ?" +msgstr "" + +#: f.tools.cc:223 +#, c-format +msgid "add image to collection: %s" +msgstr "" + +#: f.tools.cc:225 f.tools.cc:270 +msgid "remove image from collection" +msgstr "" + +#: f.tools.cc:226 f.tools.cc:271 f.tools.cc:298 +msgid "remove and save image" +msgstr "" + +#: f.tools.cc:227 f.tools.cc:316 +msgid "insert saved images here" +msgstr "" + +#: f.tools.cc:256 +msgid "add image to collection" +msgstr "" + +#: f.tools.cc:301 +msgid "too many saved files" +msgstr "" + +#: f.tools.cc:373 fotoxx-12.01.cc:205 +msgid "Move Collections" +msgstr "" + +#: f.tools.cc:375 +msgid "old top directory" +msgstr "" + +#: f.tools.cc:378 +msgid "new top directory" +msgstr "" + +#: f.tools.cc:434 +msgid "completed" +msgstr "completo" + +#: f.tools.cc:467 +msgid "Batch Convert/Resize/Export" +msgstr "" + +#: f.tools.cc:474 +msgid "new max. width" +msgstr "nova largura máxima" + +#: f.tools.cc:481 +msgid "new file type" +msgstr "" + +#: f.tools.cc:482 +msgid "same" +msgstr "" + +#: f.tools.cc:490 +msgid "replace originals" +msgstr "substituir originais" + +#: f.tools.cc:491 +msgid "export to location" +msgstr "exportar para localização" + +#: f.tools.cc:492 +msgid "remove EXIF" +msgstr "" + +#: f.tools.cc:549 +msgid "Select directory" +msgstr "Selecionar pasta" + +#: f.tools.cc:583 +#, c-format +msgid "replace original files? (max. %d x %d)" +msgstr "substituir arquivos originais? (max. %d x %d)" + +#: f.tools.cc:590 +#, c-format +msgid "" +"copy files? (max. %d x %d) \n" +" to location %s" +msgstr "" +"copiar arquivos? (max. %d x %d) \n" +" para localização %s" + +#: f.tools.cc:601 +msgid "location is not a valid directory" +msgstr "localização não é uma pasta válida" + +#: f.tools.cc:608 f.tools.cc:3007 +#, c-format +msgid "max. size %d x %d is not reasonable" +msgstr "tamanho max. %d x %d não é razoável" + +#: f.tools.cc:654 +msgid "*** file already exists" +msgstr "" + +#: f.tools.cc:662 +msgid "*** file type not supported" +msgstr "" + +#: f.tools.cc:741 +msgid "Program ufraw-batch is required" +msgstr "Programa ufraw-batch é requerido" + +#: f.tools.cc:751 fotoxx.h:770 +msgid "Open RAW File" +msgstr "Abrir arquivo RAW" + +#: f.tools.cc:764 +msgid "Select RAW files to convert" +msgstr "Selecionar arquivos RAW para converter" + +#: f.tools.cc:769 +msgid "Choose file type" +msgstr "" + +#: f.tools.cc:888 +msgid "Press ESC to exit slide show" +msgstr "Pressione ESC para sair da apresentação" + +#: f.tools.cc:889 +msgid "show only latest file versions" +msgstr "" + +#: f.tools.cc:893 +msgid "arrow keys" +msgstr "botões de setas" + +#: f.tools.cc:894 +msgid "instant" +msgstr "imediato" + +#: f.tools.cc:895 +msgid "fade-in" +msgstr "esmaecer" + +#: f.tools.cc:896 +msgid "roll-right" +msgstr "rolar para direita" + +#: f.tools.cc:897 +msgid "roll-down" +msgstr "rolar para baixo" + +#: f.tools.cc:898 +msgid "shift-left" +msgstr "salto para esquerda" + +#: f.tools.cc:899 +msgid "venetian" +msgstr "veneziano" + +#: f.tools.cc:900 +msgid "grate" +msgstr "grade" + +#: f.tools.cc:903 +msgid "radar" +msgstr "radar" + +#: f.tools.cc:904 +msgid "jaws" +msgstr "maxilas" + +#: f.tools.cc:911 fotoxx-12.01.cc:208 +msgid "Slide Show" +msgstr "Apresentação" + +#: f.tools.cc:915 +msgid "seconds" +msgstr "segundos" + +#: f.tools.cc:919 +msgid "music file" +msgstr "arquivo de música" + +#: f.tools.cc:923 +msgid "transitions" +msgstr "" + +#: f.tools.cc:1040 +msgid "Select music file or playlist" +msgstr "Selecione arquivo de música ou lista de reprodução" + +#: f.tools.cc:1727 +msgid "Sync Files is already running" +msgstr "" + +#: f.tools.cc:1778 +msgid "" +"Run Tools > Synchronize Files so that gallery windows \n" +"will be fast and Search Images will work correctly. \n" +"You can view (not edit) images while synchronize runs." +msgstr "" + +#: f.tools.cc:1812 +msgid "no top image directory is defined" +msgstr "" + +#: f.tools.cc:1818 +msgid "top image directory is invalid" +msgstr "" + +#: f.tools.cc:1823 +msgid "no search index file is present" +msgstr "" + +#: f.tools.cc:1837 +msgid "new/modified files are present" +msgstr "" + +#: f.tools.cc:1844 +msgid "no new files found" +msgstr "" + +#: f.tools.cc:1859 fotoxx-12.01.cc:209 +msgid "Synchronize Files" +msgstr "Sincronizar Arquivos" + +#: f.tools.cc:1861 +msgid "Top Image Directory:" +msgstr "Pasta raiz das imagens:" + +#: f.tools.cc:1883 +msgid "" +"file sync is necessary.\n" +"cancel anyway?" +msgstr "" + +#: f.tools.cc:1896 +msgid "top directory is invalid" +msgstr "" + +#: f.tools.cc:2292 +msgid "Select top image directory" +msgstr "Selecionar pasta raiz de imagens" + +#: f.tools.cc:2429 fotoxx-12.01.cc:210 +msgid "Show RGB" +msgstr "Mostrar RGB" + +#: f.tools.cc:2719 fotoxx-12.01.cc:211 +msgid "Grid Lines" +msgstr "Linhas de grade" + +#: f.tools.cc:2728 +msgid "x-spacing" +msgstr "espaçamento-x" + +#: f.tools.cc:2729 +msgid "x-count" +msgstr "contagem-x" + +#: f.tools.cc:2730 +msgid "x-enable" +msgstr "" + +#: f.tools.cc:2736 +msgid "y-spacing" +msgstr "espaçamento-y" + +#: f.tools.cc:2737 +msgid "y-count" +msgstr "contagem-y" + +#: f.tools.cc:2738 +msgid "y-enable" +msgstr "" + +#: f.tools.cc:2745 +msgid "x-offset" +msgstr "" + +#: f.tools.cc:2749 +msgid "y-offset" +msgstr "" + +#: f.tools.cc:2940 fotoxx-12.01.cc:213 +msgid "E-mail Images" +msgstr "Imagens via e-mail" + +#: f.tools.cc:2947 +msgid "max. width" +msgstr "máx. largura" + +#: f.tools.cc:2948 +msgid "max. height" +msgstr "máx. altura" + +#: f.tools.cc:3093 +msgid "too many files" +msgstr "arquivos em excesso" + +#: f.tools.cc:3134 +msgid "" +"Brightness should show a gradual ramp \n" +"extending all the way to the edges." +msgstr "" +"Brilho deveria mostrar uma inclinação gradual \n" +"estendendo-se até as bordas." + +#: f.tools.cc:3174 +msgid "Monitor Check" +msgstr "Verificar Monitor" + +#: f.tools.cc:3232 fotoxx-12.01.cc:215 +msgid "Monitor Gamma" +msgstr "Monitor Gamma" + +#: f.tools.cc:3294 fotoxx-12.01.cc:216 +msgid "Brightness Distribution" +msgstr "Distribuição de Brilho" + +#: f.tools.cc:3432 +msgid "Available Translations" +msgstr "Traduções disponíveis" + +#: f.tools.cc:3436 +msgid "Set Language" +msgstr "Configurar língua" + +#: f.tools.cc:3502 +msgid "Make Launcher" +msgstr "Criar Atalho" + +#: f.tools.cc:3540 +msgid "Settings" +msgstr "" + +#: f.tools.cc:3545 +msgid "Startup Display" +msgstr "" + +#: f.tools.cc:3547 +msgid "Recent Files Gallery" +msgstr "" + +#: f.tools.cc:3548 +msgid "Previous Image Viewed" +msgstr "" + +#: f.tools.cc:3549 +msgid "Blank Window" +msgstr "" + +#: f.tools.cc:3551 +msgid "Directory Gallery" +msgstr "" + +#: f.tools.cc:3556 +msgid "Image File" +msgstr "" + +#: f.tools.cc:3562 +msgid "Toolbar Style" +msgstr "Estilo da barra de ferramentas" + +#: f.tools.cc:3563 f.transform.cc:1300 +msgid "Text" +msgstr "Texto" + +#: f.tools.cc:3564 +msgid "Icons" +msgstr "" + +#: f.tools.cc:3565 +msgid "Both" +msgstr "" + +#: f.tools.cc:3568 +msgid "Warn Overwrite" +msgstr "" + +#: f.tools.cc:3639 +msgid "startup directory is invalid" +msgstr "" + +#: f.tools.cc:3650 +msgid "startup file is invalid" +msgstr "" + +#: f.tools.cc:3707 +msgid "Select startup directory" +msgstr "" + +#: f.tools.cc:3715 +msgid "Select startup image file" +msgstr "" + +#: f.transform.cc:50 +msgid "Use buttons or drag right edge with mouse" +msgstr "Use os botões ou arrante a borda direita com o mouse" + +#: f.transform.cc:60 fotoxx-12.01.cc:252 +msgid "Rotate Image" +msgstr "Rotacioanar" + +#: f.transform.cc:64 +msgid "degrees" +msgstr "graus" + +#: f.transform.cc:80 f.transform.cc:124 +msgid "Trim" +msgstr "Aparar" + +#: f.transform.cc:81 f.transform.cc:2289 f.transform.cc:3120 +#: f.transform.cc:3383 f.transform.cc:3644 +msgid "Grid" +msgstr "" + +#: f.transform.cc:123 +msgid "Undo Trim" +msgstr "Desfazer recorte" + +#: f.transform.cc:139 +#, c-format +msgid "degrees: %.1f" +msgstr "graus: %.1f" + +#: f.transform.cc:286 +msgid "gold" +msgstr "áurea" + +#: f.transform.cc:334 +msgid "Drag middle to move, drag corners to resize." +msgstr "" +"Arraste pelo centro para mover, arraste as estremidades para redimensionar." + +#: f.transform.cc:348 fotoxx-12.01.cc:253 +msgid "Trim Image" +msgstr "Recortar/Aparar bordas" + +#: f.transform.cc:348 +msgid "customize" +msgstr "customizar" + +#: f.transform.cc:359 +msgid "ratio" +msgstr "taxa" + +#: f.transform.cc:363 +msgid "Lock Ratio" +msgstr "Travar taxa" + +#: f.transform.cc:368 +msgid "invert" +msgstr "inverter" + +#: f.transform.cc:890 +msgid "Trim Buttons" +msgstr "Aparar rodapés" + +#: f.transform.cc:1064 +msgid "Lock aspect ratio" +msgstr "Manter proporção" + +#: f.transform.cc:1072 fotoxx-12.01.cc:255 +msgid "Resize Image" +msgstr "Redimensionar" + +#: f.transform.cc:1095 fotoxx-12.01.cc:326 +msgid "Prev" +msgstr "Anterior" + +#: f.transform.cc:1245 +msgid "" +"Enter text, click/drag on image.\n" +"Right click to remove" +msgstr "" +"Insira um texto, clique/arraste na imagem.\n" +"Clique com o botão direito para remover" + +#: f.transform.cc:1294 fotoxx-12.01.cc:256 +msgid "Annotate Image" +msgstr "Tomar nota" + +#: f.transform.cc:1307 +msgid "Size" +msgstr "Tamanho" + +#: f.transform.cc:1310 +msgid "Angle" +msgstr "Ângulo" + +#: f.transform.cc:1321 fotoxx.h:741 +msgid "Color" +msgstr "Cor" + +#: f.transform.cc:1322 +msgid "Transparency" +msgstr "Transparência" + +#: f.transform.cc:1325 +msgid "text" +msgstr "texto" + +#: f.transform.cc:1330 +msgid "backing" +msgstr "fundo" + +#: f.transform.cc:1333 +msgid "" +"Outline\n" +" Width" +msgstr "" +"Contorno\n" +" Largura" + +#: f.transform.cc:1335 +msgid "outline" +msgstr "contorno" + +#: f.transform.cc:1342 +msgid "Annotation File:" +msgstr "Arquivo de Comentário:" + +#: f.transform.cc:1416 +msgid "select font" +msgstr "selecionar fonte" + +#: f.transform.cc:2045 fotoxx-12.01.cc:257 +msgid "Flip Image" +msgstr "Virar" + +#: f.transform.cc:2049 f.transform.cc:2281 +msgid "horizontal" +msgstr "horizontal" + +#: f.transform.cc:2050 f.transform.cc:2280 +msgid "vertical" +msgstr "vertical" + +#: f.transform.cc:2155 fotoxx-12.01.cc:258 +msgid "Make Negative" +msgstr "Fazer Negativo" + +#: f.transform.cc:2158 +msgid "black/white positive" +msgstr "preto/branco positivo" + +#: f.transform.cc:2159 +msgid "black/white negative" +msgstr "preto/branco negativo" + +#: f.transform.cc:2160 +msgid "color positive" +msgstr "cor positiva" + +#: f.transform.cc:2161 +msgid "color negative" +msgstr "cor negativa" + +#: f.transform.cc:2272 fotoxx-12.01.cc:259 +msgid "Unbend Image" +msgstr "Desempenar" + +#: f.transform.cc:2282 +msgid "linear" +msgstr "linear" + +#: f.transform.cc:2285 +msgid "curved" +msgstr "curvo" + +#: f.transform.cc:2544 +msgid "" +" Click the four corners of a tetragon area. Press [apply]. \n" +" The image is warped to make the tetragon into a rectangle." +msgstr "" + +#: f.transform.cc:2556 fotoxx-12.01.cc:260 +msgid "Keystone Correction" +msgstr "" + +#: f.transform.cc:2724 +msgid "must have 4 corners" +msgstr "" + +#: f.transform.cc:2847 +msgid "" +" Select an area to warp using select area function. \n" +" Press [start warp] and pull area with mouse. \n" +" Make multiple mouse pulls until satisfied. \n" +" When finished, select another area or press [done]." +msgstr "" +" Selecione a área a distorcer usando a função de seleção. \n" +" Precione [iniciar distorção] e puxe a área com o mouse. \n" +" Faça vários ajustes até que esteja satisfeito. \n" +" Quando terminar, selecione outra área e precione [pronto]." + +#: f.transform.cc:2859 fotoxx-12.01.cc:261 +msgid "Warp Image (area)" +msgstr "Distorcer (área)" + +#: f.transform.cc:2864 +msgid "start warp" +msgstr "iniciar distorção" + +#: f.transform.cc:2931 +msgid "no active Select Area" +msgstr "" + +#: f.transform.cc:3099 f.transform.cc:3362 +msgid "" +" Pull an image position using the mouse. \n" +" Make multiple mouse pulls until satisfied. \n" +" When finished, press [done]." +msgstr "" +" Puxe uma posição da usando o mouse. \n" +" Faça vários ajustes até que esteja satisfeito. \n" +" Quando terminar, precione [pronto]." + +#: f.transform.cc:3112 fotoxx-12.01.cc:262 +msgid "Warp Image (curved)" +msgstr "Distorcer (curvo)" + +#: f.transform.cc:3375 fotoxx-12.01.cc:263 +msgid "Warp Image (linear)" +msgstr "Distorcer (linear)" + +#: f.transform.cc:3628 +msgid "" +" Pull on an image corner using the mouse. \n" +" Make multiple mouse pulls until satisfied. \n" +" When finished, press [done]." +msgstr "" +" Puxe um canto da imgem usando o mouse. \n" +" Faça vários ajustes até que esteja satisfeito. \n" +" Quando terminar, precione [pronto]." + +#: f.transform.cc:3639 fotoxx-12.01.cc:264 +msgid "Warp Image (affine)" +msgstr "Distorcer (afim)" + +#: fotoxx-12.01.cc:185 +msgid "File" +msgstr "Arquivo" + +#: fotoxx-12.01.cc:186 fotoxx-12.01.cc:324 +msgid "Image Gallery" +msgstr "Galeria de Imagens" + +#: fotoxx-12.01.cc:187 +msgid "Clone 50/50" +msgstr "Clonar 50/50" + +#: fotoxx-12.01.cc:188 +msgid "Clone Overlay" +msgstr "Clonar Sobreposta" + +#: fotoxx-12.01.cc:190 +msgid "Open in New Window" +msgstr "Abrir em nova janela" + +# msgstr "Abrir próximo arquivo" +#: fotoxx-12.01.cc:191 fotoxx-12.01.cc:326 +msgid "Open Previous File" +msgstr "Abrir arquivo anterior" + +#: fotoxx-12.01.cc:192 +msgid "Open Recent File" +msgstr "Abrir arquivo recente" + +#: fotoxx-12.01.cc:193 fotoxx-12.01.cc:334 +msgid "Save to Same File" +msgstr "Salvar no mesmo arquivo" + +#: fotoxx-12.01.cc:194 fotoxx-12.01.cc:335 +msgid "Save to New Version" +msgstr "Salvar nova versão" + +#: fotoxx-12.01.cc:195 fotoxx-12.01.cc:336 +msgid "Save to New File" +msgstr "Salvar novo arquivo" + +#: fotoxx-12.01.cc:197 +msgid "Trash Image File" +msgstr "Mover arquivo para lixeira" + +#: fotoxx-12.01.cc:199 +msgid "Batch Rename Files" +msgstr "Renomear vários arquivos" + +#: fotoxx-12.01.cc:200 +msgid "Print Image File" +msgstr "Imprimir" + +#: fotoxx-12.01.cc:201 fotoxx-12.01.cc:340 +msgid "Quit fotoxx" +msgstr "Sair do fotoxx" + +#: fotoxx-12.01.cc:203 +msgid "Tools" +msgstr "Ferramentas" + +#: fotoxx-12.01.cc:206 +msgid "Batch Convert" +msgstr "" + +#: fotoxx-12.01.cc:207 +msgid "Convert RAW files" +msgstr "Converter arquivos RAW" + +#: fotoxx-12.01.cc:212 +msgid "Burn Images to CD/DVD" +msgstr "Gravar imagens em CD/DVD" + +#: fotoxx-12.01.cc:214 +msgid "Check Monitor" +msgstr "Checar Monitor" + +#: fotoxx-12.01.cc:217 +msgid "Change Language" +msgstr "Trocar língua" + +#: fotoxx-12.01.cc:219 +msgid "Menu and Launcher" +msgstr "" + +#: fotoxx-12.01.cc:220 +msgid "User Settings" +msgstr "" + +#: fotoxx-12.01.cc:221 +msgid "Memory Usage" +msgstr "Uso de memória" + +#: fotoxx-12.01.cc:224 +msgid "Edit Caption/Comments" +msgstr "Editar Legendas/Comentários" + +#: fotoxx-12.01.cc:229 +msgid "View Info (short)" +msgstr "Ver Info (curto)" + +#: fotoxx-12.01.cc:230 +msgid "View Info (long)" +msgstr "Ver Info (longo)" + +#: fotoxx-12.01.cc:233 +msgid "Search Images" +msgstr "Procurar Imagens" + +#: fotoxx-12.01.cc:234 +msgid "Search Metadata" +msgstr "" + +#: fotoxx-12.01.cc:236 fotoxx-12.01.cc:237 fotoxx.h:786 +msgid "Select" +msgstr "Selecionar" + +#: fotoxx-12.01.cc:238 fotoxx.h:788 +msgid "Show" +msgstr "Mostrar" + +#: fotoxx-12.01.cc:239 fotoxx.h:761 +msgid "Hide" +msgstr "Ocultar" + +#: fotoxx-12.01.cc:240 fotoxx.h:752 +msgid "Enable" +msgstr "Habilitar" + +#: fotoxx-12.01.cc:241 fotoxx.h:748 +msgid "Disable" +msgstr "Desabilitar" + +#: fotoxx-12.01.cc:242 fotoxx.h:763 +msgid "Invert" +msgstr "Inverter" + +#: fotoxx-12.01.cc:243 fotoxx.h:796 +msgid "Unselect" +msgstr "Deselecionar" + +#: fotoxx-12.01.cc:244 fotoxx.h:743 +msgid "Copy" +msgstr "Copiar" + +#: fotoxx-12.01.cc:245 fotoxx.h:771 +msgid "Paste" +msgstr "Colar" + +#: fotoxx-12.01.cc:247 fotoxx-12.01.cc:334 fotoxx.h:783 +msgid "Save" +msgstr "Salvar" + +#: fotoxx-12.01.cc:249 +msgid "Select and Edit" +msgstr "Selecionar e Editar" + +#: fotoxx-12.01.cc:251 +msgid "Transform" +msgstr "Transformar" + +#: fotoxx-12.01.cc:254 +msgid "Auto-Trim Image" +msgstr "" + +#: fotoxx-12.01.cc:266 +msgid "Retouch" +msgstr "Retocar" + +#: fotoxx-12.01.cc:267 +msgid "Brightness/Color" +msgstr "Brilho/Cor" + +#: fotoxx-12.01.cc:268 +msgid "Gamma Curves" +msgstr "" + +#: fotoxx-12.01.cc:269 +msgid "Expand Brightness" +msgstr "Expandir Brilho" + +#: fotoxx-12.01.cc:270 +msgid "Flatten Brightness" +msgstr "Reduzir Brilho" + +#: fotoxx-12.01.cc:271 +msgid "Brightness Ramp" +msgstr "Curvas de brilho" + +#: fotoxx-12.01.cc:273 +msgid "White Balance" +msgstr "Balanço de branco" + +#: fotoxx-12.01.cc:274 +msgid "Match Colors" +msgstr "Mesclar Cores" + +#: fotoxx-12.01.cc:277 +msgid "Red Eyes" +msgstr "Olhos vermelhos" + +#: fotoxx-12.01.cc:278 +msgid "Blur Image" +msgstr "Embaçar" + +#: fotoxx-12.01.cc:280 +msgid "Reduce Noise" +msgstr "Reduzir ruído" + +#: fotoxx-12.01.cc:286 +msgid "Art" +msgstr "Arte" + +#: fotoxx-12.01.cc:287 +msgid "Color Depth" +msgstr "Resolução de cor" + +#: fotoxx-12.01.cc:288 +msgid "Drawing" +msgstr "Desenho" + +#: fotoxx-12.01.cc:289 +msgid "Outlines" +msgstr "Contornos" + +#: fotoxx-12.01.cc:290 +msgid "Embossing" +msgstr "Alto-relevo" + +#: fotoxx-12.01.cc:291 +msgid "Tiles" +msgstr "Ladrilhos" + +#: fotoxx-12.01.cc:292 +msgid "Dots" +msgstr "Pontos" + +#: fotoxx-12.01.cc:293 +msgid "Painting" +msgstr "Pintura" + +#: fotoxx-12.01.cc:295 +msgid "Combine" +msgstr "Combinar" + +#: fotoxx-12.01.cc:296 +msgid "High Dynamic Range" +msgstr "Grande Alcance Dinâmico (HDR)" + +#: fotoxx-12.01.cc:297 +msgid "High Depth of Field" +msgstr "Alta Profundidade de Campo (HDF)" + +#: fotoxx-12.01.cc:298 +msgid "Stack / Paint" +msgstr "Pilha / Pintura" + +#: fotoxx-12.01.cc:299 +msgid "Stack / Noise" +msgstr "Pilha / Ruído" + +#: fotoxx-12.01.cc:300 +msgid "Panorama" +msgstr "Panorama" + +#: fotoxx-12.01.cc:301 +msgid "Vertical Panorama" +msgstr "Panorama Vertical" + +#: fotoxx-12.01.cc:304 +msgid "Edit Plugins" +msgstr "Editar Plugins" + +#: fotoxx-12.01.cc:313 fotoxx-12.01.cc:341 fotoxx-12.01.cc:3026 +msgid "Help" +msgstr "Ajuda" + +#: fotoxx-12.01.cc:314 fotoxx-12.01.cc:3016 +msgid "About" +msgstr "Sobre" + +#: fotoxx-12.01.cc:315 fotoxx-12.01.cc:3020 +msgid "User Guide" +msgstr "Guia de usuário" + +#: fotoxx-12.01.cc:316 fotoxx-12.01.cc:3023 +msgid "User Guide Changes" +msgstr "" + +#: fotoxx-12.01.cc:317 fotoxx-12.01.cc:3032 +msgid "Edit Functions Summary" +msgstr "" + +#: fotoxx-12.01.cc:318 fotoxx-12.01.cc:3035 +msgid "Change Log" +msgstr "Relatório de mudanças" + +#: fotoxx-12.01.cc:319 fotoxx-12.01.cc:3038 +msgid "Translations" +msgstr "" + +#: fotoxx-12.01.cc:320 fotoxx-12.01.cc:3041 +msgid "Home Page" +msgstr "Página na web" + +#: fotoxx-12.01.cc:324 +msgid "Gallery" +msgstr "Galeria" + +#: fotoxx-12.01.cc:327 fotoxx.h:767 +msgid "Next" +msgstr "Próximo" + +#: fotoxx-12.01.cc:327 +msgid "Open Next File" +msgstr "Abrir próximo arquivo" + +#: fotoxx-12.01.cc:328 +msgid "Zoom-in (bigger)" +msgstr "Aproximar (aumentar)" + +#: fotoxx-12.01.cc:329 +msgid "Zoom-out (smaller)" +msgstr "Distanciar (diminuir)" + +#: fotoxx-12.01.cc:330 fotoxx.h:794 +msgid "Undo" +msgstr "Desfazer" + +#: fotoxx-12.01.cc:330 +msgid "Undo One Edit" +msgstr "Desfazer uma edição" + +#: fotoxx-12.01.cc:331 fotoxx.h:779 +msgid "Redo" +msgstr "Refazer" + +#: fotoxx-12.01.cc:331 +msgid "Redo One Edit" +msgstr "Refazer uma edição" + +#: fotoxx-12.01.cc:335 +msgid "Save+V" +msgstr "Salvar+V" + +#: fotoxx-12.01.cc:336 +msgid "Save+F" +msgstr "Salvar+F" + +#: fotoxx-12.01.cc:337 +msgid "Move Image to Trash" +msgstr "Mover para lixeira" + +#: fotoxx-12.01.cc:337 +msgid "Trash" +msgstr "Lixeira" + +#: fotoxx-12.01.cc:340 +msgid "Quit" +msgstr "Sair" + +#: fotoxx-12.01.cc:341 +msgid "Fotoxx Essentials" +msgstr "O básico do Fotoxx" + +#: fotoxx-12.01.cc:448 +msgid "first time startup" +msgstr "" + +#: fotoxx-12.01.cc:1944 +msgid "Exceed 50 anchor points" +msgstr "Excedeu 50 pontos de ancoragem" + +#: fotoxx-12.01.cc:2129 +msgid "load curve from a file" +msgstr "carregar curva de arquivo" + +#: fotoxx-12.01.cc:2182 +msgid "curve file is invalid" +msgstr "arquivo de curva inválido" + +#: fotoxx-12.01.cc:2187 +msgid "curve file has different no. of curves" +msgstr "arquivo de curva tem número de curvas diferente" + +#: fotoxx-12.01.cc:2202 +msgid "save curve to a file" +msgstr "salvar curva para arquivo" + +#: fotoxx-12.01.cc:2337 +msgid "cannot parallel edit" +msgstr "não se pode editar paralelamente" + +#: fotoxx-12.01.cc:2347 +msgid "" +"exiftool is not installed \n" +"edited images will lose EXIF data" +msgstr "" +"exiftool não está instalado \n" +"imagens editadas perderão informações EXIF" + +#: fotoxx-12.01.cc:2353 +msgid "Too many edits, please save image" +msgstr "Muitas edições, favor salvar imagem" + +#: fotoxx-12.01.cc:2358 +msgid "" +"Select area cannot be kept.\n" +"Continue?" +msgstr "" +"Área selecionada não pode ser capturada.\n" +"Continuar?" + +#: fotoxx-12.01.cc:2366 +msgid "" +"Select area not active.\n" +"Continue?" +msgstr "" +"Área selecionada não ativa.\n" +"Continuar?" + +#: fotoxx-12.01.cc:2837 +msgid "Discard edits?" +msgstr "" + +#: fotoxx-12.01.cc:2838 +msgid "" +"This action will discard current edits.\n" +"Continue to discard edits.\n" +"Go Back to keep edits." +msgstr "" + +#: fotoxx-12.01.cc:2841 +msgid "Continue" +msgstr "" + +#: fotoxx-12.01.cc:2842 +msgid "Go Back" +msgstr "" + +#: fotoxx-12.01.cc:3659 +msgid "cannot open thumbnail file" +msgstr "erro ao abrir miniatura de arquivo" + +#: fotoxx-12.01.cc:3870 fotoxx-12.01.cc:3992 +msgid "TIFF open failure" +msgstr "TIFF, Erro ao abrir" + +#: fotoxx-12.01.cc:3886 +#, c-format +msgid "TIFF bits/color=%d not supported" +msgstr "TIFF bits/cor=%d não suportado" + +#: fotoxx-12.01.cc:3901 fotoxx-12.01.cc:3939 +msgid "TIFF read failure" +msgstr "TIFF, Erro ao carregar" + +#: fotoxx-12.01.cc:4051 +msgid "TIFF write failure" +msgstr "TIFF, Erro ao gravar" + +#: fotoxx-12.01.cc:4071 +msgid "file type not supported" +msgstr "tipo de arquivo não suportado" + +#: fotoxx-12.01.cc:4178 +msgid "pixbuf write failure" +msgstr "escrita do pixbuf falhou" + +#: fotoxx.h:728 +msgid "absolute" +msgstr "" + +#: fotoxx.h:730 +msgid "Add All" +msgstr "Adicionar todos" + +#: fotoxx.h:732 +msgid "Amount" +msgstr "Quantidade" + +#: fotoxx.h:733 +msgid "Apply" +msgstr "Aplicar" + +#: fotoxx.h:734 +msgid "Black" +msgstr "" + +#: fotoxx.h:735 +msgid "Blend Width" +msgstr "Quantidade de mistura" + +#: fotoxx.h:737 +msgid "Brightness" +msgstr "Briho" + +#: fotoxx.h:738 +msgid "Browse" +msgstr "Procurar" + +#: fotoxx.h:739 +msgid "Cancel" +msgstr "Cancelar" + +#: fotoxx.h:740 +msgid "Clear" +msgstr "Limpar" + +#: fotoxx.h:742 +msgid "Commit" +msgstr "" + +#: fotoxx.h:744 +msgid "Curve File:" +msgstr "Arquivo de curva:" + +#: fotoxx.h:745 +msgid "Cut" +msgstr "" + +#: fotoxx.h:746 +msgid "Darker Areas" +msgstr "Áreas mais escuras" + +#: fotoxx.h:747 +msgid "Delete" +msgstr "Exlcuir" + +#: fotoxx.h:749 +#, c-format +msgid "" +"Discard special gallery list? \n" +" %s" +msgstr "" +"Descartar lista de galleria especial? \n" +" %s" + +#: fotoxx.h:750 +msgid "Done" +msgstr "Pronto" + +#: fotoxx.h:751 +msgid "Edit" +msgstr "Editar" + +#: fotoxx.h:753 +msgid "Erase" +msgstr "" + +#: fotoxx.h:754 +msgid "package libimage-exiftool-perl is required" +msgstr "pacote libimage-exiftool-perl requerido" + +#: fotoxx.h:755 +msgid "Fetch" +msgstr "Buscar" + +#: fotoxx.h:756 +msgid "Finish" +msgstr "Finalizar" + +#: fotoxx.h:757 +msgid "Font" +msgstr "Fonte" + +#: fotoxx.h:759 +msgid "Height" +msgstr "Altura" + +#: fotoxx.h:760 +msgid "histogram" +msgstr "histograma" + +#: fotoxx.h:762 +msgid "Insert" +msgstr "Inserir" + +#: fotoxx.h:764 +msgid "Lighter Areas" +msgstr "Áreas mais claras" + +#: fotoxx.h:765 +msgid "limit" +msgstr "limite" + +#: fotoxx.h:766 +msgid "New" +msgstr "" + +#: fotoxx.h:768 +msgid "OK" +msgstr "OK" + +#: fotoxx.h:772 +msgid "Pause" +msgstr "Pausar" + +#: fotoxx.h:773 +msgid "Percent" +msgstr "Percentagem" + +#: fotoxx.h:774 +msgid "Presets" +msgstr "Predefinições" + +#: fotoxx.h:775 +msgid "Proceed" +msgstr "Continuar" + +#: fotoxx.h:777 +msgid "range" +msgstr "variação" + +#: fotoxx.h:780 +msgid "Reduce" +msgstr "Reduzir" + +#: fotoxx.h:782 +msgid "Reset" +msgstr "" + +#: fotoxx.h:784 +msgid "Unknown file type, save as tiff/jpeg/png to edit" +msgstr "Tipo de arquivo desconhecido, Salvar como tiff/jpeg/png para editar" + +#: fotoxx.h:785 +msgid "Search" +msgstr "Buscar" + +#: fotoxx.h:789 +msgid "Start" +msgstr "Iniciar" + +#: fotoxx.h:790 +msgid "Threshold" +msgstr "Limiar" + +#: fotoxx.h:791 +#, c-format +msgid "exceed %d files" +msgstr "" + +#: fotoxx.h:792 +msgid "Undo All" +msgstr "Desfazer tudo" + +#: fotoxx.h:793 +msgid "Undo Last" +msgstr "Desfazer último" + +#: fotoxx.h:795 +msgid "Unfinish" +msgstr "" + +#: fotoxx.h:797 +msgid "View" +msgstr "" + +#: fotoxx.h:798 +msgid "White" +msgstr "" + +#: fotoxx.h:799 +msgid "Width" +msgstr "Largura" + +#: zfuncs.cc:3252 +#, c-format +msgid "help file not found: %s" +msgstr "arquivo de ajuda não encontrado: %s" + +#: zfuncs.cc:3664 zfuncs.cc:7315 +#, c-format +msgid "cannot open file %s" +msgstr "não foi possível abrir arquivo %s" + +#: zfuncs.cc:3697 +msgid "save screen to file" +msgstr "salvar tela para arquivo" + +#: zfuncs.cc:6222 +msgid "No" +msgstr "Não" + +#: zfuncs.cc:6222 +msgid "Yes" +msgstr "Sim" + +#: zfuncs.cc:6447 +msgid "open" +msgstr "abrir" + +#: zfuncs.cc:6452 +msgid "choose" +msgstr "escolher" + +#: zfuncs.cc:6457 +msgid "save" +msgstr "salvar" + +#: zfuncs.cc:6463 +msgid "open folder" +msgstr "abrir pasta" + +#: zfuncs.cc:6468 +msgid "create folder" +msgstr "criar pasta" + +#: zfuncs.cc:6474 +msgid "hidden" +msgstr "oculto" + +#: zfuncs.cc:6535 +msgid "JPG quality 0-100" +msgstr "Qualidade JPG 0-100" + +#: zfuncs.cc:6728 zfuncs.cc:6741 +msgid "margins" +msgstr "" + +#: zfuncs.cc:6737 +msgid "top" +msgstr "topo" + +#: zfuncs.cc:6738 +msgid "bottom" +msgstr "rodapé" + +#: zfuncs.cc:6739 +msgid "left" +msgstr "esquerda" + +#: zfuncs.cc:6740 +msgid "right" +msgstr "direita" + +#: zfuncs.cc:7202 +msgid "" +"Initial parameters file created. \n" +"Inspect and revise if necessary." +msgstr "" +"Arquivo de parâmetros iniciais criado. \n" +"Inspecione e revise se necessário." + +#: zfuncs.cc:7218 +msgid "load parameters from a file" +msgstr "carregar parâmetros de arquivo" + +#: zfuncs.cc:7287 +msgid "save parameters to a file" +msgstr "salvar parâmetros para um arquivo" + +#: zfuncs.cc:7425 zfuncs.cc:7431 zfuncs.cc:7437 zfuncs.cc:7443 +msgid "edit parameters" +msgstr "editar parâmetros" + +#: zfuncs.cc:7426 zfuncs.cc:7432 +msgid "" +"list\n" +"all" +msgstr "" +"lista\n" +"todos" + +#: zfuncs.cc:7426 zfuncs.cc:7432 zfuncs.cc:7438 zfuncs.cc:7444 +msgid "" +"load\n" +"file" +msgstr "" +"carregar\n" +"arquivo" + +#: zfuncs.cc:7426 zfuncs.cc:7432 zfuncs.cc:7438 zfuncs.cc:7444 +msgid "" +"save\n" +"file" +msgstr "" +"salvar\n" +"arquivo" + +#: zfuncs.cc:7427 zfuncs.cc:7439 +msgid "" +"add\n" +"new" +msgstr "" +"adicionar\n" +"novo" + +#: zfuncs.cc:7427 zfuncs.cc:7433 zfuncs.cc:7439 zfuncs.cc:7445 +msgid "apply" +msgstr "aplicar" + +#: zfuncs.cc:7479 +msgid "apply?" +msgstr "aplicar?" + +#: zfuncs.cc:7536 +msgid "(new parm name)" +msgstr "(novo nome de parâmetro)" + +#: zfuncs.cc:7536 +msgid "add parameter" +msgstr "adicionar parâmetro" + +#~ msgid "Brightness Graph" +#~ msgstr "Gráfico de Brilho" + +#~ msgid "Add Menu and Launcher" +#~ msgstr "Adicionar Menu e Atalho" + +#~ msgid "Batch Resize/Export" +#~ msgstr "Redimensionar/Exportar várias " + +#~ msgid "select by color" +#~ msgstr "seleção por cor" + +#~ msgid "radius" +#~ msgstr "raio" + +#~ msgid "match" +#~ msgstr "equiparar" + +#~ msgid "Search results file error %s" +#~ msgstr "Erro no arquivo de resultados de busca %s" + +#~ msgid "Batch Resize" +#~ msgstr "Redimencionar vários" + +#~ msgid "new max. height" +#~ msgstr "nova altura máxima" + +#~ msgid "copy EXIF" +#~ msgstr "copiar info. EXIF" + +#~ msgid "new file already exists" +#~ msgstr "novo arquivo já existe" + +#~ msgid "Select area first" +#~ msgstr "Selecione a área primeiro" + +#~ msgid "open a file" +#~ msgstr "abrir um arquivo" + +#~ msgid "paper format is crazy" +#~ msgstr "formato do papel é louco" + +#~ msgid "margins:" +#~ msgstr "margens:" + +#~ msgid "landscape" +#~ msgstr "paisagem" + +#~ msgid "portrait" +#~ msgstr "retrato" + +#~ msgid "paper format" +#~ msgstr "formato do papel" + +#~ msgid "printer ID" +#~ msgstr "ID de impressora" + +#~ msgid "print" +#~ msgstr "imprimir" + +#~ msgid "" +#~ "Discard current gallery list? \n" +#~ " %s" +#~ msgstr "" +#~ "Discartar lista de galeria atual? \n" +#~ " %s" + +#~ msgid "Edit Comments" +#~ msgstr "Editar Comentários" + +#~ msgid "Edit Caption" +#~ msgstr "Editar Legenda" + +#~ msgid "Auto-search lens mm and bow" +#~ msgstr "Procura automática de mm e curvatura de lente" + +#~ msgid "Merge the images together" +#~ msgstr "Mesclar imagens" + +#~ msgid "use two s only" +#~ msgstr "usar duas imagens apenas" + +#~ msgid "tags index arquivo error: %s" +#~ msgstr "erro no arquivo de índices: %s" + +#~ msgid "select image files to add tags" +#~ msgstr "Selecionar arquivos de imagem para etiquetar" + +#~ msgid "select files" +#~ msgstr "Selecionar arquivos" + +#~ msgid "rename files" +#~ msgstr "renomear arquivos" + +#~ msgid "freehand draw" +#~ msgstr "desenho a mão livre" + +#~ msgid "follow edge" +#~ msgstr "seguir borda" + +#~ msgid "" +#~ "exiftool missing, please install \n" +#~ " package libimage-exiftool-perl" +#~ msgstr "" +#~ "exiftool faltando, favor instalar \n" +#~ " pacote libimage-exiftool-perl" + +#~ msgid "color range" +#~ msgstr "variação de cor" + +#~ msgid "browse" +#~ msgstr "procurar" + +#~ msgid "base image" +#~ msgstr "imagem base" + +#~ msgid "add tags" +#~ msgstr "adicionar etiquetas" + +#~ msgid "TIFF colors=%d depth=%d not supported" +#~ msgstr "TIFF, cores=%d e intensidade=%d não suportadas" + +#~ msgid "Read File" +#~ msgstr "Ler arquivo" + +#~ msgid "Package ufraw required for this function" +#~ msgstr "Pacote ufraw requerido para esta função" + +#~ msgid "Fix Image Perspective" +#~ msgstr "Acertar perspectiva de imagem" + +#~ msgid "" +#~ "Convert tags to new standard now?\n" +#~ "Are your image files backed-up?" +#~ msgstr "" +#~ "Converter etiquetas para novo padrão agora?\n" +#~ "Suas imagens possuem cópia de segurança?" + +#~ msgid "Burn" +#~ msgstr "Gravar" + +#~ msgid "color intensity" +#~ msgstr "Intensidade de cor" + +#~ msgid "Batch Delete Tags" +#~ msgstr "Excluir várias etiquetas" + +#~ msgid "Clip Brightness" +#~ msgstr "Limitar Brilho" + +#~ msgid "" +#~ "position image\n" +#~ "with mouse drag" +#~ msgstr "" +#~ "posicione a imagem\n" +#~ "arrastando com o mouse" + +#~ msgid "Warp Image in Selected Area" +#~ msgstr "Distorcer imagem em área selecionada" + +#~ msgid "Warp Image (curvy)" +#~ msgstr "Distorcer (curvo)" + +#~ msgid "Warp Image" +#~ msgstr "Distorcer imagem" + +#~ msgid "Warp Area" +#~ msgstr "Distorcer área" + +#~ msgid "Open File" +#~ msgstr "Abrir Arquivo" + +#~ msgid "" +#~ " Pull on an image edge using the mouse. \n" +#~ " Make multiple mouse pulls until satisfied. \n" +#~ " When finished, press [done]." +#~ msgstr "" +#~ " Puxe uma borda da imagem usando o mouse \n" +#~ " Faça vários ajustes até que esteja satisfeito. \n" +#~ " Quando terminar, precione [pronto]." + +#~ msgid "match any tag" +#~ msgstr "condizer com qualquer etiqueta" + +#~ msgid "match all tags" +#~ msgstr "condizer com todas etiquetas" + +#~ msgid "comments" +#~ msgstr "comentários" + +#~ msgid "Tags" +#~ msgstr "Etiquetas" + +#~ msgid "Suspend" +#~ msgstr "Suspender" + +#~ msgid "Set Tile and Gap Size" +#~ msgstr "Configurar ladrilho e espaçamento" + +#~ msgid "Search Tags" +#~ msgstr "Buscar etiquetas" + +#~ msgid "Resume" +#~ msgstr "Retomar" + +#~ msgid "Edit User Comments" +#~ msgstr "Editar Comentários de Usuário" + +#~ msgid "Edit EXIF data" +#~ msgstr "Editar informações EXIF" + +#~ msgid "EXIF data" +#~ msgstr "Informações EXIF" + +#~ msgid "Delete EXIF data" +#~ msgstr "Excluir informações EXIF" + +#~ msgid "Basic EXIF data" +#~ msgstr "Informações EXIF básicas" + +#~ msgid "All EXIF data" +#~ msgstr "Toda informação EXIF" + +#~ msgid "/path*/file*" +#~ msgstr "/caminho*/arquivo*" + +#~ msgid "transparency" +#~ msgstr "transparência" + +#~ msgid "foreground" +#~ msgstr "primeiro plano" + +#~ msgid "background" +#~ msgstr "fundo" + +#~ msgid "annotation file:" +#~ msgstr "arquivo de comentário:" + +#~ msgid "tags index file error: %s" +#~ msgstr "erro no arquivo índice de etiquetas: %s" + +#~ msgid "save select area as a file" +#~ msgstr "salvar selecionador de área em arquivo" + +#~ msgid "new tags index will now be created" +#~ msgstr "novo índice de etiquetas será criado agora" + +#~ msgid "manage tags" +#~ msgstr "gerenciar etiquetas" + +#~ msgid "color select firewall" +#~ msgstr "selecionar cor do firewall" + +#~ msgid "cannot read .dist file" +#~ msgstr "Erro ao ler arquivo .dist" + +#~ msgid "brightness to clip (percent)" +#~ msgstr "Brilho a apagar (percentagem)" + +#~ msgid "Use F1 for context help" +#~ msgstr "Use F1 para ajuda contextualizada" + +#~ msgid "Stack" +#~ msgstr "Pilha" + +#~ msgid "Rebuild Tags Index" +#~ msgstr "Reconstruir índice de etiquetas" + +#~ msgid "No tags index file" +#~ msgstr "Nenhum arquivo índice de etiquetas" + +#~ msgid "" +#~ "New tags file already exists! \n" +#~ "Proceed anyway?" +#~ msgstr "" +#~ "Novo arquivo de etiquetas já existe! \n" +#~ "Continuar assim mesmo?" + +#~ msgid "HDR" +#~ msgstr "HDR" + +#~ msgid "HDF" +#~ msgstr "HDF" + +#~ msgid "" +#~ "Convert tags to new standard now? \n" +#~ "Are your image files backed-up?" +#~ msgstr "" +#~ "Converter etiquetas para novo padrão agora? \n" +#~ "Você possui cópia de segurança das imagens?" + +#~ msgid "Convert tags to new standard" +#~ msgstr "Converter etiquetas para novo padrão" + +#~ msgid "Convert Tags !!!" +#~ msgstr "Converter etiquetas!" + +#~ msgid "Constrain" +#~ msgstr "Restrição" + +#~ msgid "Area" +#~ msgstr "Área" + +#~ msgid "target group area" +#~ msgstr "área de grupo de destino" + +#~ msgid "vertical unbend" +#~ msgstr "desempeno vertical" + +#~ msgid "select by mouse:" +#~ msgstr "selecionar por mouse:" + +#~ msgid "select by color:" +#~ msgstr "selecionar por cor:" + +#~ msgid "press ESC to exit" +#~ msgstr "pressione ESC para sair" + +#~ msgid "horizontal unbend" +#~ msgstr "desempeno horizontal" + +#~ msgid "Rebuild Thumbnails" +#~ msgstr "Reconstruir miniaturas" + +#~ msgid "area outline has a hole" +#~ msgstr "contorno de área tem uma falha" + +#~ msgid "" +#~ "Search all areas for edge and inside pixels. \n" +#~ "Click inside each enclosed area in sequence." +#~ msgstr "" +#~ "Procura de áreas contornadas e pixels internos. \n" +#~ "Mantenha esta janela aberta, clique dentro de cada área enquadrada em " +#~ "sequência." + +#~ msgid "Create Launcher" +#~ msgstr "Criar atalho" + +#~ msgid "make new version" +#~ msgstr "fazer nova versão" + +#~ msgid "click on window to show RGB" +#~ msgstr "clique na janela para mostrar RGB" + +#~ msgid "Save As" +#~ msgstr "Salvar como..." + +#~ msgid "Clone fotoxx" +#~ msgstr "Clonar fotoxx" + +#~ msgid "Time Interval" +#~ msgstr "Intervalo de tempo" + +#~ msgid "Discard modifications?" +#~ msgstr "Discartar modificações?" + +#~ msgid "transition" +#~ msgstr "transição" + +#~ msgid "" +#~ "Rename failed \n" +#~ " %s" +#~ msgstr "" +#~ "Renomeação falhou \n" +#~ " %s" + +#~ msgid "incremental" +#~ msgstr "incremental" + +#~ msgid "full rebuild" +#~ msgstr "reconstruir tudo" + +#~ msgid "y-grid" +#~ msgstr "grade-y" + +#~ msgid "x-grid" +#~ msgstr "grade-x" + +#~ msgid "enable" +#~ msgstr "habilitar" + +#~ msgid "" +#~ "Click on image where new or saved \n" +#~ "images are to be inserted (after)." +#~ msgstr "" +#~ "Clique na imagem na qual a imagem nova ou \n" +#~ "salva serão inseridas (depois)." + +#~ msgid "" +#~ "Click on images to remove and save, \n" +#~ "then press [Paste] to insert them." +#~ msgstr "" +#~ "Clique em imagens para remover e salve, \n" +#~ "depois pressione [Colar] para inseri-las." + +#~ msgid "Click on images to delete." +#~ msgstr "Clique em imagens para excluir" + +#~ msgid "select image files" +#~ msgstr "selecione arquivos de imagem" + +#~ msgid "" +#~ "Select images to add, then \n" +#~ "press [Paste] to insert them." +#~ msgstr "" +#~ "Selecione imagens para adicionar, depois \n" +#~ "pressione [Colar] para inseri-las." + +#~ msgid "Insert new or saved images" +#~ msgstr "Inserir salvas ou novas imagens" + +#~ msgid "Remove and save images" +#~ msgstr "Remover e salvar imagens" + +#~ msgid "Delete images from collection" +#~ msgstr "Excluir imagens da coleção" + +#~ msgid "Add new images to collection" +#~ msgstr "Adicionar novas imagens à coleção" + +#~ msgid "Save Collection" +#~ msgstr "Salvar coleção" + +#~ msgid "" +#~ "Run Tools > Synchronize Files so that gallery windows \n" +#~ "will be fast and Search Images will work correctly." +#~ msgstr "" +#~ "Acesse Ferramentas > Sincronizar Arquivos para as janelas \n" +#~ "da galeria serem rápidas e a Procura de Imagens funcionar corretamente." + +#~ msgid "Translate" +#~ msgstr "Traduzir" + +#~ msgid "Open Collection" +#~ msgstr "Abrir Coleção" + +#~ msgid "Create Collection" +#~ msgstr "Criar Coleção" + +#~ msgid "select new file" +#~ msgstr "selecionar novo arquivo" + +#~ msgid "both" +#~ msgstr "ambos" + +#~ msgid "icons" +#~ msgstr "ícones" + +#~ msgid "lens name" +#~ msgstr "nome da lente" + +#~ msgid "start edit function first" +#~ msgstr "inicie a função de edição primeiro" + +#~ msgid "my mouse" +#~ msgstr "meu mouse" + +#~ msgid "Lens Parameters" +#~ msgstr "Parâmetros de lente" diff -Nru fotoxx-11.11.1/locales/fotoxx-ru.po fotoxx-12.01.2/locales/fotoxx-ru.po --- fotoxx-11.11.1/locales/fotoxx-ru.po 1970-01-01 00:00:00.000000000 +0000 +++ fotoxx-12.01.2/locales/fotoxx-ru.po 2012-01-04 08:47:11.000000000 +0000 @@ -0,0 +1,2985 @@ +# Russian translations for home package. +# Copyright (C) 2010 by Redf +# This file is distributed under the same license as the home package. +# Redf , 2010. +# +msgid "" +msgstr "" +"Project-Id-Version: home 2\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-12-31 21:05+0100\n" +"PO-Revision-Date: 2010-05-12 10:15+0200\n" +"Last-Translator: redf \n" +"Language-Team: Russian\n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: f.art.cc:47 +msgid "Set color depth to 1-16 bits" +msgstr " Установить глубину цвета в диапазоне от 1 до 16 бит " + +#: f.art.cc:57 +msgid "Set Color Depth" +msgstr "Установка глубины цвета" + +#: f.art.cc:171 +msgid "Simulate Drawing" +msgstr "Имитировать рисунок" + +#: f.art.cc:213 f.retouch.cc:1759 f.retouch.cc:5991 +msgid "contrast" +msgstr " Контраст" + +#: f.art.cc:215 +msgid "outlines" +msgstr "Контур" + +#: f.art.cc:220 +msgid "pencil" +msgstr "Карандаш" + +#: f.art.cc:221 +msgid "chalk" +msgstr "Мелок" + +#: f.art.cc:381 +msgid "Add Image Outlines" +msgstr "" + +#: f.art.cc:394 +msgid "outline threshold" +msgstr "" + +#: f.art.cc:397 +msgid "outline width" +msgstr "" + +#: f.art.cc:400 +msgid "image brightness" +msgstr "" + +#: f.art.cc:611 +msgid "Simulate Embossing" +msgstr "Имитировать чеканку" + +#: f.art.cc:626 +msgid "depth" +msgstr "Глубина" + +#: f.art.cc:628 f.file.cc:919 f.retouch.cc:6692 +msgid "color" +msgstr "Цвет" + +#: f.art.cc:821 +msgid "Simulate Tiles" +msgstr "Имитировать мозаику" + +#: f.art.cc:825 +msgid "tile size" +msgstr "Размер элементов" + +#: f.art.cc:829 +msgid "tile gap" +msgstr "Промежутки" + +#: f.art.cc:1003 +msgid "Convert Image to Dots" +msgstr "" + +#: f.art.cc:1007 +msgid "dot size" +msgstr "" + +#: f.art.cc:1222 +msgid "Simulate Painting" +msgstr "Имитировать живопись" + +#: f.art.cc:1226 +msgid "color depth" +msgstr "Глубина цвета" + +#: f.art.cc:1230 +msgid "patch area goal" +msgstr "" + +#: f.art.cc:1234 +msgid "req. color match" +msgstr "Цвета" + +#: f.art.cc:1238 +msgid "borders" +msgstr " Рамки" + +#: f.comp.cc:1956 f.comp.cc:1961 f.comp.cc:2582 f.comp.cc:2587 f.comp.cc:3266 +#: f.comp.cc:3271 f.comp.cc:3816 f.comp.cc:3821 +msgid "Select 2 to 9 files" +msgstr "" + +#: f.comp.cc:1982 f.comp.cc:2608 f.comp.cc:3292 f.comp.cc:3842 +msgid "Images are not all the same size" +msgstr "Bilder sind nicht gleich gross" + +#: f.comp.cc:2321 +msgid "Adjust Image Contributions" +msgstr "Коррекция изображения" + +#: f.comp.cc:2324 f.retouch.cc:886 +msgid "dark pixels" +msgstr "Темные пиксели" + +#: f.comp.cc:2326 +msgid "light pixels" +msgstr "Светлые пикселы" + +#: f.comp.cc:2328 f.info.cc:159 +msgid "file:" +msgstr "Файл:" + +#: f.comp.cc:2843 +msgid "Paint and Warp Image" +msgstr "" + +#: f.comp.cc:2846 f.comp.cc:3520 f.comp.cc:4959 f.comp.cc:5705 +msgid "image" +msgstr "" + +#: f.comp.cc:2850 f.retouch.cc:6696 +msgid "paint" +msgstr "Рисовать" + +#: f.comp.cc:2851 +msgid "warp" +msgstr "" + +#: f.comp.cc:3518 +msgid "Select and Paint Image" +msgstr "" + +#: f.comp.cc:4031 +msgid "Adjust Pixel Composition" +msgstr "" + +#: f.comp.cc:4283 f.comp.cc:4288 f.comp.cc:5173 f.comp.cc:5178 +msgid "Select 2 to 4 files" +msgstr "" + +#: f.comp.cc:4361 +msgid "" +"Drag images into rough alignment.\n" +"To rotate, drag from lower edge." +msgstr "" + +#: f.comp.cc:4363 +msgid "Search for lens mm and bow" +msgstr "" + +#: f.comp.cc:4409 f.comp.cc:5298 +msgid "Pre-align Images" +msgstr "Предварительно выравненные" + +#: f.comp.cc:4413 f.comp.cc:5302 +msgid "lens mm" +msgstr "Фокусное расстояние, мм" + +#: f.comp.cc:4417 f.comp.cc:5306 +msgid "lens bow" +msgstr "Lens bow" + +#: f.comp.cc:4419 f.comp.cc:5308 +msgid "Resize" +msgstr "" + +#: f.comp.cc:4420 f.comp.cc:5309 +msgid "resize window" +msgstr "" + +#: f.comp.cc:4457 +msgid "use two images only" +msgstr "" + +#: f.comp.cc:4478 f.comp.cc:4676 f.comp.cc:4875 f.comp.cc:5357 f.comp.cc:5620 +msgid "Too little overlap, cannot align" +msgstr "Слишком маленькое наложение, выравнять не возможно" + +#: f.comp.cc:4950 f.comp.cc:5696 +msgid "Match Brightness and Color" +msgstr "" + +#: f.comp.cc:4974 f.comp.cc:5720 +msgid "auto color" +msgstr "" + +#: f.comp.cc:4975 f.comp.cc:5721 +msgid "file color" +msgstr "" + +#: f.comp.cc:5251 +msgid "" +"Drag images into rough alignment.\n" +"To rotate, drag from right edge." +msgstr "" + +#: f.file.cc:169 f.file.cc:341 fotoxx-12.01.cc:189 fotoxx-12.01.cc:325 +msgid "Open Image File" +msgstr "Открыть" + +#: f.file.cc:321 fotoxx-12.01.cc:2862 +msgid "prior function still active" +msgstr "" + +#: f.file.cc:503 +msgid "Overwrite original file?" +msgstr "" + +#: f.file.cc:504 +msgid "Do not warn again" +msgstr "" + +#: f.file.cc:520 +msgid "Warning" +msgstr "" + +#: f.file.cc:643 +msgid "Save File" +msgstr "Сохранить в файл" + +#: f.file.cc:666 zfuncs.cc:6478 +msgid "quality" +msgstr "" + +#: f.file.cc:668 +msgid "make current" +msgstr "" + +#: f.file.cc:725 +msgid "jpeg quality must be 1-100" +msgstr "Качество jpeg должно быть от 1 до 100" + +#: f.file.cc:747 +#, c-format +msgid "" +"Overwrite file? \n" +" %s" +msgstr "" +"Переписать файл? \n" +" %s" + +#: f.file.cc:903 fotoxx-12.01.cc:196 +msgid "Create Blank Image" +msgstr "" + +#: f.file.cc:905 +msgid "file name" +msgstr "" + +#: f.file.cc:910 f.transform.cc:353 +msgid "width" +msgstr "" + +#: f.file.cc:913 f.tools.cc:477 f.transform.cc:356 +msgid "height" +msgstr "" + +#: f.file.cc:1033 +msgid "" +"Linux standard trash is not supported. \n" +"Desktop trash folder will be created." +msgstr "" + +#: f.file.cc:1051 +msgid "Move read-only file to trash?" +msgstr "Переместить изображение в корзину?" + +#: f.file.cc:1077 +#, c-format +msgid "Cannot create trash folder: %s" +msgstr "Не могу создать папку: %s" + +#: f.file.cc:1085 f.file.cc:1091 zfuncs.cc:3356 +#, c-format +msgid "error: %s" +msgstr "Ошибка: %s" + +#: f.file.cc:1136 fotoxx-12.01.cc:198 +msgid "Rename Image File" +msgstr "Переименовать" + +#: f.file.cc:1141 +msgid "old name" +msgstr "Старое имя" + +#: f.file.cc:1142 +msgid "rename to" +msgstr "Переименовать в" + +#: f.file.cc:1143 +msgid "previous" +msgstr "Предыдущий" + +#: f.file.cc:1229 +msgid "The target file already exists" +msgstr "Такой файл уже открыт" + +#: f.file.cc:1237 +#, c-format +msgid "" +"Rename failed: \n" +" %s" +msgstr "" + +#: f.file.cc:1285 +msgid "Batch Rename" +msgstr "Групповое переименование" + +#: f.file.cc:1288 f.file.cc:1340 f.info.cc:1519 f.info.cc:1773 f.tools.cc:543 +#: f.tools.cc:2990 +#, c-format +msgid "%d files selected" +msgstr "" + +#: f.file.cc:1290 +msgid "new base name" +msgstr "Префикс" + +#: f.file.cc:1293 +msgid "starting sequence" +msgstr "Начальный номер" + +#: f.file.cc:1295 +msgid "increment" +msgstr "Дополнительный номер" + +#: f.file.cc:1316 +msgid "select files to rename" +msgstr "Выберите файлы для переименования" + +#: f.file.cc:1321 +msgid "base name / sequence / increment not reasonable" +msgstr " Неправильный префикс / начальный номер / дополнительный номер" + +#: f.file.cc:1380 +msgid "new file already exists:" +msgstr "Новый файл уже открыт:" + +#: f.file.cc:1388 +msgid "filespec too long:" +msgstr "Имя файла слишком длинное:" + +#: f.file.cc:1399 +msgid "Rename failed:" +msgstr "Переименование остановлено:" + +#: f.file.cc:1660 fotoxx.h:729 +msgid "Add" +msgstr "" + +#: f.file.cc:1660 fotoxx.h:781 +msgid "Remove" +msgstr "" + +#: f.file.cc:1662 +msgid "menu name" +msgstr "" + +#: f.file.cc:1733 f.file.cc:1754 +msgid "Restart Fotoxx to update plugin menu" +msgstr "" + +#: f.info.cc:70 +msgid "Edit Caption and Comments" +msgstr "" + +#: f.info.cc:156 fotoxx-12.01.cc:225 +msgid "Edit Tags" +msgstr "Редактировать теги" + +#: f.info.cc:163 +msgid "image date (yyyymmdd)" +msgstr "Дата (ггггммдд)" + +#: f.info.cc:165 +msgid "use last" +msgstr "Использовать последний" + +#: f.info.cc:168 +msgid "image stars" +msgstr "Рейтинг" + +#: f.info.cc:186 +msgid "current tags" +msgstr "Текущий тег" + +#: f.info.cc:191 +msgid "recent tags" +msgstr "" + +#: f.info.cc:196 f.info.cc:358 f.info.cc:1368 f.info.cc:2384 +msgid "defined tags" +msgstr "" + +#: f.info.cc:345 fotoxx-12.01.cc:226 +msgid "Manage Tags" +msgstr "" + +#: f.info.cc:348 +msgid "category" +msgstr "" + +#: f.info.cc:351 +msgid "tag" +msgstr "" + +#: f.info.cc:354 +msgid "create" +msgstr "" + +#: f.info.cc:355 f.navi.cc:1421 +msgid "delete" +msgstr "" + +#: f.info.cc:1235 f.info.cc:1319 +#, c-format +msgid "search index file error: %s" +msgstr "" + +#: f.info.cc:1351 fotoxx-12.01.cc:227 +msgid "Batch Add Tags" +msgstr "Групповое добавление тегов" + +#: f.info.cc:1354 +msgid "tags to add" +msgstr "Теги для добавления" + +#: f.info.cc:1359 +msgid "create tag" +msgstr "Создать тег" + +#: f.info.cc:1415 f.info.cc:1608 +#, c-format +msgid "" +"%s \n" +" too many tags" +msgstr "" + +#: f.info.cc:1553 fotoxx-12.01.cc:228 +msgid "Batch Delete Tag" +msgstr "" + +#: f.info.cc:1556 +msgid "tag to remove" +msgstr "" + +#: f.info.cc:1560 +msgid "optional replacement" +msgstr "" + +#: f.info.cc:1565 f.tools.cc:2943 +msgid "0 files selected" +msgstr "" + +#: f.info.cc:1568 +msgid "search all files" +msgstr "" + +#: f.info.cc:1653 +msgid "no files selected" +msgstr "" + +#: f.info.cc:1659 +msgid "no tag specified" +msgstr "" + +#: f.info.cc:1683 f.info.cc:1712 +msgid "specify tag" +msgstr "" + +#: f.info.cc:1821 +msgid "View Info" +msgstr "" + +#: f.info.cc:1889 fotoxx-12.01.cc:231 +msgid "Edit Info" +msgstr "" + +#: f.info.cc:1987 fotoxx-12.01.cc:232 +msgid "Delete Info" +msgstr "" + +#: f.info.cc:1989 fotoxx.h:731 +msgid "All" +msgstr "Все" + +#: f.info.cc:1990 +msgid "One Key:" +msgstr "Один Key:" + +#: f.info.cc:2343 +msgid "Search Tags, Comments, File Names" +msgstr "" + +#: f.info.cc:2350 +msgid "date range" +msgstr "Диапазон дат" + +#: f.info.cc:2351 +msgid "stars range" +msgstr "Рейтинг" + +#: f.info.cc:2352 +msgid "search tags" +msgstr "Поиск тегов" + +#: f.info.cc:2353 +msgid "search text" +msgstr "" + +#: f.info.cc:2354 +msgid "file names" +msgstr "" + +#: f.info.cc:2359 +msgid "(yyyymmdd)" +msgstr "" + +#: f.info.cc:2365 +msgid "all/any" +msgstr "" + +#: f.info.cc:2702 +msgid "No matching images found" +msgstr "Нет ссответствующих изображений" + +#: f.info.cc:2706 f.info.cc:3059 +msgid "No search index file present" +msgstr "" + +#: f.info.cc:2777 +msgid "Additional Items for Report" +msgstr "" + +#: f.navi.cc:188 f.navi.cc:576 f.navi.cc:706 f.navi.cc:707 f.navi.cc:709 +msgid "bigger" +msgstr "Увеличить" + +#: f.navi.cc:188 +msgid "increase thumbnail size" +msgstr "Увеличить" + +#: f.navi.cc:189 +msgid "reduce thumbnail size" +msgstr "Уменьшить" + +#: f.navi.cc:189 f.navi.cc:586 f.navi.cc:708 f.navi.cc:710 +msgid "smaller" +msgstr "Уменьшить" + +#: f.navi.cc:190 f.navi.cc:600 +msgid "parent" +msgstr "Наверх" + +#: f.navi.cc:190 +msgid "parent directory" +msgstr "Директорией выше" + +#: f.navi.cc:191 f.navi.cc:625 f.navi.cc:717 +msgid "first page" +msgstr "Первая страница" + +#: f.navi.cc:191 +msgid "jump to first file" +msgstr "К первому файлу" + +#: f.navi.cc:192 f.navi.cc:623 f.navi.cc:712 f.navi.cc:719 +msgid "prev page" +msgstr "Предыдущая страница" + +#: f.navi.cc:192 +msgid "previous page" +msgstr "Предыдущая страница" + +#: f.navi.cc:193 f.navi.cc:621 f.navi.cc:714 +msgid "prev row" +msgstr "Предыдущий ряд" + +#: f.navi.cc:193 +msgid "previous row" +msgstr "Предыдущий ряд" + +#: f.navi.cc:194 f.navi.cc:622 f.navi.cc:715 +msgid "next row" +msgstr "Следующий ряд" + +#: f.navi.cc:195 f.navi.cc:624 f.navi.cc:713 f.navi.cc:720 +msgid "next page" +msgstr "Следующая страница" + +#: f.navi.cc:195 +msgid "ttip::next page" +msgstr "" + +#: f.navi.cc:196 +msgid "jump to last file" +msgstr "К последнему файлу" + +#: f.navi.cc:196 f.navi.cc:626 f.navi.cc:718 +msgid "last page" +msgstr "Последняя страница" + +#: f.navi.cc:197 f.navi.cc:571 +msgid "close" +msgstr "Закрыть" + +#: f.navi.cc:197 +msgid "close image gallery" +msgstr "Закрыть галерею" + +#: f.navi.cc:1413 fotoxx.h:787 +msgid "Select Files" +msgstr "" + +#: f.navi.cc:1413 zfuncs.cc:6296 zfuncs.cc:6332 zfuncs.cc:6485 zfuncs.cc:6728 +#: zfuncs.cc:7427 zfuncs.cc:7433 zfuncs.cc:7439 zfuncs.cc:7445 +msgid "cancel" +msgstr "Отменить" + +#: f.navi.cc:1413 zfuncs.cc:6728 +msgid "done" +msgstr "" + +#: f.navi.cc:1422 +msgid "insert" +msgstr "" + +#: f.navi.cc:1423 +msgid "add all" +msgstr "" + +#: f.retouch.cc:55 +msgid "Adjust Brightness and Color" +msgstr "Яркость и цветность" + +#: f.retouch.cc:110 +msgid "small-steps" +msgstr "" + +#: f.retouch.cc:119 +msgid "color saturation" +msgstr "Цветовая насыщенность" + +#: f.retouch.cc:126 +msgid " reset 1 " +msgstr "Сбросить один" + +#: f.retouch.cc:127 +msgid "reset all" +msgstr "Сбросить все" + +#: f.retouch.cc:599 +msgid "adjust image gamma" +msgstr "" + +#: f.retouch.cc:885 +msgid "Expand Brightness Range" +msgstr "Расширение яркости" + +#: f.retouch.cc:887 +msgid "bright pixels" +msgstr "Яркие пиксели" + +#: f.retouch.cc:1058 +msgid "Flatten Brightness Distribution" +msgstr "Выравнять яркость" + +#: f.retouch.cc:1072 +msgid "Flatten" +msgstr "Выравнивание" + +#: f.retouch.cc:1334 +msgid "Ramp brightness across image" +msgstr "Распределение яркости вокруг изображения" + +#: f.retouch.cc:1730 fotoxx-12.01.cc:272 +msgid "Tone Mapping" +msgstr "Тональное отображение" + +#: f.retouch.cc:1758 +msgid "low" +msgstr "" + +#: f.retouch.cc:1760 +msgid "high" +msgstr "" + +#: f.retouch.cc:1763 +msgid "Amplify" +msgstr "" + +#: f.retouch.cc:2069 +msgid "Adjust White Balance" +msgstr "Баланс белого" + +#: f.retouch.cc:2070 +msgid "Click white or gray image location" +msgstr "Кликните по белому или серому" + +#: f.retouch.cc:2278 +msgid "Color Match Images" +msgstr "" + +#: f.retouch.cc:2307 +msgid "mouse radius for color sample" +msgstr "" + +#: f.retouch.cc:2309 f.retouch.cc:2314 fotoxx-12.01.cc:246 fotoxx-12.01.cc:325 +#: fotoxx.h:769 +msgid "Open" +msgstr "Открыть" + +#: f.retouch.cc:2310 +msgid "image for source color" +msgstr "" + +#: f.retouch.cc:2312 +msgid "click on image to get source color" +msgstr "" + +#: f.retouch.cc:2315 +msgid "image to set matching color" +msgstr "" + +#: f.retouch.cc:2317 +msgid "click on image to set matching color" +msgstr "" + +#: f.retouch.cc:2372 +msgid "select source image color first" +msgstr "" + +#: f.retouch.cc:2584 +msgid "Add standard bias" +msgstr "" + +#: f.retouch.cc:2591 +msgid "+Brightness -Density" +msgstr "" + +#: f.retouch.cc:2592 +msgid "+Red -Cyan" +msgstr "" + +#: f.retouch.cc:2593 +msgid "+Green -Magenta" +msgstr "" + +#: f.retouch.cc:2594 +msgid "+Blue -Yellow" +msgstr "" + +#: f.retouch.cc:2599 +msgid "Contrast" +msgstr "" + +#: f.retouch.cc:2600 fotoxx.h:778 +msgid "Red" +msgstr "Красный" + +#: f.retouch.cc:2601 fotoxx.h:758 +msgid "Green" +msgstr "Зеленый" + +#: f.retouch.cc:2602 fotoxx.h:736 +msgid "Blue" +msgstr "Синий" + +#: f.retouch.cc:2730 +msgid "Load DRGB parameters" +msgstr "" + +#: f.retouch.cc:2732 f.retouch.cc:2804 f.retouch.cc:6102 f.retouch.cc:6198 +msgid "File:" +msgstr "" + +#: f.retouch.cc:2751 f.retouch.cc:2824 +msgid "DRGB parameters file" +msgstr "" + +#: f.retouch.cc:2769 f.retouch.cc:6142 +msgid "file not found" +msgstr "" + +#: f.retouch.cc:2802 +msgid "Save DRGB parameters" +msgstr "" + +#: f.retouch.cc:3034 f.tools.cc:2404 +msgid "Click image to select pixels." +msgstr "" + +#: f.retouch.cc:3072 fotoxx-12.01.cc:276 +msgid "Revise RGB" +msgstr "" + +#: f.retouch.cc:3084 +msgid "Metric:" +msgstr "" + +#: f.retouch.cc:3139 +msgid "Blend" +msgstr "" + +#: f.retouch.cc:3519 +msgid "" +"Method 1:\n" +" Left-click on red-eye to darken.\n" +"Method 2:\n" +" Drag down and right to enclose red-eye.\n" +" Left-click on red-eye to darken.\n" +"Undo red-eye:\n" +" Right-click on red-eye." +msgstr "" +" Метод 1:\n" +" Кликните левой кнопкой мышки на красных глазах.\n" +" Метод 2:\n" +" Протащите курсор вниз-вправо.\n" +" Кликните левой кнопкой мышки на красных глазах.\n" +" Отменить:\n" +" Кликните правой кнопкой мышки на красных глазах." + +#: f.retouch.cc:3534 +msgid "Red Eye Reduction" +msgstr "Уменьшение эффекта красных глаз" + +#: f.retouch.cc:3968 +msgid "Set Blur Radius" +msgstr "Размыть" + +#: f.retouch.cc:4195 fotoxx-12.01.cc:279 +msgid "Sharpen Image" +msgstr "Увеличить резкость" + +#: f.retouch.cc:4202 +msgid "edge detection" +msgstr "Обнаружение края" + +#: f.retouch.cc:4203 +msgid "cycles" +msgstr "Циклы" + +#: f.retouch.cc:4204 +msgid "reduce" +msgstr "Уменьшить" + +#: f.retouch.cc:4215 +msgid "unsharp mask" +msgstr "Маска резкости" + +#: f.retouch.cc:4228 +msgid "brightness gradient" +msgstr "Переход яркости" + +#: f.retouch.cc:4634 +msgid "" +" Press the reduce button to \n" +" reduce noise in small steps. \n" +" Use undo to start over." +msgstr "" +" Нажмите кнопку [Уменьшить] \n" +" для уменьшения шума." + +#: f.retouch.cc:4645 +msgid "Noise Reduction" +msgstr "Шумоподавление" + +#: f.retouch.cc:4650 +msgid "algorithm" +msgstr "Алгоритм" + +#: f.retouch.cc:4657 +msgid "flatten outliers by color (1)" +msgstr "Flatten outliers by color (1)" + +#: f.retouch.cc:4658 +msgid "flatten outliers by color (2)" +msgstr "Flatten outliers by color (2)" + +#: f.retouch.cc:4659 +msgid "set median brightness by color" +msgstr "Set median brightness by color" + +#: f.retouch.cc:4660 f.retouch.cc:4661 +msgid "top hat filter by color" +msgstr "Top hat аilter by color" + +#: f.retouch.cc:4976 +msgid "" +"1. Drag mouse to select. \n" +"2. Erase. 3. Repeat. " +msgstr "" + +#: f.retouch.cc:4998 fotoxx-12.01.cc:281 +msgid "Smart Erase" +msgstr "" + +#: f.retouch.cc:5003 fotoxx.h:776 +msgid "Radius" +msgstr "Радиус" + +#: f.retouch.cc:5005 +msgid "Blur" +msgstr "" + +#: f.retouch.cc:5008 +msgid "New Area" +msgstr "" + +#: f.retouch.cc:5379 fotoxx-12.01.cc:282 +msgid "Remove Dust" +msgstr "" + +#: f.retouch.cc:5383 +msgid "spot size limit" +msgstr "" + +#: f.retouch.cc:5386 +msgid "max. brightness" +msgstr "" + +#: f.retouch.cc:5389 +msgid "min. contrast" +msgstr "" + +#: f.retouch.cc:5983 fotoxx-12.01.cc:283 +msgid "Fix Stuck Pixels" +msgstr "" + +#: f.retouch.cc:5989 +msgid "pixel group" +msgstr "" + +#: f.retouch.cc:5990 +msgid "circle color" +msgstr "" + +#: f.retouch.cc:6100 +msgid "Load Stuck Pixels" +msgstr "" + +#: f.retouch.cc:6124 f.retouch.cc:6220 +msgid "Stuck Pixels file" +msgstr "" + +#: f.retouch.cc:6164 +msgid "file format error" +msgstr "" + +#: f.retouch.cc:6192 +msgid "there are zero stuck pixels" +msgstr "" + +#: f.retouch.cc:6196 +msgid "Save Stuck Pixels" +msgstr "" + +#: f.retouch.cc:6686 +#, c-format +msgid "Undo Memory %d%c" +msgstr "Память %d%c" + +#: f.retouch.cc:6688 fotoxx-12.01.cc:284 +msgid "Edit Pixels" +msgstr "Редактировать изображение" + +#: f.retouch.cc:6695 +msgid "pick" +msgstr "Выбрать" + +#: f.retouch.cc:6697 +msgid "erase" +msgstr "Стереть" + +#: f.retouch.cc:6705 +msgid "paintbrush radius" +msgstr "Радиус кисти" + +#: f.retouch.cc:6706 +msgid "transparency center" +msgstr "Центр" + +#: f.retouch.cc:6707 +msgid "transparency edge" +msgstr "Край" + +#: f.retouch.cc:6972 +msgid "" +"Undo memory limit has been reached. \n" +"Save work with [done], then resume editing." +msgstr "" +"Превышен лимит памяти (200 MB) \n" +"Сохраните изменения и продолжайте" + +#: f.select.cc:54 f.select.cc:2461 +msgid "Select Area for Edits" +msgstr "Выбрать область для редактирования" + +#: f.select.cc:55 f.select.cc:2462 +msgid "Press F1 for help" +msgstr "" + +#: f.select.cc:64 +msgid "" +"Select Area not supported \n" +"by this edit function" +msgstr "" + +#: f.select.cc:103 f.tools.cc:901 +msgid "rectangle" +msgstr "" + +#: f.select.cc:104 f.tools.cc:902 +msgid "ellipse" +msgstr "" + +#: f.select.cc:110 +msgid "draw: freehand" +msgstr "" + +#: f.select.cc:111 +msgid "draw: follow edge" +msgstr "" + +#: f.select.cc:114 +msgid "select by mouse" +msgstr "" + +#: f.select.cc:116 f.select.cc:2496 +msgid "mouse radius" +msgstr "" + +#: f.select.cc:120 +msgid "match mouse color" +msgstr "" + +#: f.select.cc:124 +msgid "search range" +msgstr "" + +#: f.select.cc:126 +msgid "firewall" +msgstr "" + +#: f.select.cc:326 f.select.cc:467 +#, c-format +msgid "exceed %d edits" +msgstr "%d превышений редактирования" + +#: f.select.cc:1021 +msgid "" +"Click one time inside each enclosed area \n" +"(possible gaps in the outline will be found). \n" +"Press F1 for help." +msgstr "" + +#: f.select.cc:1078 +msgid "finish area" +msgstr "Конечная область" + +#: f.select.cc:1113 +msgid "searching" +msgstr "Поиск" + +#: f.select.cc:1185 +msgid "outline has a gap" +msgstr "" + +#: f.select.cc:1189 +msgid "success" +msgstr "Готово" + +#: f.select.cc:1440 f.select.cc:1470 +msgid "the area is not finished" +msgstr "Область не выбрана" + +#: f.select.cc:1563 +msgid "Edge calculation in progress" +msgstr "Вычисляем..." + +#: f.select.cc:1572 +msgid "Area Edge Calc" +msgstr "Расчет области" + +#: f.select.cc:1863 +msgid "position with mouse click/drag" +msgstr "" + +#: f.select.cc:1887 +msgid "Paste Image" +msgstr "Вставить изображение" + +#: f.select.cc:1901 +msgid "angle" +msgstr "" + +#: f.select.cc:2160 +msgid "load select area from a file" +msgstr "Загрузить выбранную область из файла" + +#: f.select.cc:2194 +msgid "cannot open .tiff and .info files" +msgstr "" + +#: f.select.cc:2213 +msgid "save select area to a file" +msgstr "" + +#: f.select.cc:2248 fotoxx-12.01.cc:248 +msgid "Select Whole Image" +msgstr "" + +#: f.select.cc:2249 +msgid "Edit Function Amplifier" +msgstr "" + +#: f.select.cc:2463 +msgid "Edit function must be active" +msgstr "" + +#: f.select.cc:2499 +msgid "power: center" +msgstr "" + +#: f.select.cc:2501 +msgid "edge" +msgstr "" + +#: f.select.cc:2504 +msgid "reset area" +msgstr "" + +#: f.tools.cc:42 +msgid "" +"When editing a collection, right-click \n" +"an image or thumbnail to add or remove." +msgstr "" + +#: f.tools.cc:70 fotoxx-12.01.cc:204 +msgid "Manage Collections" +msgstr "" + +#: f.tools.cc:85 +msgid "Start new collection" +msgstr "" + +#: f.tools.cc:87 +msgid "Edit a collection" +msgstr "" + +#: f.tools.cc:89 +msgid "View a collection" +msgstr "" + +#: f.tools.cc:91 +msgid "Delete a collection" +msgstr "" + +#: f.tools.cc:95 +msgid "Editing:" +msgstr "" + +#: f.tools.cc:99 +msgid "Action:" +msgstr "" + +#: f.tools.cc:133 +msgid "New Collection" +msgstr "" + +#: f.tools.cc:156 +msgid "Edit Collection" +msgstr "" + +#: f.tools.cc:172 +msgid "View Collection" +msgstr "" + +#: f.tools.cc:193 +msgid "Delete Collection" +msgstr "" + +#: f.tools.cc:196 +#, c-format +msgid "delete %s ?" +msgstr "" + +#: f.tools.cc:223 +#, c-format +msgid "add image to collection: %s" +msgstr "" + +#: f.tools.cc:225 f.tools.cc:270 +msgid "remove image from collection" +msgstr "" + +#: f.tools.cc:226 f.tools.cc:271 f.tools.cc:298 +msgid "remove and save image" +msgstr "" + +#: f.tools.cc:227 f.tools.cc:316 +msgid "insert saved images here" +msgstr "" + +#: f.tools.cc:256 +msgid "add image to collection" +msgstr "" + +#: f.tools.cc:301 +msgid "too many saved files" +msgstr "" + +#: f.tools.cc:373 fotoxx-12.01.cc:205 +msgid "Move Collections" +msgstr "" + +#: f.tools.cc:375 +msgid "old top directory" +msgstr "" + +#: f.tools.cc:378 +msgid "new top directory" +msgstr "" + +#: f.tools.cc:434 +msgid "completed" +msgstr "Сделано" + +#: f.tools.cc:467 +msgid "Batch Convert/Resize/Export" +msgstr "" + +#: f.tools.cc:474 +msgid "new max. width" +msgstr "" + +#: f.tools.cc:481 +msgid "new file type" +msgstr "" + +#: f.tools.cc:482 +msgid "same" +msgstr "" + +#: f.tools.cc:490 +msgid "replace originals" +msgstr "" + +#: f.tools.cc:491 +msgid "export to location" +msgstr "" + +#: f.tools.cc:492 +msgid "remove EXIF" +msgstr "" + +#: f.tools.cc:549 +msgid "Select directory" +msgstr "" + +#: f.tools.cc:583 +#, c-format +msgid "replace original files? (max. %d x %d)" +msgstr "" + +#: f.tools.cc:590 +#, c-format +msgid "" +"copy files? (max. %d x %d) \n" +" to location %s" +msgstr "" + +#: f.tools.cc:601 +msgid "location is not a valid directory" +msgstr "" + +#: f.tools.cc:608 f.tools.cc:3007 +#, c-format +msgid "max. size %d x %d is not reasonable" +msgstr "" + +#: f.tools.cc:654 +msgid "*** file already exists" +msgstr "" + +#: f.tools.cc:662 +msgid "*** file type not supported" +msgstr "" + +#: f.tools.cc:741 +msgid "Program ufraw-batch is required" +msgstr "" + +#: f.tools.cc:751 fotoxx.h:770 +msgid "Open RAW File" +msgstr "Открыть RAW-файл" + +#: f.tools.cc:764 +msgid "Select RAW files to convert" +msgstr "Выбрать RAW-файлы для конвертации" + +#: f.tools.cc:769 +msgid "Choose file type" +msgstr "" + +#: f.tools.cc:888 +msgid "Press ESC to exit slide show" +msgstr "" + +#: f.tools.cc:889 +msgid "show only latest file versions" +msgstr "" + +#: f.tools.cc:893 +msgid "arrow keys" +msgstr "" + +#: f.tools.cc:894 +msgid "instant" +msgstr "" + +#: f.tools.cc:895 +msgid "fade-in" +msgstr "" + +#: f.tools.cc:896 +msgid "roll-right" +msgstr "" + +#: f.tools.cc:897 +msgid "roll-down" +msgstr "" + +#: f.tools.cc:898 +msgid "shift-left" +msgstr "" + +#: f.tools.cc:899 +msgid "venetian" +msgstr "" + +#: f.tools.cc:900 +msgid "grate" +msgstr "" + +#: f.tools.cc:903 +msgid "radar" +msgstr "" + +#: f.tools.cc:904 +msgid "jaws" +msgstr "" + +#: f.tools.cc:911 fotoxx-12.01.cc:208 +msgid "Slide Show" +msgstr "Слайд-шоу" + +#: f.tools.cc:915 +msgid "seconds" +msgstr "Секунд" + +#: f.tools.cc:919 +msgid "music file" +msgstr "" + +#: f.tools.cc:923 +msgid "transitions" +msgstr "" + +#: f.tools.cc:1040 +msgid "Select music file or playlist" +msgstr "" + +#: f.tools.cc:1727 +msgid "Sync Files is already running" +msgstr "" + +#: f.tools.cc:1778 +msgid "" +"Run Tools > Synchronize Files so that gallery windows \n" +"will be fast and Search Images will work correctly. \n" +"You can view (not edit) images while synchronize runs." +msgstr "" + +#: f.tools.cc:1812 +msgid "no top image directory is defined" +msgstr "" + +#: f.tools.cc:1818 +msgid "top image directory is invalid" +msgstr "" + +#: f.tools.cc:1823 +msgid "no search index file is present" +msgstr "" + +#: f.tools.cc:1837 +msgid "new/modified files are present" +msgstr "" + +#: f.tools.cc:1844 +msgid "no new files found" +msgstr "" + +#: f.tools.cc:1859 fotoxx-12.01.cc:209 +msgid "Synchronize Files" +msgstr "" + +#: f.tools.cc:1861 +msgid "Top Image Directory:" +msgstr "Папка с изображениями" + +#: f.tools.cc:1883 +msgid "" +"file sync is necessary.\n" +"cancel anyway?" +msgstr "" + +#: f.tools.cc:1896 +msgid "top directory is invalid" +msgstr "" + +#: f.tools.cc:2292 +msgid "Select top image directory" +msgstr "Выбор папки" + +#: f.tools.cc:2429 fotoxx-12.01.cc:210 +msgid "Show RGB" +msgstr "Показать RGB" + +#: f.tools.cc:2719 fotoxx-12.01.cc:211 +msgid "Grid Lines" +msgstr "Сетка" + +#: f.tools.cc:2728 +msgid "x-spacing" +msgstr "" + +#: f.tools.cc:2729 +msgid "x-count" +msgstr "" + +#: f.tools.cc:2730 +msgid "x-enable" +msgstr "" + +#: f.tools.cc:2736 +msgid "y-spacing" +msgstr "" + +#: f.tools.cc:2737 +msgid "y-count" +msgstr "" + +#: f.tools.cc:2738 +msgid "y-enable" +msgstr "" + +#: f.tools.cc:2745 +msgid "x-offset" +msgstr "" + +#: f.tools.cc:2749 +msgid "y-offset" +msgstr "" + +#: f.tools.cc:2940 fotoxx-12.01.cc:213 +msgid "E-mail Images" +msgstr "" + +#: f.tools.cc:2947 +msgid "max. width" +msgstr "" + +#: f.tools.cc:2948 +msgid "max. height" +msgstr "" + +#: f.tools.cc:3093 +msgid "too many files" +msgstr "" + +#: f.tools.cc:3134 +msgid "" +"Brightness should show a gradual ramp \n" +"extending all the way to the edges." +msgstr "" + +#: f.tools.cc:3174 +msgid "Monitor Check" +msgstr "" + +#: f.tools.cc:3232 fotoxx-12.01.cc:215 +msgid "Monitor Gamma" +msgstr "" + +#: f.tools.cc:3294 fotoxx-12.01.cc:216 +msgid "Brightness Distribution" +msgstr "Распределение яркости" + +#: f.tools.cc:3432 +msgid "Available Translations" +msgstr "Доступен перевод" + +#: f.tools.cc:3436 +msgid "Set Language" +msgstr "Установка языка" + +#: f.tools.cc:3502 +msgid "Make Launcher" +msgstr "" + +#: f.tools.cc:3540 +msgid "Settings" +msgstr "" + +#: f.tools.cc:3545 +msgid "Startup Display" +msgstr "" + +#: f.tools.cc:3547 +msgid "Recent Files Gallery" +msgstr "" + +#: f.tools.cc:3548 +msgid "Previous Image Viewed" +msgstr "" + +#: f.tools.cc:3549 +msgid "Blank Window" +msgstr "" + +#: f.tools.cc:3551 +msgid "Directory Gallery" +msgstr "" + +#: f.tools.cc:3556 +msgid "Image File" +msgstr "" + +#: f.tools.cc:3562 +msgid "Toolbar Style" +msgstr "" + +#: f.tools.cc:3563 f.transform.cc:1300 +msgid "Text" +msgstr "" + +#: f.tools.cc:3564 +msgid "Icons" +msgstr "" + +#: f.tools.cc:3565 +msgid "Both" +msgstr "" + +#: f.tools.cc:3568 +msgid "Warn Overwrite" +msgstr "" + +#: f.tools.cc:3639 +msgid "startup directory is invalid" +msgstr "" + +#: f.tools.cc:3650 +msgid "startup file is invalid" +msgstr "" + +#: f.tools.cc:3707 +msgid "Select startup directory" +msgstr "" + +#: f.tools.cc:3715 +msgid "Select startup image file" +msgstr "" + +#: f.transform.cc:50 +msgid "Use buttons or drag right edge with mouse" +msgstr " Пользуйтесь кнопками или тащите мышью " + +#: f.transform.cc:60 fotoxx-12.01.cc:252 +msgid "Rotate Image" +msgstr "Повернуть изображение" + +#: f.transform.cc:64 +msgid "degrees" +msgstr "Градусы" + +#: f.transform.cc:80 f.transform.cc:124 +msgid "Trim" +msgstr "Кадрировать" + +#: f.transform.cc:81 f.transform.cc:2289 f.transform.cc:3120 +#: f.transform.cc:3383 f.transform.cc:3644 +msgid "Grid" +msgstr "" + +#: f.transform.cc:123 +msgid "Undo Trim" +msgstr "Отменить" + +#: f.transform.cc:139 +#, c-format +msgid "degrees: %.1f" +msgstr "Градусы: %.1f" + +#: f.transform.cc:286 +msgid "gold" +msgstr "" + +#: f.transform.cc:334 +msgid "Drag middle to move, drag corners to resize." +msgstr "" + +#: f.transform.cc:348 fotoxx-12.01.cc:253 +msgid "Trim Image" +msgstr "Кадрировать" + +#: f.transform.cc:348 +msgid "customize" +msgstr "" + +#: f.transform.cc:359 +msgid "ratio" +msgstr "" + +#: f.transform.cc:363 +msgid "Lock Ratio" +msgstr "Фиксировать соотношение сторон" + +#: f.transform.cc:368 +msgid "invert" +msgstr "" + +#: f.transform.cc:890 +msgid "Trim Buttons" +msgstr "" + +#: f.transform.cc:1064 +msgid "Lock aspect ratio" +msgstr "Фиксировать пропорции" + +#: f.transform.cc:1072 fotoxx-12.01.cc:255 +msgid "Resize Image" +msgstr "Изменить размер изображения" + +#: f.transform.cc:1095 fotoxx-12.01.cc:326 +msgid "Prev" +msgstr "Предыдущий" + +#: f.transform.cc:1245 +msgid "" +"Enter text, click/drag on image.\n" +"Right click to remove" +msgstr "" + +#: f.transform.cc:1294 fotoxx-12.01.cc:256 +msgid "Annotate Image" +msgstr "" + +#: f.transform.cc:1307 +msgid "Size" +msgstr "" + +#: f.transform.cc:1310 +msgid "Angle" +msgstr "" + +#: f.transform.cc:1321 fotoxx.h:741 +msgid "Color" +msgstr "Цвет" + +#: f.transform.cc:1322 +msgid "Transparency" +msgstr "" + +#: f.transform.cc:1325 +msgid "text" +msgstr "" + +#: f.transform.cc:1330 +msgid "backing" +msgstr "" + +#: f.transform.cc:1333 +msgid "" +"Outline\n" +" Width" +msgstr "" + +#: f.transform.cc:1335 +msgid "outline" +msgstr "" + +#: f.transform.cc:1342 +msgid "Annotation File:" +msgstr "" + +#: f.transform.cc:1416 +msgid "select font" +msgstr "" + +#: f.transform.cc:2045 fotoxx-12.01.cc:257 +msgid "Flip Image" +msgstr "Зеркальное изображение" + +#: f.transform.cc:2049 f.transform.cc:2281 +msgid "horizontal" +msgstr "Горизонталь" + +#: f.transform.cc:2050 f.transform.cc:2280 +msgid "vertical" +msgstr "Вертикаль" + +#: f.transform.cc:2155 fotoxx-12.01.cc:258 +msgid "Make Negative" +msgstr "" + +#: f.transform.cc:2158 +msgid "black/white positive" +msgstr "" + +#: f.transform.cc:2159 +msgid "black/white negative" +msgstr "" + +#: f.transform.cc:2160 +msgid "color positive" +msgstr "" + +#: f.transform.cc:2161 +msgid "color negative" +msgstr "" + +#: f.transform.cc:2272 fotoxx-12.01.cc:259 +msgid "Unbend Image" +msgstr "Изогнуть" + +#: f.transform.cc:2282 +msgid "linear" +msgstr "" + +#: f.transform.cc:2285 +msgid "curved" +msgstr "" + +#: f.transform.cc:2544 +msgid "" +" Click the four corners of a tetragon area. Press [apply]. \n" +" The image is warped to make the tetragon into a rectangle." +msgstr "" + +#: f.transform.cc:2556 fotoxx-12.01.cc:260 +msgid "Keystone Correction" +msgstr "" + +#: f.transform.cc:2724 +msgid "must have 4 corners" +msgstr "" + +#: f.transform.cc:2847 +msgid "" +" Select an area to warp using select area function. \n" +" Press [start warp] and pull area with mouse. \n" +" Make multiple mouse pulls until satisfied. \n" +" When finished, select another area or press [done]." +msgstr "" +" Выберите область для деформации \n" +" Нажмите [Деформировать] \n" +" Управляйте процессом при помощи мышки \n" +" Выберите новую область или нажмите [Применить]" + +#: f.transform.cc:2859 fotoxx-12.01.cc:261 +msgid "Warp Image (area)" +msgstr "" + +#: f.transform.cc:2864 +msgid "start warp" +msgstr "Деформировать" + +#: f.transform.cc:2931 +msgid "no active Select Area" +msgstr "" + +#: f.transform.cc:3099 f.transform.cc:3362 +msgid "" +" Pull an image position using the mouse. \n" +" Make multiple mouse pulls until satisfied. \n" +" When finished, press [done]." +msgstr "" + +#: f.transform.cc:3112 fotoxx-12.01.cc:262 +msgid "Warp Image (curved)" +msgstr "" + +#: f.transform.cc:3375 fotoxx-12.01.cc:263 +msgid "Warp Image (linear)" +msgstr "" + +#: f.transform.cc:3628 +msgid "" +" Pull on an image corner using the mouse. \n" +" Make multiple mouse pulls until satisfied. \n" +" When finished, press [done]." +msgstr "" +" Корректируйте перспективу при помощи мышки \n" +" По окончании нажмите [Применить]" + +#: f.transform.cc:3639 fotoxx-12.01.cc:264 +msgid "Warp Image (affine)" +msgstr "Корректировать перспективу (affine)" + +#: fotoxx-12.01.cc:185 +msgid "File" +msgstr "Файл" + +#: fotoxx-12.01.cc:186 fotoxx-12.01.cc:324 +msgid "Image Gallery" +msgstr "Галерея" + +#: fotoxx-12.01.cc:187 +msgid "Clone 50/50" +msgstr "" + +#: fotoxx-12.01.cc:188 +msgid "Clone Overlay" +msgstr "" + +#: fotoxx-12.01.cc:190 +msgid "Open in New Window" +msgstr "" + +#: fotoxx-12.01.cc:191 fotoxx-12.01.cc:326 +msgid "Open Previous File" +msgstr "Открыть предыдущий файл" + +#: fotoxx-12.01.cc:192 +msgid "Open Recent File" +msgstr "Открыть последний" + +#: fotoxx-12.01.cc:193 fotoxx-12.01.cc:334 +msgid "Save to Same File" +msgstr "Сохранить" + +#: fotoxx-12.01.cc:194 fotoxx-12.01.cc:335 +msgid "Save to New Version" +msgstr "" + +#: fotoxx-12.01.cc:195 fotoxx-12.01.cc:336 +msgid "Save to New File" +msgstr "Сохранить как..." + +#: fotoxx-12.01.cc:197 +msgid "Trash Image File" +msgstr "Поместить в корзину" + +#: fotoxx-12.01.cc:199 +msgid "Batch Rename Files" +msgstr "Групповое переименование" + +#: fotoxx-12.01.cc:200 +msgid "Print Image File" +msgstr "Печать" + +#: fotoxx-12.01.cc:201 fotoxx-12.01.cc:340 +msgid "Quit fotoxx" +msgstr "Выход из fotoxx" + +#: fotoxx-12.01.cc:203 +msgid "Tools" +msgstr "Инструменты" + +#: fotoxx-12.01.cc:206 +msgid "Batch Convert" +msgstr "" + +#: fotoxx-12.01.cc:207 +msgid "Convert RAW files" +msgstr "Конвертировать RAW-файлы" + +#: fotoxx-12.01.cc:212 +msgid "Burn Images to CD/DVD" +msgstr "Записать на CD/DVD" + +#: fotoxx-12.01.cc:214 +msgid "Check Monitor" +msgstr "Отображение цветов" + +#: fotoxx-12.01.cc:217 +msgid "Change Language" +msgstr "Изменить язык" + +#: fotoxx-12.01.cc:219 +msgid "Menu and Launcher" +msgstr "" + +#: fotoxx-12.01.cc:220 +msgid "User Settings" +msgstr "" + +#: fotoxx-12.01.cc:221 +msgid "Memory Usage" +msgstr "" + +#: fotoxx-12.01.cc:224 +msgid "Edit Caption/Comments" +msgstr "" + +#: fotoxx-12.01.cc:229 +msgid "View Info (short)" +msgstr "" + +#: fotoxx-12.01.cc:230 +msgid "View Info (long)" +msgstr "" + +#: fotoxx-12.01.cc:233 +msgid "Search Images" +msgstr "" + +#: fotoxx-12.01.cc:234 +msgid "Search Metadata" +msgstr "" + +#: fotoxx-12.01.cc:236 fotoxx-12.01.cc:237 fotoxx.h:786 +msgid "Select" +msgstr "Выбрать" + +#: fotoxx-12.01.cc:238 fotoxx.h:788 +msgid "Show" +msgstr "Показать" + +#: fotoxx-12.01.cc:239 fotoxx.h:761 +msgid "Hide" +msgstr "Скрыть" + +#: fotoxx-12.01.cc:240 fotoxx.h:752 +msgid "Enable" +msgstr "Доступно" + +#: fotoxx-12.01.cc:241 fotoxx.h:748 +msgid "Disable" +msgstr "Не доступно" + +#: fotoxx-12.01.cc:242 fotoxx.h:763 +msgid "Invert" +msgstr "Инвертировать" + +#: fotoxx-12.01.cc:243 fotoxx.h:796 +msgid "Unselect" +msgstr "" + +#: fotoxx-12.01.cc:244 fotoxx.h:743 +msgid "Copy" +msgstr "Копировать" + +#: fotoxx-12.01.cc:245 fotoxx.h:771 +msgid "Paste" +msgstr "Вставить" + +#: fotoxx-12.01.cc:247 fotoxx-12.01.cc:334 fotoxx.h:783 +msgid "Save" +msgstr "Сохранить" + +#: fotoxx-12.01.cc:249 +msgid "Select and Edit" +msgstr "" + +#: fotoxx-12.01.cc:251 +msgid "Transform" +msgstr "Изменить" + +#: fotoxx-12.01.cc:254 +msgid "Auto-Trim Image" +msgstr "" + +#: fotoxx-12.01.cc:266 +msgid "Retouch" +msgstr "Ретушировать" + +#: fotoxx-12.01.cc:267 +msgid "Brightness/Color" +msgstr "Яркость и цветность" + +#: fotoxx-12.01.cc:268 +msgid "Gamma Curves" +msgstr "" + +#: fotoxx-12.01.cc:269 +msgid "Expand Brightness" +msgstr "Расширение яркости" + +#: fotoxx-12.01.cc:270 +msgid "Flatten Brightness" +msgstr "Выравнять яркость" + +#: fotoxx-12.01.cc:271 +msgid "Brightness Ramp" +msgstr "Распределение яркости" + +#: fotoxx-12.01.cc:273 +msgid "White Balance" +msgstr "Баланс белого" + +#: fotoxx-12.01.cc:274 +msgid "Match Colors" +msgstr "" + +#: fotoxx-12.01.cc:277 +msgid "Red Eyes" +msgstr "Эффект красных глаза" + +#: fotoxx-12.01.cc:278 +msgid "Blur Image" +msgstr "Размыть" + +#: fotoxx-12.01.cc:280 +msgid "Reduce Noise" +msgstr "Уменьшить шум" + +#: fotoxx-12.01.cc:286 +msgid "Art" +msgstr "Эффекты" + +#: fotoxx-12.01.cc:287 +msgid "Color Depth" +msgstr "Глубина цвета" + +#: fotoxx-12.01.cc:288 +msgid "Drawing" +msgstr "" + +#: fotoxx-12.01.cc:289 +msgid "Outlines" +msgstr "" + +#: fotoxx-12.01.cc:290 +msgid "Embossing" +msgstr "" + +#: fotoxx-12.01.cc:291 +msgid "Tiles" +msgstr "" + +#: fotoxx-12.01.cc:292 +msgid "Dots" +msgstr "" + +#: fotoxx-12.01.cc:293 +msgid "Painting" +msgstr "" + +#: fotoxx-12.01.cc:295 +msgid "Combine" +msgstr "Комбинировать" + +#: fotoxx-12.01.cc:296 +msgid "High Dynamic Range" +msgstr "" + +#: fotoxx-12.01.cc:297 +msgid "High Depth of Field" +msgstr "" + +#: fotoxx-12.01.cc:298 +msgid "Stack / Paint" +msgstr "" + +#: fotoxx-12.01.cc:299 +msgid "Stack / Noise" +msgstr "" + +#: fotoxx-12.01.cc:300 +msgid "Panorama" +msgstr "Панорама" + +#: fotoxx-12.01.cc:301 +msgid "Vertical Panorama" +msgstr "" + +#: fotoxx-12.01.cc:304 +msgid "Edit Plugins" +msgstr "" + +#: fotoxx-12.01.cc:313 fotoxx-12.01.cc:341 fotoxx-12.01.cc:3026 +msgid "Help" +msgstr "Помощь" + +#: fotoxx-12.01.cc:314 fotoxx-12.01.cc:3016 +msgid "About" +msgstr "О fotoxx" + +#: fotoxx-12.01.cc:315 fotoxx-12.01.cc:3020 +msgid "User Guide" +msgstr "Руководство пользователя" + +#: fotoxx-12.01.cc:316 fotoxx-12.01.cc:3023 +msgid "User Guide Changes" +msgstr "" + +#: fotoxx-12.01.cc:317 fotoxx-12.01.cc:3032 +msgid "Edit Functions Summary" +msgstr "" + +#: fotoxx-12.01.cc:318 fotoxx-12.01.cc:3035 +msgid "Change Log" +msgstr "Журнал изменений" + +#: fotoxx-12.01.cc:319 fotoxx-12.01.cc:3038 +msgid "Translations" +msgstr "" + +#: fotoxx-12.01.cc:320 fotoxx-12.01.cc:3041 +msgid "Home Page" +msgstr "Домашняя страница" + +#: fotoxx-12.01.cc:324 +msgid "Gallery" +msgstr "Галерея" + +#: fotoxx-12.01.cc:327 fotoxx.h:767 +msgid "Next" +msgstr "Дальше" + +#: fotoxx-12.01.cc:327 +msgid "Open Next File" +msgstr "Открыть следующий файл" + +#: fotoxx-12.01.cc:328 +msgid "Zoom-in (bigger)" +msgstr "Увеличить" + +#: fotoxx-12.01.cc:329 +msgid "Zoom-out (smaller)" +msgstr "Уменьшить" + +#: fotoxx-12.01.cc:330 fotoxx.h:794 +msgid "Undo" +msgstr "Отменить" + +#: fotoxx-12.01.cc:330 +msgid "Undo One Edit" +msgstr "Отменить" + +#: fotoxx-12.01.cc:331 fotoxx.h:779 +msgid "Redo" +msgstr "Применить" + +#: fotoxx-12.01.cc:331 +msgid "Redo One Edit" +msgstr "Применить отмененное" + +#: fotoxx-12.01.cc:335 +msgid "Save+V" +msgstr "" + +#: fotoxx-12.01.cc:336 +msgid "Save+F" +msgstr "" + +#: fotoxx-12.01.cc:337 +msgid "Move Image to Trash" +msgstr "Переместить изображение в корзину" + +#: fotoxx-12.01.cc:337 +msgid "Trash" +msgstr "Мусор" + +#: fotoxx-12.01.cc:340 +msgid "Quit" +msgstr "Выход" + +#: fotoxx-12.01.cc:341 +msgid "Fotoxx Essentials" +msgstr "" + +#: fotoxx-12.01.cc:448 +msgid "first time startup" +msgstr "" + +#: fotoxx-12.01.cc:1944 +msgid "Exceed 50 anchor points" +msgstr "Требуется более 50 точек" + +#: fotoxx-12.01.cc:2129 +msgid "load curve from a file" +msgstr "" + +#: fotoxx-12.01.cc:2182 +msgid "curve file is invalid" +msgstr "" + +#: fotoxx-12.01.cc:2187 +msgid "curve file has different no. of curves" +msgstr "" + +#: fotoxx-12.01.cc:2202 +msgid "save curve to a file" +msgstr "" + +#: fotoxx-12.01.cc:2337 +msgid "cannot parallel edit" +msgstr "" + +#: fotoxx-12.01.cc:2347 +msgid "" +"exiftool is not installed \n" +"edited images will lose EXIF data" +msgstr "" +"EXIFtool не установлен \n" +"будут потеряны данные EXIF" + +#: fotoxx-12.01.cc:2353 +msgid "Too many edits, please save image" +msgstr "Слишком много изменений, пожалуйста сограните изображение" + +#: fotoxx-12.01.cc:2358 +msgid "" +"Select area cannot be kept.\n" +"Continue?" +msgstr "" +"Выбранная область не сохранена.\n" +"Продолжить?" + +#: fotoxx-12.01.cc:2366 +msgid "" +"Select area not active.\n" +"Continue?" +msgstr "" +"Выбранная область не активна.\n" +"Продолжить?" + +#: fotoxx-12.01.cc:2837 +msgid "Discard edits?" +msgstr "" + +#: fotoxx-12.01.cc:2838 +msgid "" +"This action will discard current edits.\n" +"Continue to discard edits.\n" +"Go Back to keep edits." +msgstr "" + +#: fotoxx-12.01.cc:2841 +msgid "Continue" +msgstr "" + +#: fotoxx-12.01.cc:2842 +msgid "Go Back" +msgstr "" + +#: fotoxx-12.01.cc:3659 +msgid "cannot open thumbnail file" +msgstr "не могу найти файл" + +#: fotoxx-12.01.cc:3870 fotoxx-12.01.cc:3992 +msgid "TIFF open failure" +msgstr "TIFF ошибка открытия" + +#: fotoxx-12.01.cc:3886 +#, c-format +msgid "TIFF bits/color=%d not supported" +msgstr "" + +#: fotoxx-12.01.cc:3901 fotoxx-12.01.cc:3939 +msgid "TIFF read failure" +msgstr "TIFF ошибка чтения" + +#: fotoxx-12.01.cc:4051 +msgid "TIFF write failure" +msgstr "TIFF ошибка записи" + +#: fotoxx-12.01.cc:4071 +msgid "file type not supported" +msgstr "Этот формат файлов не поддерживается" + +#: fotoxx-12.01.cc:4178 +msgid "pixbuf write failure" +msgstr "Pixbuf - ошибка записи" + +#: fotoxx.h:728 +msgid "absolute" +msgstr "" + +#: fotoxx.h:730 +msgid "Add All" +msgstr "Добавить все" + +#: fotoxx.h:732 +msgid "Amount" +msgstr "Количество" + +#: fotoxx.h:733 +msgid "Apply" +msgstr "Применить" + +#: fotoxx.h:734 +msgid "Black" +msgstr "" + +#: fotoxx.h:735 +msgid "Blend Width" +msgstr "Ширина перекрытия" + +#: fotoxx.h:737 +msgid "Brightness" +msgstr "Яркость" + +#: fotoxx.h:738 +msgid "Browse" +msgstr "" + +#: fotoxx.h:739 +msgid "Cancel" +msgstr "Отмена" + +#: fotoxx.h:740 +msgid "Clear" +msgstr "Очистить" + +#: fotoxx.h:742 +msgid "Commit" +msgstr "" + +#: fotoxx.h:744 +msgid "Curve File:" +msgstr "" + +#: fotoxx.h:745 +msgid "Cut" +msgstr "" + +#: fotoxx.h:746 +msgid "Darker Areas" +msgstr "Темные области" + +#: fotoxx.h:747 +msgid "Delete" +msgstr "Удалить" + +#: fotoxx.h:749 +#, c-format +msgid "" +"Discard special gallery list? \n" +" %s" +msgstr "" + +#: fotoxx.h:750 +msgid "Done" +msgstr "Применить" + +#: fotoxx.h:751 +msgid "Edit" +msgstr "Редактировать" + +#: fotoxx.h:753 +msgid "Erase" +msgstr "" + +#: fotoxx.h:754 +msgid "package libimage-exiftool-perl is required" +msgstr "" + +#: fotoxx.h:755 +msgid "Fetch" +msgstr "Получить" + +#: fotoxx.h:756 +msgid "Finish" +msgstr "Финиш" + +#: fotoxx.h:757 +msgid "Font" +msgstr "" + +#: fotoxx.h:759 +msgid "Height" +msgstr "Высота" + +#: fotoxx.h:760 +msgid "histogram" +msgstr "Гистограмма" + +#: fotoxx.h:762 +msgid "Insert" +msgstr "Вставить" + +#: fotoxx.h:764 +msgid "Lighter Areas" +msgstr "Светлые области" + +#: fotoxx.h:765 +msgid "limit" +msgstr "Лимит" + +#: fotoxx.h:766 +msgid "New" +msgstr "" + +#: fotoxx.h:768 +msgid "OK" +msgstr "Ok" + +#: fotoxx.h:772 +msgid "Pause" +msgstr "Пауза" + +#: fotoxx.h:773 +msgid "Percent" +msgstr "%" + +#: fotoxx.h:774 +msgid "Presets" +msgstr "Пресеты" + +#: fotoxx.h:775 +msgid "Proceed" +msgstr "Начать" + +#: fotoxx.h:777 +msgid "range" +msgstr "Расстояние" + +#: fotoxx.h:780 +msgid "Reduce" +msgstr "Уменьшить" + +#: fotoxx.h:782 +msgid "Reset" +msgstr "" + +#: fotoxx.h:784 +msgid "Unknown file type, save as tiff/jpeg/png to edit" +msgstr "Неизвестный тип файла, сохраните как tiff/jpeg/png для редактирования" + +#: fotoxx.h:785 +msgid "Search" +msgstr "Поиск" + +#: fotoxx.h:789 +msgid "Start" +msgstr "Старт" + +#: fotoxx.h:790 +msgid "Threshold" +msgstr "Порог" + +#: fotoxx.h:791 +#, c-format +msgid "exceed %d files" +msgstr "" + +#: fotoxx.h:792 +msgid "Undo All" +msgstr "Отменить все" + +#: fotoxx.h:793 +msgid "Undo Last" +msgstr "Отменить последнее" + +#: fotoxx.h:795 +msgid "Unfinish" +msgstr "" + +#: fotoxx.h:797 +msgid "View" +msgstr "" + +#: fotoxx.h:798 +msgid "White" +msgstr "" + +#: fotoxx.h:799 +msgid "Width" +msgstr "Ширина" + +#: zfuncs.cc:3252 +#, c-format +msgid "help file not found: %s" +msgstr "Файл помощи %s не найден" + +#: zfuncs.cc:3664 zfuncs.cc:7315 +#, c-format +msgid "cannot open file %s" +msgstr "Не могу открыть файл %s" + +#: zfuncs.cc:3697 +msgid "save screen to file" +msgstr "Сохранить изображение в файл" + +#: zfuncs.cc:6222 +msgid "No" +msgstr "" + +#: zfuncs.cc:6222 +msgid "Yes" +msgstr "" + +#: zfuncs.cc:6447 +msgid "open" +msgstr "Открыть" + +#: zfuncs.cc:6452 +msgid "choose" +msgstr "" + +#: zfuncs.cc:6457 +msgid "save" +msgstr "Сохранить" + +#: zfuncs.cc:6463 +msgid "open folder" +msgstr "Открыть папку" + +#: zfuncs.cc:6468 +msgid "create folder" +msgstr "Создать папку" + +#: zfuncs.cc:6474 +msgid "hidden" +msgstr "Скрыть" + +#: zfuncs.cc:6535 +msgid "JPG quality 0-100" +msgstr "Качество JPG 0-100" + +#: zfuncs.cc:6728 zfuncs.cc:6741 +msgid "margins" +msgstr "" + +#: zfuncs.cc:6737 +msgid "top" +msgstr "" + +#: zfuncs.cc:6738 +msgid "bottom" +msgstr "" + +#: zfuncs.cc:6739 +msgid "left" +msgstr "" + +#: zfuncs.cc:6740 +msgid "right" +msgstr "" + +#: zfuncs.cc:7202 +msgid "" +"Initial parameters file created. \n" +"Inspect and revise if necessary." +msgstr "" +"Файл параметров создан \n" +"Проверьте при необходимости" + +#: zfuncs.cc:7218 +msgid "load parameters from a file" +msgstr "Загрузить параметры из файла" + +#: zfuncs.cc:7287 +msgid "save parameters to a file" +msgstr "Сохранить параметры в файл" + +#: zfuncs.cc:7425 zfuncs.cc:7431 zfuncs.cc:7437 zfuncs.cc:7443 +msgid "edit parameters" +msgstr "Редактировать пареметры" + +#: zfuncs.cc:7426 zfuncs.cc:7432 +msgid "" +"list\n" +"all" +msgstr "" +"Показать\n" +"все" + +#: zfuncs.cc:7426 zfuncs.cc:7432 zfuncs.cc:7438 zfuncs.cc:7444 +msgid "" +"load\n" +"file" +msgstr "" +"Загрузить\n" +"файл" + +#: zfuncs.cc:7426 zfuncs.cc:7432 zfuncs.cc:7438 zfuncs.cc:7444 +msgid "" +"save\n" +"file" +msgstr "" +"Сохранить\n" +"файл" + +#: zfuncs.cc:7427 zfuncs.cc:7439 +msgid "" +"add\n" +"new" +msgstr "" +"Добавить\n" +"новый" + +#: zfuncs.cc:7427 zfuncs.cc:7433 zfuncs.cc:7439 zfuncs.cc:7445 +msgid "apply" +msgstr "Применить" + +#: zfuncs.cc:7479 +msgid "apply?" +msgstr "Применить?" + +#: zfuncs.cc:7536 +msgid "(new parm name)" +msgstr "(новые параметры)" + +#: zfuncs.cc:7536 +msgid "add parameter" +msgstr "Добавить параметр" + +#~ msgid "Brightness Graph" +#~ msgstr "Диаграмма яркости" + +#~ msgid "radius" +#~ msgstr "Радиус" + +#~ msgid "Search results file error %s" +#~ msgstr "Поиск ошибок %s" + +#~ msgid "Select area first" +#~ msgstr "Сначала выберите область" + +#~ msgid "open a file" +#~ msgstr "Открыть файл" + +#~ msgid "paper format is crazy" +#~ msgstr "Невозможный формат печати" + +#~ msgid "landscape" +#~ msgstr "Ландшафт" + +#~ msgid "portrait" +#~ msgstr "Портрет" + +#~ msgid "paper format" +#~ msgstr "Формат печати" + +#~ msgid "printer ID" +#~ msgstr "ID принтера" + +#~ msgid "print" +#~ msgstr "Печать" + +#~ msgid "Time Interval" +#~ msgstr "Временной интервал" + +#~ msgid "Clone fotoxx" +#~ msgstr "Клонировать fotoxx" + +#~ msgid "Save As" +#~ msgstr "Сохранить как" + +#~ msgid "click on window to show RGB" +#~ msgstr "Кликните по окну, чтобы увидеть RGB" + +#~ msgid "Create Launcher" +#~ msgstr "Создать стартовую иконку" + +#~ msgid "" +#~ "Search all areas for edge and inside pixels. \n" +#~ "Click inside each enclosed area in sequence." +#~ msgstr "" +#~ "Поиск областей \n" +#~ "Кликните вне области" + +#~ msgid "area outline has a hole" +#~ msgstr "В области есть дыра" + +#~ msgid "horizontal unbend" +#~ msgstr "По горизонтали" + +#~ msgid "vertical unbend" +#~ msgstr "По вертикали" + +#~ msgid "target group area" +#~ msgstr "Область" + +#~ msgid "Area" +#~ msgstr "Область" + +#~ msgid "Constrain" +#~ msgstr "Ограничение" + +#~ msgid "Convert Tags !!!" +#~ msgstr "Конвертировать теги" + +#~ msgid "Convert tags to new standard" +#~ msgstr "Конверировать теги по новому стандарту" + +#~ msgid "HDF" +#~ msgstr "HDF" + +#~ msgid "HDR" +#~ msgstr "HDR" + +#~ msgid "No tags index file" +#~ msgstr "Нет индексного файла" + +#~ msgid "Rebuild Tags Index" +#~ msgstr "Переиндексировать теги" + +#~ msgid "Use F1 for context help" +#~ msgstr "Получите помощь по F1" + +#~ msgid "brightness to clip (percent)" +#~ msgstr "Яркость (%)" + +#~ msgid "cannot read .dist file" +#~ msgstr "Не могу прочесть .dist-файл" + +#~ msgid "new tags index will now be created" +#~ msgstr "Будет создан новый индекс тегов" + +#~ msgid "save select area as a file" +#~ msgstr "Сохранить выбранную область как файл" + +#~ msgid "tags index file error: %s" +#~ msgstr "Ошибка индексного файла тегов: %s" + +#~ msgid "/path*/file*" +#~ msgstr "/путь*/файл*" + +#~ msgid "All EXIF data" +#~ msgstr "Все EXIF-данные" + +#~ msgid "Basic EXIF data" +#~ msgstr "Основные EXIF-данные" + +#~ msgid "Delete EXIF data" +#~ msgstr "Удалить EXIF-данные" + +#~ msgid "EXIF data" +#~ msgstr "EXIF-данные" + +#~ msgid "Edit EXIF data" +#~ msgstr "Редактировать EXIF-данные" + +#~ msgid "Resume" +#~ msgstr "Продолжить" + +#~ msgid "Search Tags" +#~ msgstr "Поиск тегов" + +#~ msgid "Set Tile and Gap Size" +#~ msgstr "Элементы и промежутки" + +#~ msgid "Suspend" +#~ msgstr "Приостановить" + +#~ msgid "Tags" +#~ msgstr "Теги" + +#~ msgid "match all tags" +#~ msgstr "Соответствие всех тегов" + +#~ msgid "match any tag" +#~ msgstr "Соответствие любого тега" + +#~ msgid "" +#~ " Pull on an image edge using the mouse. \n" +#~ " Make multiple mouse pulls until satisfied. \n" +#~ " When finished, press [done]." +#~ msgstr "" +#~ " Корректируйте перспективу при помощи мышки \n" +#~ " По окончании нажмите [Применить]" + +#~ msgid "Warp Area" +#~ msgstr "Выборочная деформация" + +#~ msgid "Warp Image (curvy)" +#~ msgstr "Корректировать перспективу (kurvig)" + +#~ msgid "Warp Image in Selected Area" +#~ msgstr "Деформировать изображение в выбранной области" + +#~ msgid "" +#~ "position image\n" +#~ "with mouse drag" +#~ msgstr "" +#~ "Позиция\n" +#~ "С мышкой" + +#~ msgid "Read File" +#~ msgstr "Из файла" + +#~ msgid "color intensity" +#~ msgstr "Интенсивность цвета" + +#~ msgid "Burn" +#~ msgstr "Прожечь" + +#~ msgid "" +#~ "Convert tags to new standard now?\n" +#~ "Are your image files backed-up?" +#~ msgstr "" +#~ "Конвертировать теги в новый формат сейчас?\n" +#~ "Вы сделали резервные копии изображений?" + +#~ msgid "Fix Image Perspective" +#~ msgstr "Корректировать перспективу" + +#~ msgid "TIFF colors=%d depth=%d not supported" +#~ msgstr "TIFF цвета=%d глубина=%d не поддерживается" + +#~ msgid "add tags" +#~ msgstr "Добавить теги" + +#~ msgid "browse" +#~ msgstr "Просмотр" + +#~ msgid "color range" +#~ msgstr "По уровню цвета" + +#~ msgid "" +#~ "exiftool missing, please install \n" +#~ " package libimage-exiftool-perl" +#~ msgstr "" +#~ "EXIFtool не найден, пожалуйста, установите \n" +#~ "libimage-exiftool-perl" + +#~ msgid "follow edge" +#~ msgstr "По краю" + +#~ msgid "freehand draw" +#~ msgstr "Произвольная область" + +#~ msgid "rename files" +#~ msgstr "Переименовать файлы" + +#~ msgid "select files" +#~ msgstr "Выберите файлы" + +#~ msgid "select image files to add tags" +#~ msgstr "Выберите файлы изображений для добавления тегов" + +#~ msgid "" +#~ "\n" +#~ " Match Brightness and Color" +#~ msgstr "" +#~ "\n" +#~ " Соответствие цвета и яркости" + +#~ msgid "Auto" +#~ msgstr "Авто" + +#~ msgid "Auto-search lens mm and bow" +#~ msgstr "Автоматический поиск параметров объектива" + +#~ msgid "" +#~ "Drag right image into rough alignment with left \n" +#~ " to rotate, drag right edge up or down" +#~ msgstr "" +#~ "Тяните правое изображение до совмещения с левым \n" +#~ "Для поворота тяните правый край вверх или вниз" + +#~ msgid "Match Images" +#~ msgstr "Bilder angleichen" + +#~ msgid "Merge the images together" +#~ msgstr "Bilder miteinander verbinden" + +#~ msgid "Package ufraw required for this function" +#~ msgstr "Для этой функции требуется пакет ufraw" + +#~ msgid "Retouch Image" +#~ msgstr "Ретушировать изображение" + +#~ msgid "Select 2 to 10 files to combine" +#~ msgstr "Выбрать от 2 до 10 изображений" + +#~ msgid "Select image to combine" +#~ msgstr "Выберите изображение" + +#~ msgid "Current file must be included" +#~ msgstr "Файл должен быть включен" + +#~ msgid "Select between 2 and 10 files to combine" +#~ msgstr "Выберите от 2 до 10 файлов" + +#~ msgid "jpeg quality" +#~ msgstr "Качество jpeg" + +#~ msgid "" +#~ "%s \n" +#~ " tag limit exceeded" +#~ msgstr "" +#~ "%s \n" +#~ " Превышен лимит тегов" + +#~ msgid "Add or Remove Grid Lines" +#~ msgstr "Добавить или удалить сетку" + +#~ msgid "" +#~ "Drag middle to move \n" +#~ "Drag corners to resize" +#~ msgstr "" +#~ "Тяните за середину, чтобы переместить \n" +#~ "Тяните за края, чтобы изменить размер" + +#~ msgid "Index Tags" +#~ msgstr "Переиндексировать теги" + +#~ msgid "Too many tags: %d" +#~ msgstr "Слишком много тегов: %d" + +#~ msgid "Total tags exceed %d characters" +#~ msgstr "Общее превышение %d символов" + +#~ msgid "Unable to copy EXIF data" +#~ msgstr "Не могу скопировать EXIF-данные" + +#~ msgid "Unable to save image: %s" +#~ msgstr "Не могу сохранить изображение: %s" + +#~ msgid "assigned tags" +#~ msgstr "Назначенные признаки" + +#~ msgid "grid spacing" +#~ msgstr "Параметры сетки" + +#~ msgid "recently added" +#~ msgstr "Последние добавленные" + +#~ msgid "tags exceed %d characters" +#~ msgstr "Тег превысил %d символов" + +#~ msgid "Discard modifications?" +#~ msgstr "Отменить модификации?" + +#~ msgid "" +#~ "Rename failed \n" +#~ " %s" +#~ msgstr "" +#~ "Переименование остановлено \n" +#~ " %s" + +#~ msgid "incremental" +#~ msgstr "Инкрементная индексация" + +#~ msgid "full rebuild" +#~ msgstr "Полная переиндексация" + +#~ msgid "Translate" +#~ msgstr "Перевод" + +#~ msgid "select new file" +#~ msgstr "Выбрть новый файл" + +#~ msgid "lens name" +#~ msgstr "Объектив" + +#~ msgid "Lens Parameters" +#~ msgstr "Параметры объектива" diff -Nru fotoxx-11.11.1/locales/fotoxx-sv.po fotoxx-12.01.2/locales/fotoxx-sv.po --- fotoxx-11.11.1/locales/fotoxx-sv.po 1970-01-01 00:00:00.000000000 +0000 +++ fotoxx-12.01.2/locales/fotoxx-sv.po 2012-01-04 08:47:11.000000000 +0000 @@ -0,0 +1,3160 @@ +# translation of fotoxx.po to svenska +# Swedish translations for fotoxx package +# Svenska översättningar för paket fotoxx. +# Copyright (C) 2010 THE fotoxx'S COPYRIGHT HOLDER +# This file is distributed under the same license as the fotoxx package. +# +# progdev , 2010. +# Peter Landgren , 2010, 2011, 2012. +msgid "" +msgstr "" +"Project-Id-Version: fotoxx\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2012-01-04 02:54+0100\n" +"PO-Revision-Date: 2012-01-02 15:40+0100\n" +"Last-Translator: Peter Landgren \n" +"Language-Team: Swedish \n" +"Language: sv\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Lokalize 1.0\n" + +#: f.art.cc:47 +msgid "Set color depth to 1-16 bits" +msgstr "Sätt färgdjup till 1-16 bitar" + +#: f.art.cc:57 +msgid "Set Color Depth" +msgstr "Välj färgdjup" + +#: f.art.cc:171 +msgid "Simulate Drawing" +msgstr "Simulera ritning" + +#: f.art.cc:213 f.retouch.cc:1759 f.retouch.cc:5991 +msgid "contrast" +msgstr "kontrast" + +#: f.art.cc:215 +msgid "outlines" +msgstr "konturer" + +#: f.art.cc:220 +msgid "pencil" +msgstr "penna" + +#: f.art.cc:221 +msgid "chalk" +msgstr "krita" + +#: f.art.cc:381 +msgid "Add Image Outlines" +msgstr "Lägg till bildkanter" + +#: f.art.cc:394 +msgid "outline threshold" +msgstr "konturtröskel" + +#: f.art.cc:397 +msgid "outline width" +msgstr "konturbredd" + +#: f.art.cc:400 +msgid "image brightness" +msgstr "bildljushet" + +#: f.art.cc:611 +msgid "Simulate Embossing" +msgstr "Simulera upphöjning" + +#: f.art.cc:626 +msgid "depth" +msgstr "djup" + +#: f.art.cc:628 f.file.cc:921 f.retouch.cc:6692 +msgid "color" +msgstr "färg" + +#: f.art.cc:821 +msgid "Simulate Tiles" +msgstr "Simulera plattor" + +#: f.art.cc:825 +msgid "tile size" +msgstr "plattstorlek" + +#: f.art.cc:829 +msgid "tile gap" +msgstr "gap mellan plattor" + +#: f.art.cc:1003 +msgid "Convert Image to Dots" +msgstr "Omvandla bild till punkter" + +#: f.art.cc:1007 +msgid "dot size" +msgstr "punktstorlek" + +#: f.art.cc:1222 +msgid "Simulate Painting" +msgstr "Simulera målning" + +#: f.art.cc:1226 +msgid "color depth" +msgstr "färgdjup" + +#: f.art.cc:1230 +msgid "patch area goal" +msgstr "" + +#: f.art.cc:1234 +msgid "req. color match" +msgstr "beg. färgmatchning" + +#: f.art.cc:1238 +msgid "borders" +msgstr "kanter" + +#: f.comp.cc:1956 f.comp.cc:1961 f.comp.cc:2582 f.comp.cc:2587 f.comp.cc:3266 +#: f.comp.cc:3271 f.comp.cc:3816 f.comp.cc:3821 +msgid "Select 2 to 9 files" +msgstr "Välj 2 till 9 filer" + +#: f.comp.cc:1982 f.comp.cc:2608 f.comp.cc:3292 f.comp.cc:3842 +msgid "Images are not all the same size" +msgstr "Alla bilder har ej samma storlek" + +#: f.comp.cc:2321 +msgid "Adjust Image Contributions" +msgstr "Justera bildbidrag" + +#: f.comp.cc:2324 f.retouch.cc:886 +msgid "dark pixels" +msgstr "mörka pixlar" + +#: f.comp.cc:2326 +msgid "light pixels" +msgstr "ljusa pixlar" + +#: f.comp.cc:2328 f.info.cc:159 +msgid "file:" +msgstr "fil:" + +#: f.comp.cc:2843 +msgid "Paint and Warp Image" +msgstr "Måla och vik ihop bild" + +#: f.comp.cc:2846 f.comp.cc:3520 f.comp.cc:4959 f.comp.cc:5705 +msgid "image" +msgstr "bild" + +#: f.comp.cc:2850 f.retouch.cc:6696 +msgid "paint" +msgstr "måla" + +#: f.comp.cc:2851 +msgid "warp" +msgstr "vik ihop" + +#: f.comp.cc:3518 +msgid "Select and Paint Image" +msgstr "Välj och färglägg bild" + +#: f.comp.cc:4031 +msgid "Adjust Pixel Composition" +msgstr "Justera pixelsammansättning" + +#: f.comp.cc:4283 f.comp.cc:4288 f.comp.cc:5173 f.comp.cc:5178 +msgid "Select 2 to 4 files" +msgstr "Välj 2 till 4 filer" + +#: f.comp.cc:4361 +msgid "" +"Drag images into rough alignment.\n" +"To rotate, drag from lower edge." +msgstr "" +"Drag bilder till grov passning\n" +"Drag i underkant för rotera." + +#: f.comp.cc:4363 +msgid "Search for lens mm and bow" +msgstr "Sök efter lins och kräkning" + +#: f.comp.cc:4409 f.comp.cc:5298 +msgid "Pre-align Images" +msgstr "Rad upp bilder preliminärt" + +#: f.comp.cc:4413 f.comp.cc:5302 +msgid "lens mm" +msgstr "lins mm" + +#: f.comp.cc:4417 f.comp.cc:5306 +msgid "lens bow" +msgstr "linskurva" + +#: f.comp.cc:4419 f.comp.cc:5308 +msgid "Resize" +msgstr "Ändra storlek" + +#: f.comp.cc:4420 f.comp.cc:5309 +msgid "resize window" +msgstr "ändra fänsterstorlek" + +#: f.comp.cc:4457 +msgid "use two images only" +msgstr "använd bara två bilder" + +#: f.comp.cc:4478 f.comp.cc:4676 f.comp.cc:4875 f.comp.cc:5357 f.comp.cc:5620 +msgid "Too little overlap, cannot align" +msgstr "För lite överlappning, kan ej rada upp" + +#: f.comp.cc:4950 f.comp.cc:5696 +msgid "Match Brightness and Color" +msgstr "Matcha ljushet och färg" + +#: f.comp.cc:4974 f.comp.cc:5720 +msgid "auto color" +msgstr "automatisk färg" + +#: f.comp.cc:4975 f.comp.cc:5721 +msgid "file color" +msgstr "filfärg" + +#: f.comp.cc:5251 +msgid "" +"Drag images into rough alignment.\n" +"To rotate, drag from right edge." +msgstr "" +"Drag bilder till grov passninf.\n" +"Rotera genom att dra från höger kant." + +#: f.file.cc:169 f.file.cc:341 fotoxx-12.01.1.cc:188 fotoxx-12.01.1.cc:324 +msgid "Open Image File" +msgstr "Öppna bildfil" + +#: f.file.cc:321 fotoxx-12.01.1.cc:2861 +msgid "prior function still active" +msgstr "föregående funktion fortfarande aktiv" + +#: f.file.cc:503 +msgid "Overwrite original file?" +msgstr "Skriva över originalfilen?" + +#: f.file.cc:504 +msgid "Do not warn again" +msgstr "Varna inte igen" + +#: f.file.cc:520 +msgid "Warning" +msgstr "Varning" + +#: f.file.cc:643 +msgid "Save File" +msgstr "Spara fil" + +#: f.file.cc:666 zfuncs.cc:6478 +msgid "quality" +msgstr "kvalitet" + +#: f.file.cc:668 +msgid "make current" +msgstr "sätt aktuell" + +#: f.file.cc:725 +msgid "jpeg quality must be 1-100" +msgstr "jpegkvalitete måste vara 1-100" + +#: f.file.cc:747 +#, c-format +msgid "" +"Overwrite file? \n" +" %s" +msgstr "" +"Skriva över fil? \n" +" %s" + +#: f.file.cc:905 fotoxx-12.01.1.cc:195 +msgid "Create Blank Image" +msgstr "Skapa tom bild" + +#: f.file.cc:907 +msgid "file name" +msgstr "filnamn" + +#: f.file.cc:912 f.transform.cc:353 +msgid "width" +msgstr "bredd" + +#: f.file.cc:915 f.tools.cc:477 f.transform.cc:356 +msgid "height" +msgstr "höjd" + +#: f.file.cc:1035 +msgid "" +"Linux standard trash is not supported. \n" +"Desktop trash folder will be created." +msgstr "" +"Linux standarpapperskorg stöds ej. \n" +"En skrivbordspapperskorg kommer att skapas." + +#: f.file.cc:1053 +msgid "Move read-only file to trash?" +msgstr "Flytta skrivskyddd fil till Skräp?" + +#: f.file.cc:1079 +#, c-format +msgid "Cannot create trash folder: %s" +msgstr "Kan ej skapa skräpmapp: %s" + +#: f.file.cc:1087 f.file.cc:1093 zfuncs.cc:3356 +#, c-format +msgid "error: %s" +msgstr "fel: %s" + +#: f.file.cc:1138 fotoxx-12.01.1.cc:197 +msgid "Rename Image File" +msgstr "Döp om bildfil" + +#: f.file.cc:1143 +msgid "old name" +msgstr "gammalt namn" + +#: f.file.cc:1144 +msgid "rename to" +msgstr "döp om till" + +#: f.file.cc:1145 +msgid "previous" +msgstr "föregående" + +#: f.file.cc:1231 +msgid "The target file already exists" +msgstr "Målfilen finns redan" + +#: f.file.cc:1239 +#, c-format +msgid "" +"Rename failed: \n" +" %s" +msgstr "" +"Omdöpning misslyckades: \n" +" %s" + +#: f.file.cc:1287 +msgid "Batch Rename" +msgstr "Massomdöpning" + +#: f.file.cc:1290 f.file.cc:1342 f.info.cc:1519 f.info.cc:1773 f.tools.cc:543 +#: f.tools.cc:2990 +#, c-format +msgid "%d files selected" +msgstr "%d filer valda" + +#: f.file.cc:1292 +msgid "new base name" +msgstr "nytt basnamn" + +#: f.file.cc:1295 +msgid "starting sequence" +msgstr "begynnelsesekvens" + +#: f.file.cc:1297 +msgid "increment" +msgstr "steg" + +#: f.file.cc:1318 +msgid "select files to rename" +msgstr "välj filer för omdöpning" + +#: f.file.cc:1323 +msgid "base name / sequence / increment not reasonable" +msgstr "basnamn / sekvens / steg ej lämpliga" + +#: f.file.cc:1382 +msgid "new file already exists:" +msgstr "ny fil finns redan:" + +#: f.file.cc:1390 +msgid "filespec too long:" +msgstr "filspec för lång" + +#: f.file.cc:1401 +msgid "Rename failed:" +msgstr "Namnändring misslyckades:" + +#: f.file.cc:1662 fotoxx.h:729 +msgid "Add" +msgstr "Lägg till" + +#: f.file.cc:1662 fotoxx.h:781 +msgid "Remove" +msgstr "Tag bort" + +#: f.file.cc:1664 +msgid "menu name" +msgstr "menynamn" + +#: f.file.cc:1735 f.file.cc:1756 +msgid "Restart Fotoxx to update plugin menu" +msgstr "Starta om Fotoxx för att uppdatera insticksmenyn" + +#: f.info.cc:70 +msgid "Edit Caption and Comments" +msgstr "Redigera beskrivning och kommentar" + +#: f.info.cc:156 fotoxx-12.01.1.cc:224 +msgid "Edit Tags" +msgstr "Redigera taggar" + +#: f.info.cc:163 +msgid "image date (yyyymmdd)" +msgstr "bilddatum (ååååmmdd)" + +#: f.info.cc:165 +msgid "use last" +msgstr "använd senaste" + +#: f.info.cc:168 +msgid "image stars" +msgstr "bildstjärnor" + +#: f.info.cc:186 +msgid "current tags" +msgstr "aktuella taggar" + +#: f.info.cc:191 +msgid "recent tags" +msgstr "gamla märken" + +#: f.info.cc:196 f.info.cc:358 f.info.cc:1368 f.info.cc:2384 +msgid "defined tags" +msgstr "definierade märken" + +#: f.info.cc:345 fotoxx-12.01.1.cc:225 +msgid "Manage Tags" +msgstr "Hantera flikar" + +#: f.info.cc:348 +msgid "category" +msgstr "kategori" + +#: f.info.cc:351 +msgid "tag" +msgstr "märke" + +#: f.info.cc:354 +msgid "create" +msgstr "skapa" + +#: f.info.cc:355 f.navi.cc:1421 +msgid "delete" +msgstr "tag bort" + +#: f.info.cc:1235 f.info.cc:1319 +#, c-format +msgid "search index file error: %s" +msgstr "sökfilsindexfel: %s" + +#: f.info.cc:1351 fotoxx-12.01.1.cc:226 +msgid "Batch Add Tags" +msgstr "Masstillägg av taggar" + +#: f.info.cc:1354 +msgid "tags to add" +msgstr "taggar att lägga till" + +#: f.info.cc:1359 +msgid "create tag" +msgstr "skapa tagg" + +#: f.info.cc:1415 f.info.cc:1608 +#, c-format +msgid "" +"%s \n" +" too many tags" +msgstr "" +"%s \n" +" för många märken" + +#: f.info.cc:1553 fotoxx-12.01.1.cc:227 +msgid "Batch Delete Tag" +msgstr "Borttagning av flagga satsvis" + +#: f.info.cc:1556 +msgid "tag to remove" +msgstr "flagga för borttagning" + +#: f.info.cc:1560 +msgid "optional replacement" +msgstr "valbar ersättning" + +#: f.info.cc:1565 f.tools.cc:2943 +msgid "0 files selected" +msgstr "Ingen fil vald" + +#: f.info.cc:1568 +msgid "search all files" +msgstr "leta i alla filer" + +#: f.info.cc:1653 +msgid "no files selected" +msgstr "inga filer valda" + +#: f.info.cc:1659 +msgid "no tag specified" +msgstr "inga flaggor beskrivna" + +#: f.info.cc:1683 f.info.cc:1712 +msgid "specify tag" +msgstr "beskriv flagga" + +#: f.info.cc:1821 +msgid "View Info" +msgstr "Visa information" + +#: f.info.cc:1889 fotoxx-12.01.1.cc:230 +msgid "Edit Info" +msgstr "Redigera info" + +#: f.info.cc:1987 fotoxx-12.01.1.cc:231 +msgid "Delete Info" +msgstr "Borttagningsinfo" + +#: f.info.cc:1989 fotoxx.h:731 +msgid "All" +msgstr "Allt" + +#: f.info.cc:1990 +msgid "One Key:" +msgstr "One Key:" + +#: f.info.cc:2343 +msgid "Search Tags, Comments, File Names" +msgstr "Sök flaggor, kommentarer, filnamn" + +#: f.info.cc:2350 +msgid "date range" +msgstr "datumintervall" + +#: f.info.cc:2351 +msgid "stars range" +msgstr "stjärnområde" + +#: f.info.cc:2352 +msgid "search tags" +msgstr "sök taggar" + +#: f.info.cc:2353 +msgid "search text" +msgstr "sök text" + +#: f.info.cc:2354 +msgid "file names" +msgstr "filnamn" + +#: f.info.cc:2359 +msgid "(yyyymmdd)" +msgstr "(yyyymmdd)" + +#: f.info.cc:2365 +msgid "all/any" +msgstr "alla/någon" + +#: f.info.cc:2702 +msgid "No matching images found" +msgstr "Inga matchande bilder hittade" + +#: f.info.cc:2706 f.info.cc:3059 +msgid "No search index file present" +msgstr "Ingen indexsökfil rfinns" + +#: f.info.cc:2777 +msgid "Additional Items for Report" +msgstr "Ytterligare delar till rapport" + +#: f.navi.cc:188 f.navi.cc:576 f.navi.cc:706 f.navi.cc:707 f.navi.cc:709 +msgid "bigger" +msgstr "större" + +#: f.navi.cc:188 +msgid "increase thumbnail size" +msgstr "öka miniatyrbildstorlek" + +#: f.navi.cc:189 +msgid "reduce thumbnail size" +msgstr "minska miniatyrbildstorlek" + +#: f.navi.cc:189 f.navi.cc:586 f.navi.cc:708 f.navi.cc:710 +msgid "smaller" +msgstr "mindre" + +#: f.navi.cc:190 f.navi.cc:600 +msgid "parent" +msgstr "förälder" + +#: f.navi.cc:190 +msgid "parent directory" +msgstr "föräldramapp" + +#: f.navi.cc:191 f.navi.cc:625 f.navi.cc:717 +msgid "first page" +msgstr "första sida" + +#: f.navi.cc:191 +msgid "jump to first file" +msgstr "hoppa till första fil" + +#: f.navi.cc:192 f.navi.cc:623 f.navi.cc:712 f.navi.cc:719 +msgid "prev page" +msgstr "föregående sida" + +#: f.navi.cc:192 +msgid "previous page" +msgstr "föregående sida" + +#: f.navi.cc:193 f.navi.cc:621 f.navi.cc:714 +msgid "prev row" +msgstr "föregående rad" + +#: f.navi.cc:193 +msgid "previous row" +msgstr "föregående rad" + +#: f.navi.cc:194 f.navi.cc:622 f.navi.cc:715 +msgid "next row" +msgstr "nästa rad" + +#: f.navi.cc:195 f.navi.cc:624 f.navi.cc:713 f.navi.cc:720 +msgid "next page" +msgstr "nästa sida" + +#: f.navi.cc:195 +msgid "ttip::next page" +msgstr "ttip::nästa sida" + +#: f.navi.cc:196 +msgid "jump to last file" +msgstr "hoppa till sista fil" + +#: f.navi.cc:196 f.navi.cc:626 f.navi.cc:718 +msgid "last page" +msgstr "sista sida" + +#: f.navi.cc:197 f.navi.cc:571 +msgid "close" +msgstr "stäng" + +#: f.navi.cc:197 +msgid "close image gallery" +msgstr "stäng bildgalleri" + +#: f.navi.cc:1413 fotoxx.h:787 +msgid "Select Files" +msgstr "Välj filer" + +#: f.navi.cc:1413 zfuncs.cc:6296 zfuncs.cc:6332 zfuncs.cc:6485 zfuncs.cc:6728 +#: zfuncs.cc:7427 zfuncs.cc:7433 zfuncs.cc:7439 zfuncs.cc:7445 +msgid "cancel" +msgstr "avbryt" + +#: f.navi.cc:1413 zfuncs.cc:6728 +msgid "done" +msgstr "klart" + +#: f.navi.cc:1422 +msgid "insert" +msgstr "sätt in" + +#: f.navi.cc:1423 +msgid "add all" +msgstr "lägg till allt" + +#: f.retouch.cc:55 +msgid "Adjust Brightness and Color" +msgstr "Justera ljus och färg" + +#: f.retouch.cc:110 +msgid "small-steps" +msgstr "småsteg" + +#: f.retouch.cc:119 +msgid "color saturation" +msgstr "färgmättnad" + +#: f.retouch.cc:126 +msgid " reset 1 " +msgstr " reset 1 " + +#: f.retouch.cc:127 +msgid "reset all" +msgstr "återställ allt" + +#: f.retouch.cc:599 +msgid "adjust image gamma" +msgstr "justera bildens gamma" + +#: f.retouch.cc:885 +msgid "Expand Brightness Range" +msgstr "Expandera ljushetsområde" + +#: f.retouch.cc:887 +msgid "bright pixels" +msgstr "ljusa pixlar" + +#: f.retouch.cc:1058 +msgid "Flatten Brightness Distribution" +msgstr "Platta till ljushetsfördelning" + +#: f.retouch.cc:1072 +msgid "Flatten" +msgstr "Platta till" + +#: f.retouch.cc:1334 +msgid "Ramp brightness across image" +msgstr "Rampa ljushet över bild" + +#: f.retouch.cc:1730 fotoxx-12.01.1.cc:271 +msgid "Tone Mapping" +msgstr "Tonavbildning" + +#: f.retouch.cc:1758 +msgid "low" +msgstr "låg" + +#: f.retouch.cc:1760 +msgid "high" +msgstr "hög" + +#: f.retouch.cc:1763 +msgid "Amplify" +msgstr "Förstärk" + +#: f.retouch.cc:2069 +msgid "Adjust White Balance" +msgstr "Justera vitbalans" + +#: f.retouch.cc:2070 +msgid "Click white or gray image location" +msgstr "Klicka på vit- eller gråbildsplats" + +#: f.retouch.cc:2278 +msgid "Color Match Images" +msgstr "" + +#: f.retouch.cc:2307 +msgid "mouse radius for color sample" +msgstr "musradie för färgprov" + +#: f.retouch.cc:2309 f.retouch.cc:2314 fotoxx-12.01.1.cc:245 +#: fotoxx-12.01.1.cc:324 fotoxx.h:769 +msgid "Open" +msgstr "Öppna" + +#: f.retouch.cc:2310 +msgid "image for source color" +msgstr "bild för källfärg" + +#: f.retouch.cc:2312 +msgid "click on image to get source color" +msgstr "klicka på bilden för att få en källfärg" + +#: f.retouch.cc:2315 +msgid "image to set matching color" +msgstr "" + +#: f.retouch.cc:2317 +msgid "click on image to set matching color" +msgstr "" + +#: f.retouch.cc:2372 +msgid "select source image color first" +msgstr "välj källbildsfärg först" + +#: f.retouch.cc:2584 +msgid "Add standard bias" +msgstr "Lägg till standardförskjutning" + +#: f.retouch.cc:2591 +msgid "+Brightness -Density" +msgstr "+Ljusstyrka -Täthet" + +#: f.retouch.cc:2592 +msgid "+Red -Cyan" +msgstr "+Röd -Cyan" + +#: f.retouch.cc:2593 +msgid "+Green -Magenta" +msgstr "+Grön -Magenta" + +#: f.retouch.cc:2594 +msgid "+Blue -Yellow" +msgstr "+Blå -Gul" + +#: f.retouch.cc:2599 +msgid "Contrast" +msgstr "Kontrast" + +#: f.retouch.cc:2600 fotoxx.h:778 +msgid "Red" +msgstr "Röd" + +#: f.retouch.cc:2601 fotoxx.h:758 +msgid "Green" +msgstr "Grön" + +#: f.retouch.cc:2602 fotoxx.h:736 +msgid "Blue" +msgstr "Blå" + +#: f.retouch.cc:2730 +msgid "Load DRGB parameters" +msgstr "Ladda DRGB-parametrrar" + +#: f.retouch.cc:2732 f.retouch.cc:2804 f.retouch.cc:6102 f.retouch.cc:6198 +msgid "File:" +msgstr "Fil:" + +#: f.retouch.cc:2751 f.retouch.cc:2824 +msgid "DRGB parameters file" +msgstr "DRGB-parameterfil" + +#: f.retouch.cc:2769 f.retouch.cc:6142 +msgid "file not found" +msgstr "fil ej funnen" + +#: f.retouch.cc:2802 +msgid "Save DRGB parameters" +msgstr "Spara DRGB-parameterar" + +#: f.retouch.cc:3034 f.tools.cc:2404 +msgid "Click image to select pixels." +msgstr "Klicka på bild för att välja pixlar" + +#: f.retouch.cc:3072 fotoxx-12.01.1.cc:275 +msgid "Revise RGB" +msgstr "Revidera RGB" + +#: f.retouch.cc:3084 +msgid "Metric:" +msgstr "Metrisk:" + +#: f.retouch.cc:3139 +msgid "Blend" +msgstr "Ton" + +#: f.retouch.cc:3519 +msgid "" +"Method 1:\n" +" Left-click on red-eye to darken.\n" +"Method 2:\n" +" Drag down and right to enclose red-eye.\n" +" Left-click on red-eye to darken.\n" +"Undo red-eye:\n" +" Right-click on red-eye." +msgstr "" +"Metod 1:\n" +" Vänsterklicka på röd-öga för att göra mörkare.\n" +"Metod 2:\n" +" Drag ner och höger till att innesluta röd-öga.\n" +" Vänsterklicka på röd-öga för att göra mörkare.\n" +"Ångra röd-öga:\n" +" Högerklicka på röd-öga." + +#: f.retouch.cc:3534 +msgid "Red Eye Reduction" +msgstr "Rödögonminskning" + +#: f.retouch.cc:3968 +msgid "Set Blur Radius" +msgstr "Välj suddradie" + +#: f.retouch.cc:4195 fotoxx-12.01.1.cc:278 +msgid "Sharpen Image" +msgstr "Gör bild skarpare" + +#: f.retouch.cc:4202 +msgid "edge detection" +msgstr "kantdetektion" + +#: f.retouch.cc:4203 +msgid "cycles" +msgstr "perioder" + +#: f.retouch.cc:4204 +msgid "reduce" +msgstr "minska" + +#: f.retouch.cc:4215 +msgid "unsharp mask" +msgstr "oskarp mask" + +#: f.retouch.cc:4228 +msgid "brightness gradient" +msgstr "ljushetsgradient" + +#: f.retouch.cc:4634 +msgid "" +" Press the reduce button to \n" +" reduce noise in small steps. \n" +" Use undo to start over." +msgstr "" +" Tryck minska-knappen för att\n" +" minska brus i små steg.\n" +" Använd ångar för att börja om." + +#: f.retouch.cc:4645 +msgid "Noise Reduction" +msgstr "Brusminskning" + +#: f.retouch.cc:4650 +msgid "algorithm" +msgstr "algoritm" + +#: f.retouch.cc:4657 +msgid "flatten outliers by color (1)" +msgstr "platta till \"uteliggare\" med färg (1)" + +#: f.retouch.cc:4658 +msgid "flatten outliers by color (2)" +msgstr "platta till \"uteliggare\" med färg (2)" + +#: f.retouch.cc:4659 +msgid "set median brightness by color" +msgstr "sätt medialjushet genom färg" + +#: f.retouch.cc:4660 f.retouch.cc:4661 +msgid "top hat filter by color" +msgstr "top hat-filter med färg" + +#: f.retouch.cc:4976 +msgid "" +"1. Drag mouse to select. \n" +"2. Erase. 3. Repeat. " +msgstr "" +"1. Drag mus för val. \n" +"2. Radera. 3. Repetera. " + +#: f.retouch.cc:4998 fotoxx-12.01.1.cc:280 +msgid "Smart Erase" +msgstr "Fiffig radering" + +#: f.retouch.cc:5003 fotoxx.h:776 +msgid "Radius" +msgstr "Radie" + +#: f.retouch.cc:5005 +msgid "Blur" +msgstr "Göra suddigt" + +#: f.retouch.cc:5008 +msgid "New Area" +msgstr "Ny yta" + +#: f.retouch.cc:5379 fotoxx-12.01.1.cc:281 +msgid "Remove Dust" +msgstr "Tag bort damm" + +#: f.retouch.cc:5383 +msgid "spot size limit" +msgstr "" + +#: f.retouch.cc:5386 +msgid "max. brightness" +msgstr "max. ljusstyrka" + +#: f.retouch.cc:5389 +msgid "min. contrast" +msgstr "min. kontrast" + +#: f.retouch.cc:5983 fotoxx-12.01.1.cc:282 +msgid "Fix Stuck Pixels" +msgstr "Ordna fastnade pixlar" + +#: f.retouch.cc:5989 +msgid "pixel group" +msgstr "pixelgrupp" + +#: f.retouch.cc:5990 +msgid "circle color" +msgstr "cirkelfärg" + +#: f.retouch.cc:6100 +msgid "Load Stuck Pixels" +msgstr "Ladda fastnade pixlar" + +#: f.retouch.cc:6124 f.retouch.cc:6220 +msgid "Stuck Pixels file" +msgstr "Fil med fastnade pixlar" + +#: f.retouch.cc:6164 +msgid "file format error" +msgstr "filformatfel" + +#: f.retouch.cc:6192 +msgid "there are zero stuck pixels" +msgstr "det finns inga fastnade pixlar" + +#: f.retouch.cc:6196 +msgid "Save Stuck Pixels" +msgstr "Spara fastnade pixlar" + +#: f.retouch.cc:6686 +#, c-format +msgid "Undo Memory %d%c" +msgstr "Ångra minne %d%c" + +#: f.retouch.cc:6688 fotoxx-12.01.1.cc:283 +msgid "Edit Pixels" +msgstr "Redigera pixlar" + +#: f.retouch.cc:6695 +msgid "pick" +msgstr "plocka" + +#: f.retouch.cc:6697 +msgid "erase" +msgstr "radera" + +#: f.retouch.cc:6705 +msgid "paintbrush radius" +msgstr "målarpenselradie" + +#: f.retouch.cc:6706 +msgid "transparency center" +msgstr "genomskinlighetscenter" + +#: f.retouch.cc:6707 +msgid "transparency edge" +msgstr "genomskinlighetskant" + +#: f.retouch.cc:6972 +msgid "" +"Undo memory limit has been reached. \n" +"Save work with [done], then resume editing." +msgstr "" +"Ångra minnesgräns har nåtts.\n" +"Spara arbete med [gjort], fortsätt sedan redigering." + +#: f.select.cc:54 f.select.cc:2461 +msgid "Select Area for Edits" +msgstr "Välj område till redigering" + +#: f.select.cc:55 f.select.cc:2462 +msgid "Press F1 for help" +msgstr "Tryck F1 efter hjälp" + +#: f.select.cc:64 +msgid "" +"Select Area not supported \n" +"by this edit function" +msgstr "" +"Val av yta stöds ej\n" +"av denna redigeringsfunktion" + +#: f.select.cc:103 f.tools.cc:901 +msgid "rectangle" +msgstr "rektangel" + +#: f.select.cc:104 f.tools.cc:902 +msgid "ellipse" +msgstr "ellips" + +#: f.select.cc:110 +msgid "draw: freehand" +msgstr "drag: frihand" + +#: f.select.cc:111 +msgid "draw: follow edge" +msgstr "drag: följ kant" + +#: f.select.cc:114 +msgid "select by mouse" +msgstr "välj med mus" + +#: f.select.cc:116 f.select.cc:2496 +msgid "mouse radius" +msgstr "musradie" + +#: f.select.cc:120 +msgid "match mouse color" +msgstr "matcha musfärg" + +#: f.select.cc:124 +msgid "search range" +msgstr "sökområde" + +#: f.select.cc:126 +msgid "firewall" +msgstr "brandvägg" + +#: f.select.cc:326 f.select.cc:467 +#, c-format +msgid "exceed %d edits" +msgstr "överskrid %d redigeringar" + +#: f.select.cc:1021 +msgid "" +"Click one time inside each enclosed area \n" +"(possible gaps in the outline will be found). \n" +"Press F1 for help." +msgstr "" +"Klicka en gång innanför varje slutet område\n" +"(möjliga gap i kommer att hittas). \n" +"Tryck F1 för hjälp." + +#: f.select.cc:1078 +msgid "finish area" +msgstr "avslutande område" + +#: f.select.cc:1113 +msgid "searching" +msgstr "sökning" + +#: f.select.cc:1185 +msgid "outline has a gap" +msgstr "skissen har ett gap" + +#: f.select.cc:1189 +msgid "success" +msgstr "lyckades" + +#: f.select.cc:1440 f.select.cc:1470 +msgid "the area is not finished" +msgstr "området är ej avslutat" + +#: f.select.cc:1563 +msgid "Edge calculation in progress" +msgstr "Kantberäkning pågår" + +#: f.select.cc:1572 +msgid "Area Edge Calc" +msgstr "Ytkantsberäkning" + +#: f.select.cc:1863 +msgid "position with mouse click/drag" +msgstr "positionera med musklick/drag" + +#: f.select.cc:1887 +msgid "Paste Image" +msgstr "Klistra in bild" + +#: f.select.cc:1901 +msgid "angle" +msgstr "vinkel" + +#: f.select.cc:2160 +msgid "load select area from a file" +msgstr "ladda valt område från en fil" + +#: f.select.cc:2194 +msgid "cannot open .tiff and .info files" +msgstr "kan ej öppna .tiff- och .info-filer" + +#: f.select.cc:2213 +msgid "save select area to a file" +msgstr "spara valt område till en fil" + +#: f.select.cc:2248 fotoxx-12.01.1.cc:247 +msgid "Select Whole Image" +msgstr "Välj hel bild" + +#: f.select.cc:2249 +msgid "Edit Function Amplifier" +msgstr "Redigera funktionsförstärkare" + +#: f.select.cc:2463 +msgid "Edit function must be active" +msgstr "Redigeringsfunktionen måste vara aktiv§" + +#: f.select.cc:2499 +msgid "power: center" +msgstr "kraft: centrum" + +#: f.select.cc:2501 +msgid "edge" +msgstr "kant" + +#: f.select.cc:2504 +msgid "reset area" +msgstr "återställ område§" + +#: f.tools.cc:42 +msgid "" +"When editing a collection, right-click \n" +"an image or thumbnail to add or remove." +msgstr "" +"Vid redigering av en samling, högerklicka \n" +"på en bild eller miniatyr för att lägga till eller ta bort" + +#: f.tools.cc:70 fotoxx-12.01.1.cc:203 +msgid "Manage Collections" +msgstr "Hantera samlingar" + +#: f.tools.cc:85 +msgid "Start new collection" +msgstr "Påbörja en ny samling" + +#: f.tools.cc:87 +msgid "Edit a collection" +msgstr "Redigera en samling" + +#: f.tools.cc:89 +msgid "View a collection" +msgstr "Visa en samling" + +#: f.tools.cc:91 +msgid "Delete a collection" +msgstr "Tag bort en samling" + +#: f.tools.cc:95 +msgid "Editing:" +msgstr "Redigering:" + +#: f.tools.cc:99 +msgid "Action:" +msgstr "Åtgärd:" + +#: f.tools.cc:133 +msgid "New Collection" +msgstr "Ny samling" + +#: f.tools.cc:156 +msgid "Edit Collection" +msgstr "Redigera samling" + +#: f.tools.cc:172 +msgid "View Collection" +msgstr "Visa samling" + +#: f.tools.cc:193 +msgid "Delete Collection" +msgstr "Tag bort samling" + +#: f.tools.cc:196 +#, c-format +msgid "delete %s ?" +msgstr "tag bort %s ?" + +#: f.tools.cc:223 +#, c-format +msgid "add image to collection: %s" +msgstr "lägg till bild till samlingen: %s" + +#: f.tools.cc:225 f.tools.cc:270 +msgid "remove image from collection" +msgstr "tag bort bild från samling" + +#: f.tools.cc:226 f.tools.cc:271 f.tools.cc:298 +msgid "remove and save image" +msgstr "tag bort och spara bild" + +#: f.tools.cc:227 f.tools.cc:316 +msgid "insert saved images here" +msgstr "sätt in sparad bild här" + +#: f.tools.cc:256 +msgid "add image to collection" +msgstr "lägg till bild till samling" + +#: f.tools.cc:301 +msgid "too many saved files" +msgstr "för många sparade filer" + +#: f.tools.cc:373 fotoxx-12.01.1.cc:204 +msgid "Move Collections" +msgstr "Flytta samling" + +#: f.tools.cc:375 +msgid "old top directory" +msgstr "gammal högsta mapp" + +#: f.tools.cc:378 +msgid "new top directory" +msgstr "ny högsta mapp" + +#: f.tools.cc:434 +msgid "completed" +msgstr "fullgjort" + +#: f.tools.cc:467 +msgid "Batch Convert/Resize/Export" +msgstr "Satsvis konvertering/Storleksförändring/Export" + +#: f.tools.cc:474 +msgid "new max. width" +msgstr "ny max bredd" + +#: f.tools.cc:481 +msgid "new file type" +msgstr "ny filtyp" + +#: f.tools.cc:482 +msgid "same" +msgstr "samma" + +#: f.tools.cc:490 +msgid "replace originals" +msgstr "ersätta originalen" + +#: f.tools.cc:491 +msgid "export to location" +msgstr "exportera till plats" + +#: f.tools.cc:492 +msgid "remove EXIF" +msgstr "tag bort EXIF" + +#: f.tools.cc:549 +msgid "Select directory" +msgstr "Välj mapp" + +#: f.tools.cc:583 +#, c-format +msgid "replace original files? (max. %d x %d)" +msgstr "ersätta ursprungliga filer? max %d x %d)" + +#: f.tools.cc:590 +#, c-format +msgid "" +"copy files? (max. %d x %d) \n" +" to location %s" +msgstr "" +"kopiera filer? (max %d x %d) \n" +"till plats %s" + +#: f.tools.cc:601 +msgid "location is not a valid directory" +msgstr "platsen är inte en giltig mapp" + +#: f.tools.cc:608 f.tools.cc:3007 +#, c-format +msgid "max. size %d x %d is not reasonable" +msgstr "max storlek %d x %d är inte förnuftig" + +#: f.tools.cc:654 +msgid "*** file already exists" +msgstr "*** filen finns redan" + +#: f.tools.cc:662 +msgid "*** file type not supported" +msgstr "*** filtypen stöds ej" + +#: f.tools.cc:741 +msgid "Program ufraw-batch is required" +msgstr "Programmet ufraw-batch krävs" + +#: f.tools.cc:751 fotoxx.h:770 +msgid "Open RAW File" +msgstr "Öppna RAW-fil" + +#: f.tools.cc:764 +msgid "Select RAW files to convert" +msgstr "Välj RAW-filer för omvandling" + +#: f.tools.cc:769 +msgid "Choose file type" +msgstr "Välj filtyp" + +#: f.tools.cc:888 +msgid "Press ESC to exit slide show" +msgstr "Tryck ESC för att avsluta bildvisningen" + +#: f.tools.cc:889 +msgid "show only latest file versions" +msgstr "visa bara senaste filversion" + +#: f.tools.cc:893 +msgid "arrow keys" +msgstr "pilknappar" + +#: f.tools.cc:894 +msgid "instant" +msgstr "direkt" + +#: f.tools.cc:895 +msgid "fade-in" +msgstr "intoning" + +#: f.tools.cc:896 +msgid "roll-right" +msgstr "högerrullning" + +#: f.tools.cc:897 +msgid "roll-down" +msgstr "nedrullning" + +#: f.tools.cc:898 +msgid "shift-left" +msgstr "shift-vänster§" + +#: f.tools.cc:899 +msgid "venetian" +msgstr "venetianskt" + +#: f.tools.cc:900 +msgid "grate" +msgstr "rutnät" + +#: f.tools.cc:903 +msgid "radar" +msgstr "radar" + +#: f.tools.cc:904 +msgid "jaws" +msgstr "" + +#: f.tools.cc:911 fotoxx-12.01.1.cc:207 +msgid "Slide Show" +msgstr "Bildvisning" + +#: f.tools.cc:915 +msgid "seconds" +msgstr "sekunder" + +#: f.tools.cc:919 +msgid "music file" +msgstr "musikfil" + +#: f.tools.cc:923 +msgid "transitions" +msgstr "övergångar" + +#: f.tools.cc:1040 +msgid "Select music file or playlist" +msgstr "Välj musikfil eller spellista" + +#: f.tools.cc:1727 +msgid "Sync Files is already running" +msgstr "Synkronisering av filer körs redan" + +#: f.tools.cc:1778 +msgid "" +"Run Tools > Synchronize Files so that gallery windows \n" +"will be fast and Search Images will work correctly. \n" +"You can view (not edit) images while synchronize runs." +msgstr "" +"Kör Verktyg->Synkronisera filer så att gallerifönstren \n" +"blir snabba och Sök Bilder kommer att fungera korrekt. Du kan se (ej " +"redigera) bilder medan synkronisering körs." + +#: f.tools.cc:1812 +msgid "no top image directory is defined" +msgstr "ingen högsta bildmapp är definierad" + +#: f.tools.cc:1818 +msgid "top image directory is invalid" +msgstr "högsta bildmapp är ogiltig" + +#: f.tools.cc:1823 +msgid "no search index file is present" +msgstr "ingen indexsökfil finns" + +#: f.tools.cc:1837 +msgid "new/modified files are present" +msgstr "nya/ändrade filer finns" + +#: f.tools.cc:1844 +msgid "no new files found" +msgstr "inga nya filer hittade" + +#: f.tools.cc:1859 fotoxx-12.01.1.cc:208 +msgid "Synchronize Files" +msgstr "Synkronisera filer" + +#: f.tools.cc:1861 +msgid "Top Image Directory:" +msgstr "Översta bildmapp:" + +#: f.tools.cc:1883 +msgid "" +"file sync is necessary.\n" +"cancel anyway?" +msgstr "" +"filsynkronisering är nödvändigt.\n" +"avbryta ändå?" + +#: f.tools.cc:1896 +msgid "top directory is invalid" +msgstr "högsta mapp är ogiltig" + +#: f.tools.cc:2292 +msgid "Select top image directory" +msgstr "Välj översta bildmapp" + +#: f.tools.cc:2429 fotoxx-12.01.1.cc:209 +msgid "Show RGB" +msgstr "Visa RGB" + +#: f.tools.cc:2719 fotoxx-12.01.1.cc:210 +msgid "Grid Lines" +msgstr "Rutnät" + +#: f.tools.cc:2728 +msgid "x-spacing" +msgstr "x-avstånd" + +#: f.tools.cc:2729 +msgid "x-count" +msgstr "x-antal" + +#: f.tools.cc:2730 +msgid "x-enable" +msgstr "x-enable" + +#: f.tools.cc:2736 +msgid "y-spacing" +msgstr "y-avstånd" + +#: f.tools.cc:2737 +msgid "y-count" +msgstr "y-antal" + +#: f.tools.cc:2738 +msgid "y-enable" +msgstr "y-enable" + +#: f.tools.cc:2745 +msgid "x-offset" +msgstr "x-förskjutning" + +#: f.tools.cc:2749 +msgid "y-offset" +msgstr "y-förskjutning" + +#: f.tools.cc:2940 fotoxx-12.01.1.cc:212 +msgid "E-mail Images" +msgstr "E-postbilder" + +#: f.tools.cc:2947 +msgid "max. width" +msgstr "max bredd" + +#: f.tools.cc:2948 +msgid "max. height" +msgstr "max höjd" + +#: f.tools.cc:3093 +msgid "too many files" +msgstr "för många filer" + +#: f.tools.cc:3134 +msgid "" +"Brightness should show a gradual ramp \n" +"extending all the way to the edges." +msgstr "" +"Ljusheten borde visa a gradvis ramp \n" +"utvidgad hela vägen till kanterna." + +#: f.tools.cc:3174 +msgid "Monitor Check" +msgstr "Kontroll av bildskärm" + +#: f.tools.cc:3232 fotoxx-12.01.1.cc:214 +msgid "Monitor Gamma" +msgstr "Bildskärmsgamma" + +#: f.tools.cc:3294 fotoxx-12.01.1.cc:215 +msgid "Brightness Distribution" +msgstr "Ljushetsfördelning" + +#: f.tools.cc:3432 +msgid "Available Translations" +msgstr "Tillgängliga översättningar" + +#: f.tools.cc:3436 +msgid "Set Language" +msgstr "Ställ in språk" + +#: f.tools.cc:3502 +msgid "Make Launcher" +msgstr "" + +#: f.tools.cc:3540 +msgid "Settings" +msgstr "Inställningar" + +#: f.tools.cc:3545 +msgid "Startup Display" +msgstr "Uppstartskärm" + +#: f.tools.cc:3547 +msgid "Recent Files Gallery" +msgstr "Senaste filers galleri " + +#: f.tools.cc:3548 +msgid "Previous Image Viewed" +msgstr "Senaste betraktade bild" + +#: f.tools.cc:3549 +msgid "Blank Window" +msgstr "Svart fönster" + +#: f.tools.cc:3551 +msgid "Directory Gallery" +msgstr "Mappgalleri" + +#: f.tools.cc:3556 +msgid "Image File" +msgstr "Bildfil" + +#: f.tools.cc:3562 +msgid "Toolbar Style" +msgstr "Stil på verktygsrad" + +#: f.tools.cc:3563 f.transform.cc:1300 +msgid "Text" +msgstr "Text" + +#: f.tools.cc:3564 +msgid "Icons" +msgstr "Ikoner" + +#: f.tools.cc:3565 +msgid "Both" +msgstr "Bägge" + +#: f.tools.cc:3568 +msgid "Warn Overwrite" +msgstr "Varna vid överskrivning" + +#: f.tools.cc:3639 +msgid "startup directory is invalid" +msgstr "uppstartmapp är ogiltig" + +#: f.tools.cc:3650 +msgid "startup file is invalid" +msgstr "uppstartfil är ogiltig" + +#: f.tools.cc:3707 +msgid "Select startup directory" +msgstr "Välj uppstartmapp" + +#: f.tools.cc:3715 +msgid "Select startup image file" +msgstr "Välj uppstartbildfil" + +#: f.transform.cc:50 +msgid "Use buttons or drag right edge with mouse" +msgstr "Använd knappar eller dra höger kant med mus" + +#: f.transform.cc:60 fotoxx-12.01.1.cc:251 +msgid "Rotate Image" +msgstr "Rotera bild" + +#: f.transform.cc:64 +msgid "degrees" +msgstr "grader" + +#: f.transform.cc:80 f.transform.cc:124 +msgid "Trim" +msgstr "Trimma" + +#: f.transform.cc:81 f.transform.cc:2289 f.transform.cc:3120 +#: f.transform.cc:3383 f.transform.cc:3644 +msgid "Grid" +msgstr "Rutnät" + +#: f.transform.cc:123 +msgid "Undo Trim" +msgstr "Ångra trimning" + +#: f.transform.cc:139 +#, c-format +msgid "degrees: %.1f" +msgstr "grader: %.1f" + +#: f.transform.cc:286 +msgid "gold" +msgstr "guld" + +#: f.transform.cc:334 +msgid "Drag middle to move, drag corners to resize." +msgstr "Drag i mitten för att flytta, i hörnen för att ändra storlek." + +#: f.transform.cc:348 fotoxx-12.01.1.cc:252 +msgid "Trim Image" +msgstr "Trimma bild" + +#: f.transform.cc:348 +msgid "customize" +msgstr "anpassa" + +#: f.transform.cc:359 +msgid "ratio" +msgstr "förhållande" + +#: f.transform.cc:363 +msgid "Lock Ratio" +msgstr "Lås förhållande" + +#: f.transform.cc:368 +msgid "invert" +msgstr "invertera" + +#: f.transform.cc:890 +msgid "Trim Buttons" +msgstr "Trimningsknappar" + +#: f.transform.cc:1064 +msgid "Lock aspect ratio" +msgstr "Lås aspektförhållande" + +#: f.transform.cc:1072 fotoxx-12.01.1.cc:254 +msgid "Resize Image" +msgstr "Ändra bildstorlek" + +#: f.transform.cc:1095 fotoxx-12.01.1.cc:325 +msgid "Prev" +msgstr "Föreg" + +#: f.transform.cc:1245 +msgid "" +"Enter text, click/drag on image.\n" +"Right click to remove" +msgstr "" +"Skriv in text, klicka/drag i bild.\n" +"Högerklicka för att ta bort." + +#: f.transform.cc:1294 fotoxx-12.01.1.cc:255 +msgid "Annotate Image" +msgstr "Kommentera bild" + +#: f.transform.cc:1307 +msgid "Size" +msgstr "Storlek" + +#: f.transform.cc:1310 +msgid "Angle" +msgstr "Vinkel" + +#: f.transform.cc:1321 fotoxx.h:741 +msgid "Color" +msgstr "Färg" + +#: f.transform.cc:1322 +msgid "Transparency" +msgstr "Transparans" + +#: f.transform.cc:1325 +msgid "text" +msgstr "text" + +#: f.transform.cc:1330 +msgid "backing" +msgstr "" + +#: f.transform.cc:1333 +msgid "" +"Outline\n" +" Width" +msgstr "" +"Kontur\n" +" bredd" + +#: f.transform.cc:1335 +msgid "outline" +msgstr "skiss" + +#: f.transform.cc:1342 +msgid "Annotation File:" +msgstr "Notisfil:" + +#: f.transform.cc:1416 +msgid "select font" +msgstr "välj typsnitt" + +#: f.transform.cc:2045 fotoxx-12.01.1.cc:256 +msgid "Flip Image" +msgstr "Vänd bild" + +#: f.transform.cc:2049 f.transform.cc:2281 +msgid "horizontal" +msgstr "horisontell" + +#: f.transform.cc:2050 f.transform.cc:2280 +msgid "vertical" +msgstr "vertikal" + +#: f.transform.cc:2155 fotoxx-12.01.1.cc:257 +msgid "Make Negative" +msgstr "Gör negativ" + +#: f.transform.cc:2158 +msgid "black/white positive" +msgstr "svart-vit positiv" + +#: f.transform.cc:2159 +msgid "black/white negative" +msgstr "svart/vit negativ" + +#: f.transform.cc:2160 +msgid "color positive" +msgstr "färg positiv" + +#: f.transform.cc:2161 +msgid "color negative" +msgstr "färg negativ" + +#: f.transform.cc:2272 fotoxx-12.01.1.cc:258 +msgid "Unbend Image" +msgstr "Utsläta bild" + +#: f.transform.cc:2282 +msgid "linear" +msgstr "linjär" + +#: f.transform.cc:2285 +msgid "curved" +msgstr "böjd" + +#: f.transform.cc:2544 +msgid "" +" Click the four corners of a tetragon area. Press [apply]. \n" +" The image is warped to make the tetragon into a rectangle." +msgstr "" +"Klicka på de fyra hörnen i en tetragobyta. Tryck [tillämpa].\n" +"Bilden kommer att förvrängas genom att göra tetragonen till en rektangel." + +#: f.transform.cc:2556 fotoxx-12.01.1.cc:259 +msgid "Keystone Correction" +msgstr "" + +#: f.transform.cc:2724 +msgid "must have 4 corners" +msgstr "måste ha fyra hörn" + +#: f.transform.cc:2847 +msgid "" +" Select an area to warp using select area function. \n" +" Press [start warp] and pull area with mouse. \n" +" Make multiple mouse pulls until satisfied. \n" +" When finished, select another area or press [done]." +msgstr "" +"Välj ett område genom att välja en områdesfunktion. \n" +"Tryck [börja förvräng] och drag ytan med mus. \n" +"Gör flera musdrag tills du när nöjd. \n" +"När du är klar, välj ett annat område eller tryck [klar]." + +#: f.transform.cc:2859 fotoxx-12.01.1.cc:260 +msgid "Warp Image (area)" +msgstr "Vik ihop bild (yta)" + +#: f.transform.cc:2864 +msgid "start warp" +msgstr "börja förvrängning" + +#: f.transform.cc:2931 +msgid "no active Select Area" +msgstr "ingen aktiv utvald yta" + +#: f.transform.cc:3099 f.transform.cc:3362 +msgid "" +" Pull an image position using the mouse. \n" +" Make multiple mouse pulls until satisfied. \n" +" When finished, press [done]." +msgstr "" +" Drag i ett bildhörn med musen.\n" +" Gör flera musdragningar tills du är nöjd.\n" +" När du är klar, tryck [Avsluta]." + +#: f.transform.cc:3112 fotoxx-12.01.1.cc:261 +msgid "Warp Image (curved)" +msgstr "Vik ihop bild (kurva)" + +#: f.transform.cc:3375 fotoxx-12.01.1.cc:262 +msgid "Warp Image (linear)" +msgstr "Vik ihop bild (linjärt)" + +#: f.transform.cc:3628 +msgid "" +" Pull on an image corner using the mouse. \n" +" Make multiple mouse pulls until satisfied. \n" +" When finished, press [done]." +msgstr "" +" Drag i ett bildhörn med musen.\n" +" Gör flera musdragningar tills du är nöjd.\n" +" När du är klar, tryck [Avsluta]." + +#: f.transform.cc:3639 fotoxx-12.01.1.cc:263 +msgid "Warp Image (affine)" +msgstr "Förvräng bild (affine)" + +#: fotoxx-12.01.1.cc:184 +msgid "File" +msgstr "Fil" + +#: fotoxx-12.01.1.cc:185 fotoxx-12.01.1.cc:323 +msgid "Image Gallery" +msgstr "Bildgalleri" + +#: fotoxx-12.01.1.cc:186 +msgid "Clone 50/50" +msgstr "Klona 50/50" + +#: fotoxx-12.01.1.cc:187 +msgid "Clone Overlay" +msgstr "Klona Overlay" + +#: fotoxx-12.01.1.cc:189 +msgid "Open in New Window" +msgstr "Öppna i nytt fönster" + +#: fotoxx-12.01.1.cc:190 fotoxx-12.01.1.cc:325 +msgid "Open Previous File" +msgstr "Öppna föregående fil" + +#: fotoxx-12.01.1.cc:191 +msgid "Open Recent File" +msgstr "Öppna senaste fil" + +#: fotoxx-12.01.1.cc:192 fotoxx-12.01.1.cc:333 +msgid "Save to Same File" +msgstr "Spara till samma fil" + +#: fotoxx-12.01.1.cc:193 fotoxx-12.01.1.cc:334 +msgid "Save to New Version" +msgstr "Spara till ny version" + +#: fotoxx-12.01.1.cc:194 fotoxx-12.01.1.cc:335 +msgid "Save to New File" +msgstr "Spara till ny fil" + +#: fotoxx-12.01.1.cc:196 +msgid "Trash Image File" +msgstr "Skräpbildfil" + +#: fotoxx-12.01.1.cc:198 +msgid "Batch Rename Files" +msgstr "Massomdöp filer" + +#: fotoxx-12.01.1.cc:199 +msgid "Print Image File" +msgstr "Skriv ut bildfil" + +#: fotoxx-12.01.1.cc:200 fotoxx-12.01.1.cc:339 +msgid "Quit fotoxx" +msgstr "Avsluta fotoxx" + +#: fotoxx-12.01.1.cc:202 +msgid "Tools" +msgstr "Verktyg" + +#: fotoxx-12.01.1.cc:205 +msgid "Batch Convert" +msgstr "Satsvis konvertering" + +#: fotoxx-12.01.1.cc:206 +msgid "Convert RAW files" +msgstr "Omvandla RAW-filer" + +#: fotoxx-12.01.1.cc:211 +msgid "Burn Images to CD/DVD" +msgstr "Bränn bilder till CD/DVD" + +#: fotoxx-12.01.1.cc:213 +msgid "Check Monitor" +msgstr "Kontrollera skärm" + +#: fotoxx-12.01.1.cc:216 +msgid "Change Language" +msgstr "Ändra språk" + +#: fotoxx-12.01.1.cc:218 +msgid "Menu and Launcher" +msgstr "Meny och startare" + +#: fotoxx-12.01.1.cc:219 +msgid "User Settings" +msgstr "Användarinställningar" + +#: fotoxx-12.01.1.cc:220 +msgid "Memory Usage" +msgstr "Minnesutnyttjande" + +#: fotoxx-12.01.1.cc:223 +msgid "Edit Caption/Comments" +msgstr "Redigera beskrivning/kommentarer" + +#: fotoxx-12.01.1.cc:228 +msgid "View Info (short)" +msgstr "Visa information (kort)" + +#: fotoxx-12.01.1.cc:229 +msgid "View Info (long)" +msgstr "Visa information (långt)" + +#: fotoxx-12.01.1.cc:232 +msgid "Search Images" +msgstr "Bildsökning" + +#: fotoxx-12.01.1.cc:233 +msgid "Search Metadata" +msgstr "Sök metadata" + +#: fotoxx-12.01.1.cc:235 fotoxx-12.01.1.cc:236 fotoxx.h:786 +msgid "Select" +msgstr "Välj" + +#: fotoxx-12.01.1.cc:237 fotoxx.h:788 +msgid "Show" +msgstr "Visa" + +#: fotoxx-12.01.1.cc:238 fotoxx.h:761 +msgid "Hide" +msgstr "Göm" + +#: fotoxx-12.01.1.cc:239 fotoxx.h:752 +msgid "Enable" +msgstr "Koppla in" + +#: fotoxx-12.01.1.cc:240 fotoxx.h:748 +msgid "Disable" +msgstr "Koppla bort" + +#: fotoxx-12.01.1.cc:241 fotoxx.h:763 +msgid "Invert" +msgstr "Invertera" + +#: fotoxx-12.01.1.cc:242 fotoxx.h:796 +msgid "Unselect" +msgstr "Välj bort" + +#: fotoxx-12.01.1.cc:243 fotoxx.h:743 +msgid "Copy" +msgstr "Kopiera" + +#: fotoxx-12.01.1.cc:244 fotoxx.h:771 +msgid "Paste" +msgstr "Klistra in" + +#: fotoxx-12.01.1.cc:246 fotoxx-12.01.1.cc:333 fotoxx.h:783 +msgid "Save" +msgstr "Spara" + +#: fotoxx-12.01.1.cc:248 +msgid "Select and Edit" +msgstr "Välj och redigera" + +#: fotoxx-12.01.1.cc:250 +msgid "Transform" +msgstr "Omvandla" + +#: fotoxx-12.01.1.cc:253 +msgid "Auto-Trim Image" +msgstr "Trimma bild automatiskt" + +#: fotoxx-12.01.1.cc:265 +msgid "Retouch" +msgstr "Retuschera" + +#: fotoxx-12.01.1.cc:266 +msgid "Brightness/Color" +msgstr "Ljushet/färg" + +#: fotoxx-12.01.1.cc:267 +msgid "Gamma Curves" +msgstr "Gammakurvor" + +#: fotoxx-12.01.1.cc:268 +msgid "Expand Brightness" +msgstr "Expandera ljushet" + +#: fotoxx-12.01.1.cc:269 +msgid "Flatten Brightness" +msgstr "Platta till ljushet" + +#: fotoxx-12.01.1.cc:270 +msgid "Brightness Ramp" +msgstr "Ljushetsramp" + +#: fotoxx-12.01.1.cc:272 +msgid "White Balance" +msgstr "Vitbalans" + +#: fotoxx-12.01.1.cc:273 +msgid "Match Colors" +msgstr "Matchande färger" + +#: fotoxx-12.01.1.cc:276 +msgid "Red Eyes" +msgstr "Röda ögon" + +#: fotoxx-12.01.1.cc:277 +msgid "Blur Image" +msgstr "Gör bilden suddig" + +#: fotoxx-12.01.1.cc:279 +msgid "Reduce Noise" +msgstr "Minska brus" + +#: fotoxx-12.01.1.cc:285 +msgid "Art" +msgstr "Sort" + +#: fotoxx-12.01.1.cc:286 +msgid "Color Depth" +msgstr "Färgdjup" + +#: fotoxx-12.01.1.cc:287 +msgid "Drawing" +msgstr "Ritning" + +#: fotoxx-12.01.1.cc:288 +msgid "Outlines" +msgstr "Konturer" + +#: fotoxx-12.01.1.cc:289 +msgid "Embossing" +msgstr "Bosselera" + +#: fotoxx-12.01.1.cc:290 +msgid "Tiles" +msgstr "Plattor" + +#: fotoxx-12.01.1.cc:291 +msgid "Dots" +msgstr "Punkter" + +#: fotoxx-12.01.1.cc:292 +msgid "Painting" +msgstr "Färgläggning" + +#: fotoxx-12.01.1.cc:294 +msgid "Combine" +msgstr "Kombinera" + +#: fotoxx-12.01.1.cc:295 +msgid "High Dynamic Range" +msgstr "Stort dynamiskt område" + +#: fotoxx-12.01.1.cc:296 +msgid "High Depth of Field" +msgstr "" + +#: fotoxx-12.01.1.cc:297 +msgid "Stack / Paint" +msgstr "Stack / färg" + +#: fotoxx-12.01.1.cc:298 +msgid "Stack / Noise" +msgstr "Stack / brus" + +#: fotoxx-12.01.1.cc:299 +msgid "Panorama" +msgstr "Panorama" + +#: fotoxx-12.01.1.cc:300 +msgid "Vertical Panorama" +msgstr "Vertikalt panorama" + +#: fotoxx-12.01.1.cc:303 +msgid "Edit Plugins" +msgstr "Redigera insticksprogram" + +#: fotoxx-12.01.1.cc:312 fotoxx-12.01.1.cc:340 fotoxx-12.01.1.cc:3025 +msgid "Help" +msgstr "Hjälp" + +#: fotoxx-12.01.1.cc:313 fotoxx-12.01.1.cc:3015 +msgid "About" +msgstr "Om" + +#: fotoxx-12.01.1.cc:314 fotoxx-12.01.1.cc:3019 +msgid "User Guide" +msgstr "Användarguide" + +#: fotoxx-12.01.1.cc:315 fotoxx-12.01.1.cc:3022 +msgid "User Guide Changes" +msgstr "Ändringar i användarhandbok" + +#: fotoxx-12.01.1.cc:316 fotoxx-12.01.1.cc:3031 +msgid "Edit Functions Summary" +msgstr "Sammanfattning av redigeringsfunktioner" + +#: fotoxx-12.01.1.cc:317 fotoxx-12.01.1.cc:3034 +msgid "Change Log" +msgstr "Ändringslogg" + +#: fotoxx-12.01.1.cc:318 fotoxx-12.01.1.cc:3037 +msgid "Translations" +msgstr "Översättningar" + +#: fotoxx-12.01.1.cc:319 fotoxx-12.01.1.cc:3040 +msgid "Home Page" +msgstr "Hemsida" + +#: fotoxx-12.01.1.cc:323 +msgid "Gallery" +msgstr "Galleri" + +#: fotoxx-12.01.1.cc:326 fotoxx.h:767 +msgid "Next" +msgstr "Nästa" + +#: fotoxx-12.01.1.cc:326 +msgid "Open Next File" +msgstr "Öppna nästa fil" + +#: fotoxx-12.01.1.cc:327 +msgid "Zoom-in (bigger)" +msgstr "Zooma in (större)" + +#: fotoxx-12.01.1.cc:328 +msgid "Zoom-out (smaller)" +msgstr "Zooma ut (mindre)" + +#: fotoxx-12.01.1.cc:329 fotoxx.h:794 +msgid "Undo" +msgstr "Ångra" + +#: fotoxx-12.01.1.cc:329 +msgid "Undo One Edit" +msgstr "Ångra en redigering" + +#: fotoxx-12.01.1.cc:330 fotoxx.h:779 +msgid "Redo" +msgstr "Gör om" + +#: fotoxx-12.01.1.cc:330 +msgid "Redo One Edit" +msgstr "Gör om en redigering" + +#: fotoxx-12.01.1.cc:334 +msgid "Save+V" +msgstr "Spara+V" + +#: fotoxx-12.01.1.cc:335 +msgid "Save+F" +msgstr "Spara+F" + +#: fotoxx-12.01.1.cc:336 +msgid "Move Image to Trash" +msgstr "Flytta bild till Skräp" + +#: fotoxx-12.01.1.cc:336 +msgid "Trash" +msgstr "Skräp" + +#: fotoxx-12.01.1.cc:339 +msgid "Quit" +msgstr "Avsluta" + +#: fotoxx-12.01.1.cc:340 +msgid "Fotoxx Essentials" +msgstr "Fotoxx Essentials" + +#: fotoxx-12.01.1.cc:447 +msgid "first time startup" +msgstr "första start" + +#: fotoxx-12.01.1.cc:1943 +msgid "Exceed 50 anchor points" +msgstr "Överskridit 50 ankarpunkter" + +#: fotoxx-12.01.1.cc:2128 +msgid "load curve from a file" +msgstr "ladda kurva från fil" + +#: fotoxx-12.01.1.cc:2181 +msgid "curve file is invalid" +msgstr "kurvfil är ogiltig" + +#: fotoxx-12.01.1.cc:2186 +msgid "curve file has different no. of curves" +msgstr "kurvfil har annorlunda antal kurvor" + +#: fotoxx-12.01.1.cc:2201 +msgid "save curve to a file" +msgstr "spara kurva till en fil" + +#: fotoxx-12.01.1.cc:2336 +msgid "cannot parallel edit" +msgstr "kan ej redigera i parallell" + +#: fotoxx-12.01.1.cc:2346 +msgid "" +"exiftool is not installed \n" +"edited images will lose EXIF data" +msgstr "" +"exif-verktyg är ej installerat\n" +"redigerade bilder kommer att tappa EXIF-data" + +#: fotoxx-12.01.1.cc:2352 +msgid "Too many edits, please save image" +msgstr "För många redigeringar, spara bilden" + +#: fotoxx-12.01.1.cc:2357 +msgid "" +"Select area cannot be kept.\n" +"Continue?" +msgstr "" +"Valt område behållas.\n" +"Fortsätta?" + +#: fotoxx-12.01.1.cc:2365 +msgid "" +"Select area not active.\n" +"Continue?" +msgstr "" +"Valt område ej aktivt.\n" +"Fortsätta?" + +#: fotoxx-12.01.1.cc:2836 +msgid "Discard edits?" +msgstr "Strunta i redigeringar?" + +#: fotoxx-12.01.1.cc:2837 +msgid "" +"This action will discard current edits.\n" +"Continue to discard edits.\n" +"Go Back to keep edits." +msgstr "" +"Denna åtgärd kommer att förkasta aktuella redigeringar.\n" +"Fortsätt att förkasta redigeringar.\n" +"Gå tillbaka för att behålla redigeringar." + +#: fotoxx-12.01.1.cc:2840 +msgid "Continue" +msgstr "Fortsätt" + +#: fotoxx-12.01.1.cc:2841 +msgid "Go Back" +msgstr "Gå tillbaka" + +#: fotoxx-12.01.1.cc:3658 +msgid "cannot open thumbnail file" +msgstr "kan ej öppna miniatyrbildsfil" + +#: fotoxx-12.01.1.cc:3869 fotoxx-12.01.1.cc:3991 +msgid "TIFF open failure" +msgstr "Fel vid öppnande av TIFF" + +#: fotoxx-12.01.1.cc:3885 +#, c-format +msgid "TIFF bits/color=%d not supported" +msgstr "TIFF bits/color=%d stöds ej" + +#: fotoxx-12.01.1.cc:3900 fotoxx-12.01.1.cc:3938 +msgid "TIFF read failure" +msgstr "Fel vid läsning av TIFF" + +#: fotoxx-12.01.1.cc:4050 +msgid "TIFF write failure" +msgstr "Fel vid skrivning av TIFF" + +#: fotoxx-12.01.1.cc:4070 +msgid "file type not supported" +msgstr "filtyp stöds ej" + +#: fotoxx-12.01.1.cc:4177 +msgid "pixbuf write failure" +msgstr "pixbuf-skrivfel" + +#: fotoxx.h:728 +msgid "absolute" +msgstr "absolut" + +#: fotoxx.h:730 +msgid "Add All" +msgstr "Lägg till allt" + +#: fotoxx.h:732 +msgid "Amount" +msgstr "Mängd" + +#: fotoxx.h:733 +msgid "Apply" +msgstr "Tillämpa" + +#: fotoxx.h:734 +msgid "Black" +msgstr "Svart" + +#: fotoxx.h:735 +msgid "Blend Width" +msgstr "Bländaröppning" + +#: fotoxx.h:737 +msgid "Brightness" +msgstr "Ljushet" + +#: fotoxx.h:738 +msgid "Browse" +msgstr "Bläddra" + +#: fotoxx.h:739 +msgid "Cancel" +msgstr "Avbryt" + +#: fotoxx.h:740 +msgid "Clear" +msgstr "Rensa" + +#: fotoxx.h:742 +msgid "Commit" +msgstr "Delge" + +#: fotoxx.h:744 +msgid "Curve File:" +msgstr "Kurvfil:" + +#: fotoxx.h:745 +msgid "Cut" +msgstr "Beskär" + +#: fotoxx.h:746 +msgid "Darker Areas" +msgstr "Mörkare områden" + +#: fotoxx.h:747 +msgid "Delete" +msgstr "Tag bort" + +#: fotoxx.h:749 +#, c-format +msgid "" +"Discard special gallery list? \n" +" %s" +msgstr "" +"Förkasta särskild gallerilista?\n" +" %s" + +#: fotoxx.h:750 +msgid "Done" +msgstr "Gjort" + +#: fotoxx.h:751 +msgid "Edit" +msgstr "Redigera" + +#: fotoxx.h:753 +msgid "Erase" +msgstr "Radera" + +#: fotoxx.h:754 +msgid "package libimage-exiftool-perl is required" +msgstr "paketet libimage-exiftool-perl krävs" + +#: fotoxx.h:755 +msgid "Fetch" +msgstr "Hämta" + +#: fotoxx.h:756 +msgid "Finish" +msgstr "Avsluta" + +#: fotoxx.h:757 +msgid "Font" +msgstr "Typsnitt" + +#: fotoxx.h:759 +msgid "Height" +msgstr "Höjd" + +#: fotoxx.h:760 +msgid "histogram" +msgstr "histogram" + +#: fotoxx.h:762 +msgid "Insert" +msgstr "Infoga" + +#: fotoxx.h:764 +msgid "Lighter Areas" +msgstr "Ljusare områden" + +#: fotoxx.h:765 +msgid "limit" +msgstr "gräns" + +#: fotoxx.h:766 +msgid "New" +msgstr "Ny" + +#: fotoxx.h:768 +msgid "OK" +msgstr "OK" + +#: fotoxx.h:772 +msgid "Pause" +msgstr "Paus" + +#: fotoxx.h:773 +msgid "Percent" +msgstr "Procent" + +#: fotoxx.h:774 +msgid "Presets" +msgstr "Förinställningar" + +#: fotoxx.h:775 +msgid "Proceed" +msgstr "Fortsätt" + +#: fotoxx.h:777 +msgid "range" +msgstr "område" + +#: fotoxx.h:780 +msgid "Reduce" +msgstr "Minska" + +#: fotoxx.h:782 +msgid "Reset" +msgstr "Återställ" + +#: fotoxx.h:784 +msgid "Unknown file type, save as tiff/jpeg/png to edit" +msgstr "Okänd filtyp, spara som tiff/jpeg/png för att redigera" + +#: fotoxx.h:785 +msgid "Search" +msgstr "Sök" + +#: fotoxx.h:789 +msgid "Start" +msgstr "Start" + +#: fotoxx.h:790 +msgid "Threshold" +msgstr "Tröskel" + +#: fotoxx.h:791 +#, c-format +msgid "exceed %d files" +msgstr "överskred %d filer" + +#: fotoxx.h:792 +msgid "Undo All" +msgstr "Ångra allt" + +#: fotoxx.h:793 +msgid "Undo Last" +msgstr "Ångra sista" + +#: fotoxx.h:795 +msgid "Unfinish" +msgstr "Oavslutad" + +#: fotoxx.h:797 +msgid "View" +msgstr "Vy" + +#: fotoxx.h:798 +msgid "White" +msgstr "Vit" + +#: fotoxx.h:799 +msgid "Width" +msgstr "Bredd" + +#: zfuncs.cc:3252 +#, c-format +msgid "help file not found: %s" +msgstr "hjälpfil ej hittad: %s" + +#: zfuncs.cc:3664 zfuncs.cc:7315 +#, c-format +msgid "cannot open file %s" +msgstr "kan ej öppna fil %s" + +#: zfuncs.cc:3697 +msgid "save screen to file" +msgstr "spara skärmbild i fil" + +#: zfuncs.cc:6222 +msgid "No" +msgstr "Nej" + +#: zfuncs.cc:6222 +msgid "Yes" +msgstr "Ja" + +#: zfuncs.cc:6447 +msgid "open" +msgstr "öppna" + +#: zfuncs.cc:6452 +msgid "choose" +msgstr "välj" + +#: zfuncs.cc:6457 +msgid "save" +msgstr "spara" + +#: zfuncs.cc:6463 +msgid "open folder" +msgstr "öppna mapp" + +#: zfuncs.cc:6468 +msgid "create folder" +msgstr "skapa mapp" + +#: zfuncs.cc:6474 +msgid "hidden" +msgstr "gömd" + +#: zfuncs.cc:6535 +msgid "JPG quality 0-100" +msgstr "JPG-kvalitet 0-100" + +#: zfuncs.cc:6728 zfuncs.cc:6741 +msgid "margins" +msgstr "marginaler" + +#: zfuncs.cc:6737 +msgid "top" +msgstr "topp" + +#: zfuncs.cc:6738 +msgid "bottom" +msgstr "botten" + +#: zfuncs.cc:6739 +msgid "left" +msgstr "vänster" + +#: zfuncs.cc:6740 +msgid "right" +msgstr "höger" + +#: zfuncs.cc:7202 +msgid "" +"Initial parameters file created. \n" +"Inspect and revise if necessary." +msgstr "" +"Startparameterfil skapad. \n" +"Undersök och ändra vid behov." + +#: zfuncs.cc:7218 +msgid "load parameters from a file" +msgstr "ladda parametrar från fil" + +#: zfuncs.cc:7287 +msgid "save parameters to a file" +msgstr "spara parametrar i en fil" + +#: zfuncs.cc:7425 zfuncs.cc:7431 zfuncs.cc:7437 zfuncs.cc:7443 +msgid "edit parameters" +msgstr "redigera parametrar" + +#: zfuncs.cc:7426 zfuncs.cc:7432 +msgid "" +"list\n" +"all" +msgstr "" +"lista\n" +"allt" + +#: zfuncs.cc:7426 zfuncs.cc:7432 zfuncs.cc:7438 zfuncs.cc:7444 +msgid "" +"load\n" +"file" +msgstr "" +"ladda\n" +"fil" + +#: zfuncs.cc:7426 zfuncs.cc:7432 zfuncs.cc:7438 zfuncs.cc:7444 +msgid "" +"save\n" +"file" +msgstr "" +"spara\n" +"fil" + +#: zfuncs.cc:7427 zfuncs.cc:7439 +msgid "" +"add\n" +"new" +msgstr "" +"lägg till\n" +"nytt" + +#: zfuncs.cc:7427 zfuncs.cc:7433 zfuncs.cc:7439 zfuncs.cc:7445 +msgid "apply" +msgstr "tillämpa" + +#: zfuncs.cc:7479 +msgid "apply?" +msgstr "tillämpa?" + +#: zfuncs.cc:7536 +msgid "(new parm name)" +msgstr "(nytt parameternamn)" + +#: zfuncs.cc:7536 +msgid "add parameter" +msgstr "lägg till parameter" + +#~ msgid "Lens Parameters" +#~ msgstr "Linsparametrar" + +#~ msgid "my mouse" +#~ msgstr "min mus" + +#~ msgid "lens name" +#~ msgstr "linsnamn" + +#~ msgid "select new file" +#~ msgstr "välj ny fil" + +#~ msgid "Translate" +#~ msgstr "Översätt" + +#~ msgid "" +#~ "Run Tools > Synchronize Files so that gallery windows \n" +#~ "will be fast and Search Images will work correctly." +#~ msgstr "" +#~ "Kör Verktyg->Synkronisera filer så att bildfönstren \n" +#~ "blir snabba och bildsökning fungerar rätt." + +#~ msgid "full rebuild" +#~ msgstr "total återbildning" + +#~ msgid "incremental" +#~ msgstr "stegvis" + +#~ msgid "" +#~ "Rename failed \n" +#~ " %s" +#~ msgstr "" +#~ "Omdöpning misslyckades \n" +#~ " %s" + +#~ msgid "transition" +#~ msgstr "övergång" + +#~ msgid "Discard modifications?" +#~ msgstr "Kasta ändringar?" + +#~ msgid "Edit Comments" +#~ msgstr "Redigera kommentarer" + +#~ msgid "Edit Caption" +#~ msgstr "Redigera rubrik" + +#~ msgid "tags exceed %d characters" +#~ msgstr "taggar överskrider %d tecken" + +#~ msgid "recently added" +#~ msgstr "nyligen tillagd" + +#~ msgid "new file already exists: %s" +#~ msgstr "ny fill finns redan: %s" + +#~ msgid "grid spacing" +#~ msgstr "rutnätsavstånd" + +#~ msgid "filespec too long: %s" +#~ msgstr "filspecifikation för lång. %s" + +#~ msgid "assigned tags" +#~ msgstr "tilldelade taggar" + +#~ msgid "Unable to save image: %s" +#~ msgstr "Kan ej spara bild: %s" + +#~ msgid "Unable to copy EXIF data" +#~ msgstr "Kan ej kopiera EXIT-data" + +#~ msgid "Total tags exceed %d characters" +#~ msgstr "Total taggar överskreds med %d tecken" + +#~ msgid "Too many undo buffers, please save image" +#~ msgstr "För många ångrabuffertar, spara bild" + +#~ msgid "Too many tags: %d" +#~ msgstr "För många taggar: %d" + +#~ msgid "Package exiftool is missing" +#~ msgstr "Pakets exif-verktyg saknas" + +#~ msgid "Index Tags" +#~ msgstr "Indextaggar" + +#~ msgid "" +#~ "Drag middle to move \n" +#~ "Drag corners to resize" +#~ msgstr "" +#~ "Drag i mitten för att flytta\n" +#~ "Drag i hörn för att ändra storlek" + +#~ msgid "Convert Tags" +#~ msgstr "Omvandla taggar" + +#~ msgid "Add or Remove Grid Lines" +#~ msgstr "Lägg till eller ta bort rutnät" + +#~ msgid "" +#~ "%s \n" +#~ " tag limit exceeded" +#~ msgstr "" +#~ "%s \n" +#~ " tag-gräns överskriden" + +#~ msgid "jpeg quality" +#~ msgstr "jpegkvalitet" + +#~ msgid "Select between 2 and 10 files to combine" +#~ msgstr "Välj mellan 2 och 10 filer att kombinera" + +#~ msgid "Current file must be included" +#~ msgstr "Aktuell fil måste tas med" + +#~ msgid "Select image to combine" +#~ msgstr "Välj bild att kombinera" + +#~ msgid "Select 2 to 10 files to combine" +#~ msgstr "Välj2 till 20 filer att kombinera" + +#~ msgid "Retouch Image" +#~ msgstr "Retuschera bild" + +#~ msgid "Package ufraw required for this function" +#~ msgstr "Pakets ufraw behövs för denna funktion" + +#~ msgid "Merge the images together" +#~ msgstr "Slå samman bilder" + +#~ msgid "Match Images" +#~ msgstr "Matcha bilder" + +#~ msgid "" +#~ "Drag right image into rough alignment with left \n" +#~ " to rotate, drag right edge up or down" +#~ msgstr "" +#~ "Drag högra bilden till grov inlinjering med vänstra\n" +#~ " för att rotera, drag höger kant upp eller ner" + +#~ msgid "Auto-search lens mm and bow" +#~ msgstr "Sök automatiskt lins mm och kurva" + +#~ msgid "Auto" +#~ msgstr "Auto" + +#~ msgid "" +#~ "\n" +#~ " Match Brightness and Color" +#~ msgstr "" +#~ "\n" +#~ " Matcha ljushet och färg" + +#~ msgid "select image files to add tags" +#~ msgstr "välj bildfiler för tillägg av taggar" + +#~ msgid "select files" +#~ msgstr "välj filer" + +#~ msgid "rename files" +#~ msgstr "döp om fil" + +#~ msgid "freehand draw" +#~ msgstr "frihandsritning" + +#~ msgid "follow edge" +#~ msgstr "följ kant" + +#~ msgid "" +#~ "exiftool missing, please install \n" +#~ " package libimage-exiftool-perl" +#~ msgstr "" +#~ "exiftool saknas, installera \n" +#~ " paketet libimage-exiftool-perl" + +#~ msgid "color range" +#~ msgstr "färgomfång" + +#~ msgid "browse" +#~ msgstr "bläddra" + +#~ msgid "add tags" +#~ msgstr "lägg till taggar" + +#~ msgid "TIFF colors=%d depth=%d not supported" +#~ msgstr "TIFF färger=%d djup=%d ej understött" + +#~ msgid "Fix Image Perspective" +#~ msgstr "Ordna bildperspektiv" + +#~ msgid "" +#~ "Convert tags to new standard now?\n" +#~ "Are your image files backed-up?" +#~ msgstr "" +#~ "Omvandla taggar till ny standrad nu?\n" +#~ "Är dina bildfiler säkerhetskopierade?" + +#~ msgid "Burn" +#~ msgstr "Bränn" + +#~ msgid "color intensity" +#~ msgstr "färgintensitet" + +#~ msgid "Read File" +#~ msgstr "Läs fil" + +#~ msgid "" +#~ "position image\n" +#~ "with mouse drag" +#~ msgstr "" +#~ "placera bild\n" +#~ "med musdragning" + +#~ msgid "Warp Image in Selected Area" +#~ msgstr "Förvräng bild i valt område" + +#~ msgid "Warp Image (curvy)" +#~ msgstr "Förvräng bild (krokig)" + +#~ msgid "Warp Area" +#~ msgstr "Förvrängningsområde" + +#~ msgid "" +#~ " Pull on an image edge using the mouse. \n" +#~ " Make multiple mouse pulls until satisfied. \n" +#~ " When finished, press [done]." +#~ msgstr "" +#~ " Drag i en bildkant med musen.\n" +#~ " Gör flera musdragningar till du är nöjd.\n" +#~ " När du är klar tryck [Avsluta]." + +#~ msgid "comments" +#~ msgstr "kommentarer" + +#~ msgid "Suspend" +#~ msgstr "Avbryt" + +#~ msgid "Resume" +#~ msgstr "Återuppta" + +#~ msgid "/path*/file*" +#~ msgstr "/sökväg*/fil*" + +#~ msgid "transparency" +#~ msgstr "tramsparens" + +#~ msgid "match any tag" +#~ msgstr "matcha någon tagg" + +#~ msgid "match all tags" +#~ msgstr "matcha alla taggar" + +#~ msgid "foreground" +#~ msgstr "förgrund" + +#~ msgid "background" +#~ msgstr "bakgrund" + +#~ msgid "annotation file:" +#~ msgstr "anteckningsfil:" + +#~ msgid "Tags" +#~ msgstr "Taggar" + +#~ msgid "Set Tile and Gap Size" +#~ msgstr "Välj storlek på ruta och mellanrum" + +#~ msgid "Search Tags" +#~ msgstr "Sök taggar" + +#~ msgid "Edit User Comments" +#~ msgstr "Redigera användarkommentarer" + +#~ msgid "Edit EXIF data" +#~ msgstr "Redigera EXIF-data" + +#~ msgid "EXIF data" +#~ msgstr "EXIF-data" + +#~ msgid "Delete EXIF data" +#~ msgstr "Tag bort EXIF-data" + +#~ msgid "Basic EXIF data" +#~ msgstr "Grundläggande EXIF-data" + +#~ msgid "All EXIF data" +#~ msgstr "All EXIF-data" + +#~ msgid "tags index file error: %s" +#~ msgstr "taggindexfilfel: %s" + +#~ msgid "save select area as a file" +#~ msgstr "spara valt område som en fil" + +#~ msgid "new tags index will now be created" +#~ msgstr "nytt taggindex kommer nu att skapas" + +#~ msgid "manage tags" +#~ msgstr "hantera märken" + +#~ msgid "color select firewall" +#~ msgstr "färgvälj brandvägg" + +#~ msgid "cannot read .dist file" +#~ msgstr "kan ej läsa .dist-fil" + +#~ msgid "brightness to clip (percent)" +#~ msgstr "ljushet att klippa vid (procent)" + +#~ msgid "Use F1 for context help" +#~ msgstr "Använd F1 för sammanhangshjälp" + +#~ msgid "Stack" +#~ msgstr "Stack" + +#~ msgid "Rebuild Tags Index" +#~ msgstr "Bygg om taggindex" + +#~ msgid "No tags index file" +#~ msgstr "Ingen taggindexfil" + +#~ msgid "" +#~ "New tags file already exists! \n" +#~ "Proceed anyway?" +#~ msgstr "" +#~ "Ny flaggor finns redan!\n" +#~ "Fortsätta ändå?" + +#~ msgid "HDR" +#~ msgstr "HDR" + +#~ msgid "HDF" +#~ msgstr "HDF" + +#~ msgid "" +#~ "Convert tags to new standard now? \n" +#~ "Are your image files backed-up?" +#~ msgstr "" +#~ "Omvandla flaggor till ny standard nu?\n" +#~ "Är dina bildfiler säkerhetskopierade?" + +#~ msgid "Convert tags to new standard" +#~ msgstr "Omvandla taggar till ny standard" + +#~ msgid "Convert Tags !!!" +#~ msgstr "Omvandla taggar !!!" + +#~ msgid "Constrain" +#~ msgstr "Begränsning" + +#~ msgid "Area" +#~ msgstr "Yta" + +#~ msgid "target group area" +#~ msgstr "mälgruppsområde" + +#~ msgid "vertical unbend" +#~ msgstr "vertikal uträtning" + +#~ msgid "select by mouse:" +#~ msgstr "välj med mus:" + +#~ msgid "select by color:" +#~ msgstr "välj genom färg:" + +#~ msgid "press ESC to exit" +#~ msgstr "tryck ESC för att avsluta" + +#~ msgid "horizontal unbend" +#~ msgstr "horisontell utslätning" + +#~ msgid "Rebuild Thumbnails" +#~ msgstr "Bygg om miniatyrbilder" + +#~ msgid "save collection" +#~ msgstr "spara samling" + +#~ msgid "open collection" +#~ msgstr "öppna samling" + +#~ msgid "area outline has a hole" +#~ msgstr "områdesbegränsning som ett hål" + +#~ msgid "" +#~ "Search all areas for edge and inside pixels. \n" +#~ "Click inside each enclosed area in sequence." +#~ msgstr "" +#~ "Sök all ytor efter kant och insidespixlar.\n" +#~ "Klicka på insida av varje inneslutet område i följd." + +#~ msgid "Open Image Collection" +#~ msgstr "Öppna bildsamling" + +#~ msgid "Make Image Collection" +#~ msgstr "Skapa bildsamling" + +#~ msgid "Create Launcher" +#~ msgstr "Skapa en startare" + +#~ msgid "make new version" +#~ msgstr "gör en ny version" + +#~ msgid "click on window to show RGB" +#~ msgstr "klicka på fönster för att visa RGB" + +#~ msgid "Save As" +#~ msgstr "Spara som" + +#~ msgid "Clone fotoxx" +#~ msgstr "Klona fotoxx" + +#~ msgid "random" +#~ msgstr "slumpvis" + +#~ msgid "Whole Image" +#~ msgstr "Hel bild" + +#~ msgid "Time Interval" +#~ msgstr "Tidsintervall" + +#~ msgid "print" +#~ msgstr "skriv" + +#~ msgid "printer ID" +#~ msgstr "skrivar-ID" + +#~ msgid "paper format" +#~ msgstr "pappersformat" + +#~ msgid "portrait" +#~ msgstr "stående" + +#~ msgid "landscape" +#~ msgstr "liggande" + +#~ msgid "paper format is crazy" +#~ msgstr "galet pappersformat" + +#~ msgid "open a file" +#~ msgstr "öppna en fil" + +#~ msgid "Select area first" +#~ msgstr "Välj område först" + +#~ msgid "new file already exists" +#~ msgstr "nya filen finns redan" + +#~ msgid "copy EXIF" +#~ msgstr "kopiera EXIF" + +#~ msgid "new max. height" +#~ msgstr "ny max höjd" + +#~ msgid "Batch Resize" +#~ msgstr "Ändra storlek satsvis" + +#~ msgid "Search results file error %s" +#~ msgstr "Sök fel i resultat fil: %s" + +#~ msgid "match" +#~ msgstr "matcha" + +#~ msgid "radius" +#~ msgstr "radie" + +#~ msgid "select by color" +#~ msgstr "välj genom färg" + +#~ msgid "Brightness Graph" +#~ msgstr "Ljushetsdiagram" diff -Nru fotoxx-11.11.1/locales/fotoxx-zh_CN.po fotoxx-12.01.2/locales/fotoxx-zh_CN.po --- fotoxx-11.11.1/locales/fotoxx-zh_CN.po 1970-01-01 00:00:00.000000000 +0000 +++ fotoxx-12.01.2/locales/fotoxx-zh_CN.po 2012-01-04 08:47:11.000000000 +0000 @@ -0,0 +1,3282 @@ +# +# <>, YEAR, 2010. +# Jie , 2010. +# +msgid "" +msgstr "" +"Project-Id-Version: fotoxx\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-12-31 21:05+0100\n" +"PO-Revision-Date: 2010-09-08 19:28+1000\n" +"Last-Translator: Jie \n" +"Language-Team: Simplified Chinese <18n-translation@lists.linux.net.cn>\n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: UTF-8\n" +"X-Poedit-Language: Simplified Chinese\n" +"X-Poedit-Country: China PRC\n" +"X-Poedit-SourceCharset: utf-8\n" +"Plural-Forms: nplurals=1; plural=0\n" + +#: f.art.cc:47 +msgid "Set color depth to 1-16 bits" +msgstr "设置色深为 1-16bit" + +#: f.art.cc:57 +msgid "Set Color Depth" +msgstr "设置色深" + +#: f.art.cc:171 +msgid "Simulate Drawing" +msgstr "绘图" + +#: f.art.cc:213 f.retouch.cc:1759 f.retouch.cc:5991 +msgid "contrast" +msgstr "对比度" + +#: f.art.cc:215 +msgid "outlines" +msgstr "轮廓" + +#: f.art.cc:220 +msgid "pencil" +msgstr "铅笔" + +#: f.art.cc:221 +msgid "chalk" +msgstr "粉笔" + +#: f.art.cc:381 +msgid "Add Image Outlines" +msgstr "" + +#: f.art.cc:394 +msgid "outline threshold" +msgstr "" + +#: f.art.cc:397 +msgid "outline width" +msgstr "" + +#: f.art.cc:400 +msgid "image brightness" +msgstr "" + +#: f.art.cc:611 +msgid "Simulate Embossing" +msgstr "浮雕" + +#: f.art.cc:626 +msgid "depth" +msgstr "宽度" + +#: f.art.cc:628 f.file.cc:919 f.retouch.cc:6692 +msgid "color" +msgstr "色彩" + +#: f.art.cc:821 +msgid "Simulate Tiles" +msgstr "图块(马赛克)" + +#: f.art.cc:825 +msgid "tile size" +msgstr "图块尺寸" + +#: f.art.cc:829 +msgid "tile gap" +msgstr "图块边距" + +#: f.art.cc:1003 +msgid "Convert Image to Dots" +msgstr "" + +#: f.art.cc:1007 +msgid "dot size" +msgstr "" + +#: f.art.cc:1222 +msgid "Simulate Painting" +msgstr "彩绘" + +#: f.art.cc:1226 +msgid "color depth" +msgstr "色深" + +#: f.art.cc:1230 +msgid "patch area goal" +msgstr "" + +#: f.art.cc:1234 +msgid "req. color match" +msgstr "需要色彩匹配" + +#: f.art.cc:1238 +msgid "borders" +msgstr "边框" + +#: f.comp.cc:1956 f.comp.cc:1961 f.comp.cc:2582 f.comp.cc:2587 f.comp.cc:3266 +#: f.comp.cc:3271 f.comp.cc:3816 f.comp.cc:3821 +msgid "Select 2 to 9 files" +msgstr "选择2到9个文件" + +#: f.comp.cc:1982 f.comp.cc:2608 f.comp.cc:3292 f.comp.cc:3842 +msgid "Images are not all the same size" +msgstr "图像不全为同样尺寸" + +#: f.comp.cc:2321 +msgid "Adjust Image Contributions" +msgstr "调整图像输出" + +#: f.comp.cc:2324 f.retouch.cc:886 +msgid "dark pixels" +msgstr "暗 像素" + +#: f.comp.cc:2326 +msgid "light pixels" +msgstr "亮像素" + +#: f.comp.cc:2328 f.info.cc:159 +msgid "file:" +msgstr "文件:" + +#: f.comp.cc:2843 +msgid "Paint and Warp Image" +msgstr "涂画和扭曲图像" + +#: f.comp.cc:2846 f.comp.cc:3520 f.comp.cc:4959 f.comp.cc:5705 +msgid "image" +msgstr "图像" + +#: f.comp.cc:2850 f.retouch.cc:6696 +msgid "paint" +msgstr "绘制(黑白)" + +#: f.comp.cc:2851 +msgid "warp" +msgstr "扭曲" + +#: f.comp.cc:3518 +msgid "Select and Paint Image" +msgstr "" + +#: f.comp.cc:4031 +msgid "Adjust Pixel Composition" +msgstr "调整像素合成" + +#: f.comp.cc:4283 f.comp.cc:4288 f.comp.cc:5173 f.comp.cc:5178 +msgid "Select 2 to 4 files" +msgstr "选择2到4个文件" + +#: f.comp.cc:4361 +msgid "" +"Drag images into rough alignment.\n" +"To rotate, drag from lower edge." +msgstr "" +"拖拽图像粗略排布。\n" +"拖动下进行旋转。" + +#: f.comp.cc:4363 +msgid "Search for lens mm and bow" +msgstr "搜索" + +#: f.comp.cc:4409 f.comp.cc:5298 +msgid "Pre-align Images" +msgstr "预对齐 图像" + +#: f.comp.cc:4413 f.comp.cc:5302 +msgid "lens mm" +msgstr "镜头焦距" + +#: f.comp.cc:4417 f.comp.cc:5306 +msgid "lens bow" +msgstr "镜头弓度" + +#: f.comp.cc:4419 f.comp.cc:5308 +msgid "Resize" +msgstr "改变尺寸" + +#: f.comp.cc:4420 f.comp.cc:5309 +msgid "resize window" +msgstr "改变窗口尺寸" + +#: f.comp.cc:4457 +msgid "use two images only" +msgstr "使用两个图像" + +#: f.comp.cc:4478 f.comp.cc:4676 f.comp.cc:4875 f.comp.cc:5357 f.comp.cc:5620 +msgid "Too little overlap, cannot align" +msgstr "太多重叠,无法对齐" + +#: f.comp.cc:4950 f.comp.cc:5696 +msgid "Match Brightness and Color" +msgstr "匹配亮度和色彩" + +#: f.comp.cc:4974 f.comp.cc:5720 +msgid "auto color" +msgstr "自动上色" + +#: f.comp.cc:4975 f.comp.cc:5721 +msgid "file color" +msgstr "文件色彩" + +#: f.comp.cc:5251 +msgid "" +"Drag images into rough alignment.\n" +"To rotate, drag from right edge." +msgstr "" + +#: f.file.cc:169 f.file.cc:341 fotoxx-12.01.cc:189 fotoxx-12.01.cc:325 +msgid "Open Image File" +msgstr "打开图像文件" + +#: f.file.cc:321 fotoxx-12.01.cc:2862 +msgid "prior function still active" +msgstr "" + +#: f.file.cc:503 +msgid "Overwrite original file?" +msgstr "" + +#: f.file.cc:504 +msgid "Do not warn again" +msgstr "" + +#: f.file.cc:520 +msgid "Warning" +msgstr "" + +#: f.file.cc:643 +msgid "Save File" +msgstr "保存文件" + +#: f.file.cc:666 zfuncs.cc:6478 +msgid "quality" +msgstr "质量" + +#: f.file.cc:668 +msgid "make current" +msgstr "" + +#: f.file.cc:725 +msgid "jpeg quality must be 1-100" +msgstr "jpeg 质量必须在 1-100 间" + +#: f.file.cc:747 +#, c-format +msgid "" +"Overwrite file? \n" +" %s" +msgstr "" +"覆盖文件? \n" +" %s" + +#: f.file.cc:903 fotoxx-12.01.cc:196 +msgid "Create Blank Image" +msgstr "" + +#: f.file.cc:905 +msgid "file name" +msgstr "" + +#: f.file.cc:910 f.transform.cc:353 +msgid "width" +msgstr "" + +#: f.file.cc:913 f.tools.cc:477 f.transform.cc:356 +msgid "height" +msgstr "" + +#: f.file.cc:1033 +msgid "" +"Linux standard trash is not supported. \n" +"Desktop trash folder will be created." +msgstr "" +"Linux标准回收站仍未支持。\n" +"将会建立桌面回收站。" + +#: f.file.cc:1051 +msgid "Move read-only file to trash?" +msgstr "移动只读图片到可回收文件夹" + +#: f.file.cc:1077 +#, c-format +msgid "Cannot create trash folder: %s" +msgstr "无法创建可回收文件夹: %s" + +#: f.file.cc:1085 f.file.cc:1091 zfuncs.cc:3356 +#, c-format +msgid "error: %s" +msgstr "错误:%s" + +#: f.file.cc:1136 fotoxx-12.01.cc:198 +msgid "Rename Image File" +msgstr "图像文件改名" + +#: f.file.cc:1141 +msgid "old name" +msgstr "旧名称" + +#: f.file.cc:1142 +msgid "rename to" +msgstr "改名为" + +#: f.file.cc:1143 +msgid "previous" +msgstr "前一个" + +#: f.file.cc:1229 +msgid "The target file already exists" +msgstr "目标文件已经存在" + +#: f.file.cc:1237 +#, c-format +msgid "" +"Rename failed: \n" +" %s" +msgstr "" + +#: f.file.cc:1285 +msgid "Batch Rename" +msgstr "批量重命名" + +#: f.file.cc:1288 f.file.cc:1340 f.info.cc:1519 f.info.cc:1773 f.tools.cc:543 +#: f.tools.cc:2990 +#, c-format +msgid "%d files selected" +msgstr "" + +#: f.file.cc:1290 +msgid "new base name" +msgstr "新基础名称" + +#: f.file.cc:1293 +msgid "starting sequence" +msgstr "开始顺序" + +#: f.file.cc:1295 +msgid "increment" +msgstr "增量" + +#: f.file.cc:1316 +msgid "select files to rename" +msgstr "选择文件改名" + +#: f.file.cc:1321 +msgid "base name / sequence / increment not reasonable" +msgstr "基础名称/顺序/增量 不可达成" + +#: f.file.cc:1380 +msgid "new file already exists:" +msgstr "新文件已经存在:" + +#: f.file.cc:1388 +msgid "filespec too long:" +msgstr "文件特性太长:" + +#: f.file.cc:1399 +msgid "Rename failed:" +msgstr "重命名失败:" + +#: f.file.cc:1660 fotoxx.h:729 +msgid "Add" +msgstr "" + +#: f.file.cc:1660 fotoxx.h:781 +msgid "Remove" +msgstr "" + +#: f.file.cc:1662 +msgid "menu name" +msgstr "" + +#: f.file.cc:1733 f.file.cc:1754 +msgid "Restart Fotoxx to update plugin menu" +msgstr "" + +#: f.info.cc:70 +msgid "Edit Caption and Comments" +msgstr "" + +#: f.info.cc:156 fotoxx-12.01.cc:225 +msgid "Edit Tags" +msgstr "修改标签" + +#: f.info.cc:163 +msgid "image date (yyyymmdd)" +msgstr "图片日期(年月日──yyyymmdd)" + +#: f.info.cc:165 +msgid "use last" +msgstr "最后使用" + +#: f.info.cc:168 +msgid "image stars" +msgstr "图像点" + +#: f.info.cc:186 +msgid "current tags" +msgstr "当前标签" + +#: f.info.cc:191 +msgid "recent tags" +msgstr "最近的标签" + +#: f.info.cc:196 f.info.cc:358 f.info.cc:1368 f.info.cc:2384 +msgid "defined tags" +msgstr "定义的标签" + +#: f.info.cc:345 fotoxx-12.01.cc:226 +msgid "Manage Tags" +msgstr "" + +#: f.info.cc:348 +msgid "category" +msgstr "分类" + +#: f.info.cc:351 +msgid "tag" +msgstr "标签" + +#: f.info.cc:354 +msgid "create" +msgstr "创造" + +#: f.info.cc:355 f.navi.cc:1421 +msgid "delete" +msgstr "删除" + +#: f.info.cc:1235 f.info.cc:1319 +#, c-format +msgid "search index file error: %s" +msgstr "" + +#: f.info.cc:1351 fotoxx-12.01.cc:227 +msgid "Batch Add Tags" +msgstr "批量添加标签" + +#: f.info.cc:1354 +msgid "tags to add" +msgstr "要添加的标签" + +#: f.info.cc:1359 +msgid "create tag" +msgstr "创建标签" + +#: f.info.cc:1415 f.info.cc:1608 +#, c-format +msgid "" +"%s \n" +" too many tags" +msgstr "" +"%s \n" +" 太多标签" + +#: f.info.cc:1553 fotoxx-12.01.cc:228 +msgid "Batch Delete Tag" +msgstr "批量删除标签" + +#: f.info.cc:1556 +msgid "tag to remove" +msgstr "将要移除的标签" + +#: f.info.cc:1560 +msgid "optional replacement" +msgstr "可选的替代" + +#: f.info.cc:1565 f.tools.cc:2943 +msgid "0 files selected" +msgstr "" + +#: f.info.cc:1568 +msgid "search all files" +msgstr "搜索全部文件" + +#: f.info.cc:1653 +msgid "no files selected" +msgstr "" + +#: f.info.cc:1659 +msgid "no tag specified" +msgstr "" + +#: f.info.cc:1683 f.info.cc:1712 +msgid "specify tag" +msgstr "" + +#: f.info.cc:1821 +msgid "View Info" +msgstr "" + +#: f.info.cc:1889 fotoxx-12.01.cc:231 +msgid "Edit Info" +msgstr "" + +#: f.info.cc:1987 fotoxx-12.01.cc:232 +msgid "Delete Info" +msgstr "" + +#: f.info.cc:1989 fotoxx.h:731 +msgid "All" +msgstr "全部" + +#: f.info.cc:1990 +msgid "One Key:" +msgstr "一键:" + +#: f.info.cc:2343 +msgid "Search Tags, Comments, File Names" +msgstr "" + +#: f.info.cc:2350 +msgid "date range" +msgstr "日期范围" + +#: f.info.cc:2351 +msgid "stars range" +msgstr "点范围" + +#: f.info.cc:2352 +msgid "search tags" +msgstr "搜索标签" + +#: f.info.cc:2353 +msgid "search text" +msgstr "" + +#: f.info.cc:2354 +msgid "file names" +msgstr "" + +#: f.info.cc:2359 +msgid "(yyyymmdd)" +msgstr "" + +#: f.info.cc:2365 +msgid "all/any" +msgstr "" + +#: f.info.cc:2702 +msgid "No matching images found" +msgstr "未找到对应图片" + +#: f.info.cc:2706 f.info.cc:3059 +msgid "No search index file present" +msgstr "" + +#: f.info.cc:2777 +msgid "Additional Items for Report" +msgstr "" + +#: f.navi.cc:188 f.navi.cc:576 f.navi.cc:706 f.navi.cc:707 f.navi.cc:709 +msgid "bigger" +msgstr "放大" + +#: f.navi.cc:188 +msgid "increase thumbnail size" +msgstr "提升缩略图尺寸" + +#: f.navi.cc:189 +msgid "reduce thumbnail size" +msgstr "减小缩略图尺寸" + +#: f.navi.cc:189 f.navi.cc:586 f.navi.cc:708 f.navi.cc:710 +msgid "smaller" +msgstr "缩小" + +#: f.navi.cc:190 f.navi.cc:600 +msgid "parent" +msgstr "上级" + +#: f.navi.cc:190 +msgid "parent directory" +msgstr "上级目录" + +#: f.navi.cc:191 f.navi.cc:625 f.navi.cc:717 +msgid "first page" +msgstr "第一页" + +#: f.navi.cc:191 +msgid "jump to first file" +msgstr "跳至第一个文件" + +#: f.navi.cc:192 f.navi.cc:623 f.navi.cc:712 f.navi.cc:719 +msgid "prev page" +msgstr "前一页" + +#: f.navi.cc:192 +msgid "previous page" +msgstr "前一页" + +#: f.navi.cc:193 f.navi.cc:621 f.navi.cc:714 +msgid "prev row" +msgstr "前一行" + +#: f.navi.cc:193 +msgid "previous row" +msgstr "前一行" + +#: f.navi.cc:194 f.navi.cc:622 f.navi.cc:715 +msgid "next row" +msgstr "下一行" + +#: f.navi.cc:195 f.navi.cc:624 f.navi.cc:713 f.navi.cc:720 +msgid "next page" +msgstr "下一页" + +#: f.navi.cc:195 +msgid "ttip::next page" +msgstr "" + +#: f.navi.cc:196 +msgid "jump to last file" +msgstr "跳至最后一个文件" + +#: f.navi.cc:196 f.navi.cc:626 f.navi.cc:718 +msgid "last page" +msgstr "上一页" + +#: f.navi.cc:197 f.navi.cc:571 +msgid "close" +msgstr "关闭" + +#: f.navi.cc:197 +msgid "close image gallery" +msgstr "关闭图像浏览" + +#: f.navi.cc:1413 fotoxx.h:787 +msgid "Select Files" +msgstr "选择文件" + +#: f.navi.cc:1413 zfuncs.cc:6296 zfuncs.cc:6332 zfuncs.cc:6485 zfuncs.cc:6728 +#: zfuncs.cc:7427 zfuncs.cc:7433 zfuncs.cc:7439 zfuncs.cc:7445 +msgid "cancel" +msgstr "取消" + +#: f.navi.cc:1413 zfuncs.cc:6728 +msgid "done" +msgstr "完成" + +#: f.navi.cc:1422 +msgid "insert" +msgstr "插入" + +#: f.navi.cc:1423 +msgid "add all" +msgstr "添加全部" + +#: f.retouch.cc:55 +msgid "Adjust Brightness and Color" +msgstr "调节亮度和色彩" + +#: f.retouch.cc:110 +msgid "small-steps" +msgstr "" + +#: f.retouch.cc:119 +msgid "color saturation" +msgstr "色彩饱和度" + +#: f.retouch.cc:126 +msgid " reset 1 " +msgstr " 重置 1" + +#: f.retouch.cc:127 +msgid "reset all" +msgstr "全部重置" + +#: f.retouch.cc:599 +msgid "adjust image gamma" +msgstr "" + +#: f.retouch.cc:885 +msgid "Expand Brightness Range" +msgstr "扩展亮度范围" + +#: f.retouch.cc:887 +msgid "bright pixels" +msgstr "亮度像素" + +#: f.retouch.cc:1058 +msgid "Flatten Brightness Distribution" +msgstr "使亮度平均分布" + +#: f.retouch.cc:1072 +msgid "Flatten" +msgstr "白平衡" + +#: f.retouch.cc:1334 +msgid "Ramp brightness across image" +msgstr "全图光谱亮度" + +#: f.retouch.cc:1730 fotoxx-12.01.cc:272 +msgid "Tone Mapping" +msgstr "色调映射" + +#: f.retouch.cc:1758 +msgid "low" +msgstr "" + +#: f.retouch.cc:1760 +msgid "high" +msgstr "" + +#: f.retouch.cc:1763 +msgid "Amplify" +msgstr "" + +#: f.retouch.cc:2069 +msgid "Adjust White Balance" +msgstr "自动白平衡" + +#: f.retouch.cc:2070 +msgid "Click white or gray image location" +msgstr "点击白色或灰色图像位置" + +#: f.retouch.cc:2278 +msgid "Color Match Images" +msgstr "" + +#: f.retouch.cc:2307 +msgid "mouse radius for color sample" +msgstr "" + +#: f.retouch.cc:2309 f.retouch.cc:2314 fotoxx-12.01.cc:246 fotoxx-12.01.cc:325 +#: fotoxx.h:769 +msgid "Open" +msgstr "打开" + +#: f.retouch.cc:2310 +msgid "image for source color" +msgstr "" + +#: f.retouch.cc:2312 +msgid "click on image to get source color" +msgstr "" + +#: f.retouch.cc:2315 +msgid "image to set matching color" +msgstr "" + +#: f.retouch.cc:2317 +msgid "click on image to set matching color" +msgstr "" + +#: f.retouch.cc:2372 +msgid "select source image color first" +msgstr "" + +#: f.retouch.cc:2584 +msgid "Add standard bias" +msgstr "" + +#: f.retouch.cc:2591 +msgid "+Brightness -Density" +msgstr "" + +#: f.retouch.cc:2592 +msgid "+Red -Cyan" +msgstr "" + +#: f.retouch.cc:2593 +msgid "+Green -Magenta" +msgstr "" + +#: f.retouch.cc:2594 +msgid "+Blue -Yellow" +msgstr "" + +#: f.retouch.cc:2599 +msgid "Contrast" +msgstr "" + +#: f.retouch.cc:2600 fotoxx.h:778 +msgid "Red" +msgstr "红" + +#: f.retouch.cc:2601 fotoxx.h:758 +msgid "Green" +msgstr "绿" + +#: f.retouch.cc:2602 fotoxx.h:736 +msgid "Blue" +msgstr "蓝色" + +#: f.retouch.cc:2730 +msgid "Load DRGB parameters" +msgstr "" + +#: f.retouch.cc:2732 f.retouch.cc:2804 f.retouch.cc:6102 f.retouch.cc:6198 +msgid "File:" +msgstr "" + +#: f.retouch.cc:2751 f.retouch.cc:2824 +msgid "DRGB parameters file" +msgstr "" + +#: f.retouch.cc:2769 f.retouch.cc:6142 +msgid "file not found" +msgstr "" + +#: f.retouch.cc:2802 +msgid "Save DRGB parameters" +msgstr "" + +#: f.retouch.cc:3034 f.tools.cc:2404 +msgid "Click image to select pixels." +msgstr "" + +#: f.retouch.cc:3072 fotoxx-12.01.cc:276 +msgid "Revise RGB" +msgstr "" + +#: f.retouch.cc:3084 +msgid "Metric:" +msgstr "" + +#: f.retouch.cc:3139 +msgid "Blend" +msgstr "" + +#: f.retouch.cc:3519 +msgid "" +"Method 1:\n" +" Left-click on red-eye to darken.\n" +"Method 2:\n" +" Drag down and right to enclose red-eye.\n" +" Left-click on red-eye to darken.\n" +"Undo red-eye:\n" +" Right-click on red-eye." +msgstr "" +"方法一:\n" +" 鼠标左键点击红眼使其变暗。\n" +"方法二:\n" +" 拖动包围红眼。\n" +" 鼠标左键点击红眼使其变暗。\n" +"取消:\n" +" 鼠标右键点击。" + +#: f.retouch.cc:3534 +msgid "Red Eye Reduction" +msgstr "红眼减弱" + +#: f.retouch.cc:3968 +msgid "Set Blur Radius" +msgstr "设置模糊半径" + +#: f.retouch.cc:4195 fotoxx-12.01.cc:279 +msgid "Sharpen Image" +msgstr "锐化图片" + +#: f.retouch.cc:4202 +msgid "edge detection" +msgstr "边缘探测" + +#: f.retouch.cc:4203 +msgid "cycles" +msgstr "周期" + +#: f.retouch.cc:4204 +msgid "reduce" +msgstr "减小" + +#: f.retouch.cc:4215 +msgid "unsharp mask" +msgstr "模糊" + +#: f.retouch.cc:4228 +msgid "brightness gradient" +msgstr "亮度渐变" + +#: f.retouch.cc:4634 +msgid "" +" Press the reduce button to \n" +" reduce noise in small steps. \n" +" Use undo to start over." +msgstr "" +" 按下“减少”按钮 \n" +" 来减少噪点。 \n" +" 按下“重置”重新开始" + +#: f.retouch.cc:4645 +msgid "Noise Reduction" +msgstr "降噪" + +#: f.retouch.cc:4650 +msgid "algorithm" +msgstr "算法" + +#: f.retouch.cc:4657 +msgid "flatten outliers by color (1)" +msgstr "依据色彩(1) 平滑外部" + +#: f.retouch.cc:4658 +msgid "flatten outliers by color (2)" +msgstr "依据色彩(2) 平滑外部" + +#: f.retouch.cc:4659 +msgid "set median brightness by color" +msgstr "通过色彩设置居中亮度" + +#: f.retouch.cc:4660 f.retouch.cc:4661 +msgid "top hat filter by color" +msgstr "根基色彩进行 Top Hat 滤波" + +#: f.retouch.cc:4976 +msgid "" +"1. Drag mouse to select. \n" +"2. Erase. 3. Repeat. " +msgstr "" + +#: f.retouch.cc:4998 fotoxx-12.01.cc:281 +msgid "Smart Erase" +msgstr "" + +#: f.retouch.cc:5003 fotoxx.h:776 +msgid "Radius" +msgstr "半径" + +#: f.retouch.cc:5005 +msgid "Blur" +msgstr "" + +#: f.retouch.cc:5008 +msgid "New Area" +msgstr "" + +#: f.retouch.cc:5379 fotoxx-12.01.cc:282 +msgid "Remove Dust" +msgstr "" + +#: f.retouch.cc:5383 +msgid "spot size limit" +msgstr "" + +#: f.retouch.cc:5386 +msgid "max. brightness" +msgstr "" + +#: f.retouch.cc:5389 +msgid "min. contrast" +msgstr "" + +#: f.retouch.cc:5983 fotoxx-12.01.cc:283 +msgid "Fix Stuck Pixels" +msgstr "" + +#: f.retouch.cc:5989 +msgid "pixel group" +msgstr "" + +#: f.retouch.cc:5990 +msgid "circle color" +msgstr "" + +#: f.retouch.cc:6100 +msgid "Load Stuck Pixels" +msgstr "" + +#: f.retouch.cc:6124 f.retouch.cc:6220 +msgid "Stuck Pixels file" +msgstr "" + +#: f.retouch.cc:6164 +msgid "file format error" +msgstr "" + +#: f.retouch.cc:6192 +msgid "there are zero stuck pixels" +msgstr "" + +#: f.retouch.cc:6196 +msgid "Save Stuck Pixels" +msgstr "" + +#: f.retouch.cc:6686 +#, c-format +msgid "Undo Memory %d%c" +msgstr "取消记忆 %d%c" + +#: f.retouch.cc:6688 fotoxx-12.01.cc:284 +msgid "Edit Pixels" +msgstr "绘画" + +#: f.retouch.cc:6695 +msgid "pick" +msgstr "抓取" + +#: f.retouch.cc:6697 +msgid "erase" +msgstr "擦除" + +#: f.retouch.cc:6705 +msgid "paintbrush radius" +msgstr "刷子半径" + +#: f.retouch.cc:6706 +msgid "transparency center" +msgstr "透明中心" + +#: f.retouch.cc:6707 +msgid "transparency edge" +msgstr "透明边缘" + +#: f.retouch.cc:6972 +msgid "" +"Undo memory limit has been reached. \n" +"Save work with [done], then resume editing." +msgstr "" +"“取消”的内存限制(100MB)已经用尽。\n" +"按下[完成]保存,然后继续编辑。" + +#: f.select.cc:54 f.select.cc:2461 +msgid "Select Area for Edits" +msgstr "选择编辑区域" + +#: f.select.cc:55 f.select.cc:2462 +msgid "Press F1 for help" +msgstr "" + +#: f.select.cc:64 +msgid "" +"Select Area not supported \n" +"by this edit function" +msgstr "" + +#: f.select.cc:103 f.tools.cc:901 +msgid "rectangle" +msgstr "" + +#: f.select.cc:104 f.tools.cc:902 +msgid "ellipse" +msgstr "" + +#: f.select.cc:110 +msgid "draw: freehand" +msgstr "绘制:绘画" + +#: f.select.cc:111 +msgid "draw: follow edge" +msgstr "绘制:紧随边缘" + +#: f.select.cc:114 +msgid "select by mouse" +msgstr "" + +#: f.select.cc:116 f.select.cc:2496 +msgid "mouse radius" +msgstr "" + +#: f.select.cc:120 +msgid "match mouse color" +msgstr "" + +#: f.select.cc:124 +msgid "search range" +msgstr "" + +#: f.select.cc:126 +msgid "firewall" +msgstr "" + +#: f.select.cc:326 f.select.cc:467 +#, c-format +msgid "exceed %d edits" +msgstr "超出 %d 编辑" + +#: f.select.cc:1021 +msgid "" +"Click one time inside each enclosed area \n" +"(possible gaps in the outline will be found). \n" +"Press F1 for help." +msgstr "" + +#: f.select.cc:1078 +msgid "finish area" +msgstr "结束区域" + +#: f.select.cc:1113 +msgid "searching" +msgstr "搜索中" + +#: f.select.cc:1185 +msgid "outline has a gap" +msgstr "" + +#: f.select.cc:1189 +msgid "success" +msgstr "成功" + +#: f.select.cc:1440 f.select.cc:1470 +msgid "the area is not finished" +msgstr "此区域未完成" + +#: f.select.cc:1563 +msgid "Edge calculation in progress" +msgstr "正在进行边缘计算" + +#: f.select.cc:1572 +msgid "Area Edge Calc" +msgstr "区域边缘计算" + +#: f.select.cc:1863 +msgid "position with mouse click/drag" +msgstr "" + +#: f.select.cc:1887 +msgid "Paste Image" +msgstr "粘贴图像" + +#: f.select.cc:1901 +msgid "angle" +msgstr "" + +#: f.select.cc:2160 +msgid "load select area from a file" +msgstr "读取一个文件的选定区域" + +#: f.select.cc:2194 +msgid "cannot open .tiff and .info files" +msgstr "" + +#: f.select.cc:2213 +msgid "save select area to a file" +msgstr "" + +#: f.select.cc:2248 fotoxx-12.01.cc:248 +msgid "Select Whole Image" +msgstr "" + +#: f.select.cc:2249 +msgid "Edit Function Amplifier" +msgstr "" + +#: f.select.cc:2463 +msgid "Edit function must be active" +msgstr "" + +#: f.select.cc:2499 +msgid "power: center" +msgstr "" + +#: f.select.cc:2501 +msgid "edge" +msgstr "" + +#: f.select.cc:2504 +msgid "reset area" +msgstr "" + +#: f.tools.cc:42 +msgid "" +"When editing a collection, right-click \n" +"an image or thumbnail to add or remove." +msgstr "" + +#: f.tools.cc:70 fotoxx-12.01.cc:204 +msgid "Manage Collections" +msgstr "" + +#: f.tools.cc:85 +msgid "Start new collection" +msgstr "" + +#: f.tools.cc:87 +msgid "Edit a collection" +msgstr "" + +#: f.tools.cc:89 +msgid "View a collection" +msgstr "" + +#: f.tools.cc:91 +msgid "Delete a collection" +msgstr "" + +#: f.tools.cc:95 +msgid "Editing:" +msgstr "" + +#: f.tools.cc:99 +msgid "Action:" +msgstr "" + +#: f.tools.cc:133 +msgid "New Collection" +msgstr "" + +#: f.tools.cc:156 +msgid "Edit Collection" +msgstr "" + +#: f.tools.cc:172 +msgid "View Collection" +msgstr "" + +#: f.tools.cc:193 +msgid "Delete Collection" +msgstr "" + +#: f.tools.cc:196 +#, c-format +msgid "delete %s ?" +msgstr "" + +#: f.tools.cc:223 +#, c-format +msgid "add image to collection: %s" +msgstr "" + +#: f.tools.cc:225 f.tools.cc:270 +msgid "remove image from collection" +msgstr "" + +#: f.tools.cc:226 f.tools.cc:271 f.tools.cc:298 +msgid "remove and save image" +msgstr "" + +#: f.tools.cc:227 f.tools.cc:316 +msgid "insert saved images here" +msgstr "" + +#: f.tools.cc:256 +msgid "add image to collection" +msgstr "" + +#: f.tools.cc:301 +msgid "too many saved files" +msgstr "" + +#: f.tools.cc:373 fotoxx-12.01.cc:205 +msgid "Move Collections" +msgstr "" + +#: f.tools.cc:375 +msgid "old top directory" +msgstr "" + +#: f.tools.cc:378 +msgid "new top directory" +msgstr "" + +#: f.tools.cc:434 +msgid "completed" +msgstr "已完成" + +#: f.tools.cc:467 +msgid "Batch Convert/Resize/Export" +msgstr "" + +#: f.tools.cc:474 +msgid "new max. width" +msgstr "新最大宽度" + +#: f.tools.cc:481 +msgid "new file type" +msgstr "" + +#: f.tools.cc:482 +msgid "same" +msgstr "" + +#: f.tools.cc:490 +msgid "replace originals" +msgstr "取代原有的" + +#: f.tools.cc:491 +msgid "export to location" +msgstr "导出到" + +#: f.tools.cc:492 +msgid "remove EXIF" +msgstr "" + +#: f.tools.cc:549 +msgid "Select directory" +msgstr "选择路径" + +#: f.tools.cc:583 +#, c-format +msgid "replace original files? (max. %d x %d)" +msgstr "取代原有文件? (max. %d x %d)" + +#: f.tools.cc:590 +#, c-format +msgid "" +"copy files? (max. %d x %d) \n" +" to location %s" +msgstr "" +"复制文件?(最多 %d x %d) \n" +" 到 %s" + +#: f.tools.cc:601 +msgid "location is not a valid directory" +msgstr "不可识别的位置" + +#: f.tools.cc:608 f.tools.cc:3007 +#, c-format +msgid "max. size %d x %d is not reasonable" +msgstr "最大尺寸 %d x %d 不可能" + +#: f.tools.cc:654 +msgid "*** file already exists" +msgstr "" + +#: f.tools.cc:662 +msgid "*** file type not supported" +msgstr "" + +#: f.tools.cc:741 +msgid "Program ufraw-batch is required" +msgstr "需要程序 ufraw-batch" + +#: f.tools.cc:751 fotoxx.h:770 +msgid "Open RAW File" +msgstr "打开原始文件(RAW文件)" + +#: f.tools.cc:764 +msgid "Select RAW files to convert" +msgstr "选择要转化的RAW文件" + +#: f.tools.cc:769 +msgid "Choose file type" +msgstr "" + +#: f.tools.cc:888 +msgid "Press ESC to exit slide show" +msgstr "" + +#: f.tools.cc:889 +msgid "show only latest file versions" +msgstr "" + +#: f.tools.cc:893 +msgid "arrow keys" +msgstr "" + +#: f.tools.cc:894 +msgid "instant" +msgstr "" + +#: f.tools.cc:895 +msgid "fade-in" +msgstr "" + +#: f.tools.cc:896 +msgid "roll-right" +msgstr "" + +#: f.tools.cc:897 +msgid "roll-down" +msgstr "" + +#: f.tools.cc:898 +msgid "shift-left" +msgstr "" + +#: f.tools.cc:899 +msgid "venetian" +msgstr "" + +#: f.tools.cc:900 +msgid "grate" +msgstr "" + +#: f.tools.cc:903 +msgid "radar" +msgstr "" + +#: f.tools.cc:904 +msgid "jaws" +msgstr "" + +#: f.tools.cc:911 fotoxx-12.01.cc:208 +msgid "Slide Show" +msgstr "演示" + +#: f.tools.cc:915 +msgid "seconds" +msgstr "秒" + +#: f.tools.cc:919 +msgid "music file" +msgstr "" + +#: f.tools.cc:923 +msgid "transitions" +msgstr "" + +#: f.tools.cc:1040 +msgid "Select music file or playlist" +msgstr "" + +#: f.tools.cc:1727 +msgid "Sync Files is already running" +msgstr "" + +#: f.tools.cc:1778 +msgid "" +"Run Tools > Synchronize Files so that gallery windows \n" +"will be fast and Search Images will work correctly. \n" +"You can view (not edit) images while synchronize runs." +msgstr "" + +#: f.tools.cc:1812 +msgid "no top image directory is defined" +msgstr "" + +#: f.tools.cc:1818 +msgid "top image directory is invalid" +msgstr "" + +#: f.tools.cc:1823 +msgid "no search index file is present" +msgstr "" + +#: f.tools.cc:1837 +msgid "new/modified files are present" +msgstr "" + +#: f.tools.cc:1844 +msgid "no new files found" +msgstr "" + +#: f.tools.cc:1859 fotoxx-12.01.cc:209 +msgid "Synchronize Files" +msgstr "" + +#: f.tools.cc:1861 +msgid "Top Image Directory:" +msgstr "顶部图像路径:" + +#: f.tools.cc:1883 +msgid "" +"file sync is necessary.\n" +"cancel anyway?" +msgstr "" + +#: f.tools.cc:1896 +msgid "top directory is invalid" +msgstr "" + +#: f.tools.cc:2292 +msgid "Select top image directory" +msgstr "选择顶部图像位置" + +#: f.tools.cc:2429 fotoxx-12.01.cc:210 +msgid "Show RGB" +msgstr "显示RGB" + +#: f.tools.cc:2719 fotoxx-12.01.cc:211 +msgid "Grid Lines" +msgstr "网格线" + +#: f.tools.cc:2728 +msgid "x-spacing" +msgstr "" + +#: f.tools.cc:2729 +msgid "x-count" +msgstr "" + +#: f.tools.cc:2730 +msgid "x-enable" +msgstr "" + +#: f.tools.cc:2736 +msgid "y-spacing" +msgstr "" + +#: f.tools.cc:2737 +msgid "y-count" +msgstr "" + +#: f.tools.cc:2738 +msgid "y-enable" +msgstr "" + +#: f.tools.cc:2745 +msgid "x-offset" +msgstr "" + +#: f.tools.cc:2749 +msgid "y-offset" +msgstr "" + +#: f.tools.cc:2940 fotoxx-12.01.cc:213 +msgid "E-mail Images" +msgstr "" + +#: f.tools.cc:2947 +msgid "max. width" +msgstr "" + +#: f.tools.cc:2948 +msgid "max. height" +msgstr "" + +#: f.tools.cc:3093 +msgid "too many files" +msgstr "" + +#: f.tools.cc:3134 +msgid "" +"Brightness should show a gradual ramp \n" +"extending all the way to the edges." +msgstr "" + +#: f.tools.cc:3174 +msgid "Monitor Check" +msgstr "" + +#: f.tools.cc:3232 fotoxx-12.01.cc:215 +msgid "Monitor Gamma" +msgstr "" + +#: f.tools.cc:3294 fotoxx-12.01.cc:216 +msgid "Brightness Distribution" +msgstr "亮度分布" + +#: f.tools.cc:3432 +msgid "Available Translations" +msgstr "可用翻译" + +#: f.tools.cc:3436 +msgid "Set Language" +msgstr "设置语言" + +#: f.tools.cc:3502 +msgid "Make Launcher" +msgstr "" + +#: f.tools.cc:3540 +msgid "Settings" +msgstr "" + +#: f.tools.cc:3545 +msgid "Startup Display" +msgstr "" + +#: f.tools.cc:3547 +msgid "Recent Files Gallery" +msgstr "" + +#: f.tools.cc:3548 +msgid "Previous Image Viewed" +msgstr "" + +#: f.tools.cc:3549 +msgid "Blank Window" +msgstr "" + +#: f.tools.cc:3551 +msgid "Directory Gallery" +msgstr "" + +#: f.tools.cc:3556 +msgid "Image File" +msgstr "" + +#: f.tools.cc:3562 +msgid "Toolbar Style" +msgstr "" + +#: f.tools.cc:3563 f.transform.cc:1300 +msgid "Text" +msgstr "" + +#: f.tools.cc:3564 +msgid "Icons" +msgstr "" + +#: f.tools.cc:3565 +msgid "Both" +msgstr "" + +#: f.tools.cc:3568 +msgid "Warn Overwrite" +msgstr "" + +#: f.tools.cc:3639 +msgid "startup directory is invalid" +msgstr "" + +#: f.tools.cc:3650 +msgid "startup file is invalid" +msgstr "" + +#: f.tools.cc:3707 +msgid "Select startup directory" +msgstr "" + +#: f.tools.cc:3715 +msgid "Select startup image file" +msgstr "" + +#: f.transform.cc:50 +msgid "Use buttons or drag right edge with mouse" +msgstr "使用按钮或者鼠标拖到右面边缘" + +#: f.transform.cc:60 fotoxx-12.01.cc:252 +msgid "Rotate Image" +msgstr "旋转图像" + +#: f.transform.cc:64 +msgid "degrees" +msgstr "角度" + +#: f.transform.cc:80 f.transform.cc:124 +msgid "Trim" +msgstr "剪裁" + +#: f.transform.cc:81 f.transform.cc:2289 f.transform.cc:3120 +#: f.transform.cc:3383 f.transform.cc:3644 +msgid "Grid" +msgstr "" + +#: f.transform.cc:123 +msgid "Undo Trim" +msgstr "取消剪切" + +#: f.transform.cc:139 +#, c-format +msgid "degrees: %.1f" +msgstr "角度: %.1f" + +#: f.transform.cc:286 +msgid "gold" +msgstr "" + +#: f.transform.cc:334 +msgid "Drag middle to move, drag corners to resize." +msgstr "拖动中部移动,拖动角落改变尺寸。" + +#: f.transform.cc:348 fotoxx-12.01.cc:253 +msgid "Trim Image" +msgstr "剪裁图像" + +#: f.transform.cc:348 +msgid "customize" +msgstr "" + +#: f.transform.cc:359 +msgid "ratio" +msgstr "" + +#: f.transform.cc:363 +msgid "Lock Ratio" +msgstr "固定比例" + +#: f.transform.cc:368 +msgid "invert" +msgstr "反色" + +#: f.transform.cc:890 +msgid "Trim Buttons" +msgstr "" + +#: f.transform.cc:1064 +msgid "Lock aspect ratio" +msgstr "锁定长宽比例" + +#: f.transform.cc:1072 fotoxx-12.01.cc:255 +msgid "Resize Image" +msgstr "改变尺寸" + +#: f.transform.cc:1095 fotoxx-12.01.cc:326 +msgid "Prev" +msgstr "上一张" + +#: f.transform.cc:1245 +msgid "" +"Enter text, click/drag on image.\n" +"Right click to remove" +msgstr "" + +#: f.transform.cc:1294 fotoxx-12.01.cc:256 +msgid "Annotate Image" +msgstr "" + +#: f.transform.cc:1307 +msgid "Size" +msgstr "尺寸" + +#: f.transform.cc:1310 +msgid "Angle" +msgstr "" + +#: f.transform.cc:1321 fotoxx.h:741 +msgid "Color" +msgstr "颜色" + +#: f.transform.cc:1322 +msgid "Transparency" +msgstr "" + +#: f.transform.cc:1325 +msgid "text" +msgstr "" + +#: f.transform.cc:1330 +msgid "backing" +msgstr "" + +#: f.transform.cc:1333 +msgid "" +"Outline\n" +" Width" +msgstr "" + +#: f.transform.cc:1335 +msgid "outline" +msgstr "" + +#: f.transform.cc:1342 +msgid "Annotation File:" +msgstr "" + +#: f.transform.cc:1416 +msgid "select font" +msgstr "" + +#: f.transform.cc:2045 fotoxx-12.01.cc:257 +msgid "Flip Image" +msgstr "翻转图像" + +#: f.transform.cc:2049 f.transform.cc:2281 +msgid "horizontal" +msgstr "水平" + +#: f.transform.cc:2050 f.transform.cc:2280 +msgid "vertical" +msgstr "垂直" + +#: f.transform.cc:2155 fotoxx-12.01.cc:258 +msgid "Make Negative" +msgstr "反色" + +#: f.transform.cc:2158 +msgid "black/white positive" +msgstr "" + +#: f.transform.cc:2159 +msgid "black/white negative" +msgstr "" + +#: f.transform.cc:2160 +msgid "color positive" +msgstr "" + +#: f.transform.cc:2161 +msgid "color negative" +msgstr "" + +#: f.transform.cc:2272 fotoxx-12.01.cc:259 +msgid "Unbend Image" +msgstr "拉伸图像" + +#: f.transform.cc:2282 +msgid "linear" +msgstr "" + +#: f.transform.cc:2285 +msgid "curved" +msgstr "" + +#: f.transform.cc:2544 +msgid "" +" Click the four corners of a tetragon area. Press [apply]. \n" +" The image is warped to make the tetragon into a rectangle." +msgstr "" + +#: f.transform.cc:2556 fotoxx-12.01.cc:260 +msgid "Keystone Correction" +msgstr "" + +#: f.transform.cc:2724 +msgid "must have 4 corners" +msgstr "" + +#: f.transform.cc:2847 +msgid "" +" Select an area to warp using select area function. \n" +" Press [start warp] and pull area with mouse. \n" +" Make multiple mouse pulls until satisfied. \n" +" When finished, select another area or press [done]." +msgstr "" +" 鼠标左键在图像一边按下扭曲图像 \n" +" 知道满意 \n" +" 要结束,按下[完成]" + +#: f.transform.cc:2859 fotoxx-12.01.cc:261 +msgid "Warp Image (area)" +msgstr "" + +#: f.transform.cc:2864 +msgid "start warp" +msgstr "开始扭曲" + +#: f.transform.cc:2931 +msgid "no active Select Area" +msgstr "" + +#: f.transform.cc:3099 f.transform.cc:3362 +msgid "" +" Pull an image position using the mouse. \n" +" Make multiple mouse pulls until satisfied. \n" +" When finished, press [done]." +msgstr "" + +#: f.transform.cc:3112 fotoxx-12.01.cc:262 +msgid "Warp Image (curved)" +msgstr "" + +#: f.transform.cc:3375 fotoxx-12.01.cc:263 +msgid "Warp Image (linear)" +msgstr "" + +#: f.transform.cc:3628 +msgid "" +" Pull on an image corner using the mouse. \n" +" Make multiple mouse pulls until satisfied. \n" +" When finished, press [done]." +msgstr "" +" 鼠标左键在图像一边按下扭曲图像 \n" +" 知道满意 \n" +" 要结束,按下[完成]" + +#: f.transform.cc:3639 fotoxx-12.01.cc:264 +msgid "Warp Image (affine)" +msgstr "扭曲图像(affine)" + +#: fotoxx-12.01.cc:185 +msgid "File" +msgstr "文件" + +#: fotoxx-12.01.cc:186 fotoxx-12.01.cc:324 +msgid "Image Gallery" +msgstr "图像浏览" + +#: fotoxx-12.01.cc:187 +msgid "Clone 50/50" +msgstr "" + +#: fotoxx-12.01.cc:188 +msgid "Clone Overlay" +msgstr "" + +#: fotoxx-12.01.cc:190 +msgid "Open in New Window" +msgstr "" + +#: fotoxx-12.01.cc:191 fotoxx-12.01.cc:326 +msgid "Open Previous File" +msgstr "打开前一个文件" + +#: fotoxx-12.01.cc:192 +msgid "Open Recent File" +msgstr "打开最近的文件" + +#: fotoxx-12.01.cc:193 fotoxx-12.01.cc:334 +msgid "Save to Same File" +msgstr "保存到原文件" + +#: fotoxx-12.01.cc:194 fotoxx-12.01.cc:335 +msgid "Save to New Version" +msgstr "" + +#: fotoxx-12.01.cc:195 fotoxx-12.01.cc:336 +msgid "Save to New File" +msgstr "保存到新文件" + +#: fotoxx-12.01.cc:197 +msgid "Trash Image File" +msgstr "丢入可回收文件夹" + +#: fotoxx-12.01.cc:199 +msgid "Batch Rename Files" +msgstr "批量重命名文件" + +#: fotoxx-12.01.cc:200 +msgid "Print Image File" +msgstr "打印图像文件" + +#: fotoxx-12.01.cc:201 fotoxx-12.01.cc:340 +msgid "Quit fotoxx" +msgstr "退出 fotoxx" + +#: fotoxx-12.01.cc:203 +msgid "Tools" +msgstr "工具" + +#: fotoxx-12.01.cc:206 +msgid "Batch Convert" +msgstr "" + +#: fotoxx-12.01.cc:207 +msgid "Convert RAW files" +msgstr "转化RAW文件" + +#: fotoxx-12.01.cc:212 +msgid "Burn Images to CD/DVD" +msgstr "刻录图片到CD/DVD" + +#: fotoxx-12.01.cc:214 +msgid "Check Monitor" +msgstr "检查显示器" + +#: fotoxx-12.01.cc:217 +msgid "Change Language" +msgstr "改变语言" + +#: fotoxx-12.01.cc:219 +msgid "Menu and Launcher" +msgstr "" + +#: fotoxx-12.01.cc:220 +msgid "User Settings" +msgstr "" + +#: fotoxx-12.01.cc:221 +msgid "Memory Usage" +msgstr "" + +#: fotoxx-12.01.cc:224 +msgid "Edit Caption/Comments" +msgstr "" + +#: fotoxx-12.01.cc:229 +msgid "View Info (short)" +msgstr "" + +#: fotoxx-12.01.cc:230 +msgid "View Info (long)" +msgstr "" + +#: fotoxx-12.01.cc:233 +msgid "Search Images" +msgstr "" + +#: fotoxx-12.01.cc:234 +msgid "Search Metadata" +msgstr "" + +#: fotoxx-12.01.cc:236 fotoxx-12.01.cc:237 fotoxx.h:786 +msgid "Select" +msgstr "选择" + +#: fotoxx-12.01.cc:238 fotoxx.h:788 +msgid "Show" +msgstr "显示" + +#: fotoxx-12.01.cc:239 fotoxx.h:761 +msgid "Hide" +msgstr "隐藏" + +#: fotoxx-12.01.cc:240 fotoxx.h:752 +msgid "Enable" +msgstr "开启" + +#: fotoxx-12.01.cc:241 fotoxx.h:748 +msgid "Disable" +msgstr "禁止" + +#: fotoxx-12.01.cc:242 fotoxx.h:763 +msgid "Invert" +msgstr "反色" + +#: fotoxx-12.01.cc:243 fotoxx.h:796 +msgid "Unselect" +msgstr "" + +#: fotoxx-12.01.cc:244 fotoxx.h:743 +msgid "Copy" +msgstr "复制" + +#: fotoxx-12.01.cc:245 fotoxx.h:771 +msgid "Paste" +msgstr "粘贴" + +#: fotoxx-12.01.cc:247 fotoxx-12.01.cc:334 fotoxx.h:783 +msgid "Save" +msgstr "保存" + +#: fotoxx-12.01.cc:249 +msgid "Select and Edit" +msgstr "" + +#: fotoxx-12.01.cc:251 +msgid "Transform" +msgstr "变形" + +#: fotoxx-12.01.cc:254 +msgid "Auto-Trim Image" +msgstr "" + +#: fotoxx-12.01.cc:266 +msgid "Retouch" +msgstr "修正" + +#: fotoxx-12.01.cc:267 +msgid "Brightness/Color" +msgstr "调节亮度和色彩" + +#: fotoxx-12.01.cc:268 +msgid "Gamma Curves" +msgstr "" + +#: fotoxx-12.01.cc:269 +msgid "Expand Brightness" +msgstr "扩展亮度" + +#: fotoxx-12.01.cc:270 +msgid "Flatten Brightness" +msgstr "白平衡" + +#: fotoxx-12.01.cc:271 +msgid "Brightness Ramp" +msgstr "亮度光谱" + +#: fotoxx-12.01.cc:273 +msgid "White Balance" +msgstr "白平衡" + +#: fotoxx-12.01.cc:274 +msgid "Match Colors" +msgstr "" + +#: fotoxx-12.01.cc:277 +msgid "Red Eyes" +msgstr "红眼" + +#: fotoxx-12.01.cc:278 +msgid "Blur Image" +msgstr "模糊图像" + +#: fotoxx-12.01.cc:280 +msgid "Reduce Noise" +msgstr "减少噪点" + +#: fotoxx-12.01.cc:286 +msgid "Art" +msgstr "艺术" + +#: fotoxx-12.01.cc:287 +msgid "Color Depth" +msgstr "色深" + +#: fotoxx-12.01.cc:288 +msgid "Drawing" +msgstr "" + +#: fotoxx-12.01.cc:289 +msgid "Outlines" +msgstr "" + +#: fotoxx-12.01.cc:290 +msgid "Embossing" +msgstr "" + +#: fotoxx-12.01.cc:291 +msgid "Tiles" +msgstr "" + +#: fotoxx-12.01.cc:292 +msgid "Dots" +msgstr "" + +#: fotoxx-12.01.cc:293 +msgid "Painting" +msgstr "" + +#: fotoxx-12.01.cc:295 +msgid "Combine" +msgstr "接合" + +#: fotoxx-12.01.cc:296 +msgid "High Dynamic Range" +msgstr "" + +#: fotoxx-12.01.cc:297 +msgid "High Depth of Field" +msgstr "" + +#: fotoxx-12.01.cc:298 +msgid "Stack / Paint" +msgstr "" + +#: fotoxx-12.01.cc:299 +msgid "Stack / Noise" +msgstr "" + +#: fotoxx-12.01.cc:300 +msgid "Panorama" +msgstr "全景" + +#: fotoxx-12.01.cc:301 +msgid "Vertical Panorama" +msgstr "" + +#: fotoxx-12.01.cc:304 +msgid "Edit Plugins" +msgstr "" + +#: fotoxx-12.01.cc:313 fotoxx-12.01.cc:341 fotoxx-12.01.cc:3026 +msgid "Help" +msgstr "帮助" + +#: fotoxx-12.01.cc:314 fotoxx-12.01.cc:3016 +msgid "About" +msgstr "关于" + +#: fotoxx-12.01.cc:315 fotoxx-12.01.cc:3020 +msgid "User Guide" +msgstr "用户指南" + +#: fotoxx-12.01.cc:316 fotoxx-12.01.cc:3023 +msgid "User Guide Changes" +msgstr "" + +#: fotoxx-12.01.cc:317 fotoxx-12.01.cc:3032 +msgid "Edit Functions Summary" +msgstr "" + +#: fotoxx-12.01.cc:318 fotoxx-12.01.cc:3035 +msgid "Change Log" +msgstr "变动" + +#: fotoxx-12.01.cc:319 fotoxx-12.01.cc:3038 +msgid "Translations" +msgstr "" + +#: fotoxx-12.01.cc:320 fotoxx-12.01.cc:3041 +msgid "Home Page" +msgstr "主页" + +#: fotoxx-12.01.cc:324 +msgid "Gallery" +msgstr "浏览" + +#: fotoxx-12.01.cc:327 fotoxx.h:767 +msgid "Next" +msgstr "下一张" + +#: fotoxx-12.01.cc:327 +msgid "Open Next File" +msgstr "打开下一个文件" + +#: fotoxx-12.01.cc:328 +msgid "Zoom-in (bigger)" +msgstr "拉近 (更大)" + +#: fotoxx-12.01.cc:329 +msgid "Zoom-out (smaller)" +msgstr "拉远 (更小)" + +#: fotoxx-12.01.cc:330 fotoxx.h:794 +msgid "Undo" +msgstr "取消" + +#: fotoxx-12.01.cc:330 +msgid "Undo One Edit" +msgstr "取消一次编辑" + +#: fotoxx-12.01.cc:331 fotoxx.h:779 +msgid "Redo" +msgstr "重复" + +#: fotoxx-12.01.cc:331 +msgid "Redo One Edit" +msgstr "重复一次编辑" + +#: fotoxx-12.01.cc:335 +msgid "Save+V" +msgstr "" + +#: fotoxx-12.01.cc:336 +msgid "Save+F" +msgstr "" + +#: fotoxx-12.01.cc:337 +msgid "Move Image to Trash" +msgstr "移动图片到可回收文件夹" + +#: fotoxx-12.01.cc:337 +msgid "Trash" +msgstr "可回收文件夹" + +#: fotoxx-12.01.cc:340 +msgid "Quit" +msgstr "退出" + +#: fotoxx-12.01.cc:341 +msgid "Fotoxx Essentials" +msgstr "Fotoxx基础" + +#: fotoxx-12.01.cc:448 +msgid "first time startup" +msgstr "" + +#: fotoxx-12.01.cc:1944 +msgid "Exceed 50 anchor points" +msgstr "超出了 50 个锚点" + +#: fotoxx-12.01.cc:2129 +msgid "load curve from a file" +msgstr "" + +#: fotoxx-12.01.cc:2182 +msgid "curve file is invalid" +msgstr "" + +#: fotoxx-12.01.cc:2187 +msgid "curve file has different no. of curves" +msgstr "" + +#: fotoxx-12.01.cc:2202 +msgid "save curve to a file" +msgstr "" + +#: fotoxx-12.01.cc:2337 +msgid "cannot parallel edit" +msgstr "" + +#: fotoxx-12.01.cc:2347 +msgid "" +"exiftool is not installed \n" +"edited images will lose EXIF data" +msgstr "" +"exiftool未安装 \n" +"修改图片会丢失EXIF数据" + +#: fotoxx-12.01.cc:2353 +msgid "Too many edits, please save image" +msgstr "编辑太多了,请保存图片" + +#: fotoxx-12.01.cc:2358 +msgid "" +"Select area cannot be kept.\n" +"Continue?" +msgstr "" +"选择区域无法保留。\n" +"继续吗?" + +#: fotoxx-12.01.cc:2366 +msgid "" +"Select area not active.\n" +"Continue?" +msgstr "" +"选择非活动区域。\n" +"继续?" + +#: fotoxx-12.01.cc:2837 +msgid "Discard edits?" +msgstr "" + +#: fotoxx-12.01.cc:2838 +msgid "" +"This action will discard current edits.\n" +"Continue to discard edits.\n" +"Go Back to keep edits." +msgstr "" + +#: fotoxx-12.01.cc:2841 +msgid "Continue" +msgstr "" + +#: fotoxx-12.01.cc:2842 +msgid "Go Back" +msgstr "" + +#: fotoxx-12.01.cc:3659 +msgid "cannot open thumbnail file" +msgstr "无法打开缩略图" + +#: fotoxx-12.01.cc:3870 fotoxx-12.01.cc:3992 +msgid "TIFF open failure" +msgstr "TIFF开启失败" + +#: fotoxx-12.01.cc:3886 +#, c-format +msgid "TIFF bits/color=%d not supported" +msgstr "TIFF 色深(bits/color)=%d 不支持" + +#: fotoxx-12.01.cc:3901 fotoxx-12.01.cc:3939 +msgid "TIFF read failure" +msgstr "TIFF读取失败" + +#: fotoxx-12.01.cc:4051 +msgid "TIFF write failure" +msgstr "TIFF写错误" + +#: fotoxx-12.01.cc:4071 +msgid "file type not supported" +msgstr "文件类型不支持" + +#: fotoxx-12.01.cc:4178 +msgid "pixbuf write failure" +msgstr "pixbuf 写入错误" + +#: fotoxx.h:728 +msgid "absolute" +msgstr "" + +#: fotoxx.h:730 +msgid "Add All" +msgstr "添加全部" + +#: fotoxx.h:732 +msgid "Amount" +msgstr "总数" + +#: fotoxx.h:733 +msgid "Apply" +msgstr "应用" + +#: fotoxx.h:734 +msgid "Black" +msgstr "" + +#: fotoxx.h:735 +msgid "Blend Width" +msgstr "混合宽度" + +#: fotoxx.h:737 +msgid "Brightness" +msgstr "亮度" + +#: fotoxx.h:738 +msgid "Browse" +msgstr "浏览" + +#: fotoxx.h:739 +msgid "Cancel" +msgstr "取消" + +#: fotoxx.h:740 +msgid "Clear" +msgstr "清除" + +#: fotoxx.h:742 +msgid "Commit" +msgstr "" + +#: fotoxx.h:744 +msgid "Curve File:" +msgstr "" + +#: fotoxx.h:745 +msgid "Cut" +msgstr "" + +#: fotoxx.h:746 +msgid "Darker Areas" +msgstr "较暗区域" + +#: fotoxx.h:747 +msgid "Delete" +msgstr "删除" + +#: fotoxx.h:749 +#, c-format +msgid "" +"Discard special gallery list? \n" +" %s" +msgstr "" + +#: fotoxx.h:750 +msgid "Done" +msgstr "完成" + +#: fotoxx.h:751 +msgid "Edit" +msgstr "修改" + +#: fotoxx.h:753 +msgid "Erase" +msgstr "" + +#: fotoxx.h:754 +msgid "package libimage-exiftool-perl is required" +msgstr "需要软件包 libimage-exiftool-perl " + +#: fotoxx.h:755 +msgid "Fetch" +msgstr "获取" + +#: fotoxx.h:756 +msgid "Finish" +msgstr "完成" + +#: fotoxx.h:757 +msgid "Font" +msgstr "" + +#: fotoxx.h:759 +msgid "Height" +msgstr "高度" + +#: fotoxx.h:760 +msgid "histogram" +msgstr "柱状图" + +#: fotoxx.h:762 +msgid "Insert" +msgstr "插入" + +#: fotoxx.h:764 +msgid "Lighter Areas" +msgstr "较亮区域" + +#: fotoxx.h:765 +msgid "limit" +msgstr "限制" + +#: fotoxx.h:766 +msgid "New" +msgstr "" + +#: fotoxx.h:768 +msgid "OK" +msgstr "确定" + +#: fotoxx.h:772 +msgid "Pause" +msgstr "暂停" + +#: fotoxx.h:773 +msgid "Percent" +msgstr "比例" + +#: fotoxx.h:774 +msgid "Presets" +msgstr "预设" + +#: fotoxx.h:775 +msgid "Proceed" +msgstr "进行" + +#: fotoxx.h:777 +msgid "range" +msgstr "范围" + +#: fotoxx.h:780 +msgid "Reduce" +msgstr "减小" + +#: fotoxx.h:782 +msgid "Reset" +msgstr "" + +#: fotoxx.h:784 +msgid "Unknown file type, save as tiff/jpeg/png to edit" +msgstr "未知文件类型,保存为 tiff/jpeg/png 编辑" + +#: fotoxx.h:785 +msgid "Search" +msgstr "搜索" + +#: fotoxx.h:789 +msgid "Start" +msgstr "开始" + +#: fotoxx.h:790 +msgid "Threshold" +msgstr "门槛" + +#: fotoxx.h:791 +#, c-format +msgid "exceed %d files" +msgstr "" + +#: fotoxx.h:792 +msgid "Undo All" +msgstr "取消全部" + +#: fotoxx.h:793 +msgid "Undo Last" +msgstr "取消上一个" + +#: fotoxx.h:795 +msgid "Unfinish" +msgstr "" + +#: fotoxx.h:797 +msgid "View" +msgstr "" + +#: fotoxx.h:798 +msgid "White" +msgstr "" + +#: fotoxx.h:799 +msgid "Width" +msgstr "宽度" + +#: zfuncs.cc:3252 +#, c-format +msgid "help file not found: %s" +msgstr "没找到帮助文件: %s" + +#: zfuncs.cc:3664 zfuncs.cc:7315 +#, c-format +msgid "cannot open file %s" +msgstr "不能打开文件 %s" + +#: zfuncs.cc:3697 +msgid "save screen to file" +msgstr "保存屏幕到文件" + +#: zfuncs.cc:6222 +msgid "No" +msgstr "无" + +#: zfuncs.cc:6222 +msgid "Yes" +msgstr "是" + +#: zfuncs.cc:6447 +msgid "open" +msgstr "打开" + +#: zfuncs.cc:6452 +msgid "choose" +msgstr "选择\t" + +#: zfuncs.cc:6457 +msgid "save" +msgstr "保存" + +#: zfuncs.cc:6463 +msgid "open folder" +msgstr "打开文件夹" + +#: zfuncs.cc:6468 +msgid "create folder" +msgstr "创造文件夹" + +#: zfuncs.cc:6474 +msgid "hidden" +msgstr "隐藏的" + +#: zfuncs.cc:6535 +msgid "JPG quality 0-100" +msgstr "JPG 质量 0-100" + +#: zfuncs.cc:6728 zfuncs.cc:6741 +msgid "margins" +msgstr "" + +#: zfuncs.cc:6737 +msgid "top" +msgstr "" + +#: zfuncs.cc:6738 +msgid "bottom" +msgstr "" + +#: zfuncs.cc:6739 +msgid "left" +msgstr "" + +#: zfuncs.cc:6740 +msgid "right" +msgstr "" + +#: zfuncs.cc:7202 +msgid "" +"Initial parameters file created. \n" +"Inspect and revise if necessary." +msgstr "" +"初始化参数文件。 \n" +"如必要,请检查。" + +#: zfuncs.cc:7218 +msgid "load parameters from a file" +msgstr "从一个文件读取参数" + +#: zfuncs.cc:7287 +msgid "save parameters to a file" +msgstr "保存参数到文件" + +#: zfuncs.cc:7425 zfuncs.cc:7431 zfuncs.cc:7437 zfuncs.cc:7443 +msgid "edit parameters" +msgstr "修改参数" + +#: zfuncs.cc:7426 zfuncs.cc:7432 +msgid "" +"list\n" +"all" +msgstr "" +"列表\n" +"全部" + +#: zfuncs.cc:7426 zfuncs.cc:7432 zfuncs.cc:7438 zfuncs.cc:7444 +msgid "" +"load\n" +"file" +msgstr "" +"读取\n" +"文件" + +#: zfuncs.cc:7426 zfuncs.cc:7432 zfuncs.cc:7438 zfuncs.cc:7444 +msgid "" +"save\n" +"file" +msgstr "" +"保存\n" +"文件" + +#: zfuncs.cc:7427 zfuncs.cc:7439 +msgid "" +"add\n" +"new" +msgstr "" +"添加\n" +"新" + +#: zfuncs.cc:7427 zfuncs.cc:7433 zfuncs.cc:7439 zfuncs.cc:7445 +msgid "apply" +msgstr "应用" + +#: zfuncs.cc:7479 +msgid "apply?" +msgstr "应用?" + +#: zfuncs.cc:7536 +msgid "(new parm name)" +msgstr "(新参数名)" + +#: zfuncs.cc:7536 +msgid "add parameter" +msgstr "添加参数" + +#~ msgid "Brightness Graph" +#~ msgstr "亮度分布图" + +#~ msgid "radius" +#~ msgstr "半径" + +#~ msgid "match" +#~ msgstr "对应" + +#~ msgid "Search results file error %s" +#~ msgstr "搜索结果文件错误 %s" + +#~ msgid "Batch Resize" +#~ msgstr "批量改变尺寸" + +#~ msgid "new max. height" +#~ msgstr "新最大高度" + +#~ msgid "copy EXIF" +#~ msgstr "复制EXIF" + +#~ msgid "new file already exists" +#~ msgstr "新文件已经存在" + +#~ msgid "Select area first" +#~ msgstr "首先选择区域" + +#~ msgid "close thumbnail window" +#~ msgstr "关闭缩略图窗口" + +#~ msgid "file" +#~ msgstr "文件" + +#~ msgid "folder" +#~ msgstr "文件夹" + +#~ msgid "jump to specific file" +#~ msgstr "跳至指定文件" + +#, fuzzy +#~ msgid "open a directory" +#~ msgstr "跳至新目录" + +#~ msgid "select new folder" +#~ msgstr "选择新文件夹" + +#~ msgid "xdg-utils package not installed" +#~ msgstr "xdg-utils软件包没有安装" + +#~ msgid "open a file" +#~ msgstr "打开一个文件" + +#~ msgid "paper format is crazy" +#~ msgstr "疯狂的纸张格式" + +#~ msgid "landscape" +#~ msgstr "水平" + +#~ msgid "portrait" +#~ msgstr "垂直" + +#~ msgid "paper format" +#~ msgstr "纸张格式" + +#~ msgid "printer ID" +#~ msgstr "打印机ID" + +#~ msgid "print" +#~ msgstr "打印" + +#~ msgid "Time Interval" +#~ msgstr "时间间隔" + +#~ msgid "Clone fotoxx" +#~ msgstr "复制一个 fotoxx 窗口" + +#~ msgid "Save As" +#~ msgstr "保存为" + +#~ msgid "click on window to show RGB" +#~ msgstr "点击窗口显示 RGB" + +#~ msgid "make new version" +#~ msgstr "新版本" + +#~ msgid "Create Launcher" +#~ msgstr "创建启动器" + +#~ msgid "" +#~ "Search all areas for edge and inside pixels. \n" +#~ "Click inside each enclosed area in sequence." +#~ msgstr "" +#~ "搜索所有区域边缘/和内部像素。\n" +#~ "点击" + +#~ msgid "area outline has a hole" +#~ msgstr "区域轮廓有一个洞" + +#~ msgid "Rebuild Thumbnails" +#~ msgstr "重建缩略图" + +#~ msgid "horizontal unbend" +#~ msgstr "水平拉伸" + +#~ msgid "press ESC to exit" +#~ msgstr "按下ESC退出" + +#~ msgid "select by color:" +#~ msgstr "根据色彩选择" + +#~ msgid "select by mouse:" +#~ msgstr "鼠标选择" + +#~ msgid "vertical unbend" +#~ msgstr "垂直拉伸" + +#~ msgid "target group area" +#~ msgstr "瞄准组区域" + +#~ msgid "Area" +#~ msgstr "区域" + +#~ msgid "Constrain" +#~ msgstr "强制" + +#~ msgid "Convert Tags !!!" +#~ msgstr "转换标签 !!!" + +#~ msgid "Convert tags to new standard" +#~ msgstr "将标签转化为新标准" + +#~ msgid "" +#~ "Convert tags to new standard now? \n" +#~ "Are your image files backed-up?" +#~ msgstr "" +#~ "是否现在把标签转化为新标准类型?\n" +#~ "您的图片已经备份了吗?" + +#~ msgid "HDF" +#~ msgstr "HDF" + +#~ msgid "HDR" +#~ msgstr "HDR" + +#~ msgid "" +#~ "New tags file already exists! \n" +#~ "Proceed anyway?" +#~ msgstr "" +#~ "新标签文件已经存在!\n" +#~ "仍然继续吗?" + +#~ msgid "No tags index file" +#~ msgstr "无标签索引文件" + +#~ msgid "Rebuild Tags Index" +#~ msgstr "重建标签索引" + +#~ msgid "Stack" +#~ msgstr "堆放" + +#~ msgid "Use F1 for context help" +#~ msgstr "F1唤出帮助" + +#~ msgid "brightness to clip (percent)" +#~ msgstr "亮度剪切(比例)" + +#~ msgid "cannot read .dist file" +#~ msgstr "无法读取 .dist 文件" + +#~ msgid "manage tags" +#~ msgstr "管理标签" + +#~ msgid "new tags index will now be created" +#~ msgstr "将创建新的标签索引" + +#~ msgid "save select area as a file" +#~ msgstr "选定区域保存为文件" + +#~ msgid "tags index file error: %s" +#~ msgstr "标签索引错误:%s" + +#~ msgid "/path*/file*" +#~ msgstr "/path*/file*" + +#~ msgid "All EXIF data" +#~ msgstr "全部Exif数据" + +#~ msgid "Basic EXIF data" +#~ msgstr "基本Exif数据" + +#~ msgid "Delete EXIF data" +#~ msgstr "删除 Exif 数据" + +#~ msgid "EXIF data" +#~ msgstr "Exif 数据\t" + +#~ msgid "Edit EXIF data" +#~ msgstr "修改 Exif 数据" + +#~ msgid "Resume" +#~ msgstr "继续" + +#~ msgid "Search Tags" +#~ msgstr "搜索标签" + +#~ msgid "Set Tile and Gap Size" +#~ msgstr "设置图块和间距尺寸" + +#~ msgid "Suspend" +#~ msgstr "暂停" + +#~ msgid "Tags" +#~ msgstr "标签" + +#~ msgid "match all tags" +#~ msgstr "对应全部标签" + +#~ msgid "match any tag" +#~ msgstr "适合任意标签" + +#~ msgid "" +#~ " Pull on an image edge using the mouse. \n" +#~ " Make multiple mouse pulls until satisfied. \n" +#~ " When finished, press [done]." +#~ msgstr "" +#~ " 鼠标左键在图像一边按下扭曲图像 \n" +#~ " 知道满意 \n" +#~ " 要结束,按下[完成]" + +#~ msgid "Open File" +#~ msgstr "打开文件" + +#~ msgid "Warp Area" +#~ msgstr "选定区域扭曲" + +#~ msgid "Warp Image" +#~ msgstr "扭曲图像" + +#~ msgid "Warp Image (curvy)" +#~ msgstr "扭曲图像(曲线)" + +#~ msgid "Warp Image in Selected Area" +#~ msgstr "扭曲选中区域的图像" + +#~ msgid "" +#~ "position image\n" +#~ "with mouse drag" +#~ msgstr "" +#~ "使用鼠标拖拽\n" +#~ "确定图像位置" + +#~ msgid "Burn" +#~ msgstr "刻录" + +#~ msgid "Fix Image Perspective" +#~ msgstr "修复图像透视" + +#~ msgid "Read File" +#~ msgstr "读取文件" + +#~ msgid "add tags" +#~ msgstr "添加标签" + +#~ msgid "color intensity" +#~ msgstr "色彩亮度" + +#~ msgid "color range" +#~ msgstr "色彩范围" + +#~ msgid "freehand draw" +#~ msgstr "自由绘画" + +#~ msgid "rename files" +#~ msgstr "重命名文件" + +#~ msgid "select image files to add tags" +#~ msgstr "选择要添加标签的文件" + +#~ msgid "" +#~ "\n" +#~ " Match Brightness and Color" +#~ msgstr "" +#~ "\n" +#~ " 对应亮度和颜色" + +#~ msgid "Auto" +#~ msgstr "自动" + +#~ msgid "" +#~ "Drag right image into rough alignment with left \n" +#~ " to rotate, drag right edge up or down" +#~ msgstr "" +#~ "拖右面的图片与左面的成一条线\n" +#~ "进行翻转,货到有边缘上部或下部" + +#~ msgid "Match Images" +#~ msgstr "对应图像" + +#~ msgid "Merge the images together" +#~ msgstr "图片融合在一起" + +#~ msgid "Package ufraw required for this function" +#~ msgstr "此功能需要 ufraw 包" + +#~ msgid "Retouch Image" +#~ msgstr "修饰图像" + +#~ msgid "Current file must be included" +#~ msgstr "必须包括当前文件" + +#~ msgid "jpeg quality" +#~ msgstr "jpeg 质量" + +#~ msgid "" +#~ "\n" +#~ " brightness \n" +#~ " level" +#~ msgstr "" +#~ "\n" +#~ " 亮度 \n" +#~ " 级别" + +#~ msgid " color balance blue " +#~ msgstr " 色彩平衡 蓝" + +#~ msgid " color balance green " +#~ msgstr " 色彩平衡 绿" + +#~ msgid "" +#~ "%s \n" +#~ " tag limit exceeded" +#~ msgstr "" +#~ "%s \n" +#~ " 标签限制突破" + +#~ msgid "2nd image not same size as 1st image" +#~ msgstr "第二图像和第一图像大小不同" + +#~ msgid "Add or Remove Grid Lines" +#~ msgstr "添加或者移除网格线" + +#~ msgid "Bend" +#~ msgstr "扭曲" + +#, fuzzy +#~ msgid "Blend Area Edges" +#~ msgstr "半径模糊" + +#~ msgid "Build Tags Index" +#~ msgstr "建立标签索引" + +#~ msgid "Clear Select Area" +#~ msgstr "清除选定区域" + +#~ msgid "Composite Images" +#~ msgstr "合成图像" + +#~ msgid "Convert multiple RAWs" +#~ msgstr "转化多个RAW文件" + +#~ msgid "" +#~ "Convert raw file to 48-bit tiff format? \n" +#~ " (this may take a while) " +#~ msgstr "" +#~ "转换raw文件到48-bit tiff格式?\n" +#~ " (这可能需要较长一段时间) " + +#, fuzzy +#~ msgid "Delete Area" +#~ msgstr "选择区域" + +#~ msgid "Dimensions" +#~ msgstr "整体" + +#~ msgid "Distortion" +#~ msgstr "变形" + +#, fuzzy +#~ msgid "" +#~ "Drag and click to enclose an area.\n" +#~ "Use right click to undo prior." +#~ msgstr "" +#~ "用鼠标拖拽点击一个区域。\n" +#~ "鼠标右键点击取消上一次" + +#~ msgid "" +#~ "Drag middle to move \n" +#~ "Drag corners to resize" +#~ msgstr "" +#~ "拖拽中部移动\n" +#~ "拖拽角落改变尺寸" + +#~ msgid "Error Log" +#~ msgstr "错误记录" + +#~ msgid "FREEIMAGE error: %s" +#~ msgstr "FREEIMAGE 错误: %s" + +#~ msgid "FREEIMAGE unknown error" +#~ msgstr "FREEIMAGE 未知错误" + +#, fuzzy +#~ msgid "Flash" +#~ msgstr "回收站" + +#, fuzzy +#~ msgid "HDR Image Weights" +#~ msgstr "HDR高度" + +#, fuzzy +#~ msgid "Hide Area" +#~ msgstr "选择区域" + +#, fuzzy +#~ msgid "Image Weights per Brightness Level" +#~ msgstr "" +#~ "\n" +#~ " 每个亮度级别图像宽度 \n" + +#~ msgid "Index" +#~ msgstr "索引" + +#~ msgid "Index (thumbnails)" +#~ msgstr "索引(缩略图)" + +#~ msgid "Index Tags" +#~ msgstr "索引标签" + +#~ msgid "Index Tags and Thumbs" +#~ msgstr "索引标签和缩略图" + +#, fuzzy +#~ msgid "Input Images" +#~ msgstr "输出图像" + +#, fuzzy +#~ msgid "Invert Area" +#~ msgstr "反色" + +#~ msgid "Make HDF Image" +#~ msgstr "制作HDF图像(高动态范围成像)" + +#~ msgid "Make HDR Image" +#~ msgstr "制作HDR图像(高动态范围成像)" + +#, fuzzy +#~ msgid "Output Image" +#~ msgstr "输出图像" + +#~ msgid "Paint Pixels" +#~ msgstr "绘制像素" + +#~ msgid "Print" +#~ msgstr "打印" + +#~ msgid "RAW file template" +#~ msgstr "RAW文件模板" + +#~ msgid "README" +#~ msgstr "介绍" + +#~ msgid "Rotate" +#~ msgstr "旋转" + +#~ msgid "Save Image as File" +#~ msgstr "保存图像文件到" + +#~ msgid "Sharp" +#~ msgstr "锐化" + +#, fuzzy +#~ msgid "Show Area" +#~ msgstr "区域" + +#~ msgid "Simulate embossing" +#~ msgstr "模拟浮雕效果" + +#~ msgid "Special Art Effects" +#~ msgstr "艺术效果" + +#~ msgid "Thumbnail Index" +#~ msgstr "缩略图索引一个位置" + +#, fuzzy +#~ msgid "Too many points" +#~ msgstr "太多点" + +#~ msgid "Too many tags: %d" +#~ msgstr "太多标签:%d" + +#~ msgid "Total tags exceed %d characters" +#~ msgstr "全部标签超出 %d 字符。" + +#~ msgid "Tune Image" +#~ msgstr "色彩调节" + +#, fuzzy +#~ msgid "Unable to replace file" +#~ msgstr "无法保存图像" + +#~ msgid "Warp Global" +#~ msgstr "全局扭曲" + +#~ msgid "Zoom+" +#~ msgstr "放大" + +#~ msgid "Zoom-" +#~ msgstr "缩小" + +#~ msgid "assigned tags" +#~ msgstr "指定的标签" + +#~ msgid "blend" +#~ msgstr "色带" + +#~ msgid "blur radius" +#~ msgstr "半径模糊" + +#~ msgid "" +#~ "cannot create %s \n" +#~ " %s" +#~ msgstr "" +#~ "无法创建 %s \n" +#~ " %s" + +#~ msgid "click or drag trim margins" +#~ msgstr "点击或者拖动剪裁界限" + +#~ msgid "color balance" +#~ msgstr "色彩平衡 " + +#~ msgid "computing" +#~ msgstr "计算中" + +#~ msgid "exceed 100 anchor points" +#~ msgstr "超出100个轴心点" + +#~ msgid "exiftool is required to create tags" +#~ msgstr "需要exiftool创建标签" + +#~ msgid "exiftool is required to generate tags index" +#~ msgstr "exiftool 是生成标签索引必备的" + +#~ msgid "grid spacing" +#~ msgstr "网格空间" + +#~ msgid "image format error: %s" +#~ msgstr "图像格式错误: %s" + +#~ msgid "image not 8 or 16 bits/color: %s" +#~ msgstr "图像不是8位或16位色的: %s" + +#~ msgid "open RAW file" +#~ msgstr "打开RAW文件" + +#~ msgid "open image file" +#~ msgstr "打开图像文件" + +#~ msgid "quit" +#~ msgstr "退出" + +#, fuzzy +#~ msgid "radius limit" +#~ msgstr "半径" + +#~ msgid "recently added" +#~ msgstr "最近添加" + +#~ msgid "red" +#~ msgstr "红" + +#~ msgid "redo image changes" +#~ msgstr "重复图像改变" + +#~ msgid "resize image" +#~ msgstr "改变图像大小" + +#~ msgid "rotate image" +#~ msgstr "旋转图像" + +#, fuzzy +#~ msgid "set blend radius" +#~ msgstr "设定模糊半径" + +#~ msgid "sharpen image" +#~ msgstr "锐化图像" + +#~ msgid "tags exceed %d characters" +#~ msgstr "标签超出 %d 个字符" + +#~ msgid "toolbar::save" +#~ msgstr "工具栏::保存" + +#~ msgid "trim image" +#~ msgstr "剪切图像" + +#~ msgid "unbend panorama image" +#~ msgstr "松弛全景图片" + +#~ msgid "unknown image format" +#~ msgstr "未知图像格式" + +#~ msgid "Discard modifications?" +#~ msgstr "放弃改动?" + +#~ msgid "" +#~ "Rename failed \n" +#~ " %s" +#~ msgstr "" +#~ "重命名失败\n" +#~ " %s" + +#~ msgid "incremental" +#~ msgstr "增量" + +#~ msgid "full rebuild" +#~ msgstr "完整重建" + +#~ msgid "Translate" +#~ msgstr "翻译" + +#~ msgid "select new file" +#~ msgstr "选择新文件" + +#~ msgid "lens name" +#~ msgstr "镜面名称" + +#~ msgid "Lens Parameters" +#~ msgstr "镜头参数" diff -Nru fotoxx-11.11.1/locales/fr/fotoxx.po fotoxx-12.01.2/locales/fr/fotoxx.po --- fotoxx-11.11.1/locales/fr/fotoxx.po 2011-11-05 05:30:37.000000000 +0000 +++ fotoxx-12.01.2/locales/fr/fotoxx.po 1970-01-01 00:00:00.000000000 +0000 @@ -1,2367 +0,0 @@ -# translation of fotoxx_merge.po to -# mico , 2008. -# Stanislas Zeller , 2008, 2009, 2010, 2011. -# translation of fotoxx.po to -# #-#-#-#-# fotoxx.po (messages) #-#-#-#-# -# French translations for home package. -# Copyright (C) 2008 THE home'S COPYRIGHT HOLDER -# This file is distributed under the same license as the home package. -msgid "" -msgstr "" -"Project-Id-Version: fotoxx_merge\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2011-11-05 05:49+0100\n" -"PO-Revision-Date: 2011-01-05 17:07+0100\n" -"Last-Translator: Stanislas Zeller \n" -"Language-Team: \n" -"Language: fr\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n > 1);\n" -"X-Generator: KBabel 1.11.4\n" - -#: fotoxx-11.11.1.cc:179 -msgid "File" -msgstr "Fichier" - -#: fotoxx-11.11.1.cc:180 fotoxx-11.11.1.cc:316 -msgid "Image Gallery" -msgstr "Parcourir les miniatures" - -#: fotoxx-11.11.1.cc:181 -msgid "Clone 50/50" -msgstr "" - -#: fotoxx-11.11.1.cc:182 -msgid "Clone Overlay" -msgstr "" - -#: fotoxx-11.11.1.cc:183 fotoxx-11.11.1.cc:317 fotoxx-11.11.1.cc:2272 -#: fotoxx-11.11.1.cc:2444 -msgid "Open Image File" -msgstr "Ouvrir une image" - -#: fotoxx-11.11.1.cc:184 -msgid "Open in New Window" -msgstr "" - -#: fotoxx-11.11.1.cc:185 fotoxx-11.11.1.cc:318 -msgid "Open Previous File" -msgstr "Afficher l'image précédente" - -#: fotoxx-11.11.1.cc:186 -msgid "Open Recent File" -msgstr "Ouvrir un fichier récent" - -#: fotoxx-11.11.1.cc:187 fotoxx-11.11.1.cc:326 -msgid "Save to Same File" -msgstr "Enregistrer" - -#: fotoxx-11.11.1.cc:188 fotoxx-11.11.1.cc:327 -msgid "Save to New Version" -msgstr "" - -#: fotoxx-11.11.1.cc:189 fotoxx-11.11.1.cc:328 -msgid "Save to New File" -msgstr "Enregistrer sous" - -#: fotoxx-11.11.1.cc:190 fotoxx-11.11.1.cc:2990 -msgid "Create Blank Image" -msgstr "Créer une image vide" - -#: fotoxx-11.11.1.cc:191 -msgid "Trash Image File" -msgstr "Supprimer l'image" - -#: fotoxx-11.11.1.cc:192 fotoxx-11.11.1.cc:3216 -msgid "Rename Image File" -msgstr "Renommer l'image" - -#: fotoxx-11.11.1.cc:193 -msgid "Batch Rename Files" -msgstr "Renommer des fichiers par lot" - -#: fotoxx-11.11.1.cc:194 -msgid "Print Image File" -msgstr "Imprimer une image" - -#: fotoxx-11.11.1.cc:195 fotoxx-11.11.1.cc:332 -msgid "Quit fotoxx" -msgstr "Quitter Fotoxx" - -#: fotoxx-11.11.1.cc:197 -msgid "Tools" -msgstr "Outils" - -#: fotoxx-11.11.1.cc:198 fotoxx_tools.cc:70 -msgid "Manage Collections" -msgstr "" - -#: fotoxx-11.11.1.cc:199 fotoxx_tools.cc:373 -msgid "Move Collections" -msgstr "" - -#: fotoxx-11.11.1.cc:200 -msgid "Check Monitor" -msgstr "Vérifier l'écran" - -#: fotoxx-11.11.1.cc:201 fotoxx_tools.cc:550 -msgid "Monitor Gamma" -msgstr "" - -#: fotoxx-11.11.1.cc:202 -msgid "Brightness Graph" -msgstr "Diagramme de luminosité" - -#: fotoxx-11.11.1.cc:203 fotoxx_tools.cc:819 -msgid "Slide Show" -msgstr "Diaporama" - -#: fotoxx-11.11.1.cc:204 fotoxx_tools.cc:1668 -msgid "Show RGB" -msgstr "Afficher les couleurs RVB" - -#: fotoxx-11.11.1.cc:205 fotoxx_tools.cc:1962 -msgid "Grid Lines" -msgstr "Grille" - -#: fotoxx-11.11.1.cc:206 fotoxx_tools.cc:2135 -msgid "Lens Parameters" -msgstr "Configuration de l'objectif" - -#: fotoxx-11.11.1.cc:207 -msgid "Change Language" -msgstr "Changer de langue" - -#: fotoxx-11.11.1.cc:209 -msgid "Add Menu and Launcher" -msgstr "" - -#: fotoxx-11.11.1.cc:210 -msgid "Convert RAW files" -msgstr "Convertir des fichiers RAW" - -#: fotoxx-11.11.1.cc:211 -msgid "Burn Images to CD/DVD" -msgstr "Graver les images vers un CD / DVD" - -#: fotoxx-11.11.1.cc:212 fotoxx_tools.cc:2460 -msgid "E-mail Images" -msgstr "Envoyer les images par adresse électronique" - -#: fotoxx-11.11.1.cc:213 fotoxx_tools.cc:2783 -msgid "Synchronize Files" -msgstr "" - -#: fotoxx-11.11.1.cc:214 fotoxx_tools.cc:3376 -msgid "Toolbar Style" -msgstr "" - -#: fotoxx-11.11.1.cc:215 -msgid "Memory Usage" -msgstr "" - -#: fotoxx-11.11.1.cc:218 -msgid "Edit Caption/Comments" -msgstr "" - -#: fotoxx-11.11.1.cc:219 fotoxx_info.cc:156 -msgid "Edit Tags" -msgstr "Modifier les étiquettes" - -#: fotoxx-11.11.1.cc:220 fotoxx_info.cc:345 -msgid "Manage Tags" -msgstr "" - -#: fotoxx-11.11.1.cc:221 fotoxx_info.cc:1345 -msgid "Batch Add Tags" -msgstr "Ajouter des étiquettes par lot" - -#: fotoxx-11.11.1.cc:222 fotoxx_info.cc:1547 -msgid "Batch Delete Tag" -msgstr "Supprimer des étiquettes par lot" - -#: fotoxx-11.11.1.cc:223 -msgid "View Info (short)" -msgstr "Afficher les informations (résumé)" - -#: fotoxx-11.11.1.cc:224 -msgid "View Info (long)" -msgstr "Afficher les informations (complet)" - -#: fotoxx-11.11.1.cc:225 fotoxx_info.cc:1883 -msgid "Edit Info" -msgstr "Modifier les informations" - -#: fotoxx-11.11.1.cc:226 fotoxx_info.cc:1981 -msgid "Delete Info" -msgstr "Supprimer les informations" - -#: fotoxx-11.11.1.cc:227 -msgid "Search Images" -msgstr "Rechercher des images" - -#: fotoxx-11.11.1.cc:229 fotoxx-11.11.1.cc:230 -msgid "Select" -msgstr "Sélectionner" - -#: fotoxx-11.11.1.cc:231 -msgid "Show" -msgstr "Afficher" - -#: fotoxx-11.11.1.cc:232 -msgid "Hide" -msgstr "Cacher" - -#: fotoxx-11.11.1.cc:233 -msgid "Enable" -msgstr "Activer" - -#: fotoxx-11.11.1.cc:234 -msgid "Disable" -msgstr "Désactiver" - -#: fotoxx-11.11.1.cc:235 -msgid "Invert" -msgstr "Inverser" - -#: fotoxx-11.11.1.cc:236 -msgid "Unselect" -msgstr "" - -#: fotoxx-11.11.1.cc:237 -msgid "Copy" -msgstr "Copier" - -#: fotoxx-11.11.1.cc:238 -msgid "Paste" -msgstr "Coller" - -#: fotoxx-11.11.1.cc:239 fotoxx-11.11.1.cc:317 fotoxx_retouch.cc:2314 -#: fotoxx_retouch.cc:2319 -msgid "Open" -msgstr "Ouvrir" - -#: fotoxx-11.11.1.cc:240 fotoxx-11.11.1.cc:326 -msgid "Save" -msgstr "Enreg." - -#: fotoxx-11.11.1.cc:241 fotoxx_area.cc:2215 -msgid "Select Whole Image" -msgstr "Sélectionner toute l'image" - -#: fotoxx-11.11.1.cc:242 -msgid "Select and Edit" -msgstr "" - -#: fotoxx-11.11.1.cc:244 -msgid "Transform" -msgstr "Transformer" - -#: fotoxx-11.11.1.cc:245 fotoxx_transform.cc:60 -msgid "Rotate Image" -msgstr "Pivoter l'image" - -#: fotoxx-11.11.1.cc:246 fotoxx_transform.cc:346 -msgid "Trim Image" -msgstr "Rogner" - -#: fotoxx-11.11.1.cc:247 fotoxx_transform.cc:972 -msgid "Resize Image" -msgstr "Redimensionner l'image" - -#: fotoxx-11.11.1.cc:248 -msgid "Batch Resize/Export" -msgstr "" - -#: fotoxx-11.11.1.cc:249 fotoxx_transform.cc:1436 -msgid "Annotate Image" -msgstr "Annoter l'image" - -#: fotoxx-11.11.1.cc:250 fotoxx_transform.cc:2193 -msgid "Flip Image" -msgstr "Retourner l'image" - -#: fotoxx-11.11.1.cc:251 fotoxx_transform.cc:2303 -msgid "Make Negative" -msgstr "Négatif" - -#: fotoxx-11.11.1.cc:252 fotoxx_transform.cc:2420 -msgid "Unbend Image" -msgstr "Redresser" - -#: fotoxx-11.11.1.cc:253 fotoxx_transform.cc:2704 -msgid "Keystone Correction" -msgstr "" - -#: fotoxx-11.11.1.cc:254 fotoxx_transform.cc:3013 -msgid "Warp Image (area)" -msgstr "Déformer l'image (zone)" - -#: fotoxx-11.11.1.cc:255 fotoxx_transform.cc:3255 -msgid "Warp Image (curved)" -msgstr "Déformer l'image (courbé)" - -#: fotoxx-11.11.1.cc:256 fotoxx_transform.cc:3518 -msgid "Warp Image (linear)" -msgstr "Déformer l'image (linéaire)" - -#: fotoxx-11.11.1.cc:257 fotoxx_transform.cc:3782 -msgid "Warp Image (affine)" -msgstr "Déformer l'image (affiné)" - -#: fotoxx-11.11.1.cc:259 -msgid "Retouch" -msgstr "Retoucher" - -#: fotoxx-11.11.1.cc:260 -msgid "Brightness/Color" -msgstr "Luminosité et couleur" - -#: fotoxx-11.11.1.cc:261 -msgid "Gamma Curves" -msgstr "" - -#: fotoxx-11.11.1.cc:262 -msgid "Expand Brightness" -msgstr "Améliorer la luminosité" - -#: fotoxx-11.11.1.cc:263 -msgid "Flatten Brightness" -msgstr "Luminosité aplanie" - -#: fotoxx-11.11.1.cc:264 -msgid "Brightness Ramp" -msgstr "Luminosité : correction" - -#: fotoxx-11.11.1.cc:265 fotoxx_retouch.cc:1729 -msgid "Tone Mapping" -msgstr "Tone Mapping" - -#: fotoxx-11.11.1.cc:266 -msgid "White Balance" -msgstr "Balance des blancs" - -#: fotoxx-11.11.1.cc:267 -msgid "Match Colors" -msgstr "" - -#: fotoxx-11.11.1.cc:269 fotoxx_retouch.cc:2941 -msgid "Revise RGB" -msgstr "" - -#: fotoxx-11.11.1.cc:270 -msgid "Red Eyes" -msgstr "Yeux rouges" - -#: fotoxx-11.11.1.cc:271 -msgid "Blur Image" -msgstr "Flou" - -#: fotoxx-11.11.1.cc:272 fotoxx_retouch.cc:4077 -msgid "Sharpen Image" -msgstr "Netteté" - -#: fotoxx-11.11.1.cc:273 -msgid "Reduce Noise" -msgstr "Réduction du bruit" - -#: fotoxx-11.11.1.cc:274 fotoxx_retouch.cc:4881 -msgid "Smart Erase" -msgstr "" - -#: fotoxx-11.11.1.cc:275 fotoxx_retouch.cc:5271 -msgid "Remove Dust" -msgstr "" - -#: fotoxx-11.11.1.cc:276 fotoxx_retouch.cc:5877 -msgid "Edit Pixels" -msgstr "Modifier les pixels" - -#: fotoxx-11.11.1.cc:278 -msgid "Art" -msgstr "Art" - -#: fotoxx-11.11.1.cc:279 -msgid "Color Depth" -msgstr "Profondeur de couleurs" - -#: fotoxx-11.11.1.cc:280 -msgid "Drawing" -msgstr "Dessin" - -#: fotoxx-11.11.1.cc:281 -msgid "Outlines" -msgstr "" - -#: fotoxx-11.11.1.cc:282 -msgid "Embossing" -msgstr "Gaufrage" - -#: fotoxx-11.11.1.cc:283 -msgid "Tiles" -msgstr "Tuiles" - -#: fotoxx-11.11.1.cc:284 -msgid "Dots" -msgstr "Points" - -#: fotoxx-11.11.1.cc:285 -msgid "Painting" -msgstr "Peinture" - -#: fotoxx-11.11.1.cc:287 -msgid "Combine" -msgstr "Combiner" - -#: fotoxx-11.11.1.cc:288 -msgid "High Dynamic Range" -msgstr "" - -#: fotoxx-11.11.1.cc:289 -msgid "High Depth of Field" -msgstr "" - -#: fotoxx-11.11.1.cc:290 -msgid "Stack / Paint" -msgstr "" - -#: fotoxx-11.11.1.cc:291 -msgid "Stack / Noise" -msgstr "" - -#: fotoxx-11.11.1.cc:292 -msgid "Panorama" -msgstr "Panorama" - -#: fotoxx-11.11.1.cc:293 -msgid "Vertical Panorama" -msgstr "" - -#: fotoxx-11.11.1.cc:296 -msgid "Edit Plugins" -msgstr "" - -#: fotoxx-11.11.1.cc:305 fotoxx-11.11.1.cc:333 fotoxx-11.11.1.cc:4616 -msgid "Help" -msgstr "Aide" - -#: fotoxx-11.11.1.cc:306 fotoxx-11.11.1.cc:4606 -msgid "About" -msgstr "Á propos" - -#: fotoxx-11.11.1.cc:307 fotoxx-11.11.1.cc:4610 -msgid "User Guide" -msgstr "Documentation" - -#: fotoxx-11.11.1.cc:308 fotoxx-11.11.1.cc:4613 -msgid "User Guide Changes" -msgstr "" - -#: fotoxx-11.11.1.cc:309 fotoxx-11.11.1.cc:4622 -msgid "Edit Functions Summary" -msgstr "" - -#: fotoxx-11.11.1.cc:310 fotoxx-11.11.1.cc:4625 -msgid "Change Log" -msgstr "Modifications" - -#: fotoxx-11.11.1.cc:311 fotoxx-11.11.1.cc:4628 -msgid "Translations" -msgstr "" - -#: fotoxx-11.11.1.cc:312 fotoxx-11.11.1.cc:4631 -msgid "Home Page" -msgstr "Site web" - -#: fotoxx-11.11.1.cc:316 -msgid "Gallery" -msgstr "Miniatures" - -#: fotoxx-11.11.1.cc:318 fotoxx_transform.cc:995 -msgid "Prev" -msgstr "Préc." - -#: fotoxx-11.11.1.cc:319 -msgid "Next" -msgstr "Suiv." - -#: fotoxx-11.11.1.cc:319 -msgid "Open Next File" -msgstr "Afficher l'image suivante" - -#: fotoxx-11.11.1.cc:320 -msgid "Zoom-in (bigger)" -msgstr "Agrandir" - -#: fotoxx-11.11.1.cc:321 -msgid "Zoom-out (smaller)" -msgstr "Réduire" - -#: fotoxx-11.11.1.cc:322 -msgid "Undo" -msgstr "Undo" - -#: fotoxx-11.11.1.cc:322 -msgid "Undo One Edit" -msgstr "Annuler une modification" - -#: fotoxx-11.11.1.cc:323 -msgid "Redo" -msgstr "Redo" - -#: fotoxx-11.11.1.cc:323 -msgid "Redo One Edit" -msgstr "Rétablir une modification" - -#: fotoxx-11.11.1.cc:327 -msgid "Save+V" -msgstr "" - -#: fotoxx-11.11.1.cc:328 -msgid "Save+F" -msgstr "" - -#: fotoxx-11.11.1.cc:329 -msgid "Move Image to Trash" -msgstr "Déplacer l'image vers la corbeille" - -#: fotoxx-11.11.1.cc:329 -msgid "Trash" -msgstr "Suppr." - -#: fotoxx-11.11.1.cc:332 -msgid "Quit" -msgstr "Quit." - -#: fotoxx-11.11.1.cc:333 -msgid "Fotoxx Essentials" -msgstr "Guide de l'utilisateur" - -#: fotoxx-11.11.1.cc:429 -msgid "first time startup" -msgstr "" - -#: fotoxx-11.11.1.cc:1815 -msgid "Exceed 50 anchor points" -msgstr "Dépasse de 50 points d'ancrage" - -#: fotoxx-11.11.1.cc:2000 -msgid "load curve from a file" -msgstr "" - -#: fotoxx-11.11.1.cc:2053 -msgid "curve file is invalid" -msgstr "" - -#: fotoxx-11.11.1.cc:2058 -msgid "curve file has different no. of curves" -msgstr "" - -#: fotoxx-11.11.1.cc:2073 -msgid "save curve to a file" -msgstr "" - -#: fotoxx-11.11.1.cc:2420 -#, c-format -msgid "" -"Discard special gallery list? \n" -" %s" -msgstr "" - -#: fotoxx-11.11.1.cc:2430 fotoxx-11.11.1.cc:4452 -msgid "prior function still active" -msgstr "" - -#: fotoxx-11.11.1.cc:2607 -msgid "Overwrite original file?" -msgstr "" - -#: fotoxx-11.11.1.cc:2608 -msgid "Do not warn again" -msgstr "" - -#: fotoxx-11.11.1.cc:2624 -msgid "Warning" -msgstr "" - -#: fotoxx-11.11.1.cc:2747 -msgid "Save File" -msgstr "Enregistrer le fichier" - -#: fotoxx-11.11.1.cc:2770 -msgid "quality" -msgstr "Qualité" - -#: fotoxx-11.11.1.cc:2772 -msgid "make current" -msgstr "" - -#: fotoxx-11.11.1.cc:2829 -msgid "jpeg quality must be 1-100" -msgstr "La qualité du JPEG doit être compris entre 1 et 100" - -#: fotoxx-11.11.1.cc:2851 -#, c-format -msgid "" -"Overwrite file? \n" -" %s" -msgstr "" -"Écraser le fichier ? \n" -" %s" - -#: fotoxx-11.11.1.cc:2992 -msgid "file name" -msgstr "" - -#: fotoxx-11.11.1.cc:2997 fotoxx_transform.cc:351 -msgid "width" -msgstr "Largeur" - -#: fotoxx-11.11.1.cc:3000 fotoxx_transform.cc:354 -msgid "height" -msgstr "Hauteur" - -#: fotoxx-11.11.1.cc:3006 fotoxx_art.cc:628 fotoxx_retouch.cc:5881 -msgid "color" -msgstr "Couleur" - -#: fotoxx-11.11.1.cc:3120 -msgid "" -"Linux standard trash is not supported. \n" -"Desktop trash folder will be created." -msgstr "" -"La corbeille standard Linux n'est pas prise ne charge? \n" -"Un dossier corbeille sera créé." - -#: fotoxx-11.11.1.cc:3138 -msgid "Move read-only file to trash?" -msgstr "Déplacer le fichier en lecture-seule vers la corbeille ?" - -#: fotoxx-11.11.1.cc:3164 -#, c-format -msgid "Cannot create trash folder: %s" -msgstr "Impossible de créer le dossier corbeille : %s" - -#: fotoxx-11.11.1.cc:3172 fotoxx-11.11.1.cc:3178 -#, c-format -msgid "error: %s" -msgstr "Erreur : %s" - -#: fotoxx-11.11.1.cc:3221 -msgid "old name" -msgstr "Ancien nom" - -#: fotoxx-11.11.1.cc:3222 -msgid "rename to" -msgstr "Renommer en" - -#: fotoxx-11.11.1.cc:3223 -msgid "previous" -msgstr "Préc." - -#: fotoxx-11.11.1.cc:3309 -msgid "The target file already exists" -msgstr "Le fichier cible existe toujours" - -#: fotoxx-11.11.1.cc:3317 -#, c-format -msgid "" -"Rename failed: \n" -" %s" -msgstr "" - -#: fotoxx-11.11.1.cc:3365 -msgid "Batch Rename" -msgstr "Renommer par lot" - -#: fotoxx-11.11.1.cc:3368 fotoxx-11.11.1.cc:3420 fotoxx_info.cc:1513 -#: fotoxx_info.cc:1767 fotoxx_tools.cc:2510 fotoxx_transform.cc:1213 -#, c-format -msgid "%d files selected" -msgstr "" - -#: fotoxx-11.11.1.cc:3370 -msgid "new base name" -msgstr "Nouveau nom" - -#: fotoxx-11.11.1.cc:3373 -msgid "starting sequence" -msgstr "Commence par" - -#: fotoxx-11.11.1.cc:3375 -msgid "increment" -msgstr "Incrémente de" - -#: fotoxx-11.11.1.cc:3396 -msgid "select files to rename" -msgstr "Sélectionner les fichiers à renommer" - -#: fotoxx-11.11.1.cc:3401 -msgid "base name / sequence / increment not reasonable" -msgstr "Une valeur est obligatoire" - -#: fotoxx-11.11.1.cc:3460 -msgid "new file already exists:" -msgstr "Un nouveau fichier existe toujours : " - -#: fotoxx-11.11.1.cc:3468 -msgid "filespec too long:" -msgstr "Le fichier « filespec » est trop long" - -#: fotoxx-11.11.1.cc:3479 -msgid "Rename failed:" -msgstr "Le renommage a échoué : " - -#: fotoxx-11.11.1.cc:3739 -msgid "Add" -msgstr "" - -#: fotoxx-11.11.1.cc:3739 -msgid "Remove" -msgstr "" - -#: fotoxx-11.11.1.cc:3741 -msgid "menu name" -msgstr "" - -#: fotoxx-11.11.1.cc:3812 fotoxx-11.11.1.cc:3833 -msgid "Restart Fotoxx to update plugin menu" -msgstr "" - -#: fotoxx-11.11.1.cc:3927 -msgid "cannot parallel edit" -msgstr "" - -#: fotoxx-11.11.1.cc:3937 -msgid "" -"exiftool is not installed \n" -"edited images will lose EXIF data" -msgstr "" -"Le paquetage « exiftool » n'est pas installé \n" -"Les images modifiées perdront leurs données Exif" - -#: fotoxx-11.11.1.cc:3943 -msgid "Too many edits, please save image" -msgstr "Trop de modifications, veuillez enregistrer l'image" - -#: fotoxx-11.11.1.cc:3948 -msgid "" -"Select area cannot be kept.\n" -"Continue?" -msgstr "" -"Impossible de conserver la sélection de la zone.\n" -"Voulez-vous continuer ?" - -#: fotoxx-11.11.1.cc:3956 -msgid "" -"Select area not active.\n" -"Continue?" -msgstr "" -"La zone sélectionnée n'est \n" -"pas active. Continuer ?" - -#: fotoxx-11.11.1.cc:4427 -msgid "Discard edits?" -msgstr "" - -#: fotoxx-11.11.1.cc:4428 -msgid "" -"This action will discard current edits.\n" -"Continue to discard edits.\n" -"Go Back to keep edits." -msgstr "" - -#: fotoxx-11.11.1.cc:4431 -msgid "Continue" -msgstr "" - -#: fotoxx-11.11.1.cc:4432 -msgid "Go Back" -msgstr "" - -#: fotoxx-11.11.1.cc:5240 -msgid "cannot open thumbnail file" -msgstr "Impossible d'ouvrir le fichier de miniatures" - -#: fotoxx-11.11.1.cc:5433 fotoxx-11.11.1.cc:5549 -msgid "TIFF open failure" -msgstr "Impossible d'ouvrir le fichier TIFF" - -#: fotoxx-11.11.1.cc:5449 -#, c-format -msgid "TIFF bits/color=%d not supported" -msgstr "TIFF bits/color=%d n'est pas pris en charge" - -#: fotoxx-11.11.1.cc:5464 fotoxx-11.11.1.cc:5502 -msgid "TIFF read failure" -msgstr "Impossible de lire le fichier TIFF" - -#: fotoxx-11.11.1.cc:5608 -msgid "TIFF write failure" -msgstr "Impossible d'écrire le fichier TIFF" - -#: fotoxx-11.11.1.cc:5638 -msgid "file type not supported" -msgstr "Ce type de fichier n'est pas pris en charge" - -#: fotoxx-11.11.1.cc:5745 -msgid "pixbuf write failure" -msgstr "Échec d'écriture pixbuf" - -#: fotoxx_area.cc:54 fotoxx_area.cc:2427 -msgid "Select Area for Edits" -msgstr "Sélectionner une zone à modifier" - -#: fotoxx_area.cc:55 fotoxx_area.cc:2428 -msgid "Press F1 for help" -msgstr "" - -#: fotoxx_area.cc:63 -msgid "" -"Select Area not supported \n" -"by this edit function" -msgstr "" - -#: fotoxx_area.cc:99 fotoxx_tools.cc:809 -msgid "rectangle" -msgstr "" - -#: fotoxx_area.cc:100 fotoxx_tools.cc:810 -msgid "ellipse" -msgstr "" - -#: fotoxx_area.cc:101 -msgid "draw: freehand" -msgstr "Dessiner : main levée" - -#: fotoxx_area.cc:102 -msgid "draw: follow edge" -msgstr "Dessiner : suivre les contours" - -#: fotoxx_area.cc:103 -msgid "select by mouse" -msgstr "" - -#: fotoxx_area.cc:104 -msgid "select by color" -msgstr "" - -#: fotoxx_area.cc:112 -msgid "radius" -msgstr "Radius" - -#: fotoxx_area.cc:116 -msgid "match" -msgstr "Correspondance" - -#: fotoxx_area.cc:121 -msgid "firewall" -msgstr "" - -#: fotoxx_area.cc:274 fotoxx_area.cc:415 -#, c-format -msgid "exceed %d edits" -msgstr "Dépasse de %d modifications" - -#: fotoxx_area.cc:992 -msgid "" -"Click one time inside each enclosed area \n" -"(possible gaps in the outline will be found). \n" -"Press F1 for help." -msgstr "" - -#: fotoxx_area.cc:1049 -msgid "finish area" -msgstr "Cloturer la zone" - -#: fotoxx_area.cc:1083 -msgid "searching" -msgstr "Rechercher" - -#: fotoxx_area.cc:1155 -msgid "outline has a gap" -msgstr "" - -#: fotoxx_area.cc:1157 -msgid "success" -msgstr "Terminé avec succès" - -#: fotoxx_area.cc:1401 fotoxx_area.cc:1430 -msgid "the area is not finished" -msgstr "La zone n'est pas bouclée" - -#: fotoxx_area.cc:1522 -msgid "Edge calculation in progress" -msgstr "Calcul des bords en cours" - -#: fotoxx_area.cc:1531 -msgid "Area Edge Calc" -msgstr "Calcul du bord de la zone" - -#: fotoxx_area.cc:1824 -msgid "position with mouse click/drag" -msgstr "Position avec un clic / glisser" - -#: fotoxx_area.cc:1848 -msgid "Paste Image" -msgstr "Coller l'image" - -#: fotoxx_area.cc:1863 -msgid "angle" -msgstr "" - -#: fotoxx_area.cc:2127 -msgid "load select area from a file" -msgstr "Charger la zone sélectionnée à partir d'un fichier" - -#: fotoxx_area.cc:2161 -msgid "cannot open .tiff and .info files" -msgstr "" - -#: fotoxx_area.cc:2180 -msgid "save select area to a file" -msgstr "" - -#: fotoxx_area.cc:2216 -msgid "Edit Function Amplifier" -msgstr "Modifier l'amplitude" - -#: fotoxx_area.cc:2459 -msgid "mouse radius" -msgstr "" - -#: fotoxx_area.cc:2462 -msgid "power: center" -msgstr "" - -#: fotoxx_area.cc:2464 -msgid "edge" -msgstr "" - -#: fotoxx_area.cc:2468 -msgid "reset area" -msgstr "" - -#: fotoxx_area.cc:2523 -msgid "start edit function first" -msgstr "" - -#: fotoxx_art.cc:47 -msgid "Set color depth to 1-16 bits" -msgstr "" -"Configurer la profondeur de \n" -"couleurs de 1 à 16 bits." - -#: fotoxx_art.cc:57 -msgid "Set Color Depth" -msgstr "Configurer la profondeur de couleurs" - -#: fotoxx_art.cc:171 -msgid "Simulate Drawing" -msgstr "Simuler un dessin" - -#: fotoxx_art.cc:213 fotoxx_retouch.cc:1758 -msgid "contrast" -msgstr "Contraste" - -#: fotoxx_art.cc:215 -msgid "outlines" -msgstr "Contours" - -#: fotoxx_art.cc:220 -msgid "pencil" -msgstr "Crayon" - -#: fotoxx_art.cc:221 -msgid "chalk" -msgstr "Craie" - -#: fotoxx_art.cc:381 -msgid "Add Image Outlines" -msgstr "" - -#: fotoxx_art.cc:394 -msgid "outline threshold" -msgstr "" - -#: fotoxx_art.cc:397 -msgid "outline width" -msgstr "" - -#: fotoxx_art.cc:400 -msgid "image brightness" -msgstr "" - -#: fotoxx_art.cc:611 -msgid "Simulate Embossing" -msgstr "Simuler un gaufrage" - -#: fotoxx_art.cc:626 -msgid "depth" -msgstr "Profondeur" - -#: fotoxx_art.cc:821 -msgid "Simulate Tiles" -msgstr "Simuler des tuiles" - -#: fotoxx_art.cc:825 -msgid "tile size" -msgstr "Taille de la tuile" - -#: fotoxx_art.cc:829 -msgid "tile gap" -msgstr "Espace entre les tuiles" - -#: fotoxx_art.cc:1003 -msgid "Convert Image to Dots" -msgstr "Convertir l'image en points" - -#: fotoxx_art.cc:1007 -msgid "dot size" -msgstr "Taille du point" - -#: fotoxx_art.cc:1222 -msgid "Simulate Painting" -msgstr "Simuler une peinture" - -#: fotoxx_art.cc:1226 -msgid "color depth" -msgstr "Profondeur de couleurs" - -#: fotoxx_art.cc:1230 -msgid "patch area goal" -msgstr "" - -#: fotoxx_art.cc:1234 -msgid "req. color match" -msgstr "Correspondance de couleurs requise" - -#: fotoxx_art.cc:1238 -msgid "borders" -msgstr "Contours" - -#: fotoxx_comp.cc:1956 fotoxx_comp.cc:1961 fotoxx_comp.cc:2582 -#: fotoxx_comp.cc:2587 fotoxx_comp.cc:3275 fotoxx_comp.cc:3280 -#: fotoxx_comp.cc:3830 fotoxx_comp.cc:3835 -msgid "Select 2 to 9 files" -msgstr "Sélectionner 2 à 9 fichiers" - -#: fotoxx_comp.cc:1982 fotoxx_comp.cc:2608 fotoxx_comp.cc:3301 -#: fotoxx_comp.cc:3856 -msgid "Images are not all the same size" -msgstr "Les images ne sont pas toutes de la même taille" - -#: fotoxx_comp.cc:2321 -msgid "Adjust Image Contributions" -msgstr "Ajuster les recouvrements de l'image" - -#: fotoxx_comp.cc:2324 fotoxx_retouch.cc:885 -msgid "dark pixels" -msgstr "Pixels sombres" - -#: fotoxx_comp.cc:2326 -msgid "light pixels" -msgstr "Pixels lumineux" - -#: fotoxx_comp.cc:2328 fotoxx_info.cc:159 -msgid "file:" -msgstr "Fichier : " - -#: fotoxx_comp.cc:2844 -msgid "Paint and Warp Image" -msgstr "" - -#: fotoxx_comp.cc:2847 fotoxx_comp.cc:3529 fotoxx_comp.cc:4972 -#: fotoxx_comp.cc:5717 -msgid "image" -msgstr "image" - -#: fotoxx_comp.cc:2851 fotoxx_retouch.cc:5885 -msgid "paint" -msgstr "Peinture" - -#: fotoxx_comp.cc:2852 -msgid "warp" -msgstr "Déformer" - -#: fotoxx_comp.cc:3527 -msgid "Select and Paint Image" -msgstr "" - -#: fotoxx_comp.cc:4045 -msgid "Adjust Pixel Composition" -msgstr "" - -#: fotoxx_comp.cc:4297 fotoxx_comp.cc:4302 fotoxx_comp.cc:5186 -#: fotoxx_comp.cc:5191 -msgid "Select 2 to 4 files" -msgstr "Sélectionner 2 à 4 fichiers" - -#: fotoxx_comp.cc:4374 -msgid "" -"Drag images into rough alignment.\n" -"To rotate, drag from lower edge." -msgstr "" - -#: fotoxx_comp.cc:4376 -msgid "Search for lens mm and bow" -msgstr "Rechercher les valeurs « lens mm / bow »" - -#: fotoxx_comp.cc:4422 fotoxx_comp.cc:5310 -msgid "Pre-align Images" -msgstr "Images pré alignées" - -#: fotoxx_comp.cc:4426 fotoxx_comp.cc:5314 fotoxx_tools.cc:2151 -msgid "lens mm" -msgstr "Longueur de la focale (lens_mm)" - -#: fotoxx_comp.cc:4430 fotoxx_comp.cc:5318 fotoxx_tools.cc:2156 -msgid "lens bow" -msgstr "Courbe d'objectif (lens_bow)" - -#: fotoxx_comp.cc:4432 fotoxx_comp.cc:5320 -msgid "Resize" -msgstr "Redimensionner" - -#: fotoxx_comp.cc:4433 fotoxx_comp.cc:5321 -msgid "resize window" -msgstr "Redimensionner la fenêtre" - -#: fotoxx_comp.cc:4470 -msgid "use two images only" -msgstr "N'utilisez seulement que deux images" - -#: fotoxx_comp.cc:4491 fotoxx_comp.cc:4689 fotoxx_comp.cc:4888 -#: fotoxx_comp.cc:5369 fotoxx_comp.cc:5632 -msgid "Too little overlap, cannot align" -msgstr "Trop de chevauchements, impossible d'aligner." - -#: fotoxx_comp.cc:4963 fotoxx_comp.cc:5708 -msgid "Match Brightness and Color" -msgstr "Correspondance de la luminosité et de la couleur" - -#: fotoxx_comp.cc:4987 fotoxx_comp.cc:5732 -msgid "auto color" -msgstr "Couleur auto." - -#: fotoxx_comp.cc:4988 fotoxx_comp.cc:5733 -msgid "file color" -msgstr "Couleur du fichier" - -#: fotoxx_comp.cc:5263 -msgid "" -"Drag images into rough alignment.\n" -"To rotate, drag from right edge." -msgstr "" - -#: fotoxx_info.cc:70 -msgid "Edit Caption and Comments" -msgstr "" - -#: fotoxx_info.cc:163 -msgid "image date (yyyymmdd)" -msgstr "Date (aaaa-mm-jj)" - -#: fotoxx_info.cc:165 -msgid "use last" -msgstr "Dernière utilisation" - -#: fotoxx_info.cc:168 -msgid "image stars" -msgstr "Note de l'image" - -#: fotoxx_info.cc:186 -msgid "current tags" -msgstr "Étiquettes actuelles" - -#: fotoxx_info.cc:191 -msgid "recent tags" -msgstr "Étiquettes récentes" - -#: fotoxx_info.cc:196 fotoxx_info.cc:358 fotoxx_info.cc:1362 -#: fotoxx_info.cc:2290 -msgid "defined tags" -msgstr "Définir les étiquettes" - -#: fotoxx_info.cc:348 -msgid "category" -msgstr "Catégorie" - -#: fotoxx_info.cc:351 -msgid "tag" -msgstr "Étiquette" - -#: fotoxx_info.cc:354 -msgid "create" -msgstr "Créer" - -#: fotoxx_info.cc:355 -msgid "delete" -msgstr "Supprimer" - -#: fotoxx_info.cc:1229 fotoxx_info.cc:1313 -#, c-format -msgid "search index file error: %s" -msgstr "" - -#: fotoxx_info.cc:1348 -msgid "tags to add" -msgstr "Étiquettes à ajouter" - -#: fotoxx_info.cc:1353 -msgid "create tag" -msgstr "Créer une étiquette" - -#: fotoxx_info.cc:1409 fotoxx_info.cc:1602 -#, c-format -msgid "" -"%s \n" -" too many tags" -msgstr "" -"%s \n" -" trop d'étiquettes" - -#: fotoxx_info.cc:1550 -msgid "tag to remove" -msgstr "Étiquette à supprimer" - -#: fotoxx_info.cc:1554 -msgid "optional replacement" -msgstr "Remplacement optionnel" - -#: fotoxx_info.cc:1559 fotoxx_tools.cc:2463 -msgid "0 files selected" -msgstr "" - -#: fotoxx_info.cc:1562 -msgid "search all files" -msgstr "Rechercher tous les fichiers" - -#: fotoxx_info.cc:1647 -msgid "no files selected" -msgstr "Aucun fichiers sélectionnés" - -#: fotoxx_info.cc:1653 -msgid "no tag specified" -msgstr "Aucune étiquettes spécifiées" - -#: fotoxx_info.cc:1677 fotoxx_info.cc:1706 -msgid "specify tag" -msgstr "Étiquette spécifique" - -#: fotoxx_info.cc:1815 -msgid "View Info" -msgstr "Afficher les informations" - -#: fotoxx_info.cc:1983 -msgid "All" -msgstr "Tout" - -#: fotoxx_info.cc:1984 -msgid "One Key:" -msgstr "Une touche : " - -#: fotoxx_info.cc:2249 -msgid "Search Tags, Comments, File Names" -msgstr "Rechercher les étiquettes, commentaires et noms de fichiers" - -#: fotoxx_info.cc:2255 -msgid "date range" -msgstr "Date entre : " - -#: fotoxx_info.cc:2256 -msgid "stars range" -msgstr "Note entre : " - -#: fotoxx_info.cc:2257 -msgid "search tags" -msgstr "Rechercher" - -#: fotoxx_info.cc:2258 -msgid "search text" -msgstr "Rechercher le texte" - -#: fotoxx_info.cc:2259 -msgid "file names" -msgstr "Noms des fichiers" - -#: fotoxx_info.cc:2264 -msgid "(yyyymmdd)" -msgstr "" - -#: fotoxx_info.cc:2270 -msgid "all/any" -msgstr "" - -#: fotoxx_info.cc:2598 -msgid "No matching images found" -msgstr "Aucuns résultats pour cette recherche" - -#: fotoxx_info.cc:2611 -msgid "No search index file present" -msgstr "" - -#: fotoxx_info.cc:2615 -#, c-format -msgid "Search results file error %s" -msgstr "Erreur de fichier des résultats recherchés %s" - -#: fotoxx_retouch.cc:55 -msgid "Adjust Brightness and Color" -msgstr "Ajuster la luminosité et la couleur" - -#: fotoxx_retouch.cc:109 -msgid "small-steps" -msgstr "" - -#: fotoxx_retouch.cc:118 -msgid "color saturation" -msgstr "Saturation des couleurs" - -#: fotoxx_retouch.cc:125 -msgid " reset 1 " -msgstr "Réinit. 1x" - -#: fotoxx_retouch.cc:126 -msgid "reset all" -msgstr "Tout réinitialiser" - -#: fotoxx_retouch.cc:598 -msgid "adjust image gamma" -msgstr "" - -#: fotoxx_retouch.cc:884 -msgid "Expand Brightness Range" -msgstr "Améliorer la plage de luminosité" - -#: fotoxx_retouch.cc:886 -msgid "bright pixels" -msgstr "Pixels lumineux" - -#: fotoxx_retouch.cc:1057 -msgid "Flatten Brightness Distribution" -msgstr "Distribution aplanie de la luminosité" - -#: fotoxx_retouch.cc:1071 -msgid "Flatten" -msgstr "Aplanir" - -#: fotoxx_retouch.cc:1333 -msgid "Ramp brightness across image" -msgstr "Corriger la luminosité dans des parties de l'image" - -#: fotoxx_retouch.cc:1757 -msgid "low" -msgstr "" - -#: fotoxx_retouch.cc:1759 -msgid "high" -msgstr "" - -#: fotoxx_retouch.cc:1762 -msgid "Amplify" -msgstr "" - -#: fotoxx_retouch.cc:2068 -msgid "Adjust White Balance" -msgstr "Ajuster la balance des blancs" - -#: fotoxx_retouch.cc:2069 -msgid "Click white or gray image location" -msgstr "Cliquez sur une couleur de l'image" - -#: fotoxx_retouch.cc:2283 -msgid "Color Match Images" -msgstr "" - -#: fotoxx_retouch.cc:2312 -msgid "mouse radius for color sample" -msgstr "" - -#: fotoxx_retouch.cc:2315 -msgid "image for source color" -msgstr "" - -#: fotoxx_retouch.cc:2317 -msgid "click on image to get source color" -msgstr "" - -#: fotoxx_retouch.cc:2320 -msgid "image to set matching color" -msgstr "" - -#: fotoxx_retouch.cc:2322 -msgid "click on image to set matching color" -msgstr "" - -#: fotoxx_retouch.cc:2377 -msgid "select source image color first" -msgstr "" - -#: fotoxx_retouch.cc:2903 fotoxx_tools.cc:1643 -msgid "Click image to select pixels." -msgstr "" - -#: fotoxx_retouch.cc:2955 -msgid "Metric:" -msgstr "" - -#: fotoxx_retouch.cc:3010 -msgid "Blend" -msgstr "" - -#: fotoxx_retouch.cc:3394 -msgid "" -"Method 1:\n" -" Left-click on red-eye to darken.\n" -"Method 2:\n" -" Drag down and right to enclose red-eye.\n" -" Left-click on red-eye to darken.\n" -"Undo red-eye:\n" -" Right-click on red-eye." -msgstr "" -"Méthode n°1 : \n" -"- Faites un clic-gauche sur l'œil rouge pour l'assombrir. \n" -"Méthode n°2 : \n" -"- Tirer le pointeur en bas vers la droite pour l'enfermer. \n" -"- Pour annuler : faite un clic-droit sur l'œil rouge." - -#: fotoxx_retouch.cc:3409 -msgid "Red Eye Reduction" -msgstr "Réduction des yeux rouges" - -#: fotoxx_retouch.cc:3850 -msgid "Set Blur Radius" -msgstr "Configurer le radius flou" - -#: fotoxx_retouch.cc:4084 -msgid "edge detection" -msgstr "Détection des bords" - -#: fotoxx_retouch.cc:4085 -msgid "cycles" -msgstr "Cycles" - -#: fotoxx_retouch.cc:4086 -msgid "reduce" -msgstr "Réduire" - -#: fotoxx_retouch.cc:4097 -msgid "unsharp mask" -msgstr "Masque flou" - -#: fotoxx_retouch.cc:4110 -msgid "brightness gradient" -msgstr "Gradient de luminosité" - -#: fotoxx_retouch.cc:4516 -msgid "" -" Press the reduce button to \n" -" reduce noise in small steps. \n" -" Use undo to start over." -msgstr "" -" Appuyer sur [Réduire] pour atténuer \n" -" le bruit par petites étapes. \n" -" Utilisez [Undo] pour annuler." - -#: fotoxx_retouch.cc:4527 -msgid "Noise Reduction" -msgstr "Réduction du bruit" - -#: fotoxx_retouch.cc:4532 -msgid "algorithm" -msgstr "Algorithme" - -#: fotoxx_retouch.cc:4539 -msgid "flatten outliers by color (1)" -msgstr "Aplanir les extrêmes par couleur (1)" - -#: fotoxx_retouch.cc:4540 -msgid "flatten outliers by color (2)" -msgstr "Aplanir les extrêmes par couleur (2)" - -#: fotoxx_retouch.cc:4541 -msgid "set median brightness by color" -msgstr "Ajuster la luminosité médiane par couleur" - -#: fotoxx_retouch.cc:4542 fotoxx_retouch.cc:4543 -msgid "top hat filter by color" -msgstr "Filtre TopHat par couleur" - -#: fotoxx_retouch.cc:4858 -msgid "" -"1. Drag mouse to select. \n" -"2. Erase. 3. Repeat. " -msgstr "" - -#: fotoxx_retouch.cc:4889 -msgid "Radius" -msgstr "Radius" - -#: fotoxx_retouch.cc:4891 -msgid "Blur" -msgstr "" - -#: fotoxx_retouch.cc:4894 -msgid "New Area" -msgstr "" - -#: fotoxx_retouch.cc:5275 -msgid "spot size limit" -msgstr "" - -#: fotoxx_retouch.cc:5278 -msgid "max. brightness" -msgstr "" - -#: fotoxx_retouch.cc:5281 -msgid "min. contrast" -msgstr "" - -#: fotoxx_retouch.cc:5875 -#, c-format -msgid "Undo Memory %d%c" -msgstr "Annuler la mémoire %d%c" - -#: fotoxx_retouch.cc:5884 -msgid "pick" -msgstr "Sélection" - -#: fotoxx_retouch.cc:5886 -msgid "erase" -msgstr "Supprimer" - -#: fotoxx_retouch.cc:5894 -msgid "paintbrush radius" -msgstr "Radius du pinceau" - -#: fotoxx_retouch.cc:5895 -msgid "transparency center" -msgstr "Centre de transparence" - -#: fotoxx_retouch.cc:5896 -msgid "transparency edge" -msgstr "Bord de transparence" - -#: fotoxx_retouch.cc:6166 -msgid "" -"Undo memory limit has been reached. \n" -"Save work with [done], then resume editing." -msgstr "" -"L'annulation de la limite de mémoire a été atteinte. \n" -"Enregistrer votre création avec le bouton [Ok], et résumer \n" -"ensuite la modification." - -#: fotoxx_tools.cc:42 -msgid "" -"When editing a collection, right-click \n" -"an image or thumbnail to add or remove." -msgstr "" - -#: fotoxx_tools.cc:85 -msgid "Start new collection" -msgstr "" - -#: fotoxx_tools.cc:87 -msgid "Edit a collection" -msgstr "" - -#: fotoxx_tools.cc:89 -msgid "View a collection" -msgstr "" - -#: fotoxx_tools.cc:91 -msgid "Delete a collection" -msgstr "" - -#: fotoxx_tools.cc:95 -msgid "Editing:" -msgstr "" - -#: fotoxx_tools.cc:99 -msgid "Action:" -msgstr "" - -#: fotoxx_tools.cc:133 -msgid "New Collection" -msgstr "" - -#: fotoxx_tools.cc:156 -msgid "Edit Collection" -msgstr "" - -#: fotoxx_tools.cc:172 -msgid "View Collection" -msgstr "" - -#: fotoxx_tools.cc:193 -msgid "Delete Collection" -msgstr "" - -#: fotoxx_tools.cc:196 -#, c-format -msgid "delete %s ?" -msgstr "" - -#: fotoxx_tools.cc:223 -#, c-format -msgid "add image to collection: %s" -msgstr "" - -#: fotoxx_tools.cc:225 fotoxx_tools.cc:270 -msgid "remove image from collection" -msgstr "" - -#: fotoxx_tools.cc:226 fotoxx_tools.cc:271 fotoxx_tools.cc:298 -msgid "remove and save image" -msgstr "" - -#: fotoxx_tools.cc:227 fotoxx_tools.cc:316 -msgid "insert saved images here" -msgstr "" - -#: fotoxx_tools.cc:256 -msgid "add image to collection" -msgstr "" - -#: fotoxx_tools.cc:301 -msgid "too many saved files" -msgstr "" - -#: fotoxx_tools.cc:375 -msgid "old top directory" -msgstr "" - -#: fotoxx_tools.cc:378 -msgid "new top directory" -msgstr "" - -#: fotoxx_tools.cc:434 -msgid "completed" -msgstr "Complété" - -#: fotoxx_tools.cc:452 -msgid "" -"Brightness should show a gradual ramp \n" -"extending all the way to the edges." -msgstr "" - -#: fotoxx_tools.cc:492 -msgid "Monitor Check" -msgstr "" - -#: fotoxx_tools.cc:612 -msgid "Brightness Distribution" -msgstr "Distribution de la luminosité" - -#: fotoxx_tools.cc:796 -msgid "Press ESC to exit slide show" -msgstr "" - -#: fotoxx_tools.cc:797 -msgid "show only latest file versions" -msgstr "" - -#: fotoxx_tools.cc:801 -msgid "arrow keys" -msgstr "Touche « flèches »" - -#: fotoxx_tools.cc:802 -msgid "instant" -msgstr "" - -#: fotoxx_tools.cc:803 -msgid "fade-in" -msgstr "" - -#: fotoxx_tools.cc:804 -msgid "roll-right" -msgstr "" - -#: fotoxx_tools.cc:805 -msgid "roll-down" -msgstr "" - -#: fotoxx_tools.cc:806 -msgid "shift-left" -msgstr "" - -#: fotoxx_tools.cc:807 -msgid "venetian" -msgstr "Vénitien" - -#: fotoxx_tools.cc:808 -msgid "grate" -msgstr "" - -#: fotoxx_tools.cc:811 -msgid "radar" -msgstr "" - -#: fotoxx_tools.cc:812 -msgid "jaws" -msgstr "" - -#: fotoxx_tools.cc:823 -msgid "seconds" -msgstr "Secondes" - -#: fotoxx_tools.cc:827 -msgid "music file" -msgstr "" - -#: fotoxx_tools.cc:831 -msgid "transitions" -msgstr "" - -#: fotoxx_tools.cc:948 -msgid "Select music file or playlist" -msgstr "" - -#: fotoxx_tools.cc:1971 -msgid "x-spacing" -msgstr "" - -#: fotoxx_tools.cc:1972 -msgid "x-count" -msgstr "" - -#: fotoxx_tools.cc:1973 -msgid "x-enable" -msgstr "" - -#: fotoxx_tools.cc:1979 -msgid "y-spacing" -msgstr "" - -#: fotoxx_tools.cc:1980 -msgid "y-count" -msgstr "" - -#: fotoxx_tools.cc:1981 -msgid "y-enable" -msgstr "" - -#: fotoxx_tools.cc:1988 -msgid "x-offset" -msgstr "" - -#: fotoxx_tools.cc:1992 -msgid "y-offset" -msgstr "" - -#: fotoxx_tools.cc:2146 -msgid "lens name" -msgstr "nom de la focale" - -#: fotoxx_tools.cc:2220 -msgid "Available Translations" -msgstr "Traductions disponibles" - -#: fotoxx_tools.cc:2224 -msgid "Set Language" -msgstr "Changer de langue" - -#: fotoxx_tools.cc:2290 -msgid "Make Launcher" -msgstr "" - -#: fotoxx_tools.cc:2310 -msgid "Program ufraw-batch is required" -msgstr "Le logiciel « ufraw-batch » est requis." - -#: fotoxx_tools.cc:2320 -msgid "Open RAW File" -msgstr "Ouvrir une image RAW" - -#: fotoxx_tools.cc:2331 -msgid "Select RAW files to convert" -msgstr "Sélectionner des fichiers RAW à convertir" - -#: fotoxx_tools.cc:2467 -msgid "max. width" -msgstr "Largeur max." - -#: fotoxx_tools.cc:2468 -msgid "max. height" -msgstr "Hauteur max." - -#: fotoxx_tools.cc:2527 fotoxx_transform.cc:1268 -#, c-format -msgid "max. size %d x %d is not reasonable" -msgstr "La taille max. « %d x %d » est trop grande" - -#: fotoxx_tools.cc:2613 -msgid "too many files" -msgstr "Trop de fichiers" - -#: fotoxx_tools.cc:2656 -msgid "Sync Files is already running" -msgstr "" - -#: fotoxx_tools.cc:2707 -msgid "" -"Run Tools > Synchronize Files so that gallery windows \n" -"will be fast and Search Images will work correctly. \n" -"You can view (not edit) images while synchronize runs." -msgstr "" - -#: fotoxx_tools.cc:2736 -msgid "no top image directory is defined" -msgstr "" - -#: fotoxx_tools.cc:2742 -msgid "top image directory is invalid" -msgstr "" - -#: fotoxx_tools.cc:2747 -msgid "no search index file is present" -msgstr "" - -#: fotoxx_tools.cc:2761 -msgid "new/modified files are present" -msgstr "" - -#: fotoxx_tools.cc:2768 -msgid "no new files found" -msgstr "" - -#: fotoxx_tools.cc:2785 -msgid "Top Image Directory:" -msgstr "Dossier d'images parent : " - -#: fotoxx_tools.cc:2807 -msgid "file sync is mandatory" -msgstr "" - -#: fotoxx_tools.cc:2817 -msgid "top directory is invalid" -msgstr "" - -#: fotoxx_tools.cc:3201 -msgid "Select top image directory" -msgstr "Sélectionner le dossier d'images racine" - -#: fotoxx_tools.cc:3378 -msgid "icons" -msgstr "" - -#: fotoxx_tools.cc:3379 fotoxx_transform.cc:1467 -msgid "text" -msgstr "" - -#: fotoxx_tools.cc:3380 -msgid "both" -msgstr "" - -#: fotoxx_transform.cc:50 -msgid "Use buttons or drag right edge with mouse" -msgstr "Utilisez les boutons ou glissez le bord droit avec la souris" - -#: fotoxx_transform.cc:64 -msgid "degrees" -msgstr "Degrés" - -#: fotoxx_transform.cc:80 fotoxx_transform.cc:124 -msgid "Trim" -msgstr "Rogner" - -#: fotoxx_transform.cc:81 fotoxx_transform.cc:2437 fotoxx_transform.cc:3263 -#: fotoxx_transform.cc:3526 fotoxx_transform.cc:3787 -msgid "Grid" -msgstr "" - -#: fotoxx_transform.cc:123 -msgid "Undo Trim" -msgstr "Annuler Rogner" - -#: fotoxx_transform.cc:139 -#, c-format -msgid "degrees: %.1f" -msgstr "Degrés :  %.1f" - -#: fotoxx_transform.cc:286 -msgid "gold" -msgstr "" - -#: fotoxx_transform.cc:332 -msgid "Drag middle to move, drag corners to resize." -msgstr "" -"Glissez le centre pour déplacer, glissez les coins pour redimensionner." - -#: fotoxx_transform.cc:346 -msgid "customize" -msgstr "Personnaliser" - -#: fotoxx_transform.cc:357 -msgid "ratio" -msgstr "" - -#: fotoxx_transform.cc:361 -msgid "Lock Ratio" -msgstr "Verrouiller les proportions" - -#: fotoxx_transform.cc:367 -msgid "invert" -msgstr "inverser" - -#: fotoxx_transform.cc:892 -msgid "Trim Buttons" -msgstr "" - -#: fotoxx_transform.cc:964 -msgid "Lock aspect ratio" -msgstr "Verrouiller les proportions" - -#: fotoxx_transform.cc:1145 -msgid "Batch Resize" -msgstr "Redimensionner par lot" - -#: fotoxx_transform.cc:1153 -msgid "new max. width" -msgstr "Nouvelle largeur max." - -#: fotoxx_transform.cc:1154 -msgid "new max. height" -msgstr "Nouvelle hauteur max." - -#: fotoxx_transform.cc:1161 -msgid "replace originals" -msgstr "Remplacer les originaux" - -#: fotoxx_transform.cc:1162 -msgid "export to location" -msgstr "Exporter vers l'emplacement" - -#: fotoxx_transform.cc:1166 -msgid "copy EXIF" -msgstr "Copier les données EXIF" - -#: fotoxx_transform.cc:1219 -msgid "Select directory" -msgstr "Sélectionner un dossier" - -#: fotoxx_transform.cc:1243 -#, c-format -msgid "replace original files? (max. %d x %d)" -msgstr "Remplacer les fichiers originaux ? (max. %d x %d)" - -#: fotoxx_transform.cc:1250 -#, c-format -msgid "" -"copy files? (max. %d x %d) \n" -" to location %s" -msgstr "" -"Copier les fichiers ? (max. %d x %d) \n" -"vers l'emplacement %s" - -#: fotoxx_transform.cc:1261 -msgid "location is not a valid directory" -msgstr "L'emplacement n'est pas un dossier valable" - -#: fotoxx_transform.cc:1304 -msgid "new file already exists" -msgstr "Un nouveau fichier existe toujours" - -#: fotoxx_transform.cc:1388 -msgid "" -"Enter text, click/drag on image.\n" -"Right click to remove" -msgstr "" -"Saisissez du texte, cliquez et glissez sur l'image.\n" -"Un clic-droit supprime le texte." - -#: fotoxx_transform.cc:1442 -msgid "Text" -msgstr "Texte" - -#: fotoxx_transform.cc:1449 -msgid "Size" -msgstr "Taille" - -#: fotoxx_transform.cc:1452 -msgid "Angle" -msgstr "Angle" - -#: fotoxx_transform.cc:1463 -msgid "Color" -msgstr "Couleur" - -#: fotoxx_transform.cc:1464 -msgid "Transparency" -msgstr "Transparence" - -#: fotoxx_transform.cc:1472 -msgid "backing" -msgstr "" - -#: fotoxx_transform.cc:1475 -msgid "" -"Outline\n" -" Width" -msgstr "" - -#: fotoxx_transform.cc:1477 -msgid "outline" -msgstr "" - -#: fotoxx_transform.cc:1486 -msgid "Annotation File:" -msgstr "Annoter le fichier" - -#: fotoxx_transform.cc:1564 -msgid "select font" -msgstr "Sélectionner la police" - -#: fotoxx_transform.cc:2197 fotoxx_transform.cc:2429 -msgid "horizontal" -msgstr "Horizontal" - -#: fotoxx_transform.cc:2198 fotoxx_transform.cc:2428 -msgid "vertical" -msgstr "Vertical" - -#: fotoxx_transform.cc:2306 -msgid "black/white positive" -msgstr "" - -#: fotoxx_transform.cc:2307 -msgid "black/white negative" -msgstr "" - -#: fotoxx_transform.cc:2308 -msgid "color positive" -msgstr "" - -#: fotoxx_transform.cc:2309 -msgid "color negative" -msgstr "" - -#: fotoxx_transform.cc:2430 -msgid "linear" -msgstr "" - -#: fotoxx_transform.cc:2433 -msgid "curved" -msgstr "" - -#: fotoxx_transform.cc:2692 -msgid "" -" Click the four corners of a tetragon area. Press [apply]. \n" -" The image is warped to make the tetragon into a rectangle." -msgstr "" - -#: fotoxx_transform.cc:2878 -msgid "must have 4 corners" -msgstr "" - -#: fotoxx_transform.cc:2999 -msgid "" -" Select an area to warp using select area function. \n" -" Press [start warp] and pull area with mouse. \n" -" Make multiple mouse pulls until satisfied. \n" -" When finished, select another area or press [done]." -msgstr "" -"Sélectionner une zone à déformer en utilisant dans \n" -"le menu Édition / Édition de la zone / Sélectionner une zone. \n" -"Appuyer sur [Commencer] et étirez la zone avec la souris. \n" -"Effectuez des déformations jusqu'à satisfaction. \n" -"Ensuite, sélectionnez une autre zone ou cliquez sur [Ok]." - -#: fotoxx_transform.cc:3018 -msgid "start warp" -msgstr "Commencer" - -#: fotoxx_transform.cc:3067 -msgid "Select area first" -msgstr "Sélectionnez une zone en premier." - -#: fotoxx_transform.cc:3242 fotoxx_transform.cc:3505 -msgid "" -" Pull an image position using the mouse. \n" -" Make multiple mouse pulls until satisfied. \n" -" When finished, press [done]." -msgstr "" -" Tirez l'image en utilisant la souris. \n" -" Effectuez plusieurs fois le processus \n" -" jusqu'à satisfaction et cliquez sur [Ok] \n" -" pour terminer." - -#: fotoxx_transform.cc:3771 -msgid "" -" Pull on an image corner using the mouse. \n" -" Make multiple mouse pulls until satisfied. \n" -" When finished, press [done]." -msgstr "" -"Tirez un bord de l'image en utilisant la souris. \n" -"Répétez plusieurs fois l'opération jusqu'à satisfaction. \n" -"Une fois terminé, appuyez sur [Ok]." - -#~ msgid "Translate" -#~ msgstr "Traduire" - -#~ msgid "full rebuild" -#~ msgstr "Reconstruction complète" - -#~ msgid "incremental" -#~ msgstr "Incrémental" - -#~ msgid "" -#~ "Rename failed \n" -#~ " %s" -#~ msgstr "" -#~ "Le renommage a échoué \n" -#~ " %s" - -#~ msgid "transition" -#~ msgstr "Transition" - -#~ msgid "Discard modifications?" -#~ msgstr "Annuler les modifications ?" - -#~ msgid "histogram" -#~ msgstr "Histogramme" - -#~ msgid "Edit Comments" -#~ msgstr "Modifier les commentaires" - -#~ msgid "Edit Caption" -#~ msgstr "Modifier la légende" - -#~ msgid "new tags index will now be created" -#~ msgstr "" -#~ "Le nouveau fichier d'indexation des étiquettes \n" -#~ "va maintenant être créé." - -#~ msgid "cannot read .dist file" -#~ msgstr "Impossible de lire le fichier .dist" - -#~ msgid "" -#~ "New tags file already exists! \n" -#~ "Proceed anyway?" -#~ msgstr "" -#~ "Le fichier des nouvelles étiquettes existe toujours ! \n" -#~ "Voulez vous continuer le processus ?" - -#~ msgid "" -#~ "Convert tags to new standard now? \n" -#~ "Are your image files backed-up?" -#~ msgstr "" -#~ "Convertir maintenant les étiquettes vers le nouveau standard ? \n" -#~ "Vos images sont-elles sauvegardées ?" - -#~ msgid "Convert tags to new standard" -#~ msgstr "Convertir les étiquettes vers le nouveau standard" - -#~ msgid "Convert Tags !!!" -#~ msgstr "Convertir les étiquettes !!!" - -#~ msgid "tags index file error: %s" -#~ msgstr "" -#~ "Le fichier d'indexation des étiquettes \n" -#~ "retourne une erreur : %s" - -#~ msgid "save select area as a file" -#~ msgstr "Enregistrer la zone sélectionnée en tant que fichier" - -#~ msgid "manage tags" -#~ msgstr "Gérer les étiquettes" - -#~ msgid "brightness to clip (percent)" -#~ msgstr "Luminosité à remplir (pourcentage)" - -#~ msgid "Use F1 for context help" -#~ msgstr "Utiliser F1 pour l'aide contextuel" - -#~ msgid "Stack" -#~ msgstr "Empiler" - -#~ msgid "Rebuild Tags Index" -#~ msgstr "Reconstruire l'index des étiquettes" - -#~ msgid "No tags index file" -#~ msgstr "Le fichier d'indexation des étiquettes n'existe pas." - -#~ msgid "HDR" -#~ msgstr "HDR" - -#~ msgid "HDF" -#~ msgstr "HDF" - -#~ msgid "Constrain" -#~ msgstr "Contraindre" - -#~ msgid "Area" -#~ msgstr "Zone" - -#~ msgid "target group area" -#~ msgstr "Zone du groupe cible" - -#~ msgid "vertical unbend" -#~ msgstr "Axe vertical" - -#~ msgid "select by mouse:" -#~ msgstr "Sélection avec la souris : " - -#~ msgid "select by color:" -#~ msgstr "Sélection par couleurs : " - -#~ msgid "press ESC to exit" -#~ msgstr "Appuyer sur « Échap » pour quitter" - -#~ msgid "horizontal unbend" -#~ msgstr "Axe horizontal" - -#~ msgid "Rebuild Thumbnails" -#~ msgstr "Reconstruire les miniatures" - -#~ msgid "Font Colors" -#~ msgstr "Couleur de la police" - -#~ msgid "area outline has a hole" -#~ msgstr "Le contour de la zone a un trou" - -#~ msgid "Create Launcher" -#~ msgstr "Créer un lanceur" - -#~ msgid "range" -#~ msgstr "Plage" - -#~ msgid "package libimage-exiftool-perl is required" -#~ msgstr "Le paquetage « libimage-exiftool-perl » est requis" - -#~ msgid "my mouse" -#~ msgstr "Ma souris" - -#~ msgid "limit" -#~ msgstr "Limiter" - -#~ msgid "Width" -#~ msgstr "Largeur" - -#~ msgid "Unknown file type, save as tiff/jpeg/png to edit" -#~ msgstr "" -#~ "Type de fichier inconnu. Enregistrez le au format TIFF/JPEG/PNG pour le " -#~ "modifier" - -#~ msgid "Undo Last" -#~ msgstr "Annul. préc." - -#~ msgid "Undo All" -#~ msgstr "Tout annuler" - -#~ msgid "Threshold" -#~ msgstr "Seuil" - -#~ msgid "Start" -#~ msgstr "Démarrer" - -#~ msgid "Select Files" -#~ msgstr "Sélectionner les fichiers" - -#~ msgid "Search" -#~ msgstr "Rechercher" - -#~ msgid "Reduce" -#~ msgstr "Réduire" - -#~ msgid "Red" -#~ msgstr "Rouge" - -#~ msgid "Proceed" -#~ msgstr "Traiter" - -#~ msgid "Presets" -#~ msgstr "Réglages" - -#~ msgid "Percent" -#~ msgstr "pourcentage" - -#~ msgid "Pause" -#~ msgstr "Pause" - -#~ msgid "OK" -#~ msgstr "Ok" - -#~ msgid "Lighter Areas" -#~ msgstr "Zones lumineuses" - -#~ msgid "Insert" -#~ msgstr "Insérer" - -#~ msgid "Height" -#~ msgstr "Hauteur" - -#~ msgid "Green" -#~ msgstr "Vert" - -#~ msgid "Font" -#~ msgstr "Police" - -#~ msgid "Finish" -#~ msgstr "Terminer" - -#~ msgid "Fetch" -#~ msgstr "Réception" - -#~ msgid "Edit" -#~ msgstr "Modifier" - -#~ msgid "Done" -#~ msgstr "Ok" - -#~ msgid "Darker Areas" -#~ msgstr "Zones sombres" - -#~ msgid "Clear" -#~ msgstr "Effacer" - -#~ msgid "Cancel" -#~ msgstr "Annuler" - -#~ msgid "Browse" -#~ msgstr "Naviguer" - -#~ msgid "Brightness" -#~ msgstr "Luminosité" - -#~ msgid "Blue" -#~ msgstr "Bleu" - -#~ msgid "Blend Width" -#~ msgstr "Largeur du mélange" - -#~ msgid "Apply" -#~ msgstr "Appliquer" - -#~ msgid "Amount" -#~ msgstr "Quantité" - -#~ msgid "Add All" -#~ msgstr "Tout ajouter" - -#~ msgid "make new version" -#~ msgstr "Créer une nouvelle version" - -#~ msgid "click on window to show RGB" -#~ msgstr "Cliquez sur la fenêtre pour afficher les couleurs RVB" - -#~ msgid "Save As" -#~ msgstr "Enreg. sous" - -#~ msgid "Clone fotoxx" -#~ msgstr "Cloner Fotoxx" - -#~ msgid "random" -#~ msgstr "Aléatoire" - -#~ msgid "Whole Image" -#~ msgstr "Toute l'image" - -#~ msgid "Time Interval" -#~ msgstr "Intervalle de temps" - -#~ msgid "Delete" -#~ msgstr "Supprimer" diff -Nru fotoxx-11.11.1/locales/fr/zfuncs.po fotoxx-12.01.2/locales/fr/zfuncs.po --- fotoxx-11.11.1/locales/fr/zfuncs.po 2011-11-05 05:30:37.000000000 +0000 +++ fotoxx-12.01.2/locales/fr/zfuncs.po 1970-01-01 00:00:00.000000000 +0000 @@ -1,294 +0,0 @@ -# translation of zfuncs.po to français -# Stanislas Zeller , 2009, 2010. -msgid "" -msgstr "" -"Project-Id-Version: zfuncs\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2011-11-05 05:49+0100\n" -"PO-Revision-Date: 2010-02-01 19:56+0100\n" -"Last-Translator: \n" -"Language-Team: French \n" -"Language: fr\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n > 1);\n" -"X-Generator: Lokalize 0.3\n" - -#: zfuncs.cc:3192 -#, c-format -msgid "help file not found: %s" -msgstr "impossible de trouver le fichier d'aide : %s" - -#: zfuncs.cc:3296 -#, c-format -msgid "error: %s" -msgstr "Erreur : %s" - -#: zfuncs.cc:4415 zfuncs.cc:8771 -#, c-format -msgid "cannot open file %s" -msgstr "Impossible d'ouvrir le fichier %s" - -#: zfuncs.cc:4448 -msgid "save screen to file" -msgstr "Enregistrer l'écran dans un fichier" - -#: zfuncs.cc:6198 -msgid "No" -msgstr "" - -#: zfuncs.cc:6198 -msgid "Yes" -msgstr "" - -#: zfuncs.cc:6272 zfuncs.cc:6308 zfuncs.cc:6461 zfuncs.cc:6865 zfuncs.cc:8358 -#: zfuncs.cc:8883 zfuncs.cc:8889 zfuncs.cc:8895 zfuncs.cc:8901 -msgid "cancel" -msgstr "Annuler" - -#: zfuncs.cc:6423 zfuncs.cc:7552 -msgid "open" -msgstr "Ouvrir" - -#: zfuncs.cc:6428 -msgid "choose" -msgstr "" - -#: zfuncs.cc:6433 -msgid "save" -msgstr "Enregistrer" - -#: zfuncs.cc:6439 -msgid "open folder" -msgstr "Ouvrir" - -#: zfuncs.cc:6444 -msgid "create folder" -msgstr "Créer un dossier" - -#: zfuncs.cc:6450 -msgid "hidden" -msgstr "Caché" - -#: zfuncs.cc:6454 -msgid "quality" -msgstr "Qualité" - -#: zfuncs.cc:6511 -msgid "JPG quality 0-100" -msgstr "Qualité JPG 0-100" - -#: zfuncs.cc:6865 zfuncs.cc:8358 -msgid "done" -msgstr "Terminé" - -#: zfuncs.cc:6865 zfuncs.cc:6878 -msgid "margins" -msgstr "" - -#: zfuncs.cc:6874 -msgid "top" -msgstr "" - -#: zfuncs.cc:6875 -msgid "bottom" -msgstr "" - -#: zfuncs.cc:6876 -msgid "left" -msgstr "" - -#: zfuncs.cc:6877 -msgid "right" -msgstr "" - -#: zfuncs.cc:7278 zfuncs.cc:7532 zfuncs.cc:7670 zfuncs.cc:7671 zfuncs.cc:7673 -msgid "bigger" -msgstr "Plus gros" - -#: zfuncs.cc:7278 -msgid "increase thumbnail size" -msgstr "Augmenter la taille des miniatures" - -#: zfuncs.cc:7279 -msgid "reduce thumbnail size" -msgstr "Réduire la taille des miniatures" - -#: zfuncs.cc:7279 zfuncs.cc:7542 zfuncs.cc:7672 zfuncs.cc:7674 -msgid "smaller" -msgstr "Plus petit" - -#: zfuncs.cc:7280 zfuncs.cc:7571 -msgid "parent" -msgstr "" - -#: zfuncs.cc:7280 -msgid "parent directory" -msgstr "" - -#: zfuncs.cc:7281 zfuncs.cc:7589 zfuncs.cc:7681 -msgid "first page" -msgstr "Première page" - -#: zfuncs.cc:7281 -msgid "jump to first file" -msgstr "Aller au premier fichier" - -#: zfuncs.cc:7282 zfuncs.cc:7587 zfuncs.cc:7676 zfuncs.cc:7683 -msgid "prev page" -msgstr "Page précé." - -#: zfuncs.cc:7282 -msgid "previous page" -msgstr "Page précédente" - -#: zfuncs.cc:7283 zfuncs.cc:7585 zfuncs.cc:7678 -msgid "prev row" -msgstr "Ligne précé." - -#: zfuncs.cc:7283 -msgid "previous row" -msgstr "Ligne précédente" - -#: zfuncs.cc:7284 zfuncs.cc:7586 zfuncs.cc:7679 -msgid "next row" -msgstr "Ligne suiv." - -#: zfuncs.cc:7285 zfuncs.cc:7588 zfuncs.cc:7677 zfuncs.cc:7684 -msgid "next page" -msgstr "Page suiv." - -#: zfuncs.cc:7286 -msgid "jump to last file" -msgstr "Aller au dernier fichier" - -#: zfuncs.cc:7286 zfuncs.cc:7590 zfuncs.cc:7682 -msgid "last page" -msgstr "Dernière page" - -#: zfuncs.cc:7287 zfuncs.cc:7527 -msgid "close" -msgstr "Fermer" - -#: zfuncs.cc:7287 -msgid "close image gallery" -msgstr "Fermer la fenêtre des miniatures" - -#: zfuncs.cc:7558 -msgid "select new file" -msgstr "Sélectionner un nouveau fichier" - -#: zfuncs.cc:8358 -msgid "Select Files" -msgstr "" - -#: zfuncs.cc:8366 -msgid "delete" -msgstr "" - -#: zfuncs.cc:8367 -msgid "insert" -msgstr "" - -#: zfuncs.cc:8368 -msgid "add all" -msgstr "" - -#: zfuncs.cc:8658 -msgid "" -"Initial parameters file created. \n" -"Inspect and revise if necessary." -msgstr "" -"Le fichier des paramètres initiaux a été crée. \n" -"Vérifier et corriger si nécessaire." - -#: zfuncs.cc:8674 -msgid "load parameters from a file" -msgstr "Charger les paramètres à partir d'un fichier" - -#: zfuncs.cc:8743 -msgid "save parameters to a file" -msgstr "Enregistrer les paramètres dans un fichier" - -#: zfuncs.cc:8881 zfuncs.cc:8887 zfuncs.cc:8893 zfuncs.cc:8899 -msgid "edit parameters" -msgstr "Éditer les paramètres" - -#: zfuncs.cc:8882 zfuncs.cc:8888 -msgid "" -"list\n" -"all" -msgstr "" -"Lister\n" -"Tous" - -#: zfuncs.cc:8882 zfuncs.cc:8888 zfuncs.cc:8894 zfuncs.cc:8900 -msgid "" -"load\n" -"file" -msgstr "" -"Charger\n" -"Fichier" - -#: zfuncs.cc:8882 zfuncs.cc:8888 zfuncs.cc:8894 zfuncs.cc:8900 -msgid "" -"save\n" -"file" -msgstr "" -"Enreg.\n" -"Fichier" - -#: zfuncs.cc:8883 zfuncs.cc:8895 -msgid "" -"add\n" -"new" -msgstr "" -"Ajouter\n" -"Nouveau" - -#: zfuncs.cc:8883 zfuncs.cc:8889 zfuncs.cc:8895 zfuncs.cc:8901 -msgid "apply" -msgstr "Appliquer" - -#: zfuncs.cc:8935 -msgid "apply?" -msgstr "Appliquer ?" - -#: zfuncs.cc:8992 -msgid "(new parm name)" -msgstr "(Nouveaux paramètres)" - -#: zfuncs.cc:8992 -msgid "add parameter" -msgstr "Ajouter le paramètre" - -#~ msgid "print" -#~ msgstr "Imprimer" - -#~ msgid "printer ID" -#~ msgstr "ID de l'imprimante" - -#~ msgid "paper format" -#~ msgstr "Format de papier" - -#~ msgid "portrait" -#~ msgstr "Portrait" - -#~ msgid "landscape" -#~ msgstr "Paysage" - -#~ msgid "paper format is crazy" -#~ msgstr "Format de papier erroné" - -#~ msgid "open a file" -#~ msgstr "Ouvrir un fichier" - -#~ msgid "select new folder" -#~ msgstr "Sélectionner un nouveau dossier" - -#~ msgid "open a directory" -#~ msgstr "Ouvrir un dossier" - -#~ msgid "folder" -#~ msgstr "Dossier" diff -Nru fotoxx-11.11.1/locales/gl/fotoxx.po fotoxx-12.01.2/locales/gl/fotoxx.po --- fotoxx-11.11.1/locales/gl/fotoxx.po 2011-11-05 05:30:37.000000000 +0000 +++ fotoxx-12.01.2/locales/gl/fotoxx.po 1970-01-01 00:00:00.000000000 +0000 @@ -1,2773 +0,0 @@ -# Galician translations for home package. -# Copyright (C) 2008 THE home'S COPYRIGHT HOLDER -# This file is distributed under the same license as the home package. -# mico , 2008. -# -msgid "" -msgstr "" -"Project-Id-Version: fotoxx-6.9.2\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2011-11-05 05:49+0100\n" -"PO-Revision-Date: 2009-11-04 23:34+0100\n" -"Last-Translator: Miguel Anxo Bouzada \n" -"Language-Team: GALPon MiniNo \n" -"Language: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Poedit-Language: Galician\n" -"X-Poedit-Country: SPAIN\n" - -#: fotoxx-11.11.1.cc:179 -msgid "File" -msgstr "Ficheiro" - -#: fotoxx-11.11.1.cc:180 fotoxx-11.11.1.cc:316 -msgid "Image Gallery" -msgstr "Galería de imaxes" - -#: fotoxx-11.11.1.cc:181 -msgid "Clone 50/50" -msgstr "" - -#: fotoxx-11.11.1.cc:182 -msgid "Clone Overlay" -msgstr "" - -#: fotoxx-11.11.1.cc:183 fotoxx-11.11.1.cc:317 fotoxx-11.11.1.cc:2272 -#: fotoxx-11.11.1.cc:2444 -msgid "Open Image File" -msgstr "Abrir ficheiro de imaxe" - -#: fotoxx-11.11.1.cc:184 -msgid "Open in New Window" -msgstr "" - -#: fotoxx-11.11.1.cc:185 fotoxx-11.11.1.cc:318 -msgid "Open Previous File" -msgstr "Abrir o ficheiro anterior" - -#: fotoxx-11.11.1.cc:186 -msgid "Open Recent File" -msgstr "Abrir ficheiro recente" - -#: fotoxx-11.11.1.cc:187 fotoxx-11.11.1.cc:326 -msgid "Save to Same File" -msgstr "Gardar no mesmo ficheiro" - -#: fotoxx-11.11.1.cc:188 fotoxx-11.11.1.cc:327 -msgid "Save to New Version" -msgstr "" - -#: fotoxx-11.11.1.cc:189 fotoxx-11.11.1.cc:328 -msgid "Save to New File" -msgstr "Gardar nun ficheiro novo" - -#: fotoxx-11.11.1.cc:190 fotoxx-11.11.1.cc:2990 -msgid "Create Blank Image" -msgstr "" - -#: fotoxx-11.11.1.cc:191 -msgid "Trash Image File" -msgstr "Mover imaxe ao lixo" - -#: fotoxx-11.11.1.cc:192 fotoxx-11.11.1.cc:3216 -msgid "Rename Image File" -msgstr "Renomear ficheiro de imaxe" - -#: fotoxx-11.11.1.cc:193 -msgid "Batch Rename Files" -msgstr "" - -#: fotoxx-11.11.1.cc:194 -msgid "Print Image File" -msgstr "Imprimir ficheiro de imaxe" - -#: fotoxx-11.11.1.cc:195 fotoxx-11.11.1.cc:332 -msgid "Quit fotoxx" -msgstr "Saír de Fotoxx" - -#: fotoxx-11.11.1.cc:197 -msgid "Tools" -msgstr "Ferramentas" - -#: fotoxx-11.11.1.cc:198 fotoxx_tools.cc:70 -msgid "Manage Collections" -msgstr "" - -#: fotoxx-11.11.1.cc:199 fotoxx_tools.cc:373 -msgid "Move Collections" -msgstr "" - -#: fotoxx-11.11.1.cc:200 -msgid "Check Monitor" -msgstr "Comprobar monitor" - -#: fotoxx-11.11.1.cc:201 fotoxx_tools.cc:550 -msgid "Monitor Gamma" -msgstr "" - -#: fotoxx-11.11.1.cc:202 -msgid "Brightness Graph" -msgstr "Gráfica de brillo" - -#: fotoxx-11.11.1.cc:203 fotoxx_tools.cc:819 -msgid "Slide Show" -msgstr "Diaporama" - -#: fotoxx-11.11.1.cc:204 fotoxx_tools.cc:1668 -msgid "Show RGB" -msgstr "Amosar RGB" - -#: fotoxx-11.11.1.cc:205 fotoxx_tools.cc:1962 -msgid "Grid Lines" -msgstr "" - -#: fotoxx-11.11.1.cc:206 fotoxx_tools.cc:2135 -msgid "Lens Parameters" -msgstr "Parámetros da óptica" - -#: fotoxx-11.11.1.cc:207 -msgid "Change Language" -msgstr "Cambiar o idioma" - -#: fotoxx-11.11.1.cc:209 -msgid "Add Menu and Launcher" -msgstr "" - -#: fotoxx-11.11.1.cc:210 -msgid "Convert RAW files" -msgstr "" - -#: fotoxx-11.11.1.cc:211 -msgid "Burn Images to CD/DVD" -msgstr "Gravar imaxes nun CD/DVD" - -#: fotoxx-11.11.1.cc:212 fotoxx_tools.cc:2460 -msgid "E-mail Images" -msgstr "" - -#: fotoxx-11.11.1.cc:213 fotoxx_tools.cc:2783 -msgid "Synchronize Files" -msgstr "" - -#: fotoxx-11.11.1.cc:214 fotoxx_tools.cc:3376 -msgid "Toolbar Style" -msgstr "" - -#: fotoxx-11.11.1.cc:215 -msgid "Memory Usage" -msgstr "" - -#: fotoxx-11.11.1.cc:218 -msgid "Edit Caption/Comments" -msgstr "" - -#: fotoxx-11.11.1.cc:219 fotoxx_info.cc:156 -msgid "Edit Tags" -msgstr "Editar etiquetas" - -#: fotoxx-11.11.1.cc:220 fotoxx_info.cc:345 -msgid "Manage Tags" -msgstr "" - -#: fotoxx-11.11.1.cc:221 fotoxx_info.cc:1345 -msgid "Batch Add Tags" -msgstr "" - -#: fotoxx-11.11.1.cc:222 fotoxx_info.cc:1547 -msgid "Batch Delete Tag" -msgstr "" - -#: fotoxx-11.11.1.cc:223 -msgid "View Info (short)" -msgstr "" - -#: fotoxx-11.11.1.cc:224 -msgid "View Info (long)" -msgstr "" - -#: fotoxx-11.11.1.cc:225 fotoxx_info.cc:1883 -msgid "Edit Info" -msgstr "" - -#: fotoxx-11.11.1.cc:226 fotoxx_info.cc:1981 -msgid "Delete Info" -msgstr "" - -#: fotoxx-11.11.1.cc:227 -#, fuzzy -msgid "Search Images" -msgstr "Buscar etiquetas" - -#: fotoxx-11.11.1.cc:229 fotoxx-11.11.1.cc:230 -msgid "Select" -msgstr "" - -#: fotoxx-11.11.1.cc:231 -msgid "Show" -msgstr "Amosar" - -#: fotoxx-11.11.1.cc:232 -msgid "Hide" -msgstr "Agochar" - -#: fotoxx-11.11.1.cc:233 -msgid "Enable" -msgstr "" - -#: fotoxx-11.11.1.cc:234 -msgid "Disable" -msgstr "" - -#: fotoxx-11.11.1.cc:235 -msgid "Invert" -msgstr "Inverter" - -#: fotoxx-11.11.1.cc:236 -msgid "Unselect" -msgstr "" - -#: fotoxx-11.11.1.cc:237 -msgid "Copy" -msgstr "" - -#: fotoxx-11.11.1.cc:238 -msgid "Paste" -msgstr "" - -#: fotoxx-11.11.1.cc:239 fotoxx-11.11.1.cc:317 fotoxx_retouch.cc:2314 -#: fotoxx_retouch.cc:2319 -msgid "Open" -msgstr "Abrir" - -#: fotoxx-11.11.1.cc:240 fotoxx-11.11.1.cc:326 -msgid "Save" -msgstr "Gardar" - -#: fotoxx-11.11.1.cc:241 fotoxx_area.cc:2215 -msgid "Select Whole Image" -msgstr "" - -#: fotoxx-11.11.1.cc:242 -msgid "Select and Edit" -msgstr "" - -#: fotoxx-11.11.1.cc:244 -msgid "Transform" -msgstr "" - -#: fotoxx-11.11.1.cc:245 fotoxx_transform.cc:60 -msgid "Rotate Image" -msgstr "Xirar a imaxe" - -#: fotoxx-11.11.1.cc:246 fotoxx_transform.cc:346 -msgid "Trim Image" -msgstr "Recortar a imaxe" - -#: fotoxx-11.11.1.cc:247 fotoxx_transform.cc:972 -msgid "Resize Image" -msgstr "Redimensionar a imaxe" - -#: fotoxx-11.11.1.cc:248 -msgid "Batch Resize/Export" -msgstr "" - -#: fotoxx-11.11.1.cc:249 fotoxx_transform.cc:1436 -msgid "Annotate Image" -msgstr "" - -#: fotoxx-11.11.1.cc:250 fotoxx_transform.cc:2193 -msgid "Flip Image" -msgstr "" - -#: fotoxx-11.11.1.cc:251 fotoxx_transform.cc:2303 -msgid "Make Negative" -msgstr "" - -#: fotoxx-11.11.1.cc:252 fotoxx_transform.cc:2420 -msgid "Unbend Image" -msgstr "Endereitar a imaxe" - -#: fotoxx-11.11.1.cc:253 fotoxx_transform.cc:2704 -msgid "Keystone Correction" -msgstr "" - -#: fotoxx-11.11.1.cc:254 fotoxx_transform.cc:3013 -msgid "Warp Image (area)" -msgstr "" - -#: fotoxx-11.11.1.cc:255 fotoxx_transform.cc:3255 -msgid "Warp Image (curved)" -msgstr "" - -#: fotoxx-11.11.1.cc:256 fotoxx_transform.cc:3518 -msgid "Warp Image (linear)" -msgstr "" - -#: fotoxx-11.11.1.cc:257 fotoxx_transform.cc:3782 -msgid "Warp Image (affine)" -msgstr "" - -#: fotoxx-11.11.1.cc:259 -msgid "Retouch" -msgstr "Retocar" - -#: fotoxx-11.11.1.cc:260 -msgid "Brightness/Color" -msgstr "Axustar brillo e cor" - -#: fotoxx-11.11.1.cc:261 -msgid "Gamma Curves" -msgstr "" - -#: fotoxx-11.11.1.cc:262 -msgid "Expand Brightness" -msgstr "" - -#: fotoxx-11.11.1.cc:263 -msgid "Flatten Brightness" -msgstr "Distribuir o brillo uniformemente" - -#: fotoxx-11.11.1.cc:264 -msgid "Brightness Ramp" -msgstr "" - -#: fotoxx-11.11.1.cc:265 fotoxx_retouch.cc:1729 -msgid "Tone Mapping" -msgstr "" - -#: fotoxx-11.11.1.cc:266 -msgid "White Balance" -msgstr "Balance de branco" - -#: fotoxx-11.11.1.cc:267 -msgid "Match Colors" -msgstr "" - -#: fotoxx-11.11.1.cc:269 fotoxx_retouch.cc:2941 -msgid "Revise RGB" -msgstr "" - -#: fotoxx-11.11.1.cc:270 -msgid "Red Eyes" -msgstr "Ollos vermellos" - -#: fotoxx-11.11.1.cc:271 -msgid "Blur Image" -msgstr "Imaxe borrosa" - -#: fotoxx-11.11.1.cc:272 fotoxx_retouch.cc:4077 -msgid "Sharpen Image" -msgstr "Enfocar a imaxe" - -#: fotoxx-11.11.1.cc:273 -msgid "Reduce Noise" -msgstr "Redución de ruido" - -#: fotoxx-11.11.1.cc:274 fotoxx_retouch.cc:4881 -msgid "Smart Erase" -msgstr "" - -#: fotoxx-11.11.1.cc:275 fotoxx_retouch.cc:5271 -msgid "Remove Dust" -msgstr "" - -#: fotoxx-11.11.1.cc:276 fotoxx_retouch.cc:5877 -msgid "Edit Pixels" -msgstr "Editar píxeles" - -#: fotoxx-11.11.1.cc:278 -msgid "Art" -msgstr "Arte" - -#: fotoxx-11.11.1.cc:279 -msgid "Color Depth" -msgstr "Profundidade da cor" - -#: fotoxx-11.11.1.cc:280 -msgid "Drawing" -msgstr "" - -#: fotoxx-11.11.1.cc:281 -msgid "Outlines" -msgstr "" - -#: fotoxx-11.11.1.cc:282 -msgid "Embossing" -msgstr "" - -#: fotoxx-11.11.1.cc:283 -msgid "Tiles" -msgstr "" - -#: fotoxx-11.11.1.cc:284 -msgid "Dots" -msgstr "" - -#: fotoxx-11.11.1.cc:285 -msgid "Painting" -msgstr "" - -#: fotoxx-11.11.1.cc:287 -msgid "Combine" -msgstr "Combinar" - -#: fotoxx-11.11.1.cc:288 -msgid "High Dynamic Range" -msgstr "" - -#: fotoxx-11.11.1.cc:289 -msgid "High Depth of Field" -msgstr "" - -#: fotoxx-11.11.1.cc:290 -msgid "Stack / Paint" -msgstr "" - -#: fotoxx-11.11.1.cc:291 -msgid "Stack / Noise" -msgstr "" - -#: fotoxx-11.11.1.cc:292 -msgid "Panorama" -msgstr "Panoramica" - -#: fotoxx-11.11.1.cc:293 -msgid "Vertical Panorama" -msgstr "" - -#: fotoxx-11.11.1.cc:296 -msgid "Edit Plugins" -msgstr "" - -#: fotoxx-11.11.1.cc:305 fotoxx-11.11.1.cc:333 fotoxx-11.11.1.cc:4616 -msgid "Help" -msgstr "Axuda" - -#: fotoxx-11.11.1.cc:306 fotoxx-11.11.1.cc:4606 -msgid "About" -msgstr "Acerca de..." - -#: fotoxx-11.11.1.cc:307 fotoxx-11.11.1.cc:4610 -msgid "User Guide" -msgstr "Guía do usuario" - -#: fotoxx-11.11.1.cc:308 fotoxx-11.11.1.cc:4613 -msgid "User Guide Changes" -msgstr "" - -#: fotoxx-11.11.1.cc:309 fotoxx-11.11.1.cc:4622 -msgid "Edit Functions Summary" -msgstr "" - -#: fotoxx-11.11.1.cc:310 fotoxx-11.11.1.cc:4625 -msgid "Change Log" -msgstr "Editar o rexistro" - -#: fotoxx-11.11.1.cc:311 fotoxx-11.11.1.cc:4628 -msgid "Translations" -msgstr "" - -#: fotoxx-11.11.1.cc:312 fotoxx-11.11.1.cc:4631 -msgid "Home Page" -msgstr "Páxina de inicio" - -#: fotoxx-11.11.1.cc:316 -msgid "Gallery" -msgstr "Galería" - -#: fotoxx-11.11.1.cc:318 fotoxx_transform.cc:995 -msgid "Prev" -msgstr "Anterior" - -#: fotoxx-11.11.1.cc:319 -msgid "Next" -msgstr "Seguinte" - -#: fotoxx-11.11.1.cc:319 -msgid "Open Next File" -msgstr "Abrir o ficheiro seguinte" - -#: fotoxx-11.11.1.cc:320 -msgid "Zoom-in (bigger)" -msgstr "Zoom ampliar" - -#: fotoxx-11.11.1.cc:321 -msgid "Zoom-out (smaller)" -msgstr "Zoom reducir" - -#: fotoxx-11.11.1.cc:322 -msgid "Undo" -msgstr "Desfacer" - -#: fotoxx-11.11.1.cc:322 -msgid "Undo One Edit" -msgstr "Desfacer un paso" - -#: fotoxx-11.11.1.cc:323 -msgid "Redo" -msgstr "Refacer" - -#: fotoxx-11.11.1.cc:323 -msgid "Redo One Edit" -msgstr "Refacer un paso" - -#: fotoxx-11.11.1.cc:327 -msgid "Save+V" -msgstr "" - -#: fotoxx-11.11.1.cc:328 -msgid "Save+F" -msgstr "" - -#: fotoxx-11.11.1.cc:329 -msgid "Move Image to Trash" -msgstr "Enviar a imaxe ao lixo" - -#: fotoxx-11.11.1.cc:329 -msgid "Trash" -msgstr "Lixo" - -#: fotoxx-11.11.1.cc:332 -msgid "Quit" -msgstr "Sair" - -#: fotoxx-11.11.1.cc:333 -msgid "Fotoxx Essentials" -msgstr "" - -#: fotoxx-11.11.1.cc:429 -msgid "first time startup" -msgstr "" - -#: fotoxx-11.11.1.cc:1815 -msgid "Exceed 50 anchor points" -msgstr "Excédense os 50 puntos de ancoraxe" - -#: fotoxx-11.11.1.cc:2000 -msgid "load curve from a file" -msgstr "" - -#: fotoxx-11.11.1.cc:2053 -msgid "curve file is invalid" -msgstr "" - -#: fotoxx-11.11.1.cc:2058 -msgid "curve file has different no. of curves" -msgstr "" - -#: fotoxx-11.11.1.cc:2073 -msgid "save curve to a file" -msgstr "" - -#: fotoxx-11.11.1.cc:2420 -#, c-format -msgid "" -"Discard special gallery list? \n" -" %s" -msgstr "" - -#: fotoxx-11.11.1.cc:2430 fotoxx-11.11.1.cc:4452 -msgid "prior function still active" -msgstr "" - -#: fotoxx-11.11.1.cc:2607 -msgid "Overwrite original file?" -msgstr "" - -#: fotoxx-11.11.1.cc:2608 -msgid "Do not warn again" -msgstr "" - -#: fotoxx-11.11.1.cc:2624 -msgid "Warning" -msgstr "" - -#: fotoxx-11.11.1.cc:2747 -msgid "Save File" -msgstr "Gardar o ficheiro" - -#: fotoxx-11.11.1.cc:2770 -msgid "quality" -msgstr "" - -#: fotoxx-11.11.1.cc:2772 -msgid "make current" -msgstr "" - -#: fotoxx-11.11.1.cc:2829 -msgid "jpeg quality must be 1-100" -msgstr "" - -#: fotoxx-11.11.1.cc:2851 -#, c-format -msgid "" -"Overwrite file? \n" -" %s" -msgstr "" -"Sobrescribir ficheiro? \n" -" %s" - -#: fotoxx-11.11.1.cc:2992 -msgid "file name" -msgstr "" - -#: fotoxx-11.11.1.cc:2997 fotoxx_transform.cc:351 -msgid "width" -msgstr "" - -#: fotoxx-11.11.1.cc:3000 fotoxx_transform.cc:354 -msgid "height" -msgstr "" - -#: fotoxx-11.11.1.cc:3006 fotoxx_art.cc:628 fotoxx_retouch.cc:5881 -msgid "color" -msgstr "Cor" - -#: fotoxx-11.11.1.cc:3120 -msgid "" -"Linux standard trash is not supported. \n" -"Desktop trash folder will be created." -msgstr "" - -#: fotoxx-11.11.1.cc:3138 -msgid "Move read-only file to trash?" -msgstr "Enviar o ficheiro de só lectura ao lixo?" - -#: fotoxx-11.11.1.cc:3164 -#, c-format -msgid "Cannot create trash folder: %s" -msgstr "Non se pode crear o cesto do lixo: %s" - -#: fotoxx-11.11.1.cc:3172 fotoxx-11.11.1.cc:3178 -#, c-format -msgid "error: %s" -msgstr "erro: %s" - -#: fotoxx-11.11.1.cc:3221 -msgid "old name" -msgstr "Nome antigo" - -#: fotoxx-11.11.1.cc:3222 -msgid "rename to" -msgstr "Renomear como" - -#: fotoxx-11.11.1.cc:3223 -msgid "previous" -msgstr "Anterior" - -#: fotoxx-11.11.1.cc:3309 -msgid "The target file already exists" -msgstr "O ficheiro de destino xa existe" - -#: fotoxx-11.11.1.cc:3317 -#, c-format -msgid "" -"Rename failed: \n" -" %s" -msgstr "" - -#: fotoxx-11.11.1.cc:3365 -msgid "Batch Rename" -msgstr "" - -#: fotoxx-11.11.1.cc:3368 fotoxx-11.11.1.cc:3420 fotoxx_info.cc:1513 -#: fotoxx_info.cc:1767 fotoxx_tools.cc:2510 fotoxx_transform.cc:1213 -#, c-format -msgid "%d files selected" -msgstr "" - -#: fotoxx-11.11.1.cc:3370 -msgid "new base name" -msgstr "" - -#: fotoxx-11.11.1.cc:3373 -msgid "starting sequence" -msgstr "" - -#: fotoxx-11.11.1.cc:3375 -msgid "increment" -msgstr "" - -#: fotoxx-11.11.1.cc:3396 -msgid "select files to rename" -msgstr "" - -#: fotoxx-11.11.1.cc:3401 -msgid "base name / sequence / increment not reasonable" -msgstr "" - -#: fotoxx-11.11.1.cc:3460 -msgid "new file already exists:" -msgstr "" - -#: fotoxx-11.11.1.cc:3468 -msgid "filespec too long:" -msgstr "" - -#: fotoxx-11.11.1.cc:3479 -msgid "Rename failed:" -msgstr "" - -#: fotoxx-11.11.1.cc:3739 -msgid "Add" -msgstr "" - -#: fotoxx-11.11.1.cc:3739 -msgid "Remove" -msgstr "" - -#: fotoxx-11.11.1.cc:3741 -msgid "menu name" -msgstr "" - -#: fotoxx-11.11.1.cc:3812 fotoxx-11.11.1.cc:3833 -msgid "Restart Fotoxx to update plugin menu" -msgstr "" - -#: fotoxx-11.11.1.cc:3927 -msgid "cannot parallel edit" -msgstr "" - -#: fotoxx-11.11.1.cc:3937 -msgid "" -"exiftool is not installed \n" -"edited images will lose EXIF data" -msgstr "" -"O paquete «exiftool» non está instalado \n" -"ao editar as imaxes perderánse os datos EXIF" - -#: fotoxx-11.11.1.cc:3943 -msgid "Too many edits, please save image" -msgstr "" - -#: fotoxx-11.11.1.cc:3948 -msgid "" -"Select area cannot be kept.\n" -"Continue?" -msgstr "" -"Non se pode conservar a selección de área.\n" -"Continuar?" - -#: fotoxx-11.11.1.cc:3956 -msgid "" -"Select area not active.\n" -"Continue?" -msgstr "" - -#: fotoxx-11.11.1.cc:4427 -msgid "Discard edits?" -msgstr "" - -#: fotoxx-11.11.1.cc:4428 -msgid "" -"This action will discard current edits.\n" -"Continue to discard edits.\n" -"Go Back to keep edits." -msgstr "" - -#: fotoxx-11.11.1.cc:4431 -msgid "Continue" -msgstr "" - -#: fotoxx-11.11.1.cc:4432 -msgid "Go Back" -msgstr "" - -#: fotoxx-11.11.1.cc:5240 -msgid "cannot open thumbnail file" -msgstr "" - -#: fotoxx-11.11.1.cc:5433 fotoxx-11.11.1.cc:5549 -msgid "TIFF open failure" -msgstr "" - -#: fotoxx-11.11.1.cc:5449 -#, c-format -msgid "TIFF bits/color=%d not supported" -msgstr "" - -#: fotoxx-11.11.1.cc:5464 fotoxx-11.11.1.cc:5502 -msgid "TIFF read failure" -msgstr "" - -#: fotoxx-11.11.1.cc:5608 -msgid "TIFF write failure" -msgstr "" - -#: fotoxx-11.11.1.cc:5638 -msgid "file type not supported" -msgstr "" - -#: fotoxx-11.11.1.cc:5745 -msgid "pixbuf write failure" -msgstr "" - -#: fotoxx_area.cc:54 fotoxx_area.cc:2427 -msgid "Select Area for Edits" -msgstr "" - -#: fotoxx_area.cc:55 fotoxx_area.cc:2428 -msgid "Press F1 for help" -msgstr "" - -#: fotoxx_area.cc:63 -msgid "" -"Select Area not supported \n" -"by this edit function" -msgstr "" - -#: fotoxx_area.cc:99 fotoxx_tools.cc:809 -msgid "rectangle" -msgstr "" - -#: fotoxx_area.cc:100 fotoxx_tools.cc:810 -msgid "ellipse" -msgstr "" - -#: fotoxx_area.cc:101 -msgid "draw: freehand" -msgstr "" - -#: fotoxx_area.cc:102 -msgid "draw: follow edge" -msgstr "" - -#: fotoxx_area.cc:103 -msgid "select by mouse" -msgstr "" - -#: fotoxx_area.cc:104 -msgid "select by color" -msgstr "" - -#: fotoxx_area.cc:112 -msgid "radius" -msgstr "Radio" - -#: fotoxx_area.cc:116 -msgid "match" -msgstr "" - -#: fotoxx_area.cc:121 -msgid "firewall" -msgstr "" - -#: fotoxx_area.cc:274 fotoxx_area.cc:415 -#, c-format -msgid "exceed %d edits" -msgstr "" - -#: fotoxx_area.cc:992 -msgid "" -"Click one time inside each enclosed area \n" -"(possible gaps in the outline will be found). \n" -"Press F1 for help." -msgstr "" - -#: fotoxx_area.cc:1049 -msgid "finish area" -msgstr "" - -#: fotoxx_area.cc:1083 -msgid "searching" -msgstr "" - -#: fotoxx_area.cc:1155 -msgid "outline has a gap" -msgstr "" - -#: fotoxx_area.cc:1157 -msgid "success" -msgstr "" - -#: fotoxx_area.cc:1401 fotoxx_area.cc:1430 -msgid "the area is not finished" -msgstr "" - -#: fotoxx_area.cc:1522 -msgid "Edge calculation in progress" -msgstr "Precisa calcular o bordo" - -#: fotoxx_area.cc:1531 -msgid "Area Edge Calc" -msgstr "Calcular a área do bordo" - -#: fotoxx_area.cc:1824 -msgid "position with mouse click/drag" -msgstr "" - -#: fotoxx_area.cc:1848 -msgid "Paste Image" -msgstr "" - -#: fotoxx_area.cc:1863 -msgid "angle" -msgstr "" - -#: fotoxx_area.cc:2127 -msgid "load select area from a file" -msgstr "" - -#: fotoxx_area.cc:2161 -msgid "cannot open .tiff and .info files" -msgstr "" - -#: fotoxx_area.cc:2180 -msgid "save select area to a file" -msgstr "" - -#: fotoxx_area.cc:2216 -msgid "Edit Function Amplifier" -msgstr "" - -#: fotoxx_area.cc:2459 -msgid "mouse radius" -msgstr "" - -#: fotoxx_area.cc:2462 -msgid "power: center" -msgstr "" - -#: fotoxx_area.cc:2464 -msgid "edge" -msgstr "" - -#: fotoxx_area.cc:2468 -msgid "reset area" -msgstr "" - -#: fotoxx_area.cc:2523 -msgid "start edit function first" -msgstr "" - -#: fotoxx_art.cc:47 -msgid "Set color depth to 1-16 bits" -msgstr " Establecer a profundidade de cor 1-16 bits" - -#: fotoxx_art.cc:57 -msgid "Set Color Depth" -msgstr "Axustar a profundidade da cor" - -#: fotoxx_art.cc:171 -msgid "Simulate Drawing" -msgstr "Semellar un debuxo" - -#: fotoxx_art.cc:213 fotoxx_retouch.cc:1758 -msgid "contrast" -msgstr "Contraste" - -#: fotoxx_art.cc:215 -msgid "outlines" -msgstr "Bordos" - -#: fotoxx_art.cc:220 -msgid "pencil" -msgstr "Lapis" - -#: fotoxx_art.cc:221 -msgid "chalk" -msgstr "Xiz" - -#: fotoxx_art.cc:381 -msgid "Add Image Outlines" -msgstr "" - -#: fotoxx_art.cc:394 -msgid "outline threshold" -msgstr "" - -#: fotoxx_art.cc:397 -msgid "outline width" -msgstr "" - -#: fotoxx_art.cc:400 -msgid "image brightness" -msgstr "" - -#: fotoxx_art.cc:611 -msgid "Simulate Embossing" -msgstr "Semellar un repuxado" - -#: fotoxx_art.cc:626 -msgid "depth" -msgstr "Profundidade" - -#: fotoxx_art.cc:821 -msgid "Simulate Tiles" -msgstr "Semellar un mosaicos" - -#: fotoxx_art.cc:825 -msgid "tile size" -msgstr "Tamaño do mosaico" - -#: fotoxx_art.cc:829 -msgid "tile gap" -msgstr "Separación do mosaico" - -#: fotoxx_art.cc:1003 -msgid "Convert Image to Dots" -msgstr "" - -#: fotoxx_art.cc:1007 -msgid "dot size" -msgstr "" - -#: fotoxx_art.cc:1222 -msgid "Simulate Painting" -msgstr "Semellar unha pintura" - -#: fotoxx_art.cc:1226 -msgid "color depth" -msgstr "Profundidade da cor" - -#: fotoxx_art.cc:1230 -msgid "patch area goal" -msgstr "" - -#: fotoxx_art.cc:1234 -msgid "req. color match" -msgstr "Correspondencia de cor requerida" - -#: fotoxx_art.cc:1238 -msgid "borders" -msgstr "Bordos" - -#: fotoxx_comp.cc:1956 fotoxx_comp.cc:1961 fotoxx_comp.cc:2582 -#: fotoxx_comp.cc:2587 fotoxx_comp.cc:3275 fotoxx_comp.cc:3280 -#: fotoxx_comp.cc:3830 fotoxx_comp.cc:3835 -msgid "Select 2 to 9 files" -msgstr "" - -#: fotoxx_comp.cc:1982 fotoxx_comp.cc:2608 fotoxx_comp.cc:3301 -#: fotoxx_comp.cc:3856 -msgid "Images are not all the same size" -msgstr "" - -#: fotoxx_comp.cc:2321 -msgid "Adjust Image Contributions" -msgstr "" - -#: fotoxx_comp.cc:2324 fotoxx_retouch.cc:885 -msgid "dark pixels" -msgstr "" - -#: fotoxx_comp.cc:2326 -msgid "light pixels" -msgstr "" - -#: fotoxx_comp.cc:2328 fotoxx_info.cc:159 -msgid "file:" -msgstr "Ficheiro:" - -#: fotoxx_comp.cc:2844 -msgid "Paint and Warp Image" -msgstr "" - -#: fotoxx_comp.cc:2847 fotoxx_comp.cc:3529 fotoxx_comp.cc:4972 -#: fotoxx_comp.cc:5717 -msgid "image" -msgstr "" - -#: fotoxx_comp.cc:2851 fotoxx_retouch.cc:5885 -msgid "paint" -msgstr "Pintar" - -#: fotoxx_comp.cc:2852 -msgid "warp" -msgstr "" - -#: fotoxx_comp.cc:3527 -msgid "Select and Paint Image" -msgstr "" - -#: fotoxx_comp.cc:4045 -msgid "Adjust Pixel Composition" -msgstr "" - -#: fotoxx_comp.cc:4297 fotoxx_comp.cc:4302 fotoxx_comp.cc:5186 -#: fotoxx_comp.cc:5191 -msgid "Select 2 to 4 files" -msgstr "" - -#: fotoxx_comp.cc:4374 -msgid "" -"Drag images into rough alignment.\n" -"To rotate, drag from lower edge." -msgstr "" - -#: fotoxx_comp.cc:4376 -msgid "Search for lens mm and bow" -msgstr "" - -#: fotoxx_comp.cc:4422 fotoxx_comp.cc:5310 -msgid "Pre-align Images" -msgstr "Pre-aliñar imaxes" - -#: fotoxx_comp.cc:4426 fotoxx_comp.cc:5314 fotoxx_tools.cc:2151 -msgid "lens mm" -msgstr "Lonxitude focal (mm)" - -#: fotoxx_comp.cc:4430 fotoxx_comp.cc:5318 fotoxx_tools.cc:2156 -msgid "lens bow" -msgstr "Curvatura da lente" - -#: fotoxx_comp.cc:4432 fotoxx_comp.cc:5320 -msgid "Resize" -msgstr "" - -#: fotoxx_comp.cc:4433 fotoxx_comp.cc:5321 -msgid "resize window" -msgstr "" - -#: fotoxx_comp.cc:4470 -msgid "use two images only" -msgstr "" - -#: fotoxx_comp.cc:4491 fotoxx_comp.cc:4689 fotoxx_comp.cc:4888 -#: fotoxx_comp.cc:5369 fotoxx_comp.cc:5632 -msgid "Too little overlap, cannot align" -msgstr "Solapamento moi pequeno, non se pode aliñar" - -#: fotoxx_comp.cc:4963 fotoxx_comp.cc:5708 -msgid "Match Brightness and Color" -msgstr "" - -#: fotoxx_comp.cc:4987 fotoxx_comp.cc:5732 -msgid "auto color" -msgstr "" - -#: fotoxx_comp.cc:4988 fotoxx_comp.cc:5733 -msgid "file color" -msgstr "" - -#: fotoxx_comp.cc:5263 -msgid "" -"Drag images into rough alignment.\n" -"To rotate, drag from right edge." -msgstr "" - -#: fotoxx_info.cc:70 -msgid "Edit Caption and Comments" -msgstr "" - -#: fotoxx_info.cc:163 -msgid "image date (yyyymmdd)" -msgstr "Data da imaxe (aaaammdd)" - -#: fotoxx_info.cc:165 -msgid "use last" -msgstr "Usar o último" - -#: fotoxx_info.cc:168 -msgid "image stars" -msgstr "Imaxe estrela" - -#: fotoxx_info.cc:186 -msgid "current tags" -msgstr "Etiquetas actuais" - -#: fotoxx_info.cc:191 -msgid "recent tags" -msgstr "" - -#: fotoxx_info.cc:196 fotoxx_info.cc:358 fotoxx_info.cc:1362 -#: fotoxx_info.cc:2290 -msgid "defined tags" -msgstr "" - -#: fotoxx_info.cc:348 -msgid "category" -msgstr "" - -#: fotoxx_info.cc:351 -msgid "tag" -msgstr "" - -#: fotoxx_info.cc:354 -msgid "create" -msgstr "" - -#: fotoxx_info.cc:355 -msgid "delete" -msgstr "Borrar" - -#: fotoxx_info.cc:1229 fotoxx_info.cc:1313 -#, c-format -msgid "search index file error: %s" -msgstr "" - -#: fotoxx_info.cc:1348 -msgid "tags to add" -msgstr "" - -#: fotoxx_info.cc:1353 -msgid "create tag" -msgstr "Crear etiqueta" - -#: fotoxx_info.cc:1409 fotoxx_info.cc:1602 -#, c-format -msgid "" -"%s \n" -" too many tags" -msgstr "" - -#: fotoxx_info.cc:1550 -msgid "tag to remove" -msgstr "" - -#: fotoxx_info.cc:1554 -msgid "optional replacement" -msgstr "" - -#: fotoxx_info.cc:1559 fotoxx_tools.cc:2463 -msgid "0 files selected" -msgstr "" - -#: fotoxx_info.cc:1562 -msgid "search all files" -msgstr "" - -#: fotoxx_info.cc:1647 -msgid "no files selected" -msgstr "" - -#: fotoxx_info.cc:1653 -msgid "no tag specified" -msgstr "" - -#: fotoxx_info.cc:1677 fotoxx_info.cc:1706 -msgid "specify tag" -msgstr "" - -#: fotoxx_info.cc:1815 -msgid "View Info" -msgstr "" - -#: fotoxx_info.cc:1983 -msgid "All" -msgstr "" - -#: fotoxx_info.cc:1984 -msgid "One Key:" -msgstr "" - -#: fotoxx_info.cc:2249 -msgid "Search Tags, Comments, File Names" -msgstr "" - -#: fotoxx_info.cc:2255 -msgid "date range" -msgstr "Formato da data" - -#: fotoxx_info.cc:2256 -msgid "stars range" -msgstr "Rango de estrelas" - -#: fotoxx_info.cc:2257 -msgid "search tags" -msgstr "Buscar" - -#: fotoxx_info.cc:2258 -msgid "search text" -msgstr "" - -#: fotoxx_info.cc:2259 -msgid "file names" -msgstr "" - -#: fotoxx_info.cc:2264 -msgid "(yyyymmdd)" -msgstr "" - -#: fotoxx_info.cc:2270 -msgid "all/any" -msgstr "" - -#: fotoxx_info.cc:2598 -msgid "No matching images found" -msgstr "Non se atoparon imaxes" - -#: fotoxx_info.cc:2611 -msgid "No search index file present" -msgstr "" - -#: fotoxx_info.cc:2615 -#, c-format -msgid "Search results file error %s" -msgstr "Erro nos resultados da busca %s" - -#: fotoxx_retouch.cc:55 -msgid "Adjust Brightness and Color" -msgstr "Axustar brillo e cor" - -#: fotoxx_retouch.cc:109 -msgid "small-steps" -msgstr "" - -#: fotoxx_retouch.cc:118 -msgid "color saturation" -msgstr "Saturación da cor" - -#: fotoxx_retouch.cc:125 -msgid " reset 1 " -msgstr " Restablecer 1" - -#: fotoxx_retouch.cc:126 -msgid "reset all" -msgstr "Restablecer todo" - -#: fotoxx_retouch.cc:598 -msgid "adjust image gamma" -msgstr "" - -#: fotoxx_retouch.cc:884 -msgid "Expand Brightness Range" -msgstr "" - -#: fotoxx_retouch.cc:886 -msgid "bright pixels" -msgstr "" - -#: fotoxx_retouch.cc:1057 -msgid "Flatten Brightness Distribution" -msgstr "Distribuir o brillo uniformemente" - -#: fotoxx_retouch.cc:1071 -msgid "Flatten" -msgstr "Aplanar" - -#: fotoxx_retouch.cc:1333 -msgid "Ramp brightness across image" -msgstr "" - -#: fotoxx_retouch.cc:1757 -msgid "low" -msgstr "" - -#: fotoxx_retouch.cc:1759 -msgid "high" -msgstr "" - -#: fotoxx_retouch.cc:1762 -msgid "Amplify" -msgstr "" - -#: fotoxx_retouch.cc:2068 -msgid "Adjust White Balance" -msgstr "Axustar o balance de branco" - -#: fotoxx_retouch.cc:2069 -msgid "Click white or gray image location" -msgstr "Faga clic na ubicación da imaxe en branco ou gris" - -#: fotoxx_retouch.cc:2283 -msgid "Color Match Images" -msgstr "" - -#: fotoxx_retouch.cc:2312 -msgid "mouse radius for color sample" -msgstr "" - -#: fotoxx_retouch.cc:2315 -msgid "image for source color" -msgstr "" - -#: fotoxx_retouch.cc:2317 -msgid "click on image to get source color" -msgstr "" - -#: fotoxx_retouch.cc:2320 -msgid "image to set matching color" -msgstr "" - -#: fotoxx_retouch.cc:2322 -msgid "click on image to set matching color" -msgstr "" - -#: fotoxx_retouch.cc:2377 -msgid "select source image color first" -msgstr "" - -#: fotoxx_retouch.cc:2903 fotoxx_tools.cc:1643 -msgid "Click image to select pixels." -msgstr "" - -#: fotoxx_retouch.cc:2955 -msgid "Metric:" -msgstr "" - -#: fotoxx_retouch.cc:3010 -msgid "Blend" -msgstr "" - -#: fotoxx_retouch.cc:3394 -msgid "" -"Method 1:\n" -" Left-click on red-eye to darken.\n" -"Method 2:\n" -" Drag down and right to enclose red-eye.\n" -" Left-click on red-eye to darken.\n" -"Undo red-eye:\n" -" Right-click on red-eye." -msgstr "" -"Método 1:\n" -" Clic-esquerdo no ollo vermello pra escurecer.\n" -"Método 2:\n" -" Pica e arrastra a dereita para delimitar o ollo vermello.\n" -" Clic-esquerdo para escurecer o ollo vermello.\n" -"Desfacer ollos vermellos:\n" -" Clic-dereito no ollo vermello." - -#: fotoxx_retouch.cc:3409 -msgid "Red Eye Reduction" -msgstr "Redución de ollos vermellos" - -#: fotoxx_retouch.cc:3850 -msgid "Set Blur Radius" -msgstr "Definir o radio do desenfoque" - -#: fotoxx_retouch.cc:4084 -msgid "edge detection" -msgstr "Detección de bordos" - -#: fotoxx_retouch.cc:4085 -msgid "cycles" -msgstr "Ciclos" - -#: fotoxx_retouch.cc:4086 -msgid "reduce" -msgstr "Reducir" - -#: fotoxx_retouch.cc:4097 -msgid "unsharp mask" -msgstr "Máscara de desenfoque" - -#: fotoxx_retouch.cc:4110 -msgid "brightness gradient" -msgstr "" - -#: fotoxx_retouch.cc:4516 -msgid "" -" Press the reduce button to \n" -" reduce noise in small steps. \n" -" Use undo to start over." -msgstr "" -" Prema o boton Reducir para \n" -" reducir o ruido en pequenos pasos. \n" -" Use Desfacer para comezar de novo." - -#: fotoxx_retouch.cc:4527 -msgid "Noise Reduction" -msgstr "Reducción de ruido" - -#: fotoxx_retouch.cc:4532 -msgid "algorithm" -msgstr "Algoritmo" - -#: fotoxx_retouch.cc:4539 -msgid "flatten outliers by color (1)" -msgstr "Aplanar os valores extremos de cor (1)" - -#: fotoxx_retouch.cc:4540 -msgid "flatten outliers by color (2)" -msgstr "Aplanar os valores extremos de cor (2)" - -#: fotoxx_retouch.cc:4541 -msgid "set median brightness by color" -msgstr "Configurar a mediana de brillo por cor" - -#: fotoxx_retouch.cc:4542 fotoxx_retouch.cc:4543 -msgid "top hat filter by color" -msgstr "Filtro de cor «sombreiro de copa (Top-hat)»" - -#: fotoxx_retouch.cc:4858 -msgid "" -"1. Drag mouse to select. \n" -"2. Erase. 3. Repeat. " -msgstr "" - -#: fotoxx_retouch.cc:4889 -msgid "Radius" -msgstr "Radio" - -#: fotoxx_retouch.cc:4891 -msgid "Blur" -msgstr "" - -#: fotoxx_retouch.cc:4894 -msgid "New Area" -msgstr "" - -#: fotoxx_retouch.cc:5275 -msgid "spot size limit" -msgstr "" - -#: fotoxx_retouch.cc:5278 -msgid "max. brightness" -msgstr "" - -#: fotoxx_retouch.cc:5281 -msgid "min. contrast" -msgstr "" - -#: fotoxx_retouch.cc:5875 -#, c-format -msgid "Undo Memory %d%c" -msgstr "Memoria de desfacer %d%c" - -#: fotoxx_retouch.cc:5884 -msgid "pick" -msgstr "Recoller" - -#: fotoxx_retouch.cc:5886 -msgid "erase" -msgstr "Borrar" - -#: fotoxx_retouch.cc:5894 -msgid "paintbrush radius" -msgstr "Radio do pincel" - -#: fotoxx_retouch.cc:5895 -msgid "transparency center" -msgstr "Centro da transparencia" - -#: fotoxx_retouch.cc:5896 -msgid "transparency edge" -msgstr "Bordo da transparencia" - -#: fotoxx_retouch.cc:6166 -msgid "" -"Undo memory limit has been reached. \n" -"Save work with [done], then resume editing." -msgstr "" -"Acadouse o límite de memoria de desfacer. \n" -"Garde o traballo con [Feito], e despois retome a edición." - -#: fotoxx_tools.cc:42 -msgid "" -"When editing a collection, right-click \n" -"an image or thumbnail to add or remove." -msgstr "" - -#: fotoxx_tools.cc:85 -msgid "Start new collection" -msgstr "" - -#: fotoxx_tools.cc:87 -msgid "Edit a collection" -msgstr "" - -#: fotoxx_tools.cc:89 -msgid "View a collection" -msgstr "" - -#: fotoxx_tools.cc:91 -msgid "Delete a collection" -msgstr "" - -#: fotoxx_tools.cc:95 -msgid "Editing:" -msgstr "" - -#: fotoxx_tools.cc:99 -msgid "Action:" -msgstr "" - -#: fotoxx_tools.cc:133 -msgid "New Collection" -msgstr "" - -#: fotoxx_tools.cc:156 -msgid "Edit Collection" -msgstr "" - -#: fotoxx_tools.cc:172 -msgid "View Collection" -msgstr "" - -#: fotoxx_tools.cc:193 -msgid "Delete Collection" -msgstr "" - -#: fotoxx_tools.cc:196 -#, c-format -msgid "delete %s ?" -msgstr "" - -#: fotoxx_tools.cc:223 -#, c-format -msgid "add image to collection: %s" -msgstr "" - -#: fotoxx_tools.cc:225 fotoxx_tools.cc:270 -msgid "remove image from collection" -msgstr "" - -#: fotoxx_tools.cc:226 fotoxx_tools.cc:271 fotoxx_tools.cc:298 -msgid "remove and save image" -msgstr "" - -#: fotoxx_tools.cc:227 fotoxx_tools.cc:316 -msgid "insert saved images here" -msgstr "" - -#: fotoxx_tools.cc:256 -msgid "add image to collection" -msgstr "" - -#: fotoxx_tools.cc:301 -msgid "too many saved files" -msgstr "" - -#: fotoxx_tools.cc:375 -msgid "old top directory" -msgstr "" - -#: fotoxx_tools.cc:378 -msgid "new top directory" -msgstr "" - -#: fotoxx_tools.cc:434 -msgid "completed" -msgstr "" - -#: fotoxx_tools.cc:452 -msgid "" -"Brightness should show a gradual ramp \n" -"extending all the way to the edges." -msgstr "" - -#: fotoxx_tools.cc:492 -msgid "Monitor Check" -msgstr "" - -#: fotoxx_tools.cc:612 -msgid "Brightness Distribution" -msgstr "Distribuir o brillo" - -#: fotoxx_tools.cc:796 -msgid "Press ESC to exit slide show" -msgstr "" - -#: fotoxx_tools.cc:797 -msgid "show only latest file versions" -msgstr "" - -#: fotoxx_tools.cc:801 -msgid "arrow keys" -msgstr "" - -#: fotoxx_tools.cc:802 -msgid "instant" -msgstr "" - -#: fotoxx_tools.cc:803 -msgid "fade-in" -msgstr "" - -#: fotoxx_tools.cc:804 -msgid "roll-right" -msgstr "" - -#: fotoxx_tools.cc:805 -msgid "roll-down" -msgstr "" - -#: fotoxx_tools.cc:806 -msgid "shift-left" -msgstr "" - -#: fotoxx_tools.cc:807 -msgid "venetian" -msgstr "" - -#: fotoxx_tools.cc:808 -msgid "grate" -msgstr "" - -#: fotoxx_tools.cc:811 -msgid "radar" -msgstr "" - -#: fotoxx_tools.cc:812 -msgid "jaws" -msgstr "" - -#: fotoxx_tools.cc:823 -msgid "seconds" -msgstr "segundos" - -#: fotoxx_tools.cc:827 -msgid "music file" -msgstr "" - -#: fotoxx_tools.cc:831 -msgid "transitions" -msgstr "" - -#: fotoxx_tools.cc:948 -msgid "Select music file or playlist" -msgstr "" - -#: fotoxx_tools.cc:1971 -msgid "x-spacing" -msgstr "" - -#: fotoxx_tools.cc:1972 -msgid "x-count" -msgstr "" - -#: fotoxx_tools.cc:1973 -msgid "x-enable" -msgstr "" - -#: fotoxx_tools.cc:1979 -msgid "y-spacing" -msgstr "" - -#: fotoxx_tools.cc:1980 -msgid "y-count" -msgstr "" - -#: fotoxx_tools.cc:1981 -msgid "y-enable" -msgstr "" - -#: fotoxx_tools.cc:1988 -msgid "x-offset" -msgstr "" - -#: fotoxx_tools.cc:1992 -msgid "y-offset" -msgstr "" - -#: fotoxx_tools.cc:2146 -msgid "lens name" -msgstr "Nome da lente" - -#: fotoxx_tools.cc:2220 -msgid "Available Translations" -msgstr "Traducións dispoñibles" - -#: fotoxx_tools.cc:2224 -msgid "Set Language" -msgstr "Seleccionar o idioma" - -#: fotoxx_tools.cc:2290 -msgid "Make Launcher" -msgstr "" - -#: fotoxx_tools.cc:2310 -msgid "Program ufraw-batch is required" -msgstr "" - -#: fotoxx_tools.cc:2320 -msgid "Open RAW File" -msgstr "Abrir ficheiro RAW" - -#: fotoxx_tools.cc:2331 -msgid "Select RAW files to convert" -msgstr "" - -#: fotoxx_tools.cc:2467 -msgid "max. width" -msgstr "" - -#: fotoxx_tools.cc:2468 -msgid "max. height" -msgstr "" - -#: fotoxx_tools.cc:2527 fotoxx_transform.cc:1268 -#, c-format -msgid "max. size %d x %d is not reasonable" -msgstr "" - -#: fotoxx_tools.cc:2613 -msgid "too many files" -msgstr "" - -#: fotoxx_tools.cc:2656 -msgid "Sync Files is already running" -msgstr "" - -#: fotoxx_tools.cc:2707 -msgid "" -"Run Tools > Synchronize Files so that gallery windows \n" -"will be fast and Search Images will work correctly. \n" -"You can view (not edit) images while synchronize runs." -msgstr "" - -#: fotoxx_tools.cc:2736 -msgid "no top image directory is defined" -msgstr "" - -#: fotoxx_tools.cc:2742 -msgid "top image directory is invalid" -msgstr "" - -#: fotoxx_tools.cc:2747 -msgid "no search index file is present" -msgstr "" - -#: fotoxx_tools.cc:2761 -msgid "new/modified files are present" -msgstr "" - -#: fotoxx_tools.cc:2768 -msgid "no new files found" -msgstr "" - -#: fotoxx_tools.cc:2785 -msgid "Top Image Directory:" -msgstr "" - -#: fotoxx_tools.cc:2807 -msgid "file sync is mandatory" -msgstr "" - -#: fotoxx_tools.cc:2817 -msgid "top directory is invalid" -msgstr "" - -#: fotoxx_tools.cc:3201 -msgid "Select top image directory" -msgstr "Seleccionar o directório raíz de imaxes" - -#: fotoxx_tools.cc:3378 -msgid "icons" -msgstr "" - -#: fotoxx_tools.cc:3379 fotoxx_transform.cc:1467 -msgid "text" -msgstr "" - -#: fotoxx_tools.cc:3380 -msgid "both" -msgstr "" - -#: fotoxx_transform.cc:50 -msgid "Use buttons or drag right edge with mouse" -msgstr "Utilice os botóns ou arrastre o bordo dereito co rato" - -#: fotoxx_transform.cc:64 -msgid "degrees" -msgstr "Graos" - -#: fotoxx_transform.cc:80 fotoxx_transform.cc:124 -msgid "Trim" -msgstr "Recortar" - -#: fotoxx_transform.cc:81 fotoxx_transform.cc:2437 fotoxx_transform.cc:3263 -#: fotoxx_transform.cc:3526 fotoxx_transform.cc:3787 -msgid "Grid" -msgstr "" - -#: fotoxx_transform.cc:123 -msgid "Undo Trim" -msgstr "Desfacer recortar" - -#: fotoxx_transform.cc:139 -#, c-format -msgid "degrees: %.1f" -msgstr "Graos: %.1f" - -#: fotoxx_transform.cc:286 -msgid "gold" -msgstr "" - -#: fotoxx_transform.cc:332 -msgid "Drag middle to move, drag corners to resize." -msgstr "" - -#: fotoxx_transform.cc:346 -msgid "customize" -msgstr "" - -#: fotoxx_transform.cc:357 -msgid "ratio" -msgstr "" - -#: fotoxx_transform.cc:361 -msgid "Lock Ratio" -msgstr "Bloquear a relación" - -#: fotoxx_transform.cc:367 -msgid "invert" -msgstr "" - -#: fotoxx_transform.cc:892 -msgid "Trim Buttons" -msgstr "" - -#: fotoxx_transform.cc:964 -msgid "Lock aspect ratio" -msgstr "Bloquear a relación de aspecto" - -#: fotoxx_transform.cc:1145 -msgid "Batch Resize" -msgstr "" - -#: fotoxx_transform.cc:1153 -msgid "new max. width" -msgstr "" - -#: fotoxx_transform.cc:1154 -msgid "new max. height" -msgstr "" - -#: fotoxx_transform.cc:1161 -msgid "replace originals" -msgstr "" - -#: fotoxx_transform.cc:1162 -msgid "export to location" -msgstr "" - -#: fotoxx_transform.cc:1166 -msgid "copy EXIF" -msgstr "" - -#: fotoxx_transform.cc:1219 -msgid "Select directory" -msgstr "" - -#: fotoxx_transform.cc:1243 -#, c-format -msgid "replace original files? (max. %d x %d)" -msgstr "" - -#: fotoxx_transform.cc:1250 -#, c-format -msgid "" -"copy files? (max. %d x %d) \n" -" to location %s" -msgstr "" - -#: fotoxx_transform.cc:1261 -msgid "location is not a valid directory" -msgstr "" - -#: fotoxx_transform.cc:1304 -msgid "new file already exists" -msgstr "" - -#: fotoxx_transform.cc:1388 -msgid "" -"Enter text, click/drag on image.\n" -"Right click to remove" -msgstr "" - -#: fotoxx_transform.cc:1442 -msgid "Text" -msgstr "" - -#: fotoxx_transform.cc:1449 -msgid "Size" -msgstr "Tamaño" - -#: fotoxx_transform.cc:1452 -msgid "Angle" -msgstr "" - -#: fotoxx_transform.cc:1463 -msgid "Color" -msgstr "" - -#: fotoxx_transform.cc:1464 -msgid "Transparency" -msgstr "" - -#: fotoxx_transform.cc:1472 -msgid "backing" -msgstr "" - -#: fotoxx_transform.cc:1475 -msgid "" -"Outline\n" -" Width" -msgstr "" - -#: fotoxx_transform.cc:1477 -msgid "outline" -msgstr "" - -#: fotoxx_transform.cc:1486 -msgid "Annotation File:" -msgstr "" - -#: fotoxx_transform.cc:1564 -msgid "select font" -msgstr "" - -#: fotoxx_transform.cc:2197 fotoxx_transform.cc:2429 -msgid "horizontal" -msgstr "Horizontal" - -#: fotoxx_transform.cc:2198 fotoxx_transform.cc:2428 -msgid "vertical" -msgstr "Vertical" - -#: fotoxx_transform.cc:2306 -msgid "black/white positive" -msgstr "" - -#: fotoxx_transform.cc:2307 -msgid "black/white negative" -msgstr "" - -#: fotoxx_transform.cc:2308 -msgid "color positive" -msgstr "" - -#: fotoxx_transform.cc:2309 -msgid "color negative" -msgstr "" - -#: fotoxx_transform.cc:2430 -msgid "linear" -msgstr "" - -#: fotoxx_transform.cc:2433 -msgid "curved" -msgstr "" - -#: fotoxx_transform.cc:2692 -msgid "" -" Click the four corners of a tetragon area. Press [apply]. \n" -" The image is warped to make the tetragon into a rectangle." -msgstr "" - -#: fotoxx_transform.cc:2878 -msgid "must have 4 corners" -msgstr "" - -#: fotoxx_transform.cc:2999 -msgid "" -" Select an area to warp using select area function. \n" -" Press [start warp] and pull area with mouse. \n" -" Make multiple mouse pulls until satisfied. \n" -" When finished, select another area or press [done]." -msgstr "" -"Seleccione unha área para deformar utilizando o boton [Seleccionar]. \n" -"Prema [Comezar deformación] e empuxe da área co rato. \n" -"Facer varios empuxóns co rato até que quede satisfeito. \n" -"Cando teña rematado, seleccione outra área ou prema [Feito]." - -#: fotoxx_transform.cc:3018 -msgid "start warp" -msgstr "Comezar deformación" - -#: fotoxx_transform.cc:3067 -msgid "Select area first" -msgstr "Debe seleccionar primeiro a área" - -#: fotoxx_transform.cc:3242 fotoxx_transform.cc:3505 -msgid "" -" Pull an image position using the mouse. \n" -" Make multiple mouse pulls until satisfied. \n" -" When finished, press [done]." -msgstr "" - -#: fotoxx_transform.cc:3771 -msgid "" -" Pull on an image corner using the mouse. \n" -" Make multiple mouse pulls until satisfied. \n" -" When finished, press [done]." -msgstr "" -" Tirar dun bordo da imaxe empregando o rato. \n" -" Facer varios empuxóns co rato até que quede satisfeito. \n" -" Cando teña rematado, seleccione outra área ou prema [Feito]." - -#~ msgid "Translate" -#~ msgstr "Traducións" - -#~ msgid "" -#~ "Rename failed \n" -#~ " %s" -#~ msgstr "" -#~ "Fallou o renomeado \n" -#~ " %s" - -#~ msgid "Discard modifications?" -#~ msgstr "Desbotar as modificacións?" - -#~ msgid "whiteness" -#~ msgstr "Claridade" - -#~ msgid "unknown image format" -#~ msgstr "Formato de imaxe descoñecido" - -#~ msgid "undo image changes" -#~ msgstr "Desfacer os cambios na imaxe" - -#~ msgid "unbend panorama image" -#~ msgstr "Corrixir perspectiva panorámica" - -#~ msgid "trim image" -#~ msgstr "Recortar a imaxe" - -#~ msgid "toolbar::save" -#~ msgstr "Gardar" - -#, fuzzy -#~ msgid "this area cannot be processed" -#~ msgstr "" -#~ "Non se pode conservar a selección de área.\n" -#~ "Continuar?" - -#~ msgid "tags exceed %d characters" -#~ msgstr "As etiquetas do ficheiro exceden de %d caracteres" - -#~ msgid "sharpen image" -#~ msgstr "Enfocar a imaxe" - -#~ msgid "set color intensity" -#~ msgstr "Definir a intensidade da cor" - -#, fuzzy -#~ msgid "set blend radius" -#~ msgstr "Definir o radio do desenfoque" - -#~ msgid "set RGB spread" -#~ msgstr "Establece o rango RGB" - -#~ msgid "rotate image" -#~ msgstr "Xirar a imaxe" - -#~ msgid "resize image" -#~ msgstr "Redimensionar a imaxe" - -#~ msgid "redo image changes" -#~ msgstr "Refacer os cambios na imaxe" - -#~ msgid "red" -#~ msgstr "Vermello" - -#~ msgid "recently added" -#~ msgstr "Engadido recentemente" - -#, fuzzy -#~ msgid "radius limit" -#~ msgstr "Radio" - -#~ msgid "quit" -#~ msgstr "Sair" - -#~ msgid "prior function still running" -#~ msgstr "A función principal esta aínda traballando" - -#~ msgid "photo stars" -#~ msgstr "Estrelas" - -#~ msgid "photo date (yyyymmdd)" -#~ msgstr "Data da foto (aaaammdd)" - -#~ msgid "open new image file" -#~ msgstr "Abrir unha nova imaxe" - -#~ msgid "open image file" -#~ msgstr "Abrir ficheiro" - -#~ msgid "open RAW file" -#~ msgstr "Abrir ficheiro en bruto" - -#~ msgid "open" -#~ msgstr "Abrir" - -#~ msgid "kill running function" -#~ msgstr "Pechar a función actual" - -#~ msgid "kill" -#~ msgstr "Pechar" - -#~ msgid "insert" -#~ msgstr "Inserir" - -#~ msgid "input image 2" -#~ msgstr "Elixir imaxe 2" - -#~ msgid "image not 8 or 16 bits/color: %s" -#~ msgstr "A imaxe %s non ten 8 ou 16 bits/color" - -#~ msgid "image format error: %s" -#~ msgstr "Erro no formato da imaxe: %s" - -#~ msgid "graph" -#~ msgstr "gráfico" - -#~ msgid "" -#~ "file cannot be read: \n" -#~ " %s" -#~ msgstr "" -#~ "Non se pode ler o ficheiro: \n" -#~ " %s" - -#~ msgid "exiv2 package is required" -#~ msgstr "Precisase o paquete exiv2" - -#~ msgid "exiftool is required to generate tags index" -#~ msgstr "Precisase «exiftool» para xerar o índice de etiquetas" - -#~ msgid "exiftool is required to create tags" -#~ msgstr "Precisase «exiftool» para cear etiquetas" - -#, fuzzy -#~ msgid "edge calculation missing" -#~ msgstr "Precisa calcular o bordo" - -#~ msgid "defog" -#~ msgstr "desembazar" - -#~ msgid "date range (yyyymmdd)" -#~ msgstr "Formato da data (aaaammdd)" - -#~ msgid "computing" -#~ msgstr "computing" - -#~ msgid "color balance" -#~ msgstr "Balance da cor" - -#~ msgid "click or drag trim margins" -#~ msgstr "Faga clic na imaxe ou arrastre o bordo" - -#~ msgid "" -#~ "cannot create %s \n" -#~ " %s" -#~ msgstr "" -#~ "Non se pode crear %s \n" -#~ " %s" - -#~ msgid "brightness distribution" -#~ msgstr "Distribuir o brillo" - -#~ msgid "blur radius" -#~ msgstr "Radio de desenfoque" - -#~ msgid "blend" -#~ msgstr "Mestura" - -#~ msgid "bigger image" -#~ msgstr "Imaxe máis grande" - -#~ msgid "assigned tags" -#~ msgstr "Etiquetas asignadas" - -#~ msgid "adjust brightness / whiteness" -#~ msgstr "Axustar brillo / claridade" - -#~ msgid "Zoom-" -#~ msgstr "Zoom-" - -#~ msgid "Zoom+" -#~ msgstr "Zoom+" - -#~ msgid "Warp Global" -#~ msgstr "Deformación da imaxe" - -#~ msgid "Warp" -#~ msgstr "Deformar" - -#~ msgid "Unable to save image: %s" -#~ msgstr "Non se pode gardar a imaxe: %s" - -#~ msgid "Unable to save image" -#~ msgstr "Non se pode gardar a imaxe" - -#, fuzzy -#~ msgid "Unable to replace file" -#~ msgstr "Non se pode gardar a imaxe" - -#~ msgid "Unable to copy EXIF data" -#~ msgstr "Non se poden copiar os datos EXIF" - -#~ msgid "Tune Image" -#~ msgstr "Afinar a imaxe" - -#~ msgid "Total tags exceed %d characters" -#~ msgstr "O número total de etiquetas excedeu en %d caracteres" - -#~ msgid "Too many undo buffers, please save image" -#~ msgstr "Demasiados «desfacer» no bufer, garde a imaxe" - -#~ msgid "Too many tags: %d" -#~ msgstr "Demasiadas etiquetas: %d" - -#~ msgid "Too many points" -#~ msgstr "Demasiados puntos" - -#~ msgid "Thumbnail Index" -#~ msgstr "Índice de miniaturas" - -#~ msgid "Special Art Effects" -#~ msgstr "Efectos artísticos especiales" - -#~ msgid "Simulate embossing" -#~ msgstr "Semellar un repuxado" - -#, fuzzy -#~ msgid "Simulate Mosaic" -#~ msgstr "Simular repuxado" - -#, fuzzy -#~ msgid "Simulat Mosaic" -#~ msgstr "Simular repuxado" - -#~ msgid "Show Area" -#~ msgstr "Amosar área" - -#~ msgid "Sharp" -#~ msgstr "Enfoque" - -#~ msgid "" -#~ "Select area is not finished.\n" -#~ "Continue without using it?" -#~ msgstr "" -#~ "Non se completou a selección de área.\n" -#~ "Continuar sen usala?" - -#~ msgid "Select Area -mouse" -#~ msgstr "Seleccionar área -rato" - -#~ msgid "Select Area -color" -#~ msgstr "Seleccionar área -cor" - -#~ msgid "Save Image as File" -#~ msgstr "Gardar a imaxe como ficheiro" - -#~ msgid "Rotate" -#~ msgstr "Xirar" - -#~ msgid "RGB spread" -#~ msgstr "Rango RGB" - -#~ msgid "RGB Spread" -#~ msgstr "Rango RGB" - -#~ msgid "README" -#~ msgstr "LEAME" - -#~ msgid "RAW file template" -#~ msgstr "Plantilla de ficheiro RAW" - -#~ msgid "Print" -#~ msgstr "Imprimir" - -#~ msgid "Paint Pixels" -#~ msgstr "Pintar píxeles" - -#~ msgid "Package exiftool is missing" -#~ msgstr "Non se atopa o paquete «exiftool»" - -#~ msgid "Output Image" -#~ msgstr "Imaxe de saída" - -#, fuzzy -#~ msgid "Outline Image Area for Following Edits" -#~ msgstr "Área da imaxe para ediciós seguintes" - -#~ msgid "No assigned tags index file" -#~ msgstr "Etiquetas sen asignar ao ficheiro de índice" - -#~ msgid "Make HDR Image" -#~ msgstr "Facer imaxe HDR" - -#~ msgid "Make HDF Image" -#~ msgstr "Facer imaxe HDF" - -#~ msgid "" -#~ "Left click/drag: add to selected area. \n" -#~ "Right click: remove prior selection(s). \n" -#~ "Color range: add more or less at once." -#~ msgstr "" -#~ "Facer clic no botón esquerdo e arrastrar: engadir á área seleccionada. \n" -#~ "Facer clic no botón dereito: quitar a(s) selección(s) previa(s). \n" -#~ "Gama de cores: engadir máis o menos de vez." - -#~ msgid "Invert Area" -#~ msgstr "Inverter área" - -#~ msgid "Input Images" -#~ msgstr "Imaxes de entrada" - -#~ msgid "Index Tags and Thumbs" -#~ msgstr "Sincronizar etiquetas e miniaturas" - -#~ msgid "Index (thumbnails)" -#~ msgstr "Índice (miniaturas)" - -#~ msgid "Index" -#~ msgstr "Índice" - -#~ msgid "Image Weights per Brightness Level" -#~ msgstr "Peso da imaxe por nivel de brillo" - -#~ msgid "Hide Area" -#~ msgstr "Agochar área" - -#~ msgid "HDR Image Weights" -#~ msgstr "Peso da imaxe HDR" - -#, fuzzy -#~ msgid "FreeImage" -#~ msgstr "Redimensionar a imaxe" - -#, fuzzy -#~ msgid "Flash" -#~ msgstr "Lixo" - -#~ msgid "FREEIMAGE unknown error" -#~ msgstr "Erro descoñecido en FREEIMAGE" - -#~ msgid "FREEIMAGE error: %s" -#~ msgstr "Erro en FREEIMAGE: %s" - -#~ msgid "Error Log" -#~ msgstr "Rexistro de erros" - -#~ msgid "Edge Calc" -#~ msgstr "Calcular o bordo" - -#~ msgid "" -#~ "Drag middle to move \n" -#~ "Drag corners to resize" -#~ msgstr "" -#~ "Arrastre desde o interior para mover \n" -#~ "Arrastre os cantos para redimensionar" - -#, fuzzy -#~ msgid "" -#~ "Drag and click to enclose an area.\n" -#~ "Use right click to undo prior." -#~ msgstr "" -#~ "Use o rato, arrastre e faga clic para pechar unha área \n" -#~ "e o botón dereito para desfacer." - -#~ msgid "Distortion" -#~ msgstr "Distorsión" - -#~ msgid "" -#~ "Distance calculation needs a long time.\n" -#~ " Do you want to continue?" -#~ msgstr "" -#~ "O cálculo da distancia necesita bastante tempo.\n" -#~ " Desexa continuar?" - -#~ msgid "Dimensions" -#~ msgstr "Dimensións" - -#~ msgid "Delete selected area?" -#~ msgstr "Borrar a área seleccionada?" - -#~ msgid "Delete Area" -#~ msgstr "Borar a área" - -#~ msgid "" -#~ "Convert raw file to 48-bit tiff format? \n" -#~ " (this may take a while) " -#~ msgstr "" -#~ "Converter ficheiros RAW a formato tiff de 48 bits?\n" -#~ " (isto pode tardar un pouco)" - -#~ msgid "Convert multiple RAWs" -#~ msgstr "Converter múltiples RAW" - -#~ msgid "Composite Images" -#~ msgstr "Composición de imaxes" - -#~ msgid "Color Intensity" -#~ msgstr "Intensidade da cor" - -#~ msgid "Clear Select Area" -#~ msgstr "Limpar área seleccionada" - -#~ msgid "Build Tags Index" -#~ msgstr "Construir índice de etiquetas" - -#~ msgid "Brightness/Whiteness" -#~ msgstr "Axustar brillo / claridade" - -#~ msgid "Brightness/Contrast/Color" -#~ msgstr "Brillo/Contraste/Cor" - -#, fuzzy -#~ msgid "Blend Area Edges" -#~ msgstr "Radio de desenfoque" - -#~ msgid "Bend" -#~ msgstr "Mestura" - -#~ msgid "Assigned tags file error: %s" -#~ msgstr "Erro ao asignar etiquetas de ficheiro: %s" - -#~ msgid "Adjust Saturation (RGB spread)" -#~ msgstr "Ajuste de saturación (rango RGB)" - -#~ msgid "2nd image not same size as 1st image" -#~ msgstr "A 2ª imaxe non ten o mesmo tamaño que a 1ª" - -#~ msgid "2nd file is not compatible with 1st" -#~ msgstr "O segundo ficheiro non é compatible co primeiro" - -#~ msgid " color balance red " -#~ msgstr " balance da cor vermello" - -#~ msgid " color balance green " -#~ msgstr " balance da cor verde" - -#~ msgid " color balance blue " -#~ msgstr " balance da cor azul" - -#~ msgid "" -#~ " Set color depth to 1-8 bits per color. \n" -#~ " Press [apply] to update the image." -#~ msgstr "" -#~ " Establece a profundidade de cor a 1-8 bits por cor, \n" -#~ " despois prema [Aplicar] para actualizar a imaxe." - -#~ msgid " green" -#~ msgstr " Verde" - -#~ msgid " blue" -#~ msgstr " Azul" - -#~ msgid " adjust red" -#~ msgstr " Axuste vermello" - -#~ msgid "" -#~ " left: no color (grey) \n" -#~ " middle: normal (unmodified) \n" -#~ " right: maximum color" -#~ msgstr "" -#~ "esquerda: sen rango RGB (gris) \n" -#~ " centro: normal (sen modificar) \n" -#~ " dereita: rango máximo RGB" - -#~ msgid "" -#~ " left: no RGB spread (gray) \n" -#~ " middle: normal (unmodified) \n" -#~ " right: maximum RGB spread" -#~ msgstr "" -#~ "esquerda: sen cor (gris) \n" -#~ " centro: normal (sen modificar) \n" -#~ " dereita: máximo cor" - -#~ msgid "" -#~ "\n" -#~ " brightness \n" -#~ " level" -#~ msgstr "" -#~ "\n" -#~ " Brillo \n" -#~ " Nivel" - -#~ msgid "Select image to combine" -#~ msgstr "Seleccionar unha imaxe para combinar" - -#~ msgid "Retouch Image" -#~ msgstr "Retoque de imaxe" - -#~ msgid "Package ufraw required for this function" -#~ msgstr "Precisase o aplicativo «ufraw» para esta función" - -#~ msgid "Merge the images together" -#~ msgstr "Misturar as imaxes en conxunto" - -#~ msgid "Match Images" -#~ msgstr "Ensamblar as imaxes" - -#~ msgid "" -#~ "Drag right image into rough alignment with left \n" -#~ " to rotate, drag right edge up or down" -#~ msgstr "" -#~ "Arrastre a imaxe dereita para aliñala coa da esquerda \n" -#~ " para xirala, arrastre o bordo dereito cara arriba ou abaixo" - -#~ msgid "Auto-search lens mm and bow" -#~ msgstr "Buscar automaticamente o lente (mm) e a curva" - -#~ msgid "Auto" -#~ msgstr "Auto" - -#~ msgid "" -#~ "\n" -#~ " Match Brightness and Color" -#~ msgstr "" -#~ "\n" -#~ " Ensamblar a luminosidade e a cor" - -#~ msgid "color range" -#~ msgstr "Rango da cor" - -#~ msgid "add tags" -#~ msgstr "Etiquetas asignadas" - -#~ msgid "Fix Image Perspective" -#~ msgstr "Fixar a imaxe en perspectiva" - -#~ msgid "Burn" -#~ msgstr "Gravar" - -#~ msgid "color intensity" -#~ msgstr "Intensidade da cor" - -#~ msgid "Warp Image in Selected Area" -#~ msgstr "Deformar imaxe na área seleccionada" - -#~ msgid "Warp Area" -#~ msgstr "Deformación de área" - -#~ msgid "" -#~ " Pull on an image edge using the mouse. \n" -#~ " Make multiple mouse pulls until satisfied. \n" -#~ " When finished, press [done]." -#~ msgstr "" -#~ " Tirar dun bordo da imaxe empregando o rato. \n" -#~ " Facer varios empuxóns co rato até que quede satisfeito. \n" -#~ " Cando teña rematado, seleccione outra área ou prema [Feito]." - -#~ msgid "match any tag" -#~ msgstr "Elexir calquer etiqueta" - -#~ msgid "match all tags" -#~ msgstr "Elexir todas as etiquetas" - -#~ msgid "Tags" -#~ msgstr "Etiquetas" - -#~ msgid "Suspend" -#~ msgstr "Suspender" - -#~ msgid "Set Tile and Gap Size" -#~ msgstr "Axustar mosaico e tamaño da separación" - -#~ msgid "Search Tags" -#~ msgstr "Buscar etiquetas" - -#~ msgid "Resume" -#~ msgstr "Retomar" - -#~ msgid "Basic EXIF data" -#~ msgstr "Datos EXIF básicos" - -#~ msgid "All EXIF data" -#~ msgstr "Todos os datos EXIF" - -#~ msgid "/path*/file*" -#~ msgstr "/ruta*/ficheiro*" - -#~ msgid "HDR" -#~ msgstr "HDR" - -#~ msgid "HDF" -#~ msgstr "HDF" - -#~ msgid "Area" -#~ msgstr "Área" - -#~ msgid "target group area" -#~ msgstr "Área do grupo de destino" - -#~ msgid "vertical unbend" -#~ msgstr "Enderezamento vertical" - -#~ msgid "horizontal unbend" -#~ msgstr "Enderezamento horizontal" - -#~ msgid "Create Launcher" -#~ msgstr "Crear un lanzador" - -#~ msgid "Width" -#~ msgstr "Anchura" - -#~ msgid "Unknown file type, save as tiff/jpeg/png to edit" -#~ msgstr "" -#~ "Tipo de ficheiro descoñecido. gardeo como tiff/jpeg/png para editalo" - -#~ msgid "Undo Last" -#~ msgstr "Desfacer o último" - -#~ msgid "Undo All" -#~ msgstr "Desfacer todo" - -#~ msgid "Start" -#~ msgstr "Comezar" - -#~ msgid "Search" -#~ msgstr "Buscar" - -#~ msgid "Reduce" -#~ msgstr "Reducir" - -#~ msgid "Red" -#~ msgstr "Vermello" - -#~ msgid "Proceed" -#~ msgstr "Proceder" - -#~ msgid "Presets" -#~ msgstr "Predefinidos" - -#~ msgid "Percent" -#~ msgstr "Porcentaxe" - -#~ msgid "OK" -#~ msgstr "Conforme" - -#~ msgid "Lighter Areas" -#~ msgstr "Iluminar áreas" - -#~ msgid "Insert" -#~ msgstr "Inserir" - -#~ msgid "Height" -#~ msgstr "Altura" - -#~ msgid "Green" -#~ msgstr "Verde" - -#~ msgid "Finish" -#~ msgstr "Terminar" - -#~ msgid "Edit" -#~ msgstr "Editar" - -#~ msgid "Done" -#~ msgstr "Feito" - -#~ msgid "Darker Areas" -#~ msgstr "Escurecer áreas" - -#~ msgid "Clear" -#~ msgstr "Limpar" - -#~ msgid "Cancel" -#~ msgstr "Cancelar" - -#~ msgid "Brightness" -#~ msgstr "Brillo" - -#~ msgid "Blue" -#~ msgstr "Azul" - -#~ msgid "Blend Width" -#~ msgstr "Misturar por anchura" - -#~ msgid "Apply" -#~ msgstr "Aplicar" - -#~ msgid "Add All" -#~ msgstr "Engadir todo" - -#~ msgid "Save As" -#~ msgstr "Gardar como" - -#~ msgid "Clone fotoxx" -#~ msgstr "Clonar Fotoxx" - -#~ msgid "Time Interval" -#~ msgstr "Intervalo de tempo" - -#~ msgid "Delete" -#~ msgstr "Borrar" diff -Nru fotoxx-11.11.1/locales/gl/zfuncs.po fotoxx-12.01.2/locales/gl/zfuncs.po --- fotoxx-11.11.1/locales/gl/zfuncs.po 2011-11-05 05:30:37.000000000 +0000 +++ fotoxx-12.01.2/locales/gl/zfuncs.po 1970-01-01 00:00:00.000000000 +0000 @@ -1,290 +0,0 @@ -# Galician translations for home package. -# This file is put in the public domain. -# mico , 2008. -# -msgid "" -msgstr "" -"Project-Id-Version: zfuncs-2.10\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2011-11-05 05:49+0100\n" -"PO-Revision-Date: 2009-10-19 13:41+0100\n" -"Last-Translator: Miguel Anxo Bouzada \n" -"Language-Team: GALPon MiniNo \n" -"Language: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Poedit-Language: Galician\n" -"X-Poedit-Country: SPAIN\n" - -#: zfuncs.cc:3192 -#, c-format -msgid "help file not found: %s" -msgstr "O ficheiro de axuda non se atopa: %s" - -#: zfuncs.cc:3296 -#, c-format -msgid "error: %s" -msgstr "Erro: %s" - -#: zfuncs.cc:4415 zfuncs.cc:8771 -#, c-format -msgid "cannot open file %s" -msgstr "Non se pode abrir o ficheiro %s" - -#: zfuncs.cc:4448 -msgid "save screen to file" -msgstr "Gardar pantalla nun ficheiro" - -#: zfuncs.cc:6198 -msgid "No" -msgstr "" - -#: zfuncs.cc:6198 -msgid "Yes" -msgstr "" - -#: zfuncs.cc:6272 zfuncs.cc:6308 zfuncs.cc:6461 zfuncs.cc:6865 zfuncs.cc:8358 -#: zfuncs.cc:8883 zfuncs.cc:8889 zfuncs.cc:8895 zfuncs.cc:8901 -msgid "cancel" -msgstr "Cancelar" - -#: zfuncs.cc:6423 zfuncs.cc:7552 -msgid "open" -msgstr "Abrir" - -#: zfuncs.cc:6428 -msgid "choose" -msgstr "" - -#: zfuncs.cc:6433 -msgid "save" -msgstr "Gardar" - -#: zfuncs.cc:6439 -msgid "open folder" -msgstr "Abrir cartafol" - -#: zfuncs.cc:6444 -msgid "create folder" -msgstr "Crear cartafol" - -#: zfuncs.cc:6450 -msgid "hidden" -msgstr "Agochar" - -#: zfuncs.cc:6454 -msgid "quality" -msgstr "Calidade" - -#: zfuncs.cc:6511 -msgid "JPG quality 0-100" -msgstr "Calidade de JPG 0-100" - -#: zfuncs.cc:6865 zfuncs.cc:8358 -msgid "done" -msgstr "" - -#: zfuncs.cc:6865 zfuncs.cc:6878 -msgid "margins" -msgstr "" - -#: zfuncs.cc:6874 -msgid "top" -msgstr "" - -#: zfuncs.cc:6875 -msgid "bottom" -msgstr "" - -#: zfuncs.cc:6876 -msgid "left" -msgstr "" - -#: zfuncs.cc:6877 -msgid "right" -msgstr "" - -#: zfuncs.cc:7278 zfuncs.cc:7532 zfuncs.cc:7670 zfuncs.cc:7671 zfuncs.cc:7673 -msgid "bigger" -msgstr "Maior" - -#: zfuncs.cc:7278 -msgid "increase thumbnail size" -msgstr "Aumentar o tamaño da miniatura" - -#: zfuncs.cc:7279 -msgid "reduce thumbnail size" -msgstr "Reducir tamaño da miniatura" - -#: zfuncs.cc:7279 zfuncs.cc:7542 zfuncs.cc:7672 zfuncs.cc:7674 -msgid "smaller" -msgstr "Menor" - -#: zfuncs.cc:7280 zfuncs.cc:7571 -msgid "parent" -msgstr "" - -#: zfuncs.cc:7280 -msgid "parent directory" -msgstr "" - -#: zfuncs.cc:7281 zfuncs.cc:7589 zfuncs.cc:7681 -msgid "first page" -msgstr "Primeira páxina" - -#: zfuncs.cc:7281 -msgid "jump to first file" -msgstr "Cambiar ao primeiro ficheiro" - -#: zfuncs.cc:7282 zfuncs.cc:7587 zfuncs.cc:7676 zfuncs.cc:7683 -msgid "prev page" -msgstr "Páxina anterior" - -#: zfuncs.cc:7282 -msgid "previous page" -msgstr "Páxina anterior" - -#: zfuncs.cc:7283 zfuncs.cc:7585 zfuncs.cc:7678 -msgid "prev row" -msgstr "fila anterior" - -#: zfuncs.cc:7283 -msgid "previous row" -msgstr "Fila anterior" - -#: zfuncs.cc:7284 zfuncs.cc:7586 zfuncs.cc:7679 -msgid "next row" -msgstr "Seguinte fila" - -#: zfuncs.cc:7285 zfuncs.cc:7588 zfuncs.cc:7677 zfuncs.cc:7684 -msgid "next page" -msgstr "Páxina seguinte" - -#: zfuncs.cc:7286 -msgid "jump to last file" -msgstr "Cambiar ao último ficheiro" - -#: zfuncs.cc:7286 zfuncs.cc:7590 zfuncs.cc:7682 -msgid "last page" -msgstr "Última páxina" - -#: zfuncs.cc:7287 zfuncs.cc:7527 -msgid "close" -msgstr "Pechar" - -#: zfuncs.cc:7287 -msgid "close image gallery" -msgstr "Pechar a galería de imaxes" - -#: zfuncs.cc:7558 -msgid "select new file" -msgstr "Seleccionar ficheiro novo" - -#: zfuncs.cc:8358 -msgid "Select Files" -msgstr "" - -#: zfuncs.cc:8366 -msgid "delete" -msgstr "" - -#: zfuncs.cc:8367 -msgid "insert" -msgstr "" - -#: zfuncs.cc:8368 -msgid "add all" -msgstr "" - -#: zfuncs.cc:8658 -msgid "" -"Initial parameters file created. \n" -"Inspect and revise if necessary." -msgstr "" -"Parámetros iniciais creados. \n" -"Revíseseos se o desexa." - -#: zfuncs.cc:8674 -msgid "load parameters from a file" -msgstr "Cargar parámetros desde ficheiro" - -#: zfuncs.cc:8743 -msgid "save parameters to a file" -msgstr "Gardar parámetros nun ficheiro" - -#: zfuncs.cc:8881 zfuncs.cc:8887 zfuncs.cc:8893 zfuncs.cc:8899 -msgid "edit parameters" -msgstr "Editar parámetros" - -#: zfuncs.cc:8882 zfuncs.cc:8888 -msgid "" -"list\n" -"all" -msgstr "" -"Listar\n" -"todo" - -#: zfuncs.cc:8882 zfuncs.cc:8888 zfuncs.cc:8894 zfuncs.cc:8900 -msgid "" -"load\n" -"file" -msgstr "" -"Cargar\n" -"ficheiro" - -#: zfuncs.cc:8882 zfuncs.cc:8888 zfuncs.cc:8894 zfuncs.cc:8900 -msgid "" -"save\n" -"file" -msgstr "" -"Gardar\n" -"ficheiro" - -#: zfuncs.cc:8883 zfuncs.cc:8895 -msgid "" -"add\n" -"new" -msgstr "" -"Engadir\n" -"Novo" - -#: zfuncs.cc:8883 zfuncs.cc:8889 zfuncs.cc:8895 zfuncs.cc:8901 -msgid "apply" -msgstr "Aplicar" - -#: zfuncs.cc:8935 -msgid "apply?" -msgstr "Aplicar?" - -#: zfuncs.cc:8992 -msgid "(new parm name)" -msgstr "(Novo parámetro)" - -#: zfuncs.cc:8992 -msgid "add parameter" -msgstr "Engadir parámetro" - -#~ msgid "open a file" -#~ msgstr "Abrir un ficheiro" - -#~ msgid "xdg-utils package not installed" -#~ msgstr "O paquete «xdg-utils» non está instalado" - -#~ msgid "select new folder" -#~ msgstr "Seleccionar novo cartafol" - -#~ msgid "open a directory" -#~ msgstr "Abrir un novo directório" - -#~ msgid "jump to specific file" -#~ msgstr "Cambia a un ficheiro específico" - -#~ msgid "folder" -#~ msgstr "Cartafol" - -#~ msgid "file" -#~ msgstr "Ficheiro" - -#~ msgid "close thumbnail window" -#~ msgstr "Pechar Índice de miniaturas" diff -Nru fotoxx-11.11.1/locales/it/fotoxx.po fotoxx-12.01.2/locales/it/fotoxx.po --- fotoxx-11.11.1/locales/it/fotoxx.po 2011-11-05 05:30:37.000000000 +0000 +++ fotoxx-12.01.2/locales/it/fotoxx.po 1970-01-01 00:00:00.000000000 +0000 @@ -1,2348 +0,0 @@ -# translation of fotoxx.po to italian -# Eugenio Baldi , 2009. -# (revisione) Doriano Blengino , 2011 -# #-#-#-#-# fotoxx.po (messages) #-#-#-#-# -# Italian translations for home package. -# Copyright (C) 2008 THE home'S COPYRIGHT HOLDER -# This file is distributed under the same license as the home package. -msgid "" -msgstr "" -"Project-Id-Version: fotoxx\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2011-11-05 05:49+0100\n" -"PO-Revision-Date: 2010-06-03 16:14+0100\n" -"Language-Team: italiano \n" -"Language: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n > 1);\n" - -#: fotoxx-11.11.1.cc:179 -msgid "File" -msgstr "File" - -#: fotoxx-11.11.1.cc:180 fotoxx-11.11.1.cc:316 -msgid "Image Gallery" -msgstr "Galleria immagini" - -#: fotoxx-11.11.1.cc:181 -msgid "Clone 50/50" -msgstr "" - -#: fotoxx-11.11.1.cc:182 -msgid "Clone Overlay" -msgstr "" - -#: fotoxx-11.11.1.cc:183 fotoxx-11.11.1.cc:317 fotoxx-11.11.1.cc:2272 -#: fotoxx-11.11.1.cc:2444 -msgid "Open Image File" -msgstr "Apri un'immagine" - -#: fotoxx-11.11.1.cc:184 -msgid "Open in New Window" -msgstr "" - -#: fotoxx-11.11.1.cc:185 fotoxx-11.11.1.cc:318 -msgid "Open Previous File" -msgstr "Apri l'immagine precedente" - -#: fotoxx-11.11.1.cc:186 -msgid "Open Recent File" -msgstr "Apri un file recente" - -#: fotoxx-11.11.1.cc:187 fotoxx-11.11.1.cc:326 -msgid "Save to Same File" -msgstr "Salva (sovrascrivi)" - -#: fotoxx-11.11.1.cc:188 fotoxx-11.11.1.cc:327 -msgid "Save to New Version" -msgstr "" - -#: fotoxx-11.11.1.cc:189 fotoxx-11.11.1.cc:328 -msgid "Save to New File" -msgstr "Salva nuovo..." - -#: fotoxx-11.11.1.cc:190 fotoxx-11.11.1.cc:2990 -msgid "Create Blank Image" -msgstr "Crea immagine vuota" - -#: fotoxx-11.11.1.cc:191 -msgid "Trash Image File" -msgstr "Cestina l'immagine" - -#: fotoxx-11.11.1.cc:192 fotoxx-11.11.1.cc:3216 -msgid "Rename Image File" -msgstr "Rinomina l'immagine" - -#: fotoxx-11.11.1.cc:193 -msgid "Batch Rename Files" -msgstr "Rinomina più immagini" - -#: fotoxx-11.11.1.cc:194 -msgid "Print Image File" -msgstr "Stampa immagine" - -#: fotoxx-11.11.1.cc:195 fotoxx-11.11.1.cc:332 -msgid "Quit fotoxx" -msgstr "Termina fotoxx" - -#: fotoxx-11.11.1.cc:197 -msgid "Tools" -msgstr "Strumenti" - -#: fotoxx-11.11.1.cc:198 fotoxx_tools.cc:70 -msgid "Manage Collections" -msgstr "" - -#: fotoxx-11.11.1.cc:199 fotoxx_tools.cc:373 -msgid "Move Collections" -msgstr "" - -#: fotoxx-11.11.1.cc:200 -msgid "Check Monitor" -msgstr "Verifica luminosità schermo" - -#: fotoxx-11.11.1.cc:201 fotoxx_tools.cc:550 -msgid "Monitor Gamma" -msgstr "Verifica gamma dello schermo" - -#: fotoxx-11.11.1.cc:202 -msgid "Brightness Graph" -msgstr "Diagramma della luminosità" - -#: fotoxx-11.11.1.cc:203 fotoxx_tools.cc:819 -msgid "Slide Show" -msgstr "Slideshow" - -#: fotoxx-11.11.1.cc:204 fotoxx_tools.cc:1668 -msgid "Show RGB" -msgstr "Esplora i colori RGB dei pixel" - -#: fotoxx-11.11.1.cc:205 fotoxx_tools.cc:1962 -msgid "Grid Lines" -msgstr "Linee griglia" - -#: fotoxx-11.11.1.cc:206 fotoxx_tools.cc:2135 -msgid "Lens Parameters" -msgstr "Parametri dell'obbiettivo" - -#: fotoxx-11.11.1.cc:207 -msgid "Change Language" -msgstr "Cambia lingua del programma" - -#: fotoxx-11.11.1.cc:209 -msgid "Add Menu and Launcher" -msgstr "Crea menù e lanciatore" - -#: fotoxx-11.11.1.cc:210 -msgid "Convert RAW files" -msgstr "Conversione di più immagini RAW" - -#: fotoxx-11.11.1.cc:211 -msgid "Burn Images to CD/DVD" -msgstr "Masterizza immagini su CD/DVD" - -#: fotoxx-11.11.1.cc:212 fotoxx_tools.cc:2460 -msgid "E-mail Images" -msgstr "Spedire immagini via e-mail" - -#: fotoxx-11.11.1.cc:213 fotoxx_tools.cc:2783 -msgid "Synchronize Files" -msgstr "Sincronizza file" - -#: fotoxx-11.11.1.cc:214 fotoxx_tools.cc:3376 -msgid "Toolbar Style" -msgstr "" - -#: fotoxx-11.11.1.cc:215 -msgid "Memory Usage" -msgstr "Mostra uso memoria (in console)" - -#: fotoxx-11.11.1.cc:218 -msgid "Edit Caption/Comments" -msgstr "" - -#: fotoxx-11.11.1.cc:219 fotoxx_info.cc:156 -msgid "Edit Tags" -msgstr "Modifica etichette" - -#: fotoxx-11.11.1.cc:220 fotoxx_info.cc:345 -msgid "Manage Tags" -msgstr "Gestione etichette" - -#: fotoxx-11.11.1.cc:221 fotoxx_info.cc:1345 -msgid "Batch Add Tags" -msgstr "Aggiungi etichette a più immagini" - -#: fotoxx-11.11.1.cc:222 fotoxx_info.cc:1547 -msgid "Batch Delete Tag" -msgstr "Cancellazione in blocco di etichette" - -#: fotoxx-11.11.1.cc:223 -msgid "View Info (short)" -msgstr "Vedere informazioni (breve)" - -#: fotoxx-11.11.1.cc:224 -msgid "View Info (long)" -msgstr "Vedere informazioni (lungo)" - -#: fotoxx-11.11.1.cc:225 fotoxx_info.cc:1883 -msgid "Edit Info" -msgstr "Modifica informazioni" - -#: fotoxx-11.11.1.cc:226 fotoxx_info.cc:1981 -msgid "Delete Info" -msgstr "Elimina informazioni" - -#: fotoxx-11.11.1.cc:227 -msgid "Search Images" -msgstr "Ricerca immagini" - -#: fotoxx-11.11.1.cc:229 fotoxx-11.11.1.cc:230 -msgid "Select" -msgstr "Seleziona" - -#: fotoxx-11.11.1.cc:231 -msgid "Show" -msgstr "Visualizza" - -#: fotoxx-11.11.1.cc:232 -msgid "Hide" -msgstr "Nascondi" - -#: fotoxx-11.11.1.cc:233 -msgid "Enable" -msgstr "Abilita" - -#: fotoxx-11.11.1.cc:234 -msgid "Disable" -msgstr "Disabilita" - -#: fotoxx-11.11.1.cc:235 -msgid "Invert" -msgstr "Inverti" - -#: fotoxx-11.11.1.cc:236 -msgid "Unselect" -msgstr "" - -#: fotoxx-11.11.1.cc:237 -msgid "Copy" -msgstr "Copia" - -#: fotoxx-11.11.1.cc:238 -msgid "Paste" -msgstr "Incolla" - -#: fotoxx-11.11.1.cc:239 fotoxx-11.11.1.cc:317 fotoxx_retouch.cc:2314 -#: fotoxx_retouch.cc:2319 -msgid "Open" -msgstr "Carica da file" - -#: fotoxx-11.11.1.cc:240 fotoxx-11.11.1.cc:326 -msgid "Save" -msgstr "Salva" - -#: fotoxx-11.11.1.cc:241 fotoxx_area.cc:2215 -msgid "Select Whole Image" -msgstr "Seleziona l'immagine intera" - -#: fotoxx-11.11.1.cc:242 -msgid "Select and Edit" -msgstr "Seleziona e modifica" - -#: fotoxx-11.11.1.cc:244 -msgid "Transform" -msgstr "Trasforma" - -#: fotoxx-11.11.1.cc:245 fotoxx_transform.cc:60 -msgid "Rotate Image" -msgstr "Ruota immagine" - -#: fotoxx-11.11.1.cc:246 fotoxx_transform.cc:346 -msgid "Trim Image" -msgstr "Ritaglia immagine" - -#: fotoxx-11.11.1.cc:247 fotoxx_transform.cc:972 -msgid "Resize Image" -msgstr "Ridimensiona immagine" - -#: fotoxx-11.11.1.cc:248 -msgid "Batch Resize/Export" -msgstr "Ridimensiona/esporta in blocco" - -#: fotoxx-11.11.1.cc:249 fotoxx_transform.cc:1436 -msgid "Annotate Image" -msgstr "Testo sull'immagine" - -#: fotoxx-11.11.1.cc:250 fotoxx_transform.cc:2193 -msgid "Flip Image" -msgstr "Rifletti Immagine" - -#: fotoxx-11.11.1.cc:251 fotoxx_transform.cc:2303 -msgid "Make Negative" -msgstr "Trasforma in negativo" - -#: fotoxx-11.11.1.cc:252 fotoxx_transform.cc:2420 -msgid "Unbend Image" -msgstr "Svolgi (raddrizza deformazioni obbiettivo)" - -#: fotoxx-11.11.1.cc:253 fotoxx_transform.cc:2704 -msgid "Keystone Correction" -msgstr "" - -#: fotoxx-11.11.1.cc:254 fotoxx_transform.cc:3013 -msgid "Warp Image (area)" -msgstr "Deforma immagine (area)" - -#: fotoxx-11.11.1.cc:255 fotoxx_transform.cc:3255 -msgid "Warp Image (curved)" -msgstr "Deforma immagine (curve)" - -#: fotoxx-11.11.1.cc:256 fotoxx_transform.cc:3518 -msgid "Warp Image (linear)" -msgstr "Deforma immagine (lineare)" - -#: fotoxx-11.11.1.cc:257 fotoxx_transform.cc:3782 -msgid "Warp Image (affine)" -msgstr "Deforma immagine (speculare)" - -#: fotoxx-11.11.1.cc:259 -msgid "Retouch" -msgstr "Ritocco" - -#: fotoxx-11.11.1.cc:260 -msgid "Brightness/Color" -msgstr "Luminosità e colore" - -#: fotoxx-11.11.1.cc:261 -msgid "Gamma Curves" -msgstr "" - -#: fotoxx-11.11.1.cc:262 -msgid "Expand Brightness" -msgstr "Espandi luminosità" - -#: fotoxx-11.11.1.cc:263 -msgid "Flatten Brightness" -msgstr "Normalizza la luminosità" - -#: fotoxx-11.11.1.cc:264 -msgid "Brightness Ramp" -msgstr "Mappatura della luce" - -#: fotoxx-11.11.1.cc:265 fotoxx_retouch.cc:1729 -msgid "Tone Mapping" -msgstr "Mappa tonalità" - -#: fotoxx-11.11.1.cc:266 -msgid "White Balance" -msgstr "Bilanciamento del bianco" - -#: fotoxx-11.11.1.cc:267 -msgid "Match Colors" -msgstr "" - -#: fotoxx-11.11.1.cc:269 fotoxx_retouch.cc:2941 -msgid "Revise RGB" -msgstr "" - -#: fotoxx-11.11.1.cc:270 -msgid "Red Eyes" -msgstr "Correzione occhi rossi" - -#: fotoxx-11.11.1.cc:271 -msgid "Blur Image" -msgstr "Sfocatura Immagine" - -#: fotoxx-11.11.1.cc:272 fotoxx_retouch.cc:4077 -msgid "Sharpen Image" -msgstr "Contrasta immagine" - -#: fotoxx-11.11.1.cc:273 -msgid "Reduce Noise" -msgstr "Riduci disturbo" - -#: fotoxx-11.11.1.cc:274 fotoxx_retouch.cc:4881 -msgid "Smart Erase" -msgstr "Cancellazione intelligente" - -#: fotoxx-11.11.1.cc:275 fotoxx_retouch.cc:5271 -msgid "Remove Dust" -msgstr "Rimozione polvere" - -#: fotoxx-11.11.1.cc:276 fotoxx_retouch.cc:5877 -msgid "Edit Pixels" -msgstr "Modifica dei pixel" - -#: fotoxx-11.11.1.cc:278 -msgid "Art" -msgstr "Arte" - -#: fotoxx-11.11.1.cc:279 -msgid "Color Depth" -msgstr "Profondità di colore" - -#: fotoxx-11.11.1.cc:280 -msgid "Drawing" -msgstr "Disegno" - -#: fotoxx-11.11.1.cc:281 -msgid "Outlines" -msgstr "Contorni" - -#: fotoxx-11.11.1.cc:282 -msgid "Embossing" -msgstr "Bassorilievo" - -#: fotoxx-11.11.1.cc:283 -msgid "Tiles" -msgstr "Mosaico" - -#: fotoxx-11.11.1.cc:284 -msgid "Dots" -msgstr "Puntinismo" - -#: fotoxx-11.11.1.cc:285 -msgid "Painting" -msgstr "Pittura" - -#: fotoxx-11.11.1.cc:287 -msgid "Combine" -msgstr "Combina" - -#: fotoxx-11.11.1.cc:288 -msgid "High Dynamic Range" -msgstr "Combina immagini (alta dinamica - HDR)" - -#: fotoxx-11.11.1.cc:289 -msgid "High Depth of Field" -msgstr "Combina immagini (grande profondità - HDF)" - -#: fotoxx-11.11.1.cc:290 -msgid "Stack / Paint" -msgstr "Sovrapponi (interattivo con mouse)" - -#: fotoxx-11.11.1.cc:291 -msgid "Stack / Noise" -msgstr "Sovrapponi (rimozione disturbo)" - -#: fotoxx-11.11.1.cc:292 -msgid "Panorama" -msgstr "Crea un panorama" - -#: fotoxx-11.11.1.cc:293 -msgid "Vertical Panorama" -msgstr "Panorama verticale" - -#: fotoxx-11.11.1.cc:296 -msgid "Edit Plugins" -msgstr "Gestione plug-in" - -#: fotoxx-11.11.1.cc:305 fotoxx-11.11.1.cc:333 fotoxx-11.11.1.cc:4616 -msgid "Help" -msgstr "Aiuto" - -#: fotoxx-11.11.1.cc:306 fotoxx-11.11.1.cc:4606 -msgid "About" -msgstr "Info" - -#: fotoxx-11.11.1.cc:307 fotoxx-11.11.1.cc:4610 -msgid "User Guide" -msgstr "Guida Utente" - -#: fotoxx-11.11.1.cc:308 fotoxx-11.11.1.cc:4613 -msgid "User Guide Changes" -msgstr "" - -#: fotoxx-11.11.1.cc:309 fotoxx-11.11.1.cc:4622 -msgid "Edit Functions Summary" -msgstr "" - -#: fotoxx-11.11.1.cc:310 fotoxx-11.11.1.cc:4625 -msgid "Change Log" -msgstr "Cronistoria delle modifiche" - -#: fotoxx-11.11.1.cc:311 fotoxx-11.11.1.cc:4628 -msgid "Translations" -msgstr "" - -#: fotoxx-11.11.1.cc:312 fotoxx-11.11.1.cc:4631 -msgid "Home Page" -msgstr "Sito WEB" - -#: fotoxx-11.11.1.cc:316 -msgid "Gallery" -msgstr "Miniature" - -#: fotoxx-11.11.1.cc:318 fotoxx_transform.cc:995 -msgid "Prev" -msgstr "Prec." - -#: fotoxx-11.11.1.cc:319 -msgid "Next" -msgstr "Prossima" - -#: fotoxx-11.11.1.cc:319 -msgid "Open Next File" -msgstr "Apri l'immagine successiva" - -#: fotoxx-11.11.1.cc:320 -msgid "Zoom-in (bigger)" -msgstr "Ingrandire" - -#: fotoxx-11.11.1.cc:321 -msgid "Zoom-out (smaller)" -msgstr "Ridurre" - -#: fotoxx-11.11.1.cc:322 -msgid "Undo" -msgstr "Annulla" - -#: fotoxx-11.11.1.cc:322 -msgid "Undo One Edit" -msgstr "Annulla l'ultima modifica" - -#: fotoxx-11.11.1.cc:323 -msgid "Redo" -msgstr "Ripeti" - -#: fotoxx-11.11.1.cc:323 -msgid "Redo One Edit" -msgstr "Ripeti una modifica" - -#: fotoxx-11.11.1.cc:327 -msgid "Save+V" -msgstr "" - -#: fotoxx-11.11.1.cc:328 -msgid "Save+F" -msgstr "" - -#: fotoxx-11.11.1.cc:329 -msgid "Move Image to Trash" -msgstr "Sposta l'immagine nel cestino" - -#: fotoxx-11.11.1.cc:329 -msgid "Trash" -msgstr "Cestina" - -#: fotoxx-11.11.1.cc:332 -msgid "Quit" -msgstr "Uscita" - -#: fotoxx-11.11.1.cc:333 -msgid "Fotoxx Essentials" -msgstr "Fotoxx Essentials" - -#: fotoxx-11.11.1.cc:429 -msgid "first time startup" -msgstr "" - -#: fotoxx-11.11.1.cc:1815 -msgid "Exceed 50 anchor points" -msgstr "Superati 50 punti di ancoraggio" - -#: fotoxx-11.11.1.cc:2000 -msgid "load curve from a file" -msgstr "caricare curva da file" - -#: fotoxx-11.11.1.cc:2053 -msgid "curve file is invalid" -msgstr "File delle curve non valido" - -#: fotoxx-11.11.1.cc:2058 -msgid "curve file has different no. of curves" -msgstr "Il file delle curve ha un numero diverso di curve" - -#: fotoxx-11.11.1.cc:2073 -msgid "save curve to a file" -msgstr "salva curva in un file" - -#: fotoxx-11.11.1.cc:2420 -#, c-format -msgid "" -"Discard special gallery list? \n" -" %s" -msgstr "" - -#: fotoxx-11.11.1.cc:2430 fotoxx-11.11.1.cc:4452 -msgid "prior function still active" -msgstr "" -"Una funzione interattiva è ancora in uso\n" -"Terminare tale funzione e riprovare." - -#: fotoxx-11.11.1.cc:2607 -msgid "Overwrite original file?" -msgstr "" - -#: fotoxx-11.11.1.cc:2608 -msgid "Do not warn again" -msgstr "" - -#: fotoxx-11.11.1.cc:2624 -msgid "Warning" -msgstr "" - -#: fotoxx-11.11.1.cc:2747 -msgid "Save File" -msgstr "Salva file" - -#: fotoxx-11.11.1.cc:2770 -msgid "quality" -msgstr "Qualità" - -#: fotoxx-11.11.1.cc:2772 -msgid "make current" -msgstr "" - -#: fotoxx-11.11.1.cc:2829 -msgid "jpeg quality must be 1-100" -msgstr "la qualità jpeg deve essere 1-100" - -#: fotoxx-11.11.1.cc:2851 -#, c-format -msgid "" -"Overwrite file? \n" -" %s" -msgstr "" -"Sovrascrivere il file? \n" -" %s" - -#: fotoxx-11.11.1.cc:2992 -msgid "file name" -msgstr "" - -#: fotoxx-11.11.1.cc:2997 fotoxx_transform.cc:351 -msgid "width" -msgstr "larghezza" - -#: fotoxx-11.11.1.cc:3000 fotoxx_transform.cc:354 -msgid "height" -msgstr "altezza" - -#: fotoxx-11.11.1.cc:3006 fotoxx_art.cc:628 fotoxx_retouch.cc:5881 -msgid "color" -msgstr "Colore" - -#: fotoxx-11.11.1.cc:3120 -msgid "" -"Linux standard trash is not supported. \n" -"Desktop trash folder will be created." -msgstr "" -"Non è supportato il cestino strandard di Linux. \n" -"Sarà creata una cartella/cestino dedicata." - -#: fotoxx-11.11.1.cc:3138 -msgid "Move read-only file to trash?" -msgstr "Spostare il file in sola lettura nel cestino ?" - -#: fotoxx-11.11.1.cc:3164 -#, c-format -msgid "Cannot create trash folder: %s" -msgstr "Impossible creare il cestino: %s" - -#: fotoxx-11.11.1.cc:3172 fotoxx-11.11.1.cc:3178 -#, c-format -msgid "error: %s" -msgstr "errore: %s" - -#: fotoxx-11.11.1.cc:3221 -msgid "old name" -msgstr "Vecchio nome" - -#: fotoxx-11.11.1.cc:3222 -msgid "rename to" -msgstr "Rinominare in" - -#: fotoxx-11.11.1.cc:3223 -msgid "previous" -msgstr "Prec." - -#: fotoxx-11.11.1.cc:3309 -msgid "The target file already exists" -msgstr "Il file di destinazione esiste già" - -#: fotoxx-11.11.1.cc:3317 -#, c-format -msgid "" -"Rename failed: \n" -" %s" -msgstr "" - -#: fotoxx-11.11.1.cc:3365 -msgid "Batch Rename" -msgstr "Rinomina più immagini" - -#: fotoxx-11.11.1.cc:3368 fotoxx-11.11.1.cc:3420 fotoxx_info.cc:1513 -#: fotoxx_info.cc:1767 fotoxx_tools.cc:2510 fotoxx_transform.cc:1213 -#, c-format -msgid "%d files selected" -msgstr "" - -#: fotoxx-11.11.1.cc:3370 -msgid "new base name" -msgstr "Nuovo nome" - -#: fotoxx-11.11.1.cc:3373 -msgid "starting sequence" -msgstr "inizio sequenza" - -#: fotoxx-11.11.1.cc:3375 -msgid "increment" -msgstr "incremento" - -#: fotoxx-11.11.1.cc:3396 -msgid "select files to rename" -msgstr "scegliere i file da rinominare" - -#: fotoxx-11.11.1.cc:3401 -msgid "base name / sequence / increment not reasonable" -msgstr "nome principale / sequenza / incremento non ragionevole" - -#: fotoxx-11.11.1.cc:3460 -msgid "new file already exists:" -msgstr "Nuovo file già esistente:" - -#: fotoxx-11.11.1.cc:3468 -msgid "filespec too long:" -msgstr "nome file troppo lungo:" - -#: fotoxx-11.11.1.cc:3479 -msgid "Rename failed:" -msgstr "Rinominazione fallita:" - -#: fotoxx-11.11.1.cc:3739 -msgid "Add" -msgstr "Aggiungere" - -#: fotoxx-11.11.1.cc:3739 -msgid "Remove" -msgstr "Taglia" - -#: fotoxx-11.11.1.cc:3741 -msgid "menu name" -msgstr "" - -#: fotoxx-11.11.1.cc:3812 fotoxx-11.11.1.cc:3833 -msgid "Restart Fotoxx to update plugin menu" -msgstr "Riavviare fotoxx per aggiornae il menù Plugins" - -#: fotoxx-11.11.1.cc:3927 -msgid "cannot parallel edit" -msgstr "" - -#: fotoxx-11.11.1.cc:3937 -msgid "" -"exiftool is not installed \n" -"edited images will lose EXIF data" -msgstr "" -"Il programma exiftool non è installato.\n" -"Le immagini modificate perderanno le informazioni Exif." - -#: fotoxx-11.11.1.cc:3943 -msgid "Too many edits, please save image" -msgstr "Troppe modifiche, salvare l'immagine" - -#: fotoxx-11.11.1.cc:3948 -msgid "" -"Select area cannot be kept.\n" -"Continue?" -msgstr "" -"L'area selezionata non può essere mantenuta.\n" -"Continuare?" - -#: fotoxx-11.11.1.cc:3956 -msgid "" -"Select area not active.\n" -"Continue?" -msgstr "" -"Selezione di area non attiva.\n" -"Continuare?" - -#: fotoxx-11.11.1.cc:4427 -msgid "Discard edits?" -msgstr "" - -#: fotoxx-11.11.1.cc:4428 -msgid "" -"This action will discard current edits.\n" -"Continue to discard edits.\n" -"Go Back to keep edits." -msgstr "" - -#: fotoxx-11.11.1.cc:4431 -msgid "Continue" -msgstr "" - -#: fotoxx-11.11.1.cc:4432 -msgid "Go Back" -msgstr "" - -#: fotoxx-11.11.1.cc:5240 -msgid "cannot open thumbnail file" -msgstr "impossibile aprire il file delle anteprime" - -#: fotoxx-11.11.1.cc:5433 fotoxx-11.11.1.cc:5549 -msgid "TIFF open failure" -msgstr "Apertura TIFF fallita" - -#: fotoxx-11.11.1.cc:5449 -#, c-format -msgid "TIFF bits/color=%d not supported" -msgstr "TIFF bit/colori=%d non supportati" - -#: fotoxx-11.11.1.cc:5464 fotoxx-11.11.1.cc:5502 -msgid "TIFF read failure" -msgstr "Lettura TIFF fallita" - -#: fotoxx-11.11.1.cc:5608 -msgid "TIFF write failure" -msgstr "Scrittura TIFF fallita" - -#: fotoxx-11.11.1.cc:5638 -msgid "file type not supported" -msgstr "tipo di file non supportato" - -#: fotoxx-11.11.1.cc:5745 -msgid "pixbuf write failure" -msgstr "scrittura pixbuf fallita" - -#: fotoxx_area.cc:54 fotoxx_area.cc:2427 -msgid "Select Area for Edits" -msgstr "Selezione dell'area per modifiche" - -#: fotoxx_area.cc:55 fotoxx_area.cc:2428 -msgid "Press F1 for help" -msgstr "Premere F1 per l'aiuto" - -#: fotoxx_area.cc:63 -msgid "" -"Select Area not supported \n" -"by this edit function" -msgstr "" - -#: fotoxx_area.cc:99 fotoxx_tools.cc:809 -msgid "rectangle" -msgstr "Rettangolo" - -#: fotoxx_area.cc:100 fotoxx_tools.cc:810 -msgid "ellipse" -msgstr "Ellisse" - -#: fotoxx_area.cc:101 -msgid "draw: freehand" -msgstr "disegno: mano libera" - -#: fotoxx_area.cc:102 -msgid "draw: follow edge" -msgstr "disegno: segui bordi" - -#: fotoxx_area.cc:103 -msgid "select by mouse" -msgstr "selezione col mouse" - -#: fotoxx_area.cc:104 -msgid "select by color" -msgstr "selezione per colore" - -#: fotoxx_area.cc:112 -msgid "radius" -msgstr "Raggio" - -#: fotoxx_area.cc:116 -msgid "match" -msgstr "similarità:" - -#: fotoxx_area.cc:121 -msgid "firewall" -msgstr "confinamento" - -#: fotoxx_area.cc:274 fotoxx_area.cc:415 -#, c-format -msgid "exceed %d edits" -msgstr "superato %d modifiche" - -#: fotoxx_area.cc:992 -msgid "" -"Click one time inside each enclosed area \n" -"(possible gaps in the outline will be found). \n" -"Press F1 for help." -msgstr "Premere F1 per l'aiuto" - -#: fotoxx_area.cc:1049 -msgid "finish area" -msgstr "area finitura" - -#: fotoxx_area.cc:1083 -msgid "searching" -msgstr "in ricerca" - -#: fotoxx_area.cc:1155 -msgid "outline has a gap" -msgstr "il contorno è interrotto" - -#: fotoxx_area.cc:1157 -msgid "success" -msgstr "successo" - -#: fotoxx_area.cc:1401 fotoxx_area.cc:1430 -msgid "the area is not finished" -msgstr "l'area non è chiusa" - -#: fotoxx_area.cc:1522 -msgid "Edge calculation in progress" -msgstr "Ricalcolo bordo in corso" - -#: fotoxx_area.cc:1531 -msgid "Area Edge Calc" -msgstr "Calcolo area delimitata" - -#: fotoxx_area.cc:1824 -msgid "position with mouse click/drag" -msgstr "posizione con clic o trascinamento mouse" - -#: fotoxx_area.cc:1848 -msgid "Paste Image" -msgstr "Incolla immagine" - -#: fotoxx_area.cc:1863 -msgid "angle" -msgstr "angolo" - -#: fotoxx_area.cc:2127 -msgid "load select area from a file" -msgstr "caricare l'area di selezione da file" - -#: fotoxx_area.cc:2161 -msgid "cannot open .tiff and .info files" -msgstr "impossibile aprire i file .tiff e .info" - -#: fotoxx_area.cc:2180 -msgid "save select area to a file" -msgstr "salva area in un file" - -#: fotoxx_area.cc:2216 -msgid "Edit Function Amplifier" -msgstr "Regola amplificazione di funzione" - -#: fotoxx_area.cc:2459 -msgid "mouse radius" -msgstr "Raggio del mouse" - -#: fotoxx_area.cc:2462 -msgid "power: center" -msgstr "Forza: centro" - -#: fotoxx_area.cc:2464 -msgid "edge" -msgstr "bordo" - -#: fotoxx_area.cc:2468 -msgid "reset area" -msgstr "Azzera area" - -#: fotoxx_area.cc:2523 -msgid "start edit function first" -msgstr "Richiamare prima una funzione di modifica (Ritocco, Trasforma...)" - -#: fotoxx_art.cc:47 -msgid "Set color depth to 1-16 bits" -msgstr "Imposta la profondità del colore da 1 a 16 bit" - -#: fotoxx_art.cc:57 -msgid "Set Color Depth" -msgstr "Imposta la profondità di colore" - -#: fotoxx_art.cc:171 -msgid "Simulate Drawing" -msgstr "Simula disegno" - -#: fotoxx_art.cc:213 fotoxx_retouch.cc:1758 -msgid "contrast" -msgstr "Contrasto" - -#: fotoxx_art.cc:215 -msgid "outlines" -msgstr "Contorni" - -#: fotoxx_art.cc:220 -msgid "pencil" -msgstr "Matita" - -#: fotoxx_art.cc:221 -msgid "chalk" -msgstr "Gessetto" - -#: fotoxx_art.cc:381 -msgid "Add Image Outlines" -msgstr "Aggiunta contorni" - -#: fotoxx_art.cc:394 -msgid "outline threshold" -msgstr "soglia del contorno" - -#: fotoxx_art.cc:397 -msgid "outline width" -msgstr "spessore contorno" - -#: fotoxx_art.cc:400 -msgid "image brightness" -msgstr "luminosità immagine" - -#: fotoxx_art.cc:611 -msgid "Simulate Embossing" -msgstr "Simula un bassorilievo" - -#: fotoxx_art.cc:626 -msgid "depth" -msgstr "Profondità" - -#: fotoxx_art.cc:821 -msgid "Simulate Tiles" -msgstr "Simula un mosaico" - -#: fotoxx_art.cc:825 -msgid "tile size" -msgstr "Dimensione dei tasselli" - -#: fotoxx_art.cc:829 -msgid "tile gap" -msgstr "Distanza fra i tasselli" - -#: fotoxx_art.cc:1003 -msgid "Convert Image to Dots" -msgstr "Converti immagine in punti" - -#: fotoxx_art.cc:1007 -msgid "dot size" -msgstr "dimensione punto" - -#: fotoxx_art.cc:1222 -msgid "Simulate Painting" -msgstr "Simula una pittura" - -#: fotoxx_art.cc:1226 -msgid "color depth" -msgstr "Profondità dei colori" - -#: fotoxx_art.cc:1230 -msgid "patch area goal" -msgstr "Fattore artistico" - -#: fotoxx_art.cc:1234 -msgid "req. color match" -msgstr "Precisione colori" - -#: fotoxx_art.cc:1238 -msgid "borders" -msgstr "Contorni" - -#: fotoxx_comp.cc:1956 fotoxx_comp.cc:1961 fotoxx_comp.cc:2582 -#: fotoxx_comp.cc:2587 fotoxx_comp.cc:3275 fotoxx_comp.cc:3280 -#: fotoxx_comp.cc:3830 fotoxx_comp.cc:3835 -msgid "Select 2 to 9 files" -msgstr "Scegliere da 2 a 9 file" - -#: fotoxx_comp.cc:1982 fotoxx_comp.cc:2608 fotoxx_comp.cc:3301 -#: fotoxx_comp.cc:3856 -msgid "Images are not all the same size" -msgstr "Le immagini non hanno la stessa dimensione" - -#: fotoxx_comp.cc:2321 -msgid "Adjust Image Contributions" -msgstr "Regola contributi immagine" - -#: fotoxx_comp.cc:2324 fotoxx_retouch.cc:885 -msgid "dark pixels" -msgstr "pixel scuri" - -#: fotoxx_comp.cc:2326 -msgid "light pixels" -msgstr "pixel luminosi" - -#: fotoxx_comp.cc:2328 fotoxx_info.cc:159 -msgid "file:" -msgstr "File:" - -#: fotoxx_comp.cc:2844 -msgid "Paint and Warp Image" -msgstr "Dipingi e deforma immagine" - -#: fotoxx_comp.cc:2847 fotoxx_comp.cc:3529 fotoxx_comp.cc:4972 -#: fotoxx_comp.cc:5717 -msgid "image" -msgstr "immagine" - -#: fotoxx_comp.cc:2851 fotoxx_retouch.cc:5885 -msgid "paint" -msgstr "Pittura" - -#: fotoxx_comp.cc:2852 -msgid "warp" -msgstr "deformazione" - -#: fotoxx_comp.cc:3527 -msgid "Select and Paint Image" -msgstr "Seleziona e disegna" - -#: fotoxx_comp.cc:4045 -msgid "Adjust Pixel Composition" -msgstr "Regola la composizione dei pixel" - -#: fotoxx_comp.cc:4297 fotoxx_comp.cc:4302 fotoxx_comp.cc:5186 -#: fotoxx_comp.cc:5191 -msgid "Select 2 to 4 files" -msgstr "Scegliere da 2 a 4 file" - -#: fotoxx_comp.cc:4374 -msgid "" -"Drag images into rough alignment.\n" -"To rotate, drag from lower edge." -msgstr "" -"Trascinare le immagini a un allineamento approssimativo.\n" -"Per ruotarle, trascinare il bordo inferiore." - -#: fotoxx_comp.cc:4376 -msgid "Search for lens mm and bow" -msgstr "Ricerca per mm e curvatura obbiettivo" - -#: fotoxx_comp.cc:4422 fotoxx_comp.cc:5310 -msgid "Pre-align Images" -msgstr "Pre allineamento immagini" - -#: fotoxx_comp.cc:4426 fotoxx_comp.cc:5314 fotoxx_tools.cc:2151 -msgid "lens mm" -msgstr "mm focale" - -#: fotoxx_comp.cc:4430 fotoxx_comp.cc:5318 fotoxx_tools.cc:2156 -msgid "lens bow" -msgstr "curvatura" - -#: fotoxx_comp.cc:4432 fotoxx_comp.cc:5320 -msgid "Resize" -msgstr "Ridimensiona" - -#: fotoxx_comp.cc:4433 fotoxx_comp.cc:5321 -msgid "resize window" -msgstr "ridimensiona finestra" - -#: fotoxx_comp.cc:4470 -msgid "use two images only" -msgstr "utilizza solo due immagini" - -#: fotoxx_comp.cc:4491 fotoxx_comp.cc:4689 fotoxx_comp.cc:4888 -#: fotoxx_comp.cc:5369 fotoxx_comp.cc:5632 -msgid "Too little overlap, cannot align" -msgstr "Troppo poca sovrapposizione, impossibile allineare" - -#: fotoxx_comp.cc:4963 fotoxx_comp.cc:5708 -msgid "Match Brightness and Color" -msgstr "Confronta luminosità e colore" - -#: fotoxx_comp.cc:4987 fotoxx_comp.cc:5732 -msgid "auto color" -msgstr "colori automatici" - -#: fotoxx_comp.cc:4988 fotoxx_comp.cc:5733 -msgid "file color" -msgstr "file colore" - -#: fotoxx_comp.cc:5263 -msgid "" -"Drag images into rough alignment.\n" -"To rotate, drag from right edge." -msgstr "" -"Trascinare le immagini a un allineamento approssimativo.\n" -"Per ruotarle, trascinare il bordo destro." - -#: fotoxx_info.cc:70 -msgid "Edit Caption and Comments" -msgstr "" - -#: fotoxx_info.cc:163 -msgid "image date (yyyymmdd)" -msgstr "Data immagine (aaaammgg)" - -#: fotoxx_info.cc:165 -msgid "use last" -msgstr "Utilizza ultima" - -#: fotoxx_info.cc:168 -msgid "image stars" -msgstr "Valutazione dell'immagine" - -#: fotoxx_info.cc:186 -msgid "current tags" -msgstr "Etichette attuali" - -#: fotoxx_info.cc:191 -msgid "recent tags" -msgstr "etichette recenti" - -#: fotoxx_info.cc:196 fotoxx_info.cc:358 fotoxx_info.cc:1362 -#: fotoxx_info.cc:2290 -msgid "defined tags" -msgstr "etichette definite" - -#: fotoxx_info.cc:348 -msgid "category" -msgstr "categoria" - -#: fotoxx_info.cc:351 -msgid "tag" -msgstr "etichetta" - -#: fotoxx_info.cc:354 -msgid "create" -msgstr "Crea" - -#: fotoxx_info.cc:355 -msgid "delete" -msgstr "Elimina" - -#: fotoxx_info.cc:1229 fotoxx_info.cc:1313 -#, c-format -msgid "search index file error: %s" -msgstr "Errore in lettura file indice di ricerca: %s" - -#: fotoxx_info.cc:1348 -msgid "tags to add" -msgstr "etichette da aggiungere" - -#: fotoxx_info.cc:1353 -msgid "create tag" -msgstr "Crea etichetta" - -#: fotoxx_info.cc:1409 fotoxx_info.cc:1602 -#, c-format -msgid "" -"%s \n" -" too many tags" -msgstr "" -"%s \n" -" troppe etichette" - -#: fotoxx_info.cc:1550 -msgid "tag to remove" -msgstr "etichetta da rimuovere" - -#: fotoxx_info.cc:1554 -msgid "optional replacement" -msgstr "sostituzione opzionale" - -#: fotoxx_info.cc:1559 fotoxx_tools.cc:2463 -msgid "0 files selected" -msgstr "" - -#: fotoxx_info.cc:1562 -msgid "search all files" -msgstr "cerca tutti i file" - -#: fotoxx_info.cc:1647 -msgid "no files selected" -msgstr "nessun file selezionato" - -#: fotoxx_info.cc:1653 -msgid "no tag specified" -msgstr "nessuna etichetta specificata" - -#: fotoxx_info.cc:1677 fotoxx_info.cc:1706 -msgid "specify tag" -msgstr "specificare etichetta" - -#: fotoxx_info.cc:1815 -msgid "View Info" -msgstr "Vedere informazioni" - -#: fotoxx_info.cc:1983 -msgid "All" -msgstr "Tutto" - -#: fotoxx_info.cc:1984 -msgid "One Key:" -msgstr "Una chiave:" - -#: fotoxx_info.cc:2249 -msgid "Search Tags, Comments, File Names" -msgstr "Cerca in etichette, commenti, nomi file" - -#: fotoxx_info.cc:2255 -msgid "date range" -msgstr "Date: " - -#: fotoxx_info.cc:2256 -msgid "stars range" -msgstr "Valuazione" - -#: fotoxx_info.cc:2257 -msgid "search tags" -msgstr "Cerca etichette" - -#: fotoxx_info.cc:2258 -msgid "search text" -msgstr "Ricerca testo" - -#: fotoxx_info.cc:2259 -msgid "file names" -msgstr "nomi dei file" - -#: fotoxx_info.cc:2264 -msgid "(yyyymmdd)" -msgstr "" - -#: fotoxx_info.cc:2270 -msgid "all/any" -msgstr "" - -#: fotoxx_info.cc:2598 -msgid "No matching images found" -msgstr "Nessuna immagine soddisfa la ricerca" - -#: fotoxx_info.cc:2611 -msgid "No search index file present" -msgstr "File per la ricerca indicizzata non esistente." - -#: fotoxx_info.cc:2615 -#, c-format -msgid "Search results file error %s" -msgstr "Trovati %s risultati nel file errori" - -#: fotoxx_retouch.cc:55 -msgid "Adjust Brightness and Color" -msgstr "Regola luminosità e colore" - -#: fotoxx_retouch.cc:109 -msgid "small-steps" -msgstr "" - -#: fotoxx_retouch.cc:118 -msgid "color saturation" -msgstr "Saturazione dei colori" - -#: fotoxx_retouch.cc:125 -msgid " reset 1 " -msgstr " reset 1x" - -#: fotoxx_retouch.cc:126 -msgid "reset all" -msgstr "Azzerare tutto" - -#: fotoxx_retouch.cc:598 -msgid "adjust image gamma" -msgstr "" - -#: fotoxx_retouch.cc:884 -msgid "Expand Brightness Range" -msgstr "Espandi escursione di luminosità" - -#: fotoxx_retouch.cc:886 -msgid "bright pixels" -msgstr "pixel luminosi" - -#: fotoxx_retouch.cc:1057 -msgid "Flatten Brightness Distribution" -msgstr "Distribuzione normalizzata della luminosità" - -#: fotoxx_retouch.cc:1071 -msgid "Flatten" -msgstr "Quantità" - -#: fotoxx_retouch.cc:1333 -msgid "Ramp brightness across image" -msgstr "Curve della luminosità sull'immagine" - -#: fotoxx_retouch.cc:1757 -msgid "low" -msgstr "" - -#: fotoxx_retouch.cc:1759 -msgid "high" -msgstr "" - -#: fotoxx_retouch.cc:1762 -msgid "Amplify" -msgstr "Amplificazione" - -#: fotoxx_retouch.cc:2068 -msgid "Adjust White Balance" -msgstr "Regola bilanciamento del bianco" - -#: fotoxx_retouch.cc:2069 -msgid "Click white or gray image location" -msgstr "Cliccare un punto [che dovrebbe essere] bianco o grigio" - -#: fotoxx_retouch.cc:2283 -msgid "Color Match Images" -msgstr "" - -#: fotoxx_retouch.cc:2312 -msgid "mouse radius for color sample" -msgstr "" - -#: fotoxx_retouch.cc:2315 -msgid "image for source color" -msgstr "" - -#: fotoxx_retouch.cc:2317 -msgid "click on image to get source color" -msgstr "" - -#: fotoxx_retouch.cc:2320 -msgid "image to set matching color" -msgstr "" - -#: fotoxx_retouch.cc:2322 -msgid "click on image to set matching color" -msgstr "" - -#: fotoxx_retouch.cc:2377 -msgid "select source image color first" -msgstr "" - -#: fotoxx_retouch.cc:2903 fotoxx_tools.cc:1643 -msgid "Click image to select pixels." -msgstr "" - -#: fotoxx_retouch.cc:2955 -msgid "Metric:" -msgstr "" - -#: fotoxx_retouch.cc:3010 -msgid "Blend" -msgstr "" - -#: fotoxx_retouch.cc:3394 -msgid "" -"Method 1:\n" -" Left-click on red-eye to darken.\n" -"Method 2:\n" -" Drag down and right to enclose red-eye.\n" -" Left-click on red-eye to darken.\n" -"Undo red-eye:\n" -" Right-click on red-eye." -msgstr "" -"Metodo 1:\n" -" - Cliccare col pulsante sinistro sull'occhio rosso per scurirlo.\n" -"Metodo 2:\n" -" - Trascinare verso destra e in basso per circondare l'occhio rosso. \n" -" - Cliccare col pulsante sinistro sull'occhio rosso per scurirlo. \n" -"Per annullare:\n" -" - Cliccare col pulsante destro sull'occhio rosso." - -#: fotoxx_retouch.cc:3409 -msgid "Red Eye Reduction" -msgstr "Riduzione occhi rossi" - -#: fotoxx_retouch.cc:3850 -msgid "Set Blur Radius" -msgstr "Imposta il raggio di sfocatura" - -#: fotoxx_retouch.cc:4084 -msgid "edge detection" -msgstr "Riconoscimento dei bordi" - -#: fotoxx_retouch.cc:4085 -msgid "cycles" -msgstr "Cicli" - -#: fotoxx_retouch.cc:4086 -msgid "reduce" -msgstr "Riduzione" - -#: fotoxx_retouch.cc:4097 -msgid "unsharp mask" -msgstr "Maschera di contrasto" - -#: fotoxx_retouch.cc:4110 -msgid "brightness gradient" -msgstr "gradiente di luminosità" - -#: fotoxx_retouch.cc:4516 -msgid "" -" Press the reduce button to \n" -" reduce noise in small steps. \n" -" Use undo to start over." -msgstr "" -" Cliccare [Ridurre] per ridurre il disturbo \n" -" a piccoli passi. \n" -" Usare [Annulla] per ricominciare." - -#: fotoxx_retouch.cc:4527 -msgid "Noise Reduction" -msgstr "Riduzione disturbo" - -#: fotoxx_retouch.cc:4532 -msgid "algorithm" -msgstr "Algoritmo" - -#: fotoxx_retouch.cc:4539 -msgid "flatten outliers by color (1)" -msgstr "Appiattire livelli di colore (1)" - -#: fotoxx_retouch.cc:4540 -msgid "flatten outliers by color (2)" -msgstr "Appiattire livelli di colore (2)" - -#: fotoxx_retouch.cc:4541 -msgid "set median brightness by color" -msgstr "Imposta luminosità media per colore" - -#: fotoxx_retouch.cc:4542 fotoxx_retouch.cc:4543 -msgid "top hat filter by color" -msgstr "Filtro superiore per colore" - -#: fotoxx_retouch.cc:4858 -msgid "" -"1. Drag mouse to select. \n" -"2. Erase. 3. Repeat. " -msgstr "" -"1. Trascinare per selezionare. \n" -"2. Cancellare. 3. Ripetere. " - -#: fotoxx_retouch.cc:4889 -msgid "Radius" -msgstr "Raggio" - -#: fotoxx_retouch.cc:4891 -msgid "Blur" -msgstr "Sfuoca" - -#: fotoxx_retouch.cc:4894 -msgid "New Area" -msgstr "Nuova area" - -#: fotoxx_retouch.cc:5275 -msgid "spot size limit" -msgstr "limite dimensione raggio" - -#: fotoxx_retouch.cc:5278 -msgid "max. brightness" -msgstr "luminosità max" - -#: fotoxx_retouch.cc:5281 -msgid "min. contrast" -msgstr "contrasto min" - -#: fotoxx_retouch.cc:5875 -#, c-format -msgid "Undo Memory %d%c" -msgstr "Memoria per Annulla %d%c" - -#: fotoxx_retouch.cc:5884 -msgid "pick" -msgstr "Selezione" - -#: fotoxx_retouch.cc:5886 -msgid "erase" -msgstr "Cancellare" - -#: fotoxx_retouch.cc:5894 -msgid "paintbrush radius" -msgstr "Raggio del pennello" - -#: fotoxx_retouch.cc:5895 -msgid "transparency center" -msgstr "Trasparenza al centro" - -#: fotoxx_retouch.cc:5896 -msgid "transparency edge" -msgstr "Trasparenza al bordo" - -#: fotoxx_retouch.cc:6166 -msgid "" -"Undo memory limit has been reached. \n" -"Save work with [done], then resume editing." -msgstr "" -"Il limite della memoria per Annulla è stato raggiunto. \n" -"Salvare il lavoro con [Fatto], e riprendere le modifiche." - -#: fotoxx_tools.cc:42 -msgid "" -"When editing a collection, right-click \n" -"an image or thumbnail to add or remove." -msgstr "" - -#: fotoxx_tools.cc:85 -msgid "Start new collection" -msgstr "" - -#: fotoxx_tools.cc:87 -msgid "Edit a collection" -msgstr "" - -#: fotoxx_tools.cc:89 -msgid "View a collection" -msgstr "" - -#: fotoxx_tools.cc:91 -msgid "Delete a collection" -msgstr "" - -#: fotoxx_tools.cc:95 -msgid "Editing:" -msgstr "" - -#: fotoxx_tools.cc:99 -msgid "Action:" -msgstr "" - -#: fotoxx_tools.cc:133 -msgid "New Collection" -msgstr "" - -#: fotoxx_tools.cc:156 -msgid "Edit Collection" -msgstr "Modifica collezione" - -#: fotoxx_tools.cc:172 -msgid "View Collection" -msgstr "" - -#: fotoxx_tools.cc:193 -msgid "Delete Collection" -msgstr "Elimina collezione" - -#: fotoxx_tools.cc:196 -#, c-format -msgid "delete %s ?" -msgstr "" - -#: fotoxx_tools.cc:223 -#, c-format -msgid "add image to collection: %s" -msgstr "" - -#: fotoxx_tools.cc:225 fotoxx_tools.cc:270 -msgid "remove image from collection" -msgstr "" - -#: fotoxx_tools.cc:226 fotoxx_tools.cc:271 fotoxx_tools.cc:298 -msgid "remove and save image" -msgstr "" - -#: fotoxx_tools.cc:227 fotoxx_tools.cc:316 -msgid "insert saved images here" -msgstr "" - -#: fotoxx_tools.cc:256 -msgid "add image to collection" -msgstr "" - -#: fotoxx_tools.cc:301 -msgid "too many saved files" -msgstr "" - -#: fotoxx_tools.cc:375 -msgid "old top directory" -msgstr "" - -#: fotoxx_tools.cc:378 -msgid "new top directory" -msgstr "" - -#: fotoxx_tools.cc:434 -msgid "completed" -msgstr "completato" - -#: fotoxx_tools.cc:452 -msgid "" -"Brightness should show a gradual ramp \n" -"extending all the way to the edges." -msgstr "" -"Le barre dovrebbero mostrare una gradualità\n" -"in tutta la larghezza della finestra." - -#: fotoxx_tools.cc:492 -msgid "Monitor Check" -msgstr "Verifica dello schermo" - -#: fotoxx_tools.cc:612 -msgid "Brightness Distribution" -msgstr "Distribuzione della luminosità" - -#: fotoxx_tools.cc:796 -msgid "Press ESC to exit slide show" -msgstr "Premere ESC per terminare lo slide show" - -#: fotoxx_tools.cc:797 -msgid "show only latest file versions" -msgstr "" - -#: fotoxx_tools.cc:801 -msgid "arrow keys" -msgstr "Manuale: tasti freccia" - -#: fotoxx_tools.cc:802 -msgid "instant" -msgstr "Istantanea" - -#: fotoxx_tools.cc:803 -msgid "fade-in" -msgstr "Dissolvenza" - -#: fotoxx_tools.cc:804 -msgid "roll-right" -msgstr "Tenda sx-dx" - -#: fotoxx_tools.cc:805 -msgid "roll-down" -msgstr "Tenda su-giù" - -#: fotoxx_tools.cc:806 -msgid "shift-left" -msgstr "Scorrimento a sinistra" - -#: fotoxx_tools.cc:807 -msgid "venetian" -msgstr "Veneziana" - -#: fotoxx_tools.cc:808 -msgid "grate" -msgstr "Quadrettoni" - -#: fotoxx_tools.cc:811 -msgid "radar" -msgstr "" - -#: fotoxx_tools.cc:812 -msgid "jaws" -msgstr "" - -#: fotoxx_tools.cc:823 -msgid "seconds" -msgstr "secondi" - -#: fotoxx_tools.cc:827 -msgid "music file" -msgstr "File musicale" - -#: fotoxx_tools.cc:831 -msgid "transitions" -msgstr "" - -#: fotoxx_tools.cc:948 -msgid "Select music file or playlist" -msgstr "Selezionare file musicale o playlist" - -#: fotoxx_tools.cc:1971 -msgid "x-spacing" -msgstr "" - -#: fotoxx_tools.cc:1972 -msgid "x-count" -msgstr "" - -#: fotoxx_tools.cc:1973 -msgid "x-enable" -msgstr "" - -#: fotoxx_tools.cc:1979 -msgid "y-spacing" -msgstr "" - -#: fotoxx_tools.cc:1980 -msgid "y-count" -msgstr "" - -#: fotoxx_tools.cc:1981 -msgid "y-enable" -msgstr "" - -#: fotoxx_tools.cc:1988 -msgid "x-offset" -msgstr "" - -#: fotoxx_tools.cc:1992 -msgid "y-offset" -msgstr "" - -#: fotoxx_tools.cc:2146 -msgid "lens name" -msgstr "Nome lente" - -#: fotoxx_tools.cc:2220 -msgid "Available Translations" -msgstr "Traduzioni disponibili" - -#: fotoxx_tools.cc:2224 -msgid "Set Language" -msgstr "Cambia lingua" - -#: fotoxx_tools.cc:2290 -msgid "Make Launcher" -msgstr "" - -#: fotoxx_tools.cc:2310 -msgid "Program ufraw-batch is required" -msgstr "E' richiesto il programma ufraw-batch" - -#: fotoxx_tools.cc:2320 -msgid "Open RAW File" -msgstr "Apri un'immagine RAW" - -#: fotoxx_tools.cc:2331 -msgid "Select RAW files to convert" -msgstr "Scegliere i file RAW da convertire" - -#: fotoxx_tools.cc:2467 -msgid "max. width" -msgstr "larghezza max" - -#: fotoxx_tools.cc:2468 -msgid "max. height" -msgstr "altezza max" - -#: fotoxx_tools.cc:2527 fotoxx_transform.cc:1268 -#, c-format -msgid "max. size %d x %d is not reasonable" -msgstr "dimensione massima %d x %d non ragionevole" - -#: fotoxx_tools.cc:2613 -msgid "too many files" -msgstr "troppi file" - -#: fotoxx_tools.cc:2656 -msgid "Sync Files is already running" -msgstr "" - -#: fotoxx_tools.cc:2707 -msgid "" -"Run Tools > Synchronize Files so that gallery windows \n" -"will be fast and Search Images will work correctly. \n" -"You can view (not edit) images while synchronize runs." -msgstr "" - -#: fotoxx_tools.cc:2736 -msgid "no top image directory is defined" -msgstr "" - -#: fotoxx_tools.cc:2742 -msgid "top image directory is invalid" -msgstr "" - -#: fotoxx_tools.cc:2747 -msgid "no search index file is present" -msgstr "" - -#: fotoxx_tools.cc:2761 -msgid "new/modified files are present" -msgstr "" - -#: fotoxx_tools.cc:2768 -msgid "no new files found" -msgstr "" - -#: fotoxx_tools.cc:2785 -msgid "Top Image Directory:" -msgstr "Cartella principale immagini:" - -#: fotoxx_tools.cc:2807 -msgid "file sync is mandatory" -msgstr "" - -#: fotoxx_tools.cc:2817 -msgid "top directory is invalid" -msgstr "" - -#: fotoxx_tools.cc:3201 -msgid "Select top image directory" -msgstr "Scegli la cartella principale delle immagini" - -#: fotoxx_tools.cc:3378 -msgid "icons" -msgstr "" - -#: fotoxx_tools.cc:3379 fotoxx_transform.cc:1467 -msgid "text" -msgstr "" - -#: fotoxx_tools.cc:3380 -msgid "both" -msgstr "" - -#: fotoxx_transform.cc:50 -msgid "Use buttons or drag right edge with mouse" -msgstr "Usa i bottoni o trascina il margine destro con il mouse" - -#: fotoxx_transform.cc:64 -msgid "degrees" -msgstr "Gradi" - -#: fotoxx_transform.cc:80 fotoxx_transform.cc:124 -msgid "Trim" -msgstr "Ritaglia" - -#: fotoxx_transform.cc:81 fotoxx_transform.cc:2437 fotoxx_transform.cc:3263 -#: fotoxx_transform.cc:3526 fotoxx_transform.cc:3787 -msgid "Grid" -msgstr "" - -#: fotoxx_transform.cc:123 -msgid "Undo Trim" -msgstr "Annulla ritaglio" - -#: fotoxx_transform.cc:139 -#, c-format -msgid "degrees: %.1f" -msgstr "Gradi : %.1f" - -#: fotoxx_transform.cc:286 -msgid "gold" -msgstr "" - -#: fotoxx_transform.cc:332 -msgid "Drag middle to move, drag corners to resize." -msgstr "Trascinare il centro per spostare, e i lati per ridimensionare." - -#: fotoxx_transform.cc:346 -msgid "customize" -msgstr "Personalizza" - -#: fotoxx_transform.cc:357 -msgid "ratio" -msgstr "rapporto" - -#: fotoxx_transform.cc:361 -msgid "Lock Ratio" -msgstr "Blocca proporzioni" - -#: fotoxx_transform.cc:367 -msgid "invert" -msgstr "inverti" - -#: fotoxx_transform.cc:892 -msgid "Trim Buttons" -msgstr "Pulsanti di taglio" - -#: fotoxx_transform.cc:964 -msgid "Lock aspect ratio" -msgstr "Blocca proporzioni" - -#: fotoxx_transform.cc:1145 -msgid "Batch Resize" -msgstr "Ridimensiona più immagini" - -#: fotoxx_transform.cc:1153 -msgid "new max. width" -msgstr "Nuova larghezza max" - -#: fotoxx_transform.cc:1154 -msgid "new max. height" -msgstr "Nuova altezza max" - -#: fotoxx_transform.cc:1161 -msgid "replace originals" -msgstr "sostituzione originali" - -#: fotoxx_transform.cc:1162 -msgid "export to location" -msgstr "esporta su una posizione" - -#: fotoxx_transform.cc:1166 -msgid "copy EXIF" -msgstr "copia EXIF" - -#: fotoxx_transform.cc:1219 -msgid "Select directory" -msgstr "Seleziona directory" - -#: fotoxx_transform.cc:1243 -#, c-format -msgid "replace original files? (max. %d x %d)" -msgstr "Sostituire i file originali? (max. %d x %d)" - -#: fotoxx_transform.cc:1250 -#, c-format -msgid "" -"copy files? (max. %d x %d) \n" -" to location %s" -msgstr "" -"copio i file? (max. %d x %d) \n" -" nella posizione %s" - -#: fotoxx_transform.cc:1261 -msgid "location is not a valid directory" -msgstr "la posizione non è una directory valida" - -#: fotoxx_transform.cc:1304 -msgid "new file already exists" -msgstr "Nuovo file già esistente" - -#: fotoxx_transform.cc:1388 -msgid "" -"Enter text, click/drag on image.\n" -"Right click to remove" -msgstr "" -"Impostare il testo e cliccare nell'immagine.\n" -"Clic destro per rimuovere" - -#: fotoxx_transform.cc:1442 -msgid "Text" -msgstr "Testo" - -#: fotoxx_transform.cc:1449 -msgid "Size" -msgstr "Dimensione" - -#: fotoxx_transform.cc:1452 -msgid "Angle" -msgstr "Angolo" - -#: fotoxx_transform.cc:1463 -msgid "Color" -msgstr "Colore" - -#: fotoxx_transform.cc:1464 -msgid "Transparency" -msgstr "Trasparenza" - -#: fotoxx_transform.cc:1472 -msgid "backing" -msgstr "" - -#: fotoxx_transform.cc:1475 -msgid "" -"Outline\n" -" Width" -msgstr "Spessore contorno" - -#: fotoxx_transform.cc:1477 -msgid "outline" -msgstr "" - -#: fotoxx_transform.cc:1486 -msgid "Annotation File:" -msgstr "File annotazioni:" - -#: fotoxx_transform.cc:1564 -msgid "select font" -msgstr "scegliere il font" - -#: fotoxx_transform.cc:2197 fotoxx_transform.cc:2429 -msgid "horizontal" -msgstr "orizzontale" - -#: fotoxx_transform.cc:2198 fotoxx_transform.cc:2428 -msgid "vertical" -msgstr "Verticale" - -#: fotoxx_transform.cc:2306 -msgid "black/white positive" -msgstr "" - -#: fotoxx_transform.cc:2307 -msgid "black/white negative" -msgstr "" - -#: fotoxx_transform.cc:2308 -msgid "color positive" -msgstr "" - -#: fotoxx_transform.cc:2309 -msgid "color negative" -msgstr "" - -#: fotoxx_transform.cc:2430 -msgid "linear" -msgstr "lineare" - -#: fotoxx_transform.cc:2433 -msgid "curved" -msgstr "curvato" - -#: fotoxx_transform.cc:2692 -msgid "" -" Click the four corners of a tetragon area. Press [apply]. \n" -" The image is warped to make the tetragon into a rectangle." -msgstr "" - -#: fotoxx_transform.cc:2878 -msgid "must have 4 corners" -msgstr "" - -#: fotoxx_transform.cc:2999 -msgid "" -" Select an area to warp using select area function. \n" -" Press [start warp] and pull area with mouse. \n" -" Make multiple mouse pulls until satisfied. \n" -" When finished, select another area or press [done]." -msgstr "" -"Selezionare un'area da deformare utilizzando la funzione del menu. \n" -"Premere [Avvia deformazione] e trascinare con il mouse.\n" -"Trascinare più volte se necessario.\n" -"Una volta terminato, selezionare un'altra zona o premere [Fatto]. " - -#: fotoxx_transform.cc:3018 -msgid "start warp" -msgstr "Avvia deformazione" - -#: fotoxx_transform.cc:3067 -msgid "Select area first" -msgstr "Selezionare prima un'area" - -#: fotoxx_transform.cc:3242 fotoxx_transform.cc:3505 -msgid "" -" Pull an image position using the mouse. \n" -" Make multiple mouse pulls until satisfied. \n" -" When finished, press [done]." -msgstr "" -" Trascinare un punto dell'immagine con il mouse. \n" -" Eseguire diversi trascinamenti fino al completamento. \n" -" Quando finito, premere [Fatto]." - -#: fotoxx_transform.cc:3771 -msgid "" -" Pull on an image corner using the mouse. \n" -" Make multiple mouse pulls until satisfied. \n" -" When finished, press [done]." -msgstr "" -"Trascinare un bordo dell'immagine con il mouse. \n" -"Ripetere l'operazione se richiesto.\n" -"Una volta finito, premere [Fatto]." - -#~ msgid "Create Collection" -#~ msgstr "Crea collezione" - -#~ msgid "Open Collection" -#~ msgstr "Apri collezione" - -#~ msgid "Translate" -#~ msgstr "Come tradurre il programma" - -#~ msgid "" -#~ "Run Tools > Synchronize Files so that gallery windows \n" -#~ "will be fast and Search Images will work correctly." -#~ msgstr "" -#~ "Eseguire 'Strumenti > Sincronizza file' affinchè le finestre di " -#~ "anteprima \n" -#~ "siano rapide e 'Ricerca immagini' funzioni correttamente." - -#~ msgid "Save Collection" -#~ msgstr "Salva collezione" - -#~ msgid "Add new images to collection" -#~ msgstr "Aggiungi immagini alla collezione" - -#~ msgid "Delete images from collection" -#~ msgstr "Eliminare immagini dalla collezione" - -#~ msgid "Remove and save images" -#~ msgstr "Taglia (e ricorda) immagini" - -#~ msgid "Insert new or saved images" -#~ msgstr "Incolla immagini nuove o tagliate" - -#~ msgid "select image files" -#~ msgstr "scegliere i file immagine" - -#~ msgid "Click on images to delete." -#~ msgstr "Cliccare le immagini da eliminare" - -#~ msgid "" -#~ "Click on image where new or saved \n" -#~ "images are to be inserted (after)." -#~ msgstr "" -#~ "Cliccare il punto d'inserimento per immagini \n" -#~ "nuove o salvate" - -#~ msgid "full rebuild" -#~ msgstr "ricostruzione completa" - -#~ msgid "incremental" -#~ msgstr "incrementale" - -#~ msgid "" -#~ "Rename failed \n" -#~ " %s" -#~ msgstr "" -#~ "Rinominazione fallita \n" -#~ " %s" - -#~ msgid "transition" -#~ msgstr "Transizione" - -#~ msgid "Discard modifications?" -#~ msgstr "Annullare le modifiche?" - -#~ msgid "histogram" -#~ msgstr "istogramma" - -#~ msgid "range" -#~ msgstr "intervallo" - -#~ msgid "package libimage-exiftool-perl is required" -#~ msgstr "è necessario il pacchetto libimage-exiftool-perl" - -#~ msgid "my mouse" -#~ msgstr "Abilita mouse" - -#~ msgid "make new version" -#~ msgstr "Creare nuova versione" - -#~ msgid "limit" -#~ msgstr "limite" - -#~ msgid "click on window to show RGB" -#~ msgstr "cliccare sulla finestra per visualizzare RGB" - -#~ msgid "Width" -#~ msgstr "Larghezza" - -#~ msgid "Unknown file type, save as tiff/jpeg/png to edit" -#~ msgstr "" -#~ "Tipo di file sconosciuto. Salvarlo come TIFF/JPEG/PNG per modificarlo" - -#~ msgid "Undo Last" -#~ msgstr "Annulla ultimo" - -#~ msgid "Undo All" -#~ msgstr "Annulla tutto" - -#~ msgid "Threshold" -#~ msgstr "Soglia" - -#~ msgid "Start" -#~ msgstr "Inizio" - -#~ msgid "Select Files" -#~ msgstr "Seleziona i file" - -#~ msgid "Search" -#~ msgstr "Ricerca" - -#~ msgid "Save As" -#~ msgstr "Salva come" - -#~ msgid "Reduce" -#~ msgstr "Ridurre" - -#~ msgid "Red" -#~ msgstr "Rosso" - -#~ msgid "Proceed" -#~ msgstr "Prosegui" - -#~ msgid "Presets" -#~ msgstr "Fisse: " - -#~ msgid "Percent" -#~ msgstr "Percentuale" - -#~ msgid "Pause" -#~ msgstr "Sospendi" - -#~ msgid "OK" -#~ msgstr "Ok" - -#~ msgid "Lighter Areas" -#~ msgstr "Aree luminose" - -#~ msgid "Insert" -#~ msgstr "Incolla" - -#~ msgid "Height" -#~ msgstr "Altezza" - -#~ msgid "Green" -#~ msgstr "Verde" - -#~ msgid "Font" -#~ msgstr "Font" - -#~ msgid "Finish" -#~ msgstr "Termina" - -#~ msgid "Fetch" -#~ msgstr "Prendi" - -#~ msgid "Erase" -#~ msgstr "Esegui cancellatura" - -#~ msgid "Edit" -#~ msgstr "Modifica" - -#~ msgid "Done" -#~ msgstr "Fatto" - -#~ msgid "Darker Areas" -#~ msgstr "Aree scure" - -#~ msgid "Cut" -#~ msgstr "Taglia" - -#~ msgid "Commit" -#~ msgstr "Esegui" - -#~ msgid "Clone fotoxx" -#~ msgstr "Duplica fotoxx (nuova finestra)" - -#~ msgid "" -#~ "Click on images to remove and save, \n" -#~ "then press [Insert] to insert them." -#~ msgstr "" -#~ "Cliccare le immagini da tagliare (e ricordare), \n" -#~ "poi premere [Incolla] per re-inserirle." - -#~ msgid "Clear" -#~ msgstr "Pulisci" - -#~ msgid "Cancel" -#~ msgstr "Annulla" - -#~ msgid "Browse" -#~ msgstr "Sfoglia" - -#~ msgid "Brightness" -#~ msgstr "Luminosità" - -#~ msgid "Blue" -#~ msgstr "Blu" - -#~ msgid "Blend Width" -#~ msgstr "Larghezza di sfumatura" - -#~ msgid "Apply" -#~ msgstr "Applica" - -#~ msgid "Amount" -#~ msgstr "Quantità" - -#~ msgid "Add All" -#~ msgstr "Aggiungere tutto" - -#~ msgid "" -#~ "Select images to add, then \n" -#~ "press [Insert] to insert them." -#~ msgstr "" -#~ "Selezionare imagini da aggiungere, poi \n" -#~ "premere [Incolla] per aggiungerle." - -#~ msgid "random" -#~ msgstr "Casuale" - -#~ msgid "Whole Image" -#~ msgstr "Immagine intera" - -#~ msgid "Time Interval" -#~ msgstr "Intervallo di tempo" - -#~ msgid "Delete" -#~ msgstr "Elimina" - -#~ msgid "Curve File:" -#~ msgstr "File di curve" - -#~ msgid "" -#~ "Discard current gallery list? \n" -#~ " %s" -#~ msgstr "" -#~ "Svuotare la lista corrente? \n" -#~ " %s" - -#~ msgid "Edit Caption" -#~ msgstr "Modifica titolo" - -#~ msgid "Edit Comments" -#~ msgstr "Modifica commenti" diff -Nru fotoxx-11.11.1/locales/it/zfuncs.po fotoxx-12.01.2/locales/it/zfuncs.po --- fotoxx-11.11.1/locales/it/zfuncs.po 2011-11-05 05:30:37.000000000 +0000 +++ fotoxx-12.01.2/locales/it/zfuncs.po 1970-01-01 00:00:00.000000000 +0000 @@ -1,303 +0,0 @@ -# translation of zfuncs.po to italian -# Eugenio Baldi , 2009. -msgid "" -msgstr "" -"Project-Id-Version: zfuncs\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2011-11-05 05:49+0100\n" -"PO-Revision-Date: 2009-09-13 08:44+0200\n" -"Last-Translator: Eugenio Baldi \n" -"Language-Team: italiano \n" -"Language: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n > 1);\n" - -#: zfuncs.cc:3192 -#, c-format -msgid "help file not found: %s" -msgstr "File di aiuto non trovato: %s" - -#: zfuncs.cc:3296 -#, c-format -msgid "error: %s" -msgstr "Errore: %s" - -#: zfuncs.cc:4415 zfuncs.cc:8771 -#, c-format -msgid "cannot open file %s" -msgstr "non è possibile aprire il file %s" - -#: zfuncs.cc:4448 -msgid "save screen to file" -msgstr "Salva schermo in un file" - -#: zfuncs.cc:6198 -msgid "No" -msgstr "No" - -#: zfuncs.cc:6198 -msgid "Yes" -msgstr "Si" - -#: zfuncs.cc:6272 zfuncs.cc:6308 zfuncs.cc:6461 zfuncs.cc:6865 zfuncs.cc:8358 -#: zfuncs.cc:8883 zfuncs.cc:8889 zfuncs.cc:8895 zfuncs.cc:8901 -msgid "cancel" -msgstr "Annulla" - -#: zfuncs.cc:6423 zfuncs.cc:7552 -msgid "open" -msgstr "Apri" - -#: zfuncs.cc:6428 -msgid "choose" -msgstr "Scegli" - -#: zfuncs.cc:6433 -msgid "save" -msgstr "Salva" - -#: zfuncs.cc:6439 -msgid "open folder" -msgstr "Apri cartella" - -#: zfuncs.cc:6444 -msgid "create folder" -msgstr "Crea cartella" - -#: zfuncs.cc:6450 -msgid "hidden" -msgstr "Nascosto" - -#: zfuncs.cc:6454 -msgid "quality" -msgstr "Qualità" - -#: zfuncs.cc:6511 -msgid "JPG quality 0-100" -msgstr "Qualità JPG 0-100" - -#: zfuncs.cc:6865 zfuncs.cc:8358 -msgid "done" -msgstr "Fatto" - -#: zfuncs.cc:6865 zfuncs.cc:6878 -msgid "margins" -msgstr "" - -#: zfuncs.cc:6874 -msgid "top" -msgstr "" - -#: zfuncs.cc:6875 -msgid "bottom" -msgstr "" - -#: zfuncs.cc:6876 -msgid "left" -msgstr "" - -#: zfuncs.cc:6877 -msgid "right" -msgstr "" - -#: zfuncs.cc:7278 zfuncs.cc:7532 zfuncs.cc:7670 zfuncs.cc:7671 zfuncs.cc:7673 -msgid "bigger" -msgstr "Più grande" - -#: zfuncs.cc:7278 -msgid "increase thumbnail size" -msgstr "Aumenta la dimensione delle miniature" - -#: zfuncs.cc:7279 -msgid "reduce thumbnail size" -msgstr "Riduci la dimensione delle miniature" - -#: zfuncs.cc:7279 zfuncs.cc:7542 zfuncs.cc:7672 zfuncs.cc:7674 -msgid "smaller" -msgstr "Più piccolo" - -#: zfuncs.cc:7280 zfuncs.cc:7571 -msgid "parent" -msgstr "Superiore" - -#: zfuncs.cc:7280 -msgid "parent directory" -msgstr "Cartella superiore" - -#: zfuncs.cc:7281 zfuncs.cc:7589 zfuncs.cc:7681 -msgid "first page" -msgstr "Prima pagina" - -#: zfuncs.cc:7281 -msgid "jump to first file" -msgstr "Passa al primo file" - -#: zfuncs.cc:7282 zfuncs.cc:7587 zfuncs.cc:7676 zfuncs.cc:7683 -msgid "prev page" -msgstr "Pagina precedente" - -#: zfuncs.cc:7282 -msgid "previous page" -msgstr "Pagina precedente" - -#: zfuncs.cc:7283 zfuncs.cc:7585 zfuncs.cc:7678 -msgid "prev row" -msgstr "Riga prec." - -#: zfuncs.cc:7283 -msgid "previous row" -msgstr "Riga precedente" - -#: zfuncs.cc:7284 zfuncs.cc:7586 zfuncs.cc:7679 -msgid "next row" -msgstr "Riga successiva" - -#: zfuncs.cc:7285 zfuncs.cc:7588 zfuncs.cc:7677 zfuncs.cc:7684 -msgid "next page" -msgstr "Pagina successiva" - -#: zfuncs.cc:7286 -msgid "jump to last file" -msgstr "Passa all'ultimo file" - -#: zfuncs.cc:7286 zfuncs.cc:7590 zfuncs.cc:7682 -msgid "last page" -msgstr "Ultima pagina" - -#: zfuncs.cc:7287 zfuncs.cc:7527 -msgid "close" -msgstr "Chiudi" - -#: zfuncs.cc:7287 -msgid "close image gallery" -msgstr "Chiudi galleria immagini" - -#: zfuncs.cc:7558 -msgid "select new file" -msgstr "Scegliere un nuovo file" - -#: zfuncs.cc:8358 -msgid "Select Files" -msgstr "Selezionare file" - -#: zfuncs.cc:8366 -msgid "delete" -msgstr "Elimina" - -#: zfuncs.cc:8367 -msgid "insert" -msgstr "inserisci" - -#: zfuncs.cc:8368 -msgid "add all" -msgstr "Aggiungi tutti" - -#: zfuncs.cc:8658 -msgid "" -"Initial parameters file created. \n" -"Inspect and revise if necessary." -msgstr "" -"Il primo file di parametri è stato creato. \n" -"Verificare e correggere se necessario." - -#: zfuncs.cc:8674 -msgid "load parameters from a file" -msgstr "Carica i parametri da un file" - -#: zfuncs.cc:8743 -msgid "save parameters to a file" -msgstr "Salva parametri in un file" - -#: zfuncs.cc:8881 zfuncs.cc:8887 zfuncs.cc:8893 zfuncs.cc:8899 -msgid "edit parameters" -msgstr "Modifica parametri" - -#: zfuncs.cc:8882 zfuncs.cc:8888 -msgid "" -"list\n" -"all" -msgstr "" -"elenca\n" -"tutti" - -#: zfuncs.cc:8882 zfuncs.cc:8888 zfuncs.cc:8894 zfuncs.cc:8900 -msgid "" -"load\n" -"file" -msgstr "" -"Carica\n" -"file" - -#: zfuncs.cc:8882 zfuncs.cc:8888 zfuncs.cc:8894 zfuncs.cc:8900 -msgid "" -"save\n" -"file" -msgstr "" -"Salva\n" -"file" - -#: zfuncs.cc:8883 zfuncs.cc:8895 -msgid "" -"add\n" -"new" -msgstr "" -"Aggiungi\n" -"nuovo" - -#: zfuncs.cc:8883 zfuncs.cc:8889 zfuncs.cc:8895 zfuncs.cc:8901 -msgid "apply" -msgstr "Applica" - -#: zfuncs.cc:8935 -msgid "apply?" -msgstr "Applicare?" - -#: zfuncs.cc:8992 -msgid "(new parm name)" -msgstr "(nuovo nome parametro)" - -#: zfuncs.cc:8992 -msgid "add parameter" -msgstr "Aggiungi parametro" - -#~ msgid "print" -#~ msgstr "Stampa" - -#~ msgid "printer ID" -#~ msgstr "Nome stampante" - -#~ msgid "paper format" -#~ msgstr "Formato carta" - -#~ msgid "portrait" -#~ msgstr "Verticale" - -#~ msgid "landscape" -#~ msgstr "Orizzontale" - -#~ msgid "paper format is crazy" -#~ msgstr "Formato carta gagliardo!" - -#~ msgid "open a file" -#~ msgstr "Apri un file" - -#~ msgid "select new folder" -#~ msgstr "Scegli una nuova cartella" - -#, fuzzy -#~ msgid "open a directory" -#~ msgstr "Apri cartella" - -#~ msgid "jump to specific file" -#~ msgstr "Passa ad un file specifico" - -#~ msgid "folder" -#~ msgstr "Cartella" - -#~ msgid "file" -#~ msgstr "File" - -#~ msgid "close thumbnail window" -#~ msgstr "Chiudi la finestra delle miniature" diff -Nru fotoxx-11.11.1/locales/nl/fotoxx.po fotoxx-12.01.2/locales/nl/fotoxx.po --- fotoxx-11.11.1/locales/nl/fotoxx.po 2011-11-05 05:30:37.000000000 +0000 +++ fotoxx-12.01.2/locales/nl/fotoxx.po 1970-01-01 00:00:00.000000000 +0000 @@ -1,2696 +0,0 @@ -# Translation of fotoxx.po to dutch (nl) -# Translated by: Arthur Kalverboer , jun 2011. -# -msgid "" -msgstr "" -"Project-Id-Version: fotoxx 6.0\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2011-11-05 05:49+0100\n" -"PO-Revision-Date: 2009-03-06 09:57+0100\n" -"Last-Translator: Arthur\n" -"Language-Team: Dutch\n" -"Language: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#: fotoxx-11.11.1.cc:179 -msgid "File" -msgstr "Bestand" - -#: fotoxx-11.11.1.cc:180 fotoxx-11.11.1.cc:316 -msgid "Image Gallery" -msgstr "Afbeeldingsgalerie tonen" - -#: fotoxx-11.11.1.cc:181 -msgid "Clone 50/50" -msgstr "" - -#: fotoxx-11.11.1.cc:182 -msgid "Clone Overlay" -msgstr "" - -#: fotoxx-11.11.1.cc:183 fotoxx-11.11.1.cc:317 fotoxx-11.11.1.cc:2272 -#: fotoxx-11.11.1.cc:2444 -msgid "Open Image File" -msgstr "Openen..." - -#: fotoxx-11.11.1.cc:184 -msgid "Open in New Window" -msgstr "" - -#: fotoxx-11.11.1.cc:185 fotoxx-11.11.1.cc:318 -msgid "Open Previous File" -msgstr "Open voorgaand bestand" - -#: fotoxx-11.11.1.cc:186 -msgid "Open Recent File" -msgstr "Onlangs geopend" - -#: fotoxx-11.11.1.cc:187 fotoxx-11.11.1.cc:326 -msgid "Save to Same File" -msgstr "Opslaan" - -#: fotoxx-11.11.1.cc:188 fotoxx-11.11.1.cc:327 -msgid "Save to New Version" -msgstr "" - -#: fotoxx-11.11.1.cc:189 fotoxx-11.11.1.cc:328 -msgid "Save to New File" -msgstr "Opslaan als ..." - -#: fotoxx-11.11.1.cc:190 fotoxx-11.11.1.cc:2990 -msgid "Create Blank Image" -msgstr "Lege afbeelding maken" - -#: fotoxx-11.11.1.cc:191 -msgid "Trash Image File" -msgstr "Verwijderen" - -#: fotoxx-11.11.1.cc:192 fotoxx-11.11.1.cc:3216 -msgid "Rename Image File" -msgstr "Hernoemen bestand..." - -#: fotoxx-11.11.1.cc:193 -msgid "Batch Rename Files" -msgstr "Batchgewijs hernoemen..." - -#: fotoxx-11.11.1.cc:194 -msgid "Print Image File" -msgstr "Afdrukken..." - -#: fotoxx-11.11.1.cc:195 fotoxx-11.11.1.cc:332 -msgid "Quit fotoxx" -msgstr "Afsluiten" - -#: fotoxx-11.11.1.cc:197 -msgid "Tools" -msgstr "Gereedschap" - -#: fotoxx-11.11.1.cc:198 fotoxx_tools.cc:70 -msgid "Manage Collections" -msgstr "" - -#: fotoxx-11.11.1.cc:199 fotoxx_tools.cc:373 -msgid "Move Collections" -msgstr "" - -#: fotoxx-11.11.1.cc:200 -msgid "Check Monitor" -msgstr "Monitorkleuren controleren" - -#: fotoxx-11.11.1.cc:201 fotoxx_tools.cc:550 -msgid "Monitor Gamma" -msgstr "Gammawaarde monitor" - -#: fotoxx-11.11.1.cc:202 -msgid "Brightness Graph" -msgstr "Helderheidshistogram tonen" - -#: fotoxx-11.11.1.cc:203 fotoxx_tools.cc:819 -msgid "Slide Show" -msgstr "Diashow starten" - -#: fotoxx-11.11.1.cc:204 fotoxx_tools.cc:1668 -msgid "Show RGB" -msgstr "RGB waarden tonen" - -#: fotoxx-11.11.1.cc:205 fotoxx_tools.cc:1962 -msgid "Grid Lines" -msgstr "Raster instellen" - -#: fotoxx-11.11.1.cc:206 fotoxx_tools.cc:2135 -msgid "Lens Parameters" -msgstr "Lens parameters instellen" - -#: fotoxx-11.11.1.cc:207 -msgid "Change Language" -msgstr "Taal veranderen" - -#: fotoxx-11.11.1.cc:209 -msgid "Add Menu and Launcher" -msgstr "Toevoegen Menu en Start-icon" - -#: fotoxx-11.11.1.cc:210 -msgid "Convert RAW files" -msgstr "RAW-bestanden converteren" - -#: fotoxx-11.11.1.cc:211 -msgid "Burn Images to CD/DVD" -msgstr "Afbeelding op CD/DVD branden" - -#: fotoxx-11.11.1.cc:212 fotoxx_tools.cc:2460 -msgid "E-mail Images" -msgstr "E-mail afbeeldingen maken" - -#: fotoxx-11.11.1.cc:213 fotoxx_tools.cc:2783 -msgid "Synchronize Files" -msgstr "Synchroniseren bestanden" - -#: fotoxx-11.11.1.cc:214 fotoxx_tools.cc:3376 -msgid "Toolbar Style" -msgstr "Toolbar stijl" - -#: fotoxx-11.11.1.cc:215 -msgid "Memory Usage" -msgstr "Geheugengebruik" - -#: fotoxx-11.11.1.cc:218 -msgid "Edit Caption/Comments" -msgstr "" - -#: fotoxx-11.11.1.cc:219 fotoxx_info.cc:156 -msgid "Edit Tags" -msgstr "Tags aanpassen" - -#: fotoxx-11.11.1.cc:220 fotoxx_info.cc:345 -msgid "Manage Tags" -msgstr "Tags beheren" - -#: fotoxx-11.11.1.cc:221 fotoxx_info.cc:1345 -msgid "Batch Add Tags" -msgstr "Batchgewijs tags toevoegen" - -#: fotoxx-11.11.1.cc:222 fotoxx_info.cc:1547 -msgid "Batch Delete Tag" -msgstr "Batchgewijs tags verwijderen" - -#: fotoxx-11.11.1.cc:223 -msgid "View Info (short)" -msgstr "Tonen info (kort)" - -#: fotoxx-11.11.1.cc:224 -msgid "View Info (long)" -msgstr "Tonen info (uitgebreid)" - -#: fotoxx-11.11.1.cc:225 fotoxx_info.cc:1883 -msgid "Edit Info" -msgstr "Info aanpassen" - -#: fotoxx-11.11.1.cc:226 fotoxx_info.cc:1981 -msgid "Delete Info" -msgstr "Info verwijderen" - -#: fotoxx-11.11.1.cc:227 -msgid "Search Images" -msgstr "Afbeeldingen doorzoeken" - -#: fotoxx-11.11.1.cc:229 fotoxx-11.11.1.cc:230 -msgid "Select" -msgstr "Uitsnedes selecteren" - -#: fotoxx-11.11.1.cc:231 -msgid "Show" -msgstr "Tonen" - -#: fotoxx-11.11.1.cc:232 -msgid "Hide" -msgstr "Verbergen" - -#: fotoxx-11.11.1.cc:233 -msgid "Enable" -msgstr "Uitsnede activeren" - -#: fotoxx-11.11.1.cc:234 -msgid "Disable" -msgstr "Uitsnede deactiveren" - -#: fotoxx-11.11.1.cc:235 -msgid "Invert" -msgstr "Uitsnede inverteren" - -#: fotoxx-11.11.1.cc:236 -msgid "Unselect" -msgstr "" - -#: fotoxx-11.11.1.cc:237 -msgid "Copy" -msgstr "Uitsnede copieren" - -#: fotoxx-11.11.1.cc:238 -msgid "Paste" -msgstr "Uitsnede plakken" - -#: fotoxx-11.11.1.cc:239 fotoxx-11.11.1.cc:317 fotoxx_retouch.cc:2314 -#: fotoxx_retouch.cc:2319 -msgid "Open" -msgstr "Openen" - -#: fotoxx-11.11.1.cc:240 fotoxx-11.11.1.cc:326 -msgid "Save" -msgstr "Opslaan" - -#: fotoxx-11.11.1.cc:241 fotoxx_area.cc:2215 -msgid "Select Whole Image" -msgstr "Gehele afbeelding selecteren" - -#: fotoxx-11.11.1.cc:242 -msgid "Select and Edit" -msgstr "Selecteren en aanpassen" - -#: fotoxx-11.11.1.cc:244 -msgid "Transform" -msgstr "Transformeren" - -#: fotoxx-11.11.1.cc:245 fotoxx_transform.cc:60 -msgid "Rotate Image" -msgstr "Afbeelding draaien" - -#: fotoxx-11.11.1.cc:246 fotoxx_transform.cc:346 -msgid "Trim Image" -msgstr "Afbeelding bijsnijden" - -#: fotoxx-11.11.1.cc:247 fotoxx_transform.cc:972 -msgid "Resize Image" -msgstr "Afbeeldingsgrootte wijzigen" - -#: fotoxx-11.11.1.cc:248 -msgid "Batch Resize/Export" -msgstr "Batchgewijs grootte wijzigen/exporteren" - -#: fotoxx-11.11.1.cc:249 fotoxx_transform.cc:1436 -msgid "Annotate Image" -msgstr "Annotatie bij afbeelding" - -#: fotoxx-11.11.1.cc:250 fotoxx_transform.cc:2193 -msgid "Flip Image" -msgstr "Afbeelding spiegelen" - -#: fotoxx-11.11.1.cc:251 fotoxx_transform.cc:2303 -msgid "Make Negative" -msgstr "Maak negatief" - -#: fotoxx-11.11.1.cc:252 fotoxx_transform.cc:2420 -msgid "Unbend Image" -msgstr "Afbeelding ontkrommen" - -#: fotoxx-11.11.1.cc:253 fotoxx_transform.cc:2704 -msgid "Keystone Correction" -msgstr "" - -#: fotoxx-11.11.1.cc:254 fotoxx_transform.cc:3013 -msgid "Warp Image (area)" -msgstr "Afbeelding kromtrekken (uitsnede)" - -#: fotoxx-11.11.1.cc:255 fotoxx_transform.cc:3255 -msgid "Warp Image (curved)" -msgstr "Afbeelding kromtrekken (gebogen)" - -#: fotoxx-11.11.1.cc:256 fotoxx_transform.cc:3518 -msgid "Warp Image (linear)" -msgstr "Afbeelding kromtrekken (lineair)" - -#: fotoxx-11.11.1.cc:257 fotoxx_transform.cc:3782 -msgid "Warp Image (affine)" -msgstr "Afbeelding kromtrekken (affine)" - -#: fotoxx-11.11.1.cc:259 -msgid "Retouch" -msgstr "Retoucheren" - -#: fotoxx-11.11.1.cc:260 -msgid "Brightness/Color" -msgstr "Helderheid/Kleur instellen" - -#: fotoxx-11.11.1.cc:261 -msgid "Gamma Curves" -msgstr "" - -#: fotoxx-11.11.1.cc:262 -msgid "Expand Brightness" -msgstr "Helderheidsbereik vergroten" - -#: fotoxx-11.11.1.cc:263 -msgid "Flatten Brightness" -msgstr "Helderheidsverdeling afvlakken" - -#: fotoxx-11.11.1.cc:264 -msgid "Brightness Ramp" -msgstr "Helderheidsverspreiding instellen" - -#: fotoxx-11.11.1.cc:265 fotoxx_retouch.cc:1729 -msgid "Tone Mapping" -msgstr "Tone mapping instellen" - -#: fotoxx-11.11.1.cc:266 -msgid "White Balance" -msgstr "Witbalans instellen" - -#: fotoxx-11.11.1.cc:267 -msgid "Match Colors" -msgstr "" - -#: fotoxx-11.11.1.cc:269 fotoxx_retouch.cc:2941 -msgid "Revise RGB" -msgstr "" - -#: fotoxx-11.11.1.cc:270 -msgid "Red Eyes" -msgstr "Rode ogen corrigeren" - -#: fotoxx-11.11.1.cc:271 -msgid "Blur Image" -msgstr "Afbeelding vervagen" - -#: fotoxx-11.11.1.cc:272 fotoxx_retouch.cc:4077 -msgid "Sharpen Image" -msgstr "Afbeelding verscherpen" - -#: fotoxx-11.11.1.cc:273 -msgid "Reduce Noise" -msgstr "Ruis verminderen" - -#: fotoxx-11.11.1.cc:274 fotoxx_retouch.cc:4881 -msgid "Smart Erase" -msgstr "Slim verwijderen" - -#: fotoxx-11.11.1.cc:275 fotoxx_retouch.cc:5271 -msgid "Remove Dust" -msgstr "Stofspikkels verwijderen" - -#: fotoxx-11.11.1.cc:276 fotoxx_retouch.cc:5877 -msgid "Edit Pixels" -msgstr "Verven met penseel" - -#: fotoxx-11.11.1.cc:278 -msgid "Art" -msgstr "Creatief" - -#: fotoxx-11.11.1.cc:279 -msgid "Color Depth" -msgstr "Kleurdiepte instellen" - -#: fotoxx-11.11.1.cc:280 -msgid "Drawing" -msgstr "Tekenen" - -#: fotoxx-11.11.1.cc:281 -msgid "Outlines" -msgstr "Contouren" - -#: fotoxx-11.11.1.cc:282 -msgid "Embossing" -msgstr "Reliefdruk" - -#: fotoxx-11.11.1.cc:283 -msgid "Tiles" -msgstr "Tegels" - -#: fotoxx-11.11.1.cc:284 -msgid "Dots" -msgstr "Krantendruk" - -#: fotoxx-11.11.1.cc:285 -msgid "Painting" -msgstr "Verven" - -#: fotoxx-11.11.1.cc:287 -msgid "Combine" -msgstr "Samenvoegen" - -#: fotoxx-11.11.1.cc:288 -msgid "High Dynamic Range" -msgstr "Hoog dynamisch bereik (HDR)" - -#: fotoxx-11.11.1.cc:289 -msgid "High Depth of Field" -msgstr "Hoge scherptediepte (HDF)" - -#: fotoxx-11.11.1.cc:290 -msgid "Stack / Paint" -msgstr "Stapelen / Verven" - -#: fotoxx-11.11.1.cc:291 -msgid "Stack / Noise" -msgstr "Stapelen / Ruis verminderen" - -#: fotoxx-11.11.1.cc:292 -msgid "Panorama" -msgstr "Panorama maken" - -#: fotoxx-11.11.1.cc:293 -msgid "Vertical Panorama" -msgstr "Verticaal panorama" - -#: fotoxx-11.11.1.cc:296 -msgid "Edit Plugins" -msgstr "Plugins aanpassen" - -#: fotoxx-11.11.1.cc:305 fotoxx-11.11.1.cc:333 fotoxx-11.11.1.cc:4616 -msgid "Help" -msgstr "Help" - -#: fotoxx-11.11.1.cc:306 fotoxx-11.11.1.cc:4606 -msgid "About" -msgstr "Over fotoxx" - -#: fotoxx-11.11.1.cc:307 fotoxx-11.11.1.cc:4610 -msgid "User Guide" -msgstr "Gebruikershandleiding" - -#: fotoxx-11.11.1.cc:308 fotoxx-11.11.1.cc:4613 -msgid "User Guide Changes" -msgstr "" - -#: fotoxx-11.11.1.cc:309 fotoxx-11.11.1.cc:4622 -msgid "Edit Functions Summary" -msgstr "" - -#: fotoxx-11.11.1.cc:310 fotoxx-11.11.1.cc:4625 -msgid "Change Log" -msgstr "Veranderingslogboek" - -#: fotoxx-11.11.1.cc:311 fotoxx-11.11.1.cc:4628 -msgid "Translations" -msgstr "" - -#: fotoxx-11.11.1.cc:312 fotoxx-11.11.1.cc:4631 -msgid "Home Page" -msgstr "Homepage" - -#: fotoxx-11.11.1.cc:316 -msgid "Gallery" -msgstr "Galerie" - -#: fotoxx-11.11.1.cc:318 fotoxx_transform.cc:995 -msgid "Prev" -msgstr "Voorgaande" - -#: fotoxx-11.11.1.cc:319 -msgid "Next" -msgstr "Volgende" - -#: fotoxx-11.11.1.cc:319 -msgid "Open Next File" -msgstr "Open volgend bestand" - -#: fotoxx-11.11.1.cc:320 -msgid "Zoom-in (bigger)" -msgstr "Zoom-in (groter)" - -#: fotoxx-11.11.1.cc:321 -msgid "Zoom-out (smaller)" -msgstr "Zoom-uit (kleiner)" - -#: fotoxx-11.11.1.cc:322 -msgid "Undo" -msgstr "Ongedaan maken" - -#: fotoxx-11.11.1.cc:322 -msgid "Undo One Edit" -msgstr "Bewerkingsstap ongedaan maken" - -#: fotoxx-11.11.1.cc:323 -msgid "Redo" -msgstr "Opnieuw" - -#: fotoxx-11.11.1.cc:323 -msgid "Redo One Edit" -msgstr "Bewerkingsstap opnieuw uitvoeren" - -#: fotoxx-11.11.1.cc:327 -msgid "Save+V" -msgstr "" - -#: fotoxx-11.11.1.cc:328 -msgid "Save+F" -msgstr "" - -#: fotoxx-11.11.1.cc:329 -msgid "Move Image to Trash" -msgstr "Afbeelding naar prullenbak" - -#: fotoxx-11.11.1.cc:329 -msgid "Trash" -msgstr "Opruimen" - -#: fotoxx-11.11.1.cc:332 -msgid "Quit" -msgstr "Afsluiten" - -#: fotoxx-11.11.1.cc:333 -msgid "Fotoxx Essentials" -msgstr "Fotoxx overzicht" - -#: fotoxx-11.11.1.cc:429 -msgid "first time startup" -msgstr "" - -#: fotoxx-11.11.1.cc:1815 -msgid "Exceed 50 anchor points" -msgstr "50 ankerpunten overschreden" - -#: fotoxx-11.11.1.cc:2000 -msgid "load curve from a file" -msgstr "laad curve vanuit bestand" - -#: fotoxx-11.11.1.cc:2053 -msgid "curve file is invalid" -msgstr "curve bestand is ongeldig" - -#: fotoxx-11.11.1.cc:2058 -msgid "curve file has different no. of curves" -msgstr "curve bestand heeft verschillend aantal curves" - -#: fotoxx-11.11.1.cc:2073 -msgid "save curve to a file" -msgstr "bewaar curve in een bestand" - -#: fotoxx-11.11.1.cc:2420 -#, c-format -msgid "" -"Discard special gallery list? \n" -" %s" -msgstr "" - -#: fotoxx-11.11.1.cc:2430 fotoxx-11.11.1.cc:4452 -msgid "prior function still active" -msgstr "vorige functie nog actief" - -#: fotoxx-11.11.1.cc:2607 -msgid "Overwrite original file?" -msgstr "" - -#: fotoxx-11.11.1.cc:2608 -msgid "Do not warn again" -msgstr "" - -#: fotoxx-11.11.1.cc:2624 -msgid "Warning" -msgstr "" - -#: fotoxx-11.11.1.cc:2747 -msgid "Save File" -msgstr "Bestand opslaan" - -#: fotoxx-11.11.1.cc:2770 -msgid "quality" -msgstr "kwaliteit" - -#: fotoxx-11.11.1.cc:2772 -msgid "make current" -msgstr "" - -#: fotoxx-11.11.1.cc:2829 -msgid "jpeg quality must be 1-100" -msgstr "jpeg kwaliteit moet 1-100 zijn" - -#: fotoxx-11.11.1.cc:2851 -#, c-format -msgid "" -"Overwrite file? \n" -" %s" -msgstr "" -"Bestand overschrijven? \n" -" %s" - -#: fotoxx-11.11.1.cc:2992 -msgid "file name" -msgstr "" - -#: fotoxx-11.11.1.cc:2997 fotoxx_transform.cc:351 -msgid "width" -msgstr "breedte" - -#: fotoxx-11.11.1.cc:3000 fotoxx_transform.cc:354 -msgid "height" -msgstr "hoogte" - -#: fotoxx-11.11.1.cc:3006 fotoxx_art.cc:628 fotoxx_retouch.cc:5881 -msgid "color" -msgstr "kleur" - -#: fotoxx-11.11.1.cc:3120 -msgid "" -"Linux standard trash is not supported. \n" -"Desktop trash folder will be created." -msgstr "" -"Linux standaard prullenbak wordt niet ondersteund. \n" -"Desktop prullenbak zal worden aangemaakt." - -#: fotoxx-11.11.1.cc:3138 -msgid "Move read-only file to trash?" -msgstr "Alleen-lezen bestand naar prullenbak?" - -#: fotoxx-11.11.1.cc:3164 -#, c-format -msgid "Cannot create trash folder: %s" -msgstr "Kan niet map voor prullenbak maken: %s" - -#: fotoxx-11.11.1.cc:3172 fotoxx-11.11.1.cc:3178 -#, c-format -msgid "error: %s" -msgstr "fout: %s" - -#: fotoxx-11.11.1.cc:3221 -msgid "old name" -msgstr "oude naam" - -#: fotoxx-11.11.1.cc:3222 -msgid "rename to" -msgstr "hernoemen naar" - -#: fotoxx-11.11.1.cc:3223 -msgid "previous" -msgstr "vorige" - -#: fotoxx-11.11.1.cc:3309 -msgid "The target file already exists" -msgstr "Doelbestand bestaat reeds" - -#: fotoxx-11.11.1.cc:3317 -#, c-format -msgid "" -"Rename failed: \n" -" %s" -msgstr "" - -#: fotoxx-11.11.1.cc:3365 -msgid "Batch Rename" -msgstr "Batchgewijs hernoemen" - -#: fotoxx-11.11.1.cc:3368 fotoxx-11.11.1.cc:3420 fotoxx_info.cc:1513 -#: fotoxx_info.cc:1767 fotoxx_tools.cc:2510 fotoxx_transform.cc:1213 -#, c-format -msgid "%d files selected" -msgstr "" - -#: fotoxx-11.11.1.cc:3370 -msgid "new base name" -msgstr "nieuwe basisnaam" - -#: fotoxx-11.11.1.cc:3373 -msgid "starting sequence" -msgstr "start volgnummer" - -#: fotoxx-11.11.1.cc:3375 -msgid "increment" -msgstr "toename" - -#: fotoxx-11.11.1.cc:3396 -msgid "select files to rename" -msgstr "bestanden selecteren om te hernoemen" - -#: fotoxx-11.11.1.cc:3401 -msgid "base name / sequence / increment not reasonable" -msgstr "basisnaam / volgorde / toename niet zinvol" - -#: fotoxx-11.11.1.cc:3460 -msgid "new file already exists:" -msgstr "nieuw bestand bestaat reeds:" - -#: fotoxx-11.11.1.cc:3468 -msgid "filespec too long:" -msgstr "bestandsnaam te lang:" - -#: fotoxx-11.11.1.cc:3479 -msgid "Rename failed:" -msgstr "Hernoemen mislukt:" - -#: fotoxx-11.11.1.cc:3739 -msgid "Add" -msgstr "Toevoegen" - -#: fotoxx-11.11.1.cc:3739 -msgid "Remove" -msgstr "Verwijderen" - -#: fotoxx-11.11.1.cc:3741 -msgid "menu name" -msgstr "" - -#: fotoxx-11.11.1.cc:3812 fotoxx-11.11.1.cc:3833 -msgid "Restart Fotoxx to update plugin menu" -msgstr "Herstart Fotoxx om plugin menu aan te passen" - -#: fotoxx-11.11.1.cc:3927 -msgid "cannot parallel edit" -msgstr "" - -#: fotoxx-11.11.1.cc:3937 -msgid "" -"exiftool is not installed \n" -"edited images will lose EXIF data" -msgstr "" -"EXIFtool pakket niet geinstalleerd \n" -"bewerkte afbeeldingen verliezen EXIF gegevens" - -#: fotoxx-11.11.1.cc:3943 -msgid "Too many edits, please save image" -msgstr "Te veel aanpassingen, graag afbeelding opslaan" - -#: fotoxx-11.11.1.cc:3948 -msgid "" -"Select area cannot be kept.\n" -"Continue?" -msgstr "" -"Uitsnede kan niet bewaard worden.\n" -"Doorgaan?" - -#: fotoxx-11.11.1.cc:3956 -msgid "" -"Select area not active.\n" -"Continue?" -msgstr "" -"Uitsnede niet actief.\n" -"Doorgaan?" - -#: fotoxx-11.11.1.cc:4427 -msgid "Discard edits?" -msgstr "" - -#: fotoxx-11.11.1.cc:4428 -msgid "" -"This action will discard current edits.\n" -"Continue to discard edits.\n" -"Go Back to keep edits." -msgstr "" - -#: fotoxx-11.11.1.cc:4431 -msgid "Continue" -msgstr "" - -#: fotoxx-11.11.1.cc:4432 -msgid "Go Back" -msgstr "" - -#: fotoxx-11.11.1.cc:5240 -msgid "cannot open thumbnail file" -msgstr "kan miniatuur bestand niet openen" - -#: fotoxx-11.11.1.cc:5433 fotoxx-11.11.1.cc:5549 -msgid "TIFF open failure" -msgstr "TIFF open fout" - -#: fotoxx-11.11.1.cc:5449 -#, c-format -msgid "TIFF bits/color=%d not supported" -msgstr "TIFF bits/kleur=%d niet ondersteund" - -#: fotoxx-11.11.1.cc:5464 fotoxx-11.11.1.cc:5502 -msgid "TIFF read failure" -msgstr "TIFF lees fout" - -#: fotoxx-11.11.1.cc:5608 -msgid "TIFF write failure" -msgstr "TIFF schrijf fout" - -#: fotoxx-11.11.1.cc:5638 -msgid "file type not supported" -msgstr "bestandstype niet ondersteund" - -#: fotoxx-11.11.1.cc:5745 -msgid "pixbuf write failure" -msgstr "pixbuf schrijf fout" - -#: fotoxx_area.cc:54 fotoxx_area.cc:2427 -msgid "Select Area for Edits" -msgstr "Selecteer uitsnede om te bewerken" - -#: fotoxx_area.cc:55 fotoxx_area.cc:2428 -msgid "Press F1 for help" -msgstr "Druk F1 voor help" - -#: fotoxx_area.cc:63 -msgid "" -"Select Area not supported \n" -"by this edit function" -msgstr "" - -#: fotoxx_area.cc:99 fotoxx_tools.cc:809 -msgid "rectangle" -msgstr "rechthoek" - -#: fotoxx_area.cc:100 fotoxx_tools.cc:810 -msgid "ellipse" -msgstr "ellips" - -#: fotoxx_area.cc:101 -msgid "draw: freehand" -msgstr "teken: met de vrije hand" - -#: fotoxx_area.cc:102 -msgid "draw: follow edge" -msgstr "teken: volg rand" - -#: fotoxx_area.cc:103 -msgid "select by mouse" -msgstr "selecteer met muis" - -#: fotoxx_area.cc:104 -msgid "select by color" -msgstr "selecteer met kleur" - -#: fotoxx_area.cc:112 -msgid "radius" -msgstr "straal" - -#: fotoxx_area.cc:116 -msgid "match" -msgstr "gelijkenis" - -#: fotoxx_area.cc:121 -msgid "firewall" -msgstr "firewall" - -#: fotoxx_area.cc:274 fotoxx_area.cc:415 -#, c-format -msgid "exceed %d edits" -msgstr "%d bewerkingen overschreden" - -#: fotoxx_area.cc:992 -msgid "" -"Click one time inside each enclosed area \n" -"(possible gaps in the outline will be found). \n" -"Press F1 for help." -msgstr "" -"Klik eenmalig in elke uitsnede \n" -"(mogelijke gaten in de contouren worden gevonden). \n" -"Druk F1 voor help." - -#: fotoxx_area.cc:1049 -msgid "finish area" -msgstr "gereedmaken uitsnede" - -#: fotoxx_area.cc:1083 -msgid "searching" -msgstr "bezig met zoeken" - -#: fotoxx_area.cc:1155 -msgid "outline has a gap" -msgstr "contour heeft een gat" - -#: fotoxx_area.cc:1157 -msgid "success" -msgstr "succes" - -#: fotoxx_area.cc:1401 fotoxx_area.cc:1430 -msgid "the area is not finished" -msgstr "de uitsnede is niet gereed" - -#: fotoxx_area.cc:1522 -msgid "Edge calculation in progress" -msgstr "Berekening rand bezig" - -#: fotoxx_area.cc:1531 -msgid "Area Edge Calc" -msgstr "Randberekening van uitsnede" - -#: fotoxx_area.cc:1824 -msgid "position with mouse click/drag" -msgstr "positioneer met muis klik/sleep" - -#: fotoxx_area.cc:1848 -msgid "Paste Image" -msgstr "Afbeelding plakken" - -#: fotoxx_area.cc:1863 -msgid "angle" -msgstr "hoek" - -#: fotoxx_area.cc:2127 -msgid "load select area from a file" -msgstr "uitsnede-bestand laden" - -#: fotoxx_area.cc:2161 -msgid "cannot open .tiff and .info files" -msgstr "kan .tiff of .info bestanden niet openen" - -#: fotoxx_area.cc:2180 -msgid "save select area to a file" -msgstr "bewaar geselecteerde uitsnede in een bestand" - -#: fotoxx_area.cc:2216 -msgid "Edit Function Amplifier" -msgstr "Versterker functie wijzigen" - -#: fotoxx_area.cc:2459 -msgid "mouse radius" -msgstr "muis straal" - -#: fotoxx_area.cc:2462 -msgid "power: center" -msgstr "" - -#: fotoxx_area.cc:2464 -msgid "edge" -msgstr "rand" - -#: fotoxx_area.cc:2468 -msgid "reset area" -msgstr "reset uitsnede" - -#: fotoxx_area.cc:2523 -msgid "start edit function first" -msgstr "start eerst edit functie" - -#: fotoxx_art.cc:47 -msgid "Set color depth to 1-16 bits" -msgstr "Instellen kleurdiepte op 1-16 bits" - -#: fotoxx_art.cc:57 -msgid "Set Color Depth" -msgstr "Instellen kleurdiepte" - -#: fotoxx_art.cc:171 -msgid "Simulate Drawing" -msgstr "Tekenen nabootsen" - -#: fotoxx_art.cc:213 fotoxx_retouch.cc:1758 -msgid "contrast" -msgstr "contrast" - -#: fotoxx_art.cc:215 -msgid "outlines" -msgstr "contouren" - -#: fotoxx_art.cc:220 -msgid "pencil" -msgstr "potlood" - -#: fotoxx_art.cc:221 -msgid "chalk" -msgstr "krijt" - -#: fotoxx_art.cc:381 -msgid "Add Image Outlines" -msgstr "Toevoegen afbeeldings contouren" - -#: fotoxx_art.cc:394 -msgid "outline threshold" -msgstr "contour drempel" - -#: fotoxx_art.cc:397 -msgid "outline width" -msgstr "contour breedte" - -#: fotoxx_art.cc:400 -msgid "image brightness" -msgstr "helderheid afbeelding" - -#: fotoxx_art.cc:611 -msgid "Simulate Embossing" -msgstr "Reliefdruk nabootsen" - -#: fotoxx_art.cc:626 -msgid "depth" -msgstr "diepte" - -#: fotoxx_art.cc:821 -msgid "Simulate Tiles" -msgstr "Tegels nabootsen" - -#: fotoxx_art.cc:825 -msgid "tile size" -msgstr "tegelgrootte" - -#: fotoxx_art.cc:829 -msgid "tile gap" -msgstr "voegbreedte" - -#: fotoxx_art.cc:1003 -msgid "Convert Image to Dots" -msgstr "Converteer naar krantendruk" - -#: fotoxx_art.cc:1007 -msgid "dot size" -msgstr "stip grootte" - -#: fotoxx_art.cc:1222 -msgid "Simulate Painting" -msgstr "Verven nabootsen" - -#: fotoxx_art.cc:1226 -msgid "color depth" -msgstr "kleurdiepte" - -#: fotoxx_art.cc:1230 -msgid "patch area goal" -msgstr "" - -#: fotoxx_art.cc:1234 -msgid "req. color match" -msgstr "kleur aanpassing" - -#: fotoxx_art.cc:1238 -msgid "borders" -msgstr "randen" - -#: fotoxx_comp.cc:1956 fotoxx_comp.cc:1961 fotoxx_comp.cc:2582 -#: fotoxx_comp.cc:2587 fotoxx_comp.cc:3275 fotoxx_comp.cc:3280 -#: fotoxx_comp.cc:3830 fotoxx_comp.cc:3835 -msgid "Select 2 to 9 files" -msgstr "Selecteer 2 tot 9 bestanden" - -#: fotoxx_comp.cc:1982 fotoxx_comp.cc:2608 fotoxx_comp.cc:3301 -#: fotoxx_comp.cc:3856 -msgid "Images are not all the same size" -msgstr "Afbeeldingen hebben niet dezelfde grootte" - -#: fotoxx_comp.cc:2321 -msgid "Adjust Image Contributions" -msgstr "Instellen helderheidsbijdragen per afbeelding" - -#: fotoxx_comp.cc:2324 fotoxx_retouch.cc:885 -msgid "dark pixels" -msgstr "donkere pixels" - -#: fotoxx_comp.cc:2326 -msgid "light pixels" -msgstr "heldere pixels" - -#: fotoxx_comp.cc:2328 fotoxx_info.cc:159 -msgid "file:" -msgstr "bestand:" - -#: fotoxx_comp.cc:2844 -msgid "Paint and Warp Image" -msgstr "Verven en kromtrekken afbeelding" - -#: fotoxx_comp.cc:2847 fotoxx_comp.cc:3529 fotoxx_comp.cc:4972 -#: fotoxx_comp.cc:5717 -msgid "image" -msgstr "afbeelding" - -#: fotoxx_comp.cc:2851 fotoxx_retouch.cc:5885 -msgid "paint" -msgstr "verven" - -#: fotoxx_comp.cc:2852 -msgid "warp" -msgstr "kromtrekken" - -#: fotoxx_comp.cc:3527 -msgid "Select and Paint Image" -msgstr "Selecteer en verf afbeelding" - -#: fotoxx_comp.cc:4045 -msgid "Adjust Pixel Composition" -msgstr "Instellen Pixel Samenstelling" - -#: fotoxx_comp.cc:4297 fotoxx_comp.cc:4302 fotoxx_comp.cc:5186 -#: fotoxx_comp.cc:5191 -msgid "Select 2 to 4 files" -msgstr "Selecteer 2 tot 4 bestanden" - -#: fotoxx_comp.cc:4374 -msgid "" -"Drag images into rough alignment.\n" -"To rotate, drag from lower edge." -msgstr "" -"Sleep afbeeldingen ruwweg aansluitend.\n" -"Om te draaien, sleep de onderste rand." - -#: fotoxx_comp.cc:4376 -msgid "Search for lens mm and bow" -msgstr "Zoeken naar brandpuntsafstand en kromming" - -#: fotoxx_comp.cc:4422 fotoxx_comp.cc:5310 -msgid "Pre-align Images" -msgstr "Afbeelding globaal positioneren" - -#: fotoxx_comp.cc:4426 fotoxx_comp.cc:5314 fotoxx_tools.cc:2151 -msgid "lens mm" -msgstr "brandpuntsafstand mm" - -#: fotoxx_comp.cc:4430 fotoxx_comp.cc:5318 fotoxx_tools.cc:2156 -msgid "lens bow" -msgstr "lenskromming" - -#: fotoxx_comp.cc:4432 fotoxx_comp.cc:5320 -msgid "Resize" -msgstr "Grootte wijzigen" - -#: fotoxx_comp.cc:4433 fotoxx_comp.cc:5321 -msgid "resize window" -msgstr "venstergrootte wijzigen" - -#: fotoxx_comp.cc:4470 -msgid "use two images only" -msgstr "gebruik slechts twee afbeeldingen" - -#: fotoxx_comp.cc:4491 fotoxx_comp.cc:4689 fotoxx_comp.cc:4888 -#: fotoxx_comp.cc:5369 fotoxx_comp.cc:5632 -msgid "Too little overlap, cannot align" -msgstr "Te weinig overlap, uitlijnen niet mogelijk" - -#: fotoxx_comp.cc:4963 fotoxx_comp.cc:5708 -msgid "Match Brightness and Color" -msgstr "Match helderheid en kleur" - -#: fotoxx_comp.cc:4987 fotoxx_comp.cc:5732 -msgid "auto color" -msgstr "auto kleur" - -#: fotoxx_comp.cc:4988 fotoxx_comp.cc:5733 -msgid "file color" -msgstr "bestand kleur" - -#: fotoxx_comp.cc:5263 -msgid "" -"Drag images into rough alignment.\n" -"To rotate, drag from right edge." -msgstr "" -"Sleep afbeeldingen ruwweg aansluitend.\n" -"Om te draaien, sleep de rechter rand." - -#: fotoxx_info.cc:70 -msgid "Edit Caption and Comments" -msgstr "" - -#: fotoxx_info.cc:163 -msgid "image date (yyyymmdd)" -msgstr "datum (jjjjmmdd)" - -#: fotoxx_info.cc:165 -msgid "use last" -msgstr "laatste gebruiken" - -#: fotoxx_info.cc:168 -msgid "image stars" -msgstr "afbeelding sterren" - -#: fotoxx_info.cc:186 -msgid "current tags" -msgstr "huidige tags" - -#: fotoxx_info.cc:191 -msgid "recent tags" -msgstr "recente tags" - -#: fotoxx_info.cc:196 fotoxx_info.cc:358 fotoxx_info.cc:1362 -#: fotoxx_info.cc:2290 -msgid "defined tags" -msgstr "gedefineerde tags" - -#: fotoxx_info.cc:348 -msgid "category" -msgstr "categorie" - -#: fotoxx_info.cc:351 -msgid "tag" -msgstr "tag" - -#: fotoxx_info.cc:354 -msgid "create" -msgstr "maken" - -#: fotoxx_info.cc:355 -msgid "delete" -msgstr "verwijder" - -#: fotoxx_info.cc:1229 fotoxx_info.cc:1313 -#, c-format -msgid "search index file error: %s" -msgstr "zoekindex bestandsfout: %s" - -#: fotoxx_info.cc:1348 -msgid "tags to add" -msgstr "tags om toe te voegen" - -#: fotoxx_info.cc:1353 -msgid "create tag" -msgstr "tag maken" - -#: fotoxx_info.cc:1409 fotoxx_info.cc:1602 -#, c-format -msgid "" -"%s \n" -" too many tags" -msgstr "" -"%s \n" -" te veel tags" - -#: fotoxx_info.cc:1550 -msgid "tag to remove" -msgstr "tag om te verwijderen" - -#: fotoxx_info.cc:1554 -msgid "optional replacement" -msgstr "optionele herplaatsing" - -#: fotoxx_info.cc:1559 fotoxx_tools.cc:2463 -msgid "0 files selected" -msgstr "" - -#: fotoxx_info.cc:1562 -msgid "search all files" -msgstr "doorzoek alle bestanden" - -#: fotoxx_info.cc:1647 -msgid "no files selected" -msgstr "geen bestanden geselecteerd" - -#: fotoxx_info.cc:1653 -msgid "no tag specified" -msgstr "geen tag gespecificeerd" - -#: fotoxx_info.cc:1677 fotoxx_info.cc:1706 -msgid "specify tag" -msgstr "specificeer tag" - -#: fotoxx_info.cc:1815 -msgid "View Info" -msgstr "Tonen info" - -#: fotoxx_info.cc:1983 -msgid "All" -msgstr "Alles" - -#: fotoxx_info.cc:1984 -msgid "One Key:" -msgstr "Sleutel:" - -#: fotoxx_info.cc:2249 -msgid "Search Tags, Comments, File Names" -msgstr "Tags, commentaar, bestanden doorzoeken" - -#: fotoxx_info.cc:2255 -msgid "date range" -msgstr "datum van/tot" - -#: fotoxx_info.cc:2256 -msgid "stars range" -msgstr "sterren van/tot" - -#: fotoxx_info.cc:2257 -msgid "search tags" -msgstr "doorzoeken tags" - -#: fotoxx_info.cc:2258 -msgid "search text" -msgstr "doorzoeken tekst" - -#: fotoxx_info.cc:2259 -msgid "file names" -msgstr "bestandsnamen" - -#: fotoxx_info.cc:2264 -msgid "(yyyymmdd)" -msgstr "" - -#: fotoxx_info.cc:2270 -msgid "all/any" -msgstr "" - -#: fotoxx_info.cc:2598 -msgid "No matching images found" -msgstr "Geen overeenkomende afbeeldingen gevonden" - -#: fotoxx_info.cc:2611 -msgid "No search index file present" -msgstr "Zoekindex bestand niet aanwezig" - -#: fotoxx_info.cc:2615 -#, c-format -msgid "Search results file error %s" -msgstr "Zoekresultaten - bestandsfout %s" - -#: fotoxx_retouch.cc:55 -msgid "Adjust Brightness and Color" -msgstr "Instellen helderheid en kleur" - -#: fotoxx_retouch.cc:109 -msgid "small-steps" -msgstr "" - -#: fotoxx_retouch.cc:118 -msgid "color saturation" -msgstr "kleurverzadiging" - -#: fotoxx_retouch.cc:125 -msgid " reset 1 " -msgstr " herstel 1" - -#: fotoxx_retouch.cc:126 -msgid "reset all" -msgstr "alles terugzetten" - -#: fotoxx_retouch.cc:598 -msgid "adjust image gamma" -msgstr "" - -#: fotoxx_retouch.cc:884 -msgid "Expand Brightness Range" -msgstr "Helderheidsbereik vergroten" - -#: fotoxx_retouch.cc:886 -msgid "bright pixels" -msgstr "lichte pixels" - -#: fotoxx_retouch.cc:1057 -msgid "Flatten Brightness Distribution" -msgstr "Helderheidsverdeling afvlakken" - -#: fotoxx_retouch.cc:1071 -msgid "Flatten" -msgstr "afvlakken" - -#: fotoxx_retouch.cc:1333 -msgid "Ramp brightness across image" -msgstr "Helderheidsverspreiding horizontaal/verticaal" - -#: fotoxx_retouch.cc:1757 -msgid "low" -msgstr "" - -#: fotoxx_retouch.cc:1759 -msgid "high" -msgstr "" - -#: fotoxx_retouch.cc:1762 -msgid "Amplify" -msgstr "Versterken" - -#: fotoxx_retouch.cc:2068 -msgid "Adjust White Balance" -msgstr "Instellen witbalans" - -#: fotoxx_retouch.cc:2069 -msgid "Click white or gray image location" -msgstr "Klik op een witte of grijze locatie in de afbeelding" - -#: fotoxx_retouch.cc:2283 -msgid "Color Match Images" -msgstr "" - -#: fotoxx_retouch.cc:2312 -msgid "mouse radius for color sample" -msgstr "" - -#: fotoxx_retouch.cc:2315 -msgid "image for source color" -msgstr "" - -#: fotoxx_retouch.cc:2317 -msgid "click on image to get source color" -msgstr "" - -#: fotoxx_retouch.cc:2320 -msgid "image to set matching color" -msgstr "" - -#: fotoxx_retouch.cc:2322 -msgid "click on image to set matching color" -msgstr "" - -#: fotoxx_retouch.cc:2377 -msgid "select source image color first" -msgstr "" - -#: fotoxx_retouch.cc:2903 fotoxx_tools.cc:1643 -msgid "Click image to select pixels." -msgstr "" - -#: fotoxx_retouch.cc:2955 -msgid "Metric:" -msgstr "" - -#: fotoxx_retouch.cc:3010 -msgid "Blend" -msgstr "" - -#: fotoxx_retouch.cc:3394 -msgid "" -"Method 1:\n" -" Left-click on red-eye to darken.\n" -"Method 2:\n" -" Drag down and right to enclose red-eye.\n" -" Left-click on red-eye to darken.\n" -"Undo red-eye:\n" -" Right-click on red-eye." -msgstr "" -"Methode 1:\n" -" Linkerklik in het rode oog om te corrigeren.\n" -"Methode 2:\n" -" Sleep met de muis naar rechts om het rode oog te markeren.\n" -" Linkerklik in het rode oog om te corrigeren.\n" -"Ongedaan maken:\n" -" Rechterklik in het rode oog." - -#: fotoxx_retouch.cc:3409 -msgid "Red Eye Reduction" -msgstr "Rode ogen correctie" - -#: fotoxx_retouch.cc:3850 -msgid "Set Blur Radius" -msgstr "Instellen straal om te vervagen" - -#: fotoxx_retouch.cc:4084 -msgid "edge detection" -msgstr "rand herkenning" - -#: fotoxx_retouch.cc:4085 -msgid "cycles" -msgstr "cycli" - -#: fotoxx_retouch.cc:4086 -msgid "reduce" -msgstr "verminderen" - -#: fotoxx_retouch.cc:4097 -msgid "unsharp mask" -msgstr "unsharp masking" - -#: fotoxx_retouch.cc:4110 -msgid "brightness gradient" -msgstr "helderheids gradient" - -#: fotoxx_retouch.cc:4516 -msgid "" -" Press the reduce button to \n" -" reduce noise in small steps. \n" -" Use undo to start over." -msgstr "" -" Druk [verminderen] om ruis in \n" -" kleine stappen te verminderen. \n" -" Druk [Annuleren] om ongedaan te maken." - -#: fotoxx_retouch.cc:4527 -msgid "Noise Reduction" -msgstr "Ruis vermindering" - -#: fotoxx_retouch.cc:4532 -msgid "algorithm" -msgstr "algoritme" - -#: fotoxx_retouch.cc:4539 -msgid "flatten outliers by color (1)" -msgstr "afzonderlijk deel afvlakken met kleur (1)" - -#: fotoxx_retouch.cc:4540 -msgid "flatten outliers by color (2)" -msgstr "afzonderlijk deel afvlakken met kleur (2)" - -#: fotoxx_retouch.cc:4541 -msgid "set median brightness by color" -msgstr "instellen mediane helderheid per kleur" - -#: fotoxx_retouch.cc:4542 fotoxx_retouch.cc:4543 -msgid "top hat filter by color" -msgstr "tophat filter voor kleur" - -#: fotoxx_retouch.cc:4858 -msgid "" -"1. Drag mouse to select. \n" -"2. Erase. 3. Repeat. " -msgstr "" -"1. Sleep met de muis om uitsnede te definieren. \n" -"2. Druk [verwijderen]. \n" -"3. Herhaal met nieuwe uitsnede. " - -#: fotoxx_retouch.cc:4889 -msgid "Radius" -msgstr "straal" - -#: fotoxx_retouch.cc:4891 -msgid "Blur" -msgstr "Vervagen" - -#: fotoxx_retouch.cc:4894 -msgid "New Area" -msgstr "Nieuwe uitsnede" - -#: fotoxx_retouch.cc:5275 -msgid "spot size limit" -msgstr "stip grootte limiet" - -#: fotoxx_retouch.cc:5278 -msgid "max. brightness" -msgstr "max. helderheid" - -#: fotoxx_retouch.cc:5281 -msgid "min. contrast" -msgstr "min. contrast" - -#: fotoxx_retouch.cc:5875 -#, c-format -msgid "Undo Memory %d%c" -msgstr "Geheugen voor ongedaan maken %d%c" - -#: fotoxx_retouch.cc:5884 -msgid "pick" -msgstr "kiezen" - -#: fotoxx_retouch.cc:5886 -msgid "erase" -msgstr "verwijderen" - -#: fotoxx_retouch.cc:5894 -msgid "paintbrush radius" -msgstr "straal penseelcirkel" - -#: fotoxx_retouch.cc:5895 -msgid "transparency center" -msgstr "doorzichtigheid midden" - -#: fotoxx_retouch.cc:5896 -msgid "transparency edge" -msgstr "doorzichtigheid rand" - -#: fotoxx_retouch.cc:6166 -msgid "" -"Undo memory limit has been reached. \n" -"Save work with [done], then resume editing." -msgstr "" -"Ongedaan maken geheugen limiet bereikt. \n" -"Bewerkingen opslaan met [Klaar], daarna doorgaan." - -#: fotoxx_tools.cc:42 -msgid "" -"When editing a collection, right-click \n" -"an image or thumbnail to add or remove." -msgstr "" - -#: fotoxx_tools.cc:85 -msgid "Start new collection" -msgstr "" - -#: fotoxx_tools.cc:87 -msgid "Edit a collection" -msgstr "" - -#: fotoxx_tools.cc:89 -msgid "View a collection" -msgstr "" - -#: fotoxx_tools.cc:91 -msgid "Delete a collection" -msgstr "" - -#: fotoxx_tools.cc:95 -msgid "Editing:" -msgstr "" - -#: fotoxx_tools.cc:99 -msgid "Action:" -msgstr "" - -#: fotoxx_tools.cc:133 -msgid "New Collection" -msgstr "" - -#: fotoxx_tools.cc:156 -msgid "Edit Collection" -msgstr "Verzameling aanpassen" - -#: fotoxx_tools.cc:172 -msgid "View Collection" -msgstr "" - -#: fotoxx_tools.cc:193 -msgid "Delete Collection" -msgstr "Verzameling verwijderen" - -#: fotoxx_tools.cc:196 -#, c-format -msgid "delete %s ?" -msgstr "" - -#: fotoxx_tools.cc:223 -#, c-format -msgid "add image to collection: %s" -msgstr "" - -#: fotoxx_tools.cc:225 fotoxx_tools.cc:270 -msgid "remove image from collection" -msgstr "" - -#: fotoxx_tools.cc:226 fotoxx_tools.cc:271 fotoxx_tools.cc:298 -msgid "remove and save image" -msgstr "" - -#: fotoxx_tools.cc:227 fotoxx_tools.cc:316 -msgid "insert saved images here" -msgstr "" - -#: fotoxx_tools.cc:256 -msgid "add image to collection" -msgstr "" - -#: fotoxx_tools.cc:301 -msgid "too many saved files" -msgstr "" - -#: fotoxx_tools.cc:375 -msgid "old top directory" -msgstr "" - -#: fotoxx_tools.cc:378 -msgid "new top directory" -msgstr "" - -#: fotoxx_tools.cc:434 -msgid "completed" -msgstr "Klaar" - -#: fotoxx_tools.cc:452 -msgid "" -"Brightness should show a gradual ramp \n" -"extending all the way to the edges." -msgstr "" -"Helderheid moet een geleidelijke verandering laten \n" -"zien, zich geheel uitstrekkend naar de randen." - -#: fotoxx_tools.cc:492 -msgid "Monitor Check" -msgstr "Monitorkleuren controleren" - -#: fotoxx_tools.cc:612 -msgid "Brightness Distribution" -msgstr "Helderheidshistogram" - -#: fotoxx_tools.cc:796 -msgid "Press ESC to exit slide show" -msgstr "Druk ESC om diashow te stoppen" - -#: fotoxx_tools.cc:797 -msgid "show only latest file versions" -msgstr "" - -#: fotoxx_tools.cc:801 -msgid "arrow keys" -msgstr "pijltjes toetsen" - -#: fotoxx_tools.cc:802 -msgid "instant" -msgstr "" - -#: fotoxx_tools.cc:803 -msgid "fade-in" -msgstr "fade-in" - -#: fotoxx_tools.cc:804 -msgid "roll-right" -msgstr "" - -#: fotoxx_tools.cc:805 -msgid "roll-down" -msgstr "" - -#: fotoxx_tools.cc:806 -msgid "shift-left" -msgstr "schuif-links" - -#: fotoxx_tools.cc:807 -msgid "venetian" -msgstr "venetiaan" - -#: fotoxx_tools.cc:808 -msgid "grate" -msgstr "tralie" - -#: fotoxx_tools.cc:811 -msgid "radar" -msgstr "" - -#: fotoxx_tools.cc:812 -msgid "jaws" -msgstr "" - -#: fotoxx_tools.cc:823 -msgid "seconds" -msgstr "seconden" - -#: fotoxx_tools.cc:827 -msgid "music file" -msgstr "muziek bestand" - -#: fotoxx_tools.cc:831 -msgid "transitions" -msgstr "" - -#: fotoxx_tools.cc:948 -msgid "Select music file or playlist" -msgstr "Selecteer muziekbestand of speellijst" - -#: fotoxx_tools.cc:1971 -msgid "x-spacing" -msgstr "" - -#: fotoxx_tools.cc:1972 -msgid "x-count" -msgstr "" - -#: fotoxx_tools.cc:1973 -msgid "x-enable" -msgstr "" - -#: fotoxx_tools.cc:1979 -msgid "y-spacing" -msgstr "" - -#: fotoxx_tools.cc:1980 -msgid "y-count" -msgstr "" - -#: fotoxx_tools.cc:1981 -msgid "y-enable" -msgstr "" - -#: fotoxx_tools.cc:1988 -msgid "x-offset" -msgstr "" - -#: fotoxx_tools.cc:1992 -msgid "y-offset" -msgstr "" - -#: fotoxx_tools.cc:2146 -msgid "lens name" -msgstr "lens naam" - -#: fotoxx_tools.cc:2220 -msgid "Available Translations" -msgstr "Beschikbare vertalingen" - -#: fotoxx_tools.cc:2224 -msgid "Set Language" -msgstr "Instellen taal" - -#: fotoxx_tools.cc:2290 -msgid "Make Launcher" -msgstr "" - -#: fotoxx_tools.cc:2310 -msgid "Program ufraw-batch is required" -msgstr "Programma ufraw-batch is vereist" - -#: fotoxx_tools.cc:2320 -msgid "Open RAW File" -msgstr "Open RAW bestand" - -#: fotoxx_tools.cc:2331 -msgid "Select RAW files to convert" -msgstr "Selecteer RAW bestanden om te converteren" - -#: fotoxx_tools.cc:2467 -msgid "max. width" -msgstr "max. breedte" - -#: fotoxx_tools.cc:2468 -msgid "max. height" -msgstr "max. hoogte" - -#: fotoxx_tools.cc:2527 fotoxx_transform.cc:1268 -#, c-format -msgid "max. size %d x %d is not reasonable" -msgstr "max. grootte %d x %d is niet logisch" - -#: fotoxx_tools.cc:2613 -msgid "too many files" -msgstr "te veel bestanden" - -#: fotoxx_tools.cc:2656 -msgid "Sync Files is already running" -msgstr "" - -#: fotoxx_tools.cc:2707 -msgid "" -"Run Tools > Synchronize Files so that gallery windows \n" -"will be fast and Search Images will work correctly. \n" -"You can view (not edit) images while synchronize runs." -msgstr "" - -#: fotoxx_tools.cc:2736 -msgid "no top image directory is defined" -msgstr "" - -#: fotoxx_tools.cc:2742 -msgid "top image directory is invalid" -msgstr "" - -#: fotoxx_tools.cc:2747 -msgid "no search index file is present" -msgstr "" - -#: fotoxx_tools.cc:2761 -msgid "new/modified files are present" -msgstr "" - -#: fotoxx_tools.cc:2768 -msgid "no new files found" -msgstr "" - -#: fotoxx_tools.cc:2785 -msgid "Top Image Directory:" -msgstr "Bovenliggende afbeeldingsmap" - -#: fotoxx_tools.cc:2807 -msgid "file sync is mandatory" -msgstr "" - -#: fotoxx_tools.cc:2817 -msgid "top directory is invalid" -msgstr "" - -#: fotoxx_tools.cc:3201 -msgid "Select top image directory" -msgstr "Selecteer bovenliggende afbeeldingsmap" - -#: fotoxx_tools.cc:3378 -msgid "icons" -msgstr "icons" - -#: fotoxx_tools.cc:3379 fotoxx_transform.cc:1467 -msgid "text" -msgstr "tekst" - -#: fotoxx_tools.cc:3380 -msgid "both" -msgstr "beide" - -#: fotoxx_transform.cc:50 -msgid "Use buttons or drag right edge with mouse" -msgstr "gebruik knoppen of sleep rechter rand met de muis" - -#: fotoxx_transform.cc:64 -msgid "degrees" -msgstr "graden" - -#: fotoxx_transform.cc:80 fotoxx_transform.cc:124 -msgid "Trim" -msgstr "Bijsnijden" - -#: fotoxx_transform.cc:81 fotoxx_transform.cc:2437 fotoxx_transform.cc:3263 -#: fotoxx_transform.cc:3526 fotoxx_transform.cc:3787 -msgid "Grid" -msgstr "" - -#: fotoxx_transform.cc:123 -msgid "Undo Trim" -msgstr "Ongedaan maken bijsnijden" - -#: fotoxx_transform.cc:139 -#, c-format -msgid "degrees: %.1f" -msgstr "graden: %.1f" - -#: fotoxx_transform.cc:286 -msgid "gold" -msgstr "" - -#: fotoxx_transform.cc:332 -msgid "Drag middle to move, drag corners to resize." -msgstr "Sleep het midden om te verplaatsen, sleep hoeken om te vergroten." - -#: fotoxx_transform.cc:346 -msgid "customize" -msgstr "Aanpassen" - -#: fotoxx_transform.cc:357 -msgid "ratio" -msgstr "" - -#: fotoxx_transform.cc:361 -msgid "Lock Ratio" -msgstr "verhoudingen behouden" - -#: fotoxx_transform.cc:367 -msgid "invert" -msgstr "omkeren" - -#: fotoxx_transform.cc:892 -msgid "Trim Buttons" -msgstr "Bijsnijd knoppen" - -#: fotoxx_transform.cc:964 -msgid "Lock aspect ratio" -msgstr "lengte:breedte verhouding behouden" - -#: fotoxx_transform.cc:1145 -msgid "Batch Resize" -msgstr "Batchgewijs grootte wijzigen" - -#: fotoxx_transform.cc:1153 -msgid "new max. width" -msgstr "nieuwe max. breedte" - -#: fotoxx_transform.cc:1154 -msgid "new max. height" -msgstr "nieuwe max. hoogte" - -#: fotoxx_transform.cc:1161 -msgid "replace originals" -msgstr "vervangen originelen" - -#: fotoxx_transform.cc:1162 -msgid "export to location" -msgstr "exporteer naar locatie" - -#: fotoxx_transform.cc:1166 -msgid "copy EXIF" -msgstr "copieer EXIF" - -#: fotoxx_transform.cc:1219 -msgid "Select directory" -msgstr "Selecteer map" - -#: fotoxx_transform.cc:1243 -#, c-format -msgid "replace original files? (max. %d x %d)" -msgstr "vervangen originele bestanden? (max. %d x %d)" - -#: fotoxx_transform.cc:1250 -#, c-format -msgid "" -"copy files? (max. %d x %d) \n" -" to location %s" -msgstr "" -"copieer bestanden? (max. %d x %d) \n" -" naar locatie %s" - -#: fotoxx_transform.cc:1261 -msgid "location is not a valid directory" -msgstr "locatie is niet een geldige map" - -#: fotoxx_transform.cc:1304 -msgid "new file already exists" -msgstr "nieuw bestand bestaat reeds" - -#: fotoxx_transform.cc:1388 -msgid "" -"Enter text, click/drag on image.\n" -"Right click to remove" -msgstr "" -"Invoeren tekst, klik/sleep op afbeelding.\n" -"Rechter klik om te verwijderen" - -#: fotoxx_transform.cc:1442 -msgid "Text" -msgstr "Tekst" - -#: fotoxx_transform.cc:1449 -msgid "Size" -msgstr "Grootte" - -#: fotoxx_transform.cc:1452 -msgid "Angle" -msgstr "Hoek" - -#: fotoxx_transform.cc:1463 -msgid "Color" -msgstr "Kleur" - -#: fotoxx_transform.cc:1464 -msgid "Transparency" -msgstr "Doorzichtigheid" - -#: fotoxx_transform.cc:1472 -msgid "backing" -msgstr "" - -#: fotoxx_transform.cc:1475 -msgid "" -"Outline\n" -" Width" -msgstr "" -"Contour\n" -" Breedte" - -#: fotoxx_transform.cc:1477 -msgid "outline" -msgstr "" - -#: fotoxx_transform.cc:1486 -msgid "Annotation File:" -msgstr "Annotatie bestand:" - -#: fotoxx_transform.cc:1564 -msgid "select font" -msgstr "selecteer font" - -#: fotoxx_transform.cc:2197 fotoxx_transform.cc:2429 -msgid "horizontal" -msgstr "horizontaal" - -#: fotoxx_transform.cc:2198 fotoxx_transform.cc:2428 -msgid "vertical" -msgstr "verticaal" - -#: fotoxx_transform.cc:2306 -msgid "black/white positive" -msgstr "" - -#: fotoxx_transform.cc:2307 -msgid "black/white negative" -msgstr "" - -#: fotoxx_transform.cc:2308 -msgid "color positive" -msgstr "" - -#: fotoxx_transform.cc:2309 -msgid "color negative" -msgstr "" - -#: fotoxx_transform.cc:2430 -msgid "linear" -msgstr "lineair" - -#: fotoxx_transform.cc:2433 -msgid "curved" -msgstr "gebogen" - -#: fotoxx_transform.cc:2692 -msgid "" -" Click the four corners of a tetragon area. Press [apply]. \n" -" The image is warped to make the tetragon into a rectangle." -msgstr "" - -#: fotoxx_transform.cc:2878 -msgid "must have 4 corners" -msgstr "" - -#: fotoxx_transform.cc:2999 -msgid "" -" Select an area to warp using select area function. \n" -" Press [start warp] and pull area with mouse. \n" -" Make multiple mouse pulls until satisfied. \n" -" When finished, select another area or press [done]." -msgstr "" -" Selecteer een uitsnede met menu-functie [Uitsnede selecteren]. \n" -" Druk [start kromtrekken] en sleep uitsnede met de muis. \n" -" Herhalen tot het gewenste resultaat. \n" -" Indien gereed, een andere uitsnede selecteren of druk [Klaar]." - -#: fotoxx_transform.cc:3018 -msgid "start warp" -msgstr "Start kromtrekken" - -#: fotoxx_transform.cc:3067 -msgid "Select area first" -msgstr "Eerst uitsnede selecteren" - -#: fotoxx_transform.cc:3242 fotoxx_transform.cc:3505 -msgid "" -" Pull an image position using the mouse. \n" -" Make multiple mouse pulls until satisfied. \n" -" When finished, press [done]." -msgstr "" -" Sleep de plaats van een afbeelding met de muis. \n" -" Herhalen tot het gewenste resultaat. \n" -" Indien gereed, druk [Klaar]." - -#: fotoxx_transform.cc:3771 -msgid "" -" Pull on an image corner using the mouse. \n" -" Make multiple mouse pulls until satisfied. \n" -" When finished, press [done]." -msgstr "" -" Sleep een hoek van de afbeelding. \n" -" Herhalen tot het gewenste resultaat. \n" -" Indien gereed, druk [Klaar]." - -#~ msgid "Create Collection" -#~ msgstr "Verzameling maken" - -#~ msgid "Open Collection" -#~ msgstr "Verzameling openen" - -#~ msgid "Translate" -#~ msgstr "Vertaalinstructie" - -#~ msgid "" -#~ "Run Tools > Synchronize Files so that gallery windows \n" -#~ "will be fast and Search Images will work correctly." -#~ msgstr "" -#~ "Kies Gereedschap > Synchroniseren bestanden zodat gallerie vensters \n" -#~ "snel zijn en Doorzoeken afbeeldingen correct zal werken." - -#~ msgid "Save Collection" -#~ msgstr "Verzameling bewaren" - -#~ msgid "Add new images to collection" -#~ msgstr "Nieuwe afbeeldingen toevoegen aan verzameling" - -#~ msgid "Delete images from collection" -#~ msgstr "Afbeelding verwijderen uit verzameling" - -#~ msgid "Remove and save images" -#~ msgstr "Verwijderen en bewaren afbeeldingen" - -#~ msgid "Insert new or saved images" -#~ msgstr "Invoegen nieuwe of bewaarde afbeeldingen" - -#~ msgid "select image files" -#~ msgstr "selecteer afbeeldingsbestanden" - -#~ msgid "Click on images to delete." -#~ msgstr "Klik op afbeeldingen om te verwijderen." - -#~ msgid "" -#~ "Click on image where new or saved \n" -#~ "images are to be inserted (after)." -#~ msgstr "" -#~ "Klik op de afbeelding waarna nieuwe of bewaarde \n" -#~ "afbeeldingen moeten worden toegevoegd." - -#~ msgid "full rebuild" -#~ msgstr "volledig herbouwen" - -#~ msgid "incremental" -#~ msgstr "toenemend" - -#~ msgid "" -#~ "Rename failed \n" -#~ " %s" -#~ msgstr "" -#~ "Hernoemen mislukt \n" -#~ " %s" - -#~ msgid "transition" -#~ msgstr "overgang" - -#~ msgid "Discard modifications?" -#~ msgstr "Wijzigingen verwerpen?" - -#~ msgid "histogram" -#~ msgstr "histogram" - -#~ msgid "Edit Comments" -#~ msgstr "Commentaar aanpassen" - -#~ msgid "Edit Caption" -#~ msgstr "Bijschrift aanpassen" - -#~ msgid "" -#~ "Discard current gallery list? \n" -#~ " %s" -#~ msgstr "" -#~ "Vervangen huidige galerie lijst? \n" -#~ " %s" - -#~ msgid "Curve File:" -#~ msgstr "Curve bestand:" - -#~ msgid "tags exceed %d characters" -#~ msgstr "tags overschrijden %d karakters" - -#~ msgid "recently added" -#~ msgstr "pas toegevoegd" - -#~ msgid "new file already exists: %s" -#~ msgstr "nieuw bestand bestaat reeds: %s" - -#~ msgid "grid spacing" -#~ msgstr "raster grootte" - -#~ msgid "filespec too long: %s" -#~ msgstr "bestandsnaam te lang: %s" - -#~ msgid "assigned tags" -#~ msgstr "toegewezen tags" - -#~ msgid "Warp Image (curvey)" -#~ msgstr "Afbeelding kromtrekken (curvy)" - -#~ msgid "Unable to save image: %s" -#~ msgstr "Kan afbeelding niet opslaan: %s" - -#~ msgid "Unable to copy EXIF data" -#~ msgstr "Kan EXIF gegevens niet copieren" - -#~ msgid "Total tags exceed %d characters" -#~ msgstr "Aantal tags overschrijdt %d karakters" - -#~ msgid "Too many undo buffers, please save image" -#~ msgstr "te veel undo-buffers, graag afbeelding opslaan" - -#~ msgid "Too many tags: %d" -#~ msgstr "Te veel tags: %d" - -#~ msgid "Tonemap: local-2" -#~ msgstr "Tonemap: lokal-2" - -#~ msgid "Tonemap: local-1" -#~ msgstr "Tonemap: lokal-1" - -#~ msgid "Tonemap: gradient" -#~ msgstr "Tonemap: gradient" - -#~ msgid "Tonemap: base" -#~ msgstr "Tonemap: basis" - -#~ msgid "Package exiftool is missing" -#~ msgstr "Pakket exiftool mist" - -#~ msgid "No assigned tags index file" -#~ msgstr "Geen toegewezen tagindex bestand" - -#~ msgid "Index Tags and Thumbs" -#~ msgstr "Tags en Thumbs synchroniseren" - -#~ msgid "Index Tags" -#~ msgstr "Tags indexeren" - -#~ msgid "" -#~ "Drag middle to move \n" -#~ "Drag corners to resize" -#~ msgstr "" -#~ "Het midden slepen om te bewegen, \n" -#~ "Hoeken slepen om grootte te wijzigen" - -#~ msgid "Convert Tags" -#~ msgstr "Tags converteren" - -#~ msgid "Assigned tags file error: %s" -#~ msgstr "Fout in toegewezen tagbestand %s" - -#~ msgid "Add or Remove Grid Lines" -#~ msgstr "Rasterlijnen toevoegen of verwijderen" - -#~ msgid "" -#~ "%s \n" -#~ " tag limit exceeded" -#~ msgstr "" -#~ "%s \n" -#~ " Tag limiet overschreden" - -#~ msgid " Constraints" -#~ msgstr "Beperkingen" - -#~ msgid "jpeg quality" -#~ msgstr "jpeg kwaliteit" - -#~ msgid "Select between 2 and 10 files to combine" -#~ msgstr "Selecteer 2 tot 10 afbeeldingen om samen te voegen" - -#~ msgid "Current file must be included" -#~ msgstr "Huidig bestand moet in selectie zijn opgenomen" - -#~ msgid "Select image to combine" -#~ msgstr "Selecteer afbeelding om samen te voegen" - -#~ msgid "Select 2 to 10 files to combine" -#~ msgstr "Selecteer 2-10 afbeeldingen om samen te voegen" - -#~ msgid "Retouch Image" -#~ msgstr "Afbeelding retoucheren" - -#~ msgid "Package ufraw required for this function" -#~ msgstr "Pakket ufraw nodig voor deze functie" - -#~ msgid "Merge the images together" -#~ msgstr "afbeeldingen samenvoegen" - -#~ msgid "Match Images" -#~ msgstr "Afbeeldingen gelijkend maken" - -#~ msgid "" -#~ "Drag right image into rough alignment with left \n" -#~ " to rotate, drag right edge up or down" -#~ msgstr "" -#~ "Sleep rechter afbeelding om te positioneren tov de linker afbeelding \n" -#~ "Om te draaien de rechterrand met de muis op of neer slepen" - -#~ msgid "Auto-search lens mm and bow" -#~ msgstr "auto zoeken brandpuntsafstand en lenskromming" - -#~ msgid "Auto" -#~ msgstr "Auto" - -#~ msgid "" -#~ "\n" -#~ " Match Brightness and Color" -#~ msgstr "" -#~ "\n" -#~ " Helderheid en kleur aanpassen" - -#~ msgid "select image files to add tags" -#~ msgstr "bestanden selecteren om tags toe te voegen" - -#~ msgid "select files" -#~ msgstr "bestanden kiezen" - -#~ msgid "rename files" -#~ msgstr "hernoemen bestanden" - -#~ msgid "freehand draw" -#~ msgstr "vrij tekenen" - -#~ msgid "follow edge" -#~ msgstr "rand volgen" - -#~ msgid "" -#~ "exiftool missing, please install \n" -#~ " package libimage-exiftool-perl" -#~ msgstr "" -#~ "Programma exiftool ontbreekt, graag pakket \n" -#~ "libimage-exiftool-perl installeren" - -#~ msgid "color range" -#~ msgstr "kleurbereik" - -#~ msgid "browse" -#~ msgstr "doorzoeken" - -#~ msgid "add tags" -#~ msgstr "Tags toevoegen" - -#~ msgid "TIFF colors=%d depth=%d not supported" -#~ msgstr "TIFF kleuren=%d diepte=%d niet ondersteund" - -#~ msgid "Fix Image Perspective" -#~ msgstr "Perspectief corrigeren" - -#~ msgid "" -#~ "Convert tags to new standard now?\n" -#~ "Are your image files backed-up?" -#~ msgstr "" -#~ "Tags nu naar nieuwe standaard converteren?\n" -#~ "Heeft u een backup van uw afbeeldingen gemaakt?" - -#~ msgid "Burn" -#~ msgstr "Branden" - -#~ msgid "color intensity" -#~ msgstr "kleurintensiteit" - -#~ msgid "Read File" -#~ msgstr "Uitsnede-bestand laden" - -#~ msgid "transparent" -#~ msgstr "doorzichtig" - -#~ msgid "" -#~ "position image\n" -#~ "with mouse drag" -#~ msgstr "" -#~ "afbeelding positioneren\n" -#~ "door met muis te slepen" - -#~ msgid "Warp Image in Selected Area" -#~ msgstr "Afbeelding kromtrekken in geselecteerde uitsnede" - -#~ msgid "Warp Image (curvy)" -#~ msgstr "Afbeelding kromtrekken (curvy)" - -#~ msgid "Warp Image" -#~ msgstr "Kromtrekken afbeelding" - -#~ msgid "Warp Area" -#~ msgstr "Uitsnede kromtrekken" - -#~ msgid "Open File" -#~ msgstr "Open uitsnede-bestand" - -#~ msgid "" -#~ " Pull on an image edge using the mouse. \n" -#~ " Make multiple mouse pulls until satisfied. \n" -#~ " When finished, press [done]." -#~ msgstr "" -#~ " Sleep een rand van de afbeelding. \n" -#~ " Herhalen tot het gewenste resultaat. \n" -#~ " Indien gereed, druk [Klaar]." - -#~ msgid "match any tag" -#~ msgstr "overeenkomend met een tag" - -#~ msgid "match all tags" -#~ msgstr "overeenkomend met alle tags" - -#~ msgid "Tags" -#~ msgstr "Tags" - -#~ msgid "Suspend" -#~ msgstr "Onderbreken" - -#~ msgid "Set Tile and Gap Size" -#~ msgstr "Instellen tegelparameters" - -#~ msgid "Search Tags" -#~ msgstr "Tags doorzoeken" - -#~ msgid "Resume" -#~ msgstr "Hervatten" - -#~ msgid "Edit EXIF data" -#~ msgstr "EXIF gegevens aanpassen" - -#~ msgid "EXIF data" -#~ msgstr "EXIF gegevens" - -#~ msgid "Delete EXIF data" -#~ msgstr "EXIF gegevens verwijderen" - -#~ msgid "Basic EXIF data" -#~ msgstr "EXIF basisgegevens tonen" - -#~ msgid "All EXIF data" -#~ msgstr "EXIF gegevens tonen" - -#~ msgid "/path*/file*" -#~ msgstr "/pad*/bestand*" - -#~ msgid "tags index file error: %s" -#~ msgstr "tagindex bestandsfout: %s" - -#~ msgid "save select area as a file" -#~ msgstr "uitsnede opslaan als bestand" - -#~ msgid "new tags index will now be created" -#~ msgstr "nieuwe tagindex zal nu worden aangemaakt" - -#~ msgid "manage tags" -#~ msgstr "beheren tags" - -#~ msgid "cannot read .dist file" -#~ msgstr "kan .dist bestand niet lezen" - -#~ msgid "brightness to clip (percent)" -#~ msgstr "helderheidsbereik in procenten" - -#~ msgid "Use F1 for context help" -#~ msgstr "Druk op F1 voor context help" - -#~ msgid "Stack" -#~ msgstr "Afbeeldingen stapelen" - -#~ msgid "Rebuild Tags Index" -#~ msgstr "Opbouwen tagindex" - -#~ msgid "No tags index file" -#~ msgstr "Geen tagindex bestand" - -#~ msgid "" -#~ "New tags file already exists! \n" -#~ "Proceed anyway?" -#~ msgstr "" -#~ "Nieuw tag bestand bestaat reeds! \n" -#~ "Toch doorgaan?" - -#~ msgid "HDR" -#~ msgstr "HDR afbeelding maken" - -#~ msgid "HDF" -#~ msgstr "HDF afbeelding maken" - -#~ msgid "" -#~ "Convert tags to new standard now? \n" -#~ "Are your image files backed-up?" -#~ msgstr "" -#~ "Tags nu volgens nieuwe standaard converteren? \n" -#~ "Heeft u een backup van uw afbeeldingen gemaakt?" - -#~ msgid "Convert tags to new standard" -#~ msgstr "Tags volgens nieuwe standaard converteren" - -#~ msgid "Convert Tags !!!" -#~ msgstr "Tags converteren !!!" - -#~ msgid "Constrain" -#~ msgstr "beperken" - -#~ msgid "Area" -#~ msgstr "Uitsnede" - -#~ msgid "target group area" -#~ msgstr "drempel groepering uitsnedes" - -#~ msgid "vertical unbend" -#~ msgstr "verticaal ontkrommen" - -#~ msgid "select by mouse:" -#~ msgstr "selecteer muis" - -#~ msgid "select by color:" -#~ msgstr "selecteer kleur" - -#~ msgid "press ESC to exit" -#~ msgstr "druk ESC om af te sluiten" - -#~ msgid "horizontal unbend" -#~ msgstr "horizontaal ontkrommen" - -#~ msgid "Rebuild Thumbnails" -#~ msgstr "Opbouwen miniaturen" - -#~ msgid "area outline has a hole" -#~ msgstr "Contour van uitsnede heeft een gat" - -#~ msgid "" -#~ "Search all areas for edge and inside pixels. \n" -#~ "Click inside each enclosed area in sequence." -#~ msgstr "" -#~ "Doorzoeken alle uitsnedes op randpixels en interne pixels. \n" -#~ "Klik achtereenvolgens in elke uitsnede." - -#~ msgid "Create Launcher" -#~ msgstr "Start-icon maken" - -#~ msgid "range" -#~ msgstr "bereik" - -#~ msgid "package libimage-exiftool-perl is required" -#~ msgstr "pakket libimage-exiftool-perl is vereist" - -#~ msgid "limit" -#~ msgstr "limiet" - -#~ msgid "Unknown file type, save as tiff/jpeg/png to edit" -#~ msgstr "Bestandstype onbekend, om te bewerken opslaan als tiff/jpeg/png" - -#~ msgid "Start" -#~ msgstr "Starten" - -#~ msgid "Select Files" -#~ msgstr "Selecteer bestanden" - -#~ msgid "Search" -#~ msgstr "Zoeken" - -#~ msgid "Pause" -#~ msgstr "Pauze" - -#~ msgid "OK" -#~ msgstr "OK" - -#~ msgid "Insert" -#~ msgstr "Invoegen" - -#~ msgid "Font" -#~ msgstr "Font" - -#~ msgid "Edit" -#~ msgstr "Bewerken" - -#~ msgid "Clear" -#~ msgstr "Leegmaken" - -#~ msgid "Blend Width" -#~ msgstr "Meng breedte" - -#~ msgid "Add All" -#~ msgstr "Alles toevoegen" - -#~ msgid "Finish" -#~ msgstr "Gereed" - -#~ msgid "Browse" -#~ msgstr "Zoeken" - -#~ msgid "Fetch" -#~ msgstr "Ophalen" - -#~ msgid "Reduce" -#~ msgstr "verminderen" - -#~ msgid "black" -#~ msgstr "zwart" - -#~ msgid "white" -#~ msgstr "wit" - -#~ msgid "Blue" -#~ msgstr "blauw" - -#~ msgid "Red" -#~ msgstr "rood" - -#~ msgid "Green" -#~ msgstr "groen" - -#~ msgid "Lighter Areas" -#~ msgstr "Lichtere delen" - -#~ msgid "Darker Areas" -#~ msgstr "Donkere delen" - -#~ msgid "Brightness" -#~ msgstr "helderheid" - -#~ msgid "Percent" -#~ msgstr "percentage" - -#~ msgid "Presets" -#~ msgstr "verkleiningsfactor" - -#~ msgid "Threshold" -#~ msgstr "drempel" - -#~ msgid "Amount" -#~ msgstr "waarde" - -#~ msgid "Proceed" -#~ msgstr "Doorgaan" - -#~ msgid "Apply" -#~ msgstr "Toepassen" - -#~ msgid "Cancel" -#~ msgstr "Annuleren" - -#~ msgid "Done" -#~ msgstr "Klaar" - -#~ msgid "Width" -#~ msgstr "breedte" - -#~ msgid "make new version" -#~ msgstr "maak nieuwe versie" - -#~ msgid "Height" -#~ msgstr "hoogte" - -#~ msgid "click on window to show RGB" -#~ msgstr "klik op venster om RGB waarden te tonen" - -#~ msgid "Undo Last" -#~ msgstr "Laatste ongedaan maken" - -#~ msgid "Undo All" -#~ msgstr "Alles ongedaan maken" - -#~ msgid "" -#~ "Select images to add, then \n" -#~ "press [Insert] to insert them." -#~ msgstr "" -#~ "Selecteer afbeeldingen om toe te voegen, \n" -#~ "druk daarna [Toevoegen] om ze toe te voegen." - -#~ msgid "Save As" -#~ msgstr "Opslaan als ..." - -#~ msgid "Clone fotoxx" -#~ msgstr "fotoxx klonen" - -#~ msgid "" -#~ "Click on images to remove and save, \n" -#~ "then press [Insert] to insert them." -#~ msgstr "" -#~ "Klik op afbeeldingen om te verwijderen en te bewaren, \n" -#~ "druk daarna [Invoegen] to insert them." - -#~ msgid "random" -#~ msgstr "lukraak" - -#~ msgid "Whole Image" -#~ msgstr "Gehele afbeelding" - -#~ msgid "Time Interval" -#~ msgstr "Tijdsinterval" - -#~ msgid "Delete" -#~ msgstr "Uitsnede verwijderen" diff -Nru fotoxx-11.11.1/locales/nl/zfuncs.po fotoxx-12.01.2/locales/nl/zfuncs.po --- fotoxx-11.11.1/locales/nl/zfuncs.po 2011-11-05 05:30:37.000000000 +0000 +++ fotoxx-12.01.2/locales/nl/zfuncs.po 1970-01-01 00:00:00.000000000 +0000 @@ -1,285 +0,0 @@ -# Translation of zfuncs.po to dutch (nl) -# Translated by: Arthur Kalverboer , okt 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: home 2\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2011-11-05 05:49+0100\n" -"PO-Revision-Date: 2008-11-18 20:37+0100\n" -"Last-Translator: Arthur\n" -"Language-Team: Dutch\n" -"Language: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#: zfuncs.cc:3192 -#, c-format -msgid "help file not found: %s" -msgstr "help bestand niet gevonden: %s" - -#: zfuncs.cc:3296 -#, c-format -msgid "error: %s" -msgstr "fout: %s" - -#: zfuncs.cc:4415 zfuncs.cc:8771 -#, c-format -msgid "cannot open file %s" -msgstr "kan bestand niet openen %s" - -#: zfuncs.cc:4448 -msgid "save screen to file" -msgstr "schrijf scherm naar bestand" - -#: zfuncs.cc:6198 -msgid "No" -msgstr "Nee" - -#: zfuncs.cc:6198 -msgid "Yes" -msgstr "Ja" - -#: zfuncs.cc:6272 zfuncs.cc:6308 zfuncs.cc:6461 zfuncs.cc:6865 zfuncs.cc:8358 -#: zfuncs.cc:8883 zfuncs.cc:8889 zfuncs.cc:8895 zfuncs.cc:8901 -msgid "cancel" -msgstr "Annuleren" - -#: zfuncs.cc:6423 zfuncs.cc:7552 -msgid "open" -msgstr "Openen" - -#: zfuncs.cc:6428 -msgid "choose" -msgstr "Kies" - -#: zfuncs.cc:6433 -msgid "save" -msgstr "opslaan" - -#: zfuncs.cc:6439 -msgid "open folder" -msgstr "open map" - -#: zfuncs.cc:6444 -msgid "create folder" -msgstr "aanmaken map" - -#: zfuncs.cc:6450 -msgid "hidden" -msgstr "verborgen" - -#: zfuncs.cc:6454 -msgid "quality" -msgstr "kwaliteit" - -#: zfuncs.cc:6511 -msgid "JPG quality 0-100" -msgstr "JPG kwaliteit 0-100" - -#: zfuncs.cc:6865 zfuncs.cc:8358 -msgid "done" -msgstr "klaar" - -#: zfuncs.cc:6865 zfuncs.cc:6878 -msgid "margins" -msgstr "" - -#: zfuncs.cc:6874 -msgid "top" -msgstr "" - -#: zfuncs.cc:6875 -msgid "bottom" -msgstr "" - -#: zfuncs.cc:6876 -msgid "left" -msgstr "" - -#: zfuncs.cc:6877 -msgid "right" -msgstr "" - -#: zfuncs.cc:7278 zfuncs.cc:7532 zfuncs.cc:7670 zfuncs.cc:7671 zfuncs.cc:7673 -msgid "bigger" -msgstr "groter" - -#: zfuncs.cc:7278 -msgid "increase thumbnail size" -msgstr "vergroten miniaturen" - -#: zfuncs.cc:7279 -msgid "reduce thumbnail size" -msgstr "verkleinen miniaturen" - -#: zfuncs.cc:7279 zfuncs.cc:7542 zfuncs.cc:7672 zfuncs.cc:7674 -msgid "smaller" -msgstr "kleiner" - -#: zfuncs.cc:7280 zfuncs.cc:7571 -msgid "parent" -msgstr "moeder" - -#: zfuncs.cc:7280 -msgid "parent directory" -msgstr "bovenliggende map" - -#: zfuncs.cc:7281 zfuncs.cc:7589 zfuncs.cc:7681 -msgid "first page" -msgstr "eerste pagina" - -#: zfuncs.cc:7281 -msgid "jump to first file" -msgstr "spring naar eerste bestand" - -#: zfuncs.cc:7282 zfuncs.cc:7587 zfuncs.cc:7676 zfuncs.cc:7683 -msgid "prev page" -msgstr "vorige pagina" - -#: zfuncs.cc:7282 -msgid "previous page" -msgstr "vorige pagina" - -#: zfuncs.cc:7283 zfuncs.cc:7585 zfuncs.cc:7678 -msgid "prev row" -msgstr "vorige rij" - -#: zfuncs.cc:7283 -msgid "previous row" -msgstr "vorige rij" - -#: zfuncs.cc:7284 zfuncs.cc:7586 zfuncs.cc:7679 -msgid "next row" -msgstr "volgende rij" - -#: zfuncs.cc:7285 zfuncs.cc:7588 zfuncs.cc:7677 zfuncs.cc:7684 -msgid "next page" -msgstr "volgende pagina" - -#: zfuncs.cc:7286 -msgid "jump to last file" -msgstr "spring naar laatste bestand" - -#: zfuncs.cc:7286 zfuncs.cc:7590 zfuncs.cc:7682 -msgid "last page" -msgstr "laatste pagina" - -#: zfuncs.cc:7287 zfuncs.cc:7527 -msgid "close" -msgstr "sluiten" - -#: zfuncs.cc:7287 -msgid "close image gallery" -msgstr "sluiten afbeeldingsgalerie" - -#: zfuncs.cc:7558 -msgid "select new file" -msgstr "selecteer nieuw bestand" - -#: zfuncs.cc:8358 -msgid "Select Files" -msgstr "Selecteer bestanden" - -#: zfuncs.cc:8366 -msgid "delete" -msgstr "verwijder" - -#: zfuncs.cc:8367 -msgid "insert" -msgstr "invoegen" - -#: zfuncs.cc:8368 -msgid "add all" -msgstr "alles toevoegen" - -#: zfuncs.cc:8658 -msgid "" -"Initial parameters file created. \n" -"Inspect and revise if necessary." -msgstr "" -"Initieel parameter bestand wordt aangemaakt. \n" -"Zo nodig controleren en verbeteren." - -#: zfuncs.cc:8674 -msgid "load parameters from a file" -msgstr "laden parameters uit bestand" - -#: zfuncs.cc:8743 -msgid "save parameters to a file" -msgstr "schrijf parameters naar bestand" - -#: zfuncs.cc:8881 zfuncs.cc:8887 zfuncs.cc:8893 zfuncs.cc:8899 -msgid "edit parameters" -msgstr "aanpassen parameters" - -#: zfuncs.cc:8882 zfuncs.cc:8888 -msgid "" -"list\n" -"all" -msgstr "" -"opsommen\n" -"alle" - -#: zfuncs.cc:8882 zfuncs.cc:8888 zfuncs.cc:8894 zfuncs.cc:8900 -msgid "" -"load\n" -"file" -msgstr "" -"laden\n" -"bestand" - -#: zfuncs.cc:8882 zfuncs.cc:8888 zfuncs.cc:8894 zfuncs.cc:8900 -msgid "" -"save\n" -"file" -msgstr "" -"opslaan\n" -"bestand" - -#: zfuncs.cc:8883 zfuncs.cc:8895 -msgid "" -"add\n" -"new" -msgstr "" -"toevoegen\n" -"nieuw" - -#: zfuncs.cc:8883 zfuncs.cc:8889 zfuncs.cc:8895 zfuncs.cc:8901 -msgid "apply" -msgstr "toepassen" - -#: zfuncs.cc:8935 -msgid "apply?" -msgstr "toepassen?" - -#: zfuncs.cc:8992 -msgid "(new parm name)" -msgstr "(nieuwe parameter naam)" - -#: zfuncs.cc:8992 -msgid "add parameter" -msgstr "toevoegen parameter" - -#~ msgid "print" -#~ msgstr "Afdrukken" - -#~ msgid "printer ID" -#~ msgstr "printer ID" - -#~ msgid "paper format" -#~ msgstr "papier formaat" - -#~ msgid "portrait" -#~ msgstr "portrait" - -#~ msgid "landscape" -#~ msgstr "landscape" - -#~ msgid "paper format is crazy" -#~ msgstr "papier formaat zinloos" - -#~ msgid "open a file" -#~ msgstr "open bestand" diff -Nru fotoxx-11.11.1/locales/pt/fotoxx.po fotoxx-12.01.2/locales/pt/fotoxx.po --- fotoxx-11.11.1/locales/pt/fotoxx.po 2011-11-05 05:30:37.000000000 +0000 +++ fotoxx-12.01.2/locales/pt/fotoxx.po 1970-01-01 00:00:00.000000000 +0000 @@ -1,2624 +0,0 @@ -# Portuguese translations for home package. -# Copyright (C) 2010 THE home'S COPYRIGHT HOLDER -# This file is distributed under the same license as the home package. -# mico , 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: fotoxx-10.8\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2011-11-05 05:49+0100\n" -"PO-Revision-Date: 2010-07-01 22:55+0200\n" -"Last-Translator: André Campos Rodovalho \n" -"Language-Team: Portuguese\n" -"Language: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Poedit-Language: Portuguese\n" -"X-Poedit-Country: Brazil\n" - -#: fotoxx-11.11.1.cc:179 -msgid "File" -msgstr "Arquivo" - -#: fotoxx-11.11.1.cc:180 fotoxx-11.11.1.cc:316 -msgid "Image Gallery" -msgstr "Galeria de Imagens" - -#: fotoxx-11.11.1.cc:181 -msgid "Clone 50/50" -msgstr "Clonar 50/50" - -#: fotoxx-11.11.1.cc:182 -msgid "Clone Overlay" -msgstr "Clonar Sobreposta" - -#: fotoxx-11.11.1.cc:183 fotoxx-11.11.1.cc:317 fotoxx-11.11.1.cc:2272 -#: fotoxx-11.11.1.cc:2444 -msgid "Open Image File" -msgstr "Abrir arquivo" - -#: fotoxx-11.11.1.cc:184 -msgid "Open in New Window" -msgstr "Abrir em nova janela" - -# msgstr "Abrir próximo arquivo" -#: fotoxx-11.11.1.cc:185 fotoxx-11.11.1.cc:318 -msgid "Open Previous File" -msgstr "Abrir arquivo anterior" - -#: fotoxx-11.11.1.cc:186 -msgid "Open Recent File" -msgstr "Abrir arquivo recente" - -#: fotoxx-11.11.1.cc:187 fotoxx-11.11.1.cc:326 -msgid "Save to Same File" -msgstr "Salvar no mesmo arquivo" - -#: fotoxx-11.11.1.cc:188 fotoxx-11.11.1.cc:327 -msgid "Save to New Version" -msgstr "Salvar nova versão" - -#: fotoxx-11.11.1.cc:189 fotoxx-11.11.1.cc:328 -msgid "Save to New File" -msgstr "Salvar novo arquivo" - -#: fotoxx-11.11.1.cc:190 fotoxx-11.11.1.cc:2990 -msgid "Create Blank Image" -msgstr "Criar imagem em branco" - -#: fotoxx-11.11.1.cc:191 -msgid "Trash Image File" -msgstr "Mover arquivo para lixeira" - -#: fotoxx-11.11.1.cc:192 fotoxx-11.11.1.cc:3216 -msgid "Rename Image File" -msgstr "Renomear arquivo" - -#: fotoxx-11.11.1.cc:193 -msgid "Batch Rename Files" -msgstr "Renomear vários arquivos" - -#: fotoxx-11.11.1.cc:194 -msgid "Print Image File" -msgstr "Imprimir" - -#: fotoxx-11.11.1.cc:195 fotoxx-11.11.1.cc:332 -msgid "Quit fotoxx" -msgstr "Sair do fotoxx" - -#: fotoxx-11.11.1.cc:197 -msgid "Tools" -msgstr "Ferramentas" - -#: fotoxx-11.11.1.cc:198 fotoxx_tools.cc:70 -msgid "Manage Collections" -msgstr "" - -#: fotoxx-11.11.1.cc:199 fotoxx_tools.cc:373 -msgid "Move Collections" -msgstr "" - -#: fotoxx-11.11.1.cc:200 -msgid "Check Monitor" -msgstr "Checar Monitor" - -#: fotoxx-11.11.1.cc:201 fotoxx_tools.cc:550 -msgid "Monitor Gamma" -msgstr "Monitor Gamma" - -#: fotoxx-11.11.1.cc:202 -msgid "Brightness Graph" -msgstr "Gráfico de Brilho" - -#: fotoxx-11.11.1.cc:203 fotoxx_tools.cc:819 -msgid "Slide Show" -msgstr "Apresentação" - -#: fotoxx-11.11.1.cc:204 fotoxx_tools.cc:1668 -msgid "Show RGB" -msgstr "Mostrar RGB" - -#: fotoxx-11.11.1.cc:205 fotoxx_tools.cc:1962 -msgid "Grid Lines" -msgstr "Linhas de grade" - -#: fotoxx-11.11.1.cc:206 fotoxx_tools.cc:2135 -msgid "Lens Parameters" -msgstr "Parâmetros de lente" - -#: fotoxx-11.11.1.cc:207 -msgid "Change Language" -msgstr "Trocar língua" - -#: fotoxx-11.11.1.cc:209 -msgid "Add Menu and Launcher" -msgstr "Adicionar Menu e Atalho" - -#: fotoxx-11.11.1.cc:210 -msgid "Convert RAW files" -msgstr "Converter arquivos RAW" - -#: fotoxx-11.11.1.cc:211 -msgid "Burn Images to CD/DVD" -msgstr "Gravar imagens em CD/DVD" - -#: fotoxx-11.11.1.cc:212 fotoxx_tools.cc:2460 -msgid "E-mail Images" -msgstr "Imagens via e-mail" - -#: fotoxx-11.11.1.cc:213 fotoxx_tools.cc:2783 -msgid "Synchronize Files" -msgstr "Sincronizar Arquivos" - -#: fotoxx-11.11.1.cc:214 fotoxx_tools.cc:3376 -msgid "Toolbar Style" -msgstr "Estilo da barra de ferramentas" - -#: fotoxx-11.11.1.cc:215 -msgid "Memory Usage" -msgstr "Uso de memória" - -#: fotoxx-11.11.1.cc:218 -msgid "Edit Caption/Comments" -msgstr "Editar Legendas/Comentários" - -#: fotoxx-11.11.1.cc:219 fotoxx_info.cc:156 -msgid "Edit Tags" -msgstr "Editar Etiquetas" - -#: fotoxx-11.11.1.cc:220 fotoxx_info.cc:345 -msgid "Manage Tags" -msgstr "Gerenciar Etiquetas" - -#: fotoxx-11.11.1.cc:221 fotoxx_info.cc:1345 -msgid "Batch Add Tags" -msgstr "Adicinar Etiquetas em vários" - -#: fotoxx-11.11.1.cc:222 fotoxx_info.cc:1547 -msgid "Batch Delete Tag" -msgstr "Adicionar várias Etiquetas" - -#: fotoxx-11.11.1.cc:223 -msgid "View Info (short)" -msgstr "Ver Info (curto)" - -#: fotoxx-11.11.1.cc:224 -msgid "View Info (long)" -msgstr "Ver Info (longo)" - -#: fotoxx-11.11.1.cc:225 fotoxx_info.cc:1883 -msgid "Edit Info" -msgstr "Editar Info" - -#: fotoxx-11.11.1.cc:226 fotoxx_info.cc:1981 -msgid "Delete Info" -msgstr "Excluir Info" - -#: fotoxx-11.11.1.cc:227 -msgid "Search Images" -msgstr "Procurar Imagens" - -#: fotoxx-11.11.1.cc:229 fotoxx-11.11.1.cc:230 -msgid "Select" -msgstr "Selecionar" - -#: fotoxx-11.11.1.cc:231 -msgid "Show" -msgstr "Mostrar" - -#: fotoxx-11.11.1.cc:232 -msgid "Hide" -msgstr "Ocultar" - -#: fotoxx-11.11.1.cc:233 -msgid "Enable" -msgstr "Habilitar" - -#: fotoxx-11.11.1.cc:234 -msgid "Disable" -msgstr "Desabilitar" - -#: fotoxx-11.11.1.cc:235 -msgid "Invert" -msgstr "Inverter" - -#: fotoxx-11.11.1.cc:236 -msgid "Unselect" -msgstr "Deselecionar" - -#: fotoxx-11.11.1.cc:237 -msgid "Copy" -msgstr "Copiar" - -#: fotoxx-11.11.1.cc:238 -msgid "Paste" -msgstr "Colar" - -#: fotoxx-11.11.1.cc:239 fotoxx-11.11.1.cc:317 fotoxx_retouch.cc:2314 -#: fotoxx_retouch.cc:2319 -msgid "Open" -msgstr "Abrir" - -#: fotoxx-11.11.1.cc:240 fotoxx-11.11.1.cc:326 -msgid "Save" -msgstr "Salvar" - -#: fotoxx-11.11.1.cc:241 fotoxx_area.cc:2215 -msgid "Select Whole Image" -msgstr "Selecionar toda imagem" - -#: fotoxx-11.11.1.cc:242 -msgid "Select and Edit" -msgstr "Selecionar e Editar" - -#: fotoxx-11.11.1.cc:244 -msgid "Transform" -msgstr "Transformar" - -#: fotoxx-11.11.1.cc:245 fotoxx_transform.cc:60 -msgid "Rotate Image" -msgstr "Rotacioanar" - -#: fotoxx-11.11.1.cc:246 fotoxx_transform.cc:346 -msgid "Trim Image" -msgstr "Recortar/Aparar bordas" - -#: fotoxx-11.11.1.cc:247 fotoxx_transform.cc:972 -msgid "Resize Image" -msgstr "Redimensionar" - -#: fotoxx-11.11.1.cc:248 -msgid "Batch Resize/Export" -msgstr "Redimensionar/Exportar várias " - -#: fotoxx-11.11.1.cc:249 fotoxx_transform.cc:1436 -msgid "Annotate Image" -msgstr "Tomar nota" - -#: fotoxx-11.11.1.cc:250 fotoxx_transform.cc:2193 -msgid "Flip Image" -msgstr "Virar" - -#: fotoxx-11.11.1.cc:251 fotoxx_transform.cc:2303 -msgid "Make Negative" -msgstr "Fazer Negativo" - -#: fotoxx-11.11.1.cc:252 fotoxx_transform.cc:2420 -msgid "Unbend Image" -msgstr "Desempenar" - -#: fotoxx-11.11.1.cc:253 fotoxx_transform.cc:2704 -msgid "Keystone Correction" -msgstr "" - -#: fotoxx-11.11.1.cc:254 fotoxx_transform.cc:3013 -msgid "Warp Image (area)" -msgstr "Distorcer (área)" - -#: fotoxx-11.11.1.cc:255 fotoxx_transform.cc:3255 -msgid "Warp Image (curved)" -msgstr "Distorcer (curvo)" - -#: fotoxx-11.11.1.cc:256 fotoxx_transform.cc:3518 -msgid "Warp Image (linear)" -msgstr "Distorcer (linear)" - -#: fotoxx-11.11.1.cc:257 fotoxx_transform.cc:3782 -msgid "Warp Image (affine)" -msgstr "Distorcer (afim)" - -#: fotoxx-11.11.1.cc:259 -msgid "Retouch" -msgstr "Retocar" - -#: fotoxx-11.11.1.cc:260 -msgid "Brightness/Color" -msgstr "Brilho/Cor" - -#: fotoxx-11.11.1.cc:261 -msgid "Gamma Curves" -msgstr "" - -#: fotoxx-11.11.1.cc:262 -msgid "Expand Brightness" -msgstr "Expandir Brilho" - -#: fotoxx-11.11.1.cc:263 -msgid "Flatten Brightness" -msgstr "Reduzir Brilho" - -#: fotoxx-11.11.1.cc:264 -msgid "Brightness Ramp" -msgstr "Curvas de brilho" - -#: fotoxx-11.11.1.cc:265 fotoxx_retouch.cc:1729 -msgid "Tone Mapping" -msgstr "Mapa sonoro" - -#: fotoxx-11.11.1.cc:266 -msgid "White Balance" -msgstr "Balanço de branco" - -#: fotoxx-11.11.1.cc:267 -msgid "Match Colors" -msgstr "Mesclar Cores" - -#: fotoxx-11.11.1.cc:269 fotoxx_retouch.cc:2941 -msgid "Revise RGB" -msgstr "Revisar RGB" - -#: fotoxx-11.11.1.cc:270 -msgid "Red Eyes" -msgstr "Olhos vermelhos" - -#: fotoxx-11.11.1.cc:271 -msgid "Blur Image" -msgstr "Embaçar" - -#: fotoxx-11.11.1.cc:272 fotoxx_retouch.cc:4077 -msgid "Sharpen Image" -msgstr "Aguçar" - -#: fotoxx-11.11.1.cc:273 -msgid "Reduce Noise" -msgstr "Reduzir ruído" - -#: fotoxx-11.11.1.cc:274 fotoxx_retouch.cc:4881 -msgid "Smart Erase" -msgstr "Apagador inteligente" - -#: fotoxx-11.11.1.cc:275 fotoxx_retouch.cc:5271 -msgid "Remove Dust" -msgstr "Remover Sujeira" - -#: fotoxx-11.11.1.cc:276 fotoxx_retouch.cc:5877 -msgid "Edit Pixels" -msgstr "Editar Pixels" - -#: fotoxx-11.11.1.cc:278 -msgid "Art" -msgstr "Arte" - -#: fotoxx-11.11.1.cc:279 -msgid "Color Depth" -msgstr "Resolução de cor" - -#: fotoxx-11.11.1.cc:280 -msgid "Drawing" -msgstr "Desenho" - -#: fotoxx-11.11.1.cc:281 -msgid "Outlines" -msgstr "Contornos" - -#: fotoxx-11.11.1.cc:282 -msgid "Embossing" -msgstr "Alto-relevo" - -#: fotoxx-11.11.1.cc:283 -msgid "Tiles" -msgstr "Ladrilhos" - -#: fotoxx-11.11.1.cc:284 -msgid "Dots" -msgstr "Pontos" - -#: fotoxx-11.11.1.cc:285 -msgid "Painting" -msgstr "Pintura" - -#: fotoxx-11.11.1.cc:287 -msgid "Combine" -msgstr "Combinar" - -#: fotoxx-11.11.1.cc:288 -msgid "High Dynamic Range" -msgstr "Grande Alcance Dinâmico (HDR)" - -#: fotoxx-11.11.1.cc:289 -msgid "High Depth of Field" -msgstr "Alta Profundidade de Campo (HDF)" - -#: fotoxx-11.11.1.cc:290 -msgid "Stack / Paint" -msgstr "Pilha / Pintura" - -#: fotoxx-11.11.1.cc:291 -msgid "Stack / Noise" -msgstr "Pilha / Ruído" - -#: fotoxx-11.11.1.cc:292 -msgid "Panorama" -msgstr "Panorama" - -#: fotoxx-11.11.1.cc:293 -msgid "Vertical Panorama" -msgstr "Panorama Vertical" - -#: fotoxx-11.11.1.cc:296 -msgid "Edit Plugins" -msgstr "Editar Plugins" - -#: fotoxx-11.11.1.cc:305 fotoxx-11.11.1.cc:333 fotoxx-11.11.1.cc:4616 -msgid "Help" -msgstr "Ajuda" - -#: fotoxx-11.11.1.cc:306 fotoxx-11.11.1.cc:4606 -msgid "About" -msgstr "Sobre" - -#: fotoxx-11.11.1.cc:307 fotoxx-11.11.1.cc:4610 -msgid "User Guide" -msgstr "Guia de usuário" - -#: fotoxx-11.11.1.cc:308 fotoxx-11.11.1.cc:4613 -msgid "User Guide Changes" -msgstr "" - -#: fotoxx-11.11.1.cc:309 fotoxx-11.11.1.cc:4622 -msgid "Edit Functions Summary" -msgstr "" - -#: fotoxx-11.11.1.cc:310 fotoxx-11.11.1.cc:4625 -msgid "Change Log" -msgstr "Relatório de mudanças" - -#: fotoxx-11.11.1.cc:311 fotoxx-11.11.1.cc:4628 -msgid "Translations" -msgstr "" - -#: fotoxx-11.11.1.cc:312 fotoxx-11.11.1.cc:4631 -msgid "Home Page" -msgstr "Página na web" - -#: fotoxx-11.11.1.cc:316 -msgid "Gallery" -msgstr "Galeria" - -#: fotoxx-11.11.1.cc:318 fotoxx_transform.cc:995 -msgid "Prev" -msgstr "Anterior" - -#: fotoxx-11.11.1.cc:319 -msgid "Next" -msgstr "Próximo" - -#: fotoxx-11.11.1.cc:319 -msgid "Open Next File" -msgstr "Abrir próximo arquivo" - -#: fotoxx-11.11.1.cc:320 -msgid "Zoom-in (bigger)" -msgstr "Aproximar (aumentar)" - -#: fotoxx-11.11.1.cc:321 -msgid "Zoom-out (smaller)" -msgstr "Distanciar (diminuir)" - -#: fotoxx-11.11.1.cc:322 -msgid "Undo" -msgstr "Desfazer" - -#: fotoxx-11.11.1.cc:322 -msgid "Undo One Edit" -msgstr "Desfazer uma edição" - -#: fotoxx-11.11.1.cc:323 -msgid "Redo" -msgstr "Refazer" - -#: fotoxx-11.11.1.cc:323 -msgid "Redo One Edit" -msgstr "Refazer uma edição" - -#: fotoxx-11.11.1.cc:327 -msgid "Save+V" -msgstr "Salvar+V" - -#: fotoxx-11.11.1.cc:328 -msgid "Save+F" -msgstr "Salvar+F" - -#: fotoxx-11.11.1.cc:329 -msgid "Move Image to Trash" -msgstr "Mover para lixeira" - -#: fotoxx-11.11.1.cc:329 -msgid "Trash" -msgstr "Lixeira" - -#: fotoxx-11.11.1.cc:332 -msgid "Quit" -msgstr "Sair" - -#: fotoxx-11.11.1.cc:333 -msgid "Fotoxx Essentials" -msgstr "O básico do Fotoxx" - -#: fotoxx-11.11.1.cc:429 -msgid "first time startup" -msgstr "" - -#: fotoxx-11.11.1.cc:1815 -msgid "Exceed 50 anchor points" -msgstr "Excedeu 50 pontos de ancoragem" - -#: fotoxx-11.11.1.cc:2000 -msgid "load curve from a file" -msgstr "carregar curva de arquivo" - -#: fotoxx-11.11.1.cc:2053 -msgid "curve file is invalid" -msgstr "arquivo de curva inválido" - -#: fotoxx-11.11.1.cc:2058 -msgid "curve file has different no. of curves" -msgstr "arquivo de curva tem número de curvas diferente" - -#: fotoxx-11.11.1.cc:2073 -msgid "save curve to a file" -msgstr "salvar curva para arquivo" - -#: fotoxx-11.11.1.cc:2420 -#, c-format -msgid "" -"Discard special gallery list? \n" -" %s" -msgstr "" -"Descartar lista de galleria especial? \n" -" %s" - -#: fotoxx-11.11.1.cc:2430 fotoxx-11.11.1.cc:4452 -msgid "prior function still active" -msgstr "função prévia ainda ativada" - -#: fotoxx-11.11.1.cc:2607 -msgid "Overwrite original file?" -msgstr "" - -#: fotoxx-11.11.1.cc:2608 -msgid "Do not warn again" -msgstr "" - -#: fotoxx-11.11.1.cc:2624 -msgid "Warning" -msgstr "" - -#: fotoxx-11.11.1.cc:2747 -msgid "Save File" -msgstr "Salvar arquivo" - -#: fotoxx-11.11.1.cc:2770 -msgid "quality" -msgstr "qualidade" - -#: fotoxx-11.11.1.cc:2772 -msgid "make current" -msgstr "tornar atual" - -#: fotoxx-11.11.1.cc:2829 -msgid "jpeg quality must be 1-100" -msgstr "qualidade de jpeg deve estar entre 1-100" - -#: fotoxx-11.11.1.cc:2851 -#, c-format -msgid "" -"Overwrite file? \n" -" %s" -msgstr "" -"Sobrescrever arquivo? \n" -" %s" - -#: fotoxx-11.11.1.cc:2992 -msgid "file name" -msgstr "nome do arquvo" - -#: fotoxx-11.11.1.cc:2997 fotoxx_transform.cc:351 -msgid "width" -msgstr "largura" - -#: fotoxx-11.11.1.cc:3000 fotoxx_transform.cc:354 -msgid "height" -msgstr "altura" - -#: fotoxx-11.11.1.cc:3006 fotoxx_art.cc:628 fotoxx_retouch.cc:5881 -msgid "color" -msgstr "cor" - -#: fotoxx-11.11.1.cc:3120 -msgid "" -"Linux standard trash is not supported. \n" -"Desktop trash folder will be created." -msgstr "" -"Lixeira padrão Linux não suportada. \n" -"Uma pasta com lixeira será criada na Área de Trabalho." - -#: fotoxx-11.11.1.cc:3138 -msgid "Move read-only file to trash?" -msgstr "Mover arquivo de apenas leitura para lixeira?" - -#: fotoxx-11.11.1.cc:3164 -#, c-format -msgid "Cannot create trash folder: %s" -msgstr "Não foi possível criar pasta lixeira: %s" - -#: fotoxx-11.11.1.cc:3172 fotoxx-11.11.1.cc:3178 -#, c-format -msgid "error: %s" -msgstr "erro: %s" - -#: fotoxx-11.11.1.cc:3221 -msgid "old name" -msgstr "nome antigo" - -#: fotoxx-11.11.1.cc:3222 -msgid "rename to" -msgstr "renomear para" - -#: fotoxx-11.11.1.cc:3223 -msgid "previous" -msgstr "anterior" - -#: fotoxx-11.11.1.cc:3309 -msgid "The target file already exists" -msgstr "Arquivo alvo já existente" - -#: fotoxx-11.11.1.cc:3317 -#, c-format -msgid "" -"Rename failed: \n" -" %s" -msgstr "" - -#: fotoxx-11.11.1.cc:3365 -msgid "Batch Rename" -msgstr "Renomear vários" - -#: fotoxx-11.11.1.cc:3368 fotoxx-11.11.1.cc:3420 fotoxx_info.cc:1513 -#: fotoxx_info.cc:1767 fotoxx_tools.cc:2510 fotoxx_transform.cc:1213 -#, c-format -msgid "%d files selected" -msgstr "%d arquivos selecionados" - -#: fotoxx-11.11.1.cc:3370 -msgid "new base name" -msgstr "novo nome de base" - -#: fotoxx-11.11.1.cc:3373 -msgid "starting sequence" -msgstr "sequência inicial" - -#: fotoxx-11.11.1.cc:3375 -msgid "increment" -msgstr "incrementar" - -#: fotoxx-11.11.1.cc:3396 -msgid "select files to rename" -msgstr "selecionar arquivos para renomear" - -#: fotoxx-11.11.1.cc:3401 -msgid "base name / sequence / increment not reasonable" -msgstr "nome base / sequencia / incremento fixo" - -#: fotoxx-11.11.1.cc:3460 -msgid "new file already exists:" -msgstr "novo arquivo já existe:" - -#: fotoxx-11.11.1.cc:3468 -msgid "filespec too long:" -msgstr "caminho de arquivo muito longo:" - -#: fotoxx-11.11.1.cc:3479 -msgid "Rename failed:" -msgstr "Renomearação falhou:" - -#: fotoxx-11.11.1.cc:3739 -msgid "Add" -msgstr "Adicionar" - -#: fotoxx-11.11.1.cc:3739 -msgid "Remove" -msgstr "Remover" - -#: fotoxx-11.11.1.cc:3741 -msgid "menu name" -msgstr "nome do menu" - -#: fotoxx-11.11.1.cc:3812 fotoxx-11.11.1.cc:3833 -msgid "Restart Fotoxx to update plugin menu" -msgstr "Reinicie o Fotoxx para atualizar o menu de plugin" - -#: fotoxx-11.11.1.cc:3927 -msgid "cannot parallel edit" -msgstr "não se pode editar paralelamente" - -#: fotoxx-11.11.1.cc:3937 -msgid "" -"exiftool is not installed \n" -"edited images will lose EXIF data" -msgstr "" -"exiftool não está instalado \n" -"imagens editadas perderão informações EXIF" - -#: fotoxx-11.11.1.cc:3943 -msgid "Too many edits, please save image" -msgstr "Muitas edições, favor salvar imagem" - -#: fotoxx-11.11.1.cc:3948 -msgid "" -"Select area cannot be kept.\n" -"Continue?" -msgstr "" -"Área selecionada não pode ser capturada.\n" -"Continuar?" - -#: fotoxx-11.11.1.cc:3956 -msgid "" -"Select area not active.\n" -"Continue?" -msgstr "" -"Área selecionada não ativa.\n" -"Continuar?" - -#: fotoxx-11.11.1.cc:4427 -msgid "Discard edits?" -msgstr "" - -#: fotoxx-11.11.1.cc:4428 -msgid "" -"This action will discard current edits.\n" -"Continue to discard edits.\n" -"Go Back to keep edits." -msgstr "" - -#: fotoxx-11.11.1.cc:4431 -msgid "Continue" -msgstr "" - -#: fotoxx-11.11.1.cc:4432 -msgid "Go Back" -msgstr "" - -#: fotoxx-11.11.1.cc:5240 -msgid "cannot open thumbnail file" -msgstr "erro ao abrir miniatura de arquivo" - -#: fotoxx-11.11.1.cc:5433 fotoxx-11.11.1.cc:5549 -msgid "TIFF open failure" -msgstr "TIFF, Erro ao abrir" - -#: fotoxx-11.11.1.cc:5449 -#, c-format -msgid "TIFF bits/color=%d not supported" -msgstr "TIFF bits/cor=%d não suportado" - -#: fotoxx-11.11.1.cc:5464 fotoxx-11.11.1.cc:5502 -msgid "TIFF read failure" -msgstr "TIFF, Erro ao carregar" - -#: fotoxx-11.11.1.cc:5608 -msgid "TIFF write failure" -msgstr "TIFF, Erro ao gravar" - -#: fotoxx-11.11.1.cc:5638 -msgid "file type not supported" -msgstr "tipo de arquivo não suportado" - -#: fotoxx-11.11.1.cc:5745 -msgid "pixbuf write failure" -msgstr "escrita do pixbuf falhou" - -#: fotoxx_area.cc:54 fotoxx_area.cc:2427 -msgid "Select Area for Edits" -msgstr "Selecionar área para edições" - -#: fotoxx_area.cc:55 fotoxx_area.cc:2428 -msgid "Press F1 for help" -msgstr "Pressione F1 para ajuda" - -#: fotoxx_area.cc:63 -msgid "" -"Select Area not supported \n" -"by this edit function" -msgstr "" -"Seleção de Área não suportada \n" -"por esta função de edição" - -#: fotoxx_area.cc:99 fotoxx_tools.cc:809 -msgid "rectangle" -msgstr "retângulo" - -#: fotoxx_area.cc:100 fotoxx_tools.cc:810 -msgid "ellipse" -msgstr "elipse" - -#: fotoxx_area.cc:101 -msgid "draw: freehand" -msgstr "desenho: mão livre" - -#: fotoxx_area.cc:102 -msgid "draw: follow edge" -msgstr "desenho: seguir borda" - -#: fotoxx_area.cc:103 -msgid "select by mouse" -msgstr "seleção por mouse" - -#: fotoxx_area.cc:104 -msgid "select by color" -msgstr "seleção por cor" - -#: fotoxx_area.cc:112 -msgid "radius" -msgstr "raio" - -#: fotoxx_area.cc:116 -msgid "match" -msgstr "equiparar" - -#: fotoxx_area.cc:121 -msgid "firewall" -msgstr "firewall" - -#: fotoxx_area.cc:274 fotoxx_area.cc:415 -#, c-format -msgid "exceed %d edits" -msgstr "excedeu %d edições" - -#: fotoxx_area.cc:992 -msgid "" -"Click one time inside each enclosed area \n" -"(possible gaps in the outline will be found). \n" -"Press F1 for help." -msgstr "" -"Clique uma vez dentro de cada área inclusa \n" -"(possíveis fendas no contorno serão encontradas). \n" -"Pressione F1 para ajuda." - -#: fotoxx_area.cc:1049 -msgid "finish area" -msgstr "finalize a área" - -#: fotoxx_area.cc:1083 -msgid "searching" -msgstr "procurando" - -#: fotoxx_area.cc:1155 -msgid "outline has a gap" -msgstr "contorno tem uma fenda" - -#: fotoxx_area.cc:1157 -msgid "success" -msgstr "sucesso" - -#: fotoxx_area.cc:1401 fotoxx_area.cc:1430 -msgid "the area is not finished" -msgstr "a área não está finalizada" - -#: fotoxx_area.cc:1522 -msgid "Edge calculation in progress" -msgstr "Cálculo de borda em andamento" - -#: fotoxx_area.cc:1531 -msgid "Area Edge Calc" -msgstr "Calc. área de borda" - -#: fotoxx_area.cc:1824 -msgid "position with mouse click/drag" -msgstr "posicione o mouse clique/arraste" - -#: fotoxx_area.cc:1848 -msgid "Paste Image" -msgstr "Colar Imagem" - -#: fotoxx_area.cc:1863 -msgid "angle" -msgstr "ângulo" - -#: fotoxx_area.cc:2127 -msgid "load select area from a file" -msgstr "carregar selecionador de área de um arquivo" - -#: fotoxx_area.cc:2161 -msgid "cannot open .tiff and .info files" -msgstr "erro ao abrir arquivo .tiff e .info" - -#: fotoxx_area.cc:2180 -msgid "save select area to a file" -msgstr "salve a área selecionada em um arquivo" - -#: fotoxx_area.cc:2216 -msgid "Edit Function Amplifier" -msgstr "Editar função Amplificador" - -#: fotoxx_area.cc:2459 -msgid "mouse radius" -msgstr "raio do mouse" - -#: fotoxx_area.cc:2462 -msgid "power: center" -msgstr "alimentação: centro" - -#: fotoxx_area.cc:2464 -msgid "edge" -msgstr "borda" - -#: fotoxx_area.cc:2468 -msgid "reset area" -msgstr "redefinir área" - -#: fotoxx_area.cc:2523 -msgid "start edit function first" -msgstr "inicie a função de edição primeiro" - -#: fotoxx_art.cc:47 -msgid "Set color depth to 1-16 bits" -msgstr "Configurar resolução de cor para 1-16 bits" - -#: fotoxx_art.cc:57 -msgid "Set Color Depth" -msgstr "Configurar resolução de cor" - -#: fotoxx_art.cc:171 -msgid "Simulate Drawing" -msgstr "Simular Desenho" - -#: fotoxx_art.cc:213 fotoxx_retouch.cc:1758 -msgid "contrast" -msgstr "contraste" - -#: fotoxx_art.cc:215 -msgid "outlines" -msgstr "dispersão" - -#: fotoxx_art.cc:220 -msgid "pencil" -msgstr "caneta" - -#: fotoxx_art.cc:221 -msgid "chalk" -msgstr "giz" - -#: fotoxx_art.cc:381 -msgid "Add Image Outlines" -msgstr "Adicionar contornos de imagem" - -#: fotoxx_art.cc:394 -msgid "outline threshold" -msgstr "limite de contorno" - -#: fotoxx_art.cc:397 -msgid "outline width" -msgstr "largura de contorno" - -#: fotoxx_art.cc:400 -msgid "image brightness" -msgstr "brilho de imagem" - -#: fotoxx_art.cc:611 -msgid "Simulate Embossing" -msgstr "Simular Gravação em relevo" - -#: fotoxx_art.cc:626 -msgid "depth" -msgstr "profundidade" - -#: fotoxx_art.cc:821 -msgid "Simulate Tiles" -msgstr "Simular Ladrilho" - -#: fotoxx_art.cc:825 -msgid "tile size" -msgstr "tamanho do ladrilho" - -#: fotoxx_art.cc:829 -msgid "tile gap" -msgstr "espaçamento dos ladrilhos" - -#: fotoxx_art.cc:1003 -msgid "Convert Image to Dots" -msgstr "Converter imagem para pontos" - -#: fotoxx_art.cc:1007 -msgid "dot size" -msgstr "tamanho do ponto" - -#: fotoxx_art.cc:1222 -msgid "Simulate Painting" -msgstr "Simular Pintura" - -#: fotoxx_art.cc:1226 -msgid "color depth" -msgstr "resolução de cor" - -#: fotoxx_art.cc:1230 -msgid "patch area goal" -msgstr "remendar área objetivo" - -#: fotoxx_art.cc:1234 -msgid "req. color match" -msgstr "correspondência de cores requeridas" - -#: fotoxx_art.cc:1238 -msgid "borders" -msgstr "bordas" - -#: fotoxx_comp.cc:1956 fotoxx_comp.cc:1961 fotoxx_comp.cc:2582 -#: fotoxx_comp.cc:2587 fotoxx_comp.cc:3275 fotoxx_comp.cc:3280 -#: fotoxx_comp.cc:3830 fotoxx_comp.cc:3835 -msgid "Select 2 to 9 files" -msgstr "Selecionar 2 a 9 arquivos" - -#: fotoxx_comp.cc:1982 fotoxx_comp.cc:2608 fotoxx_comp.cc:3301 -#: fotoxx_comp.cc:3856 -msgid "Images are not all the same size" -msgstr "Imagens não são todas do mesmo tamanho" - -#: fotoxx_comp.cc:2321 -msgid "Adjust Image Contributions" -msgstr "Ajustar contribuição de imagem" - -#: fotoxx_comp.cc:2324 fotoxx_retouch.cc:885 -msgid "dark pixels" -msgstr "pixels escuros" - -#: fotoxx_comp.cc:2326 -msgid "light pixels" -msgstr "pixels claros" - -#: fotoxx_comp.cc:2328 fotoxx_info.cc:159 -msgid "file:" -msgstr "arquivo:" - -#: fotoxx_comp.cc:2844 -msgid "Paint and Warp Image" -msgstr "Pintar e distorcer imagem" - -#: fotoxx_comp.cc:2847 fotoxx_comp.cc:3529 fotoxx_comp.cc:4972 -#: fotoxx_comp.cc:5717 -msgid "image" -msgstr "imagem" - -#: fotoxx_comp.cc:2851 fotoxx_retouch.cc:5885 -msgid "paint" -msgstr "pintar" - -#: fotoxx_comp.cc:2852 -msgid "warp" -msgstr "distorção" - -#: fotoxx_comp.cc:3527 -msgid "Select and Paint Image" -msgstr "Selecionar e pintar imagem" - -#: fotoxx_comp.cc:4045 -msgid "Adjust Pixel Composition" -msgstr "Ajustar Composição do Pixel" - -#: fotoxx_comp.cc:4297 fotoxx_comp.cc:4302 fotoxx_comp.cc:5186 -#: fotoxx_comp.cc:5191 -msgid "Select 2 to 4 files" -msgstr "Selecionar 2 a 4 arquivos" - -#: fotoxx_comp.cc:4374 -msgid "" -"Drag images into rough alignment.\n" -"To rotate, drag from lower edge." -msgstr "" -"Arraste as imagens para o alinhamento grosseiro.\n" -"Para rotacionar, arraste da borda mais abaixo." - -#: fotoxx_comp.cc:4376 -msgid "Search for lens mm and bow" -msgstr "Procurar por mm e curvatura de lente" - -#: fotoxx_comp.cc:4422 fotoxx_comp.cc:5310 -msgid "Pre-align Images" -msgstr "Pré-alinhamento de imagens" - -#: fotoxx_comp.cc:4426 fotoxx_comp.cc:5314 fotoxx_tools.cc:2151 -msgid "lens mm" -msgstr "mm de lente" - -#: fotoxx_comp.cc:4430 fotoxx_comp.cc:5318 fotoxx_tools.cc:2156 -msgid "lens bow" -msgstr "curvatura de lente" - -#: fotoxx_comp.cc:4432 fotoxx_comp.cc:5320 -msgid "Resize" -msgstr "Redimensionar" - -#: fotoxx_comp.cc:4433 fotoxx_comp.cc:5321 -msgid "resize window" -msgstr "redimensionar janela" - -#: fotoxx_comp.cc:4470 -msgid "use two images only" -msgstr "use duas imagens apenas" - -#: fotoxx_comp.cc:4491 fotoxx_comp.cc:4689 fotoxx_comp.cc:4888 -#: fotoxx_comp.cc:5369 fotoxx_comp.cc:5632 -msgid "Too little overlap, cannot align" -msgstr "Baixa sobreposição, não é possível alinhar" - -#: fotoxx_comp.cc:4963 fotoxx_comp.cc:5708 -msgid "Match Brightness and Color" -msgstr "Parear Brilho e Cor" - -#: fotoxx_comp.cc:4987 fotoxx_comp.cc:5732 -msgid "auto color" -msgstr "cor automática" - -#: fotoxx_comp.cc:4988 fotoxx_comp.cc:5733 -msgid "file color" -msgstr "arquivo de cor" - -#: fotoxx_comp.cc:5263 -msgid "" -"Drag images into rough alignment.\n" -"To rotate, drag from right edge." -msgstr "" -"Arraste as imagens para o alinhamento grosseiro.\n" -"Para rotacionar, arraste pela borda a direita." - -#: fotoxx_info.cc:70 -msgid "Edit Caption and Comments" -msgstr "Editar Legenda e Comentários" - -#: fotoxx_info.cc:163 -msgid "image date (yyyymmdd)" -msgstr "data de imagem (AAAAmmDD)" - -#: fotoxx_info.cc:165 -msgid "use last" -msgstr "usar último" - -#: fotoxx_info.cc:168 -msgid "image stars" -msgstr "estrelas da imagem" - -#: fotoxx_info.cc:186 -msgid "current tags" -msgstr "etiquetas atuais" - -#: fotoxx_info.cc:191 -msgid "recent tags" -msgstr "etiquetas recentes" - -#: fotoxx_info.cc:196 fotoxx_info.cc:358 fotoxx_info.cc:1362 -#: fotoxx_info.cc:2290 -msgid "defined tags" -msgstr "etiquetas definidas" - -#: fotoxx_info.cc:348 -msgid "category" -msgstr "categoria" - -#: fotoxx_info.cc:351 -msgid "tag" -msgstr "etiqueta" - -#: fotoxx_info.cc:354 -msgid "create" -msgstr "criar" - -#: fotoxx_info.cc:355 -msgid "delete" -msgstr "excluir" - -#: fotoxx_info.cc:1229 fotoxx_info.cc:1313 -#, c-format -msgid "search index file error: %s" -msgstr "busca de arquivo índice erro: %s" - -#: fotoxx_info.cc:1348 -msgid "tags to add" -msgstr "etiquetas a adicionar" - -#: fotoxx_info.cc:1353 -msgid "create tag" -msgstr "criar etiqueta" - -#: fotoxx_info.cc:1409 fotoxx_info.cc:1602 -#, c-format -msgid "" -"%s \n" -" too many tags" -msgstr "" -"%s \n" -" etiquetas demais" - -#: fotoxx_info.cc:1550 -msgid "tag to remove" -msgstr "etiquetas a remover" - -#: fotoxx_info.cc:1554 -msgid "optional replacement" -msgstr "substituição opcional" - -#: fotoxx_info.cc:1559 fotoxx_tools.cc:2463 -msgid "0 files selected" -msgstr "0 arquivos selecionados" - -#: fotoxx_info.cc:1562 -msgid "search all files" -msgstr "procurar todos arquivos" - -#: fotoxx_info.cc:1647 -msgid "no files selected" -msgstr "nenhum arquivo selecionado" - -#: fotoxx_info.cc:1653 -msgid "no tag specified" -msgstr "nenhuma etiqueta especificada" - -#: fotoxx_info.cc:1677 fotoxx_info.cc:1706 -msgid "specify tag" -msgstr "especificar etiqueta" - -#: fotoxx_info.cc:1815 -msgid "View Info" -msgstr "Ver Info" - -#: fotoxx_info.cc:1983 -msgid "All" -msgstr "Todos" - -#: fotoxx_info.cc:1984 -msgid "One Key:" -msgstr "Uma chave:" - -#: fotoxx_info.cc:2249 -msgid "Search Tags, Comments, File Names" -msgstr "Procurar Etiquetas, Comentários, Nome de arquivos" - -#: fotoxx_info.cc:2255 -msgid "date range" -msgstr "variação de data" - -#: fotoxx_info.cc:2256 -msgid "stars range" -msgstr "variação de estrelas" - -#: fotoxx_info.cc:2257 -msgid "search tags" -msgstr "procurar etiquetas" - -#: fotoxx_info.cc:2258 -msgid "search text" -msgstr "procurar texto" - -#: fotoxx_info.cc:2259 -msgid "file names" -msgstr "nome de arquivos" - -#: fotoxx_info.cc:2264 -msgid "(yyyymmdd)" -msgstr "aaaammdd" - -#: fotoxx_info.cc:2270 -msgid "all/any" -msgstr "todos/qualquer" - -#: fotoxx_info.cc:2598 -msgid "No matching images found" -msgstr "Nenhuma imagem encontrada" - -#: fotoxx_info.cc:2611 -msgid "No search index file present" -msgstr "Não há arquivo índice" - -#: fotoxx_info.cc:2615 -#, c-format -msgid "Search results file error %s" -msgstr "Erro no arquivo de resultados de busca %s" - -#: fotoxx_retouch.cc:55 -msgid "Adjust Brightness and Color" -msgstr "Ajustar Brilho e Cor" - -#: fotoxx_retouch.cc:109 -msgid "small-steps" -msgstr "pouco-a-pouco" - -#: fotoxx_retouch.cc:118 -msgid "color saturation" -msgstr "saturação de cor" - -#: fotoxx_retouch.cc:125 -msgid " reset 1 " -msgstr "reconfigurar 1" - -#: fotoxx_retouch.cc:126 -msgid "reset all" -msgstr "reconfigurar tudo" - -#: fotoxx_retouch.cc:598 -msgid "adjust image gamma" -msgstr "" - -#: fotoxx_retouch.cc:884 -msgid "Expand Brightness Range" -msgstr "Aumentar variação de Brilho" - -#: fotoxx_retouch.cc:886 -msgid "bright pixels" -msgstr "pixels brilhantes" - -#: fotoxx_retouch.cc:1057 -msgid "Flatten Brightness Distribution" -msgstr "Reduzir distribuição de Brilho" - -#: fotoxx_retouch.cc:1071 -msgid "Flatten" -msgstr "Abrandar" - -#: fotoxx_retouch.cc:1333 -msgid "Ramp brightness across image" -msgstr "Curva de Brilho sobre a imagem" - -#: fotoxx_retouch.cc:1757 -msgid "low" -msgstr "baixo" - -#: fotoxx_retouch.cc:1759 -msgid "high" -msgstr "alto" - -#: fotoxx_retouch.cc:1762 -msgid "Amplify" -msgstr "Ampliar" - -#: fotoxx_retouch.cc:2068 -msgid "Adjust White Balance" -msgstr "Ajustar balanço de branco" - -#: fotoxx_retouch.cc:2069 -msgid "Click white or gray image location" -msgstr "Clique em uma área branca ou cinza da imagem" - -#: fotoxx_retouch.cc:2283 -msgid "Color Match Images" -msgstr "Imagens para mesclagem de cor" - -#: fotoxx_retouch.cc:2312 -msgid "mouse radius for color sample" -msgstr "raio do mouse para a amostra de cor" - -#: fotoxx_retouch.cc:2315 -msgid "image for source color" -msgstr "imagem para fonte de cor" - -#: fotoxx_retouch.cc:2317 -msgid "click on image to get source color" -msgstr "clique na imagem para obter a cor fonte" - -#: fotoxx_retouch.cc:2320 -msgid "image to set matching color" -msgstr "imagem para mesclagem de cor" - -#: fotoxx_retouch.cc:2322 -msgid "click on image to set matching color" -msgstr "clique na imagem para aplicar mesclagem de cor" - -#: fotoxx_retouch.cc:2377 -msgid "select source image color first" -msgstr "selecione imagem para fonte de cor primeiro" - -#: fotoxx_retouch.cc:2903 fotoxx_tools.cc:1643 -msgid "Click image to select pixels." -msgstr "Clique na imagem para selecionar pixels." - -#: fotoxx_retouch.cc:2955 -msgid "Metric:" -msgstr "Métrica:" - -#: fotoxx_retouch.cc:3010 -msgid "Blend" -msgstr "Mistura" - -#: fotoxx_retouch.cc:3394 -msgid "" -"Method 1:\n" -" Left-click on red-eye to darken.\n" -"Method 2:\n" -" Drag down and right to enclose red-eye.\n" -" Left-click on red-eye to darken.\n" -"Undo red-eye:\n" -" Right-click on red-eye." -msgstr "" -"Método 1:\n" -" Clique com o botão esquerdo no olho vermelho a escurecer.\n" -"Método 2:\n" -" Arraste e solte com o botão direito enquadrando o olho vermelho.\n" -" Clique com o botão esquerdo no olho vermelho a escurecer.\n" -"Retornar ao olho vermelho:\n" -" Clique com o botão direito no olho vermelho." - -#: fotoxx_retouch.cc:3409 -msgid "Red Eye Reduction" -msgstr "Redução de olhos vermelhos" - -#: fotoxx_retouch.cc:3850 -msgid "Set Blur Radius" -msgstr "Configurar raio de desfoque" - -#: fotoxx_retouch.cc:4084 -msgid "edge detection" -msgstr "detecção de borda" - -#: fotoxx_retouch.cc:4085 -msgid "cycles" -msgstr "ciclos" - -#: fotoxx_retouch.cc:4086 -msgid "reduce" -msgstr "reduzir" - -#: fotoxx_retouch.cc:4097 -msgid "unsharp mask" -msgstr "desaguçar máscara" - -#: fotoxx_retouch.cc:4110 -msgid "brightness gradient" -msgstr "gradiente de brilho" - -#: fotoxx_retouch.cc:4516 -msgid "" -" Press the reduce button to \n" -" reduce noise in small steps. \n" -" Use undo to start over." -msgstr "" -" Precione o botão de reduzir para \n" -" reduzir o ruído pouco-a-pouco. \n" -" Use desfazer para começar novamente." - -#: fotoxx_retouch.cc:4527 -msgid "Noise Reduction" -msgstr "Redução de ruído" - -#: fotoxx_retouch.cc:4532 -msgid "algorithm" -msgstr "algoritmo" - -#: fotoxx_retouch.cc:4539 -msgid "flatten outliers by color (1)" -msgstr "aproximar dispersos por cor (1)" - -#: fotoxx_retouch.cc:4540 -msgid "flatten outliers by color (2)" -msgstr "aproximar dispersos por cor (2)" - -#: fotoxx_retouch.cc:4541 -msgid "set median brightness by color" -msgstr "configurar brilho mediano pela cor" - -#: fotoxx_retouch.cc:4542 fotoxx_retouch.cc:4543 -msgid "top hat filter by color" -msgstr "filtro cartola por cor" - -#: fotoxx_retouch.cc:4858 -msgid "" -"1. Drag mouse to select. \n" -"2. Erase. 3. Repeat. " -msgstr "" -"1. Arraste o mouse para selecionar. \n" -"2. Apague. 3. Repita. " - -#: fotoxx_retouch.cc:4889 -msgid "Radius" -msgstr "Raio" - -#: fotoxx_retouch.cc:4891 -msgid "Blur" -msgstr "Desfoque" - -#: fotoxx_retouch.cc:4894 -msgid "New Area" -msgstr "Nova Área" - -#: fotoxx_retouch.cc:5275 -msgid "spot size limit" -msgstr "limite de tamanho de mancha" - -#: fotoxx_retouch.cc:5278 -msgid "max. brightness" -msgstr "brilho máximo" - -#: fotoxx_retouch.cc:5281 -msgid "min. contrast" -msgstr "contraste mínimo" - -#: fotoxx_retouch.cc:5875 -#, c-format -msgid "Undo Memory %d%c" -msgstr "Desfazer memória %d%c" - -#: fotoxx_retouch.cc:5884 -msgid "pick" -msgstr "capturar" - -#: fotoxx_retouch.cc:5886 -msgid "erase" -msgstr "apagar" - -#: fotoxx_retouch.cc:5894 -msgid "paintbrush radius" -msgstr "raio do pincel" - -#: fotoxx_retouch.cc:5895 -msgid "transparency center" -msgstr "centro de transparência" - -#: fotoxx_retouch.cc:5896 -msgid "transparency edge" -msgstr "borda de transparência" - -#: fotoxx_retouch.cc:6166 -msgid "" -"Undo memory limit has been reached. \n" -"Save work with [done], then resume editing." -msgstr "" -"Limite do histórico de modificações foi alcançado. \n" -"Salve seu trabalho clicando [pronto], e continue a editar." - -#: fotoxx_tools.cc:42 -msgid "" -"When editing a collection, right-click \n" -"an image or thumbnail to add or remove." -msgstr "" - -#: fotoxx_tools.cc:85 -msgid "Start new collection" -msgstr "" - -#: fotoxx_tools.cc:87 -msgid "Edit a collection" -msgstr "" - -#: fotoxx_tools.cc:89 -msgid "View a collection" -msgstr "" - -#: fotoxx_tools.cc:91 -msgid "Delete a collection" -msgstr "" - -#: fotoxx_tools.cc:95 -msgid "Editing:" -msgstr "" - -#: fotoxx_tools.cc:99 -msgid "Action:" -msgstr "" - -#: fotoxx_tools.cc:133 -msgid "New Collection" -msgstr "" - -#: fotoxx_tools.cc:156 -msgid "Edit Collection" -msgstr "Editar Coleção" - -#: fotoxx_tools.cc:172 -msgid "View Collection" -msgstr "" - -#: fotoxx_tools.cc:193 -msgid "Delete Collection" -msgstr "Excluir Coleção" - -#: fotoxx_tools.cc:196 -#, c-format -msgid "delete %s ?" -msgstr "" - -#: fotoxx_tools.cc:223 -#, c-format -msgid "add image to collection: %s" -msgstr "" - -#: fotoxx_tools.cc:225 fotoxx_tools.cc:270 -msgid "remove image from collection" -msgstr "" - -#: fotoxx_tools.cc:226 fotoxx_tools.cc:271 fotoxx_tools.cc:298 -msgid "remove and save image" -msgstr "" - -#: fotoxx_tools.cc:227 fotoxx_tools.cc:316 -msgid "insert saved images here" -msgstr "" - -#: fotoxx_tools.cc:256 -msgid "add image to collection" -msgstr "" - -#: fotoxx_tools.cc:301 -msgid "too many saved files" -msgstr "" - -#: fotoxx_tools.cc:375 -msgid "old top directory" -msgstr "" - -#: fotoxx_tools.cc:378 -msgid "new top directory" -msgstr "" - -#: fotoxx_tools.cc:434 -msgid "completed" -msgstr "completo" - -#: fotoxx_tools.cc:452 -msgid "" -"Brightness should show a gradual ramp \n" -"extending all the way to the edges." -msgstr "" -"Brilho deveria mostrar uma inclinação gradual \n" -"estendendo-se até as bordas." - -#: fotoxx_tools.cc:492 -msgid "Monitor Check" -msgstr "Verificar Monitor" - -#: fotoxx_tools.cc:612 -msgid "Brightness Distribution" -msgstr "Distribuição de Brilho" - -#: fotoxx_tools.cc:796 -msgid "Press ESC to exit slide show" -msgstr "Pressione ESC para sair da apresentação" - -#: fotoxx_tools.cc:797 -msgid "show only latest file versions" -msgstr "" - -#: fotoxx_tools.cc:801 -msgid "arrow keys" -msgstr "botões de setas" - -#: fotoxx_tools.cc:802 -msgid "instant" -msgstr "imediato" - -#: fotoxx_tools.cc:803 -msgid "fade-in" -msgstr "esmaecer" - -#: fotoxx_tools.cc:804 -msgid "roll-right" -msgstr "rolar para direita" - -#: fotoxx_tools.cc:805 -msgid "roll-down" -msgstr "rolar para baixo" - -#: fotoxx_tools.cc:806 -msgid "shift-left" -msgstr "salto para esquerda" - -#: fotoxx_tools.cc:807 -msgid "venetian" -msgstr "veneziano" - -#: fotoxx_tools.cc:808 -msgid "grate" -msgstr "grade" - -#: fotoxx_tools.cc:811 -msgid "radar" -msgstr "radar" - -#: fotoxx_tools.cc:812 -msgid "jaws" -msgstr "maxilas" - -#: fotoxx_tools.cc:823 -msgid "seconds" -msgstr "segundos" - -#: fotoxx_tools.cc:827 -msgid "music file" -msgstr "arquivo de música" - -#: fotoxx_tools.cc:831 -msgid "transitions" -msgstr "" - -#: fotoxx_tools.cc:948 -msgid "Select music file or playlist" -msgstr "Selecione arquivo de música ou lista de reprodução" - -#: fotoxx_tools.cc:1971 -msgid "x-spacing" -msgstr "espaçamento-x" - -#: fotoxx_tools.cc:1972 -msgid "x-count" -msgstr "contagem-x" - -#: fotoxx_tools.cc:1973 -msgid "x-enable" -msgstr "" - -#: fotoxx_tools.cc:1979 -msgid "y-spacing" -msgstr "espaçamento-y" - -#: fotoxx_tools.cc:1980 -msgid "y-count" -msgstr "contagem-y" - -#: fotoxx_tools.cc:1981 -msgid "y-enable" -msgstr "" - -#: fotoxx_tools.cc:1988 -msgid "x-offset" -msgstr "" - -#: fotoxx_tools.cc:1992 -msgid "y-offset" -msgstr "" - -#: fotoxx_tools.cc:2146 -msgid "lens name" -msgstr "nome da lente" - -#: fotoxx_tools.cc:2220 -msgid "Available Translations" -msgstr "Traduções disponíveis" - -#: fotoxx_tools.cc:2224 -msgid "Set Language" -msgstr "Configurar língua" - -#: fotoxx_tools.cc:2290 -msgid "Make Launcher" -msgstr "Criar Atalho" - -#: fotoxx_tools.cc:2310 -msgid "Program ufraw-batch is required" -msgstr "Programa ufraw-batch é requerido" - -#: fotoxx_tools.cc:2320 -msgid "Open RAW File" -msgstr "Abrir arquivo RAW" - -#: fotoxx_tools.cc:2331 -msgid "Select RAW files to convert" -msgstr "Selecionar arquivos RAW para converter" - -#: fotoxx_tools.cc:2467 -msgid "max. width" -msgstr "máx. largura" - -#: fotoxx_tools.cc:2468 -msgid "max. height" -msgstr "máx. altura" - -#: fotoxx_tools.cc:2527 fotoxx_transform.cc:1268 -#, c-format -msgid "max. size %d x %d is not reasonable" -msgstr "tamanho max. %d x %d não é razoável" - -#: fotoxx_tools.cc:2613 -msgid "too many files" -msgstr "arquivos em excesso" - -#: fotoxx_tools.cc:2656 -msgid "Sync Files is already running" -msgstr "" - -#: fotoxx_tools.cc:2707 -msgid "" -"Run Tools > Synchronize Files so that gallery windows \n" -"will be fast and Search Images will work correctly. \n" -"You can view (not edit) images while synchronize runs." -msgstr "" - -#: fotoxx_tools.cc:2736 -msgid "no top image directory is defined" -msgstr "" - -#: fotoxx_tools.cc:2742 -msgid "top image directory is invalid" -msgstr "" - -#: fotoxx_tools.cc:2747 -msgid "no search index file is present" -msgstr "" - -#: fotoxx_tools.cc:2761 -msgid "new/modified files are present" -msgstr "" - -#: fotoxx_tools.cc:2768 -msgid "no new files found" -msgstr "" - -#: fotoxx_tools.cc:2785 -msgid "Top Image Directory:" -msgstr "Pasta raiz das imagens:" - -#: fotoxx_tools.cc:2807 -msgid "file sync is mandatory" -msgstr "" - -#: fotoxx_tools.cc:2817 -msgid "top directory is invalid" -msgstr "" - -#: fotoxx_tools.cc:3201 -msgid "Select top image directory" -msgstr "Selecionar pasta raiz de imagens" - -#: fotoxx_tools.cc:3378 -msgid "icons" -msgstr "ícones" - -#: fotoxx_tools.cc:3379 fotoxx_transform.cc:1467 -msgid "text" -msgstr "texto" - -#: fotoxx_tools.cc:3380 -msgid "both" -msgstr "ambos" - -#: fotoxx_transform.cc:50 -msgid "Use buttons or drag right edge with mouse" -msgstr "Use os botões ou arrante a borda direita com o mouse" - -#: fotoxx_transform.cc:64 -msgid "degrees" -msgstr "graus" - -#: fotoxx_transform.cc:80 fotoxx_transform.cc:124 -msgid "Trim" -msgstr "Aparar" - -#: fotoxx_transform.cc:81 fotoxx_transform.cc:2437 fotoxx_transform.cc:3263 -#: fotoxx_transform.cc:3526 fotoxx_transform.cc:3787 -msgid "Grid" -msgstr "" - -#: fotoxx_transform.cc:123 -msgid "Undo Trim" -msgstr "Desfazer recorte" - -#: fotoxx_transform.cc:139 -#, c-format -msgid "degrees: %.1f" -msgstr "graus: %.1f" - -#: fotoxx_transform.cc:286 -msgid "gold" -msgstr "áurea" - -#: fotoxx_transform.cc:332 -msgid "Drag middle to move, drag corners to resize." -msgstr "" -"Arraste pelo centro para mover, arraste as estremidades para redimensionar." - -#: fotoxx_transform.cc:346 -msgid "customize" -msgstr "customizar" - -#: fotoxx_transform.cc:357 -msgid "ratio" -msgstr "taxa" - -#: fotoxx_transform.cc:361 -msgid "Lock Ratio" -msgstr "Travar taxa" - -#: fotoxx_transform.cc:367 -msgid "invert" -msgstr "inverter" - -#: fotoxx_transform.cc:892 -msgid "Trim Buttons" -msgstr "Aparar rodapés" - -#: fotoxx_transform.cc:964 -msgid "Lock aspect ratio" -msgstr "Manter proporção" - -#: fotoxx_transform.cc:1145 -msgid "Batch Resize" -msgstr "Redimencionar vários" - -#: fotoxx_transform.cc:1153 -msgid "new max. width" -msgstr "nova largura máxima" - -#: fotoxx_transform.cc:1154 -msgid "new max. height" -msgstr "nova altura máxima" - -#: fotoxx_transform.cc:1161 -msgid "replace originals" -msgstr "substituir originais" - -#: fotoxx_transform.cc:1162 -msgid "export to location" -msgstr "exportar para localização" - -#: fotoxx_transform.cc:1166 -msgid "copy EXIF" -msgstr "copiar info. EXIF" - -#: fotoxx_transform.cc:1219 -msgid "Select directory" -msgstr "Selecionar pasta" - -#: fotoxx_transform.cc:1243 -#, c-format -msgid "replace original files? (max. %d x %d)" -msgstr "substituir arquivos originais? (max. %d x %d)" - -#: fotoxx_transform.cc:1250 -#, c-format -msgid "" -"copy files? (max. %d x %d) \n" -" to location %s" -msgstr "" -"copiar arquivos? (max. %d x %d) \n" -" para localização %s" - -#: fotoxx_transform.cc:1261 -msgid "location is not a valid directory" -msgstr "localização não é uma pasta válida" - -#: fotoxx_transform.cc:1304 -msgid "new file already exists" -msgstr "novo arquivo já existe" - -#: fotoxx_transform.cc:1388 -msgid "" -"Enter text, click/drag on image.\n" -"Right click to remove" -msgstr "" -"Insira um texto, clique/arraste na imagem.\n" -"Clique com o botão direito para remover" - -#: fotoxx_transform.cc:1442 -msgid "Text" -msgstr "Texto" - -#: fotoxx_transform.cc:1449 -msgid "Size" -msgstr "Tamanho" - -#: fotoxx_transform.cc:1452 -msgid "Angle" -msgstr "Ângulo" - -#: fotoxx_transform.cc:1463 -msgid "Color" -msgstr "Cor" - -#: fotoxx_transform.cc:1464 -msgid "Transparency" -msgstr "Transparência" - -#: fotoxx_transform.cc:1472 -msgid "backing" -msgstr "fundo" - -#: fotoxx_transform.cc:1475 -msgid "" -"Outline\n" -" Width" -msgstr "" -"Contorno\n" -" Largura" - -#: fotoxx_transform.cc:1477 -msgid "outline" -msgstr "contorno" - -#: fotoxx_transform.cc:1486 -msgid "Annotation File:" -msgstr "Arquivo de Comentário:" - -#: fotoxx_transform.cc:1564 -msgid "select font" -msgstr "selecionar fonte" - -#: fotoxx_transform.cc:2197 fotoxx_transform.cc:2429 -msgid "horizontal" -msgstr "horizontal" - -#: fotoxx_transform.cc:2198 fotoxx_transform.cc:2428 -msgid "vertical" -msgstr "vertical" - -#: fotoxx_transform.cc:2306 -msgid "black/white positive" -msgstr "preto/branco positivo" - -#: fotoxx_transform.cc:2307 -msgid "black/white negative" -msgstr "preto/branco negativo" - -#: fotoxx_transform.cc:2308 -msgid "color positive" -msgstr "cor positiva" - -#: fotoxx_transform.cc:2309 -msgid "color negative" -msgstr "cor negativa" - -#: fotoxx_transform.cc:2430 -msgid "linear" -msgstr "linear" - -#: fotoxx_transform.cc:2433 -msgid "curved" -msgstr "curvo" - -#: fotoxx_transform.cc:2692 -msgid "" -" Click the four corners of a tetragon area. Press [apply]. \n" -" The image is warped to make the tetragon into a rectangle." -msgstr "" - -#: fotoxx_transform.cc:2878 -msgid "must have 4 corners" -msgstr "" - -#: fotoxx_transform.cc:2999 -msgid "" -" Select an area to warp using select area function. \n" -" Press [start warp] and pull area with mouse. \n" -" Make multiple mouse pulls until satisfied. \n" -" When finished, select another area or press [done]." -msgstr "" -" Selecione a área a distorcer usando a função de seleção. \n" -" Precione [iniciar distorção] e puxe a área com o mouse. \n" -" Faça vários ajustes até que esteja satisfeito. \n" -" Quando terminar, selecione outra área e precione [pronto]." - -#: fotoxx_transform.cc:3018 -msgid "start warp" -msgstr "iniciar distorção" - -#: fotoxx_transform.cc:3067 -msgid "Select area first" -msgstr "Selecione a área primeiro" - -#: fotoxx_transform.cc:3242 fotoxx_transform.cc:3505 -msgid "" -" Pull an image position using the mouse. \n" -" Make multiple mouse pulls until satisfied. \n" -" When finished, press [done]." -msgstr "" -" Puxe uma posição da usando o mouse. \n" -" Faça vários ajustes até que esteja satisfeito. \n" -" Quando terminar, precione [pronto]." - -#: fotoxx_transform.cc:3771 -msgid "" -" Pull on an image corner using the mouse. \n" -" Make multiple mouse pulls until satisfied. \n" -" When finished, press [done]." -msgstr "" -" Puxe um canto da imgem usando o mouse. \n" -" Faça vários ajustes até que esteja satisfeito. \n" -" Quando terminar, precione [pronto]." - -#~ msgid "Create Collection" -#~ msgstr "Criar Coleção" - -#~ msgid "Open Collection" -#~ msgstr "Abrir Coleção" - -#~ msgid "Translate" -#~ msgstr "Traduzir" - -#~ msgid "" -#~ "Run Tools > Synchronize Files so that gallery windows \n" -#~ "will be fast and Search Images will work correctly." -#~ msgstr "" -#~ "Acesse Ferramentas > Sincronizar Arquivos para as janelas \n" -#~ "da galeria serem rápidas e a Procura de Imagens funcionar corretamente." - -#~ msgid "Save Collection" -#~ msgstr "Salvar coleção" - -#~ msgid "Add new images to collection" -#~ msgstr "Adicionar novas imagens à coleção" - -#~ msgid "Delete images from collection" -#~ msgstr "Excluir imagens da coleção" - -#~ msgid "Remove and save images" -#~ msgstr "Remover e salvar imagens" - -#~ msgid "Insert new or saved images" -#~ msgstr "Inserir salvas ou novas imagens" - -#~ msgid "" -#~ "Select images to add, then \n" -#~ "press [Paste] to insert them." -#~ msgstr "" -#~ "Selecione imagens para adicionar, depois \n" -#~ "pressione [Colar] para inseri-las." - -#~ msgid "select image files" -#~ msgstr "selecione arquivos de imagem" - -#~ msgid "Click on images to delete." -#~ msgstr "Clique em imagens para excluir" - -#~ msgid "" -#~ "Click on images to remove and save, \n" -#~ "then press [Paste] to insert them." -#~ msgstr "" -#~ "Clique em imagens para remover e salve, \n" -#~ "depois pressione [Colar] para inseri-las." - -#~ msgid "" -#~ "Click on image where new or saved \n" -#~ "images are to be inserted (after)." -#~ msgstr "" -#~ "Clique na imagem na qual a imagem nova ou \n" -#~ "salva serão inseridas (depois)." - -#~ msgid "enable" -#~ msgstr "habilitar" - -#~ msgid "x-grid" -#~ msgstr "grade-x" - -#~ msgid "y-grid" -#~ msgstr "grade-y" - -#~ msgid "full rebuild" -#~ msgstr "reconstruir tudo" - -#~ msgid "incremental" -#~ msgstr "incremental" - -#~ msgid "" -#~ "Rename failed \n" -#~ " %s" -#~ msgstr "" -#~ "Renomeação falhou \n" -#~ " %s" - -#~ msgid "transition" -#~ msgstr "transição" - -#~ msgid "Discard modifications?" -#~ msgstr "Discartar modificações?" - -#~ msgid "histogram" -#~ msgstr "histograma" - -#~ msgid "Curve File:" -#~ msgstr "Arquivo de curva:" - -#~ msgid "Delete" -#~ msgstr "Exlcuir" - -#~ msgid "Time Interval" -#~ msgstr "Intervalo de tempo" - -#~ msgid "Clone fotoxx" -#~ msgstr "Clonar fotoxx" - -#~ msgid "Save As" -#~ msgstr "Salvar como..." - -#~ msgid "click on window to show RGB" -#~ msgstr "clique na janela para mostrar RGB" - -#~ msgid "make new version" -#~ msgstr "fazer nova versão" - -#~ msgid "Add All" -#~ msgstr "Adicionar todos" - -#~ msgid "Amount" -#~ msgstr "Quantidade" - -#~ msgid "Apply" -#~ msgstr "Aplicar" - -#~ msgid "Blend Width" -#~ msgstr "Quantidade de mistura" - -#~ msgid "Red" -#~ msgstr "Vermelho" - -#~ msgid "Green" -#~ msgstr "Verde" - -#~ msgid "Blue" -#~ msgstr "Azul" - -#~ msgid "Brightness" -#~ msgstr "Briho" - -#~ msgid "Browse" -#~ msgstr "Procurar" - -#~ msgid "Cancel" -#~ msgstr "Cancelar" - -#~ msgid "Clear" -#~ msgstr "Limpar" - -#~ msgid "Darker Areas" -#~ msgstr "Áreas mais escuras" - -#~ msgid "Done" -#~ msgstr "Pronto" - -#~ msgid "Edit" -#~ msgstr "Editar" - -#~ msgid "Fetch" -#~ msgstr "Buscar" - -#~ msgid "Finish" -#~ msgstr "Finalizar" - -#~ msgid "Font" -#~ msgstr "Fonte" - -#~ msgid "Height" -#~ msgstr "Altura" - -#~ msgid "Insert" -#~ msgstr "Inserir" - -#~ msgid "Lighter Areas" -#~ msgstr "Áreas mais claras" - -#~ msgid "OK" -#~ msgstr "OK" - -#~ msgid "Pause" -#~ msgstr "Pausar" - -#~ msgid "Percent" -#~ msgstr "Percentagem" - -#~ msgid "Presets" -#~ msgstr "Predefinições" - -#~ msgid "Proceed" -#~ msgstr "Continuar" - -#~ msgid "Reduce" -#~ msgstr "Reduzir" - -#~ msgid "Search" -#~ msgstr "Buscar" - -#~ msgid "Select Files" -#~ msgstr "Selecionar arquivos" - -#~ msgid "Start" -#~ msgstr "Iniciar" - -#~ msgid "Threshold" -#~ msgstr "Limiar" - -#~ msgid "Undo All" -#~ msgstr "Desfazer tudo" - -#~ msgid "Undo Last" -#~ msgstr "Desfazer último" - -#~ msgid "Unknown file type, save as tiff/jpeg/png to edit" -#~ msgstr "Tipo de arquivo desconhecido, Salvar como tiff/jpeg/png para editar" - -#~ msgid "Width" -#~ msgstr "Largura" - -#~ msgid "limit" -#~ msgstr "limite" - -#~ msgid "my mouse" -#~ msgstr "meu mouse" - -#~ msgid "package libimage-exiftool-perl is required" -#~ msgstr "pacote libimage-exiftool-perl requerido" - -#~ msgid "range" -#~ msgstr "variação" - -#~ msgid "Create Launcher" -#~ msgstr "Criar atalho" - -#~ msgid "" -#~ "Search all areas for edge and inside pixels. \n" -#~ "Click inside each enclosed area in sequence." -#~ msgstr "" -#~ "Procura de áreas contornadas e pixels internos. \n" -#~ "Mantenha esta janela aberta, clique dentro de cada área enquadrada em " -#~ "sequência." - -#~ msgid "area outline has a hole" -#~ msgstr "contorno de área tem uma falha" - -#~ msgid "Rebuild Thumbnails" -#~ msgstr "Reconstruir miniaturas" - -#~ msgid "horizontal unbend" -#~ msgstr "desempeno horizontal" - -#~ msgid "press ESC to exit" -#~ msgstr "pressione ESC para sair" - -#~ msgid "select by color:" -#~ msgstr "selecionar por cor:" - -#~ msgid "select by mouse:" -#~ msgstr "selecionar por mouse:" - -#~ msgid "vertical unbend" -#~ msgstr "desempeno vertical" - -#~ msgid "target group area" -#~ msgstr "área de grupo de destino" - -#~ msgid "Area" -#~ msgstr "Área" - -#~ msgid "Constrain" -#~ msgstr "Restrição" - -#~ msgid "Convert Tags !!!" -#~ msgstr "Converter etiquetas!" - -#~ msgid "Convert tags to new standard" -#~ msgstr "Converter etiquetas para novo padrão" - -#~ msgid "" -#~ "Convert tags to new standard now? \n" -#~ "Are your image files backed-up?" -#~ msgstr "" -#~ "Converter etiquetas para novo padrão agora? \n" -#~ "Você possui cópia de segurança das imagens?" - -#~ msgid "HDF" -#~ msgstr "HDF" - -#~ msgid "HDR" -#~ msgstr "HDR" - -#~ msgid "" -#~ "New tags file already exists! \n" -#~ "Proceed anyway?" -#~ msgstr "" -#~ "Novo arquivo de etiquetas já existe! \n" -#~ "Continuar assim mesmo?" - -#~ msgid "No tags index file" -#~ msgstr "Nenhum arquivo índice de etiquetas" - -#~ msgid "Rebuild Tags Index" -#~ msgstr "Reconstruir índice de etiquetas" - -#~ msgid "Stack" -#~ msgstr "Pilha" - -#~ msgid "Use F1 for context help" -#~ msgstr "Use F1 para ajuda contextualizada" - -#~ msgid "brightness to clip (percent)" -#~ msgstr "Brilho a apagar (percentagem)" - -#~ msgid "cannot read .dist file" -#~ msgstr "Erro ao ler arquivo .dist" - -#~ msgid "color select firewall" -#~ msgstr "selecionar cor do firewall" - -#~ msgid "manage tags" -#~ msgstr "gerenciar etiquetas" - -#~ msgid "new tags index will now be created" -#~ msgstr "novo índice de etiquetas será criado agora" - -#~ msgid "save select area as a file" -#~ msgstr "salvar selecionador de área em arquivo" - -#~ msgid "tags index file error: %s" -#~ msgstr "erro no arquivo índice de etiquetas: %s" - -#~ msgid "annotation file:" -#~ msgstr "arquivo de comentário:" - -#~ msgid "background" -#~ msgstr "fundo" - -#~ msgid "foreground" -#~ msgstr "primeiro plano" - -#~ msgid "transparency" -#~ msgstr "transparência" - -#~ msgid "/path*/file*" -#~ msgstr "/caminho*/arquivo*" - -#~ msgid "All EXIF data" -#~ msgstr "Toda informação EXIF" - -#~ msgid "Basic EXIF data" -#~ msgstr "Informações EXIF básicas" - -#~ msgid "Delete EXIF data" -#~ msgstr "Excluir informações EXIF" - -#~ msgid "EXIF data" -#~ msgstr "Informações EXIF" - -#~ msgid "Edit EXIF data" -#~ msgstr "Editar informações EXIF" - -#~ msgid "Edit User Comments" -#~ msgstr "Editar Comentários de Usuário" - -#~ msgid "Resume" -#~ msgstr "Retomar" - -#~ msgid "Search Tags" -#~ msgstr "Buscar etiquetas" - -#~ msgid "Set Tile and Gap Size" -#~ msgstr "Configurar ladrilho e espaçamento" - -#~ msgid "Suspend" -#~ msgstr "Suspender" - -#~ msgid "Tags" -#~ msgstr "Etiquetas" - -#~ msgid "comments" -#~ msgstr "comentários" - -#~ msgid "match all tags" -#~ msgstr "condizer com todas etiquetas" - -#~ msgid "match any tag" -#~ msgstr "condizer com qualquer etiqueta" - -#~ msgid "" -#~ " Pull on an image edge using the mouse. \n" -#~ " Make multiple mouse pulls until satisfied. \n" -#~ " When finished, press [done]." -#~ msgstr "" -#~ " Puxe uma borda da imagem usando o mouse \n" -#~ " Faça vários ajustes até que esteja satisfeito. \n" -#~ " Quando terminar, precione [pronto]." - -#~ msgid "Open File" -#~ msgstr "Abrir Arquivo" - -#~ msgid "Warp Area" -#~ msgstr "Distorcer área" - -#~ msgid "Warp Image" -#~ msgstr "Distorcer imagem" - -#~ msgid "Warp Image (curvy)" -#~ msgstr "Distorcer (curvo)" - -#~ msgid "Warp Image in Selected Area" -#~ msgstr "Distorcer imagem em área selecionada" - -#~ msgid "" -#~ "position image\n" -#~ "with mouse drag" -#~ msgstr "" -#~ "posicione a imagem\n" -#~ "arrastando com o mouse" - -#~ msgid "Clip Brightness" -#~ msgstr "Limitar Brilho" - -#~ msgid "Batch Delete Tags" -#~ msgstr "Excluir várias etiquetas" - -#~ msgid "color intensity" -#~ msgstr "Intensidade de cor" - -#~ msgid "Burn" -#~ msgstr "Gravar" - -#~ msgid "" -#~ "Convert tags to new standard now?\n" -#~ "Are your image files backed-up?" -#~ msgstr "" -#~ "Converter etiquetas para novo padrão agora?\n" -#~ "Suas imagens possuem cópia de segurança?" - -#~ msgid "done" -#~ msgstr "pronto" - -#~ msgid "Fix Image Perspective" -#~ msgstr "Acertar perspectiva de imagem" - -#~ msgid "Package ufraw required for this function" -#~ msgstr "Pacote ufraw requerido para esta função" - -#~ msgid "Read File" -#~ msgstr "Ler arquivo" - -#~ msgid "TIFF colors=%d depth=%d not supported" -#~ msgstr "TIFF, cores=%d e intensidade=%d não suportadas" - -#~ msgid "add tags" -#~ msgstr "adicionar etiquetas" - -#~ msgid "base image" -#~ msgstr "imagem base" - -#~ msgid "browse" -#~ msgstr "procurar" - -#~ msgid "color range" -#~ msgstr "variação de cor" - -#~ msgid "" -#~ "exiftool missing, please install \n" -#~ " package libimage-exiftool-perl" -#~ msgstr "" -#~ "exiftool faltando, favor instalar \n" -#~ " pacote libimage-exiftool-perl" - -#~ msgid "follow edge" -#~ msgstr "seguir borda" - -#~ msgid "freehand draw" -#~ msgstr "desenho a mão livre" - -#~ msgid "rename files" -#~ msgstr "renomear arquivos" - -#~ msgid "select files" -#~ msgstr "Selecionar arquivos" - -#~ msgid "select image files to add tags" -#~ msgstr "Selecionar arquivos de imagem para etiquetar" - -#~ msgid "tags index arquivo error: %s" -#~ msgstr "erro no arquivo de índices: %s" - -#~ msgid "use two s only" -#~ msgstr "usar duas imagens apenas" - -#~ msgid "Merge the images together" -#~ msgstr "Mesclar imagens" - -#~ msgid "Auto-search lens mm and bow" -#~ msgstr "Procura automática de mm e curvatura de lente" - -#~ msgid "insert" -#~ msgstr "inserir" - -#~ msgid "add all" -#~ msgstr "adicionar todos" - -#~ msgid "Edit Caption" -#~ msgstr "Editar Legenda" - -#~ msgid "Edit Comments" -#~ msgstr "Editar Comentários" - -#~ msgid "" -#~ "Discard current gallery list? \n" -#~ " %s" -#~ msgstr "" -#~ "Discartar lista de galeria atual? \n" -#~ " %s" diff -Nru fotoxx-11.11.1/locales/pt/zfuncs.po fotoxx-12.01.2/locales/pt/zfuncs.po --- fotoxx-11.11.1/locales/pt/zfuncs.po 2011-11-05 05:30:37.000000000 +0000 +++ fotoxx-12.01.2/locales/pt/zfuncs.po 1970-01-01 00:00:00.000000000 +0000 @@ -1,292 +0,0 @@ -# Portuguese translations for home package. -# Copyright (C) 2010 THE home'S COPYRIGHT HOLDER -# This file is distributed under the same license as the home package. -# mico , 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: home 2\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2011-11-05 05:49+0100\n" -"PO-Revision-Date: 2010-07-01 22:55+0200\n" -"Last-Translator: André Campos Rodovalho \n" -"Language-Team: Portuguese\n" -"Language: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Poedit-Language: Portuguese\n" -"X-Poedit-Country: Brazil\n" - -#: zfuncs.cc:3192 -#, c-format -msgid "help file not found: %s" -msgstr "arquivo de ajuda não encontrado: %s" - -#: zfuncs.cc:3296 -#, c-format -msgid "error: %s" -msgstr "erro: %s" - -#: zfuncs.cc:4415 zfuncs.cc:8771 -#, c-format -msgid "cannot open file %s" -msgstr "não foi possível abrir arquivo %s" - -#: zfuncs.cc:4448 -msgid "save screen to file" -msgstr "salvar tela para arquivo" - -#: zfuncs.cc:6198 -msgid "No" -msgstr "Não" - -#: zfuncs.cc:6198 -msgid "Yes" -msgstr "Sim" - -#: zfuncs.cc:6272 zfuncs.cc:6308 zfuncs.cc:6461 zfuncs.cc:6865 zfuncs.cc:8358 -#: zfuncs.cc:8883 zfuncs.cc:8889 zfuncs.cc:8895 zfuncs.cc:8901 -msgid "cancel" -msgstr "cancelar" - -#: zfuncs.cc:6423 zfuncs.cc:7552 -msgid "open" -msgstr "abrir" - -#: zfuncs.cc:6428 -msgid "choose" -msgstr "escolher" - -#: zfuncs.cc:6433 -msgid "save" -msgstr "salvar" - -#: zfuncs.cc:6439 -msgid "open folder" -msgstr "abrir pasta" - -#: zfuncs.cc:6444 -msgid "create folder" -msgstr "criar pasta" - -#: zfuncs.cc:6450 -msgid "hidden" -msgstr "oculto" - -#: zfuncs.cc:6454 -msgid "quality" -msgstr "qualidade" - -#: zfuncs.cc:6511 -msgid "JPG quality 0-100" -msgstr "Qualidade JPG 0-100" - -#: zfuncs.cc:6865 zfuncs.cc:8358 -msgid "done" -msgstr "pronto" - -#: zfuncs.cc:6865 zfuncs.cc:6878 -msgid "margins" -msgstr "" - -#: zfuncs.cc:6874 -msgid "top" -msgstr "topo" - -#: zfuncs.cc:6875 -msgid "bottom" -msgstr "rodapé" - -#: zfuncs.cc:6876 -msgid "left" -msgstr "esquerda" - -#: zfuncs.cc:6877 -msgid "right" -msgstr "direita" - -#: zfuncs.cc:7278 zfuncs.cc:7532 zfuncs.cc:7670 zfuncs.cc:7671 zfuncs.cc:7673 -msgid "bigger" -msgstr "maior" - -#: zfuncs.cc:7278 -msgid "increase thumbnail size" -msgstr "aumentar tamanho de miniaturas" - -#: zfuncs.cc:7279 -msgid "reduce thumbnail size" -msgstr "reduzir tamanho de miniaturas" - -#: zfuncs.cc:7279 zfuncs.cc:7542 zfuncs.cc:7672 zfuncs.cc:7674 -msgid "smaller" -msgstr "menor" - -#: zfuncs.cc:7280 zfuncs.cc:7571 -msgid "parent" -msgstr "anterior" - -#: zfuncs.cc:7280 -msgid "parent directory" -msgstr "pasta anterior" - -#: zfuncs.cc:7281 zfuncs.cc:7589 zfuncs.cc:7681 -msgid "first page" -msgstr "primeira página" - -#: zfuncs.cc:7281 -msgid "jump to first file" -msgstr "pular para primeiro arquivo" - -#: zfuncs.cc:7282 zfuncs.cc:7587 zfuncs.cc:7676 zfuncs.cc:7683 -msgid "prev page" -msgstr "página ant." - -#: zfuncs.cc:7282 -msgid "previous page" -msgstr "página anterior" - -#: zfuncs.cc:7283 zfuncs.cc:7585 zfuncs.cc:7678 -msgid "prev row" -msgstr "coluna ant." - -#: zfuncs.cc:7283 -msgid "previous row" -msgstr "coluna anterior" - -#: zfuncs.cc:7284 zfuncs.cc:7586 zfuncs.cc:7679 -msgid "next row" -msgstr "próxiuma coluna" - -#: zfuncs.cc:7285 zfuncs.cc:7588 zfuncs.cc:7677 zfuncs.cc:7684 -msgid "next page" -msgstr "próxima página" - -#: zfuncs.cc:7286 -msgid "jump to last file" -msgstr "pular para último arquivo" - -#: zfuncs.cc:7286 zfuncs.cc:7590 zfuncs.cc:7682 -msgid "last page" -msgstr "última página" - -#: zfuncs.cc:7287 zfuncs.cc:7527 -msgid "close" -msgstr "fechar" - -#: zfuncs.cc:7287 -msgid "close image gallery" -msgstr "fechar galeria de imagens" - -#: zfuncs.cc:7558 -msgid "select new file" -msgstr "selecionar novo arquivo" - -#: zfuncs.cc:8358 -msgid "Select Files" -msgstr "Selecionar arquivos" - -#: zfuncs.cc:8366 -msgid "delete" -msgstr "excluir" - -#: zfuncs.cc:8367 -msgid "insert" -msgstr "inserir" - -#: zfuncs.cc:8368 -msgid "add all" -msgstr "Adicionar todos" - -#: zfuncs.cc:8658 -msgid "" -"Initial parameters file created. \n" -"Inspect and revise if necessary." -msgstr "" -"Arquivo de parâmetros iniciais criado. \n" -"Inspecione e revise se necessário." - -#: zfuncs.cc:8674 -msgid "load parameters from a file" -msgstr "carregar parâmetros de arquivo" - -#: zfuncs.cc:8743 -msgid "save parameters to a file" -msgstr "salvar parâmetros para um arquivo" - -#: zfuncs.cc:8881 zfuncs.cc:8887 zfuncs.cc:8893 zfuncs.cc:8899 -msgid "edit parameters" -msgstr "editar parâmetros" - -#: zfuncs.cc:8882 zfuncs.cc:8888 -msgid "" -"list\n" -"all" -msgstr "" -"lista\n" -"todos" - -#: zfuncs.cc:8882 zfuncs.cc:8888 zfuncs.cc:8894 zfuncs.cc:8900 -msgid "" -"load\n" -"file" -msgstr "" -"carregar\n" -"arquivo" - -#: zfuncs.cc:8882 zfuncs.cc:8888 zfuncs.cc:8894 zfuncs.cc:8900 -msgid "" -"save\n" -"file" -msgstr "" -"salvar\n" -"arquivo" - -#: zfuncs.cc:8883 zfuncs.cc:8895 -msgid "" -"add\n" -"new" -msgstr "" -"adicionar\n" -"novo" - -#: zfuncs.cc:8883 zfuncs.cc:8889 zfuncs.cc:8895 zfuncs.cc:8901 -msgid "apply" -msgstr "aplicar" - -#: zfuncs.cc:8935 -msgid "apply?" -msgstr "aplicar?" - -#: zfuncs.cc:8992 -msgid "(new parm name)" -msgstr "(novo nome de parâmetro)" - -#: zfuncs.cc:8992 -msgid "add parameter" -msgstr "adicionar parâmetro" - -#~ msgid "print" -#~ msgstr "imprimir" - -#~ msgid "printer ID" -#~ msgstr "ID de impressora" - -#~ msgid "paper format" -#~ msgstr "formato do papel" - -#~ msgid "portrait" -#~ msgstr "retrato" - -#~ msgid "landscape" -#~ msgstr "paisagem" - -#~ msgid "margins:" -#~ msgstr "margens:" - -#~ msgid "paper format is crazy" -#~ msgstr "formato do papel é louco" - -#~ msgid "open a file" -#~ msgstr "abrir um arquivo" diff -Nru fotoxx-11.11.1/locales/ru/fotoxx.po fotoxx-12.01.2/locales/ru/fotoxx.po --- fotoxx-11.11.1/locales/ru/fotoxx.po 2011-11-05 05:30:37.000000000 +0000 +++ fotoxx-12.01.2/locales/ru/fotoxx.po 1970-01-01 00:00:00.000000000 +0000 @@ -1,2487 +0,0 @@ -# Russian translations for home package. -# Copyright (C) 2010 by Redf -# This file is distributed under the same license as the home package. -# Redf , 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: home 2\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2011-11-05 05:49+0100\n" -"PO-Revision-Date: 2010-05-12 10:15+0200\n" -"Last-Translator: redf \n" -"Language-Team: Russian\n" -"Language: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#: fotoxx-11.11.1.cc:179 -msgid "File" -msgstr "Файл" - -#: fotoxx-11.11.1.cc:180 fotoxx-11.11.1.cc:316 -msgid "Image Gallery" -msgstr "Галерея" - -#: fotoxx-11.11.1.cc:181 -msgid "Clone 50/50" -msgstr "" - -#: fotoxx-11.11.1.cc:182 -msgid "Clone Overlay" -msgstr "" - -#: fotoxx-11.11.1.cc:183 fotoxx-11.11.1.cc:317 fotoxx-11.11.1.cc:2272 -#: fotoxx-11.11.1.cc:2444 -msgid "Open Image File" -msgstr "Открыть" - -#: fotoxx-11.11.1.cc:184 -msgid "Open in New Window" -msgstr "" - -#: fotoxx-11.11.1.cc:185 fotoxx-11.11.1.cc:318 -msgid "Open Previous File" -msgstr "Открыть предыдущий файл" - -#: fotoxx-11.11.1.cc:186 -msgid "Open Recent File" -msgstr "Открыть последний" - -#: fotoxx-11.11.1.cc:187 fotoxx-11.11.1.cc:326 -msgid "Save to Same File" -msgstr "Сохранить" - -#: fotoxx-11.11.1.cc:188 fotoxx-11.11.1.cc:327 -msgid "Save to New Version" -msgstr "" - -#: fotoxx-11.11.1.cc:189 fotoxx-11.11.1.cc:328 -msgid "Save to New File" -msgstr "Сохранить как..." - -#: fotoxx-11.11.1.cc:190 fotoxx-11.11.1.cc:2990 -msgid "Create Blank Image" -msgstr "" - -#: fotoxx-11.11.1.cc:191 -msgid "Trash Image File" -msgstr "Поместить в корзину" - -#: fotoxx-11.11.1.cc:192 fotoxx-11.11.1.cc:3216 -msgid "Rename Image File" -msgstr "Переименовать" - -#: fotoxx-11.11.1.cc:193 -msgid "Batch Rename Files" -msgstr "Групповое переименование" - -#: fotoxx-11.11.1.cc:194 -msgid "Print Image File" -msgstr "Печать" - -#: fotoxx-11.11.1.cc:195 fotoxx-11.11.1.cc:332 -msgid "Quit fotoxx" -msgstr "Выход из fotoxx" - -#: fotoxx-11.11.1.cc:197 -msgid "Tools" -msgstr "Инструменты" - -#: fotoxx-11.11.1.cc:198 fotoxx_tools.cc:70 -msgid "Manage Collections" -msgstr "" - -#: fotoxx-11.11.1.cc:199 fotoxx_tools.cc:373 -msgid "Move Collections" -msgstr "" - -#: fotoxx-11.11.1.cc:200 -msgid "Check Monitor" -msgstr "Отображение цветов" - -#: fotoxx-11.11.1.cc:201 fotoxx_tools.cc:550 -msgid "Monitor Gamma" -msgstr "" - -#: fotoxx-11.11.1.cc:202 -msgid "Brightness Graph" -msgstr "Диаграмма яркости" - -#: fotoxx-11.11.1.cc:203 fotoxx_tools.cc:819 -msgid "Slide Show" -msgstr "Слайд-шоу" - -#: fotoxx-11.11.1.cc:204 fotoxx_tools.cc:1668 -msgid "Show RGB" -msgstr "Показать RGB" - -#: fotoxx-11.11.1.cc:205 fotoxx_tools.cc:1962 -msgid "Grid Lines" -msgstr "Сетка" - -#: fotoxx-11.11.1.cc:206 fotoxx_tools.cc:2135 -msgid "Lens Parameters" -msgstr "Параметры объектива" - -#: fotoxx-11.11.1.cc:207 -msgid "Change Language" -msgstr "Изменить язык" - -#: fotoxx-11.11.1.cc:209 -msgid "Add Menu and Launcher" -msgstr "" - -#: fotoxx-11.11.1.cc:210 -msgid "Convert RAW files" -msgstr "Конвертировать RAW-файлы" - -#: fotoxx-11.11.1.cc:211 -msgid "Burn Images to CD/DVD" -msgstr "Записать на CD/DVD" - -#: fotoxx-11.11.1.cc:212 fotoxx_tools.cc:2460 -msgid "E-mail Images" -msgstr "" - -#: fotoxx-11.11.1.cc:213 fotoxx_tools.cc:2783 -msgid "Synchronize Files" -msgstr "" - -#: fotoxx-11.11.1.cc:214 fotoxx_tools.cc:3376 -msgid "Toolbar Style" -msgstr "" - -#: fotoxx-11.11.1.cc:215 -msgid "Memory Usage" -msgstr "" - -#: fotoxx-11.11.1.cc:218 -msgid "Edit Caption/Comments" -msgstr "" - -#: fotoxx-11.11.1.cc:219 fotoxx_info.cc:156 -msgid "Edit Tags" -msgstr "Редактировать теги" - -#: fotoxx-11.11.1.cc:220 fotoxx_info.cc:345 -msgid "Manage Tags" -msgstr "" - -#: fotoxx-11.11.1.cc:221 fotoxx_info.cc:1345 -msgid "Batch Add Tags" -msgstr "Групповое добавление тегов" - -#: fotoxx-11.11.1.cc:222 fotoxx_info.cc:1547 -msgid "Batch Delete Tag" -msgstr "" - -#: fotoxx-11.11.1.cc:223 -msgid "View Info (short)" -msgstr "" - -#: fotoxx-11.11.1.cc:224 -msgid "View Info (long)" -msgstr "" - -#: fotoxx-11.11.1.cc:225 fotoxx_info.cc:1883 -msgid "Edit Info" -msgstr "" - -#: fotoxx-11.11.1.cc:226 fotoxx_info.cc:1981 -msgid "Delete Info" -msgstr "" - -#: fotoxx-11.11.1.cc:227 -msgid "Search Images" -msgstr "" - -#: fotoxx-11.11.1.cc:229 fotoxx-11.11.1.cc:230 -msgid "Select" -msgstr "Выбрать" - -#: fotoxx-11.11.1.cc:231 -msgid "Show" -msgstr "Показать" - -#: fotoxx-11.11.1.cc:232 -msgid "Hide" -msgstr "Скрыть" - -#: fotoxx-11.11.1.cc:233 -msgid "Enable" -msgstr "Доступно" - -#: fotoxx-11.11.1.cc:234 -msgid "Disable" -msgstr "Не доступно" - -#: fotoxx-11.11.1.cc:235 -msgid "Invert" -msgstr "Инвертировать" - -#: fotoxx-11.11.1.cc:236 -msgid "Unselect" -msgstr "" - -#: fotoxx-11.11.1.cc:237 -msgid "Copy" -msgstr "Копировать" - -#: fotoxx-11.11.1.cc:238 -msgid "Paste" -msgstr "Вставить" - -#: fotoxx-11.11.1.cc:239 fotoxx-11.11.1.cc:317 fotoxx_retouch.cc:2314 -#: fotoxx_retouch.cc:2319 -msgid "Open" -msgstr "Открыть" - -#: fotoxx-11.11.1.cc:240 fotoxx-11.11.1.cc:326 -msgid "Save" -msgstr "Сохранить" - -#: fotoxx-11.11.1.cc:241 fotoxx_area.cc:2215 -msgid "Select Whole Image" -msgstr "" - -#: fotoxx-11.11.1.cc:242 -msgid "Select and Edit" -msgstr "" - -#: fotoxx-11.11.1.cc:244 -msgid "Transform" -msgstr "Изменить" - -#: fotoxx-11.11.1.cc:245 fotoxx_transform.cc:60 -msgid "Rotate Image" -msgstr "Повернуть изображение" - -#: fotoxx-11.11.1.cc:246 fotoxx_transform.cc:346 -msgid "Trim Image" -msgstr "Кадрировать" - -#: fotoxx-11.11.1.cc:247 fotoxx_transform.cc:972 -msgid "Resize Image" -msgstr "Изменить размер изображения" - -#: fotoxx-11.11.1.cc:248 -msgid "Batch Resize/Export" -msgstr "" - -#: fotoxx-11.11.1.cc:249 fotoxx_transform.cc:1436 -msgid "Annotate Image" -msgstr "" - -#: fotoxx-11.11.1.cc:250 fotoxx_transform.cc:2193 -msgid "Flip Image" -msgstr "Зеркальное изображение" - -#: fotoxx-11.11.1.cc:251 fotoxx_transform.cc:2303 -msgid "Make Negative" -msgstr "" - -#: fotoxx-11.11.1.cc:252 fotoxx_transform.cc:2420 -msgid "Unbend Image" -msgstr "Изогнуть" - -#: fotoxx-11.11.1.cc:253 fotoxx_transform.cc:2704 -msgid "Keystone Correction" -msgstr "" - -#: fotoxx-11.11.1.cc:254 fotoxx_transform.cc:3013 -msgid "Warp Image (area)" -msgstr "" - -#: fotoxx-11.11.1.cc:255 fotoxx_transform.cc:3255 -msgid "Warp Image (curved)" -msgstr "" - -#: fotoxx-11.11.1.cc:256 fotoxx_transform.cc:3518 -msgid "Warp Image (linear)" -msgstr "" - -#: fotoxx-11.11.1.cc:257 fotoxx_transform.cc:3782 -msgid "Warp Image (affine)" -msgstr "Корректировать перспективу (affine)" - -#: fotoxx-11.11.1.cc:259 -msgid "Retouch" -msgstr "Ретушировать" - -#: fotoxx-11.11.1.cc:260 -msgid "Brightness/Color" -msgstr "Яркость и цветность" - -#: fotoxx-11.11.1.cc:261 -msgid "Gamma Curves" -msgstr "" - -#: fotoxx-11.11.1.cc:262 -msgid "Expand Brightness" -msgstr "Расширение яркости" - -#: fotoxx-11.11.1.cc:263 -msgid "Flatten Brightness" -msgstr "Выравнять яркость" - -#: fotoxx-11.11.1.cc:264 -msgid "Brightness Ramp" -msgstr "Распределение яркости" - -#: fotoxx-11.11.1.cc:265 fotoxx_retouch.cc:1729 -msgid "Tone Mapping" -msgstr "Тональное отображение" - -#: fotoxx-11.11.1.cc:266 -msgid "White Balance" -msgstr "Баланс белого" - -#: fotoxx-11.11.1.cc:267 -msgid "Match Colors" -msgstr "" - -#: fotoxx-11.11.1.cc:269 fotoxx_retouch.cc:2941 -msgid "Revise RGB" -msgstr "" - -#: fotoxx-11.11.1.cc:270 -msgid "Red Eyes" -msgstr "Эффект красных глаза" - -#: fotoxx-11.11.1.cc:271 -msgid "Blur Image" -msgstr "Размыть" - -#: fotoxx-11.11.1.cc:272 fotoxx_retouch.cc:4077 -msgid "Sharpen Image" -msgstr "Увеличить резкость" - -#: fotoxx-11.11.1.cc:273 -msgid "Reduce Noise" -msgstr "Уменьшить шум" - -#: fotoxx-11.11.1.cc:274 fotoxx_retouch.cc:4881 -msgid "Smart Erase" -msgstr "" - -#: fotoxx-11.11.1.cc:275 fotoxx_retouch.cc:5271 -msgid "Remove Dust" -msgstr "" - -#: fotoxx-11.11.1.cc:276 fotoxx_retouch.cc:5877 -msgid "Edit Pixels" -msgstr "Редактировать изображение" - -#: fotoxx-11.11.1.cc:278 -msgid "Art" -msgstr "Эффекты" - -#: fotoxx-11.11.1.cc:279 -msgid "Color Depth" -msgstr "Глубина цвета" - -#: fotoxx-11.11.1.cc:280 -msgid "Drawing" -msgstr "" - -#: fotoxx-11.11.1.cc:281 -msgid "Outlines" -msgstr "" - -#: fotoxx-11.11.1.cc:282 -msgid "Embossing" -msgstr "" - -#: fotoxx-11.11.1.cc:283 -msgid "Tiles" -msgstr "" - -#: fotoxx-11.11.1.cc:284 -msgid "Dots" -msgstr "" - -#: fotoxx-11.11.1.cc:285 -msgid "Painting" -msgstr "" - -#: fotoxx-11.11.1.cc:287 -msgid "Combine" -msgstr "Комбинировать" - -#: fotoxx-11.11.1.cc:288 -msgid "High Dynamic Range" -msgstr "" - -#: fotoxx-11.11.1.cc:289 -msgid "High Depth of Field" -msgstr "" - -#: fotoxx-11.11.1.cc:290 -msgid "Stack / Paint" -msgstr "" - -#: fotoxx-11.11.1.cc:291 -msgid "Stack / Noise" -msgstr "" - -#: fotoxx-11.11.1.cc:292 -msgid "Panorama" -msgstr "Панорама" - -#: fotoxx-11.11.1.cc:293 -msgid "Vertical Panorama" -msgstr "" - -#: fotoxx-11.11.1.cc:296 -msgid "Edit Plugins" -msgstr "" - -#: fotoxx-11.11.1.cc:305 fotoxx-11.11.1.cc:333 fotoxx-11.11.1.cc:4616 -msgid "Help" -msgstr "Помощь" - -#: fotoxx-11.11.1.cc:306 fotoxx-11.11.1.cc:4606 -msgid "About" -msgstr "О fotoxx" - -#: fotoxx-11.11.1.cc:307 fotoxx-11.11.1.cc:4610 -msgid "User Guide" -msgstr "Руководство пользователя" - -#: fotoxx-11.11.1.cc:308 fotoxx-11.11.1.cc:4613 -msgid "User Guide Changes" -msgstr "" - -#: fotoxx-11.11.1.cc:309 fotoxx-11.11.1.cc:4622 -msgid "Edit Functions Summary" -msgstr "" - -#: fotoxx-11.11.1.cc:310 fotoxx-11.11.1.cc:4625 -msgid "Change Log" -msgstr "Журнал изменений" - -#: fotoxx-11.11.1.cc:311 fotoxx-11.11.1.cc:4628 -msgid "Translations" -msgstr "" - -#: fotoxx-11.11.1.cc:312 fotoxx-11.11.1.cc:4631 -msgid "Home Page" -msgstr "Домашняя страница" - -#: fotoxx-11.11.1.cc:316 -msgid "Gallery" -msgstr "Галерея" - -#: fotoxx-11.11.1.cc:318 fotoxx_transform.cc:995 -msgid "Prev" -msgstr "Предыдущий" - -#: fotoxx-11.11.1.cc:319 -msgid "Next" -msgstr "Дальше" - -#: fotoxx-11.11.1.cc:319 -msgid "Open Next File" -msgstr "Открыть следующий файл" - -#: fotoxx-11.11.1.cc:320 -msgid "Zoom-in (bigger)" -msgstr "Увеличить" - -#: fotoxx-11.11.1.cc:321 -msgid "Zoom-out (smaller)" -msgstr "Уменьшить" - -#: fotoxx-11.11.1.cc:322 -msgid "Undo" -msgstr "Отменить" - -#: fotoxx-11.11.1.cc:322 -msgid "Undo One Edit" -msgstr "Отменить" - -#: fotoxx-11.11.1.cc:323 -msgid "Redo" -msgstr "Применить" - -#: fotoxx-11.11.1.cc:323 -msgid "Redo One Edit" -msgstr "Применить отмененное" - -#: fotoxx-11.11.1.cc:327 -msgid "Save+V" -msgstr "" - -#: fotoxx-11.11.1.cc:328 -msgid "Save+F" -msgstr "" - -#: fotoxx-11.11.1.cc:329 -msgid "Move Image to Trash" -msgstr "Переместить изображение в корзину" - -#: fotoxx-11.11.1.cc:329 -msgid "Trash" -msgstr "Мусор" - -#: fotoxx-11.11.1.cc:332 -msgid "Quit" -msgstr "Выход" - -#: fotoxx-11.11.1.cc:333 -msgid "Fotoxx Essentials" -msgstr "" - -#: fotoxx-11.11.1.cc:429 -msgid "first time startup" -msgstr "" - -#: fotoxx-11.11.1.cc:1815 -msgid "Exceed 50 anchor points" -msgstr "Требуется более 50 точек" - -#: fotoxx-11.11.1.cc:2000 -msgid "load curve from a file" -msgstr "" - -#: fotoxx-11.11.1.cc:2053 -msgid "curve file is invalid" -msgstr "" - -#: fotoxx-11.11.1.cc:2058 -msgid "curve file has different no. of curves" -msgstr "" - -#: fotoxx-11.11.1.cc:2073 -msgid "save curve to a file" -msgstr "" - -#: fotoxx-11.11.1.cc:2420 -#, c-format -msgid "" -"Discard special gallery list? \n" -" %s" -msgstr "" - -#: fotoxx-11.11.1.cc:2430 fotoxx-11.11.1.cc:4452 -msgid "prior function still active" -msgstr "" - -#: fotoxx-11.11.1.cc:2607 -msgid "Overwrite original file?" -msgstr "" - -#: fotoxx-11.11.1.cc:2608 -msgid "Do not warn again" -msgstr "" - -#: fotoxx-11.11.1.cc:2624 -msgid "Warning" -msgstr "" - -#: fotoxx-11.11.1.cc:2747 -msgid "Save File" -msgstr "Сохранить в файл" - -#: fotoxx-11.11.1.cc:2770 -msgid "quality" -msgstr "" - -#: fotoxx-11.11.1.cc:2772 -msgid "make current" -msgstr "" - -#: fotoxx-11.11.1.cc:2829 -msgid "jpeg quality must be 1-100" -msgstr "Качество jpeg должно быть от 1 до 100" - -#: fotoxx-11.11.1.cc:2851 -#, c-format -msgid "" -"Overwrite file? \n" -" %s" -msgstr "" -"Переписать файл? \n" -" %s" - -#: fotoxx-11.11.1.cc:2992 -msgid "file name" -msgstr "" - -#: fotoxx-11.11.1.cc:2997 fotoxx_transform.cc:351 -msgid "width" -msgstr "" - -#: fotoxx-11.11.1.cc:3000 fotoxx_transform.cc:354 -msgid "height" -msgstr "" - -#: fotoxx-11.11.1.cc:3006 fotoxx_art.cc:628 fotoxx_retouch.cc:5881 -msgid "color" -msgstr "Цвет" - -#: fotoxx-11.11.1.cc:3120 -msgid "" -"Linux standard trash is not supported. \n" -"Desktop trash folder will be created." -msgstr "" - -#: fotoxx-11.11.1.cc:3138 -msgid "Move read-only file to trash?" -msgstr "Переместить изображение в корзину?" - -#: fotoxx-11.11.1.cc:3164 -#, c-format -msgid "Cannot create trash folder: %s" -msgstr "Не могу создать папку: %s" - -#: fotoxx-11.11.1.cc:3172 fotoxx-11.11.1.cc:3178 -#, c-format -msgid "error: %s" -msgstr "Ошибка: %s" - -#: fotoxx-11.11.1.cc:3221 -msgid "old name" -msgstr "Старое имя" - -#: fotoxx-11.11.1.cc:3222 -msgid "rename to" -msgstr "Переименовать в" - -#: fotoxx-11.11.1.cc:3223 -msgid "previous" -msgstr "Предыдущий" - -#: fotoxx-11.11.1.cc:3309 -msgid "The target file already exists" -msgstr "Такой файл уже открыт" - -#: fotoxx-11.11.1.cc:3317 -#, c-format -msgid "" -"Rename failed: \n" -" %s" -msgstr "" - -#: fotoxx-11.11.1.cc:3365 -msgid "Batch Rename" -msgstr "Групповое переименование" - -#: fotoxx-11.11.1.cc:3368 fotoxx-11.11.1.cc:3420 fotoxx_info.cc:1513 -#: fotoxx_info.cc:1767 fotoxx_tools.cc:2510 fotoxx_transform.cc:1213 -#, c-format -msgid "%d files selected" -msgstr "" - -#: fotoxx-11.11.1.cc:3370 -msgid "new base name" -msgstr "Префикс" - -#: fotoxx-11.11.1.cc:3373 -msgid "starting sequence" -msgstr "Начальный номер" - -#: fotoxx-11.11.1.cc:3375 -msgid "increment" -msgstr "Дополнительный номер" - -#: fotoxx-11.11.1.cc:3396 -msgid "select files to rename" -msgstr "Выберите файлы для переименования" - -#: fotoxx-11.11.1.cc:3401 -msgid "base name / sequence / increment not reasonable" -msgstr " Неправильный префикс / начальный номер / дополнительный номер" - -#: fotoxx-11.11.1.cc:3460 -msgid "new file already exists:" -msgstr "Новый файл уже открыт:" - -#: fotoxx-11.11.1.cc:3468 -msgid "filespec too long:" -msgstr "Имя файла слишком длинное:" - -#: fotoxx-11.11.1.cc:3479 -msgid "Rename failed:" -msgstr "Переименование остановлено:" - -#: fotoxx-11.11.1.cc:3739 -msgid "Add" -msgstr "" - -#: fotoxx-11.11.1.cc:3739 -msgid "Remove" -msgstr "" - -#: fotoxx-11.11.1.cc:3741 -msgid "menu name" -msgstr "" - -#: fotoxx-11.11.1.cc:3812 fotoxx-11.11.1.cc:3833 -msgid "Restart Fotoxx to update plugin menu" -msgstr "" - -#: fotoxx-11.11.1.cc:3927 -msgid "cannot parallel edit" -msgstr "" - -#: fotoxx-11.11.1.cc:3937 -msgid "" -"exiftool is not installed \n" -"edited images will lose EXIF data" -msgstr "" -"EXIFtool не установлен \n" -"будут потеряны данные EXIF" - -#: fotoxx-11.11.1.cc:3943 -msgid "Too many edits, please save image" -msgstr "Слишком много изменений, пожалуйста сограните изображение" - -#: fotoxx-11.11.1.cc:3948 -msgid "" -"Select area cannot be kept.\n" -"Continue?" -msgstr "" -"Выбранная область не сохранена.\n" -"Продолжить?" - -#: fotoxx-11.11.1.cc:3956 -msgid "" -"Select area not active.\n" -"Continue?" -msgstr "" -"Выбранная область не активна.\n" -"Продолжить?" - -#: fotoxx-11.11.1.cc:4427 -msgid "Discard edits?" -msgstr "" - -#: fotoxx-11.11.1.cc:4428 -msgid "" -"This action will discard current edits.\n" -"Continue to discard edits.\n" -"Go Back to keep edits." -msgstr "" - -#: fotoxx-11.11.1.cc:4431 -msgid "Continue" -msgstr "" - -#: fotoxx-11.11.1.cc:4432 -msgid "Go Back" -msgstr "" - -#: fotoxx-11.11.1.cc:5240 -msgid "cannot open thumbnail file" -msgstr "не могу найти файл" - -#: fotoxx-11.11.1.cc:5433 fotoxx-11.11.1.cc:5549 -msgid "TIFF open failure" -msgstr "TIFF ошибка открытия" - -#: fotoxx-11.11.1.cc:5449 -#, c-format -msgid "TIFF bits/color=%d not supported" -msgstr "" - -#: fotoxx-11.11.1.cc:5464 fotoxx-11.11.1.cc:5502 -msgid "TIFF read failure" -msgstr "TIFF ошибка чтения" - -#: fotoxx-11.11.1.cc:5608 -msgid "TIFF write failure" -msgstr "TIFF ошибка записи" - -#: fotoxx-11.11.1.cc:5638 -msgid "file type not supported" -msgstr "Этот формат файлов не поддерживается" - -#: fotoxx-11.11.1.cc:5745 -msgid "pixbuf write failure" -msgstr "Pixbuf - ошибка записи" - -#: fotoxx_area.cc:54 fotoxx_area.cc:2427 -msgid "Select Area for Edits" -msgstr "Выбрать область для редактирования" - -#: fotoxx_area.cc:55 fotoxx_area.cc:2428 -msgid "Press F1 for help" -msgstr "" - -#: fotoxx_area.cc:63 -msgid "" -"Select Area not supported \n" -"by this edit function" -msgstr "" - -#: fotoxx_area.cc:99 fotoxx_tools.cc:809 -msgid "rectangle" -msgstr "" - -#: fotoxx_area.cc:100 fotoxx_tools.cc:810 -msgid "ellipse" -msgstr "" - -#: fotoxx_area.cc:101 -msgid "draw: freehand" -msgstr "" - -#: fotoxx_area.cc:102 -msgid "draw: follow edge" -msgstr "" - -#: fotoxx_area.cc:103 -msgid "select by mouse" -msgstr "" - -#: fotoxx_area.cc:104 -msgid "select by color" -msgstr "" - -#: fotoxx_area.cc:112 -msgid "radius" -msgstr "Радиус" - -#: fotoxx_area.cc:116 -msgid "match" -msgstr "" - -#: fotoxx_area.cc:121 -msgid "firewall" -msgstr "" - -#: fotoxx_area.cc:274 fotoxx_area.cc:415 -#, c-format -msgid "exceed %d edits" -msgstr "%d превышений редактирования" - -#: fotoxx_area.cc:992 -msgid "" -"Click one time inside each enclosed area \n" -"(possible gaps in the outline will be found). \n" -"Press F1 for help." -msgstr "" - -#: fotoxx_area.cc:1049 -msgid "finish area" -msgstr "Конечная область" - -#: fotoxx_area.cc:1083 -msgid "searching" -msgstr "Поиск" - -#: fotoxx_area.cc:1155 -msgid "outline has a gap" -msgstr "" - -#: fotoxx_area.cc:1157 -msgid "success" -msgstr "Готово" - -#: fotoxx_area.cc:1401 fotoxx_area.cc:1430 -msgid "the area is not finished" -msgstr "Область не выбрана" - -#: fotoxx_area.cc:1522 -msgid "Edge calculation in progress" -msgstr "Вычисляем..." - -#: fotoxx_area.cc:1531 -msgid "Area Edge Calc" -msgstr "Расчет области" - -#: fotoxx_area.cc:1824 -msgid "position with mouse click/drag" -msgstr "" - -#: fotoxx_area.cc:1848 -msgid "Paste Image" -msgstr "Вставить изображение" - -#: fotoxx_area.cc:1863 -msgid "angle" -msgstr "" - -#: fotoxx_area.cc:2127 -msgid "load select area from a file" -msgstr "Загрузить выбранную область из файла" - -#: fotoxx_area.cc:2161 -msgid "cannot open .tiff and .info files" -msgstr "" - -#: fotoxx_area.cc:2180 -msgid "save select area to a file" -msgstr "" - -#: fotoxx_area.cc:2216 -msgid "Edit Function Amplifier" -msgstr "" - -#: fotoxx_area.cc:2459 -msgid "mouse radius" -msgstr "" - -#: fotoxx_area.cc:2462 -msgid "power: center" -msgstr "" - -#: fotoxx_area.cc:2464 -msgid "edge" -msgstr "" - -#: fotoxx_area.cc:2468 -msgid "reset area" -msgstr "" - -#: fotoxx_area.cc:2523 -msgid "start edit function first" -msgstr "" - -#: fotoxx_art.cc:47 -msgid "Set color depth to 1-16 bits" -msgstr " Установить глубину цвета в диапазоне от 1 до 16 бит " - -#: fotoxx_art.cc:57 -msgid "Set Color Depth" -msgstr "Установка глубины цвета" - -#: fotoxx_art.cc:171 -msgid "Simulate Drawing" -msgstr "Имитировать рисунок" - -#: fotoxx_art.cc:213 fotoxx_retouch.cc:1758 -msgid "contrast" -msgstr " Контраст" - -#: fotoxx_art.cc:215 -msgid "outlines" -msgstr "Контур" - -#: fotoxx_art.cc:220 -msgid "pencil" -msgstr "Карандаш" - -#: fotoxx_art.cc:221 -msgid "chalk" -msgstr "Мелок" - -#: fotoxx_art.cc:381 -msgid "Add Image Outlines" -msgstr "" - -#: fotoxx_art.cc:394 -msgid "outline threshold" -msgstr "" - -#: fotoxx_art.cc:397 -msgid "outline width" -msgstr "" - -#: fotoxx_art.cc:400 -msgid "image brightness" -msgstr "" - -#: fotoxx_art.cc:611 -msgid "Simulate Embossing" -msgstr "Имитировать чеканку" - -#: fotoxx_art.cc:626 -msgid "depth" -msgstr "Глубина" - -#: fotoxx_art.cc:821 -msgid "Simulate Tiles" -msgstr "Имитировать мозаику" - -#: fotoxx_art.cc:825 -msgid "tile size" -msgstr "Размер элементов" - -#: fotoxx_art.cc:829 -msgid "tile gap" -msgstr "Промежутки" - -#: fotoxx_art.cc:1003 -msgid "Convert Image to Dots" -msgstr "" - -#: fotoxx_art.cc:1007 -msgid "dot size" -msgstr "" - -#: fotoxx_art.cc:1222 -msgid "Simulate Painting" -msgstr "Имитировать живопись" - -#: fotoxx_art.cc:1226 -msgid "color depth" -msgstr "Глубина цвета" - -#: fotoxx_art.cc:1230 -msgid "patch area goal" -msgstr "" - -#: fotoxx_art.cc:1234 -msgid "req. color match" -msgstr "Цвета" - -#: fotoxx_art.cc:1238 -msgid "borders" -msgstr " Рамки" - -#: fotoxx_comp.cc:1956 fotoxx_comp.cc:1961 fotoxx_comp.cc:2582 -#: fotoxx_comp.cc:2587 fotoxx_comp.cc:3275 fotoxx_comp.cc:3280 -#: fotoxx_comp.cc:3830 fotoxx_comp.cc:3835 -msgid "Select 2 to 9 files" -msgstr "" - -#: fotoxx_comp.cc:1982 fotoxx_comp.cc:2608 fotoxx_comp.cc:3301 -#: fotoxx_comp.cc:3856 -msgid "Images are not all the same size" -msgstr "Bilder sind nicht gleich gross" - -#: fotoxx_comp.cc:2321 -msgid "Adjust Image Contributions" -msgstr "Коррекция изображения" - -#: fotoxx_comp.cc:2324 fotoxx_retouch.cc:885 -msgid "dark pixels" -msgstr "Темные пиксели" - -#: fotoxx_comp.cc:2326 -msgid "light pixels" -msgstr "Светлые пикселы" - -#: fotoxx_comp.cc:2328 fotoxx_info.cc:159 -msgid "file:" -msgstr "Файл:" - -#: fotoxx_comp.cc:2844 -msgid "Paint and Warp Image" -msgstr "" - -#: fotoxx_comp.cc:2847 fotoxx_comp.cc:3529 fotoxx_comp.cc:4972 -#: fotoxx_comp.cc:5717 -msgid "image" -msgstr "" - -#: fotoxx_comp.cc:2851 fotoxx_retouch.cc:5885 -msgid "paint" -msgstr "Рисовать" - -#: fotoxx_comp.cc:2852 -msgid "warp" -msgstr "" - -#: fotoxx_comp.cc:3527 -msgid "Select and Paint Image" -msgstr "" - -#: fotoxx_comp.cc:4045 -msgid "Adjust Pixel Composition" -msgstr "" - -#: fotoxx_comp.cc:4297 fotoxx_comp.cc:4302 fotoxx_comp.cc:5186 -#: fotoxx_comp.cc:5191 -msgid "Select 2 to 4 files" -msgstr "" - -#: fotoxx_comp.cc:4374 -msgid "" -"Drag images into rough alignment.\n" -"To rotate, drag from lower edge." -msgstr "" - -#: fotoxx_comp.cc:4376 -msgid "Search for lens mm and bow" -msgstr "" - -#: fotoxx_comp.cc:4422 fotoxx_comp.cc:5310 -msgid "Pre-align Images" -msgstr "Предварительно выравненные" - -#: fotoxx_comp.cc:4426 fotoxx_comp.cc:5314 fotoxx_tools.cc:2151 -msgid "lens mm" -msgstr "Фокусное расстояние, мм" - -#: fotoxx_comp.cc:4430 fotoxx_comp.cc:5318 fotoxx_tools.cc:2156 -msgid "lens bow" -msgstr "Lens bow" - -#: fotoxx_comp.cc:4432 fotoxx_comp.cc:5320 -msgid "Resize" -msgstr "" - -#: fotoxx_comp.cc:4433 fotoxx_comp.cc:5321 -msgid "resize window" -msgstr "" - -#: fotoxx_comp.cc:4470 -msgid "use two images only" -msgstr "" - -#: fotoxx_comp.cc:4491 fotoxx_comp.cc:4689 fotoxx_comp.cc:4888 -#: fotoxx_comp.cc:5369 fotoxx_comp.cc:5632 -msgid "Too little overlap, cannot align" -msgstr "Слишком маленькое наложение, выравнять не возможно" - -#: fotoxx_comp.cc:4963 fotoxx_comp.cc:5708 -msgid "Match Brightness and Color" -msgstr "" - -#: fotoxx_comp.cc:4987 fotoxx_comp.cc:5732 -msgid "auto color" -msgstr "" - -#: fotoxx_comp.cc:4988 fotoxx_comp.cc:5733 -msgid "file color" -msgstr "" - -#: fotoxx_comp.cc:5263 -msgid "" -"Drag images into rough alignment.\n" -"To rotate, drag from right edge." -msgstr "" - -#: fotoxx_info.cc:70 -msgid "Edit Caption and Comments" -msgstr "" - -#: fotoxx_info.cc:163 -msgid "image date (yyyymmdd)" -msgstr "Дата (ггггммдд)" - -#: fotoxx_info.cc:165 -msgid "use last" -msgstr "Использовать последний" - -#: fotoxx_info.cc:168 -msgid "image stars" -msgstr "Рейтинг" - -#: fotoxx_info.cc:186 -msgid "current tags" -msgstr "Текущий тег" - -#: fotoxx_info.cc:191 -msgid "recent tags" -msgstr "" - -#: fotoxx_info.cc:196 fotoxx_info.cc:358 fotoxx_info.cc:1362 -#: fotoxx_info.cc:2290 -msgid "defined tags" -msgstr "" - -#: fotoxx_info.cc:348 -msgid "category" -msgstr "" - -#: fotoxx_info.cc:351 -msgid "tag" -msgstr "" - -#: fotoxx_info.cc:354 -msgid "create" -msgstr "" - -#: fotoxx_info.cc:355 -msgid "delete" -msgstr "" - -#: fotoxx_info.cc:1229 fotoxx_info.cc:1313 -#, c-format -msgid "search index file error: %s" -msgstr "" - -#: fotoxx_info.cc:1348 -msgid "tags to add" -msgstr "Теги для добавления" - -#: fotoxx_info.cc:1353 -msgid "create tag" -msgstr "Создать тег" - -#: fotoxx_info.cc:1409 fotoxx_info.cc:1602 -#, c-format -msgid "" -"%s \n" -" too many tags" -msgstr "" - -#: fotoxx_info.cc:1550 -msgid "tag to remove" -msgstr "" - -#: fotoxx_info.cc:1554 -msgid "optional replacement" -msgstr "" - -#: fotoxx_info.cc:1559 fotoxx_tools.cc:2463 -msgid "0 files selected" -msgstr "" - -#: fotoxx_info.cc:1562 -msgid "search all files" -msgstr "" - -#: fotoxx_info.cc:1647 -msgid "no files selected" -msgstr "" - -#: fotoxx_info.cc:1653 -msgid "no tag specified" -msgstr "" - -#: fotoxx_info.cc:1677 fotoxx_info.cc:1706 -msgid "specify tag" -msgstr "" - -#: fotoxx_info.cc:1815 -msgid "View Info" -msgstr "" - -#: fotoxx_info.cc:1983 -msgid "All" -msgstr "Все" - -#: fotoxx_info.cc:1984 -msgid "One Key:" -msgstr "Один Key:" - -#: fotoxx_info.cc:2249 -msgid "Search Tags, Comments, File Names" -msgstr "" - -#: fotoxx_info.cc:2255 -msgid "date range" -msgstr "Диапазон дат" - -#: fotoxx_info.cc:2256 -msgid "stars range" -msgstr "Рейтинг" - -#: fotoxx_info.cc:2257 -msgid "search tags" -msgstr "Поиск тегов" - -#: fotoxx_info.cc:2258 -msgid "search text" -msgstr "" - -#: fotoxx_info.cc:2259 -msgid "file names" -msgstr "" - -#: fotoxx_info.cc:2264 -msgid "(yyyymmdd)" -msgstr "" - -#: fotoxx_info.cc:2270 -msgid "all/any" -msgstr "" - -#: fotoxx_info.cc:2598 -msgid "No matching images found" -msgstr "Нет ссответствующих изображений" - -#: fotoxx_info.cc:2611 -msgid "No search index file present" -msgstr "" - -#: fotoxx_info.cc:2615 -#, c-format -msgid "Search results file error %s" -msgstr "Поиск ошибок %s" - -#: fotoxx_retouch.cc:55 -msgid "Adjust Brightness and Color" -msgstr "Яркость и цветность" - -#: fotoxx_retouch.cc:109 -msgid "small-steps" -msgstr "" - -#: fotoxx_retouch.cc:118 -msgid "color saturation" -msgstr "Цветовая насыщенность" - -#: fotoxx_retouch.cc:125 -msgid " reset 1 " -msgstr "Сбросить один" - -#: fotoxx_retouch.cc:126 -msgid "reset all" -msgstr "Сбросить все" - -#: fotoxx_retouch.cc:598 -msgid "adjust image gamma" -msgstr "" - -#: fotoxx_retouch.cc:884 -msgid "Expand Brightness Range" -msgstr "Расширение яркости" - -#: fotoxx_retouch.cc:886 -msgid "bright pixels" -msgstr "Яркие пиксели" - -#: fotoxx_retouch.cc:1057 -msgid "Flatten Brightness Distribution" -msgstr "Выравнять яркость" - -#: fotoxx_retouch.cc:1071 -msgid "Flatten" -msgstr "Выравнивание" - -#: fotoxx_retouch.cc:1333 -msgid "Ramp brightness across image" -msgstr "Распределение яркости вокруг изображения" - -#: fotoxx_retouch.cc:1757 -msgid "low" -msgstr "" - -#: fotoxx_retouch.cc:1759 -msgid "high" -msgstr "" - -#: fotoxx_retouch.cc:1762 -msgid "Amplify" -msgstr "" - -#: fotoxx_retouch.cc:2068 -msgid "Adjust White Balance" -msgstr "Баланс белого" - -#: fotoxx_retouch.cc:2069 -msgid "Click white or gray image location" -msgstr "Кликните по белому или серому" - -#: fotoxx_retouch.cc:2283 -msgid "Color Match Images" -msgstr "" - -#: fotoxx_retouch.cc:2312 -msgid "mouse radius for color sample" -msgstr "" - -#: fotoxx_retouch.cc:2315 -msgid "image for source color" -msgstr "" - -#: fotoxx_retouch.cc:2317 -msgid "click on image to get source color" -msgstr "" - -#: fotoxx_retouch.cc:2320 -msgid "image to set matching color" -msgstr "" - -#: fotoxx_retouch.cc:2322 -msgid "click on image to set matching color" -msgstr "" - -#: fotoxx_retouch.cc:2377 -msgid "select source image color first" -msgstr "" - -#: fotoxx_retouch.cc:2903 fotoxx_tools.cc:1643 -msgid "Click image to select pixels." -msgstr "" - -#: fotoxx_retouch.cc:2955 -msgid "Metric:" -msgstr "" - -#: fotoxx_retouch.cc:3010 -msgid "Blend" -msgstr "" - -#: fotoxx_retouch.cc:3394 -msgid "" -"Method 1:\n" -" Left-click on red-eye to darken.\n" -"Method 2:\n" -" Drag down and right to enclose red-eye.\n" -" Left-click on red-eye to darken.\n" -"Undo red-eye:\n" -" Right-click on red-eye." -msgstr "" -" Метод 1:\n" -" Кликните левой кнопкой мышки на красных глазах.\n" -" Метод 2:\n" -" Протащите курсор вниз-вправо.\n" -" Кликните левой кнопкой мышки на красных глазах.\n" -" Отменить:\n" -" Кликните правой кнопкой мышки на красных глазах." - -#: fotoxx_retouch.cc:3409 -msgid "Red Eye Reduction" -msgstr "Уменьшение эффекта красных глаз" - -#: fotoxx_retouch.cc:3850 -msgid "Set Blur Radius" -msgstr "Размыть" - -#: fotoxx_retouch.cc:4084 -msgid "edge detection" -msgstr "Обнаружение края" - -#: fotoxx_retouch.cc:4085 -msgid "cycles" -msgstr "Циклы" - -#: fotoxx_retouch.cc:4086 -msgid "reduce" -msgstr "Уменьшить" - -#: fotoxx_retouch.cc:4097 -msgid "unsharp mask" -msgstr "Маска резкости" - -#: fotoxx_retouch.cc:4110 -msgid "brightness gradient" -msgstr "Переход яркости" - -#: fotoxx_retouch.cc:4516 -msgid "" -" Press the reduce button to \n" -" reduce noise in small steps. \n" -" Use undo to start over." -msgstr "" -" Нажмите кнопку [Уменьшить] \n" -" для уменьшения шума." - -#: fotoxx_retouch.cc:4527 -msgid "Noise Reduction" -msgstr "Шумоподавление" - -#: fotoxx_retouch.cc:4532 -msgid "algorithm" -msgstr "Алгоритм" - -#: fotoxx_retouch.cc:4539 -msgid "flatten outliers by color (1)" -msgstr "Flatten outliers by color (1)" - -#: fotoxx_retouch.cc:4540 -msgid "flatten outliers by color (2)" -msgstr "Flatten outliers by color (2)" - -#: fotoxx_retouch.cc:4541 -msgid "set median brightness by color" -msgstr "Set median brightness by color" - -#: fotoxx_retouch.cc:4542 fotoxx_retouch.cc:4543 -msgid "top hat filter by color" -msgstr "Top hat аilter by color" - -#: fotoxx_retouch.cc:4858 -msgid "" -"1. Drag mouse to select. \n" -"2. Erase. 3. Repeat. " -msgstr "" - -#: fotoxx_retouch.cc:4889 -msgid "Radius" -msgstr "Радиус" - -#: fotoxx_retouch.cc:4891 -msgid "Blur" -msgstr "" - -#: fotoxx_retouch.cc:4894 -msgid "New Area" -msgstr "" - -#: fotoxx_retouch.cc:5275 -msgid "spot size limit" -msgstr "" - -#: fotoxx_retouch.cc:5278 -msgid "max. brightness" -msgstr "" - -#: fotoxx_retouch.cc:5281 -msgid "min. contrast" -msgstr "" - -#: fotoxx_retouch.cc:5875 -#, c-format -msgid "Undo Memory %d%c" -msgstr "Память %d%c" - -#: fotoxx_retouch.cc:5884 -msgid "pick" -msgstr "Выбрать" - -#: fotoxx_retouch.cc:5886 -msgid "erase" -msgstr "Стереть" - -#: fotoxx_retouch.cc:5894 -msgid "paintbrush radius" -msgstr "Радиус кисти" - -#: fotoxx_retouch.cc:5895 -msgid "transparency center" -msgstr "Центр" - -#: fotoxx_retouch.cc:5896 -msgid "transparency edge" -msgstr "Край" - -#: fotoxx_retouch.cc:6166 -msgid "" -"Undo memory limit has been reached. \n" -"Save work with [done], then resume editing." -msgstr "" -"Превышен лимит памяти (200 MB) \n" -"Сохраните изменения и продолжайте" - -#: fotoxx_tools.cc:42 -msgid "" -"When editing a collection, right-click \n" -"an image or thumbnail to add or remove." -msgstr "" - -#: fotoxx_tools.cc:85 -msgid "Start new collection" -msgstr "" - -#: fotoxx_tools.cc:87 -msgid "Edit a collection" -msgstr "" - -#: fotoxx_tools.cc:89 -msgid "View a collection" -msgstr "" - -#: fotoxx_tools.cc:91 -msgid "Delete a collection" -msgstr "" - -#: fotoxx_tools.cc:95 -msgid "Editing:" -msgstr "" - -#: fotoxx_tools.cc:99 -msgid "Action:" -msgstr "" - -#: fotoxx_tools.cc:133 -msgid "New Collection" -msgstr "" - -#: fotoxx_tools.cc:156 -msgid "Edit Collection" -msgstr "" - -#: fotoxx_tools.cc:172 -msgid "View Collection" -msgstr "" - -#: fotoxx_tools.cc:193 -msgid "Delete Collection" -msgstr "" - -#: fotoxx_tools.cc:196 -#, c-format -msgid "delete %s ?" -msgstr "" - -#: fotoxx_tools.cc:223 -#, c-format -msgid "add image to collection: %s" -msgstr "" - -#: fotoxx_tools.cc:225 fotoxx_tools.cc:270 -msgid "remove image from collection" -msgstr "" - -#: fotoxx_tools.cc:226 fotoxx_tools.cc:271 fotoxx_tools.cc:298 -msgid "remove and save image" -msgstr "" - -#: fotoxx_tools.cc:227 fotoxx_tools.cc:316 -msgid "insert saved images here" -msgstr "" - -#: fotoxx_tools.cc:256 -msgid "add image to collection" -msgstr "" - -#: fotoxx_tools.cc:301 -msgid "too many saved files" -msgstr "" - -#: fotoxx_tools.cc:375 -msgid "old top directory" -msgstr "" - -#: fotoxx_tools.cc:378 -msgid "new top directory" -msgstr "" - -#: fotoxx_tools.cc:434 -msgid "completed" -msgstr "Сделано" - -#: fotoxx_tools.cc:452 -msgid "" -"Brightness should show a gradual ramp \n" -"extending all the way to the edges." -msgstr "" - -#: fotoxx_tools.cc:492 -msgid "Monitor Check" -msgstr "" - -#: fotoxx_tools.cc:612 -msgid "Brightness Distribution" -msgstr "Распределение яркости" - -#: fotoxx_tools.cc:796 -msgid "Press ESC to exit slide show" -msgstr "" - -#: fotoxx_tools.cc:797 -msgid "show only latest file versions" -msgstr "" - -#: fotoxx_tools.cc:801 -msgid "arrow keys" -msgstr "" - -#: fotoxx_tools.cc:802 -msgid "instant" -msgstr "" - -#: fotoxx_tools.cc:803 -msgid "fade-in" -msgstr "" - -#: fotoxx_tools.cc:804 -msgid "roll-right" -msgstr "" - -#: fotoxx_tools.cc:805 -msgid "roll-down" -msgstr "" - -#: fotoxx_tools.cc:806 -msgid "shift-left" -msgstr "" - -#: fotoxx_tools.cc:807 -msgid "venetian" -msgstr "" - -#: fotoxx_tools.cc:808 -msgid "grate" -msgstr "" - -#: fotoxx_tools.cc:811 -msgid "radar" -msgstr "" - -#: fotoxx_tools.cc:812 -msgid "jaws" -msgstr "" - -#: fotoxx_tools.cc:823 -msgid "seconds" -msgstr "Секунд" - -#: fotoxx_tools.cc:827 -msgid "music file" -msgstr "" - -#: fotoxx_tools.cc:831 -msgid "transitions" -msgstr "" - -#: fotoxx_tools.cc:948 -msgid "Select music file or playlist" -msgstr "" - -#: fotoxx_tools.cc:1971 -msgid "x-spacing" -msgstr "" - -#: fotoxx_tools.cc:1972 -msgid "x-count" -msgstr "" - -#: fotoxx_tools.cc:1973 -msgid "x-enable" -msgstr "" - -#: fotoxx_tools.cc:1979 -msgid "y-spacing" -msgstr "" - -#: fotoxx_tools.cc:1980 -msgid "y-count" -msgstr "" - -#: fotoxx_tools.cc:1981 -msgid "y-enable" -msgstr "" - -#: fotoxx_tools.cc:1988 -msgid "x-offset" -msgstr "" - -#: fotoxx_tools.cc:1992 -msgid "y-offset" -msgstr "" - -#: fotoxx_tools.cc:2146 -msgid "lens name" -msgstr "Объектив" - -#: fotoxx_tools.cc:2220 -msgid "Available Translations" -msgstr "Доступен перевод" - -#: fotoxx_tools.cc:2224 -msgid "Set Language" -msgstr "Установка языка" - -#: fotoxx_tools.cc:2290 -msgid "Make Launcher" -msgstr "" - -#: fotoxx_tools.cc:2310 -msgid "Program ufraw-batch is required" -msgstr "" - -#: fotoxx_tools.cc:2320 -msgid "Open RAW File" -msgstr "Открыть RAW-файл" - -#: fotoxx_tools.cc:2331 -msgid "Select RAW files to convert" -msgstr "Выбрать RAW-файлы для конвертации" - -#: fotoxx_tools.cc:2467 -msgid "max. width" -msgstr "" - -#: fotoxx_tools.cc:2468 -msgid "max. height" -msgstr "" - -#: fotoxx_tools.cc:2527 fotoxx_transform.cc:1268 -#, c-format -msgid "max. size %d x %d is not reasonable" -msgstr "" - -#: fotoxx_tools.cc:2613 -msgid "too many files" -msgstr "" - -#: fotoxx_tools.cc:2656 -msgid "Sync Files is already running" -msgstr "" - -#: fotoxx_tools.cc:2707 -msgid "" -"Run Tools > Synchronize Files so that gallery windows \n" -"will be fast and Search Images will work correctly. \n" -"You can view (not edit) images while synchronize runs." -msgstr "" - -#: fotoxx_tools.cc:2736 -msgid "no top image directory is defined" -msgstr "" - -#: fotoxx_tools.cc:2742 -msgid "top image directory is invalid" -msgstr "" - -#: fotoxx_tools.cc:2747 -msgid "no search index file is present" -msgstr "" - -#: fotoxx_tools.cc:2761 -msgid "new/modified files are present" -msgstr "" - -#: fotoxx_tools.cc:2768 -msgid "no new files found" -msgstr "" - -#: fotoxx_tools.cc:2785 -msgid "Top Image Directory:" -msgstr "Папка с изображениями" - -#: fotoxx_tools.cc:2807 -msgid "file sync is mandatory" -msgstr "" - -#: fotoxx_tools.cc:2817 -msgid "top directory is invalid" -msgstr "" - -#: fotoxx_tools.cc:3201 -msgid "Select top image directory" -msgstr "Выбор папки" - -#: fotoxx_tools.cc:3378 -msgid "icons" -msgstr "" - -#: fotoxx_tools.cc:3379 fotoxx_transform.cc:1467 -msgid "text" -msgstr "" - -#: fotoxx_tools.cc:3380 -msgid "both" -msgstr "" - -#: fotoxx_transform.cc:50 -msgid "Use buttons or drag right edge with mouse" -msgstr " Пользуйтесь кнопками или тащите мышью " - -#: fotoxx_transform.cc:64 -msgid "degrees" -msgstr "Градусы" - -#: fotoxx_transform.cc:80 fotoxx_transform.cc:124 -msgid "Trim" -msgstr "Кадрировать" - -#: fotoxx_transform.cc:81 fotoxx_transform.cc:2437 fotoxx_transform.cc:3263 -#: fotoxx_transform.cc:3526 fotoxx_transform.cc:3787 -msgid "Grid" -msgstr "" - -#: fotoxx_transform.cc:123 -msgid "Undo Trim" -msgstr "Отменить" - -#: fotoxx_transform.cc:139 -#, c-format -msgid "degrees: %.1f" -msgstr "Градусы: %.1f" - -#: fotoxx_transform.cc:286 -msgid "gold" -msgstr "" - -#: fotoxx_transform.cc:332 -msgid "Drag middle to move, drag corners to resize." -msgstr "" - -#: fotoxx_transform.cc:346 -msgid "customize" -msgstr "" - -#: fotoxx_transform.cc:357 -msgid "ratio" -msgstr "" - -#: fotoxx_transform.cc:361 -msgid "Lock Ratio" -msgstr "Фиксировать соотношение сторон" - -#: fotoxx_transform.cc:367 -msgid "invert" -msgstr "" - -#: fotoxx_transform.cc:892 -msgid "Trim Buttons" -msgstr "" - -#: fotoxx_transform.cc:964 -msgid "Lock aspect ratio" -msgstr "Фиксировать пропорции" - -#: fotoxx_transform.cc:1145 -msgid "Batch Resize" -msgstr "" - -#: fotoxx_transform.cc:1153 -msgid "new max. width" -msgstr "" - -#: fotoxx_transform.cc:1154 -msgid "new max. height" -msgstr "" - -#: fotoxx_transform.cc:1161 -msgid "replace originals" -msgstr "" - -#: fotoxx_transform.cc:1162 -msgid "export to location" -msgstr "" - -#: fotoxx_transform.cc:1166 -msgid "copy EXIF" -msgstr "" - -#: fotoxx_transform.cc:1219 -msgid "Select directory" -msgstr "" - -#: fotoxx_transform.cc:1243 -#, c-format -msgid "replace original files? (max. %d x %d)" -msgstr "" - -#: fotoxx_transform.cc:1250 -#, c-format -msgid "" -"copy files? (max. %d x %d) \n" -" to location %s" -msgstr "" - -#: fotoxx_transform.cc:1261 -msgid "location is not a valid directory" -msgstr "" - -#: fotoxx_transform.cc:1304 -msgid "new file already exists" -msgstr "" - -#: fotoxx_transform.cc:1388 -msgid "" -"Enter text, click/drag on image.\n" -"Right click to remove" -msgstr "" - -#: fotoxx_transform.cc:1442 -msgid "Text" -msgstr "" - -#: fotoxx_transform.cc:1449 -msgid "Size" -msgstr "" - -#: fotoxx_transform.cc:1452 -msgid "Angle" -msgstr "" - -#: fotoxx_transform.cc:1463 -msgid "Color" -msgstr "Цвет" - -#: fotoxx_transform.cc:1464 -msgid "Transparency" -msgstr "" - -#: fotoxx_transform.cc:1472 -msgid "backing" -msgstr "" - -#: fotoxx_transform.cc:1475 -msgid "" -"Outline\n" -" Width" -msgstr "" - -#: fotoxx_transform.cc:1477 -msgid "outline" -msgstr "" - -#: fotoxx_transform.cc:1486 -msgid "Annotation File:" -msgstr "" - -#: fotoxx_transform.cc:1564 -msgid "select font" -msgstr "" - -#: fotoxx_transform.cc:2197 fotoxx_transform.cc:2429 -msgid "horizontal" -msgstr "Горизонталь" - -#: fotoxx_transform.cc:2198 fotoxx_transform.cc:2428 -msgid "vertical" -msgstr "Вертикаль" - -#: fotoxx_transform.cc:2306 -msgid "black/white positive" -msgstr "" - -#: fotoxx_transform.cc:2307 -msgid "black/white negative" -msgstr "" - -#: fotoxx_transform.cc:2308 -msgid "color positive" -msgstr "" - -#: fotoxx_transform.cc:2309 -msgid "color negative" -msgstr "" - -#: fotoxx_transform.cc:2430 -msgid "linear" -msgstr "" - -#: fotoxx_transform.cc:2433 -msgid "curved" -msgstr "" - -#: fotoxx_transform.cc:2692 -msgid "" -" Click the four corners of a tetragon area. Press [apply]. \n" -" The image is warped to make the tetragon into a rectangle." -msgstr "" - -#: fotoxx_transform.cc:2878 -msgid "must have 4 corners" -msgstr "" - -#: fotoxx_transform.cc:2999 -msgid "" -" Select an area to warp using select area function. \n" -" Press [start warp] and pull area with mouse. \n" -" Make multiple mouse pulls until satisfied. \n" -" When finished, select another area or press [done]." -msgstr "" -" Выберите область для деформации \n" -" Нажмите [Деформировать] \n" -" Управляйте процессом при помощи мышки \n" -" Выберите новую область или нажмите [Применить]" - -#: fotoxx_transform.cc:3018 -msgid "start warp" -msgstr "Деформировать" - -#: fotoxx_transform.cc:3067 -msgid "Select area first" -msgstr "Сначала выберите область" - -#: fotoxx_transform.cc:3242 fotoxx_transform.cc:3505 -msgid "" -" Pull an image position using the mouse. \n" -" Make multiple mouse pulls until satisfied. \n" -" When finished, press [done]." -msgstr "" - -#: fotoxx_transform.cc:3771 -msgid "" -" Pull on an image corner using the mouse. \n" -" Make multiple mouse pulls until satisfied. \n" -" When finished, press [done]." -msgstr "" -" Корректируйте перспективу при помощи мышки \n" -" По окончании нажмите [Применить]" - -#~ msgid "Translate" -#~ msgstr "Перевод" - -#~ msgid "full rebuild" -#~ msgstr "Полная переиндексация" - -#~ msgid "incremental" -#~ msgstr "Инкрементная индексация" - -#~ msgid "" -#~ "Rename failed \n" -#~ " %s" -#~ msgstr "" -#~ "Переименование остановлено \n" -#~ " %s" - -#~ msgid "Discard modifications?" -#~ msgstr "Отменить модификации?" - -#~ msgid "histogram" -#~ msgstr "Гистограмма" - -#~ msgid "tags exceed %d characters" -#~ msgstr "Тег превысил %d символов" - -#~ msgid "recently added" -#~ msgstr "Последние добавленные" - -#~ msgid "grid spacing" -#~ msgstr "Параметры сетки" - -#~ msgid "assigned tags" -#~ msgstr "Назначенные признаки" - -#~ msgid "Unable to save image: %s" -#~ msgstr "Не могу сохранить изображение: %s" - -#~ msgid "Unable to copy EXIF data" -#~ msgstr "Не могу скопировать EXIF-данные" - -#~ msgid "Total tags exceed %d characters" -#~ msgstr "Общее превышение %d символов" - -#~ msgid "Too many tags: %d" -#~ msgstr "Слишком много тегов: %d" - -#~ msgid "Index Tags" -#~ msgstr "Переиндексировать теги" - -#~ msgid "" -#~ "Drag middle to move \n" -#~ "Drag corners to resize" -#~ msgstr "" -#~ "Тяните за середину, чтобы переместить \n" -#~ "Тяните за края, чтобы изменить размер" - -#~ msgid "Add or Remove Grid Lines" -#~ msgstr "Добавить или удалить сетку" - -#~ msgid "" -#~ "%s \n" -#~ " tag limit exceeded" -#~ msgstr "" -#~ "%s \n" -#~ " Превышен лимит тегов" - -#~ msgid "jpeg quality" -#~ msgstr "Качество jpeg" - -#~ msgid "Select between 2 and 10 files to combine" -#~ msgstr "Выберите от 2 до 10 файлов" - -#~ msgid "Current file must be included" -#~ msgstr "Файл должен быть включен" - -#~ msgid "Select image to combine" -#~ msgstr "Выберите изображение" - -#~ msgid "Select 2 to 10 files to combine" -#~ msgstr "Выбрать от 2 до 10 изображений" - -#~ msgid "Retouch Image" -#~ msgstr "Ретушировать изображение" - -#~ msgid "Package ufraw required for this function" -#~ msgstr "Для этой функции требуется пакет ufraw" - -#~ msgid "Merge the images together" -#~ msgstr "Bilder miteinander verbinden" - -#~ msgid "Match Images" -#~ msgstr "Bilder angleichen" - -#~ msgid "" -#~ "Drag right image into rough alignment with left \n" -#~ " to rotate, drag right edge up or down" -#~ msgstr "" -#~ "Тяните правое изображение до совмещения с левым \n" -#~ "Для поворота тяните правый край вверх или вниз" - -#~ msgid "Auto-search lens mm and bow" -#~ msgstr "Автоматический поиск параметров объектива" - -#~ msgid "Auto" -#~ msgstr "Авто" - -#~ msgid "" -#~ "\n" -#~ " Match Brightness and Color" -#~ msgstr "" -#~ "\n" -#~ " Соответствие цвета и яркости" - -#~ msgid "select image files to add tags" -#~ msgstr "Выберите файлы изображений для добавления тегов" - -#~ msgid "select files" -#~ msgstr "Выберите файлы" - -#~ msgid "rename files" -#~ msgstr "Переименовать файлы" - -#~ msgid "freehand draw" -#~ msgstr "Произвольная область" - -#~ msgid "follow edge" -#~ msgstr "По краю" - -#~ msgid "" -#~ "exiftool missing, please install \n" -#~ " package libimage-exiftool-perl" -#~ msgstr "" -#~ "EXIFtool не найден, пожалуйста, установите \n" -#~ "libimage-exiftool-perl" - -#~ msgid "color range" -#~ msgstr "По уровню цвета" - -#~ msgid "browse" -#~ msgstr "Просмотр" - -#~ msgid "add tags" -#~ msgstr "Добавить теги" - -#~ msgid "TIFF colors=%d depth=%d not supported" -#~ msgstr "TIFF цвета=%d глубина=%d не поддерживается" - -#~ msgid "Fix Image Perspective" -#~ msgstr "Корректировать перспективу" - -#~ msgid "" -#~ "Convert tags to new standard now?\n" -#~ "Are your image files backed-up?" -#~ msgstr "" -#~ "Конвертировать теги в новый формат сейчас?\n" -#~ "Вы сделали резервные копии изображений?" - -#~ msgid "Burn" -#~ msgstr "Прожечь" - -#~ msgid "color intensity" -#~ msgstr "Интенсивность цвета" - -#~ msgid "Read File" -#~ msgstr "Из файла" - -#~ msgid "" -#~ "position image\n" -#~ "with mouse drag" -#~ msgstr "" -#~ "Позиция\n" -#~ "С мышкой" - -#~ msgid "Warp Image in Selected Area" -#~ msgstr "Деформировать изображение в выбранной области" - -#~ msgid "Warp Image (curvy)" -#~ msgstr "Корректировать перспективу (kurvig)" - -#~ msgid "Warp Area" -#~ msgstr "Выборочная деформация" - -#~ msgid "" -#~ " Pull on an image edge using the mouse. \n" -#~ " Make multiple mouse pulls until satisfied. \n" -#~ " When finished, press [done]." -#~ msgstr "" -#~ " Корректируйте перспективу при помощи мышки \n" -#~ " По окончании нажмите [Применить]" - -#~ msgid "match any tag" -#~ msgstr "Соответствие любого тега" - -#~ msgid "match all tags" -#~ msgstr "Соответствие всех тегов" - -#~ msgid "Tags" -#~ msgstr "Теги" - -#~ msgid "Suspend" -#~ msgstr "Приостановить" - -#~ msgid "Set Tile and Gap Size" -#~ msgstr "Элементы и промежутки" - -#~ msgid "Search Tags" -#~ msgstr "Поиск тегов" - -#~ msgid "Resume" -#~ msgstr "Продолжить" - -#~ msgid "Edit EXIF data" -#~ msgstr "Редактировать EXIF-данные" - -#~ msgid "EXIF data" -#~ msgstr "EXIF-данные" - -#~ msgid "Delete EXIF data" -#~ msgstr "Удалить EXIF-данные" - -#~ msgid "Basic EXIF data" -#~ msgstr "Основные EXIF-данные" - -#~ msgid "All EXIF data" -#~ msgstr "Все EXIF-данные" - -#~ msgid "/path*/file*" -#~ msgstr "/путь*/файл*" - -#~ msgid "tags index file error: %s" -#~ msgstr "Ошибка индексного файла тегов: %s" - -#~ msgid "save select area as a file" -#~ msgstr "Сохранить выбранную область как файл" - -#~ msgid "new tags index will now be created" -#~ msgstr "Будет создан новый индекс тегов" - -#~ msgid "cannot read .dist file" -#~ msgstr "Не могу прочесть .dist-файл" - -#~ msgid "brightness to clip (percent)" -#~ msgstr "Яркость (%)" - -#~ msgid "Use F1 for context help" -#~ msgstr "Получите помощь по F1" - -#~ msgid "Rebuild Tags Index" -#~ msgstr "Переиндексировать теги" - -#~ msgid "No tags index file" -#~ msgstr "Нет индексного файла" - -#~ msgid "HDR" -#~ msgstr "HDR" - -#~ msgid "HDF" -#~ msgstr "HDF" - -#~ msgid "Convert tags to new standard" -#~ msgstr "Конверировать теги по новому стандарту" - -#~ msgid "Convert Tags !!!" -#~ msgstr "Конвертировать теги" - -#~ msgid "Constrain" -#~ msgstr "Ограничение" - -#~ msgid "Area" -#~ msgstr "Область" - -#~ msgid "target group area" -#~ msgstr "Область" - -#~ msgid "vertical unbend" -#~ msgstr "По вертикали" - -#~ msgid "horizontal unbend" -#~ msgstr "По горизонтали" - -#~ msgid "area outline has a hole" -#~ msgstr "В области есть дыра" - -#~ msgid "" -#~ "Search all areas for edge and inside pixels. \n" -#~ "Click inside each enclosed area in sequence." -#~ msgstr "" -#~ "Поиск областей \n" -#~ "Кликните вне области" - -#~ msgid "Create Launcher" -#~ msgstr "Создать стартовую иконку" - -#~ msgid "range" -#~ msgstr "Расстояние" - -#~ msgid "limit" -#~ msgstr "Лимит" - -#~ msgid "Width" -#~ msgstr "Ширина" - -#~ msgid "Unknown file type, save as tiff/jpeg/png to edit" -#~ msgstr "" -#~ "Неизвестный тип файла, сохраните как tiff/jpeg/png для редактирования" - -#~ msgid "Undo Last" -#~ msgstr "Отменить последнее" - -#~ msgid "Undo All" -#~ msgstr "Отменить все" - -#~ msgid "Threshold" -#~ msgstr "Порог" - -#~ msgid "Start" -#~ msgstr "Старт" - -#~ msgid "Search" -#~ msgstr "Поиск" - -#~ msgid "Reduce" -#~ msgstr "Уменьшить" - -#~ msgid "Red" -#~ msgstr "Красный" - -#~ msgid "Proceed" -#~ msgstr "Начать" - -#~ msgid "Presets" -#~ msgstr "Пресеты" - -#~ msgid "Percent" -#~ msgstr "%" - -#~ msgid "Pause" -#~ msgstr "Пауза" - -#~ msgid "OK" -#~ msgstr "Ok" - -#~ msgid "Lighter Areas" -#~ msgstr "Светлые области" - -#~ msgid "Insert" -#~ msgstr "Вставить" - -#~ msgid "Height" -#~ msgstr "Высота" - -#~ msgid "Green" -#~ msgstr "Зеленый" - -#~ msgid "Finish" -#~ msgstr "Финиш" - -#~ msgid "Fetch" -#~ msgstr "Получить" - -#~ msgid "Edit" -#~ msgstr "Редактировать" - -#~ msgid "Done" -#~ msgstr "Применить" - -#~ msgid "Darker Areas" -#~ msgstr "Темные области" - -#~ msgid "Clear" -#~ msgstr "Очистить" - -#~ msgid "Cancel" -#~ msgstr "Отмена" - -#~ msgid "Brightness" -#~ msgstr "Яркость" - -#~ msgid "Blue" -#~ msgstr "Синий" - -#~ msgid "Blend Width" -#~ msgstr "Ширина перекрытия" - -#~ msgid "Apply" -#~ msgstr "Применить" - -#~ msgid "Amount" -#~ msgstr "Количество" - -#~ msgid "Add All" -#~ msgstr "Добавить все" - -#~ msgid "click on window to show RGB" -#~ msgstr "Кликните по окну, чтобы увидеть RGB" - -#~ msgid "Save As" -#~ msgstr "Сохранить как" - -#~ msgid "Clone fotoxx" -#~ msgstr "Клонировать fotoxx" - -#~ msgid "Time Interval" -#~ msgstr "Временной интервал" - -#~ msgid "Delete" -#~ msgstr "Удалить" diff -Nru fotoxx-11.11.1/locales/ru/zfuncs.po fotoxx-12.01.2/locales/ru/zfuncs.po --- fotoxx-11.11.1/locales/ru/zfuncs.po 2011-11-05 05:30:37.000000000 +0000 +++ fotoxx-12.01.2/locales/ru/zfuncs.po 1970-01-01 00:00:00.000000000 +0000 @@ -1,287 +0,0 @@ -# Russian translations for home package. -# Copyright (C) 2010 by Redf -# This file is distributed under the same license as the home package. -# Redf , 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: zfuncs-4.0\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2011-11-05 05:49+0100\n" -"PO-Revision-Date: 2008-11-18 20:37+0100\n" -"Last-Translator: redf \n" -"Language-Team: Russian\n" -"Language: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#: zfuncs.cc:3192 -#, c-format -msgid "help file not found: %s" -msgstr "Файл помощи %s не найден" - -#: zfuncs.cc:3296 -#, c-format -msgid "error: %s" -msgstr "Ошибка: %s" - -#: zfuncs.cc:4415 zfuncs.cc:8771 -#, c-format -msgid "cannot open file %s" -msgstr "Не могу открыть файл %s" - -#: zfuncs.cc:4448 -msgid "save screen to file" -msgstr "Сохранить изображение в файл" - -#: zfuncs.cc:6198 -msgid "No" -msgstr "" - -#: zfuncs.cc:6198 -msgid "Yes" -msgstr "" - -#: zfuncs.cc:6272 zfuncs.cc:6308 zfuncs.cc:6461 zfuncs.cc:6865 zfuncs.cc:8358 -#: zfuncs.cc:8883 zfuncs.cc:8889 zfuncs.cc:8895 zfuncs.cc:8901 -msgid "cancel" -msgstr "Отменить" - -#: zfuncs.cc:6423 zfuncs.cc:7552 -msgid "open" -msgstr "Открыть" - -#: zfuncs.cc:6428 -msgid "choose" -msgstr "" - -#: zfuncs.cc:6433 -msgid "save" -msgstr "Сохранить" - -#: zfuncs.cc:6439 -msgid "open folder" -msgstr "Открыть папку" - -#: zfuncs.cc:6444 -msgid "create folder" -msgstr "Создать папку" - -#: zfuncs.cc:6450 -msgid "hidden" -msgstr "Скрыть" - -#: zfuncs.cc:6454 -msgid "quality" -msgstr "Качество" - -#: zfuncs.cc:6511 -msgid "JPG quality 0-100" -msgstr "Качество JPG 0-100" - -#: zfuncs.cc:6865 zfuncs.cc:8358 -msgid "done" -msgstr "" - -#: zfuncs.cc:6865 zfuncs.cc:6878 -msgid "margins" -msgstr "" - -#: zfuncs.cc:6874 -msgid "top" -msgstr "" - -#: zfuncs.cc:6875 -msgid "bottom" -msgstr "" - -#: zfuncs.cc:6876 -msgid "left" -msgstr "" - -#: zfuncs.cc:6877 -msgid "right" -msgstr "" - -#: zfuncs.cc:7278 zfuncs.cc:7532 zfuncs.cc:7670 zfuncs.cc:7671 zfuncs.cc:7673 -msgid "bigger" -msgstr "Увеличить" - -#: zfuncs.cc:7278 -msgid "increase thumbnail size" -msgstr "Увеличить" - -#: zfuncs.cc:7279 -msgid "reduce thumbnail size" -msgstr "Уменьшить" - -#: zfuncs.cc:7279 zfuncs.cc:7542 zfuncs.cc:7672 zfuncs.cc:7674 -msgid "smaller" -msgstr "Уменьшить" - -#: zfuncs.cc:7280 zfuncs.cc:7571 -msgid "parent" -msgstr "Наверх" - -#: zfuncs.cc:7280 -msgid "parent directory" -msgstr "Директорией выше" - -#: zfuncs.cc:7281 zfuncs.cc:7589 zfuncs.cc:7681 -msgid "first page" -msgstr "Первая страница" - -#: zfuncs.cc:7281 -msgid "jump to first file" -msgstr "К первому файлу" - -#: zfuncs.cc:7282 zfuncs.cc:7587 zfuncs.cc:7676 zfuncs.cc:7683 -msgid "prev page" -msgstr "Предыдущая страница" - -#: zfuncs.cc:7282 -msgid "previous page" -msgstr "Предыдущая страница" - -#: zfuncs.cc:7283 zfuncs.cc:7585 zfuncs.cc:7678 -msgid "prev row" -msgstr "Предыдущий ряд" - -#: zfuncs.cc:7283 -msgid "previous row" -msgstr "Предыдущий ряд" - -#: zfuncs.cc:7284 zfuncs.cc:7586 zfuncs.cc:7679 -msgid "next row" -msgstr "Следующий ряд" - -#: zfuncs.cc:7285 zfuncs.cc:7588 zfuncs.cc:7677 zfuncs.cc:7684 -msgid "next page" -msgstr "Следующая страница" - -#: zfuncs.cc:7286 -msgid "jump to last file" -msgstr "К последнему файлу" - -#: zfuncs.cc:7286 zfuncs.cc:7590 zfuncs.cc:7682 -msgid "last page" -msgstr "Последняя страница" - -#: zfuncs.cc:7287 zfuncs.cc:7527 -msgid "close" -msgstr "Закрыть" - -#: zfuncs.cc:7287 -msgid "close image gallery" -msgstr "Закрыть галерею" - -#: zfuncs.cc:7558 -msgid "select new file" -msgstr "Выбрть новый файл" - -#: zfuncs.cc:8358 -msgid "Select Files" -msgstr "" - -#: zfuncs.cc:8366 -msgid "delete" -msgstr "" - -#: zfuncs.cc:8367 -msgid "insert" -msgstr "" - -#: zfuncs.cc:8368 -msgid "add all" -msgstr "" - -#: zfuncs.cc:8658 -msgid "" -"Initial parameters file created. \n" -"Inspect and revise if necessary." -msgstr "" -"Файл параметров создан \n" -"Проверьте при необходимости" - -#: zfuncs.cc:8674 -msgid "load parameters from a file" -msgstr "Загрузить параметры из файла" - -#: zfuncs.cc:8743 -msgid "save parameters to a file" -msgstr "Сохранить параметры в файл" - -#: zfuncs.cc:8881 zfuncs.cc:8887 zfuncs.cc:8893 zfuncs.cc:8899 -msgid "edit parameters" -msgstr "Редактировать пареметры" - -#: zfuncs.cc:8882 zfuncs.cc:8888 -msgid "" -"list\n" -"all" -msgstr "" -"Показать\n" -"все" - -#: zfuncs.cc:8882 zfuncs.cc:8888 zfuncs.cc:8894 zfuncs.cc:8900 -msgid "" -"load\n" -"file" -msgstr "" -"Загрузить\n" -"файл" - -#: zfuncs.cc:8882 zfuncs.cc:8888 zfuncs.cc:8894 zfuncs.cc:8900 -msgid "" -"save\n" -"file" -msgstr "" -"Сохранить\n" -"файл" - -#: zfuncs.cc:8883 zfuncs.cc:8895 -msgid "" -"add\n" -"new" -msgstr "" -"Добавить\n" -"новый" - -#: zfuncs.cc:8883 zfuncs.cc:8889 zfuncs.cc:8895 zfuncs.cc:8901 -msgid "apply" -msgstr "Применить" - -#: zfuncs.cc:8935 -msgid "apply?" -msgstr "Применить?" - -#: zfuncs.cc:8992 -msgid "(new parm name)" -msgstr "(новые параметры)" - -#: zfuncs.cc:8992 -msgid "add parameter" -msgstr "Добавить параметр" - -#~ msgid "print" -#~ msgstr "Печать" - -#~ msgid "printer ID" -#~ msgstr "ID принтера" - -#~ msgid "paper format" -#~ msgstr "Формат печати" - -#~ msgid "portrait" -#~ msgstr "Портрет" - -#~ msgid "landscape" -#~ msgstr "Ландшафт" - -#~ msgid "paper format is crazy" -#~ msgstr "Невозможный формат печати" - -#~ msgid "open a file" -#~ msgstr "Открыть файл" diff -Nru fotoxx-11.11.1/locales/sv/fotoxx.po fotoxx-12.01.2/locales/sv/fotoxx.po --- fotoxx-11.11.1/locales/sv/fotoxx.po 2011-11-05 05:30:37.000000000 +0000 +++ fotoxx-12.01.2/locales/sv/fotoxx.po 1970-01-01 00:00:00.000000000 +0000 @@ -1,2640 +0,0 @@ -# translation of fotoxx.po to svenska -# Swedish translations for fotoxx package -# Svenska översättningar för paket fotoxx. -# Copyright (C) 2010 THE fotoxx'S COPYRIGHT HOLDER -# This file is distributed under the same license as the fotoxx package. -# -# progdev , 2010. -# Peter Landgren , 2010, 2011. -msgid "" -msgstr "" -"Project-Id-Version: fotoxx\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2011-11-05 05:49+0100\n" -"PO-Revision-Date: 2011-04-04 09:46+0200\n" -"Last-Translator: Peter Landgren \n" -"Language-Team: Swedish \n" -"Language: sv\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Lokalize 1.0\n" - -#: fotoxx-11.11.1.cc:179 -msgid "File" -msgstr "Fil" - -#: fotoxx-11.11.1.cc:180 fotoxx-11.11.1.cc:316 -msgid "Image Gallery" -msgstr "Bildgalleri" - -#: fotoxx-11.11.1.cc:181 -msgid "Clone 50/50" -msgstr "" - -#: fotoxx-11.11.1.cc:182 -msgid "Clone Overlay" -msgstr "" - -#: fotoxx-11.11.1.cc:183 fotoxx-11.11.1.cc:317 fotoxx-11.11.1.cc:2272 -#: fotoxx-11.11.1.cc:2444 -msgid "Open Image File" -msgstr "Öppna bildfil" - -#: fotoxx-11.11.1.cc:184 -msgid "Open in New Window" -msgstr "" - -#: fotoxx-11.11.1.cc:185 fotoxx-11.11.1.cc:318 -msgid "Open Previous File" -msgstr "Öppna föregående fil" - -#: fotoxx-11.11.1.cc:186 -msgid "Open Recent File" -msgstr "Öppna senaste fil" - -#: fotoxx-11.11.1.cc:187 fotoxx-11.11.1.cc:326 -msgid "Save to Same File" -msgstr "Spara till samma fil" - -#: fotoxx-11.11.1.cc:188 fotoxx-11.11.1.cc:327 -msgid "Save to New Version" -msgstr "" - -#: fotoxx-11.11.1.cc:189 fotoxx-11.11.1.cc:328 -msgid "Save to New File" -msgstr "Spara till ny fil" - -#: fotoxx-11.11.1.cc:190 fotoxx-11.11.1.cc:2990 -msgid "Create Blank Image" -msgstr "Skapa tom bild" - -#: fotoxx-11.11.1.cc:191 -msgid "Trash Image File" -msgstr "Skräpbildfil" - -#: fotoxx-11.11.1.cc:192 fotoxx-11.11.1.cc:3216 -msgid "Rename Image File" -msgstr "Döp om bildfil" - -#: fotoxx-11.11.1.cc:193 -msgid "Batch Rename Files" -msgstr "Massomdöp filer" - -#: fotoxx-11.11.1.cc:194 -msgid "Print Image File" -msgstr "Skriv ut bildfil" - -#: fotoxx-11.11.1.cc:195 fotoxx-11.11.1.cc:332 -msgid "Quit fotoxx" -msgstr "Avsluta fotoxx" - -#: fotoxx-11.11.1.cc:197 -msgid "Tools" -msgstr "Verktyg" - -#: fotoxx-11.11.1.cc:198 fotoxx_tools.cc:70 -msgid "Manage Collections" -msgstr "" - -#: fotoxx-11.11.1.cc:199 fotoxx_tools.cc:373 -msgid "Move Collections" -msgstr "" - -#: fotoxx-11.11.1.cc:200 -msgid "Check Monitor" -msgstr "Kontrollera skärm" - -#: fotoxx-11.11.1.cc:201 fotoxx_tools.cc:550 -msgid "Monitor Gamma" -msgstr "Bildskärmsgamma" - -#: fotoxx-11.11.1.cc:202 -msgid "Brightness Graph" -msgstr "Ljushetsdiagram" - -#: fotoxx-11.11.1.cc:203 fotoxx_tools.cc:819 -msgid "Slide Show" -msgstr "Bildvisning" - -#: fotoxx-11.11.1.cc:204 fotoxx_tools.cc:1668 -msgid "Show RGB" -msgstr "Visa RGB" - -#: fotoxx-11.11.1.cc:205 fotoxx_tools.cc:1962 -msgid "Grid Lines" -msgstr "Rutnät" - -#: fotoxx-11.11.1.cc:206 fotoxx_tools.cc:2135 -msgid "Lens Parameters" -msgstr "Linsparametrar" - -#: fotoxx-11.11.1.cc:207 -msgid "Change Language" -msgstr "Ändra språk" - -#: fotoxx-11.11.1.cc:209 -msgid "Add Menu and Launcher" -msgstr "" - -#: fotoxx-11.11.1.cc:210 -msgid "Convert RAW files" -msgstr "Omvandla RAW-filer" - -#: fotoxx-11.11.1.cc:211 -msgid "Burn Images to CD/DVD" -msgstr "Bränn bilder till CD/DVD" - -#: fotoxx-11.11.1.cc:212 fotoxx_tools.cc:2460 -msgid "E-mail Images" -msgstr "E-postbilder" - -#: fotoxx-11.11.1.cc:213 fotoxx_tools.cc:2783 -msgid "Synchronize Files" -msgstr "Synkronisera filer" - -#: fotoxx-11.11.1.cc:214 fotoxx_tools.cc:3376 -msgid "Toolbar Style" -msgstr "" - -#: fotoxx-11.11.1.cc:215 -msgid "Memory Usage" -msgstr "Minnesutnyttjande" - -#: fotoxx-11.11.1.cc:218 -msgid "Edit Caption/Comments" -msgstr "" - -#: fotoxx-11.11.1.cc:219 fotoxx_info.cc:156 -msgid "Edit Tags" -msgstr "Redigera taggar" - -#: fotoxx-11.11.1.cc:220 fotoxx_info.cc:345 -msgid "Manage Tags" -msgstr "Hantera flikar" - -#: fotoxx-11.11.1.cc:221 fotoxx_info.cc:1345 -msgid "Batch Add Tags" -msgstr "Masstillägg av taggar" - -#: fotoxx-11.11.1.cc:222 fotoxx_info.cc:1547 -msgid "Batch Delete Tag" -msgstr "Borttagning av flagga satsvis" - -#: fotoxx-11.11.1.cc:223 -msgid "View Info (short)" -msgstr "Visa information (kort)" - -#: fotoxx-11.11.1.cc:224 -msgid "View Info (long)" -msgstr "Visa information (långt)" - -#: fotoxx-11.11.1.cc:225 fotoxx_info.cc:1883 -msgid "Edit Info" -msgstr "Redigera info" - -#: fotoxx-11.11.1.cc:226 fotoxx_info.cc:1981 -msgid "Delete Info" -msgstr "Borttagningsinfo" - -#: fotoxx-11.11.1.cc:227 -msgid "Search Images" -msgstr "Bildsökning" - -#: fotoxx-11.11.1.cc:229 fotoxx-11.11.1.cc:230 -msgid "Select" -msgstr "Välj" - -#: fotoxx-11.11.1.cc:231 -msgid "Show" -msgstr "Visa" - -#: fotoxx-11.11.1.cc:232 -msgid "Hide" -msgstr "Göm" - -#: fotoxx-11.11.1.cc:233 -msgid "Enable" -msgstr "Koppla in" - -#: fotoxx-11.11.1.cc:234 -msgid "Disable" -msgstr "Koppla bort" - -#: fotoxx-11.11.1.cc:235 -msgid "Invert" -msgstr "Invertera" - -#: fotoxx-11.11.1.cc:236 -msgid "Unselect" -msgstr "" - -#: fotoxx-11.11.1.cc:237 -msgid "Copy" -msgstr "Kopiera" - -#: fotoxx-11.11.1.cc:238 -msgid "Paste" -msgstr "Klistra in" - -#: fotoxx-11.11.1.cc:239 fotoxx-11.11.1.cc:317 fotoxx_retouch.cc:2314 -#: fotoxx_retouch.cc:2319 -msgid "Open" -msgstr "Öppna" - -#: fotoxx-11.11.1.cc:240 fotoxx-11.11.1.cc:326 -msgid "Save" -msgstr "Spara" - -#: fotoxx-11.11.1.cc:241 fotoxx_area.cc:2215 -msgid "Select Whole Image" -msgstr "Välj hel bild" - -#: fotoxx-11.11.1.cc:242 -msgid "Select and Edit" -msgstr "Välj och redigera" - -#: fotoxx-11.11.1.cc:244 -msgid "Transform" -msgstr "Omvandla" - -#: fotoxx-11.11.1.cc:245 fotoxx_transform.cc:60 -msgid "Rotate Image" -msgstr "Rotera bild" - -#: fotoxx-11.11.1.cc:246 fotoxx_transform.cc:346 -msgid "Trim Image" -msgstr "Trimma bild" - -#: fotoxx-11.11.1.cc:247 fotoxx_transform.cc:972 -msgid "Resize Image" -msgstr "Ändra bildstorlek" - -#: fotoxx-11.11.1.cc:248 -msgid "Batch Resize/Export" -msgstr "" - -#: fotoxx-11.11.1.cc:249 fotoxx_transform.cc:1436 -msgid "Annotate Image" -msgstr "Kommentera bild" - -#: fotoxx-11.11.1.cc:250 fotoxx_transform.cc:2193 -msgid "Flip Image" -msgstr "Vänd bild" - -#: fotoxx-11.11.1.cc:251 fotoxx_transform.cc:2303 -msgid "Make Negative" -msgstr "Gör negativ" - -#: fotoxx-11.11.1.cc:252 fotoxx_transform.cc:2420 -msgid "Unbend Image" -msgstr "Utsläta bild" - -#: fotoxx-11.11.1.cc:253 fotoxx_transform.cc:2704 -msgid "Keystone Correction" -msgstr "" - -#: fotoxx-11.11.1.cc:254 fotoxx_transform.cc:3013 -msgid "Warp Image (area)" -msgstr "Vik ihop bild (yta)" - -#: fotoxx-11.11.1.cc:255 fotoxx_transform.cc:3255 -msgid "Warp Image (curved)" -msgstr "Vik ihop bild (kurva)" - -#: fotoxx-11.11.1.cc:256 fotoxx_transform.cc:3518 -msgid "Warp Image (linear)" -msgstr "Vik ihop bild (linjärt)" - -#: fotoxx-11.11.1.cc:257 fotoxx_transform.cc:3782 -msgid "Warp Image (affine)" -msgstr "Förvräng bild (affine)" - -#: fotoxx-11.11.1.cc:259 -msgid "Retouch" -msgstr "Retuschera" - -#: fotoxx-11.11.1.cc:260 -msgid "Brightness/Color" -msgstr "Ljushet/färg" - -#: fotoxx-11.11.1.cc:261 -msgid "Gamma Curves" -msgstr "" - -#: fotoxx-11.11.1.cc:262 -msgid "Expand Brightness" -msgstr "Expandera ljushet" - -#: fotoxx-11.11.1.cc:263 -msgid "Flatten Brightness" -msgstr "Platta till ljushet" - -#: fotoxx-11.11.1.cc:264 -msgid "Brightness Ramp" -msgstr "Ljushetsramp" - -#: fotoxx-11.11.1.cc:265 fotoxx_retouch.cc:1729 -msgid "Tone Mapping" -msgstr "Tonavbildning" - -#: fotoxx-11.11.1.cc:266 -msgid "White Balance" -msgstr "Vitbalans" - -#: fotoxx-11.11.1.cc:267 -msgid "Match Colors" -msgstr "" - -#: fotoxx-11.11.1.cc:269 fotoxx_retouch.cc:2941 -msgid "Revise RGB" -msgstr "" - -#: fotoxx-11.11.1.cc:270 -msgid "Red Eyes" -msgstr "Röda ögon" - -#: fotoxx-11.11.1.cc:271 -msgid "Blur Image" -msgstr "Gör bilden suddig" - -#: fotoxx-11.11.1.cc:272 fotoxx_retouch.cc:4077 -msgid "Sharpen Image" -msgstr "Gör bild skarpare" - -#: fotoxx-11.11.1.cc:273 -msgid "Reduce Noise" -msgstr "Minska brus" - -#: fotoxx-11.11.1.cc:274 fotoxx_retouch.cc:4881 -msgid "Smart Erase" -msgstr "Fiffig radering" - -#: fotoxx-11.11.1.cc:275 fotoxx_retouch.cc:5271 -msgid "Remove Dust" -msgstr "" - -#: fotoxx-11.11.1.cc:276 fotoxx_retouch.cc:5877 -msgid "Edit Pixels" -msgstr "Redigera pixlar" - -#: fotoxx-11.11.1.cc:278 -msgid "Art" -msgstr "Sort" - -#: fotoxx-11.11.1.cc:279 -msgid "Color Depth" -msgstr "Färgdjup" - -#: fotoxx-11.11.1.cc:280 -msgid "Drawing" -msgstr "Ritning" - -#: fotoxx-11.11.1.cc:281 -msgid "Outlines" -msgstr "Konturer" - -#: fotoxx-11.11.1.cc:282 -msgid "Embossing" -msgstr "Bosselera" - -#: fotoxx-11.11.1.cc:283 -msgid "Tiles" -msgstr "Plattor" - -#: fotoxx-11.11.1.cc:284 -msgid "Dots" -msgstr "Punkter" - -#: fotoxx-11.11.1.cc:285 -msgid "Painting" -msgstr "Färgläggning" - -#: fotoxx-11.11.1.cc:287 -msgid "Combine" -msgstr "Kombinera" - -#: fotoxx-11.11.1.cc:288 -msgid "High Dynamic Range" -msgstr "Stort dynamiskt område" - -#: fotoxx-11.11.1.cc:289 -msgid "High Depth of Field" -msgstr "" - -#: fotoxx-11.11.1.cc:290 -msgid "Stack / Paint" -msgstr "Stack / färg" - -#: fotoxx-11.11.1.cc:291 -msgid "Stack / Noise" -msgstr "Stack / brus" - -#: fotoxx-11.11.1.cc:292 -msgid "Panorama" -msgstr "Panorama" - -#: fotoxx-11.11.1.cc:293 -msgid "Vertical Panorama" -msgstr "Vertikalt panorama" - -#: fotoxx-11.11.1.cc:296 -msgid "Edit Plugins" -msgstr "Redigera insticksprogram" - -#: fotoxx-11.11.1.cc:305 fotoxx-11.11.1.cc:333 fotoxx-11.11.1.cc:4616 -msgid "Help" -msgstr "Hjälp" - -#: fotoxx-11.11.1.cc:306 fotoxx-11.11.1.cc:4606 -msgid "About" -msgstr "Om" - -#: fotoxx-11.11.1.cc:307 fotoxx-11.11.1.cc:4610 -msgid "User Guide" -msgstr "Användarguide" - -#: fotoxx-11.11.1.cc:308 fotoxx-11.11.1.cc:4613 -msgid "User Guide Changes" -msgstr "" - -#: fotoxx-11.11.1.cc:309 fotoxx-11.11.1.cc:4622 -msgid "Edit Functions Summary" -msgstr "" - -#: fotoxx-11.11.1.cc:310 fotoxx-11.11.1.cc:4625 -msgid "Change Log" -msgstr "Ändringslogg" - -#: fotoxx-11.11.1.cc:311 fotoxx-11.11.1.cc:4628 -msgid "Translations" -msgstr "" - -#: fotoxx-11.11.1.cc:312 fotoxx-11.11.1.cc:4631 -msgid "Home Page" -msgstr "Hemsida" - -#: fotoxx-11.11.1.cc:316 -msgid "Gallery" -msgstr "Galleri" - -#: fotoxx-11.11.1.cc:318 fotoxx_transform.cc:995 -msgid "Prev" -msgstr "Föreg" - -#: fotoxx-11.11.1.cc:319 -msgid "Next" -msgstr "Nästa" - -#: fotoxx-11.11.1.cc:319 -msgid "Open Next File" -msgstr "Öppna nästa fil" - -#: fotoxx-11.11.1.cc:320 -msgid "Zoom-in (bigger)" -msgstr "Zooma in (större)" - -#: fotoxx-11.11.1.cc:321 -msgid "Zoom-out (smaller)" -msgstr "Zooma ut (mindre)" - -#: fotoxx-11.11.1.cc:322 -msgid "Undo" -msgstr "Ångra" - -#: fotoxx-11.11.1.cc:322 -msgid "Undo One Edit" -msgstr "Ångra en redigering" - -#: fotoxx-11.11.1.cc:323 -msgid "Redo" -msgstr "Gör om" - -#: fotoxx-11.11.1.cc:323 -msgid "Redo One Edit" -msgstr "Gör om en redigering" - -#: fotoxx-11.11.1.cc:327 -msgid "Save+V" -msgstr "" - -#: fotoxx-11.11.1.cc:328 -msgid "Save+F" -msgstr "" - -#: fotoxx-11.11.1.cc:329 -msgid "Move Image to Trash" -msgstr "Flytta bild till Skräp" - -#: fotoxx-11.11.1.cc:329 -msgid "Trash" -msgstr "Skräp" - -#: fotoxx-11.11.1.cc:332 -msgid "Quit" -msgstr "Avsluta" - -#: fotoxx-11.11.1.cc:333 -msgid "Fotoxx Essentials" -msgstr "Fotoxx Essentials" - -#: fotoxx-11.11.1.cc:429 -msgid "first time startup" -msgstr "" - -#: fotoxx-11.11.1.cc:1815 -msgid "Exceed 50 anchor points" -msgstr "Överskridit 50 ankarpunkter" - -#: fotoxx-11.11.1.cc:2000 -msgid "load curve from a file" -msgstr "ladda kurva från fil" - -#: fotoxx-11.11.1.cc:2053 -msgid "curve file is invalid" -msgstr "kurvfil är ogiltig" - -#: fotoxx-11.11.1.cc:2058 -msgid "curve file has different no. of curves" -msgstr "kurvfil har annorlunda antal kurvor" - -#: fotoxx-11.11.1.cc:2073 -msgid "save curve to a file" -msgstr "spara kurva till en fil" - -#: fotoxx-11.11.1.cc:2420 -#, c-format -msgid "" -"Discard special gallery list? \n" -" %s" -msgstr "" - -#: fotoxx-11.11.1.cc:2430 fotoxx-11.11.1.cc:4452 -msgid "prior function still active" -msgstr "" - -#: fotoxx-11.11.1.cc:2607 -msgid "Overwrite original file?" -msgstr "" - -#: fotoxx-11.11.1.cc:2608 -msgid "Do not warn again" -msgstr "" - -#: fotoxx-11.11.1.cc:2624 -msgid "Warning" -msgstr "" - -#: fotoxx-11.11.1.cc:2747 -msgid "Save File" -msgstr "Spara fil" - -#: fotoxx-11.11.1.cc:2770 -msgid "quality" -msgstr "kvalitet" - -#: fotoxx-11.11.1.cc:2772 -msgid "make current" -msgstr "" - -#: fotoxx-11.11.1.cc:2829 -msgid "jpeg quality must be 1-100" -msgstr "jpegkvalitete måste vara 1-100" - -#: fotoxx-11.11.1.cc:2851 -#, c-format -msgid "" -"Overwrite file? \n" -" %s" -msgstr "" -"Skriva över fil? \n" -" %s" - -#: fotoxx-11.11.1.cc:2992 -msgid "file name" -msgstr "" - -#: fotoxx-11.11.1.cc:2997 fotoxx_transform.cc:351 -msgid "width" -msgstr "bredd" - -#: fotoxx-11.11.1.cc:3000 fotoxx_transform.cc:354 -msgid "height" -msgstr "höjd" - -#: fotoxx-11.11.1.cc:3006 fotoxx_art.cc:628 fotoxx_retouch.cc:5881 -msgid "color" -msgstr "färg" - -#: fotoxx-11.11.1.cc:3120 -msgid "" -"Linux standard trash is not supported. \n" -"Desktop trash folder will be created." -msgstr "" -"Linux standarpapperskorg stöds ej. \n" -"En skrivbordspapperskorg kommer att skapas." - -#: fotoxx-11.11.1.cc:3138 -msgid "Move read-only file to trash?" -msgstr "Flytta skrivskyddd fil till Skräp?" - -#: fotoxx-11.11.1.cc:3164 -#, c-format -msgid "Cannot create trash folder: %s" -msgstr "Kan ej skapa skräpmapp: %s" - -#: fotoxx-11.11.1.cc:3172 fotoxx-11.11.1.cc:3178 -#, c-format -msgid "error: %s" -msgstr "fel: %s" - -#: fotoxx-11.11.1.cc:3221 -msgid "old name" -msgstr "gammalt namn" - -#: fotoxx-11.11.1.cc:3222 -msgid "rename to" -msgstr "döp om till" - -#: fotoxx-11.11.1.cc:3223 -msgid "previous" -msgstr "föregående" - -#: fotoxx-11.11.1.cc:3309 -msgid "The target file already exists" -msgstr "Målfilen finns redan" - -#: fotoxx-11.11.1.cc:3317 -#, c-format -msgid "" -"Rename failed: \n" -" %s" -msgstr "" - -#: fotoxx-11.11.1.cc:3365 -msgid "Batch Rename" -msgstr "Massomdöpning" - -#: fotoxx-11.11.1.cc:3368 fotoxx-11.11.1.cc:3420 fotoxx_info.cc:1513 -#: fotoxx_info.cc:1767 fotoxx_tools.cc:2510 fotoxx_transform.cc:1213 -#, c-format -msgid "%d files selected" -msgstr "" - -#: fotoxx-11.11.1.cc:3370 -msgid "new base name" -msgstr "nytt basnamn" - -#: fotoxx-11.11.1.cc:3373 -msgid "starting sequence" -msgstr "begynnelsesekvens" - -#: fotoxx-11.11.1.cc:3375 -msgid "increment" -msgstr "steg" - -#: fotoxx-11.11.1.cc:3396 -msgid "select files to rename" -msgstr "välj filer för omdöpning" - -#: fotoxx-11.11.1.cc:3401 -msgid "base name / sequence / increment not reasonable" -msgstr "basnamn / sekvens / steg ej lämpliga" - -#: fotoxx-11.11.1.cc:3460 -msgid "new file already exists:" -msgstr "ny fil finns redan:" - -#: fotoxx-11.11.1.cc:3468 -msgid "filespec too long:" -msgstr "filspec för lång" - -#: fotoxx-11.11.1.cc:3479 -msgid "Rename failed:" -msgstr "Namnändring misslyckades:" - -#: fotoxx-11.11.1.cc:3739 -msgid "Add" -msgstr "Lägg till" - -#: fotoxx-11.11.1.cc:3739 -msgid "Remove" -msgstr "Tag bort" - -#: fotoxx-11.11.1.cc:3741 -msgid "menu name" -msgstr "" - -#: fotoxx-11.11.1.cc:3812 fotoxx-11.11.1.cc:3833 -msgid "Restart Fotoxx to update plugin menu" -msgstr "Starta om Fotoxx för att uppdatera insticksmenyn" - -#: fotoxx-11.11.1.cc:3927 -msgid "cannot parallel edit" -msgstr "" - -#: fotoxx-11.11.1.cc:3937 -msgid "" -"exiftool is not installed \n" -"edited images will lose EXIF data" -msgstr "" -"exif-verktyg är ej installerat\n" -"redigerade bilder kommer att tappa EXIF-data" - -#: fotoxx-11.11.1.cc:3943 -msgid "Too many edits, please save image" -msgstr "För många redigeringar, spara bilden" - -#: fotoxx-11.11.1.cc:3948 -msgid "" -"Select area cannot be kept.\n" -"Continue?" -msgstr "" -"Valt område behållas.\n" -"Fortsätta?" - -#: fotoxx-11.11.1.cc:3956 -msgid "" -"Select area not active.\n" -"Continue?" -msgstr "" -"Valt område ej aktivt.\n" -"Fortsätta?" - -#: fotoxx-11.11.1.cc:4427 -msgid "Discard edits?" -msgstr "" - -#: fotoxx-11.11.1.cc:4428 -msgid "" -"This action will discard current edits.\n" -"Continue to discard edits.\n" -"Go Back to keep edits." -msgstr "" - -#: fotoxx-11.11.1.cc:4431 -msgid "Continue" -msgstr "" - -#: fotoxx-11.11.1.cc:4432 -msgid "Go Back" -msgstr "" - -#: fotoxx-11.11.1.cc:5240 -msgid "cannot open thumbnail file" -msgstr "kan ej öppna miniatyrbildsfil" - -#: fotoxx-11.11.1.cc:5433 fotoxx-11.11.1.cc:5549 -msgid "TIFF open failure" -msgstr "Fel vid öppnande av TIFF" - -#: fotoxx-11.11.1.cc:5449 -#, c-format -msgid "TIFF bits/color=%d not supported" -msgstr "TIFF bits/color=%d stöds ej" - -#: fotoxx-11.11.1.cc:5464 fotoxx-11.11.1.cc:5502 -msgid "TIFF read failure" -msgstr "Fel vid läsning av TIFF" - -#: fotoxx-11.11.1.cc:5608 -msgid "TIFF write failure" -msgstr "Fel vid skrivning av TIFF" - -#: fotoxx-11.11.1.cc:5638 -msgid "file type not supported" -msgstr "filtyp stöds ej" - -#: fotoxx-11.11.1.cc:5745 -msgid "pixbuf write failure" -msgstr "pixbuf-skrivfel" - -#: fotoxx_area.cc:54 fotoxx_area.cc:2427 -msgid "Select Area for Edits" -msgstr "Välj område till redigering" - -#: fotoxx_area.cc:55 fotoxx_area.cc:2428 -msgid "Press F1 for help" -msgstr "Tryck F1 efter hjälp" - -#: fotoxx_area.cc:63 -msgid "" -"Select Area not supported \n" -"by this edit function" -msgstr "" - -#: fotoxx_area.cc:99 fotoxx_tools.cc:809 -msgid "rectangle" -msgstr "rektangel" - -#: fotoxx_area.cc:100 fotoxx_tools.cc:810 -msgid "ellipse" -msgstr "ellips" - -#: fotoxx_area.cc:101 -msgid "draw: freehand" -msgstr "drag: frihand" - -#: fotoxx_area.cc:102 -msgid "draw: follow edge" -msgstr "drag: följ kant" - -#: fotoxx_area.cc:103 -msgid "select by mouse" -msgstr "välj med mus" - -#: fotoxx_area.cc:104 -msgid "select by color" -msgstr "välj genom färg" - -#: fotoxx_area.cc:112 -msgid "radius" -msgstr "radie" - -#: fotoxx_area.cc:116 -msgid "match" -msgstr "matcha" - -#: fotoxx_area.cc:121 -msgid "firewall" -msgstr "brandvägg" - -#: fotoxx_area.cc:274 fotoxx_area.cc:415 -#, c-format -msgid "exceed %d edits" -msgstr "överskrid %d redigeringar" - -#: fotoxx_area.cc:992 -msgid "" -"Click one time inside each enclosed area \n" -"(possible gaps in the outline will be found). \n" -"Press F1 for help." -msgstr "" - -#: fotoxx_area.cc:1049 -msgid "finish area" -msgstr "avslutande område" - -#: fotoxx_area.cc:1083 -msgid "searching" -msgstr "sökning" - -#: fotoxx_area.cc:1155 -msgid "outline has a gap" -msgstr "" - -#: fotoxx_area.cc:1157 -msgid "success" -msgstr "lyckades" - -#: fotoxx_area.cc:1401 fotoxx_area.cc:1430 -msgid "the area is not finished" -msgstr "området är ej avslutat" - -#: fotoxx_area.cc:1522 -msgid "Edge calculation in progress" -msgstr "Kantberäkning pågår" - -#: fotoxx_area.cc:1531 -msgid "Area Edge Calc" -msgstr "Ytkantsberäkning" - -#: fotoxx_area.cc:1824 -msgid "position with mouse click/drag" -msgstr "positionera med musklick/drag" - -#: fotoxx_area.cc:1848 -msgid "Paste Image" -msgstr "Klistra in bild" - -#: fotoxx_area.cc:1863 -msgid "angle" -msgstr "vinkel" - -#: fotoxx_area.cc:2127 -msgid "load select area from a file" -msgstr "ladda valt område från en fil" - -#: fotoxx_area.cc:2161 -msgid "cannot open .tiff and .info files" -msgstr "kan ej öppna .tiff- och .info-filer" - -#: fotoxx_area.cc:2180 -msgid "save select area to a file" -msgstr "spara valt område till en fil" - -#: fotoxx_area.cc:2216 -msgid "Edit Function Amplifier" -msgstr "Redigera funktionsförstärkare" - -#: fotoxx_area.cc:2459 -msgid "mouse radius" -msgstr "musradie" - -#: fotoxx_area.cc:2462 -msgid "power: center" -msgstr "kraft: centrum" - -#: fotoxx_area.cc:2464 -msgid "edge" -msgstr "kant" - -#: fotoxx_area.cc:2468 -msgid "reset area" -msgstr "återställ område§" - -#: fotoxx_area.cc:2523 -msgid "start edit function first" -msgstr "" - -#: fotoxx_art.cc:47 -msgid "Set color depth to 1-16 bits" -msgstr "Sätt färgdjup till 1-16 bitar" - -#: fotoxx_art.cc:57 -msgid "Set Color Depth" -msgstr "Välj färgdjup" - -#: fotoxx_art.cc:171 -msgid "Simulate Drawing" -msgstr "Simulera ritning" - -#: fotoxx_art.cc:213 fotoxx_retouch.cc:1758 -msgid "contrast" -msgstr "kontrast" - -#: fotoxx_art.cc:215 -msgid "outlines" -msgstr "konturer" - -#: fotoxx_art.cc:220 -msgid "pencil" -msgstr "penna" - -#: fotoxx_art.cc:221 -msgid "chalk" -msgstr "krita" - -#: fotoxx_art.cc:381 -msgid "Add Image Outlines" -msgstr "Lägg till bildkanter" - -#: fotoxx_art.cc:394 -msgid "outline threshold" -msgstr "konturtröskel" - -#: fotoxx_art.cc:397 -msgid "outline width" -msgstr "konturbredd" - -#: fotoxx_art.cc:400 -msgid "image brightness" -msgstr "bildljushet" - -#: fotoxx_art.cc:611 -msgid "Simulate Embossing" -msgstr "Simulera upphöjning" - -#: fotoxx_art.cc:626 -msgid "depth" -msgstr "djup" - -#: fotoxx_art.cc:821 -msgid "Simulate Tiles" -msgstr "Simulera plattor" - -#: fotoxx_art.cc:825 -msgid "tile size" -msgstr "plattstorlek" - -#: fotoxx_art.cc:829 -msgid "tile gap" -msgstr "gap mellan plattor" - -#: fotoxx_art.cc:1003 -msgid "Convert Image to Dots" -msgstr "Omvandla bild till punkter" - -#: fotoxx_art.cc:1007 -msgid "dot size" -msgstr "punktstorlek" - -#: fotoxx_art.cc:1222 -msgid "Simulate Painting" -msgstr "Simulera målning" - -#: fotoxx_art.cc:1226 -msgid "color depth" -msgstr "färgdjup" - -#: fotoxx_art.cc:1230 -msgid "patch area goal" -msgstr "" - -#: fotoxx_art.cc:1234 -msgid "req. color match" -msgstr "beg. färgmatchning" - -#: fotoxx_art.cc:1238 -msgid "borders" -msgstr "kanter" - -#: fotoxx_comp.cc:1956 fotoxx_comp.cc:1961 fotoxx_comp.cc:2582 -#: fotoxx_comp.cc:2587 fotoxx_comp.cc:3275 fotoxx_comp.cc:3280 -#: fotoxx_comp.cc:3830 fotoxx_comp.cc:3835 -msgid "Select 2 to 9 files" -msgstr "Välj 2 till 9 filer" - -#: fotoxx_comp.cc:1982 fotoxx_comp.cc:2608 fotoxx_comp.cc:3301 -#: fotoxx_comp.cc:3856 -msgid "Images are not all the same size" -msgstr "Alla bilder har ej samma storlek" - -#: fotoxx_comp.cc:2321 -msgid "Adjust Image Contributions" -msgstr "Justera bildbidrag" - -#: fotoxx_comp.cc:2324 fotoxx_retouch.cc:885 -msgid "dark pixels" -msgstr "mörka pixlar" - -#: fotoxx_comp.cc:2326 -msgid "light pixels" -msgstr "ljusa pixlar" - -#: fotoxx_comp.cc:2328 fotoxx_info.cc:159 -msgid "file:" -msgstr "fil:" - -#: fotoxx_comp.cc:2844 -msgid "Paint and Warp Image" -msgstr "Måla och vik ihop bild" - -#: fotoxx_comp.cc:2847 fotoxx_comp.cc:3529 fotoxx_comp.cc:4972 -#: fotoxx_comp.cc:5717 -msgid "image" -msgstr "bild" - -#: fotoxx_comp.cc:2851 fotoxx_retouch.cc:5885 -msgid "paint" -msgstr "måla" - -#: fotoxx_comp.cc:2852 -msgid "warp" -msgstr "vik ihop" - -#: fotoxx_comp.cc:3527 -msgid "Select and Paint Image" -msgstr "Välj och färglägg bild" - -#: fotoxx_comp.cc:4045 -msgid "Adjust Pixel Composition" -msgstr "Justera pixelsammansättning" - -#: fotoxx_comp.cc:4297 fotoxx_comp.cc:4302 fotoxx_comp.cc:5186 -#: fotoxx_comp.cc:5191 -msgid "Select 2 to 4 files" -msgstr "Välj 2 till 4 filer" - -#: fotoxx_comp.cc:4374 -msgid "" -"Drag images into rough alignment.\n" -"To rotate, drag from lower edge." -msgstr "" -"Drag bilder till grov passning\n" -"Drag i underkant för rotera." - -#: fotoxx_comp.cc:4376 -msgid "Search for lens mm and bow" -msgstr "Sök efter lins och kräkning" - -#: fotoxx_comp.cc:4422 fotoxx_comp.cc:5310 -msgid "Pre-align Images" -msgstr "Rad upp bilder preliminärt" - -#: fotoxx_comp.cc:4426 fotoxx_comp.cc:5314 fotoxx_tools.cc:2151 -msgid "lens mm" -msgstr "lins mm" - -#: fotoxx_comp.cc:4430 fotoxx_comp.cc:5318 fotoxx_tools.cc:2156 -msgid "lens bow" -msgstr "linskurva" - -#: fotoxx_comp.cc:4432 fotoxx_comp.cc:5320 -msgid "Resize" -msgstr "Ändra storlek" - -#: fotoxx_comp.cc:4433 fotoxx_comp.cc:5321 -msgid "resize window" -msgstr "ändra fänsterstorlek" - -#: fotoxx_comp.cc:4470 -msgid "use two images only" -msgstr "använd bara två bilder" - -#: fotoxx_comp.cc:4491 fotoxx_comp.cc:4689 fotoxx_comp.cc:4888 -#: fotoxx_comp.cc:5369 fotoxx_comp.cc:5632 -msgid "Too little overlap, cannot align" -msgstr "För lite överlappning, kan ej rada upp" - -#: fotoxx_comp.cc:4963 fotoxx_comp.cc:5708 -msgid "Match Brightness and Color" -msgstr "Matcha ljushet och färg" - -#: fotoxx_comp.cc:4987 fotoxx_comp.cc:5732 -msgid "auto color" -msgstr "automatisk färg" - -#: fotoxx_comp.cc:4988 fotoxx_comp.cc:5733 -msgid "file color" -msgstr "filfärg" - -#: fotoxx_comp.cc:5263 -msgid "" -"Drag images into rough alignment.\n" -"To rotate, drag from right edge." -msgstr "" -"Drag bilder till grov passninf.\n" -"Rotera genom att dra från höger kant." - -#: fotoxx_info.cc:70 -msgid "Edit Caption and Comments" -msgstr "" - -#: fotoxx_info.cc:163 -msgid "image date (yyyymmdd)" -msgstr "bilddatum (ååååmmdd)" - -#: fotoxx_info.cc:165 -msgid "use last" -msgstr "använd senaste" - -#: fotoxx_info.cc:168 -msgid "image stars" -msgstr "bildstjärnor" - -#: fotoxx_info.cc:186 -msgid "current tags" -msgstr "aktuella taggar" - -#: fotoxx_info.cc:191 -msgid "recent tags" -msgstr "gamla märken" - -#: fotoxx_info.cc:196 fotoxx_info.cc:358 fotoxx_info.cc:1362 -#: fotoxx_info.cc:2290 -msgid "defined tags" -msgstr "definierade märken" - -#: fotoxx_info.cc:348 -msgid "category" -msgstr "kategori" - -#: fotoxx_info.cc:351 -msgid "tag" -msgstr "märke" - -#: fotoxx_info.cc:354 -msgid "create" -msgstr "skapa" - -#: fotoxx_info.cc:355 -msgid "delete" -msgstr "tag bort" - -#: fotoxx_info.cc:1229 fotoxx_info.cc:1313 -#, c-format -msgid "search index file error: %s" -msgstr "sökfilsindexfel: %s" - -#: fotoxx_info.cc:1348 -msgid "tags to add" -msgstr "taggar att lägga till" - -#: fotoxx_info.cc:1353 -msgid "create tag" -msgstr "skapa tagg" - -#: fotoxx_info.cc:1409 fotoxx_info.cc:1602 -#, c-format -msgid "" -"%s \n" -" too many tags" -msgstr "" -"%s \n" -" för många märken" - -#: fotoxx_info.cc:1550 -msgid "tag to remove" -msgstr "flagga för borttagning" - -#: fotoxx_info.cc:1554 -msgid "optional replacement" -msgstr "valbar ersättning" - -#: fotoxx_info.cc:1559 fotoxx_tools.cc:2463 -msgid "0 files selected" -msgstr "" - -#: fotoxx_info.cc:1562 -msgid "search all files" -msgstr "leta i alla filer" - -#: fotoxx_info.cc:1647 -msgid "no files selected" -msgstr "inga filer valda" - -#: fotoxx_info.cc:1653 -msgid "no tag specified" -msgstr "inga flaggor beskrivna" - -#: fotoxx_info.cc:1677 fotoxx_info.cc:1706 -msgid "specify tag" -msgstr "beskriv flagga" - -#: fotoxx_info.cc:1815 -msgid "View Info" -msgstr "Visa information" - -#: fotoxx_info.cc:1983 -msgid "All" -msgstr "Allt" - -#: fotoxx_info.cc:1984 -msgid "One Key:" -msgstr "One Key:" - -#: fotoxx_info.cc:2249 -msgid "Search Tags, Comments, File Names" -msgstr "Sök flaggor, kommentarer, filnamn" - -#: fotoxx_info.cc:2255 -msgid "date range" -msgstr "datumintervall" - -#: fotoxx_info.cc:2256 -msgid "stars range" -msgstr "stjärnområde" - -#: fotoxx_info.cc:2257 -msgid "search tags" -msgstr "sök taggar" - -#: fotoxx_info.cc:2258 -msgid "search text" -msgstr "sök text" - -#: fotoxx_info.cc:2259 -msgid "file names" -msgstr "filnamn" - -#: fotoxx_info.cc:2264 -msgid "(yyyymmdd)" -msgstr "" - -#: fotoxx_info.cc:2270 -msgid "all/any" -msgstr "" - -#: fotoxx_info.cc:2598 -msgid "No matching images found" -msgstr "Inga matchande bilder hittade" - -#: fotoxx_info.cc:2611 -msgid "No search index file present" -msgstr "Ingen indexsökfil rfinns" - -#: fotoxx_info.cc:2615 -#, c-format -msgid "Search results file error %s" -msgstr "Sök fel i resultat fil: %s" - -#: fotoxx_retouch.cc:55 -msgid "Adjust Brightness and Color" -msgstr "Justera ljus och färg" - -#: fotoxx_retouch.cc:109 -msgid "small-steps" -msgstr "" - -#: fotoxx_retouch.cc:118 -msgid "color saturation" -msgstr "färgmättnad" - -#: fotoxx_retouch.cc:125 -msgid " reset 1 " -msgstr " reset 1 " - -#: fotoxx_retouch.cc:126 -msgid "reset all" -msgstr "återställ allt" - -#: fotoxx_retouch.cc:598 -msgid "adjust image gamma" -msgstr "" - -#: fotoxx_retouch.cc:884 -msgid "Expand Brightness Range" -msgstr "Expandera ljushetsområde" - -#: fotoxx_retouch.cc:886 -msgid "bright pixels" -msgstr "ljusa pixlar" - -#: fotoxx_retouch.cc:1057 -msgid "Flatten Brightness Distribution" -msgstr "Platta till ljushetsfördelning" - -#: fotoxx_retouch.cc:1071 -msgid "Flatten" -msgstr "Platta till" - -#: fotoxx_retouch.cc:1333 -msgid "Ramp brightness across image" -msgstr "Rampa ljushet över bild" - -#: fotoxx_retouch.cc:1757 -msgid "low" -msgstr "" - -#: fotoxx_retouch.cc:1759 -msgid "high" -msgstr "" - -#: fotoxx_retouch.cc:1762 -msgid "Amplify" -msgstr "Förstärk" - -#: fotoxx_retouch.cc:2068 -msgid "Adjust White Balance" -msgstr "Justera vitbalans" - -#: fotoxx_retouch.cc:2069 -msgid "Click white or gray image location" -msgstr "Klicka på vit- eller gråbildsplats" - -#: fotoxx_retouch.cc:2283 -msgid "Color Match Images" -msgstr "" - -#: fotoxx_retouch.cc:2312 -msgid "mouse radius for color sample" -msgstr "" - -#: fotoxx_retouch.cc:2315 -msgid "image for source color" -msgstr "" - -#: fotoxx_retouch.cc:2317 -msgid "click on image to get source color" -msgstr "" - -#: fotoxx_retouch.cc:2320 -msgid "image to set matching color" -msgstr "" - -#: fotoxx_retouch.cc:2322 -msgid "click on image to set matching color" -msgstr "" - -#: fotoxx_retouch.cc:2377 -msgid "select source image color first" -msgstr "" - -#: fotoxx_retouch.cc:2903 fotoxx_tools.cc:1643 -msgid "Click image to select pixels." -msgstr "" - -#: fotoxx_retouch.cc:2955 -msgid "Metric:" -msgstr "" - -#: fotoxx_retouch.cc:3010 -msgid "Blend" -msgstr "" - -#: fotoxx_retouch.cc:3394 -msgid "" -"Method 1:\n" -" Left-click on red-eye to darken.\n" -"Method 2:\n" -" Drag down and right to enclose red-eye.\n" -" Left-click on red-eye to darken.\n" -"Undo red-eye:\n" -" Right-click on red-eye." -msgstr "" -"Metod 1:\n" -" Vänsterklicka på röd-öga för att göra mörkare.\n" -"Metod 2:\n" -" Drag ner och höger till att innesluta röd-öga.\n" -" Vänsterklicka på röd-öga för att göra mörkare.\n" -"Ångra röd-öga:\n" -" Högerklicka på röd-öga." - -#: fotoxx_retouch.cc:3409 -msgid "Red Eye Reduction" -msgstr "Rödögonminskning" - -#: fotoxx_retouch.cc:3850 -msgid "Set Blur Radius" -msgstr "Välj suddradie" - -#: fotoxx_retouch.cc:4084 -msgid "edge detection" -msgstr "kantdetektion" - -#: fotoxx_retouch.cc:4085 -msgid "cycles" -msgstr "perioder" - -#: fotoxx_retouch.cc:4086 -msgid "reduce" -msgstr "minska" - -#: fotoxx_retouch.cc:4097 -msgid "unsharp mask" -msgstr "oskarp mask" - -#: fotoxx_retouch.cc:4110 -msgid "brightness gradient" -msgstr "ljushetsgradient" - -#: fotoxx_retouch.cc:4516 -msgid "" -" Press the reduce button to \n" -" reduce noise in small steps. \n" -" Use undo to start over." -msgstr "" -" Tryck minska-knappen för att\n" -" minska brus i små steg.\n" -" Använd ångar för att börja om." - -#: fotoxx_retouch.cc:4527 -msgid "Noise Reduction" -msgstr "Brusminskning" - -#: fotoxx_retouch.cc:4532 -msgid "algorithm" -msgstr "algoritm" - -#: fotoxx_retouch.cc:4539 -msgid "flatten outliers by color (1)" -msgstr "platta till \"uteliggare\" med färg (1)" - -#: fotoxx_retouch.cc:4540 -msgid "flatten outliers by color (2)" -msgstr "platta till \"uteliggare\" med färg (2)" - -#: fotoxx_retouch.cc:4541 -msgid "set median brightness by color" -msgstr "sätt medialjushet genom färg" - -#: fotoxx_retouch.cc:4542 fotoxx_retouch.cc:4543 -msgid "top hat filter by color" -msgstr "top hat-filter med färg" - -#: fotoxx_retouch.cc:4858 -msgid "" -"1. Drag mouse to select. \n" -"2. Erase. 3. Repeat. " -msgstr "" -"1. Drag mus för val. \n" -"2. Radera. 3. Repetera. " - -#: fotoxx_retouch.cc:4889 -msgid "Radius" -msgstr "Radie" - -#: fotoxx_retouch.cc:4891 -msgid "Blur" -msgstr "Göra suddigt" - -#: fotoxx_retouch.cc:4894 -msgid "New Area" -msgstr "Ny yta" - -#: fotoxx_retouch.cc:5275 -msgid "spot size limit" -msgstr "" - -#: fotoxx_retouch.cc:5278 -msgid "max. brightness" -msgstr "" - -#: fotoxx_retouch.cc:5281 -msgid "min. contrast" -msgstr "" - -#: fotoxx_retouch.cc:5875 -#, c-format -msgid "Undo Memory %d%c" -msgstr "Ångra minne %d%c" - -#: fotoxx_retouch.cc:5884 -msgid "pick" -msgstr "plocka" - -#: fotoxx_retouch.cc:5886 -msgid "erase" -msgstr "radera" - -#: fotoxx_retouch.cc:5894 -msgid "paintbrush radius" -msgstr "målarpenselradie" - -#: fotoxx_retouch.cc:5895 -msgid "transparency center" -msgstr "genomskinlighetscenter" - -#: fotoxx_retouch.cc:5896 -msgid "transparency edge" -msgstr "genomskinlighetskant" - -#: fotoxx_retouch.cc:6166 -msgid "" -"Undo memory limit has been reached. \n" -"Save work with [done], then resume editing." -msgstr "" -"Ångra minnesgräns har nåtts.\n" -"Spara arbete med [gjort], fortsätt sedan redigering." - -#: fotoxx_tools.cc:42 -msgid "" -"When editing a collection, right-click \n" -"an image or thumbnail to add or remove." -msgstr "" - -#: fotoxx_tools.cc:85 -msgid "Start new collection" -msgstr "" - -#: fotoxx_tools.cc:87 -msgid "Edit a collection" -msgstr "" - -#: fotoxx_tools.cc:89 -msgid "View a collection" -msgstr "" - -#: fotoxx_tools.cc:91 -msgid "Delete a collection" -msgstr "" - -#: fotoxx_tools.cc:95 -msgid "Editing:" -msgstr "" - -#: fotoxx_tools.cc:99 -msgid "Action:" -msgstr "" - -#: fotoxx_tools.cc:133 -msgid "New Collection" -msgstr "" - -#: fotoxx_tools.cc:156 -msgid "Edit Collection" -msgstr "" - -#: fotoxx_tools.cc:172 -msgid "View Collection" -msgstr "" - -#: fotoxx_tools.cc:193 -msgid "Delete Collection" -msgstr "" - -#: fotoxx_tools.cc:196 -#, c-format -msgid "delete %s ?" -msgstr "" - -#: fotoxx_tools.cc:223 -#, c-format -msgid "add image to collection: %s" -msgstr "" - -#: fotoxx_tools.cc:225 fotoxx_tools.cc:270 -msgid "remove image from collection" -msgstr "" - -#: fotoxx_tools.cc:226 fotoxx_tools.cc:271 fotoxx_tools.cc:298 -msgid "remove and save image" -msgstr "" - -#: fotoxx_tools.cc:227 fotoxx_tools.cc:316 -msgid "insert saved images here" -msgstr "" - -#: fotoxx_tools.cc:256 -msgid "add image to collection" -msgstr "" - -#: fotoxx_tools.cc:301 -msgid "too many saved files" -msgstr "" - -#: fotoxx_tools.cc:375 -msgid "old top directory" -msgstr "" - -#: fotoxx_tools.cc:378 -msgid "new top directory" -msgstr "" - -#: fotoxx_tools.cc:434 -msgid "completed" -msgstr "fullgjort" - -#: fotoxx_tools.cc:452 -msgid "" -"Brightness should show a gradual ramp \n" -"extending all the way to the edges." -msgstr "" -"Ljusheten borde visa a gradvis ramp \n" -"utvidgad hela vägen till kanterna." - -#: fotoxx_tools.cc:492 -msgid "Monitor Check" -msgstr "Kontroll av bildskärm" - -#: fotoxx_tools.cc:612 -msgid "Brightness Distribution" -msgstr "Ljushetsfördelning" - -#: fotoxx_tools.cc:796 -msgid "Press ESC to exit slide show" -msgstr "Tryck ESC för att avsluta bildvisningen" - -#: fotoxx_tools.cc:797 -msgid "show only latest file versions" -msgstr "" - -#: fotoxx_tools.cc:801 -msgid "arrow keys" -msgstr "pilknappar" - -#: fotoxx_tools.cc:802 -msgid "instant" -msgstr "direkt" - -#: fotoxx_tools.cc:803 -msgid "fade-in" -msgstr "intoning" - -#: fotoxx_tools.cc:804 -msgid "roll-right" -msgstr "högerrullning" - -#: fotoxx_tools.cc:805 -msgid "roll-down" -msgstr "nedrullning" - -#: fotoxx_tools.cc:806 -msgid "shift-left" -msgstr "shift-vänster§" - -#: fotoxx_tools.cc:807 -msgid "venetian" -msgstr "venetianskt" - -#: fotoxx_tools.cc:808 -msgid "grate" -msgstr "rutnät" - -#: fotoxx_tools.cc:811 -msgid "radar" -msgstr "" - -#: fotoxx_tools.cc:812 -msgid "jaws" -msgstr "" - -#: fotoxx_tools.cc:823 -msgid "seconds" -msgstr "sekunder" - -#: fotoxx_tools.cc:827 -msgid "music file" -msgstr "musikfil" - -#: fotoxx_tools.cc:831 -msgid "transitions" -msgstr "" - -#: fotoxx_tools.cc:948 -msgid "Select music file or playlist" -msgstr "Välj musikfil eller spellista" - -#: fotoxx_tools.cc:1971 -msgid "x-spacing" -msgstr "" - -#: fotoxx_tools.cc:1972 -msgid "x-count" -msgstr "" - -#: fotoxx_tools.cc:1973 -msgid "x-enable" -msgstr "" - -#: fotoxx_tools.cc:1979 -msgid "y-spacing" -msgstr "" - -#: fotoxx_tools.cc:1980 -msgid "y-count" -msgstr "" - -#: fotoxx_tools.cc:1981 -msgid "y-enable" -msgstr "" - -#: fotoxx_tools.cc:1988 -msgid "x-offset" -msgstr "" - -#: fotoxx_tools.cc:1992 -msgid "y-offset" -msgstr "" - -#: fotoxx_tools.cc:2146 -msgid "lens name" -msgstr "linsnamn" - -#: fotoxx_tools.cc:2220 -msgid "Available Translations" -msgstr "Tillgängliga översättningar" - -#: fotoxx_tools.cc:2224 -msgid "Set Language" -msgstr "Ställ in språk" - -#: fotoxx_tools.cc:2290 -msgid "Make Launcher" -msgstr "" - -#: fotoxx_tools.cc:2310 -msgid "Program ufraw-batch is required" -msgstr "Programmet ufraw-batch krävs" - -#: fotoxx_tools.cc:2320 -msgid "Open RAW File" -msgstr "Öppna RAW-fil" - -#: fotoxx_tools.cc:2331 -msgid "Select RAW files to convert" -msgstr "Välj RAW-filer för omvandling" - -#: fotoxx_tools.cc:2467 -msgid "max. width" -msgstr "max bredd" - -#: fotoxx_tools.cc:2468 -msgid "max. height" -msgstr "max höjd" - -#: fotoxx_tools.cc:2527 fotoxx_transform.cc:1268 -#, c-format -msgid "max. size %d x %d is not reasonable" -msgstr "max storlek %d x %d är inte förnuftig" - -#: fotoxx_tools.cc:2613 -msgid "too many files" -msgstr "för många filer" - -#: fotoxx_tools.cc:2656 -msgid "Sync Files is already running" -msgstr "" - -#: fotoxx_tools.cc:2707 -msgid "" -"Run Tools > Synchronize Files so that gallery windows \n" -"will be fast and Search Images will work correctly. \n" -"You can view (not edit) images while synchronize runs." -msgstr "" - -#: fotoxx_tools.cc:2736 -msgid "no top image directory is defined" -msgstr "" - -#: fotoxx_tools.cc:2742 -msgid "top image directory is invalid" -msgstr "" - -#: fotoxx_tools.cc:2747 -msgid "no search index file is present" -msgstr "" - -#: fotoxx_tools.cc:2761 -msgid "new/modified files are present" -msgstr "" - -#: fotoxx_tools.cc:2768 -msgid "no new files found" -msgstr "" - -#: fotoxx_tools.cc:2785 -msgid "Top Image Directory:" -msgstr "Översta bildmapp:" - -#: fotoxx_tools.cc:2807 -msgid "file sync is mandatory" -msgstr "" - -#: fotoxx_tools.cc:2817 -msgid "top directory is invalid" -msgstr "" - -#: fotoxx_tools.cc:3201 -msgid "Select top image directory" -msgstr "Välj översta bildmapp" - -#: fotoxx_tools.cc:3378 -msgid "icons" -msgstr "" - -#: fotoxx_tools.cc:3379 fotoxx_transform.cc:1467 -msgid "text" -msgstr "text" - -#: fotoxx_tools.cc:3380 -msgid "both" -msgstr "" - -#: fotoxx_transform.cc:50 -msgid "Use buttons or drag right edge with mouse" -msgstr "Använd knappar eller dra höger kant med mus" - -#: fotoxx_transform.cc:64 -msgid "degrees" -msgstr "grader" - -#: fotoxx_transform.cc:80 fotoxx_transform.cc:124 -msgid "Trim" -msgstr "Trimma" - -#: fotoxx_transform.cc:81 fotoxx_transform.cc:2437 fotoxx_transform.cc:3263 -#: fotoxx_transform.cc:3526 fotoxx_transform.cc:3787 -msgid "Grid" -msgstr "" - -#: fotoxx_transform.cc:123 -msgid "Undo Trim" -msgstr "Ångra trimning" - -#: fotoxx_transform.cc:139 -#, c-format -msgid "degrees: %.1f" -msgstr "grader: %.1f" - -#: fotoxx_transform.cc:286 -msgid "gold" -msgstr "" - -#: fotoxx_transform.cc:332 -msgid "Drag middle to move, drag corners to resize." -msgstr "Drag i mitten för att flytta, i hörnen för att ändra storlek." - -#: fotoxx_transform.cc:346 -msgid "customize" -msgstr "anpassa" - -#: fotoxx_transform.cc:357 -msgid "ratio" -msgstr "" - -#: fotoxx_transform.cc:361 -msgid "Lock Ratio" -msgstr "Lås förhållande" - -#: fotoxx_transform.cc:367 -msgid "invert" -msgstr "invertera" - -#: fotoxx_transform.cc:892 -msgid "Trim Buttons" -msgstr "Trimningsknappar" - -#: fotoxx_transform.cc:964 -msgid "Lock aspect ratio" -msgstr "Lås aspektförhållande" - -#: fotoxx_transform.cc:1145 -msgid "Batch Resize" -msgstr "Ändra storlek satsvis" - -#: fotoxx_transform.cc:1153 -msgid "new max. width" -msgstr "ny max bredd" - -#: fotoxx_transform.cc:1154 -msgid "new max. height" -msgstr "ny max höjd" - -#: fotoxx_transform.cc:1161 -msgid "replace originals" -msgstr "ersätta originalen" - -#: fotoxx_transform.cc:1162 -msgid "export to location" -msgstr "exportera till plats" - -#: fotoxx_transform.cc:1166 -msgid "copy EXIF" -msgstr "kopiera EXIF" - -#: fotoxx_transform.cc:1219 -msgid "Select directory" -msgstr "Välj mapp" - -#: fotoxx_transform.cc:1243 -#, c-format -msgid "replace original files? (max. %d x %d)" -msgstr "ersätta ursprungliga filer? max %d x %d)" - -#: fotoxx_transform.cc:1250 -#, c-format -msgid "" -"copy files? (max. %d x %d) \n" -" to location %s" -msgstr "" -"kopiera filer? (max %d x %d) \n" -"till plats %s" - -#: fotoxx_transform.cc:1261 -msgid "location is not a valid directory" -msgstr "platsen är inte en giltig mapp" - -#: fotoxx_transform.cc:1304 -msgid "new file already exists" -msgstr "nya filen finns redan" - -#: fotoxx_transform.cc:1388 -msgid "" -"Enter text, click/drag on image.\n" -"Right click to remove" -msgstr "" -"Skriv in text, klicka/drag i bild.\n" -"Högerklicka för att ta bort." - -#: fotoxx_transform.cc:1442 -msgid "Text" -msgstr "Text" - -#: fotoxx_transform.cc:1449 -msgid "Size" -msgstr "Storlek" - -#: fotoxx_transform.cc:1452 -msgid "Angle" -msgstr "Vinkel" - -#: fotoxx_transform.cc:1463 -msgid "Color" -msgstr "Färg" - -#: fotoxx_transform.cc:1464 -msgid "Transparency" -msgstr "Transparans" - -#: fotoxx_transform.cc:1472 -msgid "backing" -msgstr "" - -#: fotoxx_transform.cc:1475 -msgid "" -"Outline\n" -" Width" -msgstr "" -"Kontur\n" -" bredd" - -#: fotoxx_transform.cc:1477 -msgid "outline" -msgstr "" - -#: fotoxx_transform.cc:1486 -msgid "Annotation File:" -msgstr "Notisfil:" - -#: fotoxx_transform.cc:1564 -msgid "select font" -msgstr "välj typsnitt" - -#: fotoxx_transform.cc:2197 fotoxx_transform.cc:2429 -msgid "horizontal" -msgstr "horisontell" - -#: fotoxx_transform.cc:2198 fotoxx_transform.cc:2428 -msgid "vertical" -msgstr "vertikal" - -#: fotoxx_transform.cc:2306 -msgid "black/white positive" -msgstr "" - -#: fotoxx_transform.cc:2307 -msgid "black/white negative" -msgstr "" - -#: fotoxx_transform.cc:2308 -msgid "color positive" -msgstr "" - -#: fotoxx_transform.cc:2309 -msgid "color negative" -msgstr "" - -#: fotoxx_transform.cc:2430 -msgid "linear" -msgstr "linjär" - -#: fotoxx_transform.cc:2433 -msgid "curved" -msgstr "böjd" - -#: fotoxx_transform.cc:2692 -msgid "" -" Click the four corners of a tetragon area. Press [apply]. \n" -" The image is warped to make the tetragon into a rectangle." -msgstr "" - -#: fotoxx_transform.cc:2878 -msgid "must have 4 corners" -msgstr "" - -#: fotoxx_transform.cc:2999 -msgid "" -" Select an area to warp using select area function. \n" -" Press [start warp] and pull area with mouse. \n" -" Make multiple mouse pulls until satisfied. \n" -" When finished, select another area or press [done]." -msgstr "" -"Välj ett område genom att välja en områdesfunktion. \n" -"Tryck [börja förvräng] och drag ytan med mus. \n" -"Gör flera musdrag tills du när nöjd. \n" -"När du är klar, välj ett annat område eller tryck [klar]." - -#: fotoxx_transform.cc:3018 -msgid "start warp" -msgstr "börja förvrängning" - -#: fotoxx_transform.cc:3067 -msgid "Select area first" -msgstr "Välj område först" - -#: fotoxx_transform.cc:3242 fotoxx_transform.cc:3505 -msgid "" -" Pull an image position using the mouse. \n" -" Make multiple mouse pulls until satisfied. \n" -" When finished, press [done]." -msgstr "" -" Drag i ett bildhörn med musen.\n" -" Gör flera musdragningar tills du är nöjd.\n" -" När du är klar, tryck [Avsluta]." - -#: fotoxx_transform.cc:3771 -msgid "" -" Pull on an image corner using the mouse. \n" -" Make multiple mouse pulls until satisfied. \n" -" When finished, press [done]." -msgstr "" -" Drag i ett bildhörn med musen.\n" -" Gör flera musdragningar tills du är nöjd.\n" -" När du är klar, tryck [Avsluta]." - -#~ msgid "Translate" -#~ msgstr "Översätt" - -#~ msgid "" -#~ "Run Tools > Synchronize Files so that gallery windows \n" -#~ "will be fast and Search Images will work correctly." -#~ msgstr "" -#~ "Kör Verktyg->Synkronisera filer så att bildfönstren \n" -#~ "blir snabba och bildsökning fungerar rätt." - -#~ msgid "full rebuild" -#~ msgstr "total återbildning" - -#~ msgid "incremental" -#~ msgstr "stegvis" - -#~ msgid "" -#~ "Rename failed \n" -#~ " %s" -#~ msgstr "" -#~ "Omdöpning misslyckades \n" -#~ " %s" - -#~ msgid "transition" -#~ msgstr "övergång" - -#~ msgid "Discard modifications?" -#~ msgstr "Kasta ändringar?" - -#~ msgid "histogram" -#~ msgstr "histogram" - -#~ msgid "Edit Comments" -#~ msgstr "Redigera kommentarer" - -#~ msgid "Edit Caption" -#~ msgstr "Redigera rubrik" - -#~ msgid "Curve File:" -#~ msgstr "Kurvfil:" - -#~ msgid "tags exceed %d characters" -#~ msgstr "taggar överskrider %d tecken" - -#~ msgid "recently added" -#~ msgstr "nyligen tillagd" - -#~ msgid "new file already exists: %s" -#~ msgstr "ny fill finns redan: %s" - -#~ msgid "grid spacing" -#~ msgstr "rutnätsavstånd" - -#~ msgid "filespec too long: %s" -#~ msgstr "filspecifikation för lång. %s" - -#~ msgid "assigned tags" -#~ msgstr "tilldelade taggar" - -#~ msgid "Unable to save image: %s" -#~ msgstr "Kan ej spara bild: %s" - -#~ msgid "Unable to copy EXIF data" -#~ msgstr "Kan ej kopiera EXIT-data" - -#~ msgid "Total tags exceed %d characters" -#~ msgstr "Total taggar överskreds med %d tecken" - -#~ msgid "Too many undo buffers, please save image" -#~ msgstr "För många ångrabuffertar, spara bild" - -#~ msgid "Too many tags: %d" -#~ msgstr "För många taggar: %d" - -#~ msgid "Package exiftool is missing" -#~ msgstr "Pakets exif-verktyg saknas" - -#~ msgid "Index Tags" -#~ msgstr "Indextaggar" - -#~ msgid "" -#~ "Drag middle to move \n" -#~ "Drag corners to resize" -#~ msgstr "" -#~ "Drag i mitten för att flytta\n" -#~ "Drag i hörn för att ändra storlek" - -#~ msgid "Convert Tags" -#~ msgstr "Omvandla taggar" - -#~ msgid "Add or Remove Grid Lines" -#~ msgstr "Lägg till eller ta bort rutnät" - -#~ msgid "" -#~ "%s \n" -#~ " tag limit exceeded" -#~ msgstr "" -#~ "%s \n" -#~ " tag-gräns överskriden" - -#~ msgid "jpeg quality" -#~ msgstr "jpegkvalitet" - -#~ msgid "Select between 2 and 10 files to combine" -#~ msgstr "Välj mellan 2 och 10 filer att kombinera" - -#~ msgid "Current file must be included" -#~ msgstr "Aktuell fil måste tas med" - -#~ msgid "Select image to combine" -#~ msgstr "Välj bild att kombinera" - -#~ msgid "Select 2 to 10 files to combine" -#~ msgstr "Välj2 till 20 filer att kombinera" - -#~ msgid "Retouch Image" -#~ msgstr "Retuschera bild" - -#~ msgid "Package ufraw required for this function" -#~ msgstr "Pakets ufraw behövs för denna funktion" - -#~ msgid "Merge the images together" -#~ msgstr "Slå samman bilder" - -#~ msgid "Match Images" -#~ msgstr "Matcha bilder" - -#~ msgid "" -#~ "Drag right image into rough alignment with left \n" -#~ " to rotate, drag right edge up or down" -#~ msgstr "" -#~ "Drag högra bilden till grov inlinjering med vänstra\n" -#~ " för att rotera, drag höger kant upp eller ner" - -#~ msgid "Auto-search lens mm and bow" -#~ msgstr "Sök automatiskt lins mm och kurva" - -#~ msgid "Auto" -#~ msgstr "Auto" - -#~ msgid "" -#~ "\n" -#~ " Match Brightness and Color" -#~ msgstr "" -#~ "\n" -#~ " Matcha ljushet och färg" - -#~ msgid "select image files to add tags" -#~ msgstr "välj bildfiler för tillägg av taggar" - -#~ msgid "select files" -#~ msgstr "välj filer" - -#~ msgid "rename files" -#~ msgstr "döp om fil" - -#~ msgid "freehand draw" -#~ msgstr "frihandsritning" - -#~ msgid "follow edge" -#~ msgstr "följ kant" - -#~ msgid "" -#~ "exiftool missing, please install \n" -#~ " package libimage-exiftool-perl" -#~ msgstr "" -#~ "exiftool saknas, installera \n" -#~ " paketet libimage-exiftool-perl" - -#~ msgid "color range" -#~ msgstr "färgomfång" - -#~ msgid "browse" -#~ msgstr "bläddra" - -#~ msgid "add tags" -#~ msgstr "lägg till taggar" - -#~ msgid "TIFF colors=%d depth=%d not supported" -#~ msgstr "TIFF färger=%d djup=%d ej understött" - -#~ msgid "Fix Image Perspective" -#~ msgstr "Ordna bildperspektiv" - -#~ msgid "" -#~ "Convert tags to new standard now?\n" -#~ "Are your image files backed-up?" -#~ msgstr "" -#~ "Omvandla taggar till ny standrad nu?\n" -#~ "Är dina bildfiler säkerhetskopierade?" - -#~ msgid "Burn" -#~ msgstr "Bränn" - -#~ msgid "color intensity" -#~ msgstr "färgintensitet" - -#~ msgid "Read File" -#~ msgstr "Läs fil" - -#~ msgid "" -#~ "position image\n" -#~ "with mouse drag" -#~ msgstr "" -#~ "placera bild\n" -#~ "med musdragning" - -#~ msgid "Warp Image in Selected Area" -#~ msgstr "Förvräng bild i valt område" - -#~ msgid "Warp Image (curvy)" -#~ msgstr "Förvräng bild (krokig)" - -#~ msgid "Warp Area" -#~ msgstr "Förvrängningsområde" - -#~ msgid "" -#~ " Pull on an image edge using the mouse. \n" -#~ " Make multiple mouse pulls until satisfied. \n" -#~ " When finished, press [done]." -#~ msgstr "" -#~ " Drag i en bildkant med musen.\n" -#~ " Gör flera musdragningar till du är nöjd.\n" -#~ " När du är klar tryck [Avsluta]." - -#~ msgid "comments" -#~ msgstr "kommentarer" - -#~ msgid "Suspend" -#~ msgstr "Avbryt" - -#~ msgid "Resume" -#~ msgstr "Återuppta" - -#~ msgid "/path*/file*" -#~ msgstr "/sökväg*/fil*" - -#~ msgid "transparency" -#~ msgstr "tramsparens" - -#~ msgid "match any tag" -#~ msgstr "matcha någon tagg" - -#~ msgid "match all tags" -#~ msgstr "matcha alla taggar" - -#~ msgid "foreground" -#~ msgstr "förgrund" - -#~ msgid "background" -#~ msgstr "bakgrund" - -#~ msgid "annotation file:" -#~ msgstr "anteckningsfil:" - -#~ msgid "Tags" -#~ msgstr "Taggar" - -#~ msgid "Set Tile and Gap Size" -#~ msgstr "Välj storlek på ruta och mellanrum" - -#~ msgid "Search Tags" -#~ msgstr "Sök taggar" - -#~ msgid "Edit User Comments" -#~ msgstr "Redigera användarkommentarer" - -#~ msgid "Edit EXIF data" -#~ msgstr "Redigera EXIF-data" - -#~ msgid "EXIF data" -#~ msgstr "EXIF-data" - -#~ msgid "Delete EXIF data" -#~ msgstr "Tag bort EXIF-data" - -#~ msgid "Basic EXIF data" -#~ msgstr "Grundläggande EXIF-data" - -#~ msgid "All EXIF data" -#~ msgstr "All EXIF-data" - -#~ msgid "tags index file error: %s" -#~ msgstr "taggindexfilfel: %s" - -#~ msgid "save select area as a file" -#~ msgstr "spara valt område som en fil" - -#~ msgid "new tags index will now be created" -#~ msgstr "nytt taggindex kommer nu att skapas" - -#~ msgid "manage tags" -#~ msgstr "hantera märken" - -#~ msgid "color select firewall" -#~ msgstr "färgvälj brandvägg" - -#~ msgid "cannot read .dist file" -#~ msgstr "kan ej läsa .dist-fil" - -#~ msgid "brightness to clip (percent)" -#~ msgstr "ljushet att klippa vid (procent)" - -#~ msgid "Use F1 for context help" -#~ msgstr "Använd F1 för sammanhangshjälp" - -#~ msgid "Stack" -#~ msgstr "Stack" - -#~ msgid "Rebuild Tags Index" -#~ msgstr "Bygg om taggindex" - -#~ msgid "No tags index file" -#~ msgstr "Ingen taggindexfil" - -#~ msgid "" -#~ "New tags file already exists! \n" -#~ "Proceed anyway?" -#~ msgstr "" -#~ "Ny flaggor finns redan!\n" -#~ "Fortsätta ändå?" - -#~ msgid "HDR" -#~ msgstr "HDR" - -#~ msgid "HDF" -#~ msgstr "HDF" - -#~ msgid "" -#~ "Convert tags to new standard now? \n" -#~ "Are your image files backed-up?" -#~ msgstr "" -#~ "Omvandla flaggor till ny standard nu?\n" -#~ "Är dina bildfiler säkerhetskopierade?" - -#~ msgid "Convert tags to new standard" -#~ msgstr "Omvandla taggar till ny standard" - -#~ msgid "Convert Tags !!!" -#~ msgstr "Omvandla taggar !!!" - -#~ msgid "Constrain" -#~ msgstr "Begränsning" - -#~ msgid "Area" -#~ msgstr "Yta" - -#~ msgid "target group area" -#~ msgstr "mälgruppsområde" - -#~ msgid "vertical unbend" -#~ msgstr "vertikal uträtning" - -#~ msgid "select by mouse:" -#~ msgstr "välj med mus:" - -#~ msgid "select by color:" -#~ msgstr "välj genom färg:" - -#~ msgid "press ESC to exit" -#~ msgstr "tryck ESC för att avsluta" - -#~ msgid "horizontal unbend" -#~ msgstr "horisontell utslätning" - -#~ msgid "Rebuild Thumbnails" -#~ msgstr "Bygg om miniatyrbilder" - -#~ msgid "save collection" -#~ msgstr "spara samling" - -#~ msgid "open collection" -#~ msgstr "öppna samling" - -#~ msgid "area outline has a hole" -#~ msgstr "områdesbegränsning som ett hål" - -#~ msgid "" -#~ "Search all areas for edge and inside pixels. \n" -#~ "Click inside each enclosed area in sequence." -#~ msgstr "" -#~ "Sök all ytor efter kant och insidespixlar.\n" -#~ "Klicka på insida av varje inneslutet område i följd." - -#~ msgid "Open Image Collection" -#~ msgstr "Öppna bildsamling" - -#~ msgid "Make Image Collection" -#~ msgstr "Skapa bildsamling" - -#~ msgid "Create Launcher" -#~ msgstr "Skapa en startare" - -#~ msgid "range" -#~ msgstr "område" - -#~ msgid "package libimage-exiftool-perl is required" -#~ msgstr "paketet libimage-exiftool-perl krävs" - -#~ msgid "my mouse" -#~ msgstr "min mus" - -#~ msgid "limit" -#~ msgstr "gräns" - -#~ msgid "Width" -#~ msgstr "Bredd" - -#~ msgid "Unknown file type, save as tiff/jpeg/png to edit" -#~ msgstr "Okänd filtyp, spara som tiff/jpeg/png för att redigera" - -#~ msgid "Undo Last" -#~ msgstr "Ångra sista" - -#~ msgid "Undo All" -#~ msgstr "Ångra allt" - -#~ msgid "Threshold" -#~ msgstr "Tröskel" - -#~ msgid "Start" -#~ msgstr "Start" - -#~ msgid "Select Files" -#~ msgstr "Välj filer" - -#~ msgid "Search" -#~ msgstr "Sök" - -#~ msgid "Reduce" -#~ msgstr "Minska" - -#~ msgid "Red" -#~ msgstr "Röd" - -#~ msgid "Proceed" -#~ msgstr "Fortsätt" - -#~ msgid "Presets" -#~ msgstr "Förinställningar" - -#~ msgid "Percent" -#~ msgstr "Procent" - -#~ msgid "Pause" -#~ msgstr "Paus" - -#~ msgid "OK" -#~ msgstr "OK" - -#~ msgid "Lighter Areas" -#~ msgstr "Ljusare områden" - -#~ msgid "Insert" -#~ msgstr "Infoga" - -#~ msgid "Height" -#~ msgstr "Höjd" - -#~ msgid "Green" -#~ msgstr "Grön" - -#~ msgid "Font" -#~ msgstr "Typsnitt" - -#~ msgid "Finish" -#~ msgstr "Avsluta" - -#~ msgid "Fetch" -#~ msgstr "Hämta" - -#~ msgid "Erase" -#~ msgstr "Radera" - -#~ msgid "Edit" -#~ msgstr "Redigera" - -#~ msgid "Done" -#~ msgstr "Gjort" - -#~ msgid "Darker Areas" -#~ msgstr "Mörkare områden" - -#~ msgid "Clear" -#~ msgstr "Rensa" - -#~ msgid "Cancel" -#~ msgstr "Avbryt" - -#~ msgid "Browse" -#~ msgstr "Bläddra" - -#~ msgid "Brightness" -#~ msgstr "Ljushet" - -#~ msgid "Blue" -#~ msgstr "Blå" - -#~ msgid "Blend Width" -#~ msgstr "Bländaröppning" - -#~ msgid "Apply" -#~ msgstr "Tillämpa" - -#~ msgid "Amount" -#~ msgstr "Mängd" - -#~ msgid "Add All" -#~ msgstr "Lägg till allt" - -#~ msgid "make new version" -#~ msgstr "gör en ny version" - -#~ msgid "click on window to show RGB" -#~ msgstr "klicka på fönster för att visa RGB" - -#~ msgid "Save As" -#~ msgstr "Spara som" - -#~ msgid "Clone fotoxx" -#~ msgstr "Klona fotoxx" - -#~ msgid "random" -#~ msgstr "slumpvis" - -#~ msgid "Whole Image" -#~ msgstr "Hel bild" - -#~ msgid "Time Interval" -#~ msgstr "Tidsintervall" - -#~ msgid "Delete" -#~ msgstr "Tag bort" diff -Nru fotoxx-11.11.1/locales/sv/zfuncs.po fotoxx-12.01.2/locales/sv/zfuncs.po --- fotoxx-11.11.1/locales/sv/zfuncs.po 2011-11-05 05:30:37.000000000 +0000 +++ fotoxx-12.01.2/locales/sv/zfuncs.po 1970-01-01 00:00:00.000000000 +0000 @@ -1,291 +0,0 @@ -# translation of zfuncs.po to svenska -# Swedish translations for zfuncs package -# Svenska översättningar för paket zfuncs. -# Copyright (C) 2010 THE zfuncs'S COPYRIGHT HOLDER -# This file is distributed under the same license as the zfuncs package. -# -# progdev , 2010. -# Peter Landgren , 2010. -msgid "" -msgstr "" -"Project-Id-Version: zfuncs\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2011-11-05 05:49+0100\n" -"PO-Revision-Date: 2010-11-04 09:12+0100\n" -"Last-Translator: Peter Landgren \n" -"Language-Team: Swedish \n" -"Language: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Lokalize 1.0\n" - -#: zfuncs.cc:3192 -#, c-format -msgid "help file not found: %s" -msgstr "hjälpfil ej hittad: %s" - -#: zfuncs.cc:3296 -#, c-format -msgid "error: %s" -msgstr "fel: %s" - -#: zfuncs.cc:4415 zfuncs.cc:8771 -#, c-format -msgid "cannot open file %s" -msgstr "kan ej öppna fil %s" - -#: zfuncs.cc:4448 -msgid "save screen to file" -msgstr "spara skärmbild i fil" - -#: zfuncs.cc:6198 -msgid "No" -msgstr "Nej" - -#: zfuncs.cc:6198 -msgid "Yes" -msgstr "Ja" - -#: zfuncs.cc:6272 zfuncs.cc:6308 zfuncs.cc:6461 zfuncs.cc:6865 zfuncs.cc:8358 -#: zfuncs.cc:8883 zfuncs.cc:8889 zfuncs.cc:8895 zfuncs.cc:8901 -msgid "cancel" -msgstr "avbryt" - -#: zfuncs.cc:6423 zfuncs.cc:7552 -msgid "open" -msgstr "öppna" - -#: zfuncs.cc:6428 -msgid "choose" -msgstr "välj" - -#: zfuncs.cc:6433 -msgid "save" -msgstr "spara" - -#: zfuncs.cc:6439 -msgid "open folder" -msgstr "öppna mapp" - -#: zfuncs.cc:6444 -msgid "create folder" -msgstr "skapa mapp" - -#: zfuncs.cc:6450 -msgid "hidden" -msgstr "gömd" - -#: zfuncs.cc:6454 -msgid "quality" -msgstr "kvalitet" - -#: zfuncs.cc:6511 -msgid "JPG quality 0-100" -msgstr "JPG-kvalitet 0-100" - -#: zfuncs.cc:6865 zfuncs.cc:8358 -msgid "done" -msgstr "klart" - -#: zfuncs.cc:6865 zfuncs.cc:6878 -msgid "margins" -msgstr "" - -#: zfuncs.cc:6874 -msgid "top" -msgstr "" - -#: zfuncs.cc:6875 -msgid "bottom" -msgstr "" - -#: zfuncs.cc:6876 -msgid "left" -msgstr "" - -#: zfuncs.cc:6877 -msgid "right" -msgstr "" - -#: zfuncs.cc:7278 zfuncs.cc:7532 zfuncs.cc:7670 zfuncs.cc:7671 zfuncs.cc:7673 -msgid "bigger" -msgstr "större" - -#: zfuncs.cc:7278 -msgid "increase thumbnail size" -msgstr "öka miniatyrbildstorlek" - -#: zfuncs.cc:7279 -msgid "reduce thumbnail size" -msgstr "minska miniatyrbildstorlek" - -#: zfuncs.cc:7279 zfuncs.cc:7542 zfuncs.cc:7672 zfuncs.cc:7674 -msgid "smaller" -msgstr "mindre" - -#: zfuncs.cc:7280 zfuncs.cc:7571 -msgid "parent" -msgstr "förälder" - -#: zfuncs.cc:7280 -msgid "parent directory" -msgstr "föräldramapp" - -#: zfuncs.cc:7281 zfuncs.cc:7589 zfuncs.cc:7681 -msgid "first page" -msgstr "första sida" - -#: zfuncs.cc:7281 -msgid "jump to first file" -msgstr "hoppa till första fil" - -#: zfuncs.cc:7282 zfuncs.cc:7587 zfuncs.cc:7676 zfuncs.cc:7683 -msgid "prev page" -msgstr "föregående sida" - -#: zfuncs.cc:7282 -msgid "previous page" -msgstr "föregående sida" - -#: zfuncs.cc:7283 zfuncs.cc:7585 zfuncs.cc:7678 -msgid "prev row" -msgstr "föregående rad" - -#: zfuncs.cc:7283 -msgid "previous row" -msgstr "föregående rad" - -#: zfuncs.cc:7284 zfuncs.cc:7586 zfuncs.cc:7679 -msgid "next row" -msgstr "nästa rad" - -#: zfuncs.cc:7285 zfuncs.cc:7588 zfuncs.cc:7677 zfuncs.cc:7684 -msgid "next page" -msgstr "nästa sida" - -#: zfuncs.cc:7286 -msgid "jump to last file" -msgstr "hoppa till sista fil" - -#: zfuncs.cc:7286 zfuncs.cc:7590 zfuncs.cc:7682 -msgid "last page" -msgstr "sista sida" - -#: zfuncs.cc:7287 zfuncs.cc:7527 -msgid "close" -msgstr "stäng" - -#: zfuncs.cc:7287 -msgid "close image gallery" -msgstr "stäng bildgalleri" - -#: zfuncs.cc:7558 -msgid "select new file" -msgstr "välj ny fil" - -#: zfuncs.cc:8358 -msgid "Select Files" -msgstr "Välj filer" - -#: zfuncs.cc:8366 -msgid "delete" -msgstr "tag bort" - -#: zfuncs.cc:8367 -msgid "insert" -msgstr "sätt in" - -#: zfuncs.cc:8368 -msgid "add all" -msgstr "lägg till allt" - -#: zfuncs.cc:8658 -msgid "" -"Initial parameters file created. \n" -"Inspect and revise if necessary." -msgstr "" -"Startparameterfil skapad. \n" -"Undersök och ändra vid behov." - -#: zfuncs.cc:8674 -msgid "load parameters from a file" -msgstr "ladda parametrar från fil" - -#: zfuncs.cc:8743 -msgid "save parameters to a file" -msgstr "spara parametrar i en fil" - -#: zfuncs.cc:8881 zfuncs.cc:8887 zfuncs.cc:8893 zfuncs.cc:8899 -msgid "edit parameters" -msgstr "redigera parametrar" - -#: zfuncs.cc:8882 zfuncs.cc:8888 -msgid "" -"list\n" -"all" -msgstr "" -"lista\n" -"allt" - -#: zfuncs.cc:8882 zfuncs.cc:8888 zfuncs.cc:8894 zfuncs.cc:8900 -msgid "" -"load\n" -"file" -msgstr "" -"ladda\n" -"fil" - -#: zfuncs.cc:8882 zfuncs.cc:8888 zfuncs.cc:8894 zfuncs.cc:8900 -msgid "" -"save\n" -"file" -msgstr "" -"spara\n" -"fil" - -#: zfuncs.cc:8883 zfuncs.cc:8895 -msgid "" -"add\n" -"new" -msgstr "" -"lägg till\n" -"nytt" - -#: zfuncs.cc:8883 zfuncs.cc:8889 zfuncs.cc:8895 zfuncs.cc:8901 -msgid "apply" -msgstr "tillämpa" - -#: zfuncs.cc:8935 -msgid "apply?" -msgstr "tillämpa?" - -#: zfuncs.cc:8992 -msgid "(new parm name)" -msgstr "(nytt parameternamn)" - -#: zfuncs.cc:8992 -msgid "add parameter" -msgstr "lägg till parameter" - -#~ msgid "print" -#~ msgstr "skriv" - -#~ msgid "printer ID" -#~ msgstr "skrivar-ID" - -#~ msgid "paper format" -#~ msgstr "pappersformat" - -#~ msgid "portrait" -#~ msgstr "stående" - -#~ msgid "landscape" -#~ msgstr "liggande" - -#~ msgid "paper format is crazy" -#~ msgstr "galet pappersformat" - -#~ msgid "open a file" -#~ msgstr "öppna en fil" diff -Nru fotoxx-11.11.1/locales/zh_CN/fotoxx.po fotoxx-12.01.2/locales/zh_CN/fotoxx.po --- fotoxx-11.11.1/locales/zh_CN/fotoxx.po 2011-11-05 05:30:37.000000000 +0000 +++ fotoxx-12.01.2/locales/zh_CN/fotoxx.po 1970-01-01 00:00:00.000000000 +0000 @@ -1,2761 +0,0 @@ -# -# <>, YEAR, 2010. -# Jie , 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: fotoxx\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2011-11-05 05:49+0100\n" -"PO-Revision-Date: 2010-09-08 19:28+1000\n" -"Last-Translator: Jie \n" -"Language-Team: Simplified Chinese <18n-translation@lists.linux.net.cn>\n" -"Language: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: UTF-8\n" -"X-Poedit-Language: Simplified Chinese\n" -"X-Poedit-Country: China PRC\n" -"X-Poedit-SourceCharset: utf-8\n" -"Plural-Forms: nplurals=1; plural=0\n" - -#: fotoxx-11.11.1.cc:179 -msgid "File" -msgstr "文件" - -#: fotoxx-11.11.1.cc:180 fotoxx-11.11.1.cc:316 -msgid "Image Gallery" -msgstr "图像浏览" - -#: fotoxx-11.11.1.cc:181 -msgid "Clone 50/50" -msgstr "" - -#: fotoxx-11.11.1.cc:182 -msgid "Clone Overlay" -msgstr "" - -#: fotoxx-11.11.1.cc:183 fotoxx-11.11.1.cc:317 fotoxx-11.11.1.cc:2272 -#: fotoxx-11.11.1.cc:2444 -msgid "Open Image File" -msgstr "打开图像文件" - -#: fotoxx-11.11.1.cc:184 -msgid "Open in New Window" -msgstr "" - -#: fotoxx-11.11.1.cc:185 fotoxx-11.11.1.cc:318 -msgid "Open Previous File" -msgstr "打开前一个文件" - -#: fotoxx-11.11.1.cc:186 -msgid "Open Recent File" -msgstr "打开最近的文件" - -#: fotoxx-11.11.1.cc:187 fotoxx-11.11.1.cc:326 -msgid "Save to Same File" -msgstr "保存到原文件" - -#: fotoxx-11.11.1.cc:188 fotoxx-11.11.1.cc:327 -msgid "Save to New Version" -msgstr "" - -#: fotoxx-11.11.1.cc:189 fotoxx-11.11.1.cc:328 -msgid "Save to New File" -msgstr "保存到新文件" - -#: fotoxx-11.11.1.cc:190 fotoxx-11.11.1.cc:2990 -msgid "Create Blank Image" -msgstr "" - -#: fotoxx-11.11.1.cc:191 -msgid "Trash Image File" -msgstr "丢入可回收文件夹" - -#: fotoxx-11.11.1.cc:192 fotoxx-11.11.1.cc:3216 -msgid "Rename Image File" -msgstr "图像文件改名" - -#: fotoxx-11.11.1.cc:193 -msgid "Batch Rename Files" -msgstr "批量重命名文件" - -#: fotoxx-11.11.1.cc:194 -msgid "Print Image File" -msgstr "打印图像文件" - -#: fotoxx-11.11.1.cc:195 fotoxx-11.11.1.cc:332 -msgid "Quit fotoxx" -msgstr "退出 fotoxx" - -#: fotoxx-11.11.1.cc:197 -msgid "Tools" -msgstr "工具" - -#: fotoxx-11.11.1.cc:198 fotoxx_tools.cc:70 -msgid "Manage Collections" -msgstr "" - -#: fotoxx-11.11.1.cc:199 fotoxx_tools.cc:373 -msgid "Move Collections" -msgstr "" - -#: fotoxx-11.11.1.cc:200 -msgid "Check Monitor" -msgstr "检查显示器" - -#: fotoxx-11.11.1.cc:201 fotoxx_tools.cc:550 -msgid "Monitor Gamma" -msgstr "" - -#: fotoxx-11.11.1.cc:202 -msgid "Brightness Graph" -msgstr "亮度分布图" - -#: fotoxx-11.11.1.cc:203 fotoxx_tools.cc:819 -msgid "Slide Show" -msgstr "演示" - -#: fotoxx-11.11.1.cc:204 fotoxx_tools.cc:1668 -msgid "Show RGB" -msgstr "显示RGB" - -#: fotoxx-11.11.1.cc:205 fotoxx_tools.cc:1962 -msgid "Grid Lines" -msgstr "网格线" - -#: fotoxx-11.11.1.cc:206 fotoxx_tools.cc:2135 -msgid "Lens Parameters" -msgstr "镜头参数" - -#: fotoxx-11.11.1.cc:207 -msgid "Change Language" -msgstr "改变语言" - -#: fotoxx-11.11.1.cc:209 -msgid "Add Menu and Launcher" -msgstr "" - -#: fotoxx-11.11.1.cc:210 -msgid "Convert RAW files" -msgstr "转化RAW文件" - -#: fotoxx-11.11.1.cc:211 -msgid "Burn Images to CD/DVD" -msgstr "刻录图片到CD/DVD" - -#: fotoxx-11.11.1.cc:212 fotoxx_tools.cc:2460 -msgid "E-mail Images" -msgstr "" - -#: fotoxx-11.11.1.cc:213 fotoxx_tools.cc:2783 -msgid "Synchronize Files" -msgstr "" - -#: fotoxx-11.11.1.cc:214 fotoxx_tools.cc:3376 -msgid "Toolbar Style" -msgstr "" - -#: fotoxx-11.11.1.cc:215 -msgid "Memory Usage" -msgstr "" - -#: fotoxx-11.11.1.cc:218 -msgid "Edit Caption/Comments" -msgstr "" - -#: fotoxx-11.11.1.cc:219 fotoxx_info.cc:156 -msgid "Edit Tags" -msgstr "修改标签" - -#: fotoxx-11.11.1.cc:220 fotoxx_info.cc:345 -msgid "Manage Tags" -msgstr "" - -#: fotoxx-11.11.1.cc:221 fotoxx_info.cc:1345 -msgid "Batch Add Tags" -msgstr "批量添加标签" - -#: fotoxx-11.11.1.cc:222 fotoxx_info.cc:1547 -msgid "Batch Delete Tag" -msgstr "批量删除标签" - -#: fotoxx-11.11.1.cc:223 -msgid "View Info (short)" -msgstr "" - -#: fotoxx-11.11.1.cc:224 -msgid "View Info (long)" -msgstr "" - -#: fotoxx-11.11.1.cc:225 fotoxx_info.cc:1883 -msgid "Edit Info" -msgstr "" - -#: fotoxx-11.11.1.cc:226 fotoxx_info.cc:1981 -msgid "Delete Info" -msgstr "" - -#: fotoxx-11.11.1.cc:227 -msgid "Search Images" -msgstr "" - -#: fotoxx-11.11.1.cc:229 fotoxx-11.11.1.cc:230 -msgid "Select" -msgstr "选择" - -#: fotoxx-11.11.1.cc:231 -msgid "Show" -msgstr "显示" - -#: fotoxx-11.11.1.cc:232 -msgid "Hide" -msgstr "隐藏" - -#: fotoxx-11.11.1.cc:233 -msgid "Enable" -msgstr "开启" - -#: fotoxx-11.11.1.cc:234 -msgid "Disable" -msgstr "禁止" - -#: fotoxx-11.11.1.cc:235 -msgid "Invert" -msgstr "反色" - -#: fotoxx-11.11.1.cc:236 -msgid "Unselect" -msgstr "" - -#: fotoxx-11.11.1.cc:237 -msgid "Copy" -msgstr "复制" - -#: fotoxx-11.11.1.cc:238 -msgid "Paste" -msgstr "粘贴" - -#: fotoxx-11.11.1.cc:239 fotoxx-11.11.1.cc:317 fotoxx_retouch.cc:2314 -#: fotoxx_retouch.cc:2319 -msgid "Open" -msgstr "打开" - -#: fotoxx-11.11.1.cc:240 fotoxx-11.11.1.cc:326 -msgid "Save" -msgstr "保存" - -#: fotoxx-11.11.1.cc:241 fotoxx_area.cc:2215 -msgid "Select Whole Image" -msgstr "" - -#: fotoxx-11.11.1.cc:242 -msgid "Select and Edit" -msgstr "" - -#: fotoxx-11.11.1.cc:244 -msgid "Transform" -msgstr "变形" - -#: fotoxx-11.11.1.cc:245 fotoxx_transform.cc:60 -msgid "Rotate Image" -msgstr "旋转图像" - -#: fotoxx-11.11.1.cc:246 fotoxx_transform.cc:346 -msgid "Trim Image" -msgstr "剪裁图像" - -#: fotoxx-11.11.1.cc:247 fotoxx_transform.cc:972 -msgid "Resize Image" -msgstr "改变尺寸" - -#: fotoxx-11.11.1.cc:248 -msgid "Batch Resize/Export" -msgstr "" - -#: fotoxx-11.11.1.cc:249 fotoxx_transform.cc:1436 -msgid "Annotate Image" -msgstr "" - -#: fotoxx-11.11.1.cc:250 fotoxx_transform.cc:2193 -msgid "Flip Image" -msgstr "翻转图像" - -#: fotoxx-11.11.1.cc:251 fotoxx_transform.cc:2303 -msgid "Make Negative" -msgstr "反色" - -#: fotoxx-11.11.1.cc:252 fotoxx_transform.cc:2420 -msgid "Unbend Image" -msgstr "拉伸图像" - -#: fotoxx-11.11.1.cc:253 fotoxx_transform.cc:2704 -msgid "Keystone Correction" -msgstr "" - -#: fotoxx-11.11.1.cc:254 fotoxx_transform.cc:3013 -msgid "Warp Image (area)" -msgstr "" - -#: fotoxx-11.11.1.cc:255 fotoxx_transform.cc:3255 -msgid "Warp Image (curved)" -msgstr "" - -#: fotoxx-11.11.1.cc:256 fotoxx_transform.cc:3518 -msgid "Warp Image (linear)" -msgstr "" - -#: fotoxx-11.11.1.cc:257 fotoxx_transform.cc:3782 -msgid "Warp Image (affine)" -msgstr "扭曲图像(affine)" - -#: fotoxx-11.11.1.cc:259 -msgid "Retouch" -msgstr "修正" - -#: fotoxx-11.11.1.cc:260 -msgid "Brightness/Color" -msgstr "调节亮度和色彩" - -#: fotoxx-11.11.1.cc:261 -msgid "Gamma Curves" -msgstr "" - -#: fotoxx-11.11.1.cc:262 -msgid "Expand Brightness" -msgstr "扩展亮度" - -#: fotoxx-11.11.1.cc:263 -msgid "Flatten Brightness" -msgstr "白平衡" - -#: fotoxx-11.11.1.cc:264 -msgid "Brightness Ramp" -msgstr "亮度光谱" - -#: fotoxx-11.11.1.cc:265 fotoxx_retouch.cc:1729 -msgid "Tone Mapping" -msgstr "色调映射" - -#: fotoxx-11.11.1.cc:266 -msgid "White Balance" -msgstr "白平衡" - -#: fotoxx-11.11.1.cc:267 -msgid "Match Colors" -msgstr "" - -#: fotoxx-11.11.1.cc:269 fotoxx_retouch.cc:2941 -msgid "Revise RGB" -msgstr "" - -#: fotoxx-11.11.1.cc:270 -msgid "Red Eyes" -msgstr "红眼" - -#: fotoxx-11.11.1.cc:271 -msgid "Blur Image" -msgstr "模糊图像" - -#: fotoxx-11.11.1.cc:272 fotoxx_retouch.cc:4077 -msgid "Sharpen Image" -msgstr "锐化图片" - -#: fotoxx-11.11.1.cc:273 -msgid "Reduce Noise" -msgstr "减少噪点" - -#: fotoxx-11.11.1.cc:274 fotoxx_retouch.cc:4881 -msgid "Smart Erase" -msgstr "" - -#: fotoxx-11.11.1.cc:275 fotoxx_retouch.cc:5271 -msgid "Remove Dust" -msgstr "" - -#: fotoxx-11.11.1.cc:276 fotoxx_retouch.cc:5877 -msgid "Edit Pixels" -msgstr "绘画" - -#: fotoxx-11.11.1.cc:278 -msgid "Art" -msgstr "艺术" - -#: fotoxx-11.11.1.cc:279 -msgid "Color Depth" -msgstr "色深" - -#: fotoxx-11.11.1.cc:280 -msgid "Drawing" -msgstr "" - -#: fotoxx-11.11.1.cc:281 -msgid "Outlines" -msgstr "" - -#: fotoxx-11.11.1.cc:282 -msgid "Embossing" -msgstr "" - -#: fotoxx-11.11.1.cc:283 -msgid "Tiles" -msgstr "" - -#: fotoxx-11.11.1.cc:284 -msgid "Dots" -msgstr "" - -#: fotoxx-11.11.1.cc:285 -msgid "Painting" -msgstr "" - -#: fotoxx-11.11.1.cc:287 -msgid "Combine" -msgstr "接合" - -#: fotoxx-11.11.1.cc:288 -msgid "High Dynamic Range" -msgstr "" - -#: fotoxx-11.11.1.cc:289 -msgid "High Depth of Field" -msgstr "" - -#: fotoxx-11.11.1.cc:290 -msgid "Stack / Paint" -msgstr "" - -#: fotoxx-11.11.1.cc:291 -msgid "Stack / Noise" -msgstr "" - -#: fotoxx-11.11.1.cc:292 -msgid "Panorama" -msgstr "全景" - -#: fotoxx-11.11.1.cc:293 -msgid "Vertical Panorama" -msgstr "" - -#: fotoxx-11.11.1.cc:296 -msgid "Edit Plugins" -msgstr "" - -#: fotoxx-11.11.1.cc:305 fotoxx-11.11.1.cc:333 fotoxx-11.11.1.cc:4616 -msgid "Help" -msgstr "帮助" - -#: fotoxx-11.11.1.cc:306 fotoxx-11.11.1.cc:4606 -msgid "About" -msgstr "关于" - -#: fotoxx-11.11.1.cc:307 fotoxx-11.11.1.cc:4610 -msgid "User Guide" -msgstr "用户指南" - -#: fotoxx-11.11.1.cc:308 fotoxx-11.11.1.cc:4613 -msgid "User Guide Changes" -msgstr "" - -#: fotoxx-11.11.1.cc:309 fotoxx-11.11.1.cc:4622 -msgid "Edit Functions Summary" -msgstr "" - -#: fotoxx-11.11.1.cc:310 fotoxx-11.11.1.cc:4625 -msgid "Change Log" -msgstr "变动" - -#: fotoxx-11.11.1.cc:311 fotoxx-11.11.1.cc:4628 -msgid "Translations" -msgstr "" - -#: fotoxx-11.11.1.cc:312 fotoxx-11.11.1.cc:4631 -msgid "Home Page" -msgstr "主页" - -#: fotoxx-11.11.1.cc:316 -msgid "Gallery" -msgstr "浏览" - -#: fotoxx-11.11.1.cc:318 fotoxx_transform.cc:995 -msgid "Prev" -msgstr "上一张" - -#: fotoxx-11.11.1.cc:319 -msgid "Next" -msgstr "下一张" - -#: fotoxx-11.11.1.cc:319 -msgid "Open Next File" -msgstr "打开下一个文件" - -#: fotoxx-11.11.1.cc:320 -msgid "Zoom-in (bigger)" -msgstr "拉近 (更大)" - -#: fotoxx-11.11.1.cc:321 -msgid "Zoom-out (smaller)" -msgstr "拉远 (更小)" - -#: fotoxx-11.11.1.cc:322 -msgid "Undo" -msgstr "取消" - -#: fotoxx-11.11.1.cc:322 -msgid "Undo One Edit" -msgstr "取消一次编辑" - -#: fotoxx-11.11.1.cc:323 -msgid "Redo" -msgstr "重复" - -#: fotoxx-11.11.1.cc:323 -msgid "Redo One Edit" -msgstr "重复一次编辑" - -#: fotoxx-11.11.1.cc:327 -msgid "Save+V" -msgstr "" - -#: fotoxx-11.11.1.cc:328 -msgid "Save+F" -msgstr "" - -#: fotoxx-11.11.1.cc:329 -msgid "Move Image to Trash" -msgstr "移动图片到可回收文件夹" - -#: fotoxx-11.11.1.cc:329 -msgid "Trash" -msgstr "可回收文件夹" - -#: fotoxx-11.11.1.cc:332 -msgid "Quit" -msgstr "退出" - -#: fotoxx-11.11.1.cc:333 -msgid "Fotoxx Essentials" -msgstr "Fotoxx基础" - -#: fotoxx-11.11.1.cc:429 -msgid "first time startup" -msgstr "" - -#: fotoxx-11.11.1.cc:1815 -msgid "Exceed 50 anchor points" -msgstr "超出了 50 个锚点" - -#: fotoxx-11.11.1.cc:2000 -msgid "load curve from a file" -msgstr "" - -#: fotoxx-11.11.1.cc:2053 -msgid "curve file is invalid" -msgstr "" - -#: fotoxx-11.11.1.cc:2058 -msgid "curve file has different no. of curves" -msgstr "" - -#: fotoxx-11.11.1.cc:2073 -msgid "save curve to a file" -msgstr "" - -#: fotoxx-11.11.1.cc:2420 -#, c-format -msgid "" -"Discard special gallery list? \n" -" %s" -msgstr "" - -#: fotoxx-11.11.1.cc:2430 fotoxx-11.11.1.cc:4452 -msgid "prior function still active" -msgstr "" - -#: fotoxx-11.11.1.cc:2607 -msgid "Overwrite original file?" -msgstr "" - -#: fotoxx-11.11.1.cc:2608 -msgid "Do not warn again" -msgstr "" - -#: fotoxx-11.11.1.cc:2624 -msgid "Warning" -msgstr "" - -#: fotoxx-11.11.1.cc:2747 -msgid "Save File" -msgstr "保存文件" - -#: fotoxx-11.11.1.cc:2770 -msgid "quality" -msgstr "质量" - -#: fotoxx-11.11.1.cc:2772 -msgid "make current" -msgstr "" - -#: fotoxx-11.11.1.cc:2829 -msgid "jpeg quality must be 1-100" -msgstr "jpeg 质量必须在 1-100 间" - -#: fotoxx-11.11.1.cc:2851 -#, c-format -msgid "" -"Overwrite file? \n" -" %s" -msgstr "" -"覆盖文件? \n" -" %s" - -#: fotoxx-11.11.1.cc:2992 -msgid "file name" -msgstr "" - -#: fotoxx-11.11.1.cc:2997 fotoxx_transform.cc:351 -msgid "width" -msgstr "" - -#: fotoxx-11.11.1.cc:3000 fotoxx_transform.cc:354 -msgid "height" -msgstr "" - -#: fotoxx-11.11.1.cc:3006 fotoxx_art.cc:628 fotoxx_retouch.cc:5881 -msgid "color" -msgstr "色彩" - -#: fotoxx-11.11.1.cc:3120 -msgid "" -"Linux standard trash is not supported. \n" -"Desktop trash folder will be created." -msgstr "" -"Linux标准回收站仍未支持。\n" -"将会建立桌面回收站。" - -#: fotoxx-11.11.1.cc:3138 -msgid "Move read-only file to trash?" -msgstr "移动只读图片到可回收文件夹" - -#: fotoxx-11.11.1.cc:3164 -#, c-format -msgid "Cannot create trash folder: %s" -msgstr "无法创建可回收文件夹: %s" - -#: fotoxx-11.11.1.cc:3172 fotoxx-11.11.1.cc:3178 -#, c-format -msgid "error: %s" -msgstr "错误:%s" - -#: fotoxx-11.11.1.cc:3221 -msgid "old name" -msgstr "旧名称" - -#: fotoxx-11.11.1.cc:3222 -msgid "rename to" -msgstr "改名为" - -#: fotoxx-11.11.1.cc:3223 -msgid "previous" -msgstr "前一个" - -#: fotoxx-11.11.1.cc:3309 -msgid "The target file already exists" -msgstr "目标文件已经存在" - -#: fotoxx-11.11.1.cc:3317 -#, c-format -msgid "" -"Rename failed: \n" -" %s" -msgstr "" - -#: fotoxx-11.11.1.cc:3365 -msgid "Batch Rename" -msgstr "批量重命名" - -#: fotoxx-11.11.1.cc:3368 fotoxx-11.11.1.cc:3420 fotoxx_info.cc:1513 -#: fotoxx_info.cc:1767 fotoxx_tools.cc:2510 fotoxx_transform.cc:1213 -#, c-format -msgid "%d files selected" -msgstr "" - -#: fotoxx-11.11.1.cc:3370 -msgid "new base name" -msgstr "新基础名称" - -#: fotoxx-11.11.1.cc:3373 -msgid "starting sequence" -msgstr "开始顺序" - -#: fotoxx-11.11.1.cc:3375 -msgid "increment" -msgstr "增量" - -#: fotoxx-11.11.1.cc:3396 -msgid "select files to rename" -msgstr "选择文件改名" - -#: fotoxx-11.11.1.cc:3401 -msgid "base name / sequence / increment not reasonable" -msgstr "基础名称/顺序/增量 不可达成" - -#: fotoxx-11.11.1.cc:3460 -msgid "new file already exists:" -msgstr "新文件已经存在:" - -#: fotoxx-11.11.1.cc:3468 -msgid "filespec too long:" -msgstr "文件特性太长:" - -#: fotoxx-11.11.1.cc:3479 -msgid "Rename failed:" -msgstr "重命名失败:" - -#: fotoxx-11.11.1.cc:3739 -msgid "Add" -msgstr "" - -#: fotoxx-11.11.1.cc:3739 -msgid "Remove" -msgstr "" - -#: fotoxx-11.11.1.cc:3741 -msgid "menu name" -msgstr "" - -#: fotoxx-11.11.1.cc:3812 fotoxx-11.11.1.cc:3833 -msgid "Restart Fotoxx to update plugin menu" -msgstr "" - -#: fotoxx-11.11.1.cc:3927 -msgid "cannot parallel edit" -msgstr "" - -#: fotoxx-11.11.1.cc:3937 -msgid "" -"exiftool is not installed \n" -"edited images will lose EXIF data" -msgstr "" -"exiftool未安装 \n" -"修改图片会丢失EXIF数据" - -#: fotoxx-11.11.1.cc:3943 -msgid "Too many edits, please save image" -msgstr "编辑太多了,请保存图片" - -#: fotoxx-11.11.1.cc:3948 -msgid "" -"Select area cannot be kept.\n" -"Continue?" -msgstr "" -"选择区域无法保留。\n" -"继续吗?" - -#: fotoxx-11.11.1.cc:3956 -msgid "" -"Select area not active.\n" -"Continue?" -msgstr "" -"选择非活动区域。\n" -"继续?" - -#: fotoxx-11.11.1.cc:4427 -msgid "Discard edits?" -msgstr "" - -#: fotoxx-11.11.1.cc:4428 -msgid "" -"This action will discard current edits.\n" -"Continue to discard edits.\n" -"Go Back to keep edits." -msgstr "" - -#: fotoxx-11.11.1.cc:4431 -msgid "Continue" -msgstr "" - -#: fotoxx-11.11.1.cc:4432 -msgid "Go Back" -msgstr "" - -#: fotoxx-11.11.1.cc:5240 -msgid "cannot open thumbnail file" -msgstr "无法打开缩略图" - -#: fotoxx-11.11.1.cc:5433 fotoxx-11.11.1.cc:5549 -msgid "TIFF open failure" -msgstr "TIFF开启失败" - -#: fotoxx-11.11.1.cc:5449 -#, c-format -msgid "TIFF bits/color=%d not supported" -msgstr "TIFF 色深(bits/color)=%d 不支持" - -#: fotoxx-11.11.1.cc:5464 fotoxx-11.11.1.cc:5502 -msgid "TIFF read failure" -msgstr "TIFF读取失败" - -#: fotoxx-11.11.1.cc:5608 -msgid "TIFF write failure" -msgstr "TIFF写错误" - -#: fotoxx-11.11.1.cc:5638 -msgid "file type not supported" -msgstr "文件类型不支持" - -#: fotoxx-11.11.1.cc:5745 -msgid "pixbuf write failure" -msgstr "pixbuf 写入错误" - -#: fotoxx_area.cc:54 fotoxx_area.cc:2427 -msgid "Select Area for Edits" -msgstr "选择编辑区域" - -#: fotoxx_area.cc:55 fotoxx_area.cc:2428 -msgid "Press F1 for help" -msgstr "" - -#: fotoxx_area.cc:63 -msgid "" -"Select Area not supported \n" -"by this edit function" -msgstr "" - -#: fotoxx_area.cc:99 fotoxx_tools.cc:809 -msgid "rectangle" -msgstr "" - -#: fotoxx_area.cc:100 fotoxx_tools.cc:810 -msgid "ellipse" -msgstr "" - -#: fotoxx_area.cc:101 -msgid "draw: freehand" -msgstr "绘制:绘画" - -#: fotoxx_area.cc:102 -msgid "draw: follow edge" -msgstr "绘制:紧随边缘" - -#: fotoxx_area.cc:103 -msgid "select by mouse" -msgstr "" - -#: fotoxx_area.cc:104 -msgid "select by color" -msgstr "" - -#: fotoxx_area.cc:112 -msgid "radius" -msgstr "半径" - -#: fotoxx_area.cc:116 -msgid "match" -msgstr "对应" - -#: fotoxx_area.cc:121 -msgid "firewall" -msgstr "" - -#: fotoxx_area.cc:274 fotoxx_area.cc:415 -#, c-format -msgid "exceed %d edits" -msgstr "超出 %d 编辑" - -#: fotoxx_area.cc:992 -msgid "" -"Click one time inside each enclosed area \n" -"(possible gaps in the outline will be found). \n" -"Press F1 for help." -msgstr "" - -#: fotoxx_area.cc:1049 -msgid "finish area" -msgstr "结束区域" - -#: fotoxx_area.cc:1083 -msgid "searching" -msgstr "搜索中" - -#: fotoxx_area.cc:1155 -msgid "outline has a gap" -msgstr "" - -#: fotoxx_area.cc:1157 -msgid "success" -msgstr "成功" - -#: fotoxx_area.cc:1401 fotoxx_area.cc:1430 -msgid "the area is not finished" -msgstr "此区域未完成" - -#: fotoxx_area.cc:1522 -msgid "Edge calculation in progress" -msgstr "正在进行边缘计算" - -#: fotoxx_area.cc:1531 -msgid "Area Edge Calc" -msgstr "区域边缘计算" - -#: fotoxx_area.cc:1824 -msgid "position with mouse click/drag" -msgstr "" - -#: fotoxx_area.cc:1848 -msgid "Paste Image" -msgstr "粘贴图像" - -#: fotoxx_area.cc:1863 -msgid "angle" -msgstr "" - -#: fotoxx_area.cc:2127 -msgid "load select area from a file" -msgstr "读取一个文件的选定区域" - -#: fotoxx_area.cc:2161 -msgid "cannot open .tiff and .info files" -msgstr "" - -#: fotoxx_area.cc:2180 -msgid "save select area to a file" -msgstr "" - -#: fotoxx_area.cc:2216 -msgid "Edit Function Amplifier" -msgstr "" - -#: fotoxx_area.cc:2459 -msgid "mouse radius" -msgstr "" - -#: fotoxx_area.cc:2462 -msgid "power: center" -msgstr "" - -#: fotoxx_area.cc:2464 -msgid "edge" -msgstr "" - -#: fotoxx_area.cc:2468 -msgid "reset area" -msgstr "" - -#: fotoxx_area.cc:2523 -msgid "start edit function first" -msgstr "" - -#: fotoxx_art.cc:47 -msgid "Set color depth to 1-16 bits" -msgstr "设置色深为 1-16bit" - -#: fotoxx_art.cc:57 -msgid "Set Color Depth" -msgstr "设置色深" - -#: fotoxx_art.cc:171 -msgid "Simulate Drawing" -msgstr "绘图" - -#: fotoxx_art.cc:213 fotoxx_retouch.cc:1758 -msgid "contrast" -msgstr "对比度" - -#: fotoxx_art.cc:215 -msgid "outlines" -msgstr "轮廓" - -#: fotoxx_art.cc:220 -msgid "pencil" -msgstr "铅笔" - -#: fotoxx_art.cc:221 -msgid "chalk" -msgstr "粉笔" - -#: fotoxx_art.cc:381 -msgid "Add Image Outlines" -msgstr "" - -#: fotoxx_art.cc:394 -msgid "outline threshold" -msgstr "" - -#: fotoxx_art.cc:397 -msgid "outline width" -msgstr "" - -#: fotoxx_art.cc:400 -msgid "image brightness" -msgstr "" - -#: fotoxx_art.cc:611 -msgid "Simulate Embossing" -msgstr "浮雕" - -#: fotoxx_art.cc:626 -msgid "depth" -msgstr "宽度" - -#: fotoxx_art.cc:821 -msgid "Simulate Tiles" -msgstr "图块(马赛克)" - -#: fotoxx_art.cc:825 -msgid "tile size" -msgstr "图块尺寸" - -#: fotoxx_art.cc:829 -msgid "tile gap" -msgstr "图块边距" - -#: fotoxx_art.cc:1003 -msgid "Convert Image to Dots" -msgstr "" - -#: fotoxx_art.cc:1007 -msgid "dot size" -msgstr "" - -#: fotoxx_art.cc:1222 -msgid "Simulate Painting" -msgstr "彩绘" - -#: fotoxx_art.cc:1226 -msgid "color depth" -msgstr "色深" - -#: fotoxx_art.cc:1230 -msgid "patch area goal" -msgstr "" - -#: fotoxx_art.cc:1234 -msgid "req. color match" -msgstr "需要色彩匹配" - -#: fotoxx_art.cc:1238 -msgid "borders" -msgstr "边框" - -#: fotoxx_comp.cc:1956 fotoxx_comp.cc:1961 fotoxx_comp.cc:2582 -#: fotoxx_comp.cc:2587 fotoxx_comp.cc:3275 fotoxx_comp.cc:3280 -#: fotoxx_comp.cc:3830 fotoxx_comp.cc:3835 -msgid "Select 2 to 9 files" -msgstr "选择2到9个文件" - -#: fotoxx_comp.cc:1982 fotoxx_comp.cc:2608 fotoxx_comp.cc:3301 -#: fotoxx_comp.cc:3856 -msgid "Images are not all the same size" -msgstr "图像不全为同样尺寸" - -#: fotoxx_comp.cc:2321 -msgid "Adjust Image Contributions" -msgstr "调整图像输出" - -#: fotoxx_comp.cc:2324 fotoxx_retouch.cc:885 -msgid "dark pixels" -msgstr "暗 像素" - -#: fotoxx_comp.cc:2326 -msgid "light pixels" -msgstr "亮像素" - -#: fotoxx_comp.cc:2328 fotoxx_info.cc:159 -msgid "file:" -msgstr "文件:" - -#: fotoxx_comp.cc:2844 -msgid "Paint and Warp Image" -msgstr "涂画和扭曲图像" - -#: fotoxx_comp.cc:2847 fotoxx_comp.cc:3529 fotoxx_comp.cc:4972 -#: fotoxx_comp.cc:5717 -msgid "image" -msgstr "图像" - -#: fotoxx_comp.cc:2851 fotoxx_retouch.cc:5885 -msgid "paint" -msgstr "绘制(黑白)" - -#: fotoxx_comp.cc:2852 -msgid "warp" -msgstr "扭曲" - -#: fotoxx_comp.cc:3527 -msgid "Select and Paint Image" -msgstr "" - -#: fotoxx_comp.cc:4045 -msgid "Adjust Pixel Composition" -msgstr "调整像素合成" - -#: fotoxx_comp.cc:4297 fotoxx_comp.cc:4302 fotoxx_comp.cc:5186 -#: fotoxx_comp.cc:5191 -msgid "Select 2 to 4 files" -msgstr "选择2到4个文件" - -#: fotoxx_comp.cc:4374 -msgid "" -"Drag images into rough alignment.\n" -"To rotate, drag from lower edge." -msgstr "" -"拖拽图像粗略排布。\n" -"拖动下进行旋转。" - -#: fotoxx_comp.cc:4376 -msgid "Search for lens mm and bow" -msgstr "搜索" - -#: fotoxx_comp.cc:4422 fotoxx_comp.cc:5310 -msgid "Pre-align Images" -msgstr "预对齐 图像" - -#: fotoxx_comp.cc:4426 fotoxx_comp.cc:5314 fotoxx_tools.cc:2151 -msgid "lens mm" -msgstr "镜头焦距" - -#: fotoxx_comp.cc:4430 fotoxx_comp.cc:5318 fotoxx_tools.cc:2156 -msgid "lens bow" -msgstr "镜头弓度" - -#: fotoxx_comp.cc:4432 fotoxx_comp.cc:5320 -msgid "Resize" -msgstr "改变尺寸" - -#: fotoxx_comp.cc:4433 fotoxx_comp.cc:5321 -msgid "resize window" -msgstr "改变窗口尺寸" - -#: fotoxx_comp.cc:4470 -msgid "use two images only" -msgstr "使用两个图像" - -#: fotoxx_comp.cc:4491 fotoxx_comp.cc:4689 fotoxx_comp.cc:4888 -#: fotoxx_comp.cc:5369 fotoxx_comp.cc:5632 -msgid "Too little overlap, cannot align" -msgstr "太多重叠,无法对齐" - -#: fotoxx_comp.cc:4963 fotoxx_comp.cc:5708 -msgid "Match Brightness and Color" -msgstr "匹配亮度和色彩" - -#: fotoxx_comp.cc:4987 fotoxx_comp.cc:5732 -msgid "auto color" -msgstr "自动上色" - -#: fotoxx_comp.cc:4988 fotoxx_comp.cc:5733 -msgid "file color" -msgstr "文件色彩" - -#: fotoxx_comp.cc:5263 -msgid "" -"Drag images into rough alignment.\n" -"To rotate, drag from right edge." -msgstr "" - -#: fotoxx_info.cc:70 -msgid "Edit Caption and Comments" -msgstr "" - -#: fotoxx_info.cc:163 -msgid "image date (yyyymmdd)" -msgstr "图片日期(年月日──yyyymmdd)" - -#: fotoxx_info.cc:165 -msgid "use last" -msgstr "最后使用" - -#: fotoxx_info.cc:168 -msgid "image stars" -msgstr "图像点" - -#: fotoxx_info.cc:186 -msgid "current tags" -msgstr "当前标签" - -#: fotoxx_info.cc:191 -msgid "recent tags" -msgstr "最近的标签" - -#: fotoxx_info.cc:196 fotoxx_info.cc:358 fotoxx_info.cc:1362 -#: fotoxx_info.cc:2290 -msgid "defined tags" -msgstr "定义的标签" - -#: fotoxx_info.cc:348 -msgid "category" -msgstr "分类" - -#: fotoxx_info.cc:351 -msgid "tag" -msgstr "标签" - -#: fotoxx_info.cc:354 -msgid "create" -msgstr "创造" - -#: fotoxx_info.cc:355 -msgid "delete" -msgstr "删除" - -#: fotoxx_info.cc:1229 fotoxx_info.cc:1313 -#, c-format -msgid "search index file error: %s" -msgstr "" - -#: fotoxx_info.cc:1348 -msgid "tags to add" -msgstr "要添加的标签" - -#: fotoxx_info.cc:1353 -msgid "create tag" -msgstr "创建标签" - -#: fotoxx_info.cc:1409 fotoxx_info.cc:1602 -#, c-format -msgid "" -"%s \n" -" too many tags" -msgstr "" -"%s \n" -" 太多标签" - -#: fotoxx_info.cc:1550 -msgid "tag to remove" -msgstr "将要移除的标签" - -#: fotoxx_info.cc:1554 -msgid "optional replacement" -msgstr "可选的替代" - -#: fotoxx_info.cc:1559 fotoxx_tools.cc:2463 -msgid "0 files selected" -msgstr "" - -#: fotoxx_info.cc:1562 -msgid "search all files" -msgstr "搜索全部文件" - -#: fotoxx_info.cc:1647 -msgid "no files selected" -msgstr "" - -#: fotoxx_info.cc:1653 -msgid "no tag specified" -msgstr "" - -#: fotoxx_info.cc:1677 fotoxx_info.cc:1706 -msgid "specify tag" -msgstr "" - -#: fotoxx_info.cc:1815 -msgid "View Info" -msgstr "" - -#: fotoxx_info.cc:1983 -msgid "All" -msgstr "全部" - -#: fotoxx_info.cc:1984 -msgid "One Key:" -msgstr "一键:" - -#: fotoxx_info.cc:2249 -msgid "Search Tags, Comments, File Names" -msgstr "" - -#: fotoxx_info.cc:2255 -msgid "date range" -msgstr "日期范围" - -#: fotoxx_info.cc:2256 -msgid "stars range" -msgstr "点范围" - -#: fotoxx_info.cc:2257 -msgid "search tags" -msgstr "搜索标签" - -#: fotoxx_info.cc:2258 -msgid "search text" -msgstr "" - -#: fotoxx_info.cc:2259 -msgid "file names" -msgstr "" - -#: fotoxx_info.cc:2264 -msgid "(yyyymmdd)" -msgstr "" - -#: fotoxx_info.cc:2270 -msgid "all/any" -msgstr "" - -#: fotoxx_info.cc:2598 -msgid "No matching images found" -msgstr "未找到对应图片" - -#: fotoxx_info.cc:2611 -msgid "No search index file present" -msgstr "" - -#: fotoxx_info.cc:2615 -#, c-format -msgid "Search results file error %s" -msgstr "搜索结果文件错误 %s" - -#: fotoxx_retouch.cc:55 -msgid "Adjust Brightness and Color" -msgstr "调节亮度和色彩" - -#: fotoxx_retouch.cc:109 -msgid "small-steps" -msgstr "" - -#: fotoxx_retouch.cc:118 -msgid "color saturation" -msgstr "色彩饱和度" - -#: fotoxx_retouch.cc:125 -msgid " reset 1 " -msgstr " 重置 1" - -#: fotoxx_retouch.cc:126 -msgid "reset all" -msgstr "全部重置" - -#: fotoxx_retouch.cc:598 -msgid "adjust image gamma" -msgstr "" - -#: fotoxx_retouch.cc:884 -msgid "Expand Brightness Range" -msgstr "扩展亮度范围" - -#: fotoxx_retouch.cc:886 -msgid "bright pixels" -msgstr "亮度像素" - -#: fotoxx_retouch.cc:1057 -msgid "Flatten Brightness Distribution" -msgstr "使亮度平均分布" - -#: fotoxx_retouch.cc:1071 -msgid "Flatten" -msgstr "白平衡" - -#: fotoxx_retouch.cc:1333 -msgid "Ramp brightness across image" -msgstr "全图光谱亮度" - -#: fotoxx_retouch.cc:1757 -msgid "low" -msgstr "" - -#: fotoxx_retouch.cc:1759 -msgid "high" -msgstr "" - -#: fotoxx_retouch.cc:1762 -msgid "Amplify" -msgstr "" - -#: fotoxx_retouch.cc:2068 -msgid "Adjust White Balance" -msgstr "自动白平衡" - -#: fotoxx_retouch.cc:2069 -msgid "Click white or gray image location" -msgstr "点击白色或灰色图像位置" - -#: fotoxx_retouch.cc:2283 -msgid "Color Match Images" -msgstr "" - -#: fotoxx_retouch.cc:2312 -msgid "mouse radius for color sample" -msgstr "" - -#: fotoxx_retouch.cc:2315 -msgid "image for source color" -msgstr "" - -#: fotoxx_retouch.cc:2317 -msgid "click on image to get source color" -msgstr "" - -#: fotoxx_retouch.cc:2320 -msgid "image to set matching color" -msgstr "" - -#: fotoxx_retouch.cc:2322 -msgid "click on image to set matching color" -msgstr "" - -#: fotoxx_retouch.cc:2377 -msgid "select source image color first" -msgstr "" - -#: fotoxx_retouch.cc:2903 fotoxx_tools.cc:1643 -msgid "Click image to select pixels." -msgstr "" - -#: fotoxx_retouch.cc:2955 -msgid "Metric:" -msgstr "" - -#: fotoxx_retouch.cc:3010 -msgid "Blend" -msgstr "" - -#: fotoxx_retouch.cc:3394 -msgid "" -"Method 1:\n" -" Left-click on red-eye to darken.\n" -"Method 2:\n" -" Drag down and right to enclose red-eye.\n" -" Left-click on red-eye to darken.\n" -"Undo red-eye:\n" -" Right-click on red-eye." -msgstr "" -"方法一:\n" -" 鼠标左键点击红眼使其变暗。\n" -"方法二:\n" -" 拖动包围红眼。\n" -" 鼠标左键点击红眼使其变暗。\n" -"取消:\n" -" 鼠标右键点击。" - -#: fotoxx_retouch.cc:3409 -msgid "Red Eye Reduction" -msgstr "红眼减弱" - -#: fotoxx_retouch.cc:3850 -msgid "Set Blur Radius" -msgstr "设置模糊半径" - -#: fotoxx_retouch.cc:4084 -msgid "edge detection" -msgstr "边缘探测" - -#: fotoxx_retouch.cc:4085 -msgid "cycles" -msgstr "周期" - -#: fotoxx_retouch.cc:4086 -msgid "reduce" -msgstr "减小" - -#: fotoxx_retouch.cc:4097 -msgid "unsharp mask" -msgstr "模糊" - -#: fotoxx_retouch.cc:4110 -msgid "brightness gradient" -msgstr "亮度渐变" - -#: fotoxx_retouch.cc:4516 -msgid "" -" Press the reduce button to \n" -" reduce noise in small steps. \n" -" Use undo to start over." -msgstr "" -" 按下“减少”按钮 \n" -" 来减少噪点。 \n" -" 按下“重置”重新开始" - -#: fotoxx_retouch.cc:4527 -msgid "Noise Reduction" -msgstr "降噪" - -#: fotoxx_retouch.cc:4532 -msgid "algorithm" -msgstr "算法" - -#: fotoxx_retouch.cc:4539 -msgid "flatten outliers by color (1)" -msgstr "依据色彩(1) 平滑外部" - -#: fotoxx_retouch.cc:4540 -msgid "flatten outliers by color (2)" -msgstr "依据色彩(2) 平滑外部" - -#: fotoxx_retouch.cc:4541 -msgid "set median brightness by color" -msgstr "通过色彩设置居中亮度" - -#: fotoxx_retouch.cc:4542 fotoxx_retouch.cc:4543 -msgid "top hat filter by color" -msgstr "根基色彩进行 Top Hat 滤波" - -#: fotoxx_retouch.cc:4858 -msgid "" -"1. Drag mouse to select. \n" -"2. Erase. 3. Repeat. " -msgstr "" - -#: fotoxx_retouch.cc:4889 -msgid "Radius" -msgstr "半径" - -#: fotoxx_retouch.cc:4891 -msgid "Blur" -msgstr "" - -#: fotoxx_retouch.cc:4894 -msgid "New Area" -msgstr "" - -#: fotoxx_retouch.cc:5275 -msgid "spot size limit" -msgstr "" - -#: fotoxx_retouch.cc:5278 -msgid "max. brightness" -msgstr "" - -#: fotoxx_retouch.cc:5281 -msgid "min. contrast" -msgstr "" - -#: fotoxx_retouch.cc:5875 -#, c-format -msgid "Undo Memory %d%c" -msgstr "取消记忆 %d%c" - -#: fotoxx_retouch.cc:5884 -msgid "pick" -msgstr "抓取" - -#: fotoxx_retouch.cc:5886 -msgid "erase" -msgstr "擦除" - -#: fotoxx_retouch.cc:5894 -msgid "paintbrush radius" -msgstr "刷子半径" - -#: fotoxx_retouch.cc:5895 -msgid "transparency center" -msgstr "透明中心" - -#: fotoxx_retouch.cc:5896 -msgid "transparency edge" -msgstr "透明边缘" - -#: fotoxx_retouch.cc:6166 -msgid "" -"Undo memory limit has been reached. \n" -"Save work with [done], then resume editing." -msgstr "" -"“取消”的内存限制(100MB)已经用尽。\n" -"按下[完成]保存,然后继续编辑。" - -#: fotoxx_tools.cc:42 -msgid "" -"When editing a collection, right-click \n" -"an image or thumbnail to add or remove." -msgstr "" - -#: fotoxx_tools.cc:85 -msgid "Start new collection" -msgstr "" - -#: fotoxx_tools.cc:87 -msgid "Edit a collection" -msgstr "" - -#: fotoxx_tools.cc:89 -msgid "View a collection" -msgstr "" - -#: fotoxx_tools.cc:91 -msgid "Delete a collection" -msgstr "" - -#: fotoxx_tools.cc:95 -msgid "Editing:" -msgstr "" - -#: fotoxx_tools.cc:99 -msgid "Action:" -msgstr "" - -#: fotoxx_tools.cc:133 -msgid "New Collection" -msgstr "" - -#: fotoxx_tools.cc:156 -msgid "Edit Collection" -msgstr "" - -#: fotoxx_tools.cc:172 -msgid "View Collection" -msgstr "" - -#: fotoxx_tools.cc:193 -msgid "Delete Collection" -msgstr "" - -#: fotoxx_tools.cc:196 -#, c-format -msgid "delete %s ?" -msgstr "" - -#: fotoxx_tools.cc:223 -#, c-format -msgid "add image to collection: %s" -msgstr "" - -#: fotoxx_tools.cc:225 fotoxx_tools.cc:270 -msgid "remove image from collection" -msgstr "" - -#: fotoxx_tools.cc:226 fotoxx_tools.cc:271 fotoxx_tools.cc:298 -msgid "remove and save image" -msgstr "" - -#: fotoxx_tools.cc:227 fotoxx_tools.cc:316 -msgid "insert saved images here" -msgstr "" - -#: fotoxx_tools.cc:256 -msgid "add image to collection" -msgstr "" - -#: fotoxx_tools.cc:301 -msgid "too many saved files" -msgstr "" - -#: fotoxx_tools.cc:375 -msgid "old top directory" -msgstr "" - -#: fotoxx_tools.cc:378 -msgid "new top directory" -msgstr "" - -#: fotoxx_tools.cc:434 -msgid "completed" -msgstr "已完成" - -#: fotoxx_tools.cc:452 -msgid "" -"Brightness should show a gradual ramp \n" -"extending all the way to the edges." -msgstr "" - -#: fotoxx_tools.cc:492 -msgid "Monitor Check" -msgstr "" - -#: fotoxx_tools.cc:612 -msgid "Brightness Distribution" -msgstr "亮度分布" - -#: fotoxx_tools.cc:796 -msgid "Press ESC to exit slide show" -msgstr "" - -#: fotoxx_tools.cc:797 -msgid "show only latest file versions" -msgstr "" - -#: fotoxx_tools.cc:801 -msgid "arrow keys" -msgstr "" - -#: fotoxx_tools.cc:802 -msgid "instant" -msgstr "" - -#: fotoxx_tools.cc:803 -msgid "fade-in" -msgstr "" - -#: fotoxx_tools.cc:804 -msgid "roll-right" -msgstr "" - -#: fotoxx_tools.cc:805 -msgid "roll-down" -msgstr "" - -#: fotoxx_tools.cc:806 -msgid "shift-left" -msgstr "" - -#: fotoxx_tools.cc:807 -msgid "venetian" -msgstr "" - -#: fotoxx_tools.cc:808 -msgid "grate" -msgstr "" - -#: fotoxx_tools.cc:811 -msgid "radar" -msgstr "" - -#: fotoxx_tools.cc:812 -msgid "jaws" -msgstr "" - -#: fotoxx_tools.cc:823 -msgid "seconds" -msgstr "秒" - -#: fotoxx_tools.cc:827 -msgid "music file" -msgstr "" - -#: fotoxx_tools.cc:831 -msgid "transitions" -msgstr "" - -#: fotoxx_tools.cc:948 -msgid "Select music file or playlist" -msgstr "" - -#: fotoxx_tools.cc:1971 -msgid "x-spacing" -msgstr "" - -#: fotoxx_tools.cc:1972 -msgid "x-count" -msgstr "" - -#: fotoxx_tools.cc:1973 -msgid "x-enable" -msgstr "" - -#: fotoxx_tools.cc:1979 -msgid "y-spacing" -msgstr "" - -#: fotoxx_tools.cc:1980 -msgid "y-count" -msgstr "" - -#: fotoxx_tools.cc:1981 -msgid "y-enable" -msgstr "" - -#: fotoxx_tools.cc:1988 -msgid "x-offset" -msgstr "" - -#: fotoxx_tools.cc:1992 -msgid "y-offset" -msgstr "" - -#: fotoxx_tools.cc:2146 -msgid "lens name" -msgstr "镜面名称" - -#: fotoxx_tools.cc:2220 -msgid "Available Translations" -msgstr "可用翻译" - -#: fotoxx_tools.cc:2224 -msgid "Set Language" -msgstr "设置语言" - -#: fotoxx_tools.cc:2290 -msgid "Make Launcher" -msgstr "" - -#: fotoxx_tools.cc:2310 -msgid "Program ufraw-batch is required" -msgstr "需要程序 ufraw-batch" - -#: fotoxx_tools.cc:2320 -msgid "Open RAW File" -msgstr "打开原始文件(RAW文件)" - -#: fotoxx_tools.cc:2331 -msgid "Select RAW files to convert" -msgstr "选择要转化的RAW文件" - -#: fotoxx_tools.cc:2467 -msgid "max. width" -msgstr "" - -#: fotoxx_tools.cc:2468 -msgid "max. height" -msgstr "" - -#: fotoxx_tools.cc:2527 fotoxx_transform.cc:1268 -#, c-format -msgid "max. size %d x %d is not reasonable" -msgstr "最大尺寸 %d x %d 不可能" - -#: fotoxx_tools.cc:2613 -msgid "too many files" -msgstr "" - -#: fotoxx_tools.cc:2656 -msgid "Sync Files is already running" -msgstr "" - -#: fotoxx_tools.cc:2707 -msgid "" -"Run Tools > Synchronize Files so that gallery windows \n" -"will be fast and Search Images will work correctly. \n" -"You can view (not edit) images while synchronize runs." -msgstr "" - -#: fotoxx_tools.cc:2736 -msgid "no top image directory is defined" -msgstr "" - -#: fotoxx_tools.cc:2742 -msgid "top image directory is invalid" -msgstr "" - -#: fotoxx_tools.cc:2747 -msgid "no search index file is present" -msgstr "" - -#: fotoxx_tools.cc:2761 -msgid "new/modified files are present" -msgstr "" - -#: fotoxx_tools.cc:2768 -msgid "no new files found" -msgstr "" - -#: fotoxx_tools.cc:2785 -msgid "Top Image Directory:" -msgstr "顶部图像路径:" - -#: fotoxx_tools.cc:2807 -msgid "file sync is mandatory" -msgstr "" - -#: fotoxx_tools.cc:2817 -msgid "top directory is invalid" -msgstr "" - -#: fotoxx_tools.cc:3201 -msgid "Select top image directory" -msgstr "选择顶部图像位置" - -#: fotoxx_tools.cc:3378 -msgid "icons" -msgstr "" - -#: fotoxx_tools.cc:3379 fotoxx_transform.cc:1467 -msgid "text" -msgstr "" - -#: fotoxx_tools.cc:3380 -msgid "both" -msgstr "" - -#: fotoxx_transform.cc:50 -msgid "Use buttons or drag right edge with mouse" -msgstr "使用按钮或者鼠标拖到右面边缘" - -#: fotoxx_transform.cc:64 -msgid "degrees" -msgstr "角度" - -#: fotoxx_transform.cc:80 fotoxx_transform.cc:124 -msgid "Trim" -msgstr "剪裁" - -#: fotoxx_transform.cc:81 fotoxx_transform.cc:2437 fotoxx_transform.cc:3263 -#: fotoxx_transform.cc:3526 fotoxx_transform.cc:3787 -msgid "Grid" -msgstr "" - -#: fotoxx_transform.cc:123 -msgid "Undo Trim" -msgstr "取消剪切" - -#: fotoxx_transform.cc:139 -#, c-format -msgid "degrees: %.1f" -msgstr "角度: %.1f" - -#: fotoxx_transform.cc:286 -msgid "gold" -msgstr "" - -#: fotoxx_transform.cc:332 -msgid "Drag middle to move, drag corners to resize." -msgstr "拖动中部移动,拖动角落改变尺寸。" - -#: fotoxx_transform.cc:346 -msgid "customize" -msgstr "" - -#: fotoxx_transform.cc:357 -msgid "ratio" -msgstr "" - -#: fotoxx_transform.cc:361 -msgid "Lock Ratio" -msgstr "固定比例" - -#: fotoxx_transform.cc:367 -msgid "invert" -msgstr "反色" - -#: fotoxx_transform.cc:892 -msgid "Trim Buttons" -msgstr "" - -#: fotoxx_transform.cc:964 -msgid "Lock aspect ratio" -msgstr "锁定长宽比例" - -#: fotoxx_transform.cc:1145 -msgid "Batch Resize" -msgstr "批量改变尺寸" - -#: fotoxx_transform.cc:1153 -msgid "new max. width" -msgstr "新最大宽度" - -#: fotoxx_transform.cc:1154 -msgid "new max. height" -msgstr "新最大高度" - -#: fotoxx_transform.cc:1161 -msgid "replace originals" -msgstr "取代原有的" - -#: fotoxx_transform.cc:1162 -msgid "export to location" -msgstr "导出到" - -#: fotoxx_transform.cc:1166 -msgid "copy EXIF" -msgstr "复制EXIF" - -#: fotoxx_transform.cc:1219 -msgid "Select directory" -msgstr "选择路径" - -#: fotoxx_transform.cc:1243 -#, c-format -msgid "replace original files? (max. %d x %d)" -msgstr "取代原有文件? (max. %d x %d)" - -#: fotoxx_transform.cc:1250 -#, c-format -msgid "" -"copy files? (max. %d x %d) \n" -" to location %s" -msgstr "" -"复制文件?(最多 %d x %d) \n" -" 到 %s" - -#: fotoxx_transform.cc:1261 -msgid "location is not a valid directory" -msgstr "不可识别的位置" - -#: fotoxx_transform.cc:1304 -msgid "new file already exists" -msgstr "新文件已经存在" - -#: fotoxx_transform.cc:1388 -msgid "" -"Enter text, click/drag on image.\n" -"Right click to remove" -msgstr "" - -#: fotoxx_transform.cc:1442 -msgid "Text" -msgstr "" - -#: fotoxx_transform.cc:1449 -msgid "Size" -msgstr "尺寸" - -#: fotoxx_transform.cc:1452 -msgid "Angle" -msgstr "" - -#: fotoxx_transform.cc:1463 -msgid "Color" -msgstr "颜色" - -#: fotoxx_transform.cc:1464 -msgid "Transparency" -msgstr "" - -#: fotoxx_transform.cc:1472 -msgid "backing" -msgstr "" - -#: fotoxx_transform.cc:1475 -msgid "" -"Outline\n" -" Width" -msgstr "" - -#: fotoxx_transform.cc:1477 -msgid "outline" -msgstr "" - -#: fotoxx_transform.cc:1486 -msgid "Annotation File:" -msgstr "" - -#: fotoxx_transform.cc:1564 -msgid "select font" -msgstr "" - -#: fotoxx_transform.cc:2197 fotoxx_transform.cc:2429 -msgid "horizontal" -msgstr "水平" - -#: fotoxx_transform.cc:2198 fotoxx_transform.cc:2428 -msgid "vertical" -msgstr "垂直" - -#: fotoxx_transform.cc:2306 -msgid "black/white positive" -msgstr "" - -#: fotoxx_transform.cc:2307 -msgid "black/white negative" -msgstr "" - -#: fotoxx_transform.cc:2308 -msgid "color positive" -msgstr "" - -#: fotoxx_transform.cc:2309 -msgid "color negative" -msgstr "" - -#: fotoxx_transform.cc:2430 -msgid "linear" -msgstr "" - -#: fotoxx_transform.cc:2433 -msgid "curved" -msgstr "" - -#: fotoxx_transform.cc:2692 -msgid "" -" Click the four corners of a tetragon area. Press [apply]. \n" -" The image is warped to make the tetragon into a rectangle." -msgstr "" - -#: fotoxx_transform.cc:2878 -msgid "must have 4 corners" -msgstr "" - -#: fotoxx_transform.cc:2999 -msgid "" -" Select an area to warp using select area function. \n" -" Press [start warp] and pull area with mouse. \n" -" Make multiple mouse pulls until satisfied. \n" -" When finished, select another area or press [done]." -msgstr "" -" 鼠标左键在图像一边按下扭曲图像 \n" -" 知道满意 \n" -" 要结束,按下[完成]" - -#: fotoxx_transform.cc:3018 -msgid "start warp" -msgstr "开始扭曲" - -#: fotoxx_transform.cc:3067 -msgid "Select area first" -msgstr "首先选择区域" - -#: fotoxx_transform.cc:3242 fotoxx_transform.cc:3505 -msgid "" -" Pull an image position using the mouse. \n" -" Make multiple mouse pulls until satisfied. \n" -" When finished, press [done]." -msgstr "" - -#: fotoxx_transform.cc:3771 -msgid "" -" Pull on an image corner using the mouse. \n" -" Make multiple mouse pulls until satisfied. \n" -" When finished, press [done]." -msgstr "" -" 鼠标左键在图像一边按下扭曲图像 \n" -" 知道满意 \n" -" 要结束,按下[完成]" - -#~ msgid "Translate" -#~ msgstr "翻译" - -#~ msgid "full rebuild" -#~ msgstr "完整重建" - -#~ msgid "incremental" -#~ msgstr "增量" - -#~ msgid "" -#~ "Rename failed \n" -#~ " %s" -#~ msgstr "" -#~ "重命名失败\n" -#~ " %s" - -#~ msgid "Discard modifications?" -#~ msgstr "放弃改动?" - -#~ msgid "histogram" -#~ msgstr "柱状图" - -#~ msgid "unknown image format" -#~ msgstr "未知图像格式" - -#~ msgid "unbend panorama image" -#~ msgstr "松弛全景图片" - -#~ msgid "trim image" -#~ msgstr "剪切图像" - -#~ msgid "toolbar::save" -#~ msgstr "工具栏::保存" - -#~ msgid "tags exceed %d characters" -#~ msgstr "标签超出 %d 个字符" - -#~ msgid "sharpen image" -#~ msgstr "锐化图像" - -#, fuzzy -#~ msgid "set blend radius" -#~ msgstr "设定模糊半径" - -#~ msgid "rotate image" -#~ msgstr "旋转图像" - -#~ msgid "resize image" -#~ msgstr "改变图像大小" - -#~ msgid "redo image changes" -#~ msgstr "重复图像改变" - -#~ msgid "red" -#~ msgstr "红" - -#~ msgid "recently added" -#~ msgstr "最近添加" - -#, fuzzy -#~ msgid "radius limit" -#~ msgstr "半径" - -#~ msgid "quit" -#~ msgstr "退出" - -#~ msgid "open image file" -#~ msgstr "打开图像文件" - -#~ msgid "open RAW file" -#~ msgstr "打开RAW文件" - -#~ msgid "open" -#~ msgstr "打开" - -#~ msgid "insert" -#~ msgstr "插入" - -#~ msgid "image not 8 or 16 bits/color: %s" -#~ msgstr "图像不是8位或16位色的: %s" - -#~ msgid "image format error: %s" -#~ msgstr "图像格式错误: %s" - -#~ msgid "grid spacing" -#~ msgstr "网格空间" - -#~ msgid "exiftool is required to generate tags index" -#~ msgstr "exiftool 是生成标签索引必备的" - -#~ msgid "exiftool is required to create tags" -#~ msgstr "需要exiftool创建标签" - -#~ msgid "exceed 100 anchor points" -#~ msgstr "超出100个轴心点" - -#~ msgid "computing" -#~ msgstr "计算中" - -#~ msgid "color balance" -#~ msgstr "色彩平衡 " - -#~ msgid "click or drag trim margins" -#~ msgstr "点击或者拖动剪裁界限" - -#~ msgid "" -#~ "cannot create %s \n" -#~ " %s" -#~ msgstr "" -#~ "无法创建 %s \n" -#~ " %s" - -#~ msgid "blur radius" -#~ msgstr "半径模糊" - -#~ msgid "blend" -#~ msgstr "色带" - -#~ msgid "assigned tags" -#~ msgstr "指定的标签" - -#~ msgid "Zoom-" -#~ msgstr "缩小" - -#~ msgid "Zoom+" -#~ msgstr "放大" - -#~ msgid "Warp Global" -#~ msgstr "全局扭曲" - -#, fuzzy -#~ msgid "Unable to replace file" -#~ msgstr "无法保存图像" - -#~ msgid "Tune Image" -#~ msgstr "色彩调节" - -#~ msgid "Total tags exceed %d characters" -#~ msgstr "全部标签超出 %d 字符。" - -#~ msgid "Too many tags: %d" -#~ msgstr "太多标签:%d" - -#, fuzzy -#~ msgid "Too many points" -#~ msgstr "太多点" - -#~ msgid "Thumbnail Index" -#~ msgstr "缩略图索引一个位置" - -#~ msgid "Special Art Effects" -#~ msgstr "艺术效果" - -#~ msgid "Simulate embossing" -#~ msgstr "模拟浮雕效果" - -#, fuzzy -#~ msgid "Show Area" -#~ msgstr "区域" - -#~ msgid "Sharp" -#~ msgstr "锐化" - -#~ msgid "Save Image as File" -#~ msgstr "保存图像文件到" - -#~ msgid "Rotate" -#~ msgstr "旋转" - -#~ msgid "README" -#~ msgstr "介绍" - -#~ msgid "RAW file template" -#~ msgstr "RAW文件模板" - -#~ msgid "Print" -#~ msgstr "打印" - -#~ msgid "Paint Pixels" -#~ msgstr "绘制像素" - -#, fuzzy -#~ msgid "Output Image" -#~ msgstr "输出图像" - -#~ msgid "Make HDR Image" -#~ msgstr "制作HDR图像(高动态范围成像)" - -#~ msgid "Make HDF Image" -#~ msgstr "制作HDF图像(高动态范围成像)" - -#, fuzzy -#~ msgid "Invert Area" -#~ msgstr "反色" - -#, fuzzy -#~ msgid "Input Images" -#~ msgstr "输出图像" - -#~ msgid "Index Tags and Thumbs" -#~ msgstr "索引标签和缩略图" - -#~ msgid "Index Tags" -#~ msgstr "索引标签" - -#~ msgid "Index (thumbnails)" -#~ msgstr "索引(缩略图)" - -#~ msgid "Index" -#~ msgstr "索引" - -#, fuzzy -#~ msgid "Image Weights per Brightness Level" -#~ msgstr "" -#~ "\n" -#~ " 每个亮度级别图像宽度 \n" - -#, fuzzy -#~ msgid "Hide Area" -#~ msgstr "选择区域" - -#, fuzzy -#~ msgid "HDR Image Weights" -#~ msgstr "HDR高度" - -#, fuzzy -#~ msgid "Flash" -#~ msgstr "回收站" - -#~ msgid "FREEIMAGE unknown error" -#~ msgstr "FREEIMAGE 未知错误" - -#~ msgid "FREEIMAGE error: %s" -#~ msgstr "FREEIMAGE 错误: %s" - -#~ msgid "Error Log" -#~ msgstr "错误记录" - -#~ msgid "" -#~ "Drag middle to move \n" -#~ "Drag corners to resize" -#~ msgstr "" -#~ "拖拽中部移动\n" -#~ "拖拽角落改变尺寸" - -#, fuzzy -#~ msgid "" -#~ "Drag and click to enclose an area.\n" -#~ "Use right click to undo prior." -#~ msgstr "" -#~ "用鼠标拖拽点击一个区域。\n" -#~ "鼠标右键点击取消上一次" - -#~ msgid "Distortion" -#~ msgstr "变形" - -#~ msgid "Dimensions" -#~ msgstr "整体" - -#, fuzzy -#~ msgid "Delete Area" -#~ msgstr "选择区域" - -#~ msgid "" -#~ "Convert raw file to 48-bit tiff format? \n" -#~ " (this may take a while) " -#~ msgstr "" -#~ "转换raw文件到48-bit tiff格式?\n" -#~ " (这可能需要较长一段时间) " - -#~ msgid "Convert multiple RAWs" -#~ msgstr "转化多个RAW文件" - -#~ msgid "Composite Images" -#~ msgstr "合成图像" - -#~ msgid "Clear Select Area" -#~ msgstr "清除选定区域" - -#~ msgid "Build Tags Index" -#~ msgstr "建立标签索引" - -#, fuzzy -#~ msgid "Blend Area Edges" -#~ msgstr "半径模糊" - -#~ msgid "Bend" -#~ msgstr "扭曲" - -#~ msgid "Add or Remove Grid Lines" -#~ msgstr "添加或者移除网格线" - -#~ msgid "2nd image not same size as 1st image" -#~ msgstr "第二图像和第一图像大小不同" - -#~ msgid "" -#~ "%s \n" -#~ " tag limit exceeded" -#~ msgstr "" -#~ "%s \n" -#~ " 标签限制突破" - -#~ msgid " color balance green " -#~ msgstr " 色彩平衡 绿" - -#~ msgid " color balance blue " -#~ msgstr " 色彩平衡 蓝" - -#~ msgid "" -#~ "\n" -#~ " brightness \n" -#~ " level" -#~ msgstr "" -#~ "\n" -#~ " 亮度 \n" -#~ " 级别" - -#~ msgid "jpeg quality" -#~ msgstr "jpeg 质量" - -#~ msgid "Current file must be included" -#~ msgstr "必须包括当前文件" - -#~ msgid "Retouch Image" -#~ msgstr "修饰图像" - -#~ msgid "Package ufraw required for this function" -#~ msgstr "此功能需要 ufraw 包" - -#~ msgid "Merge the images together" -#~ msgstr "图片融合在一起" - -#~ msgid "Match Images" -#~ msgstr "对应图像" - -#~ msgid "" -#~ "Drag right image into rough alignment with left \n" -#~ " to rotate, drag right edge up or down" -#~ msgstr "" -#~ "拖右面的图片与左面的成一条线\n" -#~ "进行翻转,货到有边缘上部或下部" - -#~ msgid "Auto" -#~ msgstr "自动" - -#~ msgid "" -#~ "\n" -#~ " Match Brightness and Color" -#~ msgstr "" -#~ "\n" -#~ " 对应亮度和颜色" - -#~ msgid "select image files to add tags" -#~ msgstr "选择要添加标签的文件" - -#~ msgid "rename files" -#~ msgstr "重命名文件" - -#~ msgid "freehand draw" -#~ msgstr "自由绘画" - -#~ msgid "color range" -#~ msgstr "色彩范围" - -#~ msgid "color intensity" -#~ msgstr "色彩亮度" - -#~ msgid "add tags" -#~ msgstr "添加标签" - -#~ msgid "Read File" -#~ msgstr "读取文件" - -#~ msgid "Fix Image Perspective" -#~ msgstr "修复图像透视" - -#~ msgid "Burn" -#~ msgstr "刻录" - -#~ msgid "" -#~ "position image\n" -#~ "with mouse drag" -#~ msgstr "" -#~ "使用鼠标拖拽\n" -#~ "确定图像位置" - -#~ msgid "Warp Image in Selected Area" -#~ msgstr "扭曲选中区域的图像" - -#~ msgid "Warp Image (curvy)" -#~ msgstr "扭曲图像(曲线)" - -#~ msgid "Warp Image" -#~ msgstr "扭曲图像" - -#~ msgid "Warp Area" -#~ msgstr "选定区域扭曲" - -#~ msgid "Open File" -#~ msgstr "打开文件" - -#~ msgid "" -#~ " Pull on an image edge using the mouse. \n" -#~ " Make multiple mouse pulls until satisfied. \n" -#~ " When finished, press [done]." -#~ msgstr "" -#~ " 鼠标左键在图像一边按下扭曲图像 \n" -#~ " 知道满意 \n" -#~ " 要结束,按下[完成]" - -#~ msgid "match any tag" -#~ msgstr "适合任意标签" - -#~ msgid "match all tags" -#~ msgstr "对应全部标签" - -#~ msgid "Tags" -#~ msgstr "标签" - -#~ msgid "Suspend" -#~ msgstr "暂停" - -#~ msgid "Set Tile and Gap Size" -#~ msgstr "设置图块和间距尺寸" - -#~ msgid "Search Tags" -#~ msgstr "搜索标签" - -#~ msgid "Resume" -#~ msgstr "继续" - -#~ msgid "Edit EXIF data" -#~ msgstr "修改 Exif 数据" - -#~ msgid "EXIF data" -#~ msgstr "Exif 数据\t" - -#~ msgid "Delete EXIF data" -#~ msgstr "删除 Exif 数据" - -#~ msgid "Basic EXIF data" -#~ msgstr "基本Exif数据" - -#~ msgid "All EXIF data" -#~ msgstr "全部Exif数据" - -#~ msgid "/path*/file*" -#~ msgstr "/path*/file*" - -#~ msgid "tags index file error: %s" -#~ msgstr "标签索引错误:%s" - -#~ msgid "save select area as a file" -#~ msgstr "选定区域保存为文件" - -#~ msgid "new tags index will now be created" -#~ msgstr "将创建新的标签索引" - -#~ msgid "manage tags" -#~ msgstr "管理标签" - -#~ msgid "cannot read .dist file" -#~ msgstr "无法读取 .dist 文件" - -#~ msgid "brightness to clip (percent)" -#~ msgstr "亮度剪切(比例)" - -#~ msgid "Use F1 for context help" -#~ msgstr "F1唤出帮助" - -#~ msgid "Stack" -#~ msgstr "堆放" - -#~ msgid "Rebuild Tags Index" -#~ msgstr "重建标签索引" - -#~ msgid "No tags index file" -#~ msgstr "无标签索引文件" - -#~ msgid "" -#~ "New tags file already exists! \n" -#~ "Proceed anyway?" -#~ msgstr "" -#~ "新标签文件已经存在!\n" -#~ "仍然继续吗?" - -#~ msgid "HDR" -#~ msgstr "HDR" - -#~ msgid "HDF" -#~ msgstr "HDF" - -#~ msgid "" -#~ "Convert tags to new standard now? \n" -#~ "Are your image files backed-up?" -#~ msgstr "" -#~ "是否现在把标签转化为新标准类型?\n" -#~ "您的图片已经备份了吗?" - -#~ msgid "Convert tags to new standard" -#~ msgstr "将标签转化为新标准" - -#~ msgid "Convert Tags !!!" -#~ msgstr "转换标签 !!!" - -#~ msgid "Constrain" -#~ msgstr "强制" - -#~ msgid "Area" -#~ msgstr "区域" - -#~ msgid "target group area" -#~ msgstr "瞄准组区域" - -#~ msgid "vertical unbend" -#~ msgstr "垂直拉伸" - -#~ msgid "select by mouse:" -#~ msgstr "鼠标选择" - -#~ msgid "select by color:" -#~ msgstr "根据色彩选择" - -#~ msgid "press ESC to exit" -#~ msgstr "按下ESC退出" - -#~ msgid "horizontal unbend" -#~ msgstr "水平拉伸" - -#~ msgid "Rebuild Thumbnails" -#~ msgstr "重建缩略图" - -#~ msgid "area outline has a hole" -#~ msgstr "区域轮廓有一个洞" - -#~ msgid "" -#~ "Search all areas for edge and inside pixels. \n" -#~ "Click inside each enclosed area in sequence." -#~ msgstr "" -#~ "搜索所有区域边缘/和内部像素。\n" -#~ "点击" - -#~ msgid "Create Launcher" -#~ msgstr "创建启动器" - -#~ msgid "range" -#~ msgstr "范围" - -#~ msgid "package libimage-exiftool-perl is required" -#~ msgstr "需要软件包 libimage-exiftool-perl " - -#~ msgid "limit" -#~ msgstr "限制" - -#~ msgid "Width" -#~ msgstr "宽度" - -#~ msgid "Unknown file type, save as tiff/jpeg/png to edit" -#~ msgstr "未知文件类型,保存为 tiff/jpeg/png 编辑" - -#~ msgid "Undo Last" -#~ msgstr "取消上一个" - -#~ msgid "Undo All" -#~ msgstr "取消全部" - -#~ msgid "Threshold" -#~ msgstr "门槛" - -#~ msgid "Start" -#~ msgstr "开始" - -#~ msgid "Select Files" -#~ msgstr "选择文件" - -#~ msgid "Search" -#~ msgstr "搜索" - -#~ msgid "Reduce" -#~ msgstr "减小" - -#~ msgid "Red" -#~ msgstr "红" - -#~ msgid "Proceed" -#~ msgstr "进行" - -#~ msgid "Presets" -#~ msgstr "预设" - -#~ msgid "Percent" -#~ msgstr "比例" - -#~ msgid "Pause" -#~ msgstr "暂停" - -#~ msgid "OK" -#~ msgstr "确定" - -#~ msgid "Lighter Areas" -#~ msgstr "较亮区域" - -#~ msgid "Insert" -#~ msgstr "插入" - -#~ msgid "Height" -#~ msgstr "高度" - -#~ msgid "Green" -#~ msgstr "绿" - -#~ msgid "Finish" -#~ msgstr "完成" - -#~ msgid "Fetch" -#~ msgstr "获取" - -#~ msgid "Edit" -#~ msgstr "修改" - -#~ msgid "Done" -#~ msgstr "完成" - -#~ msgid "Darker Areas" -#~ msgstr "较暗区域" - -#~ msgid "Clear" -#~ msgstr "清除" - -#~ msgid "Cancel" -#~ msgstr "取消" - -#~ msgid "Browse" -#~ msgstr "浏览" - -#~ msgid "Brightness" -#~ msgstr "亮度" - -#~ msgid "Blue" -#~ msgstr "蓝色" - -#~ msgid "Blend Width" -#~ msgstr "混合宽度" - -#~ msgid "Apply" -#~ msgstr "应用" - -#~ msgid "Amount" -#~ msgstr "总数" - -#~ msgid "Add All" -#~ msgstr "添加全部" - -#~ msgid "make new version" -#~ msgstr "新版本" - -#~ msgid "click on window to show RGB" -#~ msgstr "点击窗口显示 RGB" - -#~ msgid "Save As" -#~ msgstr "保存为" - -#~ msgid "Clone fotoxx" -#~ msgstr "复制一个 fotoxx 窗口" - -#~ msgid "Time Interval" -#~ msgstr "时间间隔" - -#~ msgid "Delete" -#~ msgstr "删除" diff -Nru fotoxx-11.11.1/locales/zh_CN/zfuncs.po fotoxx-12.01.2/locales/zh_CN/zfuncs.po --- fotoxx-11.11.1/locales/zh_CN/zfuncs.po 2011-11-05 05:30:37.000000000 +0000 +++ fotoxx-12.01.2/locales/zh_CN/zfuncs.po 1970-01-01 00:00:00.000000000 +0000 @@ -1,312 +0,0 @@ -# -# luojie , 2010. -# Jie , 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: 10.9\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2011-11-05 05:49+0100\n" -"PO-Revision-Date: 2010-09-08 13:52+1000\n" -"Last-Translator: Jie \n" -"Language-Team: Simplified Chinese <18n-translation@lists.linux.net.cn>\n" -"Language: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: UTF-8\n" -"X-Poedit-SourceCharset: utf-8\n" -"Plural-Forms: nplurals=1; plural=0\n" -"X-Poedit-Language: Chinese\n" -"X-Poedit-Country: CHINA\n" -"X-Poedit-Bookmarks: -1,1435,-1,-1,-1,-1,-1,-1,-1,-1\n" - -#: zfuncs.cc:3192 -#, c-format -msgid "help file not found: %s" -msgstr "没找到帮助文件: %s" - -#: zfuncs.cc:3296 -#, c-format -msgid "error: %s" -msgstr "错误: %s" - -#: zfuncs.cc:4415 zfuncs.cc:8771 -#, c-format -msgid "cannot open file %s" -msgstr "不能打开文件 %s" - -#: zfuncs.cc:4448 -msgid "save screen to file" -msgstr "保存屏幕到文件" - -#: zfuncs.cc:6198 -msgid "No" -msgstr "无" - -#: zfuncs.cc:6198 -msgid "Yes" -msgstr "是" - -#: zfuncs.cc:6272 zfuncs.cc:6308 zfuncs.cc:6461 zfuncs.cc:6865 zfuncs.cc:8358 -#: zfuncs.cc:8883 zfuncs.cc:8889 zfuncs.cc:8895 zfuncs.cc:8901 -msgid "cancel" -msgstr "取消" - -#: zfuncs.cc:6423 zfuncs.cc:7552 -msgid "open" -msgstr "打开" - -#: zfuncs.cc:6428 -msgid "choose" -msgstr "选择\t" - -#: zfuncs.cc:6433 -msgid "save" -msgstr "保存" - -#: zfuncs.cc:6439 -msgid "open folder" -msgstr "打开文件夹" - -#: zfuncs.cc:6444 -msgid "create folder" -msgstr "创造文件夹" - -#: zfuncs.cc:6450 -msgid "hidden" -msgstr "隐藏的" - -#: zfuncs.cc:6454 -msgid "quality" -msgstr "质量" - -#: zfuncs.cc:6511 -msgid "JPG quality 0-100" -msgstr "JPG 质量 0-100" - -#: zfuncs.cc:6865 zfuncs.cc:8358 -msgid "done" -msgstr "完成" - -#: zfuncs.cc:6865 zfuncs.cc:6878 -msgid "margins" -msgstr "" - -#: zfuncs.cc:6874 -msgid "top" -msgstr "" - -#: zfuncs.cc:6875 -msgid "bottom" -msgstr "" - -#: zfuncs.cc:6876 -msgid "left" -msgstr "" - -#: zfuncs.cc:6877 -msgid "right" -msgstr "" - -#: zfuncs.cc:7278 zfuncs.cc:7532 zfuncs.cc:7670 zfuncs.cc:7671 zfuncs.cc:7673 -msgid "bigger" -msgstr "放大" - -#: zfuncs.cc:7278 -msgid "increase thumbnail size" -msgstr "提升缩略图尺寸" - -#: zfuncs.cc:7279 -msgid "reduce thumbnail size" -msgstr "减小缩略图尺寸" - -#: zfuncs.cc:7279 zfuncs.cc:7542 zfuncs.cc:7672 zfuncs.cc:7674 -msgid "smaller" -msgstr "缩小" - -#: zfuncs.cc:7280 zfuncs.cc:7571 -msgid "parent" -msgstr "上级" - -#: zfuncs.cc:7280 -msgid "parent directory" -msgstr "上级目录" - -#: zfuncs.cc:7281 zfuncs.cc:7589 zfuncs.cc:7681 -msgid "first page" -msgstr "第一页" - -#: zfuncs.cc:7281 -msgid "jump to first file" -msgstr "跳至第一个文件" - -#: zfuncs.cc:7282 zfuncs.cc:7587 zfuncs.cc:7676 zfuncs.cc:7683 -msgid "prev page" -msgstr "前一页" - -#: zfuncs.cc:7282 -msgid "previous page" -msgstr "前一页" - -#: zfuncs.cc:7283 zfuncs.cc:7585 zfuncs.cc:7678 -msgid "prev row" -msgstr "前一行" - -#: zfuncs.cc:7283 -msgid "previous row" -msgstr "前一行" - -#: zfuncs.cc:7284 zfuncs.cc:7586 zfuncs.cc:7679 -msgid "next row" -msgstr "下一行" - -#: zfuncs.cc:7285 zfuncs.cc:7588 zfuncs.cc:7677 zfuncs.cc:7684 -msgid "next page" -msgstr "下一页" - -#: zfuncs.cc:7286 -msgid "jump to last file" -msgstr "跳至最后一个文件" - -#: zfuncs.cc:7286 zfuncs.cc:7590 zfuncs.cc:7682 -msgid "last page" -msgstr "上一页" - -#: zfuncs.cc:7287 zfuncs.cc:7527 -msgid "close" -msgstr "关闭" - -#: zfuncs.cc:7287 -msgid "close image gallery" -msgstr "关闭图像浏览" - -#: zfuncs.cc:7558 -msgid "select new file" -msgstr "选择新文件" - -#: zfuncs.cc:8358 -msgid "Select Files" -msgstr "选择文件" - -#: zfuncs.cc:8366 -msgid "delete" -msgstr "删除" - -#: zfuncs.cc:8367 -msgid "insert" -msgstr "插入" - -#: zfuncs.cc:8368 -msgid "add all" -msgstr "添加全部" - -#: zfuncs.cc:8658 -msgid "" -"Initial parameters file created. \n" -"Inspect and revise if necessary." -msgstr "" -"初始化参数文件。 \n" -"如必要,请检查。" - -#: zfuncs.cc:8674 -msgid "load parameters from a file" -msgstr "从一个文件读取参数" - -#: zfuncs.cc:8743 -msgid "save parameters to a file" -msgstr "保存参数到文件" - -#: zfuncs.cc:8881 zfuncs.cc:8887 zfuncs.cc:8893 zfuncs.cc:8899 -msgid "edit parameters" -msgstr "修改参数" - -#: zfuncs.cc:8882 zfuncs.cc:8888 -msgid "" -"list\n" -"all" -msgstr "" -"列表\n" -"全部" - -#: zfuncs.cc:8882 zfuncs.cc:8888 zfuncs.cc:8894 zfuncs.cc:8900 -msgid "" -"load\n" -"file" -msgstr "" -"读取\n" -"文件" - -#: zfuncs.cc:8882 zfuncs.cc:8888 zfuncs.cc:8894 zfuncs.cc:8900 -msgid "" -"save\n" -"file" -msgstr "" -"保存\n" -"文件" - -#: zfuncs.cc:8883 zfuncs.cc:8895 -msgid "" -"add\n" -"new" -msgstr "" -"添加\n" -"新" - -#: zfuncs.cc:8883 zfuncs.cc:8889 zfuncs.cc:8895 zfuncs.cc:8901 -msgid "apply" -msgstr "应用" - -#: zfuncs.cc:8935 -msgid "apply?" -msgstr "应用?" - -#: zfuncs.cc:8992 -msgid "(new parm name)" -msgstr "(新参数名)" - -#: zfuncs.cc:8992 -msgid "add parameter" -msgstr "添加参数" - -#~ msgid "print" -#~ msgstr "打印" - -#~ msgid "printer ID" -#~ msgstr "打印机ID" - -#~ msgid "paper format" -#~ msgstr "纸张格式" - -#~ msgid "portrait" -#~ msgstr "垂直" - -#~ msgid "landscape" -#~ msgstr "水平" - -#~ msgid "paper format is crazy" -#~ msgstr "疯狂的纸张格式" - -#~ msgid "open a file" -#~ msgstr "打开一个文件" - -#~ msgid "xdg-utils package not installed" -#~ msgstr "xdg-utils软件包没有安装" - -#~ msgid "select new folder" -#~ msgstr "选择新文件夹" - -#, fuzzy -#~ msgid "open a directory" -#~ msgstr "跳至新目录" - -#~ msgid "jump to specific file" -#~ msgstr "跳至指定文件" - -#~ msgid "folder" -#~ msgstr "文件夹" - -#~ msgid "file" -#~ msgstr "文件" - -#~ msgid "close thumbnail window" -#~ msgstr "关闭缩略图窗口" diff -Nru fotoxx-11.11.1/Makefile fotoxx-12.01.2/Makefile --- fotoxx-11.11.1/Makefile 2011-11-05 05:30:36.000000000 +0000 +++ fotoxx-12.01.2/Makefile 2012-01-04 08:47:11.000000000 +0000 @@ -1,6 +1,6 @@ # fotoxx makefile -PROGRAM = fotoxx-11.11.1.cc +VERSION = 12.01.2.cc # defaults for parameters that may be pre-defined CXXFLAGS ?= -O3 -g -Wall @@ -17,40 +17,44 @@ MENUFILE = $(PREFIX)/share/applications/kornelix-fotoxx.desktop CFLAGS = $(CXXFLAGS) -c `pkg-config --cflags gtk+-2.0` -LIBS = `pkg-config --libs gtk+-2.0 gthread-2.0` +LIBS = `pkg-config --libs gtk+-2.0` -fotoxx: fotoxx.o fotoxx_tools.o fotoxx_area.o fotoxx_info.o \ - fotoxx_retouch.o fotoxx_transform.o fotoxx_art.o fotoxx_comp.o \ - zfuncs.o - $(CXX) $(LDFLAGS) fotoxx.o fotoxx_tools.o fotoxx_area.o fotoxx_info.o \ - fotoxx_retouch.o fotoxx_transform.o fotoxx_art.o fotoxx_comp.o \ - zfuncs.o \ - $(LIBS) -ltiff -o fotoxx +fotoxx: fotoxx.o f.file.o f.tools.o f.select.o f.info.o f.retouch.o \ + f.transform.o f.art.o f.comp.o f.navi.o zfuncs.o + $(CXX) $(LDFLAGS) -o fotoxx fotoxx.o f.file.o f.tools.o f.select.o f.info.o \ + f.retouch.o f.transform.o f.art.o f.comp.o f.navi.o zfuncs.o \ + $(LIBS) -ltiff @ ./dependencies.sh -fotoxx.o: $(PROGRAM) fotoxx.h - $(CXX) $(CFLAGS) -o fotoxx.o $(PROGRAM) +fotoxx.o: fotoxx-$(VERSION) fotoxx.h + $(CXX) $(CFLAGS) -o fotoxx.o fotoxx-$(VERSION) -fotoxx_tools.o: fotoxx_tools.cc fotoxx.h - $(CXX) $(CFLAGS) fotoxx_tools.cc +f.file.o: f.file.cc fotoxx.h + $(CXX) $(CFLAGS) f.file.cc -fotoxx_area.o: fotoxx_area.cc fotoxx.h - $(CXX) $(CFLAGS) fotoxx_area.cc +f.tools.o: f.tools.cc fotoxx.h + $(CXX) $(CFLAGS) f.tools.cc -fotoxx_info.o: fotoxx_info.cc fotoxx.h - $(CXX) $(CFLAGS) fotoxx_info.cc +f.select.o: f.select.cc fotoxx.h + $(CXX) $(CFLAGS) f.select.cc -fotoxx_retouch.o: fotoxx_retouch.cc fotoxx.h - $(CXX) $(CFLAGS) fotoxx_retouch.cc +f.info.o: f.info.cc fotoxx.h + $(CXX) $(CFLAGS) f.info.cc -fotoxx_transform.o: fotoxx_transform.cc fotoxx.h - $(CXX) $(CFLAGS) fotoxx_transform.cc +f.retouch.o: f.retouch.cc fotoxx.h + $(CXX) $(CFLAGS) f.retouch.cc -fotoxx_art.o: fotoxx_art.cc fotoxx.h - $(CXX) $(CFLAGS) fotoxx_art.cc +f.transform.o: f.transform.cc fotoxx.h + $(CXX) $(CFLAGS) f.transform.cc -fotoxx_comp.o: fotoxx_comp.cc fotoxx.h - $(CXX) $(CFLAGS) fotoxx_comp.cc +f.art.o: f.art.cc fotoxx.h + $(CXX) $(CFLAGS) f.art.cc + +f.comp.o: f.comp.cc fotoxx.h + $(CXX) $(CFLAGS) f.comp.cc + +f.navi.o: f.navi.cc fotoxx.h + $(CXX) $(CFLAGS) f.navi.cc zfuncs.o: zfuncs.cc $(CXX) $(CFLAGS) zfuncs.cc -D PREFIX=\"$(PREFIX)\" @@ -64,7 +68,7 @@ mkdir -p $(DESTDIR)$(PREFIX)/share/applications cp -f fotoxx $(DESTDIR)$(BINDIR) cp -f icons/* $(DESTDIR)$(ICONDIR) - cp -f -R locales/* $(DESTDIR)$(LOCALESDIR) + cp -f locales/* $(DESTDIR)$(LOCALESDIR) cp -f -R doc/* $(DESTDIR)$(DOCDIR) # man page cp -f doc/fotoxx.man fotoxx.1 diff -Nru fotoxx-11.11.1/zfuncs.cc fotoxx-12.01.2/zfuncs.cc --- fotoxx-11.11.1/zfuncs.cc 2011-11-05 05:30:36.000000000 +0000 +++ fotoxx-12.01.2/zfuncs.cc 2012-01-04 08:47:11.000000000 +0000 @@ -1,7 +1,7 @@ /************************************************************************** zfuncs.cpp collection of Linux and GDK/GTK utility functions - Copyright 2006 2007 2008 2009 2010 2011 Michael Cornelison + Copyright 2006 2007 2008 2009 2010 2011 2012 Michael Cornelison source URL: kornelix.squarespace.com contact: kornelix2@googlemail.com @@ -29,6 +29,17 @@ system-level utility functions ***************************************************************************/ + +// Pause and wait for user KB input + +void apppause() +{ + printf("*** pause, press return to continue: "); + getchar(); + return; +} + + // Output a message to stdout and wait for user ACK. // Works like printf. @@ -47,20 +58,13 @@ return; } -void apppause() -{ - printf("*** pause, press return to continue: "); - getchar(); - return; -} - /**************************************************************************/ // crash with error message and traceback dump in popup window // works like printf -void zappcrash(cchar *pMess, ... ) // v.3.8 +void zappcrash(cchar *pMess, ... ) { va_list arglist; FILE *fid1, *fid2; @@ -103,7 +107,7 @@ if (pp1 && pp2 && pp2 < plim) { *pp2 = 0; strncpy0(hexaddr,pp1+1,20); - snprintf(command,300,"addr2line -e %s %s",progexe,hexaddr); // convert to source program v.3.8 + snprintf(command,300,"addr2line -e %s %s",progexe,hexaddr); // convert to source program fid2 = popen(command,"r"); // and line number pfunc = fgets(buff,300,fid2); pclose(fid2); @@ -126,7 +130,7 @@ // application initialization function to catch segfaults -void catch_signals() // v.2.22 +void catch_signals() { void sighandler(int signal); struct sigaction sigact; @@ -153,7 +157,7 @@ // This function will restart the current program with root privileges, // if the correct (sudo) password is given. It does not return. -void beroot(int argc, char *argv[]) // v.3.8 +void beroot(int argc, char *argv[]) { int cc1, cc2, ii, err; char command[1000]; @@ -195,7 +199,7 @@ /**************************************************************************/ -// get time in real seconds (since 2000.01.01 00:00:00) // v.2.12 +// get time in real seconds (since 2000.01.01 00:00:00) double get_seconds() { @@ -210,7 +214,7 @@ // start a timer or get elapsed time with millisecond resolution. -void start_timer(double &time0) // double v.2.20 +void start_timer(double &time0) { timeval timev; @@ -235,7 +239,7 @@ // start a process CPU timer or get elapsed process CPU time // returns seconds with millisecond resolution -void start_CPUtimer(double &time0) // double v.2.20 +void start_CPUtimer(double &time0) { time0 = CPUtime(); return; @@ -404,7 +408,67 @@ /**************************************************************************/ -// start a detached thread using a simplified protocol // v.2.11 +// sleep for specified time in seconds (double) +// signals can cause early return + +void zsleep(double dsecs) +{ + unsigned isecs, nsecs; + timespec tsecs; + + if (dsecs == 0.0) return; + isecs = unsigned(dsecs); + nsecs = unsigned(1000000000.0 * (dsecs - isecs)); + tsecs.tv_sec = isecs; + tsecs.tv_nsec = nsecs; + nanosleep(&tsecs,null); + return; +} + + +/**************************************************************************/ + +// Lock or unlock a multi-process multi-thread resource. +// Only one process/thread may posess a given lock. +// A reboot or process exit or crash releases the lock. +// global_lock() returns fd > 0 if success, -1 otherwise. +// To unlock, call global_unlock(fd). + +int global_lock(cchar *lockname) // v.4.7 +{ + int err, fd; + char lockfile[100]; + + strcpy(lockfile,"/tmp/global_lock_"); + strcat(lockfile,lockname); + + fd = open(lockfile,O_RDWR|O_CREAT,0666); // open or create the lock file + if (fd < 0) { + printf("global_lock(), %s \n",strerror(errno)); + return -1; + } + + err = flock(fd,LOCK_EX|LOCK_NB); // request exclusive non-blocking lock + if (err) { + close(fd); + return -1; + } + + return fd + 1; // return value is >= 1 +} + + +int global_unlock(int fd) +{ + int err = close(fd - 1); + if (err < 0) return -1; + else return 1; +} + + +/**************************************************************************/ + +// start a detached thread using a simplified protocol void start_detached_thread(void * threadfunc(void *), void * arg) { @@ -498,66 +562,6 @@ /**************************************************************************/ -// sleep for specified time in seconds (double) -// signals can cause early return - -void zsleep(double dsecs) -{ - unsigned isecs, nsecs; - timespec tsecs; - - if (dsecs == 0.0) return; - isecs = unsigned(dsecs); - nsecs = unsigned(1000000000.0 * (dsecs - isecs)); - tsecs.tv_sec = isecs; - tsecs.tv_nsec = nsecs; - nanosleep(&tsecs,null); - return; -} - - -/**************************************************************************/ - -// Lock or unlock a multi-process multi-thread resource. -// Only one process/thread may posess a given lock. -// A reboot or process exit or crash releases the lock. -// global_lock() returns fd > 0 if success, -1 otherwise. -// To unlock, call global_unlock(fd). - -int global_lock(cchar *lockname) // v.4.7 -{ - int err, fd; - char lockfile[100]; - - strcpy(lockfile,"/tmp/global_lock_"); - strcat(lockfile,lockname); - - fd = open(lockfile,O_RDWR|O_CREAT,0666); // open or create the lock file - if (fd < 0) { - printf("global_lock(), %s \n",strerror(errno)); - return -1; - } - - err = flock(fd,LOCK_EX|LOCK_NB); // request exclusive non-blocking lock - if (err) { - close(fd); - return -1; - } - - return fd + 1; // return value is >= 1 -} - - -int global_unlock(int fd) -{ - int err = close(fd - 1); - if (err < 0) return -1; - else return 1; -} - - -/**************************************************************************/ - // malloc() and free() wrappers with auto crash on failure and log option. // overflow sentinel is placed after end of allocated memory // zmalloc() and zfree() calls are logged if log count > 0 @@ -569,7 +573,7 @@ void zmalloc_tabulate(cchar *tag, int bytes); // private function -char * zmalloc(size_t bytes, cchar *tag) // optional tag, v.3.5 +char * zmalloc(size_t bytes, cchar *tag) // optional tag { void *maddr = malloc(bytes + zmalloc_add); if (! maddr) zappcrash("Memory request for %zu bytes failed. \n" @@ -590,7 +594,7 @@ strncpy(psen2,"sen2",4); zmalloc_tot += bytes; - zmalloc_tabulate(ptag,bytes); // track usage by tag v.3.7 + zmalloc_tabulate(ptag,bytes); // track usage by tag if (zmalloc_logcount) { printf("zmalloc %-20s loc: %p bytes: %zu total: %u \n",ptag,puser,bytes,zmalloc_tot); @@ -603,7 +607,7 @@ // free memory allocated by zmalloc(). checks for overflow. -void zfree(void *puser) // v.3.5 +void zfree(void *puser) { if (! puser) zappcrash("zfree: null address"); @@ -617,12 +621,12 @@ if (strncmp("sen1",psen1,4)) // check sentinels zappcrash("zfree: invalid address %p",puser); if (strncmp("sen2",psen2,4)) - zappcrash("zfree: buffer overflow |%s|%s|",ptag,puser); // v.3.9 - *psen1 = *psen2 = 0; // destroy sentinels v.3.8 + zappcrash("zfree: buffer overflow |%s|%s|",ptag,puser); + *psen1 = *psen2 = 0; // destroy sentinels zmalloc_tot -= bytes; - zmalloc_tabulate(ptag,-bytes); // track usage by tag v.3.7 + zmalloc_tabulate(ptag,-bytes); // track usage by tag if (zmalloc_logcount) { printf("zfree %-20s loc: %p bytes: %zu total: %u \n",ptag,puser,bytes,zmalloc_tot); @@ -636,7 +640,7 @@ // turn logging flag on for specified log count, or off if count = 0; -void zmalloc_log(int count) // v.3.5 +void zmalloc_log(int count) { zmalloc_logcount = count; return; @@ -649,7 +653,7 @@ HashTab *zmalloc_hashtab = 0; uint zmalloc_count[1000], zmalloc_bytes[1000]; -void zmalloc_tabulate(cchar *ptag, int bytes) // v.3.7 +void zmalloc_tabulate(cchar *ptag, int bytes) { int ii; @@ -664,7 +668,7 @@ if (ii < 0) zappcrash("zmalloc hash table full"); zmalloc_bytes[ii] += bytes; - if (bytes > 0) ++zmalloc_count[ii]; // v.3.8 + if (bytes > 0) ++zmalloc_count[ii]; else --zmalloc_count[ii]; return; @@ -673,7 +677,7 @@ // report total memory allocated per tag - leak detection utility -void zmalloc_report() // v.3.5 +void zmalloc_report() { int count, ii, first = 1; uint bytes; @@ -688,7 +692,7 @@ ii = zmalloc_hashtab->Find(tag); if (ii < 0) zappcrash("zmalloc hash table bug: %s",tag); bytes = zmalloc_bytes[ii]; - count = zmalloc_count[ii]; // added, v.3.8 + count = zmalloc_count[ii]; if (bytes) printf(" %-20s %8d %d \n",tag,count,bytes); } @@ -704,14 +708,13 @@ // Get command exit status: err = command_status(contx) // Caller owns returned strings which are candidates for zfree() // -// strcat(buff," 2>&1"); // combine stdout and stderr v.2.14 removed FILE * CO_contx[10] = { 0,0,0,0,0,0,0,0,0,0 }; int CO_status[10]; char * command_output(int &contx, cchar *command, ...) // simplify, allow parallel usage -{ // v.2.3 +{ FILE *fid; va_list arglist; char buff[10000], *prec; @@ -723,7 +726,7 @@ if (contx == 10) zappcrash("command_output(), parallel usage > 9"); va_start(arglist,command); // format command - vsnprintf(buff,999,command,arglist); + vsnprintf(buff,9999,command,arglist); va_end(arglist); fid = popen(buff,"r"); // execute command, output to FID @@ -737,7 +740,7 @@ fid = CO_contx[contx] - 1000; prec = fgets_trim(buff,9999,fid,1); // next output, less trailing \n - if (prec) return strdupz(prec,0,"command_output"); // return output to caller v.3.5 + if (prec) return strdupz(prec,0,"command_output"); // return output to caller CO_status[contx] = pclose(fid); // EOF, set status CO_contx[contx] = 0; // mark context free @@ -747,7 +750,7 @@ int command_status(int contx) // get command exit status { int err = CO_status[contx]; - return WEXITSTATUS(err); // special BS for subprocess v.2.3 + return WEXITSTATUS(err); // special BS for subprocess } @@ -764,7 +767,7 @@ int err, nsignal = 0; sprintf(buff,"ps -C %s h o pid",pname); - fid = popen(buff,"r"); // popen() instead of system() v.3.0 + fid = popen(buff,"r"); // popen() instead of system() if (! fid) return 2; pp = fgets(buff,100,fid); pclose(fid); @@ -789,7 +792,7 @@ // command: shell command or filespec of the program to start // returns 0 if successfully started, else returns an error code -int runroot(cchar *sucomm, cchar *command) // v.2.10 +int runroot(cchar *sucomm, cchar *command) { char xtcommand[500]; int err; @@ -818,7 +821,7 @@ // If any are missing, pop-up a window of missing programs // Returns the number of missing programs (zero if none). -int checkinstall(cchar *prog1, ...) // null terminated list // v.2.10 +int checkinstall(cchar *prog1, ...) // null terminated list { va_list arglist; char *buff, errmessage[200] = "missing programs:\n"; @@ -879,7 +882,7 @@ pp = fgets(buff,maxcc,fid); if (! pp) return pp; cc = strlen(buff); - if (bf) while (cc && buff[cc-1] > 0 && buff[cc-1] <= ' ') --cc; // utf8 v.2.4 + if (bf) while (cc && buff[cc-1] > 0 && buff[cc-1] <= ' ') --cc; else while (cc && buff[cc-1] > 0 && buff[cc-1] < ' ') --cc; buff[cc] = 0; return pp; @@ -894,7 +897,7 @@ int samedirk(cchar *file1, cchar *file2) { int cc1, cc2; - cchar *pp1, *pp2; // v.2.15 + cchar *pp1, *pp2; if (! file1 || ! file2) return 0; pp1 = strrchr(file1,'/'); @@ -928,7 +931,7 @@ ***************************************************************************/ -int parsefile(cchar *ppath, char **pdirk, char **pfile, char **pext) // v.2.15 +int parsefile(cchar *ppath, char **pdirk, char **pfile, char **pext) { struct stat statb; static char dirk[1000], file[200], ext[8]; @@ -971,7 +974,7 @@ /************************************************************************** - utility to measure CPU time spent in various functions or code blocks v.2.7 + utility to measure CPU time spent in various functions or code blocks cpu_profile_init() initialize at start of test cpu_profile_report() report CPU time per function @@ -1232,9 +1235,8 @@ // Produce random value from hashed input string. // Output range is 0 to max-1. -// rewritten v.3.7: better for "nearly equal" strings -int strHash(cchar *string, int max) // v.3.7 +int strHash(cchar *string, int max) { uint hash = 1; uchar byte; @@ -1290,7 +1292,7 @@ { strncpy(dest,source,cc); dest[cc-1] = 0; - if (strlen(source) >= cc) return 1; // truncated v.2.4 + if (strlen(source) >= cc) return 1; // truncated else return 0; } @@ -1330,7 +1332,7 @@ // Remove leading and trailing blanks from a string. // Returns remaining length, possibly zero. -int strTrim2(char *dest, cchar *source) // v.2.4 +int strTrim2(char *dest, cchar *source) { cchar *pp1, *pp2; int cc; @@ -1340,12 +1342,12 @@ while (*pp1 == ' ') pp1++; while (*pp2 == ' ' && pp2 > pp1) pp2--; cc = pp2 - pp1 + 1; - memmove(dest,pp1,cc); // allow overlap v.3.7 + memmove(dest,pp1,cc); dest[cc] = 0; return cc; } -int strTrim2(char *string) // v.3.7 +int strTrim2(char *string) { return strTrim2(string,(cchar *) string); } @@ -1494,7 +1496,7 @@ int repl_1str(cchar *strin, char *strout, cchar *ssin, cchar *ssout) { int ccc, cc1, cc2, nfound; - cchar *ppp; // v.2.15 + cchar *ppp; cc1 = strlen(ssin); cc2 = strlen(ssout); @@ -1653,13 +1655,13 @@ char * strdupz(cchar *string, int more, cchar *tag) { - char *pp = zmalloc(strlen(string)+1+more,tag); // v.3.5 + char *pp = zmalloc(strlen(string)+1+more,tag); strcpy(pp,string); return pp; } -// copy into existing 'zmalloc' string if present and long enough // v.2.8 +// copy into existing 'zmalloc' string if present and long enough // else free memory and allocate a longer one // destination string is subject for zfree() @@ -1668,7 +1670,7 @@ int ccs, ccd; ccs = strlen(source); - if (! zdest) zdest = zmalloc(ccs+1+more,tag); // v.3.5 + if (! zdest) zdest = zmalloc(ccs+1+more,tag); ccd = (int) *(zdest-8); if (ccd < ccs+1) { zfree(zdest); @@ -1721,7 +1723,7 @@ // - 1st byte of multibyte sequence is negative (actually 0xC0 to 0xFD) // - subsequent bytes are negative and < 0xC0 (actually 0x80 to 0xBF) -int utf8len(cchar *utf8string) // v.2.3 +int utf8len(cchar *utf8string) { int ii, cc; char xlimit = 0xC0; @@ -1747,7 +1749,7 @@ // returns number of graphic characters extracted, <= cc // Output string is null terminated after last extracted character. -int utf8substring(char *utf8out, cchar *utf8in, int pos, int cc) // v.2.3 +int utf8substring(char *utf8out, cchar *utf8in, int pos, int cc) { int ii, jj, kk, posx, ccx; char xlimit = 0xC0; @@ -1782,7 +1784,7 @@ // check a string for valid utf8 encoding // returns: 0 = OK, 1 = bad string -int utf8_check(cchar *string) // v.2.4 +int utf8_check(cchar *string) { cchar *pp; unsigned char ch1, ch2, nch; @@ -1816,7 +1818,7 @@ // Nth graphic character position, zero based // returns starting character (byte) position of Nth graphic character -int utf8_position(cchar *utf8in, int Nth) // v.2.4 +int utf8_position(cchar *utf8in, int Nth) { int ii, posx; char xlimit = 0xC0; @@ -1844,7 +1846,7 @@ int cc, ii; bitmap *bm; - bm = (bitmap *) zmalloc(sizeof(bitmap),"bitmap"); // v.3.5 + bm = (bitmap *) zmalloc(sizeof(bitmap),"bitmap"); bm->nbits = nbits; cc = (nbits + 7) / 8; bm->bits = (uchar *) zmalloc(cc,"bitmap"); @@ -1910,7 +1912,7 @@ { pvlist *pv; - pv = (pvlist *) zmalloc(sizeof(pvlist),"pvlist"); // v.3.5 + pv = (pvlist *) zmalloc(sizeof(pvlist),"pvlist"); pv->max = max; pv->act = 0; pv->list = (char **) zmalloc(max * sizeof(char *),"pvlist"); @@ -1943,7 +1945,7 @@ if (pv->act == pv->max) pvlist_remove(pv,0); // if list full, remove 1st entry ii = pv->act; - pv->list[ii] = strdupz(entry,0,"pvlist"); // add to end of list v.3.5 + pv->list[ii] = strdupz(entry,0,"pvlist"); // add to end of list pv->act++; return ii; } @@ -1964,7 +1966,7 @@ for (ii = pv->act; ii > 0; ii--) // push all list entries down pv->list[ii] = pv->list[ii-1]; - pv->list[0] = strdupz(entry,0,"pvlist"); // add to start of list v.3.5 + pv->list[0] = strdupz(entry,0,"pvlist"); // add to start of list pv->act++; return 0; } @@ -2018,7 +2020,7 @@ // replace Nth entry with new one -int pvlist_replace(pvlist * pv, int ii, cchar *entry) // v.3.5 +int pvlist_replace(pvlist * pv, int ii, cchar *entry) { if (ii < 0 || ii >= pv->act) return -1; zfree(pv->list[ii]); @@ -2292,7 +2294,7 @@ // prec is the desired digits of precision to output. // WARNING: only the last 100 conversions remain available in memory. -char * formatKBMB(double fnum, int prec) // v.2.25 +char * formatKBMB(double fnum, int prec) { #define kilo 1000 #define mega (kilo*kilo) @@ -2440,7 +2442,7 @@ ***/ cchar * SearchWild(cchar *wpath, int &uflag) // use popen() instead of scratch file -{ // v.3.0 +{ static FILE *fid = 0; static char matchfile[maxfcc]; char searchpath[maxfcc]; @@ -2505,7 +2507,7 @@ // perform a binary search on sorted list of integers // return matching element or -1 if not found -int bsearch(int element, int nn, int list[]) +int bsearch(int seekint, int nn, int list[]) { int ii, jj, kk, rkk; @@ -2516,7 +2518,7 @@ while (true) { - kk = list[ii] - element; // check element + kk = list[ii] - seekint; // check element if (kk > 0) { @@ -2548,6 +2550,52 @@ } +// perform a binary search on sorted set of records in memory +// return matching record number (0 based) or -1 if not found + +int bsearch(char *seekrec, char *allrecs, int recl, int nrecs) +{ + int ii, jj, kk, rkk; + + ii = nrecs / 2; // next element to search + jj = (ii + 1) / 2; // next increment + nrecs--; // last element + rkk = 0; + + while (true) + { + kk = strcmp(allrecs+ii*recl,seekrec); // compare member rec to seek rec + + if (kk > 0) + { + ii -= jj; // too high, go down in set + if (ii < 0) return -1; + } + + else if (kk < 0) + { + ii += jj; // too low, go up in set + if (ii > nrecs) return -1; + } + + else if (kk == 0) return ii; // matched + + jj = jj / 2; // reduce increment + + if (jj == 0) + { + jj = 1; // step by 1 element + if (! rkk) rkk = kk; // save direction + else + { + if (rkk > 0) { if (kk < 0) return -1; } // if change direction, fail + else if (kk > 0) return -1; + } + } + } +} + + /************************************************************************** heap sort functions ***************************************************************************/ @@ -2953,7 +3001,7 @@ return nrand48((unsigned int16 *) seed); } -int lrandz() // built-in seed v.3.3 +int lrandz() { static int64 seed = 12345678; return lrandz(&seed); @@ -2966,7 +3014,7 @@ return erand48((unsigned int16 *) seed); } -double drandz() // built-in seed v.3.3 +double drandz() { static int64 seed = 23459876; return drandz(&seed); @@ -2975,7 +3023,7 @@ /************************************************************************** - spline1: define a curve using a set of data points (x and y values) v.2.11 + spline1: define a curve using a set of data points (x and y values) spline2: for a given x-value, return a y-value fitting the curve For spline1, the no. of curve-defining points must be < 100. @@ -3055,36 +3103,36 @@ /************************************************************************** Initialize application files according to following conventions: // new version v.4.1 - + binary executable is at: /installoc/bin/appname // = PREFIX/bin/appname + + binary executable is at: /prefix/bin/appname // = PREFIX/bin/appname + other application directories are derived as follows: - /installoc/share/appname/data/ desktop, parameters, etc. - /installoc/share/doc/appname/ README, CHANGES, user guide - /installoc/share/appname/icons/ icon files .png - /installoc/share/appname/locales/ translations: /de/appname.po etc. + /prefix/share/appname/data/ desktop, parameters, etc. + /prefix/share/doc/appname/ README, CHANGES, user guide + /prefix/share/appname/icons/ icon files .png + /prefix/share/appname/locales/ translations: appname-de.po etc. /home/user/.appname/ parameters etc. are copied here - zinstalloc install location has /bin and /share subtrees - zdatadir installed data files .desktop, parameters, etc. - zdocdir user documentation README, CHANGES, user guide - zicondir icons icon files .png - zlocalesdir translation files /de/appname.po etc. - zuserdir /home/user/.appname log file, user parameters + zprefix install location has /bin and /share subtrees + zdatadir installed data files .desktop, parameters, etc. + zdocdir user documentation README, changelog, user guide + zicondir icons icon files .png + zlocalesdir translation files appname-de.po, etc. + zuserdir /home/user/.appname log file, user parameters ***/ namespace zfuncs { char zappname[20]; - char zinstalloc[200], zdatadir[200], zdocdir[200]; // app directories + char zprefix[200], zdatadir[200], zdocdir[200]; // app directories char zicondir[200], zlocalesdir[200], zuserdir[200]; - char zlanguage[8] = "en"; // "lc" or "lc_RC" + char zlang[8] = "en"; // "lc" or "lc_RC" char JPGquality[4] = "85"; // JPG file save quality cchar *F1_help_topic = 0; // current F1 help topic int open_popup_windows = 0; // open popup window count pthread_t tid_main = 0; // main thread ID v.4.8 } -cchar * get_zinstalloc() { return zfuncs::zinstalloc; } // /usr or /home/ +cchar * get_zprefix() { return zfuncs::zprefix; } // /usr or /home/ cchar * get_zuserdir() { return zfuncs::zuserdir; } // /home/user/.appname cchar * get_zdatadir() { return zfuncs::zdatadir; } // parameters, icons cchar * get_zdocdir() { return zfuncs::zdocdir; } // documentation files @@ -3099,7 +3147,9 @@ char work[200]; char logfile[200], oldlog[200]; cchar *appfile; - int err; + int secs, err; + time_t Tnow; + char *chTnow; struct stat statdat; va_list arglist; FILE *fid; @@ -3108,16 +3158,16 @@ strcpy(zappname,appname); // save app name - #ifndef PREFIX // v.4.7 + #ifndef PREFIX // install location v.4.7 #define PREFIX "/usr" #endif strncpy0(work,PREFIX,199); // /usr or /home/ v.4.6 - strcpy(zinstalloc,work); // /installoc - strncatv(zdatadir,199,work,"/share/",zappname,"/data",null); // /installoc/share/appname/data - strncatv(zicondir,199,work,"/share/",zappname,"/icons",null); // /installoc/share/appname/icons - strncatv(zlocalesdir,199,work,"/share/",zappname,"/locales",null); // /installoc/share/appname/locales - strncatv(zdocdir,199,work,"/share/doc/",zappname,null); // /installoc/share/doc/appname + strcpy(zprefix,work); // /prefix + strncatv(zdatadir,199,work,"/share/",zappname,"/data",null); // /prefix/share/appname/data + strncatv(zicondir,199,work,"/share/",zappname,"/icons",null); // /prefix/share/appname/icons + strncatv(zlocalesdir,199,work,"/share/",zappname,"/locales",null); // /prefix/share/appname/locales + strncatv(zdocdir,199,work,"/share/doc/",zappname,null); // /prefix/share/doc/appname snprintf(zuserdir,199,"%s/.%s",getenv("HOME"),zappname); // /home/user/.appname/ v.4.3 err = stat(zuserdir,&statdat); // does it exist already? @@ -3135,16 +3185,26 @@ va_end(arglist); } + tid_main = pthread_self(); // v.4.8 + Tnow = time(0); + chTnow = ctime(&Tnow); + chTnow[19] = 0; + if (! isatty(1)) { // not attached to a terminal v.4.1 snprintf(logfile,199,"%s/%s.log",zuserdir,zappname); - snprintf(oldlog,199,"%s/%s.log.old",zuserdir,zappname); // prior log file >> *.old.log v.4.3 - rename(logfile,oldlog); + snprintf(oldlog,199,"%s/%s.log.old",zuserdir,zappname); + err = stat(logfile,&statdat); + if (! err) { + secs = Tnow - statdat.st_mtime; // if log file age > 1 hour v.5.0 + if (secs > 3600) rename(logfile,oldlog); // rename to *.old + } fid = freopen(logfile,"a",stdout); // redirect output to log file fid = freopen(logfile,"a",stderr); // /home/user/.appname/appname.log if (! fid) printf("cannot redirect stdout and stderr \n"); } + + printf("=========== %s %s \n",zappname,chTnow); - tid_main = pthread_self(); // v.4.8 return 1; } @@ -3155,24 +3215,24 @@ // help file: /zdocdir/userguide-lc_RC.html (or) *-lc.html (or) *-en.html // context: optional arg. show file starting at internal link = context // look for user guide file in /usr/share/doc/appname/ -// and in /usr/share/doc/appname/extras/ // v.4.7 distros are different +// and in /usr/share/doc/appname/extras/ // distros are different v.4.7 -void showz_userguide(cchar *context) // added context v.2.29 +void showz_userguide(cchar *context) { using namespace zfuncs; int err; char docfile[200], url[200], lang[4]; - snprintf(docfile,199,"%s/userguide-%s.html",zdocdir,zlanguage); // look for userguide-lc_RC.html + snprintf(docfile,199,"%s/userguide-%s.html",zdocdir,zlang); // look for userguide-lc_RC.html err = access(docfile,R_OK); if (! err) goto add_context; - snprintf(docfile,199,"%s/extras/userguide-%s.html",zdocdir,zlanguage); + snprintf(docfile,199,"%s/extras/userguide-%s.html",zdocdir,zlang); err = access(docfile,R_OK); if (! err) goto add_context; - strncpy0(lang,zlanguage,3); + strncpy0(lang,zlang,3); snprintf(docfile,199,"%s/userguide-%s.html",zdocdir,lang); // look for userguide-lc.html err = access(docfile,R_OK); if (! err) goto add_context; @@ -3194,7 +3254,7 @@ add_context: - if (context && *context) // v.3.7 + if (context && *context) strncatv(docfile,199,"#",context,null); // file://.../userguide-xx.html#context snprintf(url,199,"file://%s",docfile); showz_html(url); @@ -3243,22 +3303,22 @@ int err; command = "zcat"; - snprintf(buff1,199,"%s/%s.gz",zdocdir,file); // look for .../appname/file.gz + snprintf(buff1,199,"%s/%s.gz",zdocdir,file); // look for .../appname/file.gz err = stat(buff1,&statb); if (! err) goto showit; command = "cat"; - snprintf(buff1,199,"%s/%s",zdocdir,file); // look for .../appname/file + snprintf(buff1,199,"%s/%s",zdocdir,file); // look for .../appname/file err = stat(buff1,&statb); if (! err) goto showit; command = "zcat"; - snprintf(buff1,199,"%s/extras/%s.gz",zdocdir,file); // look for .../appname/extras/file.gz + snprintf(buff1,199,"%s/extras/%s.gz",zdocdir,file); // look for .../appname/extras/file.gz err = stat(buff1,&statb); if (! err) goto showit; command = "cat"; - snprintf(buff1,199,"%s/extras/%s",zdocdir,file); // look for .../appname/extras/file + snprintf(buff1,199,"%s/extras/%s",zdocdir,file); // look for .../appname/extras/file err = stat(buff1,&statb); if (! err) goto showit; @@ -3296,7 +3356,7 @@ zmessageACK(null,ZTX("error: %s"),strerror(errno)); return; } - + fputs("[Desktop Entry]\n",fid); // [Desktop Entry] snprintf(work,199,"Name=%s\n",appname); // Name=appname fputs(work,fid); @@ -3306,12 +3366,12 @@ fputs(work,fid); fputs("Type=Application\n",fid); // Type=Application fputs("Terminal=false\n",fid); // Terminal=false - snprintf(work,199,"Exec=%s/bin/%s\n",zinstalloc,command); // Exec=/usr/bin/appname -options + snprintf(work,199,"Exec=%s/bin/%s\n",zprefix,command); // Exec=/usr/bin/appname -options fputs(work,fid); snprintf(work,199,"Icon=%s/%s.png\n",zicondir,appname); // Icon=/usr/share/appname/icons/appname.png fputs(work,fid); fclose(fid); - + snprintf(work,199,"chmod 0750 %s",dtfile); // make executable err = system(work); if (err) zmessLogACK(null,"error: %s",wstrerror(err)); @@ -3324,2714 +3384,2678 @@ } -/************************************************************************** +// show a local or remote html file using the user's preferred browser +// to show a local file starting at an internal live link location: +// url = "file://directory/.../filename#livelink - Translation Functions +void showz_html(cchar *url) +{ + char command[500]; + static char prog[20]; + static int ftf = 1, err; + + if (ftf) { + ftf = 0; + strcpy(prog,"xdg-open"); + err = system("xdg-open --version"); + if (err) { + strcpy(prog,"firefox"); + err = system("firefox -v"); + if (err) *prog = 0; + } + } - Translation files are standard .po files as used in the Gnu gettext - system. However the .po files are used directly, and there is no need - to merge and compile them into a binary format (.mo files). + if (! *prog) { + zmessLogACK(null,"no xdg-open or firefox, cannot show document"); + return; + } + + snprintf(command,499,"%s %s &",prog,url); + printf(" %s \n",command); // v.4.1 + err = system(command); + return; +} - Initialize: - int ZTXinit(cchar *lang) - lang is "lc" or "lc_RC" or null (current locale will be used) - If files are found in both .../lc/xxx.po and .../lc_RC/xxx.po, - both sets of files are processed. If a translation is present in - both sets, the regional dialect (lc_RC) will be used. +/************************************************************************** + GTK utility functions +**************************************************************************/ - Translate a text string: - cchar *translation = ZTX(cchar *english) - english: text string which may have printf formats (%d %s ...) - translation: the returned equivalent translation +// Iterate main loop every "skip" calls - If the user language is English or if no translation is found, - the input string is returned, else the translated string. - - A text string may have a context part "context::string", where - "context" is any string < 30 characters and "string" is the - English text or the translation text. The context part "context::" - is removed in the returned string. This is to handle the case where - a single English string may need multiple translations, depending - on context. The English string may be present multiple times in a - .po file, each one marked with a different context and having a - different translation. Context is optional in translation strings. +void zmainloop(int skip) +{ + static int xskip = 0; - example: - - program code: - - printf(ZTX("answer: %d %s \n more on next line"), 123, "qwerty"); - - A German .po file would have the following entry: + if (skip) { + if (++xskip < skip) return; + xskip = 0; + } - msgid "" - "answer: %d %s \n" - " more on next line" - msgstr "" - "Antwort: %d %s \n" - " mehr in der nächsten Zeile" + if (! pthread_equal(pthread_self(),zfuncs::tid_main)) return; // thread caller, do nothing v.5.0 -***/ - -namespace ZTXnames // remove GOFUNC usage becasue of -{ // GCC optimization errors v.2.18 - FILE *fidr, *fidw; - char buff[ZTXmaxcc], *ppq1, *ppq2, lc_RC[8]; - char *porec, *wporec; - char Etext[ZTXmaxcc], Ttext[ZTXmaxcc]; // .po text: "line 1 %s \n" "line 2" - char **etext, **ttext; // arrays, english and translations - char **estring, **tstring; // merged, un-quoted, un-escaped - int Ntext = 0; // array counts - int Ftranslate = 0; // 0/1/2 = translate none/all/missing - zdialog *zddump; // dialog for editing translations - GtkWidget *trwin; // text window within dialog - void ZTXread_pofiles(); // private functions - void ZTXgettext(char *text); - char *ZTXmergetext(cchar *text); - void ZTX_translation_dump(int index); - void ZTX_translation_update(); - void ZTXgettext2(char *text); - void ZTXwritetext(cchar *header, char *text); + gdk_flush(); // v.5.0 + while (gtk_events_pending()) gtk_main_iteration(); // main() caller OK + return; } -// read and process .po files at application startup -// prepare english strings and translations for quick access +/**************************************************************************/ + +// crash if current execution is not the main() thread -void ZTXinit(cchar *lang) // initialize translations +void zthreadcrash() { - using namespace zfuncs; - using namespace ZTXnames; + if (pthread_equal(pthread_self(),zfuncs::tid_main)) return; // v.4.8 + zappcrash("forbidden function called from thread"); + return; +} - int ii; - char *pp; - if (Ntext) { // free prior translation - for (ii = 0; ii < Ntext; ii++) { - zfree(etext[ii]); - zfree(ttext[ii]); - zfree(estring[ii]); - zfree(tstring[ii]); - } - zfree(etext); - zfree(ttext); - zfree(estring); - zfree(tstring); - Ntext = 0; +/**************************************************************************/ + +// write message to text view window +// line: +N existing lines from top (replace) +// -N existing lines from bottom (replace) +// 0 next line (add new line at bottom) +// scroll logic assumes only one \n per message + +void wprintx(GtkWidget *mLog, int line, cchar *message, cchar *font) +{ + GtkTextMark *endMark; + GtkTextBuffer *textBuff; + GtkTextIter iter1, iter2; + GtkTextTag *fontag = 0; + int nlines, scroll = 0; + + if (! mLog) { // if no GUI use STDOUT + printf("%s",message); + return; } + + zthreadcrash(); + + textBuff = gtk_text_view_get_buffer(GTK_TEXT_VIEW(mLog)); - etext = (char **) zmalloc(ZTXmaxent * sizeof(char *),"ZTX"); // english text and translations - ttext = (char **) zmalloc(ZTXmaxent * sizeof(char *),"ZTX"); // (segmented, quoted, escaped) - estring = (char **) zmalloc(ZTXmaxent * sizeof(char *),"ZTX"); // english strings and translations - tstring = (char **) zmalloc(ZTXmaxent * sizeof(char *),"ZTX"); // (merged, un-quoted, un-escaped) + endMark = gtk_text_buffer_get_mark(textBuff,"wpxend"); // get my end mark - if (lang && *lang) strncpy0(zlanguage,lang,6); // use language from caller - else { // help Linux chaos - pp = getenv("LANG"); // use $LANG if defined - if (! pp) pp = getenv("LANGUAGE"); // use $LANGUAGE if defined - if (! pp) pp = setlocale(LC_MESSAGES,""); // use locale if defined - if (pp) strncpy0(zlanguage,pp,6); // "lc_RC" language/region code - else strcpy(zlanguage,"en"); // use English + if (! endMark) { + gtk_text_buffer_get_end_iter(textBuff,&iter1); // new buffer, set my end mark + endMark = gtk_text_buffer_create_mark(textBuff,"wpxend",&iter1,0); } - if (*zlanguage < 'a') strcpy(zlanguage,"en"); // use English if garbage - printf("language: %s \n",zlanguage); + nlines = gtk_text_buffer_get_line_count(textBuff); // lines now in buffer + + if (line == 0) scroll++; // auto scroll is on + + if (line < 0) { + line = nlines + line + 1; // last lines: -1, -2 ... + if (line < 1) line = 1; // above top, use line 1 + } + + if (line > nlines) line = 0; // below bottom, treat as append - if (strnEqu(zlanguage,"en",2)) return; // English, do nothing v.4.3 + if (line == 0) gtk_text_buffer_get_end_iter(textBuff,&iter1); // append new line - strncpy0(lc_RC,zlanguage,6); // process .../locales/lc_RC/*.po FIRST - if (strlen(lc_RC) > 3) ZTXread_pofiles(); + if (line > 0) { + gtk_text_buffer_get_iter_at_line(textBuff,&iter1,line-1); // old line start + if (line < nlines) + gtk_text_buffer_get_iter_at_line(textBuff,&iter2,line); // old line end + if (line == nlines) // or buffer end + gtk_text_buffer_get_end_iter(textBuff,&iter2); + gtk_text_buffer_delete(textBuff,&iter1,&iter2); // delete old line + } - strncpy0(lc_RC,zlanguage,3); // process .../locales/lc/*.po - ZTXread_pofiles(); + if (font) { // insert new line with caller font + fontag = gtk_text_buffer_create_tag(textBuff,0,"font",font,0); // fontag is textBuff specific + gtk_text_buffer_insert_with_tags(textBuff,&iter1,message,-1,fontag,null); + } + else // insert new line with default font + gtk_text_buffer_insert(textBuff,&iter1,message,-1); + if (scroll) // scroll line into view + gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(mLog),endMark,0,0,1,1); + + zmainloop(); // v.4.8 return; } - -// private function -// read and process .po files - -void ZTXnames::ZTXread_pofiles() // revised v.4.3 +void wprintf(GtkWidget *mLog, int line, cchar *mess, ... ) // "printf" version { - using namespace zfuncs; - using namespace ZTXnames; + va_list arglist; + char message[1000]; - int ii, err, contx = 0; - char *pp, *pofile, podir[200], command[200]; + va_start(arglist,mess); + vsnprintf(message,999,mess,arglist); + va_end(arglist); - snprintf(podir,199,"%s/locales/%s",zuserdir,lc_RC); // look for user .po files - snprintf(command,199,"find %s/*.po 2>/dev/null",podir); // (translation project is underway) - err = system(command); - if (! err) printf("using user .po files for %s \n",lc_RC); - else { - snprintf(podir,199,"%s/%s",zlocalesdir,lc_RC); // look for installed .po files - snprintf(command,199,"find %s/*.po",podir); - err = system(command); - if (! err) printf("using installed .po files for %s \n",lc_RC); - else printf("no translation files found for %s \n",lc_RC); - } - - strcat(command," 2>/dev/null"); // suppress error messages - - while ((pofile = command_output(contx,command))) // get user or installed .po files - { - fidr = fopen(pofile,"r"); // open .po file - if (! fidr) { - printf("cannot open translation file: %s \n",pofile); // error, ignore file - zfree(pofile); - continue; - } - - porec = 0; // no .po record yet - *Etext = *Ttext = 0; // no text yet + wprintx(mLog,line,message); + return; +} - while (true) - { - if (! porec) porec = fgets_trim(buff,ZTXmaxcc,fidr); // get next .po record - if (! porec) break; // EOF - - if (blank_null(porec)) { // blank record - porec = 0; - continue; - } - if (*porec == '#') { // comment - porec = 0; - continue; - } +void wprintf(GtkWidget *mLog, cchar *mess, ... ) // "printf", scrolling output +{ + va_list arglist; + char message[1000]; - if (strnEqu(porec,"msgid",5)) // start new english string - { - if (*Etext) { // two in a row - printf("no translation: %s \n",Etext); - *Etext = 0; - } + va_start(arglist,mess); + vsnprintf(message,999,mess,arglist); // stop overflow, remove warning + va_end(arglist); - if (*Ttext) { - printf("orphan translation: %s \n",Ttext); - *Ttext = 0; - } + wprintx(mLog,0,message); + return; +} - porec += 5; // get segmented text string - ZTXgettext(Etext); // "segment1 %s \n" "segment2" ... - } - else if (strnEqu(porec,"msgstr",6)) // start new translation - { - porec += 6; // get segmented string - ZTXgettext(Ttext); - - if (! *Etext) { - printf("orphan translation: %s \n",Ttext); - *Ttext = 0; - continue; - } +/**************************************************************************/ - if (strlen(Ttext) < 3) { // translation is "" - printf("no translation: %s \n",Etext); - strcpy(Ttext,Etext); // substitute english text - } - } - - else - { - printf("unrecognized .po record: %s \n",porec); - porec = 0; - continue; - } - - if (*Etext && *Ttext) // have an english/translation pair - { - etext[Ntext] = strdupz(Etext,0,"ZTX"); - ttext[Ntext] = strdupz(Ttext,0,"ZTX"); - *Etext = *Ttext = 0; - Ntext++; - if (Ntext == ZTXmaxent) // cannot continue - zappcrash("more than %d translations",ZTXmaxent); - } - } - - fclose(fidr); - zfree(pofile); - } +// scroll a text view window to put a given line on screen +// 1st line = 1. for last line use line = 0. - printf(".po files have %d entries \n",Ntext); +void wscroll(GtkWidget *mLog, int line) +{ + GtkTextBuffer *textbuff; + GtkTextIter iter; + GtkTextMark *mark; - for (ii = 0; ii < Ntext; ii++) - { - pp = ZTXmergetext(etext[ii]); - estring[ii] = strdupz(pp,0,"ZTX"); - pp = ZTXmergetext(ttext[ii]); - tstring[ii] = strdupz(pp,0,"ZTX"); - } + if (! mLog) return; + textbuff = gtk_text_view_get_buffer(GTK_TEXT_VIEW(mLog)); + if (line <= 0) line = gtk_text_buffer_get_line_count(textbuff); + line = line - 1; + gtk_text_buffer_get_iter_at_line(textbuff,&iter,line); + mark = gtk_text_buffer_create_mark(textbuff,0,&iter,0); // bugfix, gtk_text_view_scroll_to_iter() + gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(mLog),mark,0,0,1,1); // fails with no error v.4.0 return; } -// private function -// read and combine multiple 'msgid' or 'msgstr' quoted strings -// output is one string with one or more quoted segments: -// "text line 1 %s \n" "text line 2" ... -// each segment comes from a different line in the input .po file +/**************************************************************************/ -void ZTXnames::ZTXgettext(char *pstring) // v.4.3 +// clear a text view window and get a new buffer (a kind of defrag) + +void wclear(GtkWidget *mLog) { - using namespace ZTXnames; + GtkTextBuffer *buff; - int cc, scc = 0; + if (! mLog) return; - while (true) // join multiple quoted strings - { - while (*porec && *porec != '"') porec++; // find opening string quote - if (! *porec) { - porec = fgets_trim(buff,ZTXmaxcc,fidr); // get next .po record - if (! porec) return; - if (strnEqu(porec,"msgid",5)) return; // end of this string - if (strnEqu(porec,"msgstr",6)) return; - } - ppq1 = porec; // opening quote - ppq2 = ppq1 + 1; - while ((*ppq2 && *ppq2 != '"') || // find closing (non-escaped) quote - (*ppq2 == '"' && *(ppq2-1) == '\\')) ppq2++; - if (! *ppq2) return; - cc = ppq2 - ppq1 + 1; // min. case is "" - if (cc + 1 + scc >= ZTXmaxcc) - printf("string is too long %s \n",pstring); - else { - strncpy0(pstring+scc,ppq1,cc+1); // accum. substrings, minus quotes - scc += cc; - } - porec = ppq2 + 1; - } - + buff = gtk_text_view_get_buffer(GTK_TEXT_VIEW(mLog)); + gtk_text_buffer_set_text(buff,"",-1); return; } -// private function -// convert quoted string segments into binary form that -// matches the compiled string in the source program -// (remove quotes, merge strings, un-escape \n \" etc.) +// clear a text view window from designated line to end of buffer -char * ZTXnames::ZTXmergetext(cchar *dirtystring) // v.4.3 +void wclear(GtkWidget *mLog, int line) { - static char cleanstring[ZTXmaxcc]; - int ii, jj; - - strncpy0(cleanstring,dirtystring,ZTXmaxcc); - clean_escapes(cleanstring); - - for (ii = jj = 0; cleanstring[ii]; ii++) - if (cleanstring[ii] != '"') - cleanstring[jj++] = cleanstring[ii]; - cleanstring[jj] = 0; - return cleanstring; + GtkTextBuffer *textBuff; + GtkTextIter iter1, iter2; + + if (! mLog) return; + + textBuff = gtk_text_view_get_buffer(GTK_TEXT_VIEW(mLog)); + gtk_text_buffer_get_iter_at_line(textBuff,&iter1,line-1); // iter at line start + gtk_text_buffer_get_end_iter(textBuff,&iter2); + gtk_text_buffer_delete(textBuff,&iter1,&iter2); // delete existing line + return; } -// Translate the input english string or return the input string. -// Look for "context::string" and return "string" only if context found. -// This function may need a few microseconds. This can be improved -// if needed by sorting the english strings and using a binary search. +/**************************************************************************/ -cchar * ZTX(cchar *english) -{ - using namespace ZTXnames; +// get text records from a text view window, one per call +// removes trailing new line characters ( \n ) - cchar *pp, *pp2; - int ii; +char * wscanf(GtkWidget *mLog, int & ftf) +{ + GtkTextBuffer *textBuff; + GtkTextIter iter1, iter2; + static char *precs = 0, *prec1, *pret; + static int cc; - if (! english) return "null"; // v.4.3 + if (! mLog) return 0; - for (ii = 0; ii < Ntext; ii++) // find translation v.4.3 - if (strEqu(english,estring[ii])) break; - if (ii < Ntext) pp = tstring[ii]; - else pp = english; + if (ftf) + { // get all window text + ftf = 0; + if (precs) g_free(precs); // free prior memory if there + textBuff = gtk_text_view_get_buffer(GTK_TEXT_VIEW(mLog)); // get all text + gtk_text_buffer_get_bounds(textBuff,&iter1,&iter2); + precs = gtk_text_buffer_get_text(textBuff,&iter1,&iter2,0); + prec1 = precs; // 1st record + } - if (Ftranslate) { - if (ii < Ntext) ZTX_translation_dump(ii); // output translation - else printf("message not in .po: %s \n",english); + if (! precs || (*prec1 == 0)) // no more records + { + if (precs) g_free(precs); + precs = 0; + return 0; } - - for (pp2 = pp; *pp2 && pp2 < pp+30; pp2++) // remove context if present - if (*pp2 == ':' && *(pp2+1) == ':') return pp2+2; - return pp; + cc = 0; + while ((prec1[cc] != 0) && (prec1[cc] != '\n')) cc++; // scan for terminator + pret = prec1; + prec1 = prec1 + cc; // next record + if (*prec1 == '\n') prec1++; + pret[cc] = 0; // replace \n with 0 + return pret; } -/************************************************************************** +/**************************************************************************/ - Online Translation Utility +// dump text window into file +// return: 0: OK +N: error - Run the application to be translated in the usual manner. Select each - menu or toolbar function needing translation. The related english text - strings and current translations are dumped into a text edit window. - The user can edit the translations while using the application and - therefore more easily understand the complete context. - - If the application menu "Translate" is selected, the function - ZTX_translation_start() is called and the user dialog is used to - set translation mode ON or OFF. If ON, the .po translation files - are copied from the install location to a user location (if not - already there) where they will be modified. These user .po files - will be used for translations going forward. +int wfiledump_maxcc = 0; + +int wfiledump(GtkWidget *mLog, char *filespec) +{ + FILE *fid; + char *prec; + int ftf, err, cc; + + if (! mLog) return 0; + + fid = fopen(filespec,"w"); // open file + if (! fid) { + zmessageACK(null,ZTX("cannot open file %s"),filespec); + return 1; + } - Whenever the application calls ZTX() to get a translation, the - function ZTX_translation_dump() is called to add the english text - and the current translation to the text edit window. - ______________________________________________________ - | | - | msgid "English text with formats %d %d ... " | - | msgstr "Deutscher Text mit Formats %d %s ... " | - | ... | - | [apply] [cancel] | - |______________________________________________________| + wfiledump_maxcc = 0; - As the application is exercised (menus and dialogs), all english text - and current translations are added to the window. Where no translation - is available, the english text is repeated as the translation. The user - may edit the window to update the translations. When done, using the - [apply] button updates the translation .po files in the user location. + ftf = 1; + while (true) + { + prec = wscanf(mLog,ftf); // get text line + if (! prec) break; + fprintf(fid,"%s\n",prec); // output with \n + cc = strlen(prec); + if (cc > wfiledump_maxcc) wfiledump_maxcc = cc; + } - Limitation: - ZTXinit() merges .po files from locales lc_RC and lc alone if both are - present. Where both locales translate the same english string, then - the one in lc_RC is used. ZTX_translation() also uses both locales but - does not know if a modified translation belongs to the locale lc_RC or - lc. If an english string is translated in both locales, any modified - translation is written back to the .po files in lc_RC only. + err = fclose(fid); // close file + if (err) { zmessageACK(null,"file close error"); return 2; } + else return 0; +} -***************************************************************************/ +/**************************************************************************/ -// This function is called from the application menu "Translate". -// Set translation mode ON or OFF (zfuncs::Ftranslate). If ON and no -// user .po translation files (/home//.appname/locales/lc/*.po) -// are found, then they are copied from the installed .po files to -// provide a starting point for changes. A text edit window is opened -// to display the english strings and their current translations, -// if any, and collect the edited updates. +// save text window to file, via file chooser dialog -void ZTX_translation_start() // new v.4.3 +void wfilesave(GtkWidget *mLog) { - using namespace zfuncs; - using namespace ZTXnames; + int err; + char *file; - int ZTX_translation_event(zdialog *zd, cchar *event); + if (! mLog) return; - zdialog *zd; - int err, tron, trmissing; - char command[200]; - char podir1[200], podir2[200]; - - if (strnEqu(zlanguage,"en",2)) { // locale cannot be english - zmessageACK(0,"cannot translate locale %s",zlanguage); - return; - } + file = zgetfile1(ZTX("save screen to file"),"save","screen-save.txt"); + if (! file) return; + err = wfiledump(mLog,file); + if (err) zmessageACK(null,"save screen failed (%d)",err); + zfree(file); + return; +} -/* ___________________________________________ - | | - | Translation mode: (o) ON (o) OFF | - | [x] Show missing translations only | - | | - | [done] [cancel] | - |___________________________________________| -*/ - zd = zdialog_new("Translation Mode",0,"done","cancel",null); - zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=5"); - zdialog_add_widget(zd,"label","labm","hb1","Translation mode:","space=5"); - zdialog_add_widget(zd,"radio","tron","hb1","ON","space=5"); - zdialog_add_widget(zd,"radio","troff","hb1","OFF","space=5"); - zdialog_add_widget(zd,"hbox","hb2","dialog",0,"space=5"); - zdialog_add_widget(zd,"check","trmissing","hb2","Show missing translations only"); - - zdialog_stuff(zd,"tron",1); - zdialog_stuff(zd,"troff",0); - zdialog_stuff(zd,"trmissing",1); - - zdialog_run(zd); // run dialog - zdialog_wait(zd); +/**************************************************************************/ - Ftranslate = 0; +// print text window to default printer +// use landscape mode if max. print line > A4 width - if (zd->zstat == 1) { // [done] - zdialog_fetch(zd,"tron",tron); - zdialog_fetch(zd,"trmissing",trmissing); - if (tron) Ftranslate = 1; // dump all translations - if (tron && trmissing) Ftranslate = 2; // dump only missing translations - } - zdialog_free(zd); +void wprintp(GtkWidget *mLog) +{ + int pid, err; + char tempfile[50], command[200]; - if (Ftranslate) // start or continue translation mode - { - strncpy0(lc_RC,zlanguage,6); // current locale, lc or lc_RC - - for (int pass = 1; pass <= 2; pass++) - { - if (pass == 1 && strlen(lc_RC) < 3) continue; // read .po files for locale lc_RC - if (pass == 2) lc_RC[2] = 0; // read .po files for locale lc + if (! mLog) return; - snprintf(podir1,199,"%s/%s",zlocalesdir,lc_RC); // installed .po files for lc_RC - snprintf(podir2,199,"%s/locales/%s",zuserdir,lc_RC); // user .po files for new translations - - snprintf(command,199,"find %s/*.po",podir2); // look for user .po files - err = system(command); // (resume translation project) - if (err) { - snprintf(command,199,"find %s/*.po",podir1); // look for installed .po files - err = system(command); - if (err) printf("No .po files found in %s \n",podir1); - else { - snprintf(command,199,"mkdir -p -m 0750 %s",podir2); // create directory if not already - err = system(command); - snprintf(command,199,"cp %s/*.po %s",podir1,podir2); // copy installed .po files to user - err = system(command); - if (! err) printf(".po files copied from %s to %s \n",podir1,podir2); - else printf("cannot copy .po files from %s to %s \n",podir1,podir2); - } - } - } - - ZTXinit(zlanguage); // re-initialize translations + pid = getpid(); + snprintf(tempfile,49,"/tmp/wprintp-%d",pid); + err = wfiledump(mLog,tempfile); + if (err) return; - zddump = zdialog_new("Translations",0,"apply","cancel",null); // create dialog for translations - zdialog_add_widget(zddump,"scrwin","scrwin","dialog",0,"expand"); - zdialog_add_widget(zddump,"edit","edit","scrwin"); - zdialog_resize(zddump,600,400); - zdialog_run(zddump,ZTX_translation_event); - trwin = zdialog_widget(zddump,"edit"); // text edit window in dialog - } + if (wfiledump_maxcc < 97) + snprintf(command,199,"lp -o %s -o %s -o %s -o %s -o %s -o %s %s", + "cpi=14","lpi=8","page-left=50","page-top=50", + "page-right=40","page-bottom=40",tempfile); + + else + snprintf(command,199,"lp -o %s -o %s -o %s -o %s -o %s -o %s -o %s %s", + "landscape","cpi=14","lpi=8","page-left=50","page-top=50", + "page-right=40","page-bottom=40",tempfile); + err = system(command); + if (err) zmessLogACK(null,"print error %s",wstrerror(err)); return; } -// dialog event and completion function +/************************************************************************** + simplified GTK menu bar, tool bar, status bar functions +***************************************************************************/ + +int tbIconSize = 24; // valid during toolbar construction +GtkTooltips *tbTooltips = 0; // one instance for all toolbars + + +// create menu bar and add to vertical packing box -int ZTX_translation_event(zdialog *zd, cchar *event) // v.4.3 +GtkWidget * create_menubar(GtkWidget *vbox) // icon size removed { - using namespace ZTXnames; - - if (! zd->zstat) return 1; // wait for [apply] or [cancel] + GtkWidget *wmbar; - if (zd->zstat == 1) // [apply] - ZTX_translation_update(); // update user .po files + wmbar = gtk_menu_bar_new(); + gtk_box_pack_start(GTK_BOX(vbox),wmbar,0,0,0); + return wmbar; +} - Ftranslate = 0; - zdialog_free(zd); // kill edit window - zddump = 0; - trwin = 0; - return 1; + +// add menu item to menu bar + +GtkWidget * add_menubar_item(GtkWidget *wmbar, cchar *mname, mtFunc func) +{ + GtkWidget *wmitem; + + wmitem = gtk_menu_item_new_with_label(mname); + gtk_menu_shell_append(GTK_MENU_SHELL(wmbar),wmitem); + if (func) G_SIGNAL(wmitem,"activate",func,mname); + return wmitem; } -// This function is called from ZTX() for every translation. -// Add the english text and current translation to the text edit window. +// create a popup menu // v.4.7 -void ZTXnames::ZTX_translation_dump(int index) // new v.4.3 +GtkWidget * create_popmenu() { - using namespace zfuncs; - using namespace ZTXnames; - - char outstring[ZTXmaxcc]; - char *pp1, *pp2; - int cc; + GtkWidget *popmenu; - if (strEqu(zlanguage,"en")) return; - if (! zddump) return; // no translation edit window + popmenu = gtk_menu_new(); + return popmenu; +} - if (! Ftranslate) return; // translate mode OFF - if (Ftranslate == 2 && // only missing translations wanted - strNeq(etext[index],ttext[index])) return; // and this translation not missing - strcpy(outstring,"msgid "); // msgid "english line 1 %s \n" - pp1 = etext[index]; // "english line 2" - // ... - while (*pp1) { - while (*pp1 && *pp1 != '"') pp1++; - pp2 = pp1 + 1; - while (*pp1 && *pp2 && *pp2 != '"') pp2++; - if (*pp1 && *pp2) { - cc = strlen(outstring); - strncpy0(outstring+cc,pp1,pp2-pp1+2); - wprintf(trwin,"%s\n",outstring); - *outstring = 0; - pp1 = pp2 + 1; - } - } - - strcpy(outstring,"msgstr "); // msgstr "translation line 1 %s \n" - pp1 = ttext[index]; // "translation line 2" - // ... - while (*pp1) { - while (*pp1 && *pp1 != '"') pp1++; - pp2 = pp1 + 1; - while (*pp1 && *pp2 && *pp2 != '"') pp2++; - if (*pp1 && *pp2) { - cc = strlen(outstring); - strncpy0(outstring+cc,pp1,pp2-pp1+2); - wprintf(trwin,"%s\n",outstring); - *outstring = 0; - pp1 = pp2 + 1; - } - } - - wprintf(trwin,"\n"); // blank line between pairs +// add a menu item to a popup menu // v.4.7 - return; +GtkWidget * add_popmenu_item(GtkWidget *popmenu, cchar *mname, mtFunc func) +{ + GtkWidget *wmitem; + + wmitem = gtk_menu_item_new_with_label(mname); + gtk_menu_shell_append(GTK_MENU_SHELL(popmenu),wmitem); + if (func) G_SIGNAL(wmitem,"activate",func,mname); + return wmitem; } -// merge translation edit window with user .po files and clear the window +// pop-up the menu at current mouse position // v.4.7 -void ZTXnames::ZTX_translation_update() // new v.4.3 +void popup_menu(GtkWidget *popmenu) { - using namespace zfuncs; - using namespace ZTXnames; + gtk_menu_popup(GTK_MENU(popmenu),0,0,0,0,0,gtk_get_current_event_time()); + gtk_widget_show_all(popmenu); + return; +} - int contx, ii, err, ftf, Nupd, Npos; - char *pofile1, pofile2[200], *pofiles[100], podir[200]; - char command[200], command2[400]; - char *pp, Fused[ZTXmaxent]; - ftf = 1; - wporec = 0; - *Etext = *Ttext = 0; - Nupd = 0; +// add submenu item to menu item, optional response function - while (true) // scan translation edit window - { - if (! wporec) wporec = wscanf(trwin,ftf); - if (! wporec) break; // EOF +GtkWidget * add_submenu_item(GtkWidget *wmitem, cchar *mlab, mtFunc func) +{ + GtkWidget *wmsub, *wmsubitem; + GtkWidget *wicon = 0; - if (blank_null(wporec)) { // blank record - wporec = 0; - continue; + wmsub = gtk_menu_item_get_submenu(GTK_MENU_ITEM(wmitem)); + if (wmsub == null) { + wmsub = gtk_menu_new(); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(wmitem),wmsub); + } + + if (strEqu(mlab,"separator")) + wmsubitem = gtk_separator_menu_item_new(); + else { + if (wicon) { + wmsubitem = gtk_image_menu_item_new_with_label(mlab); + gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(wmsubitem),wicon); } + else wmsubitem = gtk_menu_item_new_with_label(mlab); + } - if (strnEqu(wporec,"msgid",5)) // start new english string - { - if (*Etext) { // two in a row - printf("no translation: %s \n",Etext); - *Etext = 0; - } + gtk_menu_shell_append(GTK_MENU_SHELL(wmsub),wmsubitem); + if (func) G_SIGNAL(wmsubitem,"activate",func,mlab); + return wmsubitem; +} - if (*Ttext) { // should not happen - printf("orphan translation: %s \n",Ttext); - *Ttext = 0; - } - wporec += 5; // get segmented text string - ZTXgettext2(Etext); // "segment1 %s \n" "segment2" ... - } +// create toolbar and add to vertical packing box - else if (strnEqu(wporec,"msgstr",6)) // start new translation - { - wporec += 6; // get segmented string - ZTXgettext2(Ttext); - - if (! *Ttext) { - if (*Etext) printf("no translation: %s \n",Etext); - *Etext = 0; - } - else if (! *Etext) { // orphan or redundant translation - printf("orphan translation: %s \n",Ttext); - *Ttext = 0; - } - } - - else - { - printf("unrecognized record: %s \n",wporec); - wporec = 0; - continue; - } - - if (*Etext && *Ttext) // have an english/translation pair - { - for (ii = 0; ii < Ntext; ii++) // find existing (prior) entry - if (strEqu(Etext,etext[ii])) break; // in translation tables - if (ii == Ntext) - printf("English changed, translation ignored: %s \n",Etext); - else if (strNeq(Ttext,ttext[ii])) { // translation was updated - zfree(ttext[ii]); - ttext[ii] = strdupz(Ttext,0,"ZTX"); - Nupd++; - } - *Etext = *Ttext = 0; - } - } +GtkWidget * create_toolbar(GtkWidget *vbox, int iconsize, int vert) +{ + using namespace zfuncs; - printf("%d new translations found \n",Nupd); - if (! Nupd) return; // nothing new + GtkWidget *wtbar; - strncpy0(lc_RC,zlanguage,6); // current locale, lc_RC or lc only - Npos = 0; + wtbar = gtk_toolbar_new(); + if (vert) gtk_toolbar_set_orientation(GTK_TOOLBAR(wtbar),GTK_ORIENTATION_VERTICAL); + gtk_box_pack_start(GTK_BOX(vbox),wtbar,0,0,0); + tbIconSize = iconsize; - for (int pass = 1; pass <= 2; pass++) // loop two locale codes - { - if (pass == 1 && strlen(lc_RC) < 3) continue; // locale = lc_RC (if RC present) - if (pass == 2) lc_RC[2] = 0; // then locale = lc + if (! tbTooltips) tbTooltips = gtk_tooltips_new(); + return wtbar; +} - snprintf(podir,199,"%s/locales/%s",zuserdir,lc_RC); // user .po files for new translations - snprintf(command,199,"find %s/*.po",podir); // look for user .po files - strcat(command," 2>/dev/null"); // suppress error messages - contx = 0; - while ((pofile1 = command_output(contx,command))) // find each .po file - { - if (Npos == 100) zappcrash("exceed 100 .po files"); - pofiles[Npos++] = pofile1; // add to ordered list of .po files - } - } +// add toolbar button with stock icon ("gtk-quit") or custom icon ("iconfile.png") - memset(Fused,0,ZTXmaxent); - Nupd = 0; +GtkWidget * add_toolbar_button(GtkWidget *wtbar, cchar *blab, cchar *btip, cchar *icon, mtFunc func) +{ + using namespace zfuncs; - for (int kpo = 0; kpo < Npos; kpo++) // loop each .po file - { - fidr = fopen(pofiles[kpo],"r"); // open .po file for read - if (! fidr) { - printf("cannot read translation file: %s \n",pofiles[kpo]); - return; - } - - strcpy(pofile2,pofiles[kpo]); // open .po.new file for write - strcat(pofile2,".new"); - fidw = fopen(pofile2,"w"); - if (! fidw) { - printf("cannot write updated translation file: %s \n",pofile2); - fclose(fidr); - return; - } + GtkToolItem *tbutton; + GError *gerror = 0; + GdkPixbuf *pixbuf; + GtkWidget *wicon = 0; + char iconpath[200]; + + if (blab && strEqu(blab,"separator")) { // v.4.3 + tbutton = gtk_separator_tool_item_new(); + gtk_toolbar_insert(GTK_TOOLBAR(wtbar),GTK_TOOL_ITEM(tbutton),-1); + return (GtkWidget *) tbutton; + } - porec = 0; - *Etext = *Ttext = 0; + if (icon == null || *icon == 0) + tbutton = gtk_tool_button_new(0,0); - while (true) // loop each .po record - { - if (! porec) porec = fgets_trim(buff,ZTXmaxcc,fidr); // next record - if (! porec) break; // EOF + else if (strnEqu(icon,"gtk-",4)) + tbutton = gtk_tool_button_new_from_stock(icon); - if (strnEqu(porec,"msgid",5)) { // msgid: "english 1 %s \n" "english 2" ... - porec += 5; - ZTXgettext(Etext); // aggregate strings - } + else { + *iconpath = 0; + strncatv(iconpath,199,zicondir,"/",icon,null); + pixbuf = gdk_pixbuf_new_from_file_at_scale(iconpath,tbIconSize,tbIconSize,1,&gerror); + if (pixbuf) wicon = gtk_image_new_from_pixbuf(pixbuf); + if (wicon) tbutton = gtk_tool_button_new(wicon,0); + else tbutton = gtk_tool_button_new_from_stock("gtk-missing-image"); + } - else if (strnEqu(porec,"msgstr",6)) { // msgstr: "translation %s \n" ... - porec += 6; - ZTXgettext(Ttext); // aggregate strings - } + if (blab) gtk_tool_button_set_label(GTK_TOOL_BUTTON(tbutton),blab); + if (btip) gtk_tool_item_set_tooltip(tbutton,tbTooltips,btip,""); + gtk_tool_item_set_homogeneous(tbutton,0); + gtk_toolbar_insert(GTK_TOOLBAR(wtbar),GTK_TOOL_ITEM(tbutton),-1); + if (func) G_SIGNAL(tbutton,"clicked",func,blab); + return (GtkWidget *) tbutton; +} - else { - fprintf(fidw,"%s\n",porec); // other record, copy to output - porec = 0; - continue; - } - - if (*Etext && *Ttext) // have an english/translation pair - { - for (ii = 0; ii < Ntext; ii++) // find matching english in - if (strEqu(Etext,etext[ii])) break; // existing translations - if (ii < Ntext && ! Fused[ii]) { - if (strNeq(etext[ii],ttext[ii]) && - strNeq(Ttext,ttext[ii])) { // translation added or updated - printf("changed: %s %s \n",etext[ii],ttext[ii]); - strcpy(Ttext,ttext[ii]); // substitute new translation - Nupd++; // actual .po updates made - } - Fused[ii] = 1; // mark english string as used - } - - ZTXwritetext("msgid",Etext); // output msgid: strings - ZTXwritetext("msgstr",Ttext); // and msgstr: strings - *Etext = *Ttext = 0; - } - } - fclose(fidr); - fclose(fidw); - } +// create a status bar and add to the start of a packing box - for (ii = 0; ii < Npos; ii++) // free memory - zfree(pofiles[ii]); - - printf("new .po files have %d updated translations \n",Nupd); - if (! Nupd) return; +GtkWidget * create_stbar(GtkWidget *pbox) +{ + GtkWidget *stbar; + static PangoFontDescription *fontdesc; - strncpy0(lc_RC,zlanguage,6); // current locale, lc_RC or lc only + stbar = gtk_statusbar_new(); + fontdesc = pango_font_description_from_string("Monospace 9"); + gtk_widget_modify_font(stbar,fontdesc); // *** GTK does not work *** + gtk_box_pack_start(GTK_BOX(pbox),stbar,0,0,0); + gtk_widget_show(stbar); + return stbar; +} - for (int pass = 1; pass <= 2; pass++) // loop two locale codes - { - if (pass == 1 && strlen(lc_RC) < 3) continue; // locale = lc_RC (if RC present) - if (pass == 2) lc_RC[2] = 0; // then locale = lc - snprintf(podir,199,"%s/locales/%s",zuserdir,lc_RC); // user .po files for new translations - snprintf(command,199,"find %s/*.po.new",podir); // look for .po.new files - strcat(command," 2>/dev/null"); // suppress error messages +// display message in status bar - contx = 0; - while ((pofile1 = command_output(contx,command))) // loop each .po.new file - { - strcpy(pofile2,pofile1); - pp = strstr(pofile2,".new"); - if (pp) *pp = 0; - snprintf(command2,399,"mv -f %s %s",pofile1,pofile2); // move *.po.new to *.po (replace) - err = system(command2); - if (err) printf("cannot copy %s to *.po",pofile1); - zfree(pofile1); - } - } - - ZTXinit(zlanguage); // put translations in use +int stbar_message(GtkWidget *wstbar, cchar *message) +{ + static int ctx = -1; - return; + if (ctx == -1) ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(wstbar),"all"); + gtk_statusbar_pop(GTK_STATUSBAR(wstbar),ctx); + gtk_statusbar_push(GTK_STATUSBAR(wstbar),ctx,message); + return 0; } -// private function -// read and combine multiple 'msgid' or 'msgstr' quoted strings -// output is one string with one or more quoted segments: -// "text line 1 %s \n" "text line 2" ... -// each segment comes from a different line in the translation edit window +/************************************************************************** + simplified GTK dialog functions +***************************************************************************/ -void ZTXnames::ZTXgettext2(char *pstring) // v.4.3 -{ - using namespace ZTXnames; - int cc, scc = 0, ftf = 0; +// counter, keeps track of open or pending zdialogs - while (true) // join multiple quoted strings - { - while (*wporec && *wporec != '"') wporec++; // find opening string quote - if (! *wporec) { - wporec = wscanf(trwin,ftf); - if (! wporec) return; - if (strnEqu(wporec,"msgid",5)) return; // end of this string - if (strnEqu(wporec,"msgstr",6)) return; - } - ppq1 = wporec; // opening quote - ppq2 = ppq1 + 1; - while ((*ppq2 && *ppq2 != '"') || // find closing (non-escaped) quote - (*ppq2 == '"' && *(ppq2-1) == '\\')) ppq2++; - if (! *ppq2) { - wporec = 0; - return; - } - cc = ppq2 - ppq1 + 1; // min. case is "" - if (cc + 1 + scc >= ZTXmaxcc) - printf("string is too long %s \n",pstring); - else { - strncpy0(pstring+scc,ppq1,cc+1); // accum. substrings, minus quotes - scc += cc; - } - wporec = ppq2 + 1; - } - - return; -} +namespace zfuncs { int zdialog_busy; } -// private function -// write quoted seqmented string to output .po file, 1 record per segment -// msgid "english string segment 1 %s \n" -// "english string segment 2 \n" -// ... +// private functions for widget events and dialog completion -void ZTXnames::ZTXwritetext(cchar *header, char *text) -{ - char *pp1, *pp2; - int cc, ftf; - char segment[ZTXmaxcc]; +int zdialog_widget_event(GtkWidget *, zdialog *zd); +int zdialog_response_event(GtkWidget *, int zstat, zdialog *zd); - ftf = 1; - pp1 = text; - while (true) - { - while (*pp1 && *pp1 != '"') pp1++; // opening quote - if (! *pp1) break; - pp2 = pp1 + 1; - while ((*pp2 && *pp2 != '"') || // find closing (non-escaped) quote - (*pp2 == '"' && *(pp2-1) == '\\')) pp2++; - if (! *pp2) break; - cc = pp2 - pp1 + 1; - if (cc >= ZTXmaxcc) cc = ZTXmaxcc - 1; - strncpy0(segment,pp1,cc+1); - if (ftf) fprintf(fidw,"%s %s\n",header,segment); - else fprintf(fidw,"%s\n",segment); - ftf = 0; - pp1 = pp2 + 1; - } +// create a new zdialog dialog +// optional arguments: up to zdmaxbutts button labels followed by null +// returned dialog status: +N = button N (1 to zdmaxbutts) +// <0 = [x] button or other GTK destroy action - return; -} +// v.3.5 overhaul: +// build own completion buttons, replacing the fat GTK standard buttons +// completion buttons are also events like other widgets +// get rid of separate dialog completion function +// all dialogs run parallel, use zdialog_wait() if needed +zdialog * zdialog_new(cchar *title, GtkWidget *parent, ...) // parent added +{ + zdialog *zd; + GtkWidget *dialog, *hbox, *butt, *hsep; + cchar *bulab[zdmaxbutts]; + int cc, ii, nbu; + va_list arglist; -/**************************************************************************/ + va_start(arglist,parent); + for (nbu = 0; nbu < zdmaxbutts; nbu++) // get completion buttons + { + bulab[nbu] = va_arg(arglist, cchar *); + if (! bulab[nbu]) break; + } + va_end(arglist); -// crash if current execution is not the main() thread + if (! title) title = " "; // v.5.0 -inline void zthreadcrash() -{ - if (pthread_equal(pthread_self(),zfuncs::tid_main)) return; // v.4.8 - zappcrash("forbidden function called from thread"); - return; -} + dialog = gtk_dialog_new(); // attributes optional + gtk_window_set_title(GTK_WINDOW(dialog),title); + gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog)->vbox),2); + gtk_dialog_set_has_separator(GTK_DIALOG(dialog),0); + cc = sizeof(zdialog); // allocate zdialog + zd = (zdialog *) zmalloc(cc,"zdialog"); -/**************************************************************************/ + if (parent) { // v.4.4 + zd->parent = parent; + gtk_window_set_transient_for(GTK_WINDOW(dialog),GTK_WINDOW(parent)); + } -// Iterate main loop every "skip" calls + if (nbu) { // there are some completion buttons + hbox = gtk_hbox_new(0,0); + gtk_box_pack_end(GTK_BOX(GTK_DIALOG(dialog)->vbox),hbox,0,0,0); // add hbox for buttons at dialog bottom + hsep = gtk_hseparator_new(); // add separator line + gtk_box_pack_end(GTK_BOX(GTK_DIALOG(dialog)->vbox),hsep,0,0,5); -void zmainloop(int skip) // v.2.8 -{ - static int xskip = 0; - - if (skip) { - if (++xskip < skip) return; - xskip = 0; + for (ii = nbu-1; ii >= 0; ii--) { // add buttons to hbox + butt = gtk_button_new_with_label(bulab[ii]); // reverse order nbu-1...0 + gtk_box_pack_end(GTK_BOX(hbox),butt,0,0,5); + G_SIGNAL(butt,"clicked",zdialog_widget_event,zd); // connect to event function + zd->compbutt[ii] = butt; // save button widgets + } } + + zd->sentinel = zdsentinel; // validity sentinel + zd->eventCB = 0; // no user event callback function + zd->zstat = 0; // no zdialog status + zd->disabled = 1; // widget signals disabled + zd->saveposn = 0; // position not saved v.4.4 + zd->help_topic = 0; // no help topic v.4.5 - if (! pthread_equal(pthread_self(),zfuncs::tid_main)) return; // thread caller, do nothing v.5.0 + zd->widget[0].type = "dialog"; // set up 1st widget = dialog + zd->widget[0].name = "dialog"; + zd->widget[0].pname = 0; + zd->widget[0].data = strdupz(title,0,"zdialog"); + zd->widget[0].cblist = 0; + zd->widget[0].widget = dialog; - while (gtk_events_pending()) gtk_main_iteration(); // main() caller OK - return; + zd->widget[1].type = 0; // eof - no contained widgets yet + return zd; } -/**************************************************************************/ - -// write message to text view window -// line: +N existing lines from top (replace) -// -N existing lines from bottom (replace) -// 0 next line (add new line at bottom) -// scroll logic assumes only one \n per message +// add widget to existing zdialog -void wprintx(GtkWidget *mLog, int line, cchar *message, cchar *font) +int zdialog_add_widget ( + zdialog *zd, cchar *type, cchar *name, cchar *pname, // mandatory args + cchar *data, int scc, int homog, int expand, int space, int wrap) // optional args (default = 0) { - GtkTextMark *endMark; - GtkTextBuffer *textBuff; - GtkTextIter iter1, iter2; - GtkTextTag *fontag = 0; - int nlines, scroll = 0; - - if (! mLog) { // if no GUI use STDOUT v.3.0 - printf("%s",message); - return; - } - - zthreadcrash(); + GtkWidget *widget = 0, *pwidget = 0; + GtkTextBuffer *editBuff = 0; + GdkColor gdkcolor; + cchar *pp, *ptype = 0; + char vdata[30]; + double min, max, step, val; + int iiw, iip, kk, err; + + static PangoFontDescription *monofont = 0; - textBuff = gtk_text_view_get_buffer(GTK_TEXT_VIEW(mLog)); + if (! zd) zappcrash("zdialog null pointer"); // detect destroyed dialog + if (zd->sentinel != zdsentinel) zappcrash("zdialog invalid"); - endMark = gtk_text_buffer_get_mark(textBuff,"wpxend"); // get my end mark + for (iiw = 1; zd->widget[iiw].type; iiw++); // find next avail. slot + if (iiw > zdmaxwidgets-2) zappcrash("too many widgets: %d",iiw); - if (! endMark) { - gtk_text_buffer_get_end_iter(textBuff,&iter1); // new buffer, set my end mark - endMark = gtk_text_buffer_create_mark(textBuff,"wpxend",&iter1,0); - } + zd->widget[iiw].type = strdupz(type,0,"zdialog"); // initz. widget struct + zd->widget[iiw].name = strdupz(name,0,"zdialog"); // all strings in nonvolatile mem + zd->widget[iiw].pname = strdupz(pname,0,"zdialog"); + zd->widget[iiw].data = 0; + zd->widget[iiw].cblist = 0; + zd->widget[iiw].scc = scc; + zd->widget[iiw].homog = homog; + zd->widget[iiw].expand = expand; + zd->widget[iiw].space = space; + zd->widget[iiw].wrap = wrap; + zd->widget[iiw].widget = 0; - nlines = gtk_text_buffer_get_line_count(textBuff); // lines now in buffer + zd->widget[iiw+1].type = 0; // new EOF marker - if (line == 0) scroll++; // auto scroll is on + if (strcmpv(type,"dialog","hbox","vbox","hsep","vsep","frame","scrwin", + "label","link","entry","edit","button","togbutt","check","combo", + "comboE","radio","spin","hscale","vscale","colorbutt", null) == 0) + zappcrash("zdialog, bad widget type: %s",type); - if (line < 0) { - line = nlines + line + 1; // last lines: -1, -2 ... - if (line < 1) line = 1; // above top, use line 1 - } - - if (line > nlines) line = 0; // below bottom, treat as append + for (iip = iiw-1; iip >= 0; iip--) // find parent (container) widget + if (strEqu(pname,zd->widget[iip].name)) break; + if (iip < 0) zappcrash("zdialog, no parent for widget: %s",name); - if (line == 0) gtk_text_buffer_get_end_iter(textBuff,&iter1); // append new line + pwidget = zd->widget[iip].widget; // parent widget, type + ptype = zd->widget[iip].type; - if (line > 0) { - gtk_text_buffer_get_iter_at_line(textBuff,&iter1,line-1); // old line start - if (line < nlines) - gtk_text_buffer_get_iter_at_line(textBuff,&iter2,line); // old line end - if (line == nlines) // or buffer end - gtk_text_buffer_get_end_iter(textBuff,&iter2); - gtk_text_buffer_delete(textBuff,&iter1,&iter2); // delete old line - } - - if (font) { // insert new line with caller font - fontag = gtk_text_buffer_create_tag(textBuff,0,"font",font,0); // fontag is textBuff specific v.3.9 - gtk_text_buffer_insert_with_tags(textBuff,&iter1,message,-1,fontag,null); - } - else // insert new line with default font - gtk_text_buffer_insert(textBuff,&iter1,message,-1); - - if (scroll) // scroll line into view - gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(mLog),endMark,0,0,1,1); + if (strcmpv(ptype,"dialog","hbox","vbox","frame","scrwin",null) == 0) + zappcrash("zdialog, bad widget parent type: %s",ptype); - zmainloop(); // v.4.8 - return; -} + if (! monofont) monofont = pango_font_description_from_string("Monospace"); -void wprintf(GtkWidget *mLog, int line, cchar *mess, ... ) // "printf" version -{ - va_list arglist; - char message[1000]; + if (strEqu(type,"hbox")) widget = gtk_hbox_new(homog,space); // expandable container boxes + if (strEqu(type,"vbox")) widget = gtk_vbox_new(homog,space); - va_start(arglist,mess); - vsnprintf(message,999,mess,arglist); - va_end(arglist); + if (strEqu(type,"hsep")) widget = gtk_hseparator_new(); // horiz. & vert. separators + if (strEqu(type,"vsep")) widget = gtk_vseparator_new(); + + if (strEqu(type,"frame")) { // frame around contained widgets + widget = gtk_frame_new(data); + gtk_frame_set_shadow_type(GTK_FRAME(widget),GTK_SHADOW_IN); + } - wprintx(mLog,line,message); - return; -} + if (strEqu(type,"scrwin")) { // scrolled window container + widget = gtk_scrolled_window_new(0,0); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(widget), + GTK_POLICY_AUTOMATIC,GTK_POLICY_AUTOMATIC); + } -void wprintf(GtkWidget *mLog, cchar *mess, ... ) // "printf", scrolling output -{ - va_list arglist; - char message[1000]; + if (strEqu(type,"label")) widget = gtk_label_new(data); // label (static text) - va_start(arglist,mess); - vsnprintf(message,999,mess,arglist); // stop overflow, remove warning - va_end(arglist); + if (strEqu(type,"link")) { // label is clickable v.4.0 + widget = gtk_link_button_new(data); + G_SIGNAL(widget,"clicked",zdialog_widget_event,zd); + } - wprintx(mLog,0,message); - return; -} + if (strEqu(type,"entry")) { // 1-line text entry + widget = gtk_entry_new(); + if (data) gtk_entry_set_text(GTK_ENTRY(widget),data); + if (scc) gtk_entry_set_width_chars(GTK_ENTRY(widget),scc); + gtk_widget_modify_font(widget,monofont); + G_SIGNAL(widget,"changed",zdialog_widget_event,zd); + } + + if (strEqu(type,"edit")) { // multiline edit box + widget = gtk_text_view_new(); + editBuff = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget)); + if (data) gtk_text_buffer_set_text(editBuff,data,-1); + gtk_text_view_set_editable(GTK_TEXT_VIEW(widget),1); + if (wrap) gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(widget),GTK_WRAP_WORD); // v.4.3 + gtk_widget_modify_font(widget,monofont); + G_SIGNAL(editBuff,"changed",zdialog_widget_event,zd); // buffer signals, not widget + } + if (strEqu(type,"button")) { // button + widget = gtk_button_new_with_label(data); + G_SIGNAL(widget,"clicked",zdialog_widget_event,zd); + } -/**************************************************************************/ + if (strEqu(type,"togbutt")) { // toggle button + widget = gtk_toggle_button_new_with_label(data); + G_SIGNAL(widget,"toggled",zdialog_widget_event,zd); + } -// scroll a text view window to put a given line on screen -// 1st line = 1. for last line use line = 0. - -void wscroll(GtkWidget *mLog, int line) // v.2.3 -{ - GtkTextBuffer *textbuff; - GtkTextIter iter; - GtkTextMark *mark; - - if (! mLog) return; // v.3.0 - - textbuff = gtk_text_view_get_buffer(GTK_TEXT_VIEW(mLog)); - if (line <= 0) line = gtk_text_buffer_get_line_count(textbuff); - line = line - 1; - gtk_text_buffer_get_iter_at_line(textbuff,&iter,line); - mark = gtk_text_buffer_create_mark(textbuff,0,&iter,0); // bugfix, gtk_text_view_scroll_to_iter() - gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(mLog),mark,0,0,1,1); // fails with no error v.4.0 - return; -} + if (strEqu(type,"check")) { // checkbox + if (data) widget = gtk_check_button_new_with_label(data); + else widget = gtk_check_button_new(); + G_SIGNAL(widget,"toggled",zdialog_widget_event,zd); + } + + if (strEqu(type,"combo")) { // combo box + widget = gtk_combo_box_new_text(); + zd->widget[iiw].cblist = pvlist_create(zdcbmax); // for drop-down list + if (! blank_null(data)) { + pvlist_append(zd->widget[iiw].cblist,data); // add data to drop-down list + gtk_combo_box_append_text(GTK_COMBO_BOX(widget),data); + gtk_combo_box_set_active(GTK_COMBO_BOX(widget),0); + } + gtk_widget_modify_font(widget,monofont); + G_SIGNAL(widget,"changed",zdialog_widget_event,zd); + } + if (strEqu(type,"comboE")) { // combo box with entry box + widget = gtk_combo_box_entry_new_text(); + zd->widget[iiw].cblist = pvlist_create(zdcbmax); // for drop-down list + if (! blank_null(data)) { + gtk_entry_set_text(GTK_ENTRY(GTK_BIN(widget)->child),data); // entry = initial data + pvlist_append(zd->widget[iiw].cblist,data); // add data to drop-down list + gtk_combo_box_append_text(GTK_COMBO_BOX(widget),data); + } + gtk_widget_modify_font(widget,monofont); + G_SIGNAL(widget,"changed",zdialog_widget_event,zd); + } + + if (strEqu(type,"radio")) { // radio button + for (kk = iip+1; kk <= iiw; kk++) + if (strEqu(zd->widget[kk].pname,pname) && // find first radio button + strEqu(zd->widget[kk].type,"radio")) break; // with same container + if (kk == iiw) + widget = gtk_radio_button_new_with_label(null,data); // this one is first + else + widget = gtk_radio_button_new_with_label_from_widget // not first, add to group + (GTK_RADIO_BUTTON(zd->widget[kk].widget),data); + G_SIGNAL(widget,"toggled",zdialog_widget_event,zd); + } -/**************************************************************************/ + if (strcmpv(type,"spin","hscale","vscale",null)) { // spin button or sliding scale + pp = strField(data,'|',1); err = convSD(pp,min); // locale fix + pp = strField(data,'|',2); err += convSD(pp,max); + pp = strField(data,'|',3); err += convSD(pp,step); + pp = strField(data,'|',4); err += convSD(pp,val); + if (err) { min = 0; max = 100; step = 1; val = 50; } -// clear a text view window and get a new buffer (a kind of defrag) + if (*type == 's') { + widget = gtk_spin_button_new_with_range(min,max,step); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget),val); + } + if (*type == 'h') { + widget = gtk_hscale_new_with_range(min,max,step); + gtk_range_set_value(GTK_RANGE(widget),val); + gtk_scale_set_draw_value(GTK_SCALE(widget),0); + } + if (*type == 'v') { + widget = gtk_vscale_new_with_range(min,max,step); + gtk_range_set_value(GTK_RANGE(widget),val); + gtk_scale_set_draw_value(GTK_SCALE(widget),0); + } + G_SIGNAL(widget,"value-changed",zdialog_widget_event,zd); + sprintf(vdata,"%g",val); + data = vdata; + } + + if (strEqu(type,"colorbutt")) { // color edit button + if (! data) data = "0|0|0"; // data format: "nnn|nnn|nnn" = RGB + pp = strField(data,'|',1); gdkcolor.red = 256 * atoi(pp); + pp = strField(data,'|',2); gdkcolor.green = 256 * atoi(pp); + pp = strField(data,'|',3); gdkcolor.blue = 256 * atoi(pp); + widget = gtk_color_button_new_with_color(&gdkcolor); + G_SIGNAL(widget,"color-set",zdialog_widget_event,zd); + } + + // all widget types come here -void wclear(GtkWidget *mLog) -{ - GtkTextBuffer *buff; + zd->widget[iiw].widget = widget; // set widget in zdialog - if (! mLog) return; // v.3.0 + if (strEqu(ptype,"hbox") || strEqu(ptype,"vbox")) // add to hbox/vbox + gtk_box_pack_start(GTK_BOX(pwidget),widget,expand,expand,space); + if (strEqu(ptype,"frame")) // add to frame + gtk_container_add(GTK_CONTAINER(pwidget),widget); + if (strEqu(ptype,"scrwin")) // add to scroll window + gtk_container_add(GTK_CONTAINER(pwidget),widget); + if (strEqu(ptype,"dialog")) // add to dialog box + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(pwidget)->vbox), + widget,expand,expand,space); + if (data) + zd->widget[iiw].data = strdupz(data,0,"zdialog"); // use heap memory - buff = gtk_text_view_get_buffer(GTK_TEXT_VIEW(mLog)); - gtk_text_buffer_set_text(buff,"",-1); - return; + return 0; } -// clear a text view window from designated line to end of buffer +// add widget to existing zdialog - alternative form (clearer and easier code) +// options: "scc=nn | homog | expand | space=nn | wrap" (all optional, any order) -void wclear(GtkWidget *mLog, int line) +int zdialog_add_widget(zdialog *zd, cchar *type, cchar *name, + cchar *parent, cchar *data, cchar *options) { - GtkTextBuffer *textBuff; - GtkTextIter iter1, iter2; - - if (! mLog) return; // v.3.0 - - textBuff = gtk_text_view_get_buffer(GTK_TEXT_VIEW(mLog)); - gtk_text_buffer_get_iter_at_line(textBuff,&iter1,line-1); // iter at line start - gtk_text_buffer_get_end_iter(textBuff,&iter2); - gtk_text_buffer_delete(textBuff,&iter1,&iter2); // delete existing line - return; + int stat, scc = 0, homog = 0, expand = 0, space = 0, wrap = 0, begin = 1; + char pname[8]; + double pval; + + while (true) + { + stat = strParms(begin,options,pname,8,pval); + if (stat == -1) break; + if (stat == 1) zappcrash("bad zdialog options: %s",options); + if (strEqu(pname,"scc")) scc = (int(pval)); + else if (strEqu(pname,"homog")) homog = 1; + else if (strEqu(pname,"expand")) expand = 1; + else if (strEqu(pname,"space")) space = (int(pval)); + else if (strEqu(pname,"wrap")) wrap = 1; + else zappcrash("bad zdialog options: %s",options); + } + + stat = zdialog_add_widget(zd,type,name,parent,data,scc,homog,expand,space,wrap); + return stat; } -/**************************************************************************/ - -// get text records from a text view window, one per call -// removes trailing new line characters ( \n ) +// get GTK widget from zdialog and widget name -char * wscanf(GtkWidget *mLog, int & ftf) +GtkWidget * zdialog_widget(zdialog *zd, cchar *name) { - GtkTextBuffer *textBuff; - GtkTextIter iter1, iter2; - static char *precs = 0, *prec1, *pret; - static int cc; - - if (! mLog) return 0; // v.3.0 - - if (ftf) - { // get all window text - ftf = 0; - if (precs) g_free(precs); // free prior memory if there - textBuff = gtk_text_view_get_buffer(GTK_TEXT_VIEW(mLog)); // get all text - gtk_text_buffer_get_bounds(textBuff,&iter1,&iter2); - precs = gtk_text_buffer_get_text(textBuff,&iter1,&iter2,0); - prec1 = precs; // 1st record - } - - if (! precs || (*prec1 == 0)) // no more records - { - if (precs) g_free(precs); - precs = 0; - return 0; - } + if (! zd) return 0; // detect destroyed dialog + if (zd->sentinel != zdsentinel) return 0; - cc = 0; - while ((prec1[cc] != 0) && (prec1[cc] != '\n')) cc++; // scan for terminator - pret = prec1; - prec1 = prec1 + cc; // next record - if (*prec1 == '\n') prec1++; - pret[cc] = 0; // replace \n with 0 - return pret; + for (int ii = 0; zd->widget[ii].type; ii++) // v.4.4 + if (strEqu(zd->widget[ii].name,name)) return zd->widget[ii].widget; + return 0; } -/**************************************************************************/ - -// dump text window into file -// return: 0: OK +N: error - -int wfiledump_maxcc = 0; +// set a common group for a set of radio buttons -int wfiledump(GtkWidget *mLog, char *filespec) +int zdialog_set_group(zdialog *zd, cchar *radio1, ...) // (GTK, this does not work) { - FILE *fid; - char *prec; - int ftf, err, cc; + va_list arglist; + cchar *radio2; + GtkWidget *gwidget, *widget; + GSList *glist; - if (! mLog) return 0; // v.3.0 + gwidget = zdialog_widget(zd,radio1); + glist = gtk_radio_button_get_group(GTK_RADIO_BUTTON(gwidget)); + if (! glist) zappcrash("no radio button group"); - fid = fopen(filespec,"w"); // open file - if (! fid) { - zmessageACK(null,ZTX("cannot open file %s"),filespec); - return 1; - } - - wfiledump_maxcc = 0; + va_start(arglist,radio1); - ftf = 1; while (true) { - prec = wscanf(mLog,ftf); // get text line - if (! prec) break; - fprintf(fid,"%s\n",prec); // output with \n - cc = strlen(prec); - if (cc > wfiledump_maxcc) wfiledump_maxcc = cc; + radio2 = va_arg(arglist,cchar *); + if (! radio2) break; + widget = zdialog_widget(zd,radio2); + gtk_radio_button_set_group(GTK_RADIO_BUTTON(widget),glist); } - err = fclose(fid); // close file - if (err) { zmessageACK(null,"file close error"); return 2; } - else return 0; -} + va_end(arglist); + return 0; +} -/**************************************************************************/ -// save text window to file, via file chooser dialog +// resize dialog to a size greater than initial size +// (as determined by the included widgets) -void wfilesave(GtkWidget *mLog) +int zdialog_resize(zdialog *zd, int width, int height) { - int err; - char *file; - - if (! mLog) return; // v.3.0 + if (! zd) zappcrash("zdialog null pointer"); // detect destroyed dialog + if (zd->sentinel != zdsentinel) zappcrash("zdialog invalid"); - file = zgetfile1(ZTX("save screen to file"),"save","screen-save.txt"); - if (! file) return; - err = wfiledump(mLog,file); - if (err) zmessageACK(null,"save screen failed (%d)",err); - zfree(file); - return; + GtkWidget *window = zd->widget[0].widget; + gtk_window_set_default_size(GTK_WINDOW(window),width,height); + return 1; } -/**************************************************************************/ - -// print text window to default printer -// use landscape mode if max. print line > A4 width +// put data into a zdialog widget -void wprintp(GtkWidget *mLog) +int zdialog_put_data(zdialog *zd, cchar *name, cchar *data) { - int pid, err; - char tempfile[50], command[200]; - - if (! mLog) return; // v.3.0 - - pid = getpid(); - snprintf(tempfile,49,"/tmp/wprintp-%d",pid); - err = wfiledump(mLog,tempfile); - if (err) return; + GtkWidget *widget; + GtkTextBuffer *textBuff; + GdkColor gdkcolor; + int iiw, nn, kk; + cchar *type, *pp; + char *wdata; + double val; + + if (! zd || zd->sentinel != zdsentinel) { // detect destroyed dialog + printf("zdialog_put_data(%s,%s), zdialog invalid \n",name,data); + return 0; + } + + for (iiw = 1; zd->widget[iiw].type; iiw++) // find widget + if (strEqu(zd->widget[iiw].name,name)) break; + if (! zd->widget[iiw].type) { + printf("zdialog_put_data(%s), widget invalid \n",name); // v.4.4 + return 0; + } + + type = zd->widget[iiw].type; + widget = zd->widget[iiw].widget; - if (wfiledump_maxcc < 97) - snprintf(command,199,"lp -o %s -o %s -o %s -o %s -o %s -o %s %s", - "cpi=14","lpi=8","page-left=50","page-top=50", - "page-right=40","page-bottom=40",tempfile); + wdata = zd->widget[iiw].data; + if (wdata) zfree(wdata); // free prior data memory + zd->widget[iiw].data = 0; - else - snprintf(command,199,"lp -o %s -o %s -o %s -o %s -o %s -o %s -o %s %s", - "landscape","cpi=14","lpi=8","page-left=50","page-top=50", - "page-right=40","page-bottom=40",tempfile); + if (data) { + wdata = strdupz(data,0,"zdialog"); // set new data for widget + zd->widget[iiw].data = wdata; + if (utf8_check(wdata)) + printf("zdialog: bad UTF8 encoding %s \n",wdata); + } + + zd->disabled++; // disable for widget stuffing - err = system(command); - if (err) zmessLogACK(null,"print error %s",wstrerror(err)); - return; -} + if (strEqu(type,"label")) + gtk_label_set_text(GTK_LABEL(widget),data); + if (strEqu(type,"link")) + gtk_label_set_text(GTK_LABEL(widget),data); -/************************************************************************** - simplified GTK menu bar, tool bar, status bar functions -***************************************************************************/ + if (strEqu(type,"entry")) + gtk_entry_set_text(GTK_ENTRY(widget),data); -int tbIconSize = 24; // valid during toolbar construction -GtkTooltips *tbTooltips = 0; // one instance for all toolbars + if (strEqu(type,"button")) // change button label + gtk_button_set_label(GTK_BUTTON(widget),data); + if (strEqu(type,"edit")) { + textBuff = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget)); + gtk_text_buffer_set_text(textBuff,data,-1); + } + + if (strcmpv(type,"togbutt","check","radio",null)) + { + if (! data) kk = nn = 0; + else kk = convSI(data,nn); + if (kk != 0) nn = 0; // data not integer, force zero + if (nn <= 0) nn = 0; else nn = 1; + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget),nn); // set gtk widget value + } -// create menu bar and add to vertical packing box + if (strEqu(type,"spin")) { + kk = convSD(data,val); + if (kk != 0) val = 0.0; + gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget),val); + } + + if (strEqu(type,"colorbutt")) { // color button + pp = strField(data,'|',1); + if (pp) gdkcolor.red = 256 * atoi(pp); // bugfix + pp = strField(data,'|',2); + if (pp) gdkcolor.green = 256 * atoi(pp); + pp = strField(data,'|',3); + if (pp) gdkcolor.blue = 256 * atoi(pp); + gtk_color_button_set_color(GTK_COLOR_BUTTON(widget),&gdkcolor); + } + + if (strcmpv(type,"hscale","vscale",null)) { + kk = convSD(data,val); + if (kk != 0) val = 0.0; + gtk_range_set_value(GTK_RANGE(widget),val); + } + + if (strEqu(type,"combo")) { + if (! blank_null(data)) { + kk = pvlist_prepend(zd->widget[iiw].cblist,data,1); // add to drop-down list + if (kk == 0) // (only if unique) + gtk_combo_box_prepend_text(GTK_COMBO_BOX(widget),data); + kk = pvlist_find(zd->widget[iiw].cblist,data); + gtk_combo_box_set_active(GTK_COMBO_BOX(widget),kk); // make the active entry + } + else gtk_combo_box_set_active(GTK_COMBO_BOX(widget),-1); // make no active entry + } -GtkWidget * create_menubar(GtkWidget *vbox) // icon size removed v.2.29 -{ - GtkWidget *wmbar; + if (strEqu(type,"comboE")) { + if (! blank_null(data)) { + kk = pvlist_prepend(zd->widget[iiw].cblist,data,1); // add to drop-down list + if (kk == 0) // (only if unique) + gtk_combo_box_prepend_text(GTK_COMBO_BOX(widget),data); + gtk_entry_set_text(GTK_ENTRY(GTK_BIN(widget)->child),data); // stuff entry box with new data + } + else gtk_entry_set_text(GTK_ENTRY(GTK_BIN(widget)->child),""); // stuff entry box with nothing + } - wmbar = gtk_menu_bar_new(); - gtk_box_pack_start(GTK_BOX(vbox),wmbar,0,0,0); - return wmbar; + zd->disabled--; // re-enable dialog + return iiw; } -// add menu item to menu bar +// get data from a dialog widget based on its name -GtkWidget * add_menubar_item(GtkWidget *wmbar, cchar *mname, mtFunc func) +cchar * zdialog_get_data(zdialog *zd, cchar *name) { - GtkWidget *wmitem; + if (! zd) return 0; // detect destroyed dialog + if (zd->sentinel != zdsentinel) return 0; - wmitem = gtk_menu_item_new_with_label(mname); - gtk_menu_shell_append(GTK_MENU_SHELL(wmbar),wmitem); - if (func) G_SIGNAL(wmitem,"activate",func,mname); - return wmitem; + for (int ii = 1; zd->widget[ii].type; ii++) + if (strEqu(zd->widget[ii].name,name)) + return zd->widget[ii].data; + return 0; } -// create a popup menu // v.4.7 +// set new limits for a numeric data entry widget (spin, hscale, vscale) -GtkWidget * create_popmenu() +int zdialog_set_limits(zdialog *zd, cchar *name, double min, double max) // new v.4.4 { - GtkWidget *popmenu; + GtkWidget *widget; + cchar *type; + int iiw; - popmenu = gtk_menu_new(); - return popmenu; -} + if (! zd) return 0; // detect destroyed dialog + if (zd->sentinel != zdsentinel) return 0; + + for (iiw = 1; zd->widget[iiw].type; iiw++) + if (strEqu(name,zd->widget[iiw].name)) break; + if (! zd->widget[iiw].type) { + printf("zdialog_stuff_limits, %s not found \n",name); + return 0; + } + widget = zd->widget[iiw].widget; + type = zd->widget[iiw].type; -// add a menu item to a popup menu // v.4.7 + if (*type == 's') + gtk_spin_button_set_range(GTK_SPIN_BUTTON(widget),min,max); -GtkWidget * add_popmenu_item(GtkWidget *popmenu, cchar *mname, mtFunc func) -{ - GtkWidget *wmitem; + if (*type == 'h' || *type == 'v') + gtk_range_set_range(GTK_RANGE(widget),min,max); - wmitem = gtk_menu_item_new_with_label(mname); - gtk_menu_shell_append(GTK_MENU_SHELL(popmenu),wmitem); - if (func) G_SIGNAL(wmitem,"activate",func,mname); - return wmitem; + return 1; } -// pop-up the menu at current mouse position // v.4.7 +// put help topic into dialog -void popup_menu(GtkWidget *popmenu) +void zdialog_help(zdialog *zd, cchar *help_topic) { - gtk_menu_popup(GTK_MENU(popmenu),0,0,0,0,0,gtk_get_current_event_time()); - gtk_widget_show_all(popmenu); + zd->help_topic = help_topic; return; } -// add submenu item to menu item, optional response function -// icon code removed // v.2.29 +// run the dialog and send events to the event function +// evfunc: int func(zdialog *zd, cchar *event) +// posn: optional dialog box position (see zdialog_set_position) -GtkWidget * add_submenu_item(GtkWidget *wmitem, cchar *mlab, mtFunc func) +int zdialog_run(zdialog *zd, zdialog_event evfunc, cchar *posn) // v.4.4 { - GtkWidget *wmsub, *wmsubitem; - GtkWidget *wicon = 0; + int zdialog_KBpress(GtkWidget *, GdkEventKey *event, zdialog *zd); + int zdialog_KBrelease(GtkWidget *, GdkEventKey *event, zdialog *zd); + int zdialog_focus_event_signal(GtkWidget *, GdkEvent *event, zdialog *zd); - wmsub = gtk_menu_item_get_submenu(GTK_MENU_ITEM(wmitem)); - if (wmsub == null) { - wmsub = gtk_menu_new(); - gtk_menu_item_set_submenu(GTK_MENU_ITEM(wmitem),wmsub); - } + int ii; + GtkWidget *widget, *dialog; + + if (! zd) zappcrash("zdialog null pointer"); // detect destroyed dialog + if (zd->sentinel != zdsentinel) zappcrash("zdialog invalid"); - if (strEqu(mlab,"separator")) // v.2.16 - wmsubitem = gtk_separator_menu_item_new(); - else { - if (wicon) { - wmsubitem = gtk_image_menu_item_new_with_label(mlab); - gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(wmsubitem),wicon); - } - else wmsubitem = gtk_menu_item_new_with_label(mlab); - } + dialog = zd->widget[0].widget; - gtk_menu_shell_append(GTK_MENU_SHELL(wmsub),wmsubitem); - if (func) G_SIGNAL(wmsubitem,"activate",func,mlab); - return wmsubitem; -} + if (posn) zdialog_set_position(zd,posn); // v.4.4 + for (ii = 1; zd->widget[ii].type; ii++) // *** stop auto-selection + { // (GTK "feature") + if (strEqu(zd->widget[ii].type,"entry")) { + widget = zd->widget[ii].widget; + gtk_editable_set_position(GTK_EDITABLE(widget),-1); + break; + } -// create toolbar and add to vertical packing box + if (strEqu(zd->widget[ii].type,"comboE")) { // also combo edit box + widget = zd->widget[ii].widget; + gtk_editable_set_position(GTK_EDITABLE(GTK_BIN(widget)->child),-1); + break; + } + } -GtkWidget * create_toolbar(GtkWidget *vbox, int iconsize, int vert) -{ - using namespace zfuncs; + if (evfunc) zd->eventCB = (void *) evfunc; // link to dialog event callback - GtkWidget *wtbar; + dialog = zd->widget[0].widget; + gtk_widget_show_all(dialog); // activate dialog + gtk_window_present(GTK_WINDOW(dialog)); + if (! zd->parent) // if no parent, force to top + gtk_window_set_keep_above(GTK_WINDOW(dialog),1); // v.4.9 - wtbar = gtk_toolbar_new(); - if (vert) gtk_toolbar_set_orientation(GTK_TOOLBAR(wtbar),GTK_ORIENTATION_VERTICAL); - gtk_box_pack_start(GTK_BOX(vbox),wtbar,0,0,0); - tbIconSize = iconsize; + G_SIGNAL(dialog,"focus-in-event",zdialog_focus_event_signal,zd); // connect focus event function v.5.0 + G_SIGNAL(dialog,"key-press-event",zdialog_KBpress,zd); // connect key press event function + G_SIGNAL(dialog,"key-release-event",zdialog_KBrelease,zd); // connect key release event function + G_SIGNAL(dialog,"response",zdialog_response_event,zd); // connect dialog response function - if (! tbTooltips) tbTooltips = gtk_tooltips_new(); - return wtbar; + zd->disabled = 0; // enable widget events v.4.7 + + zfuncs::zdialog_busy++; // count open zdialogs v.4.7 + + return 0; // return now, dialog is non-modal } -// add toolbar button with stock icon ("gtk-quit") or custom icon ("iconfile.png") +// zdialog event handler - private function called for dialog events. +// Updates data in zdialog, calls user callback function (if present). -GtkWidget * add_toolbar_button(GtkWidget *wtbar, cchar *blab, cchar *btip, cchar *icon, mtFunc func) +int zdialog_widget_event(GtkWidget *widget, zdialog *zd) { - using namespace zfuncs; - - GtkToolItem *tbutton; - GError *gerror = 0; - GdkPixbuf *pixbuf; - GtkWidget *wicon = 0; - char iconpath[200]; - - if (blab && strEqu(blab,"separator")) { // v.4.3 - tbutton = gtk_separator_tool_item_new(); - gtk_toolbar_insert(GTK_TOOLBAR(wtbar),GTK_TOOL_ITEM(tbutton),-1); - return (GtkWidget *) tbutton; - } + zdialog_event *evfunc = 0; // dialog event callback function - if (icon == null || *icon == 0) - tbutton = gtk_tool_button_new(0,0); + GtkTextView *textView = 0; + GtkTextBuffer *textBuff = 0; + GtkTextIter iter1, iter2; + GdkColor gdkcolor; + static GtkWidget *lastwidget = 0; + int ii, nn; + cchar *wname, *type, *wdata; + char sdata[20]; + double dval; + static int cbadded = 0; - else if (strnEqu(icon,"gtk-",4)) - tbutton = gtk_tool_button_new_from_stock(icon); + if (! zd) return 1; // detect destroyed dialog v.5.0 + if (zd->sentinel != zdsentinel) return 1; + + for (ii = 0; ii < zdmaxbutts; ii++) // check completion buttons + if (zd->compbutt[ii] == widget) break; + if (ii < zdmaxbutts) { + zd->zstat = ii+1; // zdialog status = button no. + if (zd->eventCB) { + evfunc = (zdialog_event *) zd->eventCB; // do callback function + evfunc(zd,"zstat"); + } + return 1; // v.5.0 + } - else { - *iconpath = 0; - strncatv(iconpath,199,zicondir,"/",icon,null); - pixbuf = gdk_pixbuf_new_from_file_at_scale(iconpath,tbIconSize,tbIconSize,1,&gerror); - if (pixbuf) wicon = gtk_image_new_from_pixbuf(pixbuf); - if (wicon) tbutton = gtk_tool_button_new(wicon,0); - else tbutton = gtk_tool_button_new_from_stock("gtk-missing-image"); + for (ii = 1; zd->widget[ii].type; ii++) // find widget in zdialog + if (zd->widget[ii].widget == widget) goto found_widget; + + for (ii = 1; zd->widget[ii].type; ii++) { // failed, test if buffer + if (strEqu(zd->widget[ii].type,"edit")) { // of text view widget + textView = GTK_TEXT_VIEW(zd->widget[ii].widget); + textBuff = gtk_text_view_get_buffer(textView); + if (widget == (GtkWidget *) textBuff) goto found_widget; + } } - if (blab) gtk_tool_button_set_label(GTK_TOOL_BUTTON(tbutton),blab); - if (btip) gtk_tool_item_set_tooltip(tbutton,tbTooltips,btip,""); - gtk_tool_item_set_homogeneous(tbutton,0); // v.3.5 - gtk_toolbar_insert(GTK_TOOLBAR(wtbar),GTK_TOOL_ITEM(tbutton),-1); - if (func) G_SIGNAL(tbutton,"clicked",func,blab); - return (GtkWidget *) tbutton; -} + printf("zdialog event %s, ignored \n",zd->widget[ii].name); // not found, ignore event v.4.7 + return 1; +found_widget: -// create a status bar and add to the start of a packing box + if (zd->disabled) return 1; // stop re-entrance from own updates + zd->disabled = 1; // (zdialog_put_data()) -GtkWidget * create_stbar(GtkWidget *pbox) -{ - GtkWidget *stbar; - static PangoFontDescription *fontdesc; + wname = zd->widget[ii].name; + type = zd->widget[ii].type; + wdata = 0; - stbar = gtk_statusbar_new(); - fontdesc = pango_font_description_from_string("Monospace 9"); - gtk_widget_modify_font(stbar,fontdesc); // *** GTK does not work *** - gtk_box_pack_start(GTK_BOX(pbox),stbar,0,0,0); - gtk_widget_show(stbar); - return stbar; -} + if (strEqu(type,"button")) wdata = "clicked"; + + if (strEqu(type,"entry")) + wdata = gtk_entry_get_text(GTK_ENTRY(widget)); + + if (strEqu(type,"edit")) { + gtk_text_buffer_get_bounds(textBuff,&iter1,&iter2); + wdata = gtk_text_buffer_get_text(textBuff,&iter1,&iter2,0); + } + if (strcmpv(type,"radio","check","togbutt",null)) + { + nn = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); + if (nn == 0) wdata = "0"; + else wdata = "1"; + } -// display message in status bar + if (strEqu(type,"combo")) + wdata = gtk_combo_box_get_active_text(GTK_COMBO_BOX(widget)); -int stbar_message(GtkWidget *wstbar, cchar *message) -{ - static int ctx = -1; + if (strEqu(type,"comboE")) + { + if (widget == lastwidget && cbadded) { + pvlist_remove(zd->widget[ii].cblist,0); // detect multiple edits (keystrokes) + gtk_combo_box_remove_text(GTK_COMBO_BOX(widget),0); // and replace prior entry with new + } + wdata = gtk_entry_get_text(GTK_ENTRY(GTK_BIN(widget)->child)); + cbadded = 0; + if (! blank_null(wdata)) { + nn = pvlist_prepend(zd->widget[ii].cblist,wdata,1); // add entry to drop-down list + if (nn == 0) { // (only if unique) + gtk_combo_box_prepend_text(GTK_COMBO_BOX(widget),wdata); + cbadded = 1; + } + } + } + + if (strEqu(type,"spin")) + { + dval = gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget)); + sprintf(sdata,"%g",dval); + wdata = sdata; + } + + if (strEqu(type,"colorbutt")) // color button + { + gtk_color_button_get_color(GTK_COLOR_BUTTON(widget),&gdkcolor); + sprintf(sdata,"%d|%d|%d",gdkcolor.red/256,gdkcolor.green/256,gdkcolor.blue/256); + wdata = sdata; + } + + if (strcmpv(type,"hscale","vscale",null)) + { + dval = gtk_range_get_value(GTK_RANGE(widget)); + sprintf(sdata,"%g",dval); + wdata = sdata; + } + + // all widgets come here - if (ctx == -1) ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(wstbar),"all"); - gtk_statusbar_pop(GTK_STATUSBAR(wstbar),ctx); - gtk_statusbar_push(GTK_STATUSBAR(wstbar),ctx,message); - return 0; + if (zd->widget[ii].data) zfree(zd->widget[ii].data); // clear prior data + zd->widget[ii].data = 0; + + if (wdata) zd->widget[ii].data = strdupz(wdata,0,"zdialog"); // set new data + + lastwidget = widget; // remember last widget updated + + if (zd->eventCB) { + evfunc = (zdialog_event *) zd->eventCB; // do user callback function + evfunc(zd,wname); + } + + zd->disabled = 0; // re-enable widgets + return 1; // v.5.0 } -/************************************************************************** - simplified GTK dialog functions -***************************************************************************/ +// zdialog response handler for "focus-in-event" signal // v.5.0 + +int zdialog_focus_event_signal(GtkWidget *, GdkEvent *event, zdialog *zd) +{ + if (zd->zstat) return 0; // already complete + if (zd->help_topic) + zfuncs::F1_help_topic = zd->help_topic; // set help topic + zdialog_send_event(zd,"focus"); // notify dialog event function + return 0; // must be 0 +} -// counter, keeps track of open or pending zdialogs +// zdialog response handler for keyboard events -namespace zfuncs { int zdialog_busy; } +int zdialog_KBpress(GtkWidget *, GdkEventKey *event, zdialog *zd) // prevent KB key press from being +{ // sent to toolbar buttons + return 0; // must be 0 +} +int zdialog_KBrelease(GtkWidget *, GdkEventKey *kbevent, zdialog *zd) +{ + zdialog_event *evfunc = 0; // dialog event callback function -// private functions for widget events and dialog completion + int KBkey = kbevent->keyval; + char event[8]; + + if (KBkey == GDK_F1) { + showz_userguide(zfuncs::F1_help_topic); // context help + return 1; + } -void zdialog_widget_event(GtkWidget *, zdialog *zd); -void zdialog_response_event(GtkWidget *, int stat, zdialog *zd); + if (zd->eventCB) { + evfunc = (zdialog_event *) zd->eventCB; // do user callback function v.4.7 + strcpy(event,"KB x"); // with event = "KB x" + event[3] = KBkey; // (x = key now released) + evfunc(zd,event); + return 1; + } + return 0; +} -// create a new zdialog dialog -// optional arguments: up to zdmaxbutts button labels followed by null -// returned dialog status: +N = button N (1 to zdmaxbutts) -// <0 = [x] button or other GTK destroy action -// v.3.5 overhaul: -// build own completion buttons, replacing the fat GTK standard buttons -// completion buttons are also events like other widgets -// get rid of separate dialog completion function -// all dialogs run parallel, use zdialog_wait() if needed +// zdialog response handler - private function called when dialog is completed. +// called when dialog is canceled via [x] button or destroyed by GTK (zstat < 0). -zdialog * zdialog_new(cchar *title, GtkWidget *parent, ...) // parent added v.2.5 +int zdialog_response_event(GtkWidget *, int zstat, zdialog *zd) { - zdialog *zd; - GtkWidget *dialog, *hbox, *butt, *hsep; - cchar *bulab[zdmaxbutts]; - int cc, ii, nbu; - va_list arglist; + zdialog_event *evfunc = 0; // dialog event callback function - va_start(arglist,parent); - for (nbu = 0; nbu < zdmaxbutts; nbu++) // get completion buttons - { - bulab[nbu] = va_arg(arglist, cchar *); - if (! bulab[nbu]) break; + if (! zd) return 1; // detect destroyed dialog v.4.9 + if (zd->sentinel != zdsentinel) return 1; + if (zd->zstat) return 1; // already complete + + if (zstat > -1) zstat = -1; // insure cancel status v.5.0 + zd->zstat = zstat; // set zdialog status + + if (zd->eventCB) { + evfunc = (zdialog_event *) zd->eventCB; // do callback function + evfunc(zd,"zstat"); // (should do zfree()) } - va_end(arglist); - dialog = gtk_dialog_new(); // attributes optional v.3.3 - if (title) gtk_window_set_title(GTK_WINDOW(dialog),title); - gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog)->vbox),2); - gtk_dialog_set_has_separator(GTK_DIALOG(dialog),0); + return 1; // v.5.0 +} - cc = sizeof(zdialog); // allocate zdialog - zd = (zdialog *) zmalloc(cc,"zdialog"); // v.3.5 - if (parent) { // v.4.4 - zd->parent = parent; - gtk_window_set_transient_for(GTK_WINDOW(dialog),GTK_WINDOW(parent)); - } +// send an event to an active dialog - if (nbu) { // there are some completion buttons - hbox = gtk_hbox_new(0,0); - gtk_box_pack_end(GTK_BOX(GTK_DIALOG(dialog)->vbox),hbox,0,0,0); // add hbox for buttons at dialog bottom - hsep = gtk_hseparator_new(); // add separator line - gtk_box_pack_end(GTK_BOX(GTK_DIALOG(dialog)->vbox),hsep,0,0,5); +int zdialog_send_event(zdialog *zd, cchar *event) +{ + zdialog_event * evfunc = 0; // dialog event callback function - for (ii = nbu-1; ii >= 0; ii--) { // add buttons to hbox - butt = gtk_button_new_with_label(bulab[ii]); // reverse order nbu-1...0 - gtk_box_pack_end(GTK_BOX(hbox),butt,0,0,5); - G_SIGNAL(butt,"clicked",zdialog_widget_event,zd) // connect to event function - zd->compbutt[ii] = butt; // save button widgets - } + if (zd && zd->sentinel == zdsentinel) { // check dialog is active + evfunc = (zdialog_event *) zd->eventCB; + if (evfunc) evfunc(zd,event); // call dialog event function } - - zd->sentinel = zdsentinel; // validity sentinel - zd->eventCB = 0; // no user event callback function - zd->zstat = 0; // no zdialog status - zd->disabled = 1; // widget signals disabled - zd->saveposn = 0; // position not saved v.4.4 - zd->help_topic = 0; // no help topic v.4.5 - - zd->widget[0].type = "dialog"; // set up 1st widget = dialog - zd->widget[0].name = "dialog"; - zd->widget[0].pname = 0; - zd->widget[0].data = strdupz(title,0,"zdialog"); // v.3.5 - zd->widget[0].cblist = 0; - zd->widget[0].widget = dialog; - zd->widget[1].type = 0; // eof - no contained widgets yet - return zd; + return 1; } -// add widget to existing zdialog +// Complete a dialog and give it a status, without user action. +// Dialog event function will be called, zdialog_wait() will return. +// returns: 0 = no active dialog, 1 = OK -int zdialog_add_widget ( - zdialog *zd, cchar *type, cchar *name, cchar *pname, // mandatory args - cchar *data, int scc, int homog, int expand, int space, int wrap) // optional args (default = 0) +int zdialog_send_response(zdialog *zd, int zstat) { - GtkWidget *widget = 0, *pwidget = 0; - GtkTextBuffer *editBuff = 0; - GdkColor gdkcolor; - cchar *pp, *ptype = 0; - char vdata[30]; - double min, max, step, val; - int iiw, iip, kk, err; + zdialog_event *evfunc = 0; // dialog event callback function - static PangoFontDescription *monofont = 0; - - if (! zd) zappcrash("zdialog null pointer"); // detect destroyed dialog v.2.2 - if (zd->sentinel != zdsentinel) zappcrash("zdialog invalid"); + if (! zd) return 0; // detect destroyed dialog + if (zd->sentinel != zdsentinel) return 0; - for (iiw = 1; zd->widget[iiw].type; iiw++); // find next avail. slot - if (iiw > zdmaxwidgets-2) zappcrash("too many widgets: %d",iiw); + zd->zstat = zstat; // set status - zd->widget[iiw].type = strdupz(type,0,"zdialog"); // initz. widget struct v.3.5 - zd->widget[iiw].name = strdupz(name,0,"zdialog"); // all strings in nonvolatile mem - zd->widget[iiw].pname = strdupz(pname,0,"zdialog"); - zd->widget[iiw].data = 0; - zd->widget[iiw].cblist = 0; - zd->widget[iiw].scc = scc; - zd->widget[iiw].homog = homog; - zd->widget[iiw].expand = expand; - zd->widget[iiw].space = space; - zd->widget[iiw].wrap = wrap; - zd->widget[iiw].widget = 0; + if (zd->eventCB) { + evfunc = (zdialog_event *) zd->eventCB; // do callback function + evfunc(zd,"zstat"); + } - zd->widget[iiw+1].type = 0; // new EOF marker + return 1; +} - if (strcmpv(type,"dialog","hbox","vbox","hsep","vsep","frame","scrwin", - "label","link","entry","edit","button","togbutt","check","combo", - "comboE","radio","spin","hscale","vscale","colorbutt", null) == 0) - zappcrash("zdialog, bad widget type: %s",type); - for (iip = iiw-1; iip >= 0; iip--) // find parent (container) widget - if (strEqu(pname,zd->widget[iip].name)) break; - if (iip < 0) zappcrash("zdialog, no parent for widget: %s",name); +// Destroy the zdialog - must be done by zdialog_run() caller +// (else dialog continues active even after completion button). +// Data in widgets remains valid until zdialog_free() is called. - pwidget = zd->widget[iip].widget; // parent widget, type - ptype = zd->widget[iip].type; +int zdialog_destroy(zdialog *zd) +{ + using namespace zfuncs; - if (strcmpv(ptype,"dialog","hbox","vbox","frame","scrwin",null) == 0) - zappcrash("zdialog, bad widget parent type: %s",ptype); + if (! zd) return 0; // detect destroyed dialog + if (zd->sentinel != zdsentinel) return 0; - if (! monofont) monofont = pango_font_description_from_string("Monospace"); - - if (strEqu(type,"hbox")) widget = gtk_hbox_new(homog,space); // expandable container boxes - if (strEqu(type,"vbox")) widget = gtk_vbox_new(homog,space); - - if (strEqu(type,"hsep")) widget = gtk_hseparator_new(); // horiz. & vert. separators - if (strEqu(type,"vsep")) widget = gtk_vseparator_new(); - - if (strEqu(type,"frame")) { // frame around contained widgets - widget = gtk_frame_new(data); - gtk_frame_set_shadow_type(GTK_FRAME(widget),GTK_SHADOW_IN); - } - - if (strEqu(type,"scrwin")) { // scrolled window container - widget = gtk_scrolled_window_new(0,0); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(widget), // v.2.10 - GTK_POLICY_AUTOMATIC,GTK_POLICY_AUTOMATIC); - } - - if (strEqu(type,"label")) widget = gtk_label_new(data); // label (static text) - - if (strEqu(type,"link")) { // label is clickable v.4.0 - widget = gtk_link_button_new(data); - G_SIGNAL(widget,"clicked",zdialog_widget_event,zd); - } - - if (strEqu(type,"entry")) { // 1-line text entry - widget = gtk_entry_new(); - if (data) gtk_entry_set_text(GTK_ENTRY(widget),data); - if (scc) gtk_entry_set_width_chars(GTK_ENTRY(widget),scc); - gtk_widget_modify_font(widget,monofont); - G_SIGNAL(widget,"changed",zdialog_widget_event,zd) - } - - if (strEqu(type,"edit")) { // multiline edit box - widget = gtk_text_view_new(); - editBuff = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget)); - if (data) gtk_text_buffer_set_text(editBuff,data,-1); - gtk_text_view_set_editable(GTK_TEXT_VIEW(widget),1); - if (wrap) gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(widget),GTK_WRAP_WORD); // v.4.3 - gtk_widget_modify_font(widget,monofont); - G_SIGNAL(editBuff,"changed",zdialog_widget_event,zd) // buffer signals, not widget - } - - if (strEqu(type,"button")) { // button - widget = gtk_button_new_with_label(data); - G_SIGNAL(widget,"clicked",zdialog_widget_event,zd) + if (zd->zstat < 0) { // destroyed by [x] button or GTK + zd->widget[0].widget = 0; // assume GTK dialog is gone + zdialog_busy--; // v.4.7 } - if (strEqu(type,"togbutt")) { // toggle button - widget = gtk_toggle_button_new_with_label(data); - G_SIGNAL(widget,"toggled",zdialog_widget_event,zd) + if (zd->widget[0].widget) { // multiple destroys OK + if (zd->saveposn) + zdialog_save_position(zd); // save position for next use v.4.7 + gtk_widget_destroy(zd->widget[0].widget); // destroy GTK dialog + zdialog_busy--; // v.4.7 + zd->widget[0].widget = 0; } + + if (! zd->zstat) zd->zstat = -1; // status = destroyed + return 1; +} - if (strEqu(type,"check")) { // checkbox - if (data) widget = gtk_check_button_new_with_label(data); - else widget = gtk_check_button_new(); - G_SIGNAL(widget,"toggled",zdialog_widget_event,zd) - } - - if (strEqu(type,"combo")) { // combo box - widget = gtk_combo_box_new_text(); - zd->widget[iiw].cblist = pvlist_create(zdcbmax); // for drop-down list - if (! blank_null(data)) { - pvlist_append(zd->widget[iiw].cblist,data); // add data to drop-down list - gtk_combo_box_append_text(GTK_COMBO_BOX(widget),data); - gtk_combo_box_set_active(GTK_COMBO_BOX(widget),0); - } - gtk_widget_modify_font(widget,monofont); - G_SIGNAL(widget,"changed",zdialog_widget_event,zd) - } - if (strEqu(type,"comboE")) { // combo box with entry box - widget = gtk_combo_box_entry_new_text(); - zd->widget[iiw].cblist = pvlist_create(zdcbmax); // for drop-down list - if (! blank_null(data)) { - gtk_entry_set_text(GTK_ENTRY(GTK_BIN(widget)->child),data); // entry = initial data - pvlist_append(zd->widget[iiw].cblist,data); // add data to drop-down list - gtk_combo_box_append_text(GTK_COMBO_BOX(widget),data); - } - gtk_widget_modify_font(widget,monofont); - G_SIGNAL(widget,"changed",zdialog_widget_event,zd) - } - - if (strEqu(type,"radio")) { // radio button - for (kk = iip+1; kk <= iiw; kk++) - if (strEqu(zd->widget[kk].pname,pname) && // find first radio button - strEqu(zd->widget[kk].type,"radio")) break; // with same container - if (kk == iiw) - widget = gtk_radio_button_new_with_label(null,data); // this one is first - else - widget = gtk_radio_button_new_with_label_from_widget // not first, add to group - (GTK_RADIO_BUTTON(zd->widget[kk].widget),data); - G_SIGNAL(widget,"toggled",zdialog_widget_event,zd) - } +// free zdialog memory (destroy first, if not already) - if (strcmpv(type,"spin","hscale","vscale",null)) { // spin button or sliding scale - pp = strField(data,'|',1); err = convSD(pp,min); // locale fix - pp = strField(data,'|',2); err += convSD(pp,max); - pp = strField(data,'|',3); err += convSD(pp,step); - pp = strField(data,'|',4); err += convSD(pp,val); - if (err) { min = 0; max = 100; step = 1; val = 50; } +int zdialog_free(zdialog *&zd) // reference +{ + if (! zd) return 0; // detect destroyed dialog + if (zd->sentinel != zdsentinel) return 0; + zdialog_destroy(zd); // destroy GTK dialog if there + zd->sentinel = 0; // mark invalid + zfree(zd->widget[0].data); // bugfix memory leak - if (*type == 's') { - widget = gtk_spin_button_new_with_range(min,max,step); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget),val); - } - if (*type == 'h') { - widget = gtk_hscale_new_with_range(min,max,step); - gtk_range_set_value(GTK_RANGE(widget),val); - gtk_scale_set_draw_value(GTK_SCALE(widget),0); - } - if (*type == 'v') { - widget = gtk_vscale_new_with_range(min,max,step); - gtk_range_set_value(GTK_RANGE(widget),val); - gtk_scale_set_draw_value(GTK_SCALE(widget),0); - } - G_SIGNAL(widget,"value-changed",zdialog_widget_event,zd) - sprintf(vdata,"%g",val); - data = vdata; + for (int ii = 1; zd->widget[ii].type; ii++) // loop through widgets + { + if (strcmpv(zd->widget[ii].type,"combo","comboE",null)) // bugfix, free combo list + pvlist_free(zd->widget[ii].cblist); + zfree((char *) zd->widget[ii].type); // free strings + zfree((char *) zd->widget[ii].name); + zfree((char *) zd->widget[ii].pname); + if (zd->widget[ii].data) zfree(zd->widget[ii].data); // free data } - if (strEqu(type,"colorbutt")) { // color edit button v.2.17 - if (! data) data = "0|0|0"; // data format: "nnn|nnn|nnn" = RGB - pp = strField(data,'|',1); gdkcolor.red = 256 * atoi(pp); - pp = strField(data,'|',2); gdkcolor.green = 256 * atoi(pp); - pp = strField(data,'|',3); gdkcolor.blue = 256 * atoi(pp); - widget = gtk_color_button_new_with_color(&gdkcolor); - G_SIGNAL(widget,"color-set",zdialog_widget_event,zd) - } - - // all widget types come here - - zd->widget[iiw].widget = widget; // set widget in zdialog - - if (strEqu(ptype,"hbox") || strEqu(ptype,"vbox")) // add to hbox/vbox - gtk_box_pack_start(GTK_BOX(pwidget),widget,expand,expand,space); - if (strEqu(ptype,"frame")) // add to frame - gtk_container_add(GTK_CONTAINER(pwidget),widget); - if (strEqu(ptype,"scrwin")) // add to scroll window - gtk_container_add(GTK_CONTAINER(pwidget),widget); - if (strEqu(ptype,"dialog")) // add to dialog box - gtk_box_pack_start(GTK_BOX(GTK_DIALOG(pwidget)->vbox), - widget,expand,expand,space); - if (data) - zd->widget[iiw].data = strdupz(data,0,"zdialog"); // use heap memory v.3.5 - - return 0; + zfree(zd); // free zdialog memory + zd = 0; // clear pointer + return 1; } -// add widget to existing zdialog - alternative form (clearer and easier code) -// options: "scc=nn | homog | expand | space=nn | wrap" (all optional, any order) +// wait for a zdialog to have a completion status or be destroyed +// returns completion status or -1 if destroyed -int zdialog_add_widget(zdialog *zd, cchar *type, cchar *name, - cchar *parent, cchar *data, cchar *options) +int zdialog_wait(zdialog *zd) { - int stat, scc = 0, homog = 0, expand = 0, space = 0, wrap = 0, begin = 1; - char pname[8]; - double pval; - while (true) { - stat = strParms(begin,options,pname,8,pval); - if (stat == -1) break; - if (stat == 1) zappcrash("bad zdialog options: %s",options); - if (strEqu(pname,"scc")) scc = (int(pval)); - else if (strEqu(pname,"homog")) homog = 1; - else if (strEqu(pname,"expand")) expand = 1; - else if (strEqu(pname,"space")) space = (int(pval)); - else if (strEqu(pname,"wrap")) wrap = 1; - else zappcrash("bad zdialog options: %s",options); + zmainloop(); + if (! zd) return -1; // dialog destroyed + if (zd->sentinel != zdsentinel) return -1; + if (zd->zstat) return zd->zstat; + zsleep(0.01); } - - stat = zdialog_add_widget(zd,type,name,parent,data,scc,homog,expand,space,wrap); - return stat; } -// get GTK widget from zdialog and widget name +// put cursor at named widget -GtkWidget * zdialog_widget(zdialog *zd, cchar *name) +int zdialog_goto(zdialog *zd, cchar *name) { - if (! zd) return 0; // detect destroyed dialog v.2.2 + GtkWidget *widget; + if (zd->sentinel != zdsentinel) return 0; + widget = zdialog_widget(zd, name); + if (! widget) return 0; - for (int ii = 0; zd->widget[ii].type; ii++) // v.4.4 - if (strEqu(zd->widget[ii].name,name)) return zd->widget[ii].widget; - return 0; + gtk_editable_select_region(GTK_EDITABLE(widget),0,-1); // focus on widget + gtk_widget_grab_focus(widget); + + return 1; } -// set a common group for a set of radio buttons +// set cursor for zdialog (e.g. busy cursor) -int zdialog_set_group(zdialog *zd, cchar *radio1, ...) // new v.3.1 (GTK, this does not work) +void zdialog_set_cursor(zdialog *zd, GdkCursor *cursor) { - va_list arglist; - cchar *radio2; - GtkWidget *gwidget, *widget; - GSList *glist; + GtkWidget *dialog; + + if (zd->sentinel != zdsentinel) return; + dialog = zd->widget[0].widget; + if (! dialog) return; + gdk_window_set_cursor(dialog->window,cursor); + return; +} - gwidget = zdialog_widget(zd,radio1); - glist = gtk_radio_button_get_group(GTK_RADIO_BUTTON(gwidget)); - if (! glist) zappcrash("no radio button group"); - va_start(arglist,radio1); - - while (true) - { - radio2 = va_arg(arglist,cchar *); - if (! radio2) break; - widget = zdialog_widget(zd,radio2); - gtk_radio_button_set_group(GTK_RADIO_BUTTON(widget),glist); - } - - va_end(arglist); +// convenience functions for stuffing and retrieving widget data - return 0; +int zdialog_stuff(zdialog *zd, cchar *name, cchar *data) // stuff a string +{ + zdialog_put_data(zd, name, data); + return 1; } - -// resize dialog to a size greater than initial size -// (as determined by the included widgets) - -int zdialog_resize(zdialog *zd, int width, int height) +int zdialog_stuff(zdialog *zd, cchar *name, int idata) // stuff an integer { - if (! zd) zappcrash("zdialog null pointer"); // detect destroyed dialog v.2.2 - if (zd->sentinel != zdsentinel) zappcrash("zdialog invalid"); + char string[16]; - GtkWidget *window = zd->widget[0].widget; - gtk_window_set_default_size(GTK_WINDOW(window),width,height); + sprintf(string,"%d",idata); + zdialog_put_data(zd,name,string); return 1; } - -// put data into a zdialog widget - -int zdialog_put_data(zdialog *zd, cchar *name, cchar *data) +int zdialog_stuff(zdialog *zd, cchar *name, double ddata) // stuff a double { - GtkWidget *widget; - GtkTextBuffer *textBuff; - GdkColor gdkcolor; - int iiw, nn, kk; - cchar *type, *pp; - char *wdata; - double val; + char string[32]; - if (! zd || zd->sentinel != zdsentinel) { // detect destroyed dialog v.2.2 - printf("zdialog_put_data(%s,%s), zdialog invalid \n",name,data); + snprintf(string,31,"%g",ddata); // outputs decimal point or comma + zdialog_put_data(zd,name,string); // (per locale) + return 1; +} + +int zdialog_fetch(zdialog *zd, cchar *name, char *data, int maxcc) // fetch string data +{ + cchar *zdata; + + zdata = zdialog_get_data(zd,name); + if (! zdata) { + *data = 0; return 0; } - for (iiw = 1; zd->widget[iiw].type; iiw++) // find widget - if (strEqu(zd->widget[iiw].name,name)) break; - if (! zd->widget[iiw].type) { - printf("zdialog_put_data(%s), widget invalid \n",name); // v.4.4 + return strncpy0(data,zdata,maxcc); // 0 = OK, 1 = truncation +} + +int zdialog_fetch(zdialog *zd, cchar *name, int &idata) // fetch an integer +{ + cchar *zdata; + + zdata = zdialog_get_data(zd,name); + if (! zdata) { + idata = 0; return 0; } - type = zd->widget[iiw].type; - widget = zd->widget[iiw].widget; + idata = atoi(zdata); + return 1; +} - wdata = zd->widget[iiw].data; - if (wdata) zfree(wdata); // free prior data memory - zd->widget[iiw].data = 0; +int zdialog_fetch(zdialog *zd, cchar *name, double &ddata) // fetch a double +{ + int stat; + cchar *zdata; - if (data) { - wdata = strdupz(data,0,"zdialog"); // set new data for widget v.3.5 - zd->widget[iiw].data = wdata; - if (utf8_check(wdata)) - printf("zdialog: bad UTF8 encoding %s \n",wdata); // v.2.4 + zdata = zdialog_get_data(zd,name); + if (! zdata) { + ddata = 0; + return 0; } - zd->disabled++; // disable for widget stuffing v.2.9 - - if (strEqu(type,"label")) - gtk_label_set_text(GTK_LABEL(widget),data); - - if (strEqu(type,"link")) - gtk_label_set_text(GTK_LABEL(widget),data); - - if (strEqu(type,"entry")) - gtk_entry_set_text(GTK_ENTRY(widget),data); + stat = convSD(zdata,ddata); // period or comma decimal point OK + if (stat < 4) return 1; + return 0; +} - if (strEqu(type,"button")) // change button label v.2.21 - gtk_button_set_label(GTK_BUTTON(widget),data); +int zdialog_fetch(zdialog *zd, cchar *name, float &fdata) // fetch a float +{ + int stat; + cchar *zdata; + double ddata; - if (strEqu(type,"edit")) { - textBuff = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget)); - gtk_text_buffer_set_text(textBuff,data,-1); + zdata = zdialog_get_data(zd,name); + if (! zdata) { + fdata = 0; + return 0; } - if (strcmpv(type,"togbutt","check","radio",null)) - { - if (! data) kk = nn = 0; - else kk = convSI(data,nn); - if (kk != 0) nn = 0; // data not integer, force zero - if (nn <= 0) nn = 0; else nn = 1; - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget),nn); // set gtk widget value - } + stat = convSD(zdata,ddata); // period or comma decimal point OK + fdata = ddata; + if (stat < 4) return 1; + return 0; +} - if (strEqu(type,"spin")) { - kk = convSD(data,val); - if (kk != 0) val = 0.0; - gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget),val); - } - - if (strEqu(type,"colorbutt")) { // color button v.2.17 - pp = strField(data,'|',1); - if (pp) gdkcolor.red = 256 * atoi(pp); // bugfix v.3.8 - pp = strField(data,'|',2); - if (pp) gdkcolor.green = 256 * atoi(pp); - pp = strField(data,'|',3); - if (pp) gdkcolor.blue = 256 * atoi(pp); - gtk_color_button_set_color(GTK_COLOR_BUTTON(widget),&gdkcolor); - } - - if (strcmpv(type,"hscale","vscale",null)) { - kk = convSD(data,val); - if (kk != 0) val = 0.0; - gtk_range_set_value(GTK_RANGE(widget),val); - } - - if (strEqu(type,"combo")) { - if (! blank_null(data)) { - kk = pvlist_prepend(zd->widget[iiw].cblist,data,1); // add to drop-down list - if (kk == 0) // (only if unique) - gtk_combo_box_prepend_text(GTK_COMBO_BOX(widget),data); - kk = pvlist_find(zd->widget[iiw].cblist,data); - gtk_combo_box_set_active(GTK_COMBO_BOX(widget),kk); // make the active entry v.2.7 - } - else gtk_combo_box_set_active(GTK_COMBO_BOX(widget),-1); // make no active entry - } - if (strEqu(type,"comboE")) { - if (! blank_null(data)) { - kk = pvlist_prepend(zd->widget[iiw].cblist,data,1); // add to drop-down list - if (kk == 0) // (only if unique) - gtk_combo_box_prepend_text(GTK_COMBO_BOX(widget),data); - gtk_entry_set_text(GTK_ENTRY(GTK_BIN(widget)->child),data); // stuff entry box with new data - } - else gtk_entry_set_text(GTK_ENTRY(GTK_BIN(widget)->child),""); // stuff entry box with nothing - } +// append new item to combo box list without changing entry box - zd->disabled--; // re-enable dialog v.2.9 - return iiw; -} +int zdialog_cb_app(zdialog *zd, cchar *name, cchar *data) +{ + int ii, nn; + if (! zd) zappcrash("zdialog null pointer"); // detect destroyed dialog + if (zd->sentinel != zdsentinel) zappcrash("zdialog invalid"); -// get data from a dialog widget based on its name + if (blank_null(data)) return 0; // find widget + for (ii = 1; zd->widget[ii].type; ii++) + if (strEqu(zd->widget[ii].name,name)) break; + if (! zd->widget[ii].type) return 0; // not found + if (! strcmpv(zd->widget[ii].type,"combo","comboE",null)) return 0; // not combo box -cchar * zdialog_get_data(zdialog *zd, cchar *name) -{ - if (! zd) return 0; // detect destroyed dialog v.2.2 - if (zd->sentinel != zdsentinel) return 0; + nn = pvlist_append(zd->widget[ii].cblist,data,1); // append unique + if (nn >= 0) + gtk_combo_box_append_text(GTK_COMBO_BOX(zd->widget[ii].widget),data); - for (int ii = 1; zd->widget[ii].type; ii++) - if (strEqu(zd->widget[ii].name,name)) - return zd->widget[ii].data; - return 0; + return 1; } -// set new limits for a numeric data entry widget (spin, hscale, vscale) +// prepend new item to combo box list without changing entry box -int zdialog_set_limits(zdialog *zd, cchar *name, double min, double max) // new v.4.4 +int zdialog_cb_prep(zdialog *zd, cchar *name, cchar *data) { - GtkWidget *widget; - cchar *type; - int iiw; - - if (! zd) return 0; // detect destroyed dialog v.2.2 - if (zd->sentinel != zdsentinel) return 0; - - for (iiw = 1; zd->widget[iiw].type; iiw++) - if (strEqu(name,zd->widget[iiw].name)) break; - if (! zd->widget[iiw].type) { - printf("zdialog_stuff_limits, %s not found \n",name); - return 0; - } + int ii, nn; - widget = zd->widget[iiw].widget; - type = zd->widget[iiw].type; + if (! zd) zappcrash("zdialog null pointer"); // detect destroyed dialog + if (zd->sentinel != zdsentinel) zappcrash("zdialog invalid"); - if (*type == 's') - gtk_spin_button_set_range(GTK_SPIN_BUTTON(widget),min,max); + if (blank_null(data)) return 0; // find widget + for (ii = 1; zd->widget[ii].type; ii++) + if (strEqu(zd->widget[ii].name,name)) break; + if (! zd->widget[ii].type) return 0; // not found + if (! strcmpv(zd->widget[ii].type,"combo","comboE",null)) return 0; // not combo box - if (*type == 'h' || *type == 'v') - gtk_range_set_range(GTK_RANGE(widget),min,max); + nn = pvlist_prepend(zd->widget[ii].cblist,data,1); // append unique + if (nn == 0) + gtk_combo_box_prepend_text(GTK_COMBO_BOX(zd->widget[ii].widget),data); return 1; } -// put help topic into dialog +// get combo box drop-down list entry -void zdialog_help(zdialog *zd, cchar *help_topic) +char * zdialog_cb_get(zdialog *zd, cchar *name, int Nth) { - zd->help_topic = help_topic; - return; + int ii; + + if (! zd) return 0; // detect destroyed dialog + if (zd->sentinel != zdsentinel) return 0; + + for (ii = 1; zd->widget[ii].type; ii++) // find widget + if (strEqu(zd->widget[ii].name,name)) break; + if (! zd->widget[ii].type) return 0; // not found + if (! strcmpv(zd->widget[ii].type,"combo","comboE",null)) return 0; // not combo box + return pvlist_get(zd->widget[ii].cblist,Nth); } -// run the dialog and send events to the event function -// evfunc: int func(zdialog *zd, cchar *event) -// posn: optional dialog box position (see zdialog_set_position) +// delete entry by name from combo drop down list -int zdialog_run(zdialog *zd, zdialog_event evfunc, cchar *posn) // v.4.4 +int zdialog_cb_delete(zdialog *zd, cchar *name, cchar *data) { - int zdialog_KBpress(GtkWidget *, GdkEventKey *event, zdialog *zd); - int zdialog_KBrelease(GtkWidget *, GdkEventKey *event, zdialog *zd); - int zdialog_event_signal(GtkWidget *, GdkEvent *event, zdialog *zd); + int ii, nn; - int ii; - GtkWidget *widget, *dialog; - - if (! zd) zappcrash("zdialog null pointer"); // detect destroyed dialog v.2.2 - if (zd->sentinel != zdsentinel) zappcrash("zdialog invalid"); + if (! zd) return 0; // detect destroyed dialog + if (zd->sentinel != zdsentinel) return 0; - dialog = zd->widget[0].widget; + for (ii = 1; zd->widget[ii].type; ii++) // find widget + if (strEqu(zd->widget[ii].name,name)) break; + if (! zd->widget[ii].type) return 0; // not found + if (! strcmpv(zd->widget[ii].type,"combo","comboE",null)) return 0; // not combo box - if (posn) zdialog_set_position(zd,posn); // v.4.4 + nn = pvlist_find(zd->widget[ii].cblist,data); // find entry by name + if (nn < 0) return -1; - for (ii = 1; zd->widget[ii].type; ii++) // *** stop auto-selection - { // (GTK "feature") - if (strEqu(zd->widget[ii].type,"entry")) { - widget = zd->widget[ii].widget; - gtk_editable_set_position(GTK_EDITABLE(widget),-1); - break; - } + pvlist_remove(zd->widget[ii].cblist,nn); // remove from memory list + gtk_combo_box_remove_text(GTK_COMBO_BOX(zd->widget[ii].widget),nn); // and from widget + gtk_combo_box_set_active(GTK_COMBO_BOX(zd->widget[ii].widget),-1); // set no active entry - if (strEqu(zd->widget[ii].type,"comboE")) { // also combo edit box - widget = zd->widget[ii].widget; - gtk_editable_set_position(GTK_EDITABLE(GTK_BIN(widget)->child),-1); - break; - } - } + return 0; +} - if (evfunc) zd->eventCB = (void *) evfunc; // link to dialog event callback - dialog = zd->widget[0].widget; - gtk_widget_show_all(dialog); // activate dialog - gtk_window_present(GTK_WINDOW(dialog)); - if (! zd->parent) // if no parent, force to top - gtk_window_set_keep_above(GTK_WINDOW(dialog),1); // v.4.9 +// delete all entries from combo drop down list - G_SIGNAL(dialog,"event",zdialog_event_signal,zd) // connect general event function v.4.5 - G_SIGNAL(dialog,"key-press-event",zdialog_KBpress,zd) // connect key press event function - G_SIGNAL(dialog,"key-release-event",zdialog_KBrelease,zd) // connect key release event function - G_SIGNAL(dialog,"response",zdialog_response_event,zd); // connect dialog response function - - zd->disabled = 0; // enable widget events v.4.7 +int zdialog_cb_clear(zdialog *zd, cchar *name) +{ + int ii, jj, nn; - zfuncs::zdialog_busy++; // count open zdialogs v.4.7 + if (! zd) return 0; // detect destroyed dialog + if (zd->sentinel != zdsentinel) return 0; - return 0; // return now, dialog is non-modal + for (ii = 1; zd->widget[ii].type; ii++) // find widget + if (strEqu(zd->widget[ii].name,name)) break; + if (! zd->widget[ii].type) return 0; // not found + if (! strcmpv(zd->widget[ii].type,"combo","comboE",null)) return 0; // not combo box + + nn = pvlist_count(zd->widget[ii].cblist); // entry count + for (jj = nn-1; jj >= 0; jj--) { + pvlist_remove(zd->widget[ii].cblist,jj); // remove from memory list + gtk_combo_box_remove_text(GTK_COMBO_BOX(zd->widget[ii].widget),jj); // remove from widget + } + + gtk_combo_box_set_active(GTK_COMBO_BOX(zd->widget[ii].widget),-1); // set no active entry + if (strEqu(zd->widget[ii].type,"comboE")) // stuff entry box with nothing + gtk_entry_set_text(GTK_ENTRY(GTK_BIN(zd->widget[ii].widget)->child),""); + + return 0; } -// zdialog event handler - private function called for dialog events. -// Updates data in zdialog, calls user callback function (if present). +// make a combo box drop down to show all entries -void zdialog_widget_event(GtkWidget *widget, zdialog *zd) +int zdialog_cb_popup(zdialog *zd, cchar *name) { - zdialog_event *evfunc = 0; // dialog event callback function + int ii; - GtkTextView *textView = 0; - GtkTextBuffer *textBuff = 0; - GtkTextIter iter1, iter2; - GdkColor gdkcolor; - static GtkWidget *lastwidget = 0; - int ii, nn; - cchar *wname, *type, *wdata; - char sdata[20]; - double dval; - static int cbadded = 0; + if (! zd) return 0; // detect destroyed dialog + if (zd->sentinel != zdsentinel) return 0; - if (! zd) return; // detect destroyed dialog v.4.9 - if (zd->sentinel != zdsentinel) return; - - for (ii = 0; ii < zdmaxbutts; ii++) // check completion buttons v.3.5 - if (zd->compbutt[ii] == widget) break; - if (ii < zdmaxbutts) { - zd->zstat = ii+1; // zdialog status = button no. - if (zd->eventCB) { - evfunc = (zdialog_event *) zd->eventCB; // do callback function - evfunc(zd,"zstat"); - } - return; - } + for (ii = 1; zd->widget[ii].type; ii++) // find widget + if (strEqu(zd->widget[ii].name,name)) break; + if (! zd->widget[ii].type) return 0; // not found + if (! strcmpv(zd->widget[ii].type,"combo","comboE",null)) return 0; // not combo box - for (ii = 1; zd->widget[ii].type; ii++) // find widget in zdialog - if (zd->widget[ii].widget == widget) goto found_widget; + gtk_combo_box_popup(GTK_COMBO_BOX(zd->widget[ii].widget)); - for (ii = 1; zd->widget[ii].type; ii++) { // failed, test if buffer - if (strEqu(zd->widget[ii].type,"edit")) { // of text view widget - textView = GTK_TEXT_VIEW(zd->widget[ii].widget); - textBuff = gtk_text_view_get_buffer(textView); - if (widget == (GtkWidget *) textBuff) goto found_widget; - } - } + return 0; +} - printf("zdialog event %s, ignored \n",zd->widget[ii].name); // not found, ignore event v.4.7 - return; -found_widget: +/**************************************************************************/ - if (zd->disabled) return; // stop re-entrance from own updates - zd->disabled = 1; // (zdialog_put_data()) +// functions to save and recall zdialog window positions - wname = zd->widget[ii].name; - type = zd->widget[ii].type; - wdata = 0; +namespace zdposn_names +{ + struct zdposn_t { + float xpos, ypos; // window position WRT parent or desktop + char wintitle[64]; // window title (ID) + } zdposn[200]; // space for 200 windows - if (strEqu(type,"button")) wdata = "clicked"; - - if (strEqu(type,"entry")) - wdata = gtk_entry_get_text(GTK_ENTRY(widget)); - - if (strEqu(type,"edit")) { - gtk_text_buffer_get_bounds(textBuff,&iter1,&iter2); - wdata = gtk_text_buffer_get_text(textBuff,&iter1,&iter2,0); - } + int Nzdposn; // no. in use + int Nzdpmax = 200; // table size +} - if (strcmpv(type,"radio","check","togbutt",null)) - { - nn = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); - if (nn == 0) wdata = "0"; - else wdata = "1"; - } - if (strEqu(type,"combo")) - wdata = gtk_combo_box_get_active_text(GTK_COMBO_BOX(widget)); +// Load zdialog positions table from its file (application startup) +// or save zdialog positions table to its file (application exit). +// Action is "load" or "save". Number of table entries is returned. - if (strEqu(type,"comboE")) +int zdialog_positions(cchar *action) // new v.4.4 +{ + using namespace zdposn_names; + + char posfile[200], buff[100], wintitle[64], *pp; + float xpos, ypos; + int nn, ii; + FILE *fid; + + snprintf(posfile,199,"%s/zdialog_positions",get_zuserdir()); // /home//.appname/zdialog_positions + + if (strEqu(action,"load")) // load dialog positions table from file { - if (widget == lastwidget && cbadded) { - pvlist_remove(zd->widget[ii].cblist,0); // detect multiple edits (keystrokes) - gtk_combo_box_remove_text(GTK_COMBO_BOX(widget),0); // and replace prior entry with new + fid = fopen(posfile,"r"); + if (! fid) { + Nzdposn = 0; + return 0; } - wdata = gtk_entry_get_text(GTK_ENTRY(GTK_BIN(widget)->child)); - cbadded = 0; - if (! blank_null(wdata)) { - nn = pvlist_prepend(zd->widget[ii].cblist,wdata,1); // add entry to drop-down list - if (nn == 0) { // (only if unique) - gtk_combo_box_prepend_text(GTK_COMBO_BOX(widget),wdata); - cbadded = 1; - } + + for (nn = 0; nn < Nzdpmax; nn++) + { + pp = fgets(buff,100,fid); + if (! pp) break; + if (strlen(pp) < 64) continue; + strncpy0(wintitle,buff,64); + strTrim(wintitle); + if (strlen(wintitle) < 3) continue; + ii = sscanf(buff + 64," %f %f ",&xpos,&ypos); + if (ii != 2) continue; + strcpy(zdposn[nn].wintitle,wintitle); + zdposn[nn].xpos = xpos; + zdposn[nn].ypos = ypos; } + + fclose(fid); + Nzdposn = nn; + return Nzdposn; } - if (strEqu(type,"spin")) - { - dval = gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget)); - sprintf(sdata,"%g",dval); - wdata = sdata; - } - - if (strEqu(type,"colorbutt")) // color button v.2.17 - { - gtk_color_button_get_color(GTK_COLOR_BUTTON(widget),&gdkcolor); - sprintf(sdata,"%d|%d|%d",gdkcolor.red/256,gdkcolor.green/256,gdkcolor.blue/256); - wdata = sdata; - } - - if (strcmpv(type,"hscale","vscale",null)) + if (strEqu(action,"save")) // save dialog positions table to file { - dval = gtk_range_get_value(GTK_RANGE(widget)); - sprintf(sdata,"%g",dval); - wdata = sdata; - } - - // all widgets come here - - if (zd->widget[ii].data) zfree(zd->widget[ii].data); // clear prior data - zd->widget[ii].data = 0; - - if (wdata) zd->widget[ii].data = strdupz(wdata,0,"zdialog"); // set new data v.3.5 - - lastwidget = widget; // remember last widget updated + fid = fopen(posfile,"w"); + if (! fid) { + printf("cannot write zdialog_positions file \n"); + return 0; + } - if (zd->eventCB) { - evfunc = (zdialog_event *) zd->eventCB; // do user callback function - evfunc(zd,wname); + for (nn = 0; nn < Nzdposn; nn++) + fprintf(fid,"%-64s %0.1f %0.1f \n",zdposn[nn].wintitle, + zdposn[nn].xpos, zdposn[nn].ypos); + fclose(fid); + return Nzdposn; } - - zd->disabled = 0; // re-enable widgets - return; -} - - -// zdialog response handler for "event" signal (all events) - -int zdialog_event_signal(GtkWidget *, GdkEvent *event, zdialog *zd) -{ - if (zd->help_topic) - zfuncs::F1_help_topic = zd->help_topic; // set help topic v.4.5 + + printf("zdialog_positions bad action: %s \n",action); return 0; } -// zdialog response handler for keyboard events - -int zdialog_KBpress(GtkWidget *, GdkEventKey *event, zdialog *zd) // prevent KB key press from being -{ // sent to toolbar buttons - return 0; -} +// Set the initial or new zdialog window position from "posn" +// null: window manager decides +// "mouse" put dialog at mouse position +// "desktop" center dialog in desktop window +// "parent" center dialog in parent window +// "save" use the same position last set by the user +// "nn/nn" put NW corner of dialog in parent window at % size +// (e.g. "50/50" puts NW corner at center of parent) -int zdialog_KBrelease(GtkWidget *, GdkEventKey *kbevent, zdialog *zd) +void zdialog_set_position(zdialog *zd, cchar *posn) // new v.4.4 { - zdialog_event *evfunc = 0; // dialog event callback function + using namespace zdposn_names; - int KBkey = kbevent->keyval; - char event[8]; + int ii, ppx, ppy, zdpx, zdpy, pww, phh; + float xpos, ypos; + char wintitle[64], *pp; + GtkWidget *parent, *dialog; + + parent = zd->parent; + dialog = zd->widget[0].widget; - if (KBkey == GDK_F1) { - showz_userguide(zfuncs::F1_help_topic); // context help v.3.7 - return 1; + if (strEqu(posn,"mouse")) { + gtk_window_set_position(GTK_WINDOW(dialog),GTK_WIN_POS_MOUSE); + return; } - if (zd->eventCB) { - evfunc = (zdialog_event *) zd->eventCB; // do user callback function v.4.7 - strcpy(event,"KB x"); // with event = "KB x" - event[3] = KBkey; // (x = key now released) - evfunc(zd,event); - return 1; + if (strEqu(posn,"desktop")) { + gtk_window_set_position(GTK_WINDOW(dialog),GTK_WIN_POS_CENTER); + return; } - return 0; -} - - -// zdialog response handler - private function called when dialog is completed. -// called when dialog is canceled via [x] button or destroyed by GTK (zstat < 0). - -void zdialog_response_event(GtkWidget *, int zstat, zdialog *zd) -{ - zdialog_event *evfunc = 0; // dialog event callback function - - if (! zd) return; // detect destroyed dialog v.4.9 - if (zd->sentinel != zdsentinel) return; - if (zd->zstat) return; // already complete v.3.5 - - zd->zstat = zstat; // set zdialog status + if (strEqu(posn,"parent")) { + gtk_window_set_position(GTK_WINDOW(dialog),GTK_WIN_POS_CENTER_ON_PARENT); + return; + } - if (zd->eventCB) { - evfunc = (zdialog_event *) zd->eventCB; // do callback function - evfunc(zd,"zstat"); // (should do zfree()) + if (! parent) { // no parent window + ppx = ppy = 0; // use desktop + pww = gdk_screen_width(); + phh = gdk_screen_height(); + } + else { + gtk_window_get_position(GTK_WINDOW(parent),&ppx,&ppy); // parent window NW corner + gtk_window_get_size(GTK_WINDOW(parent),&pww,&phh); // parent window size } - return; -} - - -// send an event to an active dialog + if (strEqu(posn,"save")) // use last saved window position + { + zd->saveposn = 1; // set flag for zdialog_free() -int zdialog_send_event(zdialog *zd, cchar *event) // new v.2.17 -{ - zdialog_event * evfunc = 0; // dialog event callback function + pp = (char *) gtk_window_get_title(GTK_WINDOW(dialog)); // get window title, used as ID + if (! pp) return; + if (strlen(pp) < 2) return; + strncpy0(wintitle,pp,64); // window title, < 64 chars. + for (ii = 0; ii < Nzdposn; ii++) // search table for title + if (strEqu(wintitle,zdposn[ii].wintitle)) break; + if (ii == Nzdposn) return; // not found - zdialog_free() will add - if (zd && zd->sentinel == zdsentinel) { // check dialog is active - evfunc = (zdialog_event *) zd->eventCB; - if (evfunc) evfunc(zd,event); // call dialog event function + zdpx = ppx + 0.01 * zdposn[ii].xpos * pww; // position for dialog window + zdpy = ppy + 0.01 * zdposn[ii].ypos * phh; + gtk_window_move(GTK_WINDOW(dialog),zdpx,zdpy); + return; } - return 1; + else // "nn/nn" // position from caller + { + ii = sscanf(posn,"%f/%f",&xpos,&ypos); // parse "nn/nn" + if (ii != 2) return; + zdpx = ppx + 0.01 * xpos * pww; // position for dialog window + zdpy = ppy + 0.01 * ypos * phh; + gtk_window_move(GTK_WINDOW(dialog),zdpx,zdpy); + return; + } } -// Complete a dialog and give it a status, without user action. -// Dialog event function will be called, zdialog_wait() will return. -// returns: 0 = no active dialog, 1 = OK +// If the dialog window position is "save" then save +// its position WRT parent or desktop for next use. -int zdialog_send_response(zdialog *zd, int zstat) // new v.2.23 +void zdialog_save_position(zdialog *zd) // new v.4.4 { - zdialog_event *evfunc = 0; // dialog event callback function + using namespace zdposn_names; - if (! zd) return 0; // detect destroyed dialog - if (zd->sentinel != zdsentinel) return 0; + int ii, ppx, ppy, pww, phh, zdpx, zdpy; + float xpos, ypos; + char wintitle[64], *pp; + GtkWidget *parent, *dialog; - zd->zstat = zstat; // set status + dialog = zd->widget[0].widget; + if (! dialog) return; // destroyed v.4.7 + + parent = zd->parent; // parent window - if (zd->eventCB) { - evfunc = (zdialog_event *) zd->eventCB; // do callback function - evfunc(zd,"zstat"); + if (! parent) { // no parent window + ppx = ppy = 0; // use desktop + pww = gdk_screen_width(); + phh = gdk_screen_height(); + } + else { + gtk_window_get_position(GTK_WINDOW(parent),&ppx,&ppy); // parent window NW corner + gtk_window_get_size(GTK_WINDOW(parent),&pww,&phh); // parent window size } - return 1; -} + gtk_window_get_position(GTK_WINDOW(dialog),&zdpx,&zdpy); // dialog window NW corner + xpos = 100.0 * (zdpx - ppx) / pww; // dialog window relative position + ypos = 100.0 * (zdpy - ppy) / phh; // (as percent of parent size) -// Destroy the zdialog - must be done by zdialog_run() caller -// (else dialog continues active even after completion button). -// Data in widgets remains valid until zdialog_free() is called. + pp = (char *) gtk_window_get_title(GTK_WINDOW(dialog)); + if (! pp) return; + if (strlen(pp) < 2) return; + strncpy0(wintitle,pp,64); // window title, < 64 chars. -int zdialog_destroy(zdialog *zd) -{ - using namespace zfuncs; - - if (! zd) return 0; // detect destroyed dialog v.2.2 - if (zd->sentinel != zdsentinel) return 0; - - if (zd->zstat < 0) { // destroyed by [x] button or GTK - zd->widget[0].widget = 0; // assume GTK dialog is gone - zdialog_busy--; // v.4.7 + for (ii = 0; ii < Nzdposn; ii++) // search table for window + if (strEqu(wintitle,zdposn[ii].wintitle)) break; + if (ii == Nzdposn) { // not found + if (ii == Nzdpmax) return; // table full + strcpy(zdposn[ii].wintitle,wintitle); // add window to table + Nzdposn++; } - if (zd->widget[0].widget) { // multiple destroys OK - if (zd->saveposn) - zdialog_save_position(zd); // save position for next use v.4.7 - gtk_widget_destroy(zd->widget[0].widget); // destroy GTK dialog - zdialog_busy--; // v.4.7 - zd->widget[0].widget = 0; - } - - if (! zd->zstat) zd->zstat = -1; // status = destroyed v.3.5 - return 1; + zdposn[ii].xpos = xpos; // save window position + zdposn[ii].ypos = ypos; + return; } -// free zdialog memory (destroy first, if not already) +/************************************************************************** -int zdialog_free(zdialog *&zd) // reference v.3.9 -{ - if (! zd) return 0; // detect destroyed dialog v.2.2 - if (zd->sentinel != zdsentinel) return 0; + Translation Functions - zdialog_destroy(zd); // destroy GTK dialog if there - zd->sentinel = 0; // mark invalid v.2.2 - zfree(zd->widget[0].data); // bugfix memory leak v.3.5 + Translation files are standard .po files as used in the Gnu gettext + system. However the .po files are used directly, and there is no need + to merge and compile them into a binary format (.mo files). - for (int ii = 1; zd->widget[ii].type; ii++) // loop through widgets - { - if (strcmpv(zd->widget[ii].type,"combo","comboE",null)) // bugfix, free combo list v.3.5 - pvlist_free(zd->widget[ii].cblist); - zfree((char *) zd->widget[ii].type); // free strings - zfree((char *) zd->widget[ii].name); - zfree((char *) zd->widget[ii].pname); - if (zd->widget[ii].data) zfree(zd->widget[ii].data); // free data - } + Initialize: + int ZTXinit(cchar *lang) + lang is "lc" or "lc_RC" or null (current locale will be used) + + Translate a text string: + cchar *translation = ZTX(cchar *english) + english: text string which may have printf formats (%d %s ...) + translation: the returned equivalent translation + + If the user language is English or if no translation is found, + the input string is returned, else the translated string. - zfree(zd); // free zdialog memory - zd = 0; // clear pointer v.3.9 - return 1; -} + A text string may have a context part "context::string", where + "context" is any string < 30 characters and "string" is the + English text or the translation text. The context part "context::" + is removed in the returned string. This is to handle the case where + a single English string may need multiple translations, depending + on context. The English string may be present multiple times in a + .po file, each one marked with a different context and having a + different translation. Context is optional in translation strings. + + example: + + program code: + printf(ZTX("answer: %d %s \n next line"), 123, "qwerty"); + + A German .po file (appname-de.po) would have the following: -// wait for a zdialog to have a completion status or be destroyed -// returns completion status or -1 if destroyed + msgid "" + "answer: %d %s \n" + " next line" + msgstr "" + "Antwort: %d %s \n" + " nächste Zeile" -int zdialog_wait(zdialog *zd) // v.3.3 -{ - while (true) - { - zmainloop(); - if (! zd) return -1; // dialog destroyed v.3.5 - if (zd->sentinel != zdsentinel) return -1; - if (zd->zstat) return zd->zstat; - zsleep(0.01); - } +***/ + +namespace ZTXnames // remove GOFUNC usage becasue of +{ // GCC optimization errors + FILE *fidr, *fidw; + char buff[ZTXmaxcc], *ppq1, *ppq2; + char *porec, *wporec; + char Etext[ZTXmaxcc], Ttext[ZTXmaxcc]; // .po text: "line 1 %s \n" "line 2" + char **etext, **ttext; // arrays, english and translations + char **estring, **tstring; // merged, un-quoted, un-escaped + int Ntext = 0; // array counts + int Ftranslate = 0; // 0/1/2 = translate none/all/missing + zdialog *zddump; // dialog for editing translations + GtkWidget *trwin; // text window within dialog + void ZTXgettext(char *text); + char *ZTXmergetext(cchar *text); + void ZTX_translation_dump(int index); + void ZTX_translation_update(); + void ZTXgettext2(char *text); + void ZTXwritetext(cchar *header, char *text); } -// put cursor at named widget +// read and process .po file at application startup +// prepare english strings and translations for quick access -int zdialog_goto(zdialog *zd, cchar *name) // v.2.23 +void ZTXinit(cchar *lang) // initialize translations v.5.0 { - GtkWidget *widget; - - if (zd->sentinel != zdsentinel) return 0; - widget = zdialog_widget(zd, name); - if (! widget) return 0; + using namespace zfuncs; + using namespace ZTXnames; - gtk_editable_select_region(GTK_EDITABLE(widget),0,-1); // focus on widget - gtk_widget_grab_focus(widget); + int ii, err; + char *pp, pofile[200]; + char lc[4], lc_RC[8]; // language (de), * + region (de_AT) + struct stat statb; - return 1; -} + if (Ntext) { // free prior translation + for (ii = 0; ii < Ntext; ii++) { + zfree(etext[ii]); + zfree(ttext[ii]); + zfree(estring[ii]); + zfree(tstring[ii]); + } + zfree(etext); + zfree(ttext); + zfree(estring); + zfree(tstring); + Ntext = 0; + } + etext = (char **) zmalloc(ZTXmaxent * sizeof(char *),"ZTX"); // english text and translations + ttext = (char **) zmalloc(ZTXmaxent * sizeof(char *),"ZTX"); // (segmented, quoted, escaped) + estring = (char **) zmalloc(ZTXmaxent * sizeof(char *),"ZTX"); // english strings and translations + tstring = (char **) zmalloc(ZTXmaxent * sizeof(char *),"ZTX"); // (merged, un-quoted, un-escaped) -// set cursor for zdialog (e.g. busy cursor) + if (lang && *lang) strncpy0(zlang,lang,6); // use language from caller + else { // help Linux chaos + pp = getenv("LANG"); // use $LANG if defined + if (! pp) pp = getenv("LANGUAGE"); // use $LANGUAGE if defined + if (! pp) pp = setlocale(LC_MESSAGES,""); // use locale if defined + if (pp) strncpy0(zlang,pp,6); // "lc_RC" language/region code + else strcpy(zlang,"en"); // use English + } -void zdialog_set_cursor(zdialog *zd, GdkCursor *cursor) // v.3.8 -{ - GtkWidget *dialog; + if (*zlang < 'a') strcpy(zlang,"en"); // use English if garbage + printf("language: %s \n",zlang); + + if (strnEqu(zlang,"en",2)) return; // English, do nothing v.4.3 - if (zd->sentinel != zdsentinel) return; - dialog = zd->widget[0].widget; - if (! dialog) return; - gdk_window_set_cursor(dialog->window,cursor); - return; -} - - -// convenience functions for stuffing and retrieving widget data + strncpy0(lc,zlang,3); // language code alone, e.g. "de" + strncpy0(lc_RC,zlang,6); // + opt. region code, "de" or "de_AT" -int zdialog_stuff(zdialog *zd, cchar *name, cchar *data) // stuff a string -{ - zdialog_put_data(zd, name, data); - return 1; -} + snprintf(pofile,199,"%s/locales/%s-%s.po",zuserdir,zappname,lc_RC); // look for user custom .po file + err = stat(pofile,&statb); // (a translation project is underway) + if (err) { + snprintf(pofile,199,"%s/locales/%s-%s.po",zuserdir,zappname,lc); + err = stat(pofile,&statb); + } -int zdialog_stuff(zdialog *zd, cchar *name, int idata) // stuff an integer -{ - char string[16]; + if (err) { // look for normal installed .po file + snprintf(pofile,199,"%s/%s-%s.po",zlocalesdir,zappname,lc_RC); + err = stat(pofile,&statb); + if (err) { + snprintf(pofile,199,"%s/%s-%s.po",zlocalesdir,zappname,lc); // default to lc only v.5.0 + err = stat(pofile,&statb); + } + } - sprintf(string,"%d",idata); - zdialog_put_data(zd,name,string); - return 1; -} + if (! err) printf("using translation file: %s \n",pofile); + else { + printf("no translation file found for %s \n",lc_RC); + return; + } -int zdialog_stuff(zdialog *zd, cchar *name, double ddata) // stuff a double -{ - char string[32]; + fidr = fopen(pofile,"r"); // open .po file + if (! fidr) { + printf("cannot open translation file: %s \n",pofile); + return; + } - snprintf(string,31,"%g",ddata); // outputs decimal point or comma - zdialog_put_data(zd,name,string); // (per locale) - return 1; -} + porec = 0; // no .po record yet + *Etext = *Ttext = 0; // no text yet -int zdialog_fetch(zdialog *zd, cchar *name, char *data, int maxcc) // fetch string data -{ - cchar *zdata; + while (true) + { + if (! porec) porec = fgets_trim(buff,ZTXmaxcc,fidr); // get next .po record + if (! porec) break; // EOF + + if (blank_null(porec)) { // blank record + porec = 0; + continue; + } + if (*porec == '#') { // comment + porec = 0; + continue; + } - zdata = zdialog_get_data(zd,name); - if (! zdata) { - *data = 0; - return 0; - } - - return strncpy0(data,zdata,maxcc); // 0 = OK, 1 = truncation v.2.4 -} + if (strnEqu(porec,"msgid",5)) // start new english string + { + if (*Etext) { // two in a row + printf("no translation: %s \n",Etext); + *Etext = 0; + } -int zdialog_fetch(zdialog *zd, cchar *name, int &idata) // fetch an integer -{ - cchar *zdata; + if (*Ttext) { + printf("orphan translation: %s \n",Ttext); + *Ttext = 0; + } - zdata = zdialog_get_data(zd,name); - if (! zdata) { - idata = 0; - return 0; - } - - idata = atoi(zdata); - return 1; -} + porec += 5; // get segmented text string + ZTXgettext(Etext); // "segment1 %s \n" "segment2" ... + } -int zdialog_fetch(zdialog *zd, cchar *name, double &ddata) // fetch a double -{ - int stat; - cchar *zdata; + else if (strnEqu(porec,"msgstr",6)) // start new translation + { + porec += 6; // get segmented string + ZTXgettext(Ttext); + + if (! *Etext) { + printf("orphan translation: %s \n",Ttext); + *Ttext = 0; + continue; + } - zdata = zdialog_get_data(zd,name); - if (! zdata) { - ddata = 0; - return 0; + if (strlen(Ttext) < 3) { // translation is "" + printf("no translation: %s \n",Etext); + strcpy(Ttext,Etext); // substitute english text + } + } + + else + { + printf("unrecognized .po record: %s \n",porec); + porec = 0; + continue; + } + + if (*Etext && *Ttext) // have an english/translation pair + { + etext[Ntext] = strdupz(Etext,0,"ZTX"); // add to translation tables + ttext[Ntext] = strdupz(Ttext,0,"ZTX"); + *Etext = *Ttext = 0; + Ntext++; + if (Ntext == ZTXmaxent) // cannot continue + zappcrash("more than %d translations",ZTXmaxent); + } } - stat = convSD(zdata,ddata); // period or comma decimal point OK - if (stat < 4) return 1; - return 0; -} - -int zdialog_fetch(zdialog *zd, cchar *name, float &fdata) // fetch a float v.3.4 -{ - int stat; - cchar *zdata; - double ddata; + fclose(fidr); - zdata = zdialog_get_data(zd,name); - if (! zdata) { - fdata = 0; - return 0; + printf(".po file has %d entries \n",Ntext); + + for (ii = 0; ii < Ntext; ii++) + { + pp = ZTXmergetext(etext[ii]); // merge segmented text strings + estring[ii] = strdupz(pp,0,"ZTX"); + pp = ZTXmergetext(ttext[ii]); + tstring[ii] = strdupz(pp,0,"ZTX"); } - stat = convSD(zdata,ddata); // period or comma decimal point OK - fdata = ddata; - if (stat < 4) return 1; - return 0; + return; } -// append new item to combo box list without changing entry box +// private function +// read and combine multiple 'msgid' or 'msgstr' quoted strings +// output is one string with one or more quoted segments: +// "text line 1 %s \n" "text line 2" ... +// each segment comes from a different line in the input .po file -int zdialog_cb_app(zdialog *zd, cchar *name, cchar *data) +void ZTXnames::ZTXgettext(char *pstring) // v.4.3 { - int ii, nn; - - if (! zd) zappcrash("zdialog null pointer"); // detect destroyed dialog v.2.2 - if (zd->sentinel != zdsentinel) zappcrash("zdialog invalid"); - - if (blank_null(data)) return 0; // find widget - for (ii = 1; zd->widget[ii].type; ii++) - if (strEqu(zd->widget[ii].name,name)) break; - if (! zd->widget[ii].type) return 0; // not found - if (! strcmpv(zd->widget[ii].type,"combo","comboE",null)) return 0; // not combo box + using namespace ZTXnames; - nn = pvlist_append(zd->widget[ii].cblist,data,1); // append unique - if (nn >= 0) - gtk_combo_box_append_text(GTK_COMBO_BOX(zd->widget[ii].widget),data); + int cc, scc = 0; - return 1; + while (true) // join multiple quoted strings + { + while (*porec && *porec != '"') porec++; // find opening string quote + if (! *porec) { + porec = fgets_trim(buff,ZTXmaxcc,fidr); // get next .po record + if (! porec) return; + if (strnEqu(porec,"msgid",5)) return; // end of this string + if (strnEqu(porec,"msgstr",6)) return; + } + ppq1 = porec; // opening quote + ppq2 = ppq1 + 1; + while ((*ppq2 && *ppq2 != '"') || // find closing (non-escaped) quote + (*ppq2 == '"' && *(ppq2-1) == '\\')) ppq2++; + if (! *ppq2) return; + cc = ppq2 - ppq1 + 1; // min. case is "" + if (cc + 1 + scc >= ZTXmaxcc) + printf("string is too long %s \n",pstring); + else { + strncpy0(pstring+scc,ppq1,cc+1); // accum. substrings, minus quotes + scc += cc; + } + porec = ppq2 + 1; + } + + return; } -// prepend new item to combo box list without changing entry box +// private function +// convert quoted string segments into binary form that +// matches the compiled string in the source program +// (remove quotes, merge strings, un-escape \n \" etc.) -int zdialog_cb_prep(zdialog *zd, cchar *name, cchar *data) +char * ZTXnames::ZTXmergetext(cchar *dirtystring) // v.4.3 { - int ii, nn; - - if (! zd) zappcrash("zdialog null pointer"); // detect destroyed dialog v.2.2 - if (zd->sentinel != zdsentinel) zappcrash("zdialog invalid"); - - if (blank_null(data)) return 0; // find widget - for (ii = 1; zd->widget[ii].type; ii++) - if (strEqu(zd->widget[ii].name,name)) break; - if (! zd->widget[ii].type) return 0; // not found - if (! strcmpv(zd->widget[ii].type,"combo","comboE",null)) return 0; // not combo box - - nn = pvlist_prepend(zd->widget[ii].cblist,data,1); // append unique - if (nn == 0) - gtk_combo_box_prepend_text(GTK_COMBO_BOX(zd->widget[ii].widget),data); - - return 1; + static char cleanstring[ZTXmaxcc]; + int ii, jj; + + strncpy0(cleanstring,dirtystring,ZTXmaxcc); + clean_escapes(cleanstring); + + for (ii = jj = 0; cleanstring[ii]; ii++) + if (cleanstring[ii] != '"') + cleanstring[jj++] = cleanstring[ii]; + cleanstring[jj] = 0; + return cleanstring; } -// get combo box drop-down list entry +// Translate the input english string or return the input string. +// Look for "context::string" and return "string" only if context found. +// This function may need a few microseconds if thousands of strings must be searched. -char * zdialog_cb_get(zdialog *zd, cchar *name, int Nth) +cchar * ZTX(cchar *english) { - int ii; + using namespace ZTXnames; - if (! zd) return 0; // detect destroyed dialog v.2.2 - if (zd->sentinel != zdsentinel) return 0; + cchar *pp, *pp2; + int ii; + + if (! english) return "null"; // v.4.3 + + for (ii = 0; ii < Ntext; ii++) // find translation v.4.3 + if (strEqu(english,estring[ii])) break; + if (ii < Ntext) pp = tstring[ii]; + else pp = english; + + if (Ftranslate) { + if (ii < Ntext) ZTX_translation_dump(ii); // output translation + else printf("message not in .po: %s \n",english); + } + + for (pp2 = pp; *pp2 && pp2 < pp+30; pp2++) // remove context if present + if (*pp2 == ':' && *(pp2+1) == ':') return pp2+2; - for (ii = 1; zd->widget[ii].type; ii++) // find widget - if (strEqu(zd->widget[ii].name,name)) break; - if (! zd->widget[ii].type) return 0; // not found - if (! strcmpv(zd->widget[ii].type,"combo","comboE",null)) return 0; // not combo box - return pvlist_get(zd->widget[ii].cblist,Nth); + return pp; } -// delete entry by name from combo drop down list // v.2.4 - -int zdialog_cb_delete(zdialog *zd, cchar *name, cchar *data) -{ - int ii, nn; - - if (! zd) return 0; // detect destroyed dialog v.2.2 - if (zd->sentinel != zdsentinel) return 0; - - for (ii = 1; zd->widget[ii].type; ii++) // find widget - if (strEqu(zd->widget[ii].name,name)) break; - if (! zd->widget[ii].type) return 0; // not found - if (! strcmpv(zd->widget[ii].type,"combo","comboE",null)) return 0; // not combo box +/************************************************************************** - nn = pvlist_find(zd->widget[ii].cblist,data); // find entry by name - if (nn < 0) return -1; + Online Translation Utility - pvlist_remove(zd->widget[ii].cblist,nn); // remove from memory list - gtk_combo_box_remove_text(GTK_COMBO_BOX(zd->widget[ii].widget),nn); // and from widget - gtk_combo_box_set_active(GTK_COMBO_BOX(zd->widget[ii].widget),-1); // set no active entry - - return 0; -} + If the application menu "Translate" is selected, the function + ZTX_translation_start() is called and the user dialog is used to + set translation mode ON or OFF. If ON, the .po translation file + is copied from the install location to a user location (if not + already there) where it will be modified. This user .po file + will be used for translations going forward. + + Run the application to be translated in the usual manner. Select each + menu or toolbar function needing translation. The related english text + strings and current translations are dumped into a text edit window. + The user can edit the translations while using the application and + therefore more easily understand the complete context. + + Whenever the application calls ZTX() to get a translation, the + function ZTX_translation_dump() is called to add the english text + and the current translation to the text edit window. + ______________________________________________________ + | | + | msgid "English text with formats %d %d ... " | + | msgstr "Deutscher Text mit Formats %d %s ... " | + | ... | + | [apply] [cancel] | + |______________________________________________________| + + As the application is exercised (menus and dialogs), all english text + and current translations are added to the window. Where no translation + is available, the english text is repeated as the translation. The user + may edit the window to update the translations. When done, using the + [apply] button updates the translation .po file in the user location. + +***************************************************************************/ -// delete all entries from combo drop down list +// This function is called from the application menu "Translate". +// Set translation mode ON or OFF (zfuncs::Ftranslate). If ON and no +// .po translation file is found in /home//.appname/locales/, +// then it is copied from the installed .po file to provide a starting +// point for changes. A text edit window is opened to display the +// english strings and their current translations, if any, and for +// input of the revised translations. -int zdialog_cb_clear(zdialog *zd, cchar *name) +void ZTX_translation_start(GtkWidget *parent) // new v.4.3 { - int ii, jj, nn; - - if (! zd) return 0; // detect destroyed dialog v.2.2 - if (zd->sentinel != zdsentinel) return 0; + using namespace zfuncs; + using namespace ZTXnames; - for (ii = 1; zd->widget[ii].type; ii++) // find widget - if (strEqu(zd->widget[ii].name,name)) break; - if (! zd->widget[ii].type) return 0; // not found - if (! strcmpv(zd->widget[ii].type,"combo","comboE",null)) return 0; // not combo box + int ZTX_translation_event(zdialog *zd, cchar *event); - nn = pvlist_count(zd->widget[ii].cblist); // entry count - for (jj = nn-1; jj >= 0; jj--) { - pvlist_remove(zd->widget[ii].cblist,jj); // remove from memory list - gtk_combo_box_remove_text(GTK_COMBO_BOX(zd->widget[ii].widget),jj); // remove from widget + zdialog *zd; + int err, tron, trmissing; + char *pp, command[400]; + char pofile1[200], pofile2[200]; + struct stat statb; + + if (strnEqu(zlang,"en",2)) { // locale cannot be english + zmessageACK(0,"cannot translate locale %s",zlang); + return; } - gtk_combo_box_set_active(GTK_COMBO_BOX(zd->widget[ii].widget),-1); // set no active entry - if (strEqu(zd->widget[ii].type,"comboE")) // stuff entry box with nothing - gtk_entry_set_text(GTK_ENTRY(GTK_BIN(zd->widget[ii].widget)->child),""); - - return 0; -} + if (Ftranslate) return; // already active v.5.0 + Ftranslate = 1; +/* ___________________________________________ + | | + | Translation mode: (o) ON (o) OFF | + | [x] Show missing translations only | + | | + | [apply] [cancel] | + |___________________________________________| +*/ -// make a combo box drop down to show all entries + zd = zdialog_new("Translation Mode",parent,"apply","cancel",null); + zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=5"); + zdialog_add_widget(zd,"label","labm","hb1","Translation mode:","space=5"); + zdialog_add_widget(zd,"radio","tron","hb1","ON","space=5"); + zdialog_add_widget(zd,"radio","troff","hb1","OFF","space=5"); + zdialog_add_widget(zd,"hbox","hb2","dialog",0,"space=5"); + zdialog_add_widget(zd,"check","trmissing","hb2","Show missing translations only"); + + zdialog_stuff(zd,"tron",1); + zdialog_stuff(zd,"troff",0); + zdialog_stuff(zd,"trmissing",1); + + zdialog_run(zd); // run dialog + zdialog_wait(zd); -int zdialog_cb_popup(zdialog *zd, cchar *name) // v.3.8 -{ - int ii; + if (zd->zstat == 1) { // [apply] + zdialog_fetch(zd,"tron",tron); + zdialog_fetch(zd,"trmissing",trmissing); + if (tron) Ftranslate = 1; // dump all translations + if (tron && trmissing) Ftranslate = 2; // dump only missing translations + } + else Ftranslate = 0; // v.5.0 - if (! zd) return 0; // detect destroyed dialog v.2.2 - if (zd->sentinel != zdsentinel) return 0; + zdialog_free(zd); - for (ii = 1; zd->widget[ii].type; ii++) // find widget - if (strEqu(zd->widget[ii].name,name)) break; - if (! zd->widget[ii].type) return 0; // not found - if (! strcmpv(zd->widget[ii].type,"combo","comboE",null)) return 0; // not combo box + if (Ftranslate) // start or continue translation mode + { + snprintf(pofile1,199,"%s/%s-%s.po",zlocalesdir,zappname,zlang); // installed .po file for lc_RC + snprintf(pofile2,199,"%s/locales/%s-%s.po",zuserdir,zappname,zlang); // user .po file for new translations + + err = stat(pofile2,&statb); // look for user .po file + if (err) { + err = stat(pofile1,&statb); // look for installed .po file + if (err) printf("No .po file found %s \n",pofile1); + else { + pp = strrchr(pofile2,'/'); // create /locales if needed + *pp = 0; // bugfix v.5.0 + mkdir(pofile2,0754); + *pp = '/'; + snprintf(command,399,"cp -R %s %s",pofile1,pofile2); // copy installed .po file to user + err = system(command); + if (! err) printf(".po file copied from %s to %s \n",pofile1,pofile2); + else printf("cannot copy .po file from %s to %s \n",pofile1,pofile2); + } + } + + ZTXinit(zlang); // re-initialize translations - gtk_combo_box_popup(GTK_COMBO_BOX(zd->widget[ii].widget)); + zddump = zdialog_new("Translations",parent,"apply","cancel",null); // create dialog for translation edits + zdialog_add_widget(zddump,"scrwin","scrwin","dialog",0,"expand"); + zdialog_add_widget(zddump,"edit","edit","scrwin"); + zdialog_resize(zddump,600,400); + zdialog_run(zddump,ZTX_translation_event); + trwin = zdialog_widget(zddump,"edit"); // text edit window in dialog + } - return 0; + return; } -/**************************************************************************/ - -// functions to save and recall zdialog window positions +// dialog event and completion function -namespace zdposn_names +int ZTX_translation_event(zdialog *zd, cchar *event) // v.4.3 { - struct zdposn_t { - float xpos, ypos; // window position WRT parent or desktop - char wintitle[64]; // window title (ID) - } zdposn[200]; // space for 200 windows + using namespace ZTXnames; + + if (! zd->zstat) return 1; // wait for [apply] or [cancel] - int Nzdposn; // no. in use - int Nzdpmax = 200; // table size + if (zd->zstat == 1) // [apply] + ZTX_translation_update(); // update user .po file + + Ftranslate = 0; + zdialog_free(zd); // kill edit window + zddump = 0; + trwin = 0; + return 1; } -// Load zdialog positions table from its file (application startup) -// or save zdialog positions table to its file (application exit). -// Action is "load" or "save". Number of table entries is returned. +// This function is called from ZTX() for every translation. +// Add the english text and current translation to the text edit window. -int zdialog_positions(cchar *action) // new v.4.4 +void ZTXnames::ZTX_translation_dump(int index) // new v.4.3 { - using namespace zdposn_names; + using namespace zfuncs; + using namespace ZTXnames; - char posfile[200], buff[100], wintitle[64], *pp; - float xpos, ypos; - int nn, ii; - FILE *fid; - - snprintf(posfile,199,"%s/zdialog_positions",get_zuserdir()); // /home//.appname/zdialog_positions + char outstring[ZTXmaxcc]; + char *pp1, *pp2; + int cc; + + if (strEqu(zlang,"en")) return; + if (! zddump) return; // no translation edit window - if (strEqu(action,"load")) // load dialog positions table from file - { - fid = fopen(posfile,"r"); - if (! fid) { - Nzdposn = 0; - return 0; - } + if (! Ftranslate) return; // translate mode OFF + if (Ftranslate == 2 && // only missing translations wanted + strNeq(etext[index],ttext[index])) return; // and this translation not missing - for (nn = 0; nn < Nzdpmax; nn++) - { - pp = fgets(buff,100,fid); - if (! pp) break; - if (strlen(pp) < 64) continue; - strncpy0(wintitle,buff,64); - strTrim(wintitle); - if (strlen(wintitle) < 3) continue; - ii = sscanf(buff + 64," %f %f ",&xpos,&ypos); - if (ii != 2) continue; - strcpy(zdposn[nn].wintitle,wintitle); - zdposn[nn].xpos = xpos; - zdposn[nn].ypos = ypos; + strcpy(outstring,"msgid "); // msgid "english line 1 %s \n" + pp1 = etext[index]; // "english line 2" + // ... + while (*pp1) { + while (*pp1 && *pp1 != '"') pp1++; + pp2 = pp1 + 1; + while (*pp1 && *pp2 && *pp2 != '"') pp2++; + if (*pp1 && *pp2) { + cc = strlen(outstring); + strncpy0(outstring+cc,pp1,pp2-pp1+2); + wprintf(trwin,"%s\n",outstring); + *outstring = 0; + pp1 = pp2 + 1; } - - fclose(fid); - Nzdposn = nn; - return Nzdposn; } - if (strEqu(action,"save")) // save dialog positions table to file - { - fid = fopen(posfile,"w"); - if (! fid) { - printf("cannot write zdialog_positions file \n"); - return 0; + strcpy(outstring,"msgstr "); // msgstr "translation line 1 %s \n" + pp1 = ttext[index]; // "translation line 2" + // ... + while (*pp1) { + while (*pp1 && *pp1 != '"') pp1++; + pp2 = pp1 + 1; + while (*pp1 && *pp2 && *pp2 != '"') pp2++; + if (*pp1 && *pp2) { + cc = strlen(outstring); + strncpy0(outstring+cc,pp1,pp2-pp1+2); + wprintf(trwin,"%s\n",outstring); + *outstring = 0; + pp1 = pp2 + 1; } - - for (nn = 0; nn < Nzdposn; nn++) - fprintf(fid,"%-64s %0.1f %0.1f \n",zdposn[nn].wintitle, - zdposn[nn].xpos, zdposn[nn].ypos); - fclose(fid); - return Nzdposn; } - printf("zdialog_positions bad action: %s \n",action); - return 0; + wprintf(trwin,"\n"); // blank line between pairs + + return; } -// Set the initial or new zdialog window position from "posn" -// null: window manager decides -// "mouse" put dialog at mouse position -// "desktop" center dialog in desktop window -// "parent" center dialog in parent window -// "save" use the same position last set by the user -// "nn/nn" put NW corner of dialog in parent window at % size -// (e.g. "50/50" puts NW corner at center of parent) +// merge translation edit window with user .po file and clear the window -void zdialog_set_position(zdialog *zd, cchar *posn) // new v.4.4 +void ZTXnames::ZTX_translation_update() // modified v.5.0 { - using namespace zdposn_names; - - int ii, ppx, ppy, zdpx, zdpy, pww, phh; - float xpos, ypos; - char wintitle[64], *pp; - GtkWidget *parent, *dialog; + using namespace zfuncs; + using namespace ZTXnames; - parent = zd->parent; - dialog = zd->widget[0].widget; - - if (strEqu(posn,"mouse")) { - gtk_window_set_position(GTK_WINDOW(dialog),GTK_WIN_POS_MOUSE); - return; - } + int ii, err, ftf, Nupd; + char pofile1[200], pofile2[200]; + char Fused[ZTXmaxent]; - if (strEqu(posn,"desktop")) { - gtk_window_set_position(GTK_WINDOW(dialog),GTK_WIN_POS_CENTER); - return; - } + ftf = 1; + wporec = 0; + *Etext = *Ttext = 0; + Nupd = 0; - if (strEqu(posn,"parent")) { - gtk_window_set_position(GTK_WINDOW(dialog),GTK_WIN_POS_CENTER_ON_PARENT); - return; + while (true) // scan translation edit window + { + if (! wporec) wporec = wscanf(trwin,ftf); + if (! wporec) break; // EOF + + if (blank_null(wporec)) { // blank record + wporec = 0; + continue; + } + + if (strnEqu(wporec,"msgid",5)) // start new english string + { + if (*Etext) { // two in a row + printf("no translation: %s \n",Etext); + *Etext = 0; + } + + if (*Ttext) { // should not happen + printf("orphan translation: %s \n",Ttext); + *Ttext = 0; + } + + wporec += 5; // get segmented text string + ZTXgettext2(Etext); // "segment1 %s \n" "segment2" ... + } + + else if (strnEqu(wporec,"msgstr",6)) // start new translation + { + wporec += 6; // get segmented string + ZTXgettext2(Ttext); + + if (! *Ttext) { + if (*Etext) printf("no translation: %s \n",Etext); + *Etext = 0; + } + else if (! *Etext) { // orphan or redundant translation + printf("orphan translation: %s \n",Ttext); + *Ttext = 0; + } + } + + else + { + printf("unrecognized record: %s \n",wporec); + wporec = 0; + continue; + } + + if (*Etext && *Ttext) // have an english/translation pair + { + for (ii = 0; ii < Ntext; ii++) // find existing (prior) entry + if (strEqu(Etext,etext[ii])) break; // in translation tables + if (ii == Ntext) + printf("English changed, translation ignored: %s \n",Etext); + else if (strNeq(Ttext,ttext[ii])) { // translation was updated + zfree(ttext[ii]); + ttext[ii] = strdupz(Ttext,0,"ZTX"); + Nupd++; + } + *Etext = *Ttext = 0; + } } - if (! parent) { // no parent window - ppx = ppy = 0; // use desktop - pww = gdk_screen_width(); - phh = gdk_screen_height(); + printf("%d new translations found \n",Nupd); + if (! Nupd) return; // nothing new + + memset(Fused,0,ZTXmaxent); // clear 'english text used' flags + + snprintf(pofile1,199,"%s/locales/%s-%s.po",zuserdir,zappname,zlang); // user .po file for new translations + fidr = fopen(pofile1,"r"); // open .po file for read + if (! fidr) { + printf("cannot read translation file: %s \n",pofile1); + return; } - else { - gtk_window_get_position(GTK_WINDOW(parent),&ppx,&ppy); // parent window NW corner - gtk_window_get_size(GTK_WINDOW(parent),&pww,&phh); // parent window size + + strcpy(pofile2,pofile1); // open .po.new file for write + strcat(pofile2,".new"); + fidw = fopen(pofile2,"w"); + if (! fidw) { + printf("cannot write updated translation file: %s \n",pofile2); + fclose(fidr); + return; } + + Nupd = 0; // count updates to .po file + porec = 0; + *Etext = *Ttext = 0; - if (strEqu(posn,"save")) // use last saved window position + while (true) // loop each .po record { - zd->saveposn = 1; // set flag for zdialog_free() + if (! porec) porec = fgets_trim(buff,ZTXmaxcc,fidr); // next record + if (! porec) break; // EOF - pp = (char *) gtk_window_get_title(GTK_WINDOW(dialog)); // get window title, used as ID - if (! pp) return; - if (strlen(pp) < 2) return; - strncpy0(wintitle,pp,64); // window title, < 64 chars. - for (ii = 0; ii < Nzdposn; ii++) // search table for title - if (strEqu(wintitle,zdposn[ii].wintitle)) break; - if (ii == Nzdposn) return; // not found - zdialog_free() will add + if (strnEqu(porec,"msgid",5)) { // msgid: "english 1 %s \n" "english 2" ... + porec += 5; + ZTXgettext(Etext); // aggregate strings + } - zdpx = ppx + 0.01 * zdposn[ii].xpos * pww; // position for dialog window - zdpy = ppy + 0.01 * zdposn[ii].ypos * phh; - gtk_window_move(GTK_WINDOW(dialog),zdpx,zdpy); - return; + else if (strnEqu(porec,"msgstr",6)) { // msgstr: "translation %s \n" ... + porec += 6; + ZTXgettext(Ttext); // aggregate strings + } + + else { + fprintf(fidw,"%s\n",porec); // other record, copy to output + porec = 0; + continue; + } + + if (*Etext && *Ttext) // have an english/translation pair + { + for (ii = 0; ii < Ntext; ii++) // find matching english in + if (strEqu(Etext,etext[ii])) break; // existing translations + if (ii < Ntext && ! Fused[ii]) { + if (strNeq(etext[ii],ttext[ii]) && + strNeq(Ttext,ttext[ii])) { // log translation added or updated + printf("changed: %s \n %s \n", // v.5.0 + etext[ii], ttext[ii]); + strcpy(Ttext,ttext[ii]); // substitute new translation + Nupd++; // actual .po updates made + } + Fused[ii] = 1; // mark english string as used + } + + ZTXwritetext("msgid",Etext); // output msgid: strings + ZTXwritetext("msgstr",Ttext); // and msgstr: strings + *Etext = *Ttext = 0; + } } - else // "nn/nn" // position from caller - { - ii = sscanf(posn,"%f/%f",&xpos,&ypos); // parse "nn/nn" - if (ii != 2) return; - zdpx = ppx + 0.01 * xpos * pww; // position for dialog window - zdpy = ppy + 0.01 * ypos * phh; - gtk_window_move(GTK_WINDOW(dialog),zdpx,zdpy); - return; + fclose(fidr); + fclose(fidw); + + if (Nupd) { // rename *.po.new to *.po + err = rename(pofile2,pofile1); + if (err) printf("cannot rename %s to *.po",pofile2); } + else remove(pofile2); // no changes, delete *.po.new + + ZTXinit(zlang); // put translations in use + + return; } -// If the dialog window position is "save" then save -// its position WRT parent or desktop for next use. +// private function +// read and combine multiple 'msgid' or 'msgstr' quoted strings +// output is one string with one or more quoted segments: +// "text line 1 %s \n" "text line 2" ... +// each segment comes from a different line in the translation edit window -void zdialog_save_position(zdialog *zd) // new v.4.4 +void ZTXnames::ZTXgettext2(char *pstring) // v.4.3 { - using namespace zdposn_names; + using namespace ZTXnames; - int ii, ppx, ppy, pww, phh, zdpx, zdpy; - float xpos, ypos; - char wintitle[64], *pp; - GtkWidget *parent, *dialog; + int cc, scc = 0, ftf = 0; - parent = zd->parent; - dialog = zd->widget[0].widget; - if (! dialog) return; // destroyed v.4.7 - - if (! parent) { // no parent window - ppx = ppy = 0; // use desktop - pww = gdk_screen_width(); - phh = gdk_screen_height(); - } - else { - gtk_window_get_position(GTK_WINDOW(parent),&ppx,&ppy); // parent window NW corner - gtk_window_get_size(GTK_WINDOW(parent),&pww,&phh); // parent window size + while (true) // join multiple quoted strings + { + while (*wporec && *wporec != '"') wporec++; // find opening string quote + if (! *wporec) { + wporec = wscanf(trwin,ftf); + if (! wporec) return; + if (blank_null(wporec)) continue; // bugfix v.5.0 + if (strnEqu(wporec,"msgid",5)) return; // end of this string + if (strnEqu(wporec,"msgstr",6)) return; + } + ppq1 = wporec; // opening quote + ppq2 = ppq1 + 1; + while ((*ppq2 && *ppq2 != '"') || // find closing (non-escaped) quote + (*ppq2 == '"' && *(ppq2-1) == '\\')) ppq2++; + if (! *ppq2) { + wporec = 0; + return; + } + cc = ppq2 - ppq1 + 1; // min. case is "" + if (cc + 1 + scc >= ZTXmaxcc) + printf("string is too long: %s \n",pstring); + else { + strncpy0(pstring+scc,ppq1,cc+1); // accum. substrings, minus quotes + scc += cc; + } + wporec = ppq2 + 1; } + + return; +} - gtk_window_get_position(GTK_WINDOW(dialog),&zdpx,&zdpy); // dialog window NW corner - xpos = 100.0 * (zdpx - ppx) / pww; // dialog window relative position - ypos = 100.0 * (zdpy - ppy) / phh; // (as percent of parent size) +// private function +// write quoted seqmented string to output .po file, 1 record per segment +// msgid "english string segment 1 %s \n" +// "english string segment 2 \n" +// ... - pp = (char *) gtk_window_get_title(GTK_WINDOW(dialog)); - if (! pp) return; - if (strlen(pp) < 2) return; - strncpy0(wintitle,pp,64); // window title, < 64 chars. +void ZTXnames::ZTXwritetext(cchar *header, char *text) +{ + char *pp1, *pp2; + int cc, ftf; + char segment[ZTXmaxcc]; - for (ii = 0; ii < Nzdposn; ii++) // search table for window - if (strEqu(wintitle,zdposn[ii].wintitle)) break; - if (ii == Nzdposn) { // not found - if (ii == Nzdpmax) return; // table full - strcpy(zdposn[ii].wintitle,wintitle); // add window to table - Nzdposn++; + ftf = 1; + pp1 = text; + + while (true) + { + while (*pp1 && *pp1 != '"') pp1++; // opening quote + if (! *pp1) break; + pp2 = pp1 + 1; + while ((*pp2 && *pp2 != '"') || // find closing (non-escaped) quote + (*pp2 == '"' && *(pp2-1) == '\\')) pp2++; + if (! *pp2) break; + cc = pp2 - pp1 + 1; + if (cc >= ZTXmaxcc) cc = ZTXmaxcc - 1; + strncpy0(segment,pp1,cc+1); + if (ftf) fprintf(fidw,"%s %s\n",header,segment); + else fprintf(fidw,"%s\n",segment); + ftf = 0; + pp1 = pp2 + 1; } - zdposn[ii].xpos = xpos; // save window position - zdposn[ii].ypos = ypos; return; } @@ -6062,10 +6086,10 @@ gtk_window_set_title(GTK_WINDOW(mWin),text); gtk_window_set_default_size(GTK_WINDOW(mWin),ww,hh); - if (parent) // parent added v.3.3 + if (parent) // parent added gtk_window_set_transient_for(GTK_WINDOW(mWin),GTK_WINDOW(parent)); - if (parent) // v.3.7 + if (parent) gtk_window_set_position(GTK_WINDOW(mWin),GTK_WIN_POS_CENTER_ON_PARENT); else gtk_window_set_position(GTK_WINDOW(mWin),GTK_WIN_POS_MOUSE); @@ -6112,12 +6136,12 @@ // execute a command and show the output in a scrolling popup window -int popup_command(cchar *command, int ww, int hh, GtkWidget *parent) // use write_popup_text() v.3.1 +int popup_command(cchar *command, int ww, int hh, GtkWidget *parent) // use write_popup_text() { char *buff; int err, contx = 0; - write_popup_text("open",command,ww,hh,parent); // bugfix v.3.8 + write_popup_text("open",command,ww,hh,parent); // bugfix while ((buff = command_output(contx,command))) { @@ -6136,7 +6160,7 @@ // display message box and wait for user acknowledgement -void zmessageACK(GtkWidget *parent, cchar *pMess, ... ) // v.3.7 +void zmessageACK(GtkWidget *parent, cchar *pMess, ... ) { va_list arglist; char message[400]; @@ -6147,7 +6171,7 @@ vsnprintf(message,400,pMess,arglist); va_end(arglist); - zd = zdialog_new("",parent," X ",null); // v.3.9 + zd = zdialog_new("",parent," X ",null); zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=5"); zdialog_add_widget(zd,"label","lab1","hb1",message,"space=5"); zdialog_resize(zd,200,0); @@ -6162,2446 +6186,966 @@ /**************************************************************************/ -// log error message to STDOUT as well as message box and user OK - -void zmessLogACK(GtkWidget *parent, cchar *pMess, ...) // v.3.5 -{ - va_list arglist; - char message[200]; - - va_start(arglist,pMess); - vsnprintf(message,200,pMess,arglist); - va_end(arglist); - - printf("%s \n",message); - zmessageACK(parent,message); - return; -} - - -/**************************************************************************/ - -// display message box and wait for user Yes or No response - -int zmessageYN(GtkWidget *parent, cchar *pMess, ... ) // v.3.7 -{ - va_list arglist; - char message[400]; - zdialog *zd; - int zstat; - GtkWidget *widget; - - va_start(arglist,pMess); - vsnprintf(message,400,pMess,arglist); - va_end(arglist); - - zd = zdialog_new("message",parent,ZTX("Yes"),ZTX("No"),null); - zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=5"); - zdialog_add_widget(zd,"label","lab1","hb1",message,"space=5"); - zdialog_resize(zd,200,0); - widget = zdialog_widget(zd,"dialog"); // make modal v.4.4 - gtk_window_set_modal(GTK_WINDOW(widget),1); - zdialog_run(zd); - zstat = zdialog_wait(zd); - zdialog_free(zd); - if (zstat == 1) return 1; - return 0; -} - - -/**************************************************************************/ - -// Display message box with message and button to display help topic // v.3.9 - -char *zmessage_help_topic = 0; - -void zmessage_help(GtkWidget *parent, cchar *topic, cchar *pmess, ... ) -{ - int zmessage_help_event(zdialog *zd, cchar *event); - - va_list arglist; - char message[400]; - zdialog *zd; - - va_start(arglist,pmess); - vsnprintf(message,400,pmess,arglist); - va_end(arglist); - - if (zmessage_help_topic) zfree(zmessage_help_topic); - zmessage_help_topic = strdupz(topic,0,"zmessage_help"); - - zd = zdialog_new("context help",parent,"Help"," X ",null); - zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=5"); - zdialog_add_widget(zd,"label","lab1","hb1",message,"space=5"); - zdialog_resize(zd,200,0); - zdialog_run(zd,zmessage_help_event); - zdialog_wait(zd); - zdialog_free(zd); - return; -} - -int zmessage_help_event(zdialog *zd, cchar *event) -{ - if (zd->zstat == 1) { - showz_userguide(zmessage_help_topic); - zd->zstat = 0; - } - - return 0; -} - - -/**************************************************************************/ - -// display message indefinitely until timeout or user cancel -// or caller kills it with zdialog_free() - -zdialog * zmessage_post(GtkWidget *parent, int seconds, cchar *pMess, ... ) -{ - int zmessage_post_timeout(zdialog *zd); - int zmessage_post_event(zdialog *zd, cchar *event); - - va_list arglist; - char message[400]; - static zdialog *zd; - - va_start(arglist,pMess); - vsnprintf(message,400,pMess,arglist); - va_end(arglist); - - zd = zdialog_new("message",parent,ZTX("cancel"),null); - zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=5"); - zdialog_add_widget(zd,"label","lab1","hb1",message,"space=5"); - zdialog_run(zd,zmessage_post_event); - - if (seconds) // seconds added v.4.3 - g_timeout_add_seconds(seconds,(GSourceFunc) zmessage_post_timeout,zd); - - return zd; -} - -int zmessage_post_timeout(zdialog *zd) -{ - if (zd && zd->zstat == 0) zdialog_free(zd); - return 0; -} - -int zmessage_post_event(zdialog *zd, cchar *event) -{ - if (zd && zd->zstat) zdialog_free(zd); - return 0; -} - - -/**************************************************************************/ - -// get text input from a popup dialog -// returned text is subject for zfree() - -char * zdialog_text(GtkWidget *parent, cchar *title, cchar *inittext) -{ - zdialog *zd; - int zstat; - char *text; - GtkWidget *widget; - - zd = zdialog_new(title,parent,"OK",ZTX("cancel"),null); - zdialog_add_widget(zd,"frame","fred","dialog"); - zdialog_add_widget(zd,"edit","edit","fred"); - if (inittext) zdialog_stuff(zd,"edit",inittext); - - zdialog_resize(zd,200,0); // v.3.7 - widget = zdialog_widget(zd,"dialog"); // make modal v.4.4 - gtk_window_set_modal(GTK_WINDOW(widget),1); - zdialog_run(zd); - zstat = zdialog_wait(zd); - if (zstat == 1) - text = (char *) zdialog_get_data(zd,"edit"); - else text = 0; - if (text) text = strdupz(text,0,"zdialog_text"); - zdialog_free(zd); - return text; -} - - -/**************************************************************************/ - -// Display a dialog with a message and 1-5 choice buttons. -// Returns choice 1-N corresponding to button selected. -// Parent window may be NULL. -// List of buttons must be NULL terminated. - -int zdialog_choose(cchar *title, GtkWidget *parent, cchar *message, ...) // new v.4.7 -{ - zdialog *zd; - va_list arglist; - int ii, zstat, Nbutts; - cchar *butts[5]; - - va_start(arglist,message); - - for (ii = 0; ii < 5; ii++) - { - butts[ii] = va_arg(arglist,cchar *); - if (! butts[ii]) break; - } - - Nbutts = ii; - if (! Nbutts) zappcrash("zdialog_choose(), no buttons"); - -repeat: - - zd = zdialog_new(title,parent,butts[0],butts[1],butts[2],butts[3],butts[4],null); - zdialog_add_widget(zd,"hbox","hbmess","dialog","space=5"); - zdialog_add_widget(zd,"label","labmess","hbmess",message,"space=5"); - zdialog_run(zd); - zstat = zdialog_wait(zd); - zdialog_free(zd); - - if (zstat < 1) goto repeat; - return zstat; -} - - -/**************************************************************************/ - -// File chooser dialog for one or more files -// -// Action: "open" select an existing file -// "openN" select multiple existing files -// "save" select an existing or new file -// "folder" select existing folder -// "create folder" select existing or new folder -// -// buttx: "hidden" add button to toggle display of hidden files -// "quality" add button to set JPG file save quality -// optional, default = null -// -// Returns a list of filespecs terminated with null. -// Memory for returned list and returned files are subjects for zfree(); - - -// version to select only 1 file - -char * zgetfile1(cchar *title, cchar *action, cchar *initfile, cchar *buttx) -{ - if (strEqu(action,"openN")) zappcrash("zgetfile1 called with openN"); - char **flist = zgetfileN(title,action,initfile,buttx); - if (! flist) return 0; - char *file = *flist; - zfree(flist); - return file; -} - - -// select one or multiple files // overhauled v.3.8 - -char ** zgetfileN(cchar *title, cchar *action, cchar *initfile, cchar *buttx) -{ - using namespace zfuncs; - - void zgetfile_preview(GtkWidget *dialog, GtkWidget *pvwidget); // private functions - void zgetfile_KBkey(GtkWidget *dialog, GdkEventKey *event); - void zgetfile_newfolder(GtkFileChooser *dialog, void *); - - GtkFileChooserAction fcact = GTK_FILE_CHOOSER_ACTION_OPEN; - - GtkWidget *dialog; - GtkWidget *pvwidget = gtk_image_new(); - GSList *gslist = 0; - cchar *button1 = 0, *buttxx = 0; - char *pdir, *pfile; - int ii, err, NF, setfname = 0; - int fcstat, bcode = 0, qnum, hide = 0; - char *qual, *file1, *file2, **flist = 0; - struct stat fstat; - - zthreadcrash(); // thread usage not allowed v.3.9 - - if (strEqu(action,"open")) { - fcact = GTK_FILE_CHOOSER_ACTION_OPEN; - button1 = ZTX("open"); - } - - if (strEqu(action,"openN")) { - fcact = GTK_FILE_CHOOSER_ACTION_OPEN; - button1 = ZTX("choose"); - } - - if (strEqu(action,"save")) { - fcact = GTK_FILE_CHOOSER_ACTION_SAVE; - button1 = ZTX("save"); - setfname = 1; - } - - if (strEqu(action,"folder")) { - fcact = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER; - button1 = ZTX("open folder"); - } - - if (strEqu(action,"create folder")) { - fcact = GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER; - button1 = ZTX("create folder"); - setfname = 1; - } - - if (buttx) { - if (strnEqu(buttx,"hidden",6)) { // generate text for translation - buttxx = ZTX("hidden"); // bugfix v.4.4 - bcode = 103; - } - if (strEqu(buttx,"quality")) { - buttxx = ZTX("quality"); - bcode = 104; - } - } - - dialog = gtk_file_chooser_dialog_new(title, null, fcact, // create file selection dialog - button1, GTK_RESPONSE_ACCEPT, - ZTX("cancel"), GTK_RESPONSE_CANCEL, - buttxx, bcode, null); - - gtk_file_chooser_set_preview_widget(GTK_FILE_CHOOSER(dialog),pvwidget); - - G_SIGNAL(dialog,"update-preview",zgetfile_preview,pvwidget); // create preview for selected file - G_SIGNAL(dialog,"key-release-event",zgetfile_KBkey,0); // respond to F1 help key - - gtk_window_set_position(GTK_WINDOW(dialog),GTK_WIN_POS_MOUSE); // put dialog at mouse position - gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(dialog),0); // default: no show hidden - - if (strEqu(action,"save")) // overwrite confirmation - gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog),1); - - if (strEqu(action,"openN")) - gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog),1); // select multiple files - - if (initfile) { // pre-select filespec - err = stat(initfile,&fstat); - if (err) { - pdir = strdupz(initfile); // non-existent file - pfile = strrchr(pdir,'/'); - if (pfile && pfile > pdir) { - *pfile++ = 0; // set folder name - gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog),pdir); - } - if (setfname) // set new file name v.4.7 - gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog),pfile); - zfree(pdir); - } - else if (S_ISREG(fstat.st_mode)) // select given file - gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog),initfile); - else if (S_ISDIR(fstat.st_mode)) // select given folder - gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog),initfile); - } - - gtk_widget_show_all(dialog); // v.3.9 - - while (true) - { - fcstat = gtk_dialog_run(GTK_DIALOG(dialog)); // run dialog, get status button - - if (fcstat == 103) { // show/hide hidden files - hide = gtk_file_chooser_get_show_hidden(GTK_FILE_CHOOSER(dialog)); - hide = 1 - hide; - gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(dialog),hide); - } - - else if (fcstat == 104) { // get JPG quality parameter - while (true) { - qual = zdialog_text(null,ZTX("JPG quality 0-100"),JPGquality); - if (! qual) break; // cancel = no change - err = convSI(qual,qnum,0,100); - zfree(qual); - if (err) continue; // enforce 0-100 - snprintf(JPGquality,4,"%d",qnum); - break; - } - } - - else break; // some other button - } - - if (fcstat == GTK_RESPONSE_ACCEPT) - { - gslist = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog)); - if (! gslist) goto fcreturn; - NF = g_slist_length(gslist); // no. selected files - if (! NF) goto fcreturn; - - flist = (char **) zmalloc((NF+1)*sizeof(char *),"zgetfile"); // allocate returned list v.3.5 - - for (ii = 0; ii < NF; ii++) - { // process selected files - file1 = (char *) g_slist_nth_data(gslist,ii); - if (strlen(file1) >= maxfcc) // v.3.5 - file1 = (char *) "ridiculously long filespec"; - file2 = strdupz(file1,0,"zgetfile"); // re-allocate memory v.3.5 - g_free(file1); - flist[ii] = file2; - } - flist[ii] = 0; // EOL marker - } - -fcreturn: - if (gslist) g_slist_free(gslist); - gtk_widget_destroy(dialog); - return flist; -} - - -// zgetfile private function - get preview images for image files // v.2.0 - -void zgetfile_preview(GtkWidget *dialog, GtkWidget *pvwidget) -{ - GdkPixbuf *thumbnail; - char *filename; - - filename = gtk_file_chooser_get_preview_filename(GTK_FILE_CHOOSER(dialog)); - - if (! filename) { - gtk_file_chooser_set_preview_widget_active(GTK_FILE_CHOOSER(dialog),0); - return; - } - - thumbnail = 0; - if (image_file_type(filename) == 2) // supported image file type - thumbnail = image_thumbnail(filename,192); // use 192x192 pixels v.4.7 - g_free(filename); - - if (thumbnail) { - gtk_image_set_from_pixbuf(GTK_IMAGE(pvwidget),thumbnail); - gtk_file_chooser_set_preview_widget_active(GTK_FILE_CHOOSER(dialog),1); - g_object_unref(thumbnail); - } - else gtk_file_chooser_set_preview_widget_active(GTK_FILE_CHOOSER(dialog),0); - - return; -} - - -// zgetfile private function - respond to F1 key -// zfuncs::F1_help_topic must be pre-loaded by caller if needed. - -void zgetfile_KBkey(GtkWidget *dialog, GdkEventKey *event) -{ - int KBkey = event->keyval; - if (KBkey == GDK_F1) - showz_userguide(zfuncs::F1_help_topic); - return; -} - - -/**************************************************************************/ - -// show a local or remote html file using the user's preferred browser // v.2.18 -// to show a local file starting at an internal live link location: -// url = "file://directory/.../filename#livelink - -void showz_html(cchar *url) -{ - char command[500]; - static char prog[20]; - static int ftf = 1, err; - - if (ftf) { - ftf = 0; - strcpy(prog,"xdg-open"); - err = system("xdg-open --version"); - if (err) { - strcpy(prog,"firefox"); - err = system("firefox -v"); - if (err) *prog = 0; - } - } - - if (! *prog) { - zmessLogACK(null,"no xdg-open or firefox, cannot show document"); - return; - } - - snprintf(command,499,"%s %s &",prog,url); // add '&' v.2.18 - printf(" %s \n",command); // v.4.1 - err = system(command); - return; -} - - -/**************************************************************************/ - -// connect a user callback function to a window drag-drop event - -void drag_drop_connect(GtkWidget *window, drag_drop_func *ufunc) // v.2.19 -{ - int drag_drop_connect2(GtkWidget *, void *, int, int, void *, int, int, void *); - char string[] = "STRING"; - GtkTargetEntry file_drop_target = { string, 0, 0 }; - - gtk_drag_dest_set(window, GTK_DEST_DEFAULT_ALL, &file_drop_target, 1, GDK_ACTION_COPY); - G_SIGNAL(window, "drag-data-received", drag_drop_connect2, ufunc) - gtk_drag_dest_add_uri_targets(window); // accept URI (file) drop v.2.27 - - return; -} - - -// private function -// get dropped file, clean escapes, pass to user function -// passed filespec is subject for zfree() - -int drag_drop_connect2(GtkWidget *, void *, int mpx, int mpy, void *sdata, int, int, void *ufunc) -{ - char * drag_drop_unescape(cchar *escaped_string); - drag_drop_func *ufunc2; - - char *text, *text2, *file, *file2; - int cc; - - text = (char *) ((GtkSelectionData *) sdata)->data; - ufunc2 = (drag_drop_func *) ufunc; - - if (strstr(text,"file://")) // text is a filespec - { - file = strdupz(text+7); // get rid of junk added by GTK - cc = strlen(file); - while (file[cc-1] < ' ') cc--; - file[cc] = 0; - file2 = drag_drop_unescape(file); // clean %xx escapes from Nautilus - zfree(file); - ufunc2(mpx,mpy,file2); // pass file to user function - } - - else - { - text2 = strdupz(text,0,"drag_drop"); // v.3.5 - ufunc2(mpx,mpy,text2); - } - - return 1; -} - - -// private function -// Clean %xx escapes from strange Nautilus drag-drop file names - -char * drag_drop_unescape(cchar *inp) -{ - int drag_drop_convhex(char ch); - - char inch, *out, *outp; - int nib1, nib2; - - out = zmalloc(strlen(inp)+1,"drag_drop"); // v.3.5 - outp = out; - - while ((inch = *inp++)) - { - if (inch == '%') - { - nib1 = drag_drop_convhex(*inp++); - nib2 = drag_drop_convhex(*inp++); - *outp++ = nib1 << 4 | nib2; - } - else *outp++ = inch; - } - - *outp = 0; - return out; -} - - -// private function - convert character 0-F to number 0-15 - -int drag_drop_convhex(char ch) -{ - if (ch >= '0' && ch <= '9') return ch - '0'; - if (ch >= 'A' && ch <= 'F') return ch - 'A' + 10; - if (ch >= 'a' && ch <= 'f') return ch - 'a' + 10; - return ch; -} - - -// make a cursor from a graphic file in application's icon directory - -GdkCursor * zmakecursor(cchar *iconfile) // v.3.7 -{ - using namespace zfuncs; - - GError *gerror = 0; - GdkPixbuf *pixbuf; - GdkDisplay *display; - GdkCursor *cursor = 0; - char iconpath[200]; - - zthreadcrash(); // thread usage not allowed v.3.9 - - display = gdk_display_get_default(); - *iconpath = 0; - strncatv(iconpath,199,zicondir,"/",iconfile,null); - pixbuf = gdk_pixbuf_new_from_file(iconpath,&gerror); - if (pixbuf && display) - cursor = gdk_cursor_new_from_pixbuf(display,pixbuf,0,0); - else printf("%s \n",gerror->message); - return cursor; -} - - -/**************************************************************************/ -// GDK/GTK image file utility functions -// for functions returning char *, caller responsible for zfree() -/**************************************************************************/ - - -/************************************************************************** - - Programs for printing an image file new v.4.7 - - HPLIP problem: Setting paper size was made less flexible. - GtkPrintSettings paper size must agree with the one in the current - printer setup. This can only be set in the printer setup dialog, not - in the application. Also the print size (width, height) comes from - the chosen paper size and cannot be changed in the application. - Print margins can be changed to effect printing a smaller or shifted - image on a larger paper size. - - - print_image_paper_setup() - - Do a print paper format selection, after which the page width, height - and orientation are available to the caller. Units are CM. - (paper width and height are reversed for landscape orientation) - - - print_image_margins_setup() - - Optionally set the print margins. If not done they are zero - (or printer-dependent minimum). Afterwards the margins are - available to the caller. Units are CM. - - - print_image_file(cchar *imagefile) - - Print the image file on the printer and paper size determined by - a prior call to print_image_paper_setup. - - -***************************************************************************/ - - -namespace print_image -{ - #define MM GTK_UNIT_MM - #define PRINTOP GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG - #define PORTRAIT GTK_PAGE_ORIENTATION_PORTRAIT - #define LANDSCAPE GTK_PAGE_ORIENTATION_LANDSCAPE - #define QUALITY GTK_PRINT_QUALITY_HIGH - - GtkPageSetup *priorpagesetup = 0; - GtkPageSetup *pagesetup; - GtkPrintSettings *printsettings = 0; - GtkPrintOperation *printop; - GtkPageOrientation orientation = PORTRAIT; - GdkPixbuf *pixbuf; - cchar *printer = 0; - double width = 21.0, height = 29.7; // paper size, CM (default A4 portrait) - double margins[4] = { 0, 0, 0, 0 }; // print margins, CM (default none) - int landscape = 0; // true if landscape -} - - -void print_image_paper_setup() -{ - using namespace print_image; - - char printsettingsfile[200], pagesetupfile[200]; - - snprintf(printsettingsfile,200,"%s/printsettings",get_zuserdir()); - snprintf(pagesetupfile,200,"%s/pagesetup",get_zuserdir()); - - if (! printsettings) { // start with prior print settings - printsettings = gtk_print_settings_new_from_file(printsettingsfile,0); - if (! printsettings) - printsettings = gtk_print_settings_new(); - } - - if (! priorpagesetup) { // start with prior page setup - priorpagesetup = gtk_page_setup_new_from_file(pagesetupfile,0); - if (! priorpagesetup) - priorpagesetup = gtk_page_setup_new(); - } - - pagesetup = gtk_print_run_page_setup_dialog // select printer, paper size - (0,priorpagesetup,printsettings); // and orientation - if (! pagesetup) return; - - g_object_unref(priorpagesetup); // save for next call - priorpagesetup = pagesetup; - - width = gtk_page_setup_get_paper_width(pagesetup,MM); // save paper width, height - height = gtk_page_setup_get_paper_height(pagesetup,MM); - width = width / 10; // use cm units - height = height / 10; - - orientation = gtk_print_settings_get_orientation(printsettings); // save orientation - if (orientation == LANDSCAPE) landscape = 1; - else landscape = 0; - - gtk_print_settings_set_quality(printsettings,QUALITY); // set high quality 300 dpi - gtk_print_settings_set_resolution(printsettings,300); - - gtk_print_settings_to_file(printsettings,printsettingsfile,0); // save print settings to file - gtk_page_setup_to_file(pagesetup,pagesetupfile,0); // save print settings to file - - return; -} - - -void print_image_margins_setup() -{ - using namespace print_image; - - zdialog *zd; - int zstat; - - zd = zdialog_new(ZTX("margins"),0,ZTX("done"),ZTX("cancel"),0); // build dialog - - zdialog_add_widget(zd,"hbox","hbmlab","dialog",0,"homog"); // top bottom left right - zdialog_add_widget(zd,"vbox","vbmarg","hbmlab",0,"space=3"); // margins [___] [___] [___] [___] - zdialog_add_widget(zd,"vbox","vbtop","hbmlab",0,"space=3"); - zdialog_add_widget(zd,"vbox","vbbottom","hbmlab",0,"space=3"); - zdialog_add_widget(zd,"vbox","vbleft","hbmlab",0,"space=3"); - zdialog_add_widget(zd,"vbox","vbright","hbmlab",0,"space=3"); - zdialog_add_widget(zd,"label","space","vbmarg"," "); - zdialog_add_widget(zd,"label","labtop","vbtop",ZTX("top")); - zdialog_add_widget(zd,"label","labbot","vbbottom",ZTX("bottom")); - zdialog_add_widget(zd,"label","lableft","vbleft",ZTX("left")); - zdialog_add_widget(zd,"label","labright","vbright",ZTX("right")); - zdialog_add_widget(zd,"label","labmarg","vbmarg",ZTX("margins"),"space=3"); - zdialog_add_widget(zd,"spin","mtop","vbtop","0|3|0.1|0"); - zdialog_add_widget(zd,"spin","mbottom","vbbottom","0|3|0.1|0"); - zdialog_add_widget(zd,"spin","mleft","vbleft","0|3|0.1|0"); - zdialog_add_widget(zd,"spin","mright","vbright","0|3|0.1|0"); - - zdialog_stuff(zd,"mtop",margins[0]); // stuff prior print margins - zdialog_stuff(zd,"mbottom",margins[1]); - zdialog_stuff(zd,"mleft",margins[2]); - zdialog_stuff(zd,"mright",margins[3]); - - zdialog_run(zd); // run dialog - zstat = zdialog_wait(zd); // wait for completion - - if (zstat != 1) { // user canceled - zdialog_free(zd); - return; - } - - zdialog_fetch(zd,"mtop",margins[0]); // set print margins - zdialog_fetch(zd,"mbottom",margins[1]); - zdialog_fetch(zd,"mleft",margins[2]); - zdialog_fetch(zd,"mright",margins[3]); - - zdialog_free(zd); // kill dialog - - gtk_page_setup_set_top_margin(pagesetup,10*margins[0],MM); // set page margins, mm units - gtk_page_setup_set_bottom_margin(pagesetup,10*margins[1],MM); - gtk_page_setup_set_left_margin(pagesetup,10*margins[2],MM); - gtk_page_setup_set_right_margin(pagesetup,10*margins[3],MM); - - return; -} - - -void print_image_file(cchar *imagefile) -{ - using namespace print_image; - - void print_image_page(GtkPrintOperation *, GtkPrintContext *, int page); - - GtkPrintOperationResult printstat; - GError *gerror = 0; - - pixbuf = gdk_pixbuf_new_from_file(imagefile,&gerror); // read image file - if (! pixbuf) { - zmessageACK(null,gerror->message); - return; - } - - printop = gtk_print_operation_new(); // print operation - gtk_print_operation_set_default_page_setup(printop,pagesetup); - gtk_print_operation_set_print_settings(printop,printsettings); - gtk_print_operation_set_n_pages(printop,1); - - g_signal_connect(printop,"draw-page",G_CALLBACK(print_image_page),0); // start print - printstat = gtk_print_operation_run(printop,PRINTOP,0,0); - - if (printstat == GTK_PRINT_OPERATION_RESULT_ERROR) { - gtk_print_operation_get_error(printop,&gerror); - zmessageACK(null,gerror->message); - } - - g_object_unref(printop); - return; -} - - -// draw the graphics for the print page -// rescale with cairo: print resolution of 300 dpi is no longer ignored - -void print_image_page(GtkPrintOperation *printop, GtkPrintContext *printcontext, int page) -{ - using namespace print_image; - - cairo_t *cairocontext; - double iww, ihh, pww, phh, scale; - - pww = gtk_print_context_get_width(printcontext); // print context size - phh = gtk_print_context_get_height(printcontext); - - iww = gdk_pixbuf_get_width(pixbuf); // image size - ihh = gdk_pixbuf_get_height(pixbuf); - - scale = pww / iww; // rescale to fit page - if (phh / ihh < scale) scale = phh / ihh; - - cairocontext = gtk_print_context_get_cairo_context(printcontext); // use cairo to rescale - cairo_translate(cairocontext,0,0); - cairo_scale(cairocontext,scale,scale); - gdk_cairo_set_source_pixbuf(cairocontext,pixbuf,0,0); - cairo_paint(cairocontext); - - return; -} - - -/************************************************************************** - - GdkPixbuf * gdk_pixbuf_rotate(GdkPixbuf *pixbuf, double angle, int acolor) - - Rotate a pixbuf through an arbitrary angle (degrees). - - The returned image has the same size as the original, but the - pixbuf envelope is increased to accomodate the rotated original - (e.g. a 100x100 pixbuf rotated 45 deg. needs a 142x142 pixbuf). - - Pixels added around the rotated image have all RGB values = acolor. // v.2.17 - Angle is in degrees. Positive direction is clockwise. - Pixbuf must have 8 bits per channel and 3 or 4 channels. - Loss of resolution is about 1/2 pixel. - Speed is about 18 million pixels/sec. on my 2.67 GHz CPU. // v.3.2 - - NULL is returned if the function fails for one of the following: - - pixbuf not 8 bits/channel or < 3 channels - - unable to create output pixbuf (lack of memory?) - - Algorithm: - create output pixbuf big enough for rotated input pixbuf - compute coefficients for affine transform - loop all output pixels - get next output pixel (px2,py2) - convert to input pixel (px1,py1) using affine transform // v.3.2 - if outside of pixmap - output pixel = black - continue - for 4 input pixels based at (px0,py0) = (int(px1),int(py1)) - compute overlap (0 to 1) with (px1,py1) - sum RGB values * overlap - output aggregate RGB to pixel (px2,py2) - -***/ - -GdkPixbuf * gdk_pixbuf_rotate(GdkPixbuf *pixbuf1, double angle, int acolor) -{ - typedef unsigned char *pixel; // 3 RGB values, 0-255 each - - GdkPixbuf *pixbuf2; - GdkColorspace color; - - int nch, nbits, alpha; - int ww1, hh1, rs1, ww2, hh2, rs2; - int px2, py2, px0, py0; - pixel ppix1, ppix2, pix0, pix1, pix2, pix3; - double px1, py1; - double f0, f1, f2, f3, red, green, blue, tran = 0; - double a, b, d, e, ww15, hh15, ww25, hh25; - double pi = 3.141593; - - zthreadcrash(); // thread usage not allowed v.3.9 - - nch = gdk_pixbuf_get_n_channels(pixbuf1); - nbits = gdk_pixbuf_get_bits_per_sample(pixbuf1); - if (nch < 3) return 0; // must have 3+ channels (colors) - if (nbits != 8) return 0; // must be 8 bits per channel - - color = gdk_pixbuf_get_colorspace(pixbuf1); // get input pixbuf1 attributes - alpha = gdk_pixbuf_get_has_alpha(pixbuf1); - ww1 = gdk_pixbuf_get_width(pixbuf1); - hh1 = gdk_pixbuf_get_height(pixbuf1); - rs1 = gdk_pixbuf_get_rowstride(pixbuf1); - - while (angle < -180) angle += 360; // normalize, -180 to +180 - while (angle > 180) angle -= 360; - angle = angle * pi / 180; // radians, -pi to +pi - - if (fabs(angle) < 0.001) { // bugfix 0.01 >> 0.001 v.2.1 - pixbuf2 = gdk_pixbuf_copy(pixbuf1); // angle is zero within my precision - return pixbuf2; - } +// log error message to STDOUT as well as message box and user OK - ww2 = int(ww1*fabs(cos(angle)) + hh1*fabs(sin(angle))); // rectangle containing rotated image - hh2 = int(ww1*fabs(sin(angle)) + hh1*fabs(cos(angle))); +void zmessLogACK(GtkWidget *parent, cchar *pMess, ...) +{ + va_list arglist; + char message[200]; - pixbuf2 = gdk_pixbuf_new(color,alpha,nbits,ww2,hh2); // create output pixbuf2 - if (! pixbuf2) return 0; - rs2 = gdk_pixbuf_get_rowstride(pixbuf2); - - ppix1 = gdk_pixbuf_get_pixels(pixbuf1); // input pixel array - ppix2 = gdk_pixbuf_get_pixels(pixbuf2); // output pixel array + va_start(arglist,pMess); + vsnprintf(message,200,pMess,arglist); + va_end(arglist); - ww15 = 0.5 * ww1; - hh15 = 0.5 * hh1; - ww25 = 0.5 * ww2; - hh25 = 0.5 * hh2; + printf("%s \n",message); + zmessageACK(parent,message); + return; +} - a = cos(angle); // affine transform coefficients v.3.2 - b = sin(angle); - d = - sin(angle); - e = cos(angle); - - for (py2 = 0; py2 < hh2; py2++) // loop through output pixels - for (px2 = 0; px2 < ww2; px2++) - { - px1 = a * (px2 - ww25) + b * (py2 - hh25) + ww15; // (px1,py1) = corresponding v.3.2 - py1 = d * (px2 - ww25) + e * (py2 - hh25) + hh15; // point within input pixels +/**************************************************************************/ - px0 = int(px1); // pixel containing (px1,py1) - py0 = int(py1); - - if (px1 < 0 || px0 >= ww1-1 || py1 < 0 || py0 >= hh1-1) { // if outside input pixel array - pix2 = ppix2 + py2 * rs2 + px2 * nch; // output is acolor v.2.17 - pix2[0] = pix2[1] = pix2[2] = acolor; - continue; - } +// display message box and wait for user Yes or No response - pix0 = ppix1 + py0 * rs1 + px0 * nch; // 4 input pixels based at (px0,py0) - pix1 = pix0 + rs1; - pix2 = pix0 + nch; - pix3 = pix0 + rs1 + nch; +int zmessageYN(GtkWidget *parent, cchar *pMess, ... ) +{ + va_list arglist; + char message[400]; + zdialog *zd; + int zstat; + GtkWidget *widget; - f0 = (px0+1 - px1) * (py0+1 - py1); // overlap of (px1,py1) - f1 = (px0+1 - px1) * (py1 - py0); // in each of the 4 pixels - f2 = (px1 - px0) * (py0+1 - py1); - f3 = (px1 - px0) * (py1 - py0); + va_start(arglist,pMess); + vsnprintf(message,400,pMess,arglist); + va_end(arglist); - red = f0 * pix0[0] + f1 * pix1[0] + f2 * pix2[0] + f3 * pix3[0]; // sum the weighted inputs - green = f0 * pix0[1] + f1 * pix1[1] + f2 * pix2[1] + f3 * pix3[1]; - blue = f0 * pix0[2] + f1 * pix1[2] + f2 * pix2[2] + f3 * pix3[2]; - if (alpha) - tran = f0 * pix0[3] + f1 * pix1[3] + f2 * pix2[3] + f3 * pix3[3]; // bugfix v.3.3 - - if (red == acolor && green == acolor && blue == acolor) { // avoid acolor in image v.2.17 - if (blue == 0) blue = 1; - else blue--; - } - - pix2 = ppix2 + py2 * rs2 + px2 * nch; // output pixel - pix2[0] = int(red); - pix2[1] = int(green); - pix2[2] = int(blue); - if (alpha) pix2[3] = int(tran); // bugfix v.3.3 - } - - return pixbuf2; + zd = zdialog_new("message",parent,ZTX("Yes"),ZTX("No"),null); + zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=5"); + zdialog_add_widget(zd,"label","lab1","hb1",message,"space=5"); + zdialog_resize(zd,200,0); + widget = zdialog_widget(zd,"dialog"); // make modal v.4.4 + gtk_window_set_modal(GTK_WINDOW(widget),1); + zdialog_run(zd); + zstat = zdialog_wait(zd); + zdialog_free(zd); + if (zstat == 1) return 1; + return 0; } -/************************************************************************** +/**************************************************************************/ - functions for navigation of image files in a directory // overhauled v.2.3 - - get first or last image, previous or next image - - create an image gallery window (thumbnail images) - - use gallery window to navigate and select images +// Display message box with message and button to display help topic -**************************************************************************/ +char *zmessage_help_topic = 0; -namespace image_navi +void zmessage_help(GtkWidget *parent, cchar *topic, cchar *pmess, ... ) { - #define maxFiles 100000 // max image files in one directory v.4.1 - #define thumbnail_cachesize 10000 // max thumbnails cached in memory v.4.1 - #define imagetypes ".jpeg .jpg .png .tif .tiff .bmp .gif .svg .xpm" // supported image file types - - #define TEXTWIN GTK_TEXT_WINDOW_TEXT // GDK window of GTK text view - #define NODITHER GDK_RGB_DITHER_NONE - #define SCROLLWIN GTK_SCROLLED_WINDOW - #define NEVER GTK_POLICY_NEVER - #define ALWAYS GTK_POLICY_ALWAYS - #define interp GDK_INTERP_BILINEAR - #define colorspace GDK_COLORSPACE_RGB - - int thumbfilesize = 256; // default thumbnail image size v.4.7 - #define thumbxx 6 // thumbx array size - int thumbx[6] = { 512, 360, 256, 180, 128, 90 }; // thumbnail image step sizes v.4.7 - - char *galleryname = 0; // image directory or file list name - int gallerytype = 0; // 1/2 = directory / file list - int nfiles = 0; // total file count (incl. subdirks) - int nimages = 0; // image file count - char **flist = 0; // image file list - - typedef void ufunc(int Nth, int button); // callback function for clicked image - ufunc *userfunc; - - GtkWidget *wing = 0, *vboxx, *scrwing, *layout; // image gallery and drawing windows - GtkWidget *pwing = 0; // parent window - GtkAdjustment *scrollbar; - GdkGC *gdkgc = 0; // graphics context - - int xwinW = 1000, xwinH = 700; // gallery window initial size - int xwinX, xwinY; // gallery window initial position - int thumbsize = thumbfilesize; // thumbnail image <= thumbnail file - int thumbW, thumbH; // gallery window thumbnail cell size - int xrows, xcols; // gallery window thumbnail rows, cols - int xmargW, xmargH; // cell margin from left and top edge - int genthumbs = 0; // count newly generated thumbnails - int scrollposn; // gallery window scroll position - int maxscroll; // max. scroll position - int fpresent = 0; // force gallery window to z-top - int targposn = 0; // scroll-to file position (Nth) - cchar *toomanyfiles = "exceed %d files in one directory"; - - // private functions - int gallery_paint(GtkWidget *, GdkEventExpose *); // gallery window paint function - void draw_text(GtkWidget *win, char *text, int x, int y, int ww); // draw text in gallery window - void gallery_destroy(); // gallery window destroy event function - void menufuncx(GtkWidget *win, cchar *menu); // function for gallery window buttons - void mouse_xevent(GtkWidget *, GdkEventButton *, void *); // gallery window mouse event function - int KBxpress(GtkWidget *, GdkEventKey *, void *); // gallery window key press event func. - int KBxrelease(GtkWidget *, GdkEventKey *, void *); // gallery window key release event - char * image_navigate(cchar *filez, cchar *action, int Nth = 0); // image file list setup and navigate - int image_fcomp(cchar *file1, cchar *file2); // file name compare (special sort) -} + int zmessage_help_event(zdialog *zd, cchar *event); + va_list arglist; + char message[400]; + zdialog *zd; -/************************************************************************** + va_start(arglist,pmess); + vsnprintf(message,400,pmess,arglist); + va_end(arglist); - public function to create/update image gallery (thumbnail window) // overhauled v.4.1 + if (zmessage_help_topic) zfree(zmessage_help_topic); + zmessage_help_topic = strdupz(topic,0,"zmessage_help"); + + zd = zdialog_new("context help",parent,"Help"," X ",null); + zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=5"); + zdialog_add_widget(zd,"label","lab1","hb1",message,"space=5"); + zdialog_resize(zd,200,0); + zdialog_run(zd,zmessage_help_event); + zdialog_wait(zd); + zdialog_free(zd); + return; +} - Make window scrolling window of thumbnails for a list of files - Handle window buttons (up row, down page, open file, etc.) - Call ufunc() when thumbnail image is clicked - - char * image_gallery(cchar *filez, cchar *action, int Nth, - void ufunc(int Nth, int button), GtkWidget *parent) - - filez: image file or directory of image files or file with list of image files - - action: init: filez = initial file or directory - initF: filez = file with list of image files to use - sort: sort the file list, directories first, ignore case - insert: insert filez into file list at position Nth (0 to last+1) - delete: delete Nth file in list - find: return Nth file (0 base) or null if Nth > last - paint1: create or refresh gallery window, anchor = Nth file - paint2: refresh gallery window if present, anchor = Nth file - close close gallery window - - Nth: file to return (action = find) or file to scroll-to (action = paint) - - void ufunc(int Nth): - - returns Nth of clicked thumbnail (0 to last) - - returns -1 if gallery window is closed - - returns -2 if key F1 is pressed (for context help) - - parent: optional parent window - if present, gallery window will overlay the parent window - (window placement can be undone by the user) - - Returned values: - Nth: filespec, others: null - The returned file belongs to caller and is subject for zfree(). +int zmessage_help_event(zdialog *zd, cchar *event) +{ + if (zd->zstat == 1) { + showz_userguide(zmessage_help_topic); + zd->zstat = 0; + } -***************************************************************************/ + return 0; +} -char * image_gallery(cchar *filez, cchar *action, int Nth, - void ufunc(int Nth, int button), GtkWidget *parent) -{ - using namespace image_navi; - GtkWidget *tbarx; +/**************************************************************************/ - zthreadcrash(); // thread usage not allowed +// display message indefinitely until timeout or user cancel +// or caller kills it with zdialog_free() - if (ufunc) userfunc = ufunc; // save callback function - if (parent) pwing = parent; // save parent window +zdialog * zmessage_post(GtkWidget *parent, int seconds, cchar *pMess, ... ) +{ + int zmessage_post_timeout(zdialog *zd); + int zmessage_post_event(zdialog *zd, cchar *event); - if (strstr("init initF sort insert delete find",action)) - return image_navigate(filez,action,Nth); // create or navigate image file list - - if (strEqu(action,"close")) { - if (wing) gtk_widget_destroy(wing); - return 0; - } + va_list arglist; + char message[400]; + static zdialog *zd; + + va_start(arglist,pMess); + vsnprintf(message,400,pMess,arglist); + va_end(arglist); + + zd = zdialog_new("message",parent,ZTX("cancel"),null); + zdialog_add_widget(zd,"hbox","hb1","dialog",0,"space=5"); + zdialog_add_widget(zd,"label","lab1","hb1",message,"space=5"); + zdialog_run(zd,zmessage_post_event); - if (! strnEqu(action,"paint",5)) // must be paint1 or paint2 - zappcrash("image_gallery action: %s",action); + if (seconds) // seconds added v.4.3 + g_timeout_add_seconds(seconds,(GSourceFunc) zmessage_post_timeout,zd); + + return zd; +} - if (strEqu(action,"paint2") && ! wing) return 0; // refresh but window not active - if (strEqu(action,"paint1")) fpresent++; // bring window to z-top +int zmessage_post_timeout(zdialog *zd) +{ + if (zd && zd->zstat == 0) zdialog_free(zd); + return 0; +} - if (Nth >= 0) targposn = Nth; // scroll-to file position v.4.1 - else if (filez) targposn = image_gallery_position(filez,0); // or use filez if present v.4.4 - if (targposn > nfiles-1) targposn = nfiles-1; // (-1 for no change) v.4.1 +int zmessage_post_event(zdialog *zd, cchar *event) +{ + if (zd && zd->zstat) zdialog_free(zd); + return 0; +} - if (wing) { // repaint existing gallery window - gallery_paint(0,0); - return 0; - } - wing = gtk_window_new(GTK_WINDOW_TOPLEVEL); // create new gallery window - - if (pwing) { - gtk_window_get_size(GTK_WINDOW(pwing),&xwinW,&xwinH); // overlay parent window v.3.8 - gtk_window_get_position(GTK_WINDOW(pwing),&xwinX,&xwinY); - gtk_window_set_default_size(GTK_WINDOW(wing),xwinW,xwinH); - gtk_window_move(GTK_WINDOW(wing),xwinX,xwinY); - } - else { - gtk_window_set_default_size(GTK_WINDOW(wing),xwinW,xwinH+56); // + toolbar size to stop shrinkage - gtk_window_set_position(GTK_WINDOW(wing),GTK_WIN_POS_MOUSE); // v.3.7 - } +/**************************************************************************/ - vboxx = gtk_vbox_new(0,0); // vertical packing box - gtk_container_add(GTK_CONTAINER(wing),vboxx); // add to main window +// get text input from a popup dialog +// returned text is subject for zfree() - tbarx = create_toolbar(vboxx,24); // add toolbar and buttons - gtk_toolbar_set_style(GTK_TOOLBAR(tbarx),GTK_TOOLBAR_BOTH); // v.4.7 - - add_toolbar_button(tbarx, ZTX("bigger"), ZTX("increase thumbnail size"), "gtk-zoom-in", menufuncx); - add_toolbar_button(tbarx, ZTX("smaller"), ZTX("reduce thumbnail size"), "gtk-zoom-out", menufuncx); - add_toolbar_button(tbarx, ZTX("parent"), ZTX("parent directory"), "folder.png", menufuncx); - add_toolbar_button(tbarx, ZTX("first page"), ZTX("jump to first file"), "first-page.png", menufuncx); - add_toolbar_button(tbarx, ZTX("prev page"), ZTX("previous page"), "prev-page.png", menufuncx); - add_toolbar_button(tbarx, ZTX("prev row"), ZTX("previous row"), "prev-row.png", menufuncx); - add_toolbar_button(tbarx, ZTX("next row"), ZTX("next row"), "next-row.png", menufuncx); - add_toolbar_button(tbarx, ZTX("next page"), ZTX("next page"), "next-page.png", menufuncx); - add_toolbar_button(tbarx, ZTX("last page"), ZTX("jump to last file"), "last-page.png", menufuncx); - add_toolbar_button(tbarx, ZTX("close"), ZTX("close image gallery"), "gtk-close", menufuncx); - - scrwing = gtk_scrolled_window_new(0,0); // create scrolled window - gtk_container_add(GTK_CONTAINER(vboxx),scrwing); // add to main window - layout = gtk_layout_new(0,0); // create drawing window - gtk_container_add(GTK_CONTAINER(scrwing),layout); // add to scrolled window - gtk_scrolled_window_set_policy(SCROLLWIN(scrwing),NEVER,ALWAYS); // vertical scroll bar - scrollbar = gtk_layout_get_vadjustment(GTK_LAYOUT(layout)); - - G_SIGNAL(wing,"destroy",gallery_destroy,0) // connect window events - G_SIGNAL(layout,"expose-event",gallery_paint,0) - gtk_widget_add_events(layout,GDK_BUTTON_PRESS_MASK); // connect mouse events - G_SIGNAL(layout,"button-press-event",mouse_xevent,0) - G_SIGNAL(wing,"key-press-event",KBxpress,0) // connect KB events - G_SIGNAL(wing,"key-release-event",KBxrelease,0) - - gtk_widget_show_all(wing); // show all widgets - gdkgc = gdk_gc_new(layout->window); // initz. graphics context - gallery_paint(0,0); // repaint - gtk_window_present(GTK_WINDOW(wing)); // bring gallery window to top - zmainloop(); // v.4.7 +char * zdialog_text(GtkWidget *parent, cchar *title, cchar *inittext) +{ + zdialog *zd; + int zstat; + char *text; + GtkWidget *widget; + + zd = zdialog_new(title,parent,"OK",ZTX("cancel"),null); + zdialog_add_widget(zd,"frame","fred","dialog"); + zdialog_add_widget(zd,"edit","edit","fred"); + if (inittext) zdialog_stuff(zd,"edit",inittext); - return 0; + zdialog_resize(zd,200,0); + widget = zdialog_widget(zd,"dialog"); // make modal v.4.4 + gtk_window_set_modal(GTK_WINDOW(widget),1); + zdialog_run(zd); + zstat = zdialog_wait(zd); + if (zstat == 1) + text = (char *) zdialog_get_data(zd,"edit"); + else text = 0; + if (text) text = strdupz(text,0,"zdialog_text"); + zdialog_free(zd); + return text; } -// expose event private function -// paint gallery window - draw all thumbnail images that can fit -// v.3.6 mostly rewritten for higher speed and scroll bar support - -int image_navi::gallery_paint(GtkWidget *, GdkEventExpose *expose) -{ - using namespace image_navi; - - GdkPixbuf *pxbT; - GdkRectangle rect; - int ii, nrows, row1, row2; - int currscrollposn; - int layoutW, layoutH; - int expy1, expy2, row, col; - int thumx, thumy, orgx, orgy, ww, hh; - int popup = 0; - char *fileC, *pp, *fname; - char wintitle[200]; - - xwinW = layout->allocation.width; // curr. gallery window size - xwinH = layout->allocation.height; - - thumbW = thumbsize + 10; // thumbnail cell size - thumbH = thumbsize + 30; - xmargW = xmargH = 5; // edge margins - - if (! thumbsize) { - thumbW = 400; // zero, list view v.4.7 - thumbH = 20; - } - - xrows = int(0.2 + 1.0 * xwinH / thumbH); // get thumbnail rows and cols that v.4.1 - xcols = int(0.3 + 1.0 * xwinW / thumbW); // (almost) fit in window - if (xrows < 1) xrows = 1; - if (xcols < 1) xcols = 1; - nrows = (nfiles+xcols-1) / xcols; // thumbnail rows, 1 or more v.4.1 - if (nrows < 1) nrows = 1; // bugfix v.4.7 - - layoutW = xcols * thumbW + xmargW + 10; // layout size for entire file list - layoutH = (nrows+1) * thumbH + xmargH; // last row + 1 - if (layoutH < xwinH) layoutH = xwinH; // bugfix - gtk_layout_set_size(GTK_LAYOUT(layout),layoutW,layoutH); - - maxscroll = layoutH - xwinH; // scroll to end of layout - if (maxscroll < 0) maxscroll = 0; - - gtk_adjustment_set_step_increment(scrollbar,thumbH); // scrollbar works in row steps - gtk_adjustment_set_page_increment(scrollbar,thumbH * xrows); // and in page steps - - currscrollposn = gtk_adjustment_get_value(scrollbar); // current scroll position - scrollposn = currscrollposn; - - if (targposn >= 0) { - scrollposn = targposn / xcols * thumbH; // set initial scroll position from - if (scrollposn > maxscroll) scrollposn = maxscroll; // target file position if defined, - scrollposn = scrollposn / thumbH * thumbH; // then disable it for local control - } // of scrolling from gallery window - targposn = -1; - - if (scrollposn > maxscroll) scrollposn = maxscroll; // bugfix v.3.7 - - if (scrollposn != currscrollposn) - gtk_adjustment_set_value(scrollbar,scrollposn); // will cause re-entrance - - if (! expose) // initial window or navigation button - { - snprintf(wintitle,199,"%s %d files",galleryname,nfiles); // window title: gallery name and file count - gtk_window_set_title(GTK_WINDOW(wing),wintitle); - gdk_window_invalidate_rect(wing->window,0,1); // will cause re-entrance v.4.1 - if (fpresent) gtk_window_present(GTK_WINDOW(wing)); // bring window to top - zmainloop(); // v.4.7 - fpresent = 0; - return 0; - } - - rect = expose->area; // exposed area to refresh - expy1 = rect.y; - expy2 = expy1 + rect.height; - row1 = expy1 / thumbH; - row2 = expy2 / thumbH; - - ii = row1 * xcols; // 1st image file in top row - if (ii >= nfiles) return 1; - fileC = strdupz(flist[ii],0,"gallery_paint"); // next file to write to window - *fileC = '/'; // directories have ! instead of / +/**************************************************************************/ - for (row = row1; row <= row2; row++) // draw file thumbnails - for (col = 0; col < xcols; col++) - { - thumx = col * thumbW + xmargW; // upper left corner in window space - thumy = row * thumbH + xmargH; - - if (thumy < expy2 && thumy+14 > expy1) { // if in exposed area, - pp = (char *) strrchr(fileC,'/'); // draw file name - if (pp) fname = pp + 1; - else fname = fileC; - draw_text(layout,fname,thumx,thumy,thumbW); - } - - if (thumbsize) // zero >> list view v.3.7 - pxbT = image_thumbnail(fileC,thumbsize); // get thumbnail - else pxbT = 0; - - if (genthumbs == 1 && ! popup) { // inform user of delay v.4.0 - write_popup_text("open","please wait",200,10,wing); - write_popup_text("write","\n generating thumbnails"); // 1st pass gtk bug, no text //// - genthumbs = 2; - popup = 1; - } +// Display a dialog with a message and 1-5 choice buttons. +// Returns choice 1-N corresponding to button selected. +// Parent window may be NULL. +// List of buttons must be NULL terminated. - if (genthumbs < 5) zmainloop(); // mysterious, necessary //// - - if (pxbT) { - thumy = thumy + 16; // thumbnail 16 pixels down from text - orgx = 0; - orgy = 0; - ww = gdk_pixbuf_get_width(pxbT); - hh = gdk_pixbuf_get_height(pxbT); - - if (thumy < expy1) { - orgy = orgy + (expy1 - thumy); - hh = hh - (expy1 - thumy); - } - if (thumy + orgy + hh > expy2) - hh = hh - (thumy + orgy + hh - expy2); - - if (orgy >= 0 && hh > 0) - gdk_draw_pixbuf(GTK_LAYOUT(layout)->bin_window,0,pxbT, - orgx,orgy,thumx+orgx,thumy+orgy,ww,hh,NODITHER,0,0); - g_object_unref(pxbT); - } +int zdialog_choose(cchar *title, GtkWidget *parent, cchar *message, ...) // new v.4.7 +{ + zdialog *zd; + va_list arglist; + int ii, zstat, Nbutts; + cchar *butts[6]; + + va_start(arglist,message); - zfree(fileC); - fileC = 0; - if (++ii == nfiles) goto thumbsdone; - fileC = strdupz(flist[ii],0,"gallery_paint"); - *fileC = '/'; + for (ii = 0; ii < 5; ii++) + { + butts[ii] = va_arg(arglist,cchar *); + if (! butts[ii]) break; } -thumbsdone: + Nbutts = ii; + if (! Nbutts) zappcrash("zdialog_choose(), no buttons"); - if (fileC) zfree(fileC); // leak v.4.1 - if (popup) { - write_popup_text("close"); // v.4.0 - genthumbs = 0; - } +repeat: - return 1; + zd = zdialog_new(title,parent,butts[0],butts[1],butts[2],butts[3],butts[4],null); + zdialog_add_widget(zd,"hbox","hbmess","dialog","space=5"); + zdialog_add_widget(zd,"label","labmess","hbmess",message,"space=5"); + zdialog_run(zd); + zstat = zdialog_wait(zd); + zdialog_free(zd); + + if (zstat < 1) goto repeat; + return zstat; } -// private function -// write text for thumbnail limited by width of thumbnail +/**************************************************************************/ + +// File chooser dialog for one or more files +// +// Action: "open" select an existing file +// "openN" select multiple existing files +// "save" select an existing or new file +// "folder" select existing folder +// "create folder" select existing or new folder +// +// buttx: "hidden" add button to toggle display of hidden files +// "quality" add button to set JPG file save quality +// optional, default = null +// +// Returns a list of filespecs terminated with null. +// Memory for returned list and returned files are subjects for zfree(); + + +// version to select only 1 file -void image_navi::draw_text(GtkWidget *win, char *text, int x, int y, int ww) +char * zgetfile1(cchar *title, cchar *action, cchar *initfile, cchar *buttx) { - using namespace image_navi; - - static PangoFontDescription *pfont = 0; - static PangoLayout *playout = 0; - - int nn, ww2, hh2, cc; - char text2[100]; - static int thumbsize2 = 0; - static char thumbfont[12] = ""; - - if (thumbsize != thumbsize2) { // scale file name font to thumbnail size - thumbsize2 = thumbsize; // v.4.7 - nn = 7 + thumbsize / 128; // font size from 7 to 10 - if (thumbsize == 0) nn = 9; // list view, use 9 - sprintf(thumbfont,"sans %d",nn); - pfont = pango_font_description_from_string(thumbfont); - playout = gtk_widget_create_pango_layout(win,0); - pango_layout_set_font_description(playout,pfont); - } - - for (cc = 50; cc > 7; cc--) // allow up to 50 graphic chars. - { // and reduce until fits v.2.3 - cc = utf8substring(text2,text,0,cc); // get substring up to cc chars. - pango_layout_set_text(playout,text2,-1); // compute layout - pango_layout_get_pixel_size(playout,&ww2,&hh2); // pixel width of layout - if (ww2 < ww) break; // stop when it fits - } - - gdk_draw_layout(GTK_LAYOUT(win)->bin_window,gdkgc,x,y,playout); - return; + if (strEqu(action,"openN")) zappcrash("zgetfile1 called with openN"); + char **flist = zgetfileN(title,action,initfile,buttx); + if (! flist) return 0; + char *file = *flist; + zfree(flist); + return file; } -// private function -// gallery window destroy event - track if window is active or not +// select one or multiple files // overhauled -void image_navi::gallery_destroy() +char ** zgetfileN(cchar *title, cchar *action, cchar *initfile, cchar *buttx) { - using namespace image_navi; - - wing = 0; // no window - if (userfunc) userfunc(-1,0); // tell caller - return; -} - + using namespace zfuncs; -// private function - menu function for gallery window -// - scroll window as requested -// - jump to new file or folder as requested + void zgetfile_preview(GtkWidget *dialog, GtkWidget *pvwidget); // private functions + void zgetfile_KBkey(GtkWidget *dialog, GdkEventKey *event); + void zgetfile_newfolder(GtkFileChooser *dialog, void *); -void image_navi::menufuncx(GtkWidget *win, cchar *menu) -{ - using namespace image_navi; + GtkFileChooserAction fcact = GTK_FILE_CHOOSER_ACTION_OPEN; - int ii, scrollp; - char *filex, *filez, *pp; - char buff[maxfcc]; + GtkWidget *dialog; + GtkWidget *pvwidget = gtk_image_new(); + GSList *gslist = 0; + cchar *button1 = 0, *buttxx = 0; + char *pdir, *pfile; + int ii, err, NF, setfname = 0; + int fcstat, bcode = 0, qnum, hide = 0; + char *qual, *file1, *file2, **flist = 0; + struct stat fstat; - if (strEqu(menu,ZTX("close"))) { // close image gallery window - gtk_widget_destroy(wing); // destroy event function calls userfunc(-1) - return; - } + zthreadcrash(); // thread usage not allowed - if (strEqu(menu,ZTX("bigger"))) { // next bigger thumbnail size - for (ii = 0; ii < thumbxx; ii++) - if (thumbsize == thumbx[ii]) break; - if (ii == 0) return; - thumbsize = thumbx[ii-1]; - targposn = scrollposn / thumbH * xcols; // keep top row position v.4.1 - gallery_paint(0,0); - return; + if (strEqu(action,"open")) { + fcact = GTK_FILE_CHOOSER_ACTION_OPEN; + button1 = ZTX("open"); } - if (strEqu(menu,ZTX("smaller"))) { // next smaller - for (ii = 0; ii < thumbxx; ii++) - if (thumbsize == thumbx[ii]) break; - if (ii >= thumbxx-1) thumbsize = 0; // no thumbs, list view v.3.7 - else thumbsize = thumbx[ii+1]; - targposn = scrollposn / thumbH * xcols; // keep top row position v.4.1 - gallery_paint(0,0); - return; + if (strEqu(action,"openN")) { + fcact = GTK_FILE_CHOOSER_ACTION_OPEN; + button1 = ZTX("choose"); } - if (strEqu(menu,ZTX("open"))) { // go to a specific file - if (nfiles) { - filez = strdupz(flist[0],0,"image_navi"); - *filez = '/'; - } - else filez = 0; - filex = zgetfile1(ZTX("select new file"),"folder",filez); // file chooser dialog v.4.7 - if (filez) zfree(filez); - if (filex) { - image_navigate(filex,"init"); // get new file list - targposn = image_gallery_position(filex,0); // initial window scroll target - gallery_paint(0,0); - zfree(filex); - } - return; + if (strEqu(action,"save")) { + fcact = GTK_FILE_CHOOSER_ACTION_SAVE; + button1 = ZTX("save"); + setfname = 1; } - scrollp = scrollposn; // v.3.7 - - if (strEqu(menu,ZTX("parent"))) { // go up to '/' and stop v.4.7 - if (galleryname && gallerytype == 1) - filez = strdupz(galleryname); - else filez = strdupz(getcwd(buff,maxfcc-1),0,"image_navi"); - *filez = '/'; - pp = strrchr(filez,'/'); - if (pp > filez) *pp = 0; - else strcpy(filez,"/"); - image_navigate(filez,"init"); // get new file list - gallery_paint(0,0); - zfree(filez); - scrollp = 0; // v.3.7 - } - - if (strEqu(menu,ZTX("prev row"))) scrollp -= thumbH; - if (strEqu(menu,ZTX("next row"))) scrollp += thumbH; - if (strEqu(menu,ZTX("prev page"))) scrollp -= thumbH * xrows; - if (strEqu(menu,ZTX("next page"))) scrollp += thumbH * xrows; - if (strEqu(menu,ZTX("first page"))) scrollp = 0; - if (strEqu(menu,ZTX("last page"))) scrollp = maxscroll; - - if (scrollp < 0) scrollp = 0; // enforce limits - if (scrollp > maxscroll) scrollp = maxscroll; - scrollp = scrollp / thumbH * thumbH; // align top row - - if (scrollp != scrollposn) - gtk_adjustment_set_value(scrollbar,scrollp); - - return; -} - - -// private function -// mouse event function for gallery window - get selected thumbnail and file -// user function receives clicked file, which is subject for zfree() - -void image_navi::mouse_xevent(GtkWidget *, GdkEventButton *event, void *) -{ - using namespace image_navi; + if (strEqu(action,"folder")) { + fcact = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER; + button1 = ZTX("open folder"); + } - int mousex, mousey, mousebutt; - int row, col, nrows, ii, err; - char *filez; - struct stat statb; + if (strEqu(action,"create folder")) { + fcact = GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER; + button1 = ZTX("create folder"); + setfname = 1; + } - if (! nfiles) return; // empty window + if (buttx) { + if (strnEqu(buttx,"hidden",6)) { // generate text for translation + buttxx = ZTX("hidden"); // bugfix v.4.4 + bcode = 103; + } + if (strEqu(buttx,"quality")) { + buttxx = ZTX("quality"); + bcode = 104; + } + } - mousex = int(event->x); - mousey = int(event->y); - mousebutt = event->button; // v.4.7 + dialog = gtk_file_chooser_dialog_new(title, null, fcact, // create file selection dialog + button1, GTK_RESPONSE_ACCEPT, + ZTX("cancel"), GTK_RESPONSE_CANCEL, + buttxx, bcode, null); - row = (mousey - xmargH) / thumbH; // find selected row, col - col = (mousex - xmargW) / thumbW; + gtk_file_chooser_set_preview_widget(GTK_FILE_CHOOSER(dialog),pvwidget); - nrows = 1 + (nfiles-1) / xcols; // total thumbnail rows, 1 or more - if (col < 0 || col >= xcols) return; - if (row < 0 || row >= nrows) return; + G_SIGNAL(dialog,"update-preview",zgetfile_preview,pvwidget); // create preview for selected file + G_SIGNAL(dialog,"key-release-event",zgetfile_KBkey,0); // respond to F1 help key + + gtk_window_set_position(GTK_WINDOW(dialog),GTK_WIN_POS_MOUSE); // put dialog at mouse position + gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(dialog),0); // default: no show hidden - ii = xcols * row + col; - if (ii >= nfiles) return; + if (strEqu(action,"save")) // overwrite confirmation + gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog),1); - filez = strdupz(flist[ii],0,"image_navi"); // selected file - *filez = '/'; - - err = stat(filez,&statb); - if (err) { // file is gone? - zfree(filez); - return; - } + if (strEqu(action,"openN")) + gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog),1); // select multiple files - if (S_ISDIR(statb.st_mode)) { // if directory, go there - image_navigate(filez,"init"); - gallery_paint(0,0); - zfree(filez); - return; + if (initfile) { // pre-select filespec + err = stat(initfile,&fstat); + if (err) { + pdir = strdupz(initfile); // non-existent file + pfile = strrchr(pdir,'/'); + if (pfile && pfile > pdir) { + *pfile++ = 0; // set folder name + gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog),pdir); + } + if (setfname) // set new file name v.4.7 + gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog),pfile); + zfree(pdir); + } + else if (S_ISREG(fstat.st_mode)) // select given file + gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog),initfile); + else if (S_ISDIR(fstat.st_mode)) // select given folder + gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog),initfile); } - - if (userfunc) userfunc(ii,mousebutt); // clicked file position to user - return; -} + gtk_widget_show_all(dialog); -// private function -// KB event function - respond to keyboard navigation keys -// key definitions: /usr/include/gtk-2.0/gdk/gdkkeysyms.h + while (true) + { + fcstat = gtk_dialog_run(GTK_DIALOG(dialog)); // run dialog, get status button -int image_navi::KBxpress(GtkWidget *win, GdkEventKey *event, void *) // prevent propagation of key-press -{ // events to toolbar buttons v.2.9 - return 1; -} + if (fcstat == 103) { // show/hide hidden files + hide = gtk_file_chooser_get_show_hidden(GTK_FILE_CHOOSER(dialog)); + hide = 1 - hide; + gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(dialog),hide); + } -int image_navi::KBxrelease(GtkWidget *win, GdkEventKey *event, void *) -{ - using namespace image_navi; + else if (fcstat == 104) { // get JPG quality parameter + while (true) { + qual = zdialog_text(null,ZTX("JPG quality 0-100"),JPGquality); + if (! qual) break; // cancel = no change + err = convSI(qual,qnum,0,100); + zfree(qual); + if (err) continue; // enforce 0-100 + snprintf(JPGquality,4,"%d",qnum); + break; + } + } - int KBkey; - - KBkey = event->keyval; + else break; // some other button + } - if (KBkey == GDK_plus) menufuncx(win,ZTX("bigger")); // +/- = bigger/smaller thumbnails - if (KBkey == GDK_equal) menufuncx(win,ZTX("bigger")); - if (KBkey == GDK_minus) menufuncx(win,ZTX("smaller")); - if (KBkey == GDK_KP_Add) menufuncx(win,ZTX("bigger")); // keypad +/- also v.2.24 - if (KBkey == GDK_KP_Subtract) menufuncx(win,ZTX("smaller")); + if (fcstat == GTK_RESPONSE_ACCEPT) + { + gslist = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog)); + if (! gslist) goto fcreturn; + NF = g_slist_length(gslist); // no. selected files + if (! NF) goto fcreturn; - if (KBkey == GDK_Left) menufuncx(win,ZTX("prev page")); // left arrow = previous page - if (KBkey == GDK_Right) menufuncx(win,ZTX("next page")); // right arrow = next page - if (KBkey == GDK_Up) menufuncx(win,ZTX("prev row")); // up arrow = previous row - if (KBkey == GDK_Down) menufuncx(win,ZTX("next row")); // down arrow = next row - - if (KBkey == GDK_Home) menufuncx(win,ZTX("first page")); // keys added v.2.26 - if (KBkey == GDK_End) menufuncx(win,ZTX("last page")); - if (KBkey == GDK_Page_Up) menufuncx(win,ZTX("prev page")); - if (KBkey == GDK_Page_Down) menufuncx(win,ZTX("next page")); + flist = (char **) zmalloc((NF+1)*sizeof(char *),"zgetfile"); // allocate returned list + + for (ii = 0; ii < NF; ii++) + { // process selected files + file1 = (char *) g_slist_nth_data(gslist,ii); + if (strlen(file1) >= maxfcc) + file1 = (char *) "ridiculously long filespec"; + file2 = strdupz(file1,0,"zgetfile"); // re-allocate memory + g_free(file1); + flist[ii] = file2; + } + flist[ii] = 0; // EOL marker + } - if (KBkey == GDK_Escape) gtk_widget_destroy(win); // Escape = cancel gallery window - - if (KBkey == GDK_F1) - showz_userguide(zfuncs::F1_help_topic); // F1 help request v.4.1 - - return 1; +fcreturn: + if (gslist) g_slist_free(gslist); + gtk_widget_destroy(dialog); + return flist; } -// Public function - get file position in file list. -// If Nth position matches file, this is returned. -// Otherwise the file is searched from position 0. -// Position 0-last is returned if found, or -1 if not. +// zgetfile private function - get preview images for image files -int image_gallery_position(cchar *file, int Nth) // new v.4.1 +void zgetfile_preview(GtkWidget *dialog, GtkWidget *pvwidget) { - using namespace image_navi; - - int ii; - - if (! nfiles) return -1; - - if (Nth >= 0 && Nth < nfiles) ii = Nth; - else ii = 0; - - if (strEqu(file+1,flist[ii]+1)) return ii; // 1st flist[ii] char. may be ! - - for (ii = 0; ii < nfiles; ii++) - if (strEqu(file+1,flist[ii]+1)) break; - - if (ii < nfiles) return ii; - return -1; -} - + using namespace zfuncs; -// public function -// determine if a file is a directory or a supported image file type -// return: 0 = error, 1 = directory, 2 = image file, 3 = other + GdkPixbuf *thumbnail; + char *filename; -int image_file_type(cchar *file) -{ - using namespace image_navi; + filename = gtk_file_chooser_get_preview_filename(GTK_FILE_CHOOSER(dialog)); - int err, cc; - cchar *pp; - struct stat statbuf; + if (! filename) { + gtk_file_chooser_set_preview_widget_active(GTK_FILE_CHOOSER(dialog),0); + return; + } - if (! file) return 0; - err = stat(file,&statbuf); - if (err) return 0; + thumbnail = get_thumbnail(filename,192); // use 192x192 pixels + g_free(filename); - if (S_ISDIR(statbuf.st_mode)) { // directory - cc = strlen(file); - if (cc > 12) { - pp = file + cc - 12; - if (strEqu(pp,"/.thumbnails")) return 3; // .thumbnails - } - return 1; + if (thumbnail) { + gtk_image_set_from_pixbuf(GTK_IMAGE(pvwidget),thumbnail); + gtk_file_chooser_set_preview_widget_active(GTK_FILE_CHOOSER(dialog),1); + g_object_unref(thumbnail); } + else gtk_file_chooser_set_preview_widget_active(GTK_FILE_CHOOSER(dialog),0); - if (S_ISREG(statbuf.st_mode)) { // reg. file - pp = strrchr(file,'.'); - if (! pp) return 3; - pp = strcasestr(imagetypes,pp); // supported image type - if (pp) return 2; - } - - return 3; + return; } -// Public function -// Get thumbnail filespec for the given image file. -// If missing or stale, add or update in /.thumbnails directory. -// Returned filespec is subject for zfree(). -// Use 4 threads to build missing thumbnails asynchrounously // v.4.4 -// (and hopefully ahead of need). +// zgetfile private function - respond to F1 key +// zfuncs::F1_help_topic must be pre-loaded by caller if needed. -namespace image_thumbs +void zgetfile_KBkey(GtkWidget *dialog, GdkEventKey *event) { - char * image_thumbfile_1x(char *imagefile); - void * image_thumbfile_thread(void *arg); - int image_thumbfile_lock(char *imagefile, int lock); - cchar *toomanyfiles = "exceed %d files in one directory"; - char *imagefilex; - char *thumbfilex; - char *directoryx; - char **filelistx; - int Nfilesx; - int indexx; - int busythreads; - int stopthreads; - char *lockfiles[5]; - mutex filelock = PTHREAD_MUTEX_INITIALIZER; - mutex thumblock = PTHREAD_MUTEX_INITIALIZER; + int KBkey = event->keyval; + if (KBkey == GDK_F1) + showz_userguide(zfuncs::F1_help_topic); + return; } -char * image_thumbfile(char *imagefile) -{ - using namespace image_thumbs; +/************************************************************************** - char *thumbfile, *directory; - char *pfile, *bfile, *buff; - cchar *findcommand = "find \"%s\" -maxdepth 1"; - struct stat statf, statb; - int err, ftyp, contx = 0; + Programs for printing an image file new v.4.7 - zthreadcrash(); // thread usage not allowed + HPLIP problem: Setting paper size was made less flexible. + GtkPrintSettings paper size must agree with the one in the current + printer setup. This can only be set in the printer setup dialog, not + in the application. Also the print size (width, height) comes from + the chosen paper size and cannot be changed in the application. + Print margins can be changed to effect printing a smaller or shifted + image on a larger paper size. - err = stat(imagefile,&statf); - if (err) return 0; - if (! S_ISREG(statf.st_mode)) return 0; // not a regular file - if (image_file_type(imagefile) != 2) return 0; // unsupported image type + + print_image_paper_setup() - pfile = strrchr(imagefile,'/'); // get .../filename.xxx - if (! pfile) return 0; - if (pfile > imagefile+12 && strnEqu(pfile-12,"/.thumbnails/",13)) { // .../.thumbnails/filename.xxx ?? - thumbfile = strdupz(imagefile,0,"image_thumbfile"); // yes, a thumbnail file - return thumbfile; // return same file - } + Do a print paper format selection, after which the page width, height + and orientation are available to the caller. Units are CM. + (paper width and height are reversed for landscape orientation) - thumbfile = strdupz(imagefile,20,"image_thumbfile"); // construct thumbnail file - bfile = thumbfile + (pfile - imagefile); // .../.thumbnails/filename.xxx.png - strcpy(bfile,"/.thumbnails"); - bfile += 12; - strcpy(bfile,pfile); - strcat(bfile,".png"); - - err = stat(thumbfile,&statb); // thumbnail file exists ?? - if (! err) { // yes - if (statb.st_mtime >= statf.st_mtime) return thumbfile; // up to date, return it - zfree(thumbfile); - thumbfile = image_thumbfile_1x(imagefile); // refresh stale thumbnail - return thumbfile; // return it - } - - zfree(thumbfile); - - directory = strdupz(imagefile,0,"image_thumbfile"); // thumbnail does not exist - pfile = strrchr(directory,'/'); - pfile[1] = 0; // image directory/ - if (! directoryx) directoryx = directory; // first use - else if (strNeq(directoryx,directory)) { // new directory to search - stopthreads = 1; - while (busythreads) zsleep(0.001); // stop prior search if any - zfree(directoryx); - directoryx = directory; // directory for new search - } - else zfree(directory); // no change - - imagefilex = imagefile; // target thumbnail to get - - while (busythreads) { // if ongoing search, request thumbnail - if (! imagefilex) return thumbfilex; // from existing search threads - zsleep(0.001); // (this can fail rarely) - } - - if (filelistx) // set up empty file list - for (int ii = 0; ii < Nfilesx; ii++) zfree(filelistx[ii]); - else - filelistx = (char **) zmalloc(maxFiles * sizeof(char *),"image_thumbfile"); - Nfilesx = 0; - - while ((buff = command_output(contx,findcommand,directoryx))) // search image file directory - { - if (Nfilesx == maxFiles) { // no room - zmessageACK(0,toomanyfiles,maxFiles); - break; - } - - ftyp = image_file_type(buff); - if (ftyp == 2) { // supported image file type - filelistx[Nfilesx] = buff; // add to file list - Nfilesx++; - } - else zfree(buff); - } + print_image_margins_setup() + + Optionally set the print margins. If not done they are zero + (or printer-dependent minimum). Afterwards the margins are + available to the caller. Units are CM. - busythreads = 4; // start search threads for this directory - stopthreads = 0; - indexx = -1; - for (int ii = 0; ii < 4; ii++) - start_detached_thread(image_thumbfile_thread,0); + print_image_file(cchar *imagefile) - while (busythreads) { // return as soon as target thumbnail - if (! imagefilex) return thumbfilex; // has been generated - zsleep(0.001); - } - - if (! imagefilex) return thumbfilex; - printf("image_thumbfile failed %s \n",imagefile); // failure - return 0; -} + Print the image file on the printer and paper size determined by + a prior call to print_image_paper_setup. -// private function -// four threads each processing 1/4 of the entries in filelistx +***************************************************************************/ -void * image_thumbs::image_thumbfile_thread(void *arg) +namespace print_image { - using namespace image_thumbs; - - int ii; - char *thumbfile; - - while (indexx < Nfilesx) - { - if (imagefilex) { // if thumbnail request is waiting - mutex_lock(&thumblock); // take care of it first - if (imagefilex) - thumbfilex = image_thumbfile_1x(imagefilex); - imagefilex = 0; - mutex_unlock(&thumblock); - } - - if (stopthreads) break; // stop before done - - ii = zadd_locked(indexx,+1); // get next file from list - if (ii >= Nfilesx) break; - - thumbfile = image_thumbfile_1x(filelistx[ii]); // make thumbnail file if needed - if (thumbfile) zfree(thumbfile); - } + #define MM GTK_UNIT_MM + #define PRINTOP GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG + #define PORTRAIT GTK_PAGE_ORIENTATION_PORTRAIT + #define LANDSCAPE GTK_PAGE_ORIENTATION_LANDSCAPE + #define QUALITY GTK_PRINT_QUALITY_HIGH - zadd_locked(busythreads,-1); // decrement busy count - pthread_exit(0); // "return" cannot be used here + GtkPageSetup *priorpagesetup = 0; + GtkPageSetup *pagesetup; + GtkPrintSettings *printsettings = 0; + GtkPrintOperation *printop; + GtkPageOrientation orientation = PORTRAIT; + GdkPixbuf *pixbuf; + cchar *printer = 0; + double width = 21.0, height = 29.7; // paper size, CM (default A4 portrait) + double margins[4] = { 0, 0, 0, 0 }; // print margins, CM (default none) + int landscape = 0; // true if landscape } -// Private function to create a single thumbnail file. -// Get thumbnail file for the given image file. -// If missing or stale, add or update in /.thumbnails directory. -// Returned filespec is subject for zfree(). - -char * image_thumbs::image_thumbfile_1x(char *imagefile) +void print_image_paper_setup(GtkWidget *parent) { - using namespace image_thumbs; - - GdkPixbuf *thumbpxb; - GError *gerror = 0; - char *pfile, *bfile, *thumbfile; - int err, sizew, sizeh; - struct stat statf, statb; + using namespace print_image; - err = stat(imagefile,&statf); - if (err) return 0; - if (! S_ISREG(statf.st_mode)) return 0; // not a regular file - if (image_file_type(imagefile) != 2) return 0; // unsupported image type + char printsettingsfile[200], pagesetupfile[200]; - pfile = strrchr(imagefile,'/'); // get .../filename.xxx - if (! pfile) return 0; - if (pfile > imagefile+12 && strnEqu(pfile-12,"/.thumbnails/",13)) { // .../.thumbnails/filename.xxx ?? - thumbfile = strdupz(imagefile,0,"image_thumbfile"); // yes, a thumbnail file - return thumbfile; // return same file - } - - thumbfile = strdupz(imagefile,20,"image_thumbfile"); // construct thumbnail file - bfile = thumbfile + (pfile - imagefile); // .../.thumbnails/filename.xxx.png - strcpy(bfile,"/.thumbnails"); - bfile += 12; - strcpy(bfile,pfile); - strcat(bfile,".png"); - - while (! image_thumbfile_lock(imagefile,1)) zsleep(0.001); // lock file for me - - err = stat(thumbfile,&statb); // thumbnail file exists ?? - if (err || (statb.st_mtime < statf.st_mtime)) - { // does not exist or stale - *bfile = 0; - err = stat(thumbfile,&statb); - if (err) err = mkdir(thumbfile,0751); // create .thumbnails directory - if (err) { - image_thumbfile_lock(imagefile,0); - return 0; - } - *bfile = *pfile; - sizew = sizeh = image_navi::thumbfilesize; // create thumbnail pixbuf - thumbpxb = gdk_pixbuf_new_from_file_at_size(imagefile,sizew,sizeh,&gerror); - if (! thumbpxb) { - printf("gdk_pixbuf_new error: %s \n",gerror->message); // diagnose error v.3.3 - image_thumbfile_lock(imagefile,0); - return 0; - } - gdk_pixbuf_save(thumbpxb,thumbfile,"png",&gerror,null); // save in /.thumbnails/ directory - g_object_unref(thumbpxb); - image_navi::genthumbs++; // count generated thumbnails + snprintf(printsettingsfile,200,"%s/printsettings",get_zuserdir()); + snprintf(pagesetupfile,200,"%s/pagesetup",get_zuserdir()); + + if (! printsettings) { // start with prior print settings + printsettings = gtk_print_settings_new_from_file(printsettingsfile,0); + if (! printsettings) + printsettings = gtk_print_settings_new(); } - image_thumbfile_lock(imagefile,0); // return thumbfile - return thumbfile; -} - - -// prevent interference from multiple threads working on the same image file + if (! priorpagesetup) { // start with prior page setup + priorpagesetup = gtk_page_setup_new_from_file(pagesetupfile,0); + if (! priorpagesetup) + priorpagesetup = gtk_page_setup_new(); + } -int image_thumbs::image_thumbfile_lock(char *imagefile, int lock) -{ - using namespace image_thumbs; + pagesetup = gtk_print_run_page_setup_dialog // select printer, paper size + (GTK_WINDOW(parent),priorpagesetup,printsettings); // and orientation + if (! pagesetup) return; - int ii, jj = -1; + g_object_unref(priorpagesetup); // save for next call + priorpagesetup = pagesetup; - mutex_lock(&filelock); // v.4.7 always lock - - if (lock) // lock file if possible - { - for (ii = 0; ii < 5; ii++) { - if (! lockfiles[ii]) jj = ii; // remember 1st empty slot - else if (strEqu(lockfiles[ii],imagefile)) { - mutex_unlock(&filelock); // file is already locked - return 0; - } - } + width = gtk_page_setup_get_paper_width(pagesetup,MM); // save paper width, height + height = gtk_page_setup_get_paper_height(pagesetup,MM); + width = width / 10; // use cm units + height = height / 10; + + orientation = gtk_print_settings_get_orientation(printsettings); // save orientation + if (orientation == LANDSCAPE) landscape = 1; + else landscape = 0; - if (jj < 0) zappcrash("image_thumbfile_lock > 5"); - lockfiles[jj] = imagefile; // lock the file - mutex_unlock(&filelock); - return 1; - } + gtk_print_settings_set_quality(printsettings,QUALITY); // set high quality 300 dpi + gtk_print_settings_set_resolution(printsettings,300); + + gtk_print_settings_to_file(printsettings,printsettingsfile,0); // save print settings to file + gtk_page_setup_to_file(pagesetup,pagesetupfile,0); // save print settings to file - else // unlock file - { - for (ii = 0; ii < 5; ii++) { - if (! lockfiles[ii]) continue; - if (strEqu(lockfiles[ii],imagefile)) { - lockfiles[ii] = 0; - mutex_unlock(&filelock); - return 1; - } - } - zappcrash("image_thumbfile_lock gone"); - return 0; - } + return; } -// Public function -// Get thumbnail image for given image file, from .thumbnails directory. -// Add thumbnail file if missing, or update it if older than image file. -// Returned thumbnail belongs to caller: g_object_unref() is necessary. - -GdkPixbuf * image_thumbnail(char *fpath, int size) +void print_image_margins_setup(GtkWidget *parent) { - using namespace zfuncs; - using namespace image_navi; + using namespace print_image; + + zdialog *zd; + int zstat; - GdkPixbuf *thumbpxb; - GError *gerror = 0; - int ii, err; - char *bpath; - time_t mtime; - struct stat statf; - const int cachesize = thumbnail_cachesize; // shorthand v.3.7 + zd = zdialog_new(ZTX("margins"),parent,ZTX("done"),ZTX("cancel"),0); // build dialog - static int nextcache, ftf = 1; - static int sizecache[cachesize]; - static time_t mtimecache[cachesize]; - static char *fpathcache[cachesize]; - static GdkPixbuf *pixbufcache[cachesize]; - - zthreadcrash(); // thread usage not allowed v.3.9 - - if (ftf) { // first call v.3.7 - for (ii = 0; ii < cachesize; ii++) - fpathcache[ii] = 0; // clear cache - ftf = 0; - } + zdialog_add_widget(zd,"hbox","hbmlab","dialog",0,"homog"); // top bottom left right + zdialog_add_widget(zd,"vbox","vbmarg","hbmlab",0,"space=3"); // margins [___] [___] [___] [___] + zdialog_add_widget(zd,"vbox","vbtop","hbmlab",0,"space=3"); + zdialog_add_widget(zd,"vbox","vbbottom","hbmlab",0,"space=3"); + zdialog_add_widget(zd,"vbox","vbleft","hbmlab",0,"space=3"); + zdialog_add_widget(zd,"vbox","vbright","hbmlab",0,"space=3"); + zdialog_add_widget(zd,"label","space","vbmarg"," "); + zdialog_add_widget(zd,"label","labtop","vbtop",ZTX("top")); + zdialog_add_widget(zd,"label","labbot","vbbottom",ZTX("bottom")); + zdialog_add_widget(zd,"label","lableft","vbleft",ZTX("left")); + zdialog_add_widget(zd,"label","labright","vbright",ZTX("right")); + zdialog_add_widget(zd,"label","labmarg","vbmarg",ZTX("margins"),"space=3"); + zdialog_add_widget(zd,"spin","mtop","vbtop","0|3|0.1|0"); + zdialog_add_widget(zd,"spin","mbottom","vbbottom","0|3|0.1|0"); + zdialog_add_widget(zd,"spin","mleft","vbleft","0|3|0.1|0"); + zdialog_add_widget(zd,"spin","mright","vbright","0|3|0.1|0"); - err = stat(fpath,&statf); // fpath status info - if (err) return 0; + zdialog_stuff(zd,"mtop",margins[0]); // stuff prior print margins + zdialog_stuff(zd,"mbottom",margins[1]); + zdialog_stuff(zd,"mleft",margins[2]); + zdialog_stuff(zd,"mright",margins[3]); - if (S_ISDIR(statf.st_mode)) { // if directory, return folder image - bpath = zmalloc(500); - strncatv(bpath,499,zicondir,"/folder256.png",null); - thumbpxb = gdk_pixbuf_new_from_file_at_size(bpath,size,size,&gerror); - zfree(bpath); - return thumbpxb; - } - - mtime = statf.st_mtime; // last modification time - - if (! size) size = thumbfilesize; // default thumb size - - for (ii = nextcache; ii >= 0; ii--) // get cached pixbuf if found v.3.7 - if (fpathcache[ii] && strEqu(fpath,fpathcache[ii]) && - sizecache[ii] == size && mtime == mtimecache[ii]) break; // check mtime (bugfix) v.3.9 - if (ii >= 0) { - thumbpxb = gdk_pixbuf_copy(pixbufcache[ii]); - return thumbpxb; - } - for (ii = cachesize-1; ii > nextcache; ii--) // continue search - if (fpathcache[ii] && strEqu(fpath,fpathcache[ii]) && - sizecache[ii] == size && mtime == mtimecache[ii]) break; - if (ii > nextcache) { - thumbpxb = gdk_pixbuf_copy(pixbufcache[ii]); - return thumbpxb; + zdialog_run(zd); // run dialog + zstat = zdialog_wait(zd); // wait for completion + + if (zstat != 1) { // user canceled + zdialog_free(zd); + return; } - if (size > thumbfilesize) { // support huge thumbnails v.3.6 - thumbpxb = gdk_pixbuf_new_from_file_at_size(fpath,size,size,&gerror); - goto addcache; - } - - bpath = image_thumbfile(fpath); // get thumbnail file - if (! bpath) return 0; - thumbpxb = gdk_pixbuf_new_from_file_at_size(bpath,size,size,&gerror); // get thumbnail - zfree(bpath); - goto addcache; - -addcache: - nextcache++; // next cache slot (oldest) v.3.7 - if (nextcache == cachesize) nextcache = 0; - ii = nextcache; - if (fpathcache[ii]) { // free prior occupant - zfree(fpathcache[ii]); - g_object_unref(pixbufcache[ii]); - } - fpathcache[ii] = strdupz(fpath,0,"thumbnail_cache"); // add new occupant - pixbufcache[ii] = gdk_pixbuf_copy(thumbpxb); // this memory is not tracked - sizecache[ii] = size; - mtimecache[ii] = mtime; // v.3.9 - - return thumbpxb; // return pixbuf to caller -} + zdialog_fetch(zd,"mtop",margins[0]); // set print margins + zdialog_fetch(zd,"mbottom",margins[1]); + zdialog_fetch(zd,"mleft",margins[2]); + zdialog_fetch(zd,"mright",margins[3]); + zdialog_free(zd); // kill dialog -/************************************************************************** + gtk_page_setup_set_top_margin(pagesetup,10*margins[0],MM); // set page margins, mm units + gtk_page_setup_set_bottom_margin(pagesetup,10*margins[1],MM); + gtk_page_setup_set_left_margin(pagesetup,10*margins[2],MM); + gtk_page_setup_set_right_margin(pagesetup,10*margins[3],MM); + + return; +} - private function - manage list of image files within a directory // overhauled v.4.1 - get an image file in the same directory as given file or directory +void print_image_file(cchar *imagefile) +{ + using namespace print_image; - char * image_navi::image_navigate(cchar *filez, cchar *action, int Nth) + void print_image_page(GtkPrintOperation *, GtkPrintContext *, int page); - action: init: file list = directories and image files in directory filez - initF: file list = filez = list of image files to use (cchar **) - sort: sort the file list, directories first, ignore case - insert: insert filez into file list at position Nth (0 to last+1) - delete: delete Nth file in list - find: returns Nth file (0 base) or null if Nth > last + GtkPrintOperationResult printstat; + GError *gerror = 0; - Nth: file to return for action = find + pixbuf = gdk_pixbuf_new_from_file(imagefile,&gerror); // read image file + if (! pixbuf) { + zmessageACK(null,gerror->message); + return; + } - Returned values: - find: filespec, else null - The returned file belongs to caller and is subject for zfree(). - -***************************************************************************/ - -char * image_navi::image_navigate(cchar *filez, cchar *action, int Nth) -{ - using namespace image_navi; - - char *buff; - cchar *findcommand = "find \"%s\" -maxdepth 1"; - char *pp, *file2; - int err, ii, ftyp, contx = 0, fposn; - FILE *fid; - struct stat statbuf; + printop = gtk_print_operation_new(); // print operation + gtk_print_operation_set_default_page_setup(printop,pagesetup); + gtk_print_operation_set_print_settings(printop,printsettings); + gtk_print_operation_set_n_pages(printop,1); - if (! strstr("init initF sort insert delete find",action)) - zappcrash("image_navigate %s",action); + g_signal_connect(printop,"draw-page",G_CALLBACK(print_image_page),0); // start print + printstat = gtk_print_operation_run(printop,PRINTOP,0,0); - if (strnEqu(action,"init",4)) { // init or initF - if (flist) - for (int ii = 0; ii < nfiles; ii++) zfree(flist[ii]); // free prior list memory - if (flist) zfree(flist); - flist = (char **) zmalloc(maxFiles * sizeof(char *),"image_navi"); // list of file pointers - nfiles = nimages = 0; // no files - fposn = 0; + if (printstat == GTK_PRINT_OPERATION_RESULT_ERROR) { + gtk_print_operation_get_error(printop,&gerror); + zmessageACK(null,gerror->message); } - if (strEqu(action,"init")) // initialize from given directory - { - if (! filez) return 0; // should not happen + g_object_unref(printop); + return; +} - galleryname = strdupz(filez,0,"image_navi"); - gallerytype = 1; // gallery type = directory - err = stat(galleryname,&statbuf); - if (err) { - pp = (char *) strrchr(galleryname,'/'); // bad file, check directory part - if (! pp) return 0; - pp[1] = 0; - err = stat(galleryname,&statbuf); - if (err) return 0; // give up, empty file list - } +// draw the graphics for the print page +// rescale with cairo: print resolution of 300 dpi is no longer ignored - if (S_ISREG(statbuf.st_mode)) { // if a file, get directory part - pp = (char *) strrchr(galleryname,'/'); - if (! pp) return 0; - pp[1] = 0; - } +void print_image_page(GtkPrintOperation *printop, GtkPrintContext *printcontext, int page) +{ + using namespace print_image; - while ((buff = command_output(contx,findcommand,galleryname))) // find all files - { - if (strEqu(buff,galleryname)) { // skip self directory - zfree(buff); - continue; - } - - if (nfiles == maxFiles) { // message, not crash v.4.4 - zmessageACK(0,toomanyfiles,maxFiles); - break; - } + cairo_t *cairocontext; + double iww, ihh, pww, phh, scale; - ftyp = image_file_type(buff); + pww = gtk_print_context_get_width(printcontext); // print context size + phh = gtk_print_context_get_height(printcontext); - if (ftyp == 1) { // subdirectory - flist[nfiles] = buff; // add to file list - flist[nfiles][0] = '!'; // if directory, make it sort first - nfiles++; - } + iww = gdk_pixbuf_get_width(pixbuf); // image size + ihh = gdk_pixbuf_get_height(pixbuf); + + scale = pww / iww; // rescale to fit page + if (phh / ihh < scale) scale = phh / ihh; - else if (ftyp == 2) { // supported image file type - flist[nfiles] = buff; // add to file list - nfiles++; - nimages++; // v.4.1 - } + cairocontext = gtk_print_context_get_cairo_context(printcontext); // use cairo to rescale + cairo_translate(cairocontext,0,0); + cairo_scale(cairocontext,scale,scale); + gdk_cairo_set_source_pixbuf(cairocontext,pixbuf,0,0); + cairo_paint(cairocontext); - else { - zfree(buff); // (.thumbnails not ftyp 1) - continue; - } - } + return; +} - if (nfiles > 1) - HeapSort(flist,nfiles,image_fcomp); // Heap Sort - pointers to strings - return 0; - } +/**************************************************************************/ - if (strEqu(action,"initF")) // initialize from given list v.2.4 - { - galleryname = strdupz(filez,0,"image_navi"); - gallerytype = 2; // gallery type = file list v.4.1 - - fid = fopen(galleryname,"r"); // open file - if (! fid) return 0; +// connect a user callback function to a window drag-drop event - buff = zmalloc(maxfcc); - - while (true) // read list of files - { - if (nfiles == maxFiles) { - zmessageACK(0,toomanyfiles,maxFiles); - break; - } - pp = fgets_trim(buff,maxfcc-1,fid,1); - if (! pp) break; - err = stat(pp,&statbuf); // check file exists v.4.7 - if (err) continue; - flist[nfiles] = strdupz(buff,0,"image_navi"); // add files to memory list v.3.5 - nfiles++; - nimages++; - } +void drag_drop_connect(GtkWidget *window, drag_drop_func *ufunc) +{ + int drag_drop_connect2(GtkWidget *, void *, int, int, void *, int, int, void *); + char string[] = "STRING"; + GtkTargetEntry file_drop_target = { string, 0, 0 }; - fclose(fid); - zfree(buff); // sort removed v.3.9 - return 0; - } + gtk_drag_dest_set(window, GTK_DEST_DEFAULT_ALL, &file_drop_target, 1, GDK_ACTION_COPY); + G_SIGNAL(window, "drag-data-received", drag_drop_connect2, ufunc); + gtk_drag_dest_add_uri_targets(window); // accept URI (file) drop - if (strEqu(action,"sort")) // sort the list from initF v.3.9 - { - if (nfiles == 0) return 0; - HeapSort(flist,nfiles,image_fcomp); // Heap Sort - pointers to strings - return 0; - } + return; +} - if (strEqu(action,"insert")) // insert new file into list v.3.8 - { - fposn = Nth; // file position from caller - if (fposn < 0) fposn = 0; // limit to allowed range - if (fposn > nfiles) fposn = nfiles; - if (nfiles == maxFiles-1) { // no room - zmessageACK(0,toomanyfiles,maxFiles); - return 0; - } +// private function +// get dropped file, clean escapes, pass to user function +// passed filespec is subject for zfree() - for (ii = nfiles; ii > fposn; ii--) // create hole is list - flist[ii] = flist[ii-1]; +int drag_drop_connect2(GtkWidget *, void *, int mpx, int mpy, void *sdata, int, int, void *ufunc) +{ + char * drag_drop_unescape(cchar *escaped_string); + drag_drop_func *ufunc2; - flist[fposn] = strdupz(filez,0,"image_navi"); // put new file in hole - nfiles++; - } + char *text, *text2, *file, *file2; + int cc; + + text = (char *) ((GtkSelectionData *) sdata)->data; + ufunc2 = (drag_drop_func *) ufunc; - if (strEqu(action,"delete")) // delete file from list v.3.8 + if (strstr(text,"file://")) // text is a filespec { - fposn = Nth; // file position from caller must be OK - if (fposn < 0 || fposn > nfiles-1) return 0; - zfree(flist[fposn]); // remove file from list - nfiles--; - for (ii = fposn; ii < nfiles; ii++) { // close the hole - if (nfiles < 0) printf("meaningless reference %d",ii); // stop g++ optimization bug //// - flist[ii] = flist[ii+1]; - } + file = strdupz(text+7); // get rid of junk added by GTK + cc = strlen(file); + while (file[cc-1] < ' ') cc--; + file[cc] = 0; + file2 = drag_drop_unescape(file); // clean %xx escapes from Nautilus + zfree(file); + ufunc2(mpx,mpy,file2); // pass file to user function } - if (strEqu(action,"find")) + else { - fposn = Nth; // file position from caller must be OK - if (fposn < 0 || fposn > nfiles-1) return 0; - file2 = strdupz(flist[fposn],0,"image_navi"); // get Nth file - file2[0] = '/'; // restore initial '/' - err = stat(file2,&statbuf); - if (! err) return file2; - zfree(file2); + text2 = strdupz(text,0,"drag_drop"); + ufunc2(mpx,mpy,text2); } - return 0; + return 1; } -// private function for special file name compare -// directories sort first and upper/lower case is ignored +// private function +// Clean %xx escapes from strange Nautilus drag-drop file names -int image_navi::image_fcomp(cchar *file1, cchar *file2) +char * drag_drop_unescape(cchar *inp) { - int nn; - nn = strcasecmp(file1,file2); // compare ignoring case - if (nn != 0) return nn; - nn = strcmp(file1,file2); // if equal, do normal compare - return nn; + int drag_drop_convhex(char ch); + + char inch, *out, *outp; + int nib1, nib2; + + out = zmalloc(strlen(inp)+1,"drag_drop"); + outp = out; + + while ((inch = *inp++)) + { + if (inch == '%') + { + nib1 = drag_drop_convhex(*inp++); + nib2 = drag_drop_convhex(*inp++); + *outp++ = nib1 << 4 | nib2; + } + else *outp++ = inch; + } + + *outp = 0; + return out; } -/**************************************************************************/ +// private function - convert character 0-F to number 0-15 -// Select files from the image gallery window, return list of files selected. -// The dialog shows the list of files selected and can be edited. -// The returned file list belongs to caller and is subject for zfree(). -// The file list EOL is marked with null. -// The image_gallery() callback function is changed and must be restored by caller. +int drag_drop_convhex(char ch) +{ + if (ch >= '0' && ch <= '9') return ch - '0'; + if (ch >= 'A' && ch <= 'F') return ch - 'A' + 10; + if (ch >= 'a' && ch <= 'f') return ch - 'a' + 10; + return ch; +} -int imgl_showthumb(); -void imgl_insert_file(cchar *imagefile); -void imgl_gallery_file(int Nth, int button); -GtkWidget *imgl_drawarea = 0; -GtkWidget *imgl_files = 0; -cchar *imgl_font = "Monospace 8"; -zdialog *imgl_zd = 0; -int imgl_fontheight = 14; -int imgl_cursorpos = 0; +/************************************************************************** + Miscellaneous GDK/GTK functions +***************************************************************************/ +// Get thumbnail image for given image file. +// Returned thumbnail belongs to caller: g_object_unref() is necessary. -char ** image_gallery_getfiles(char *startdir, GtkWidget *parent) // new v.3.7 +GdkPixbuf * get_thumbnail(char *fpath, int size) // v.5.0 { - int imgl_dialog_event(zdialog *zd, cchar *event); - int imgl_mouseclick(GtkWidget *, GdkEventButton *event, void *); + using namespace zfuncs; - PangoLanguage *plang; - PangoFontDescription *pfontdesc; - PangoContext *pcontext; - PangoFont *pfont; - PangoFontMetrics *pmetrics; - GdkCursor *cursor; - GdkWindow *gdkwin; - GtkTextBuffer *textBuff; - GtkTextIter iter1, iter2; + GdkPixbuf *thumbpxb; + GError *gerror = 0; + int err; + char *bpath; + struct stat statf; - int fontascent, fontdescent; - int line, nlines, ii; - char *imagefile, **filelist; - - zthreadcrash(); // thread usage not allowed v.3.9 - - image_gallery(startdir,"paint1",0,imgl_gallery_file,parent); // activate image gallery window - - imgl_zd = zdialog_new(ZTX("Select Files"),0,ZTX("done"),ZTX("cancel"),null); - zdialog_add_widget(imgl_zd,"hbox","hb1","dialog",0,"expand|space=5"); - zdialog_add_widget(imgl_zd,"frame","fr11","hb1",0,"expand"); - zdialog_add_widget(imgl_zd,"scrwin","scrwin","fr11",0,"expand"); - zdialog_add_widget(imgl_zd,"edit","files","scrwin"); - zdialog_add_widget(imgl_zd,"vbox","vb12","hb1"); - zdialog_add_widget(imgl_zd,"frame","fr12","vb12"); - zdialog_add_widget(imgl_zd,"hbox","hb2","dialog",0,"space=5"); - zdialog_add_widget(imgl_zd,"button","delete","hb2",ZTX("delete"),"space=8"); - zdialog_add_widget(imgl_zd,"button","insert","hb2",ZTX("insert"),"space=8"); - zdialog_add_widget(imgl_zd,"button","addall","hb2",ZTX("add all"),"space=30"); - - GtkWidget *textbox = zdialog_widget(imgl_zd,"files"); // disable text wrap v.3.8 - gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(textbox),GTK_WRAP_NONE); - - GtkWidget *frame = zdialog_widget(imgl_zd,"fr12"); // drawing area for thumbnail image - imgl_drawarea = gtk_drawing_area_new(); - gtk_widget_set_size_request(imgl_drawarea,256,258); // increased v.3.9 - gtk_container_add(GTK_CONTAINER(frame),imgl_drawarea); - - imgl_files = zdialog_widget(imgl_zd,"files"); // activate mouse-clicks for - gtk_widget_add_events(imgl_files,GDK_BUTTON_PRESS_MASK); // file list widget - G_SIGNAL(imgl_files,"button-press-event",imgl_mouseclick,0) - - pfontdesc = pango_font_description_from_string(imgl_font); // set default font for files window - gtk_widget_modify_font(imgl_files,pfontdesc); - - plang = pango_language_get_default(); // get font metrics (what a mess) - pcontext = gtk_widget_get_pango_context(imgl_files); - pfont = pango_context_load_font(pcontext,pfontdesc); - pmetrics = pango_font_get_metrics(pfont,plang); - fontascent = pango_font_metrics_get_ascent(pmetrics) / PANGO_SCALE; - fontdescent = pango_font_metrics_get_descent(pmetrics) / PANGO_SCALE; - imgl_fontheight = fontascent + fontdescent; // effective line height - - zdialog_resize(imgl_zd,600,0); // start dialog - zdialog_run(imgl_zd,imgl_dialog_event); - - cursor = gdk_cursor_new(GDK_TOP_LEFT_ARROW); // arrow cursor for file list widget - gdkwin = gtk_text_view_get_window(GTK_TEXT_VIEW(imgl_files),TEXTWIN); // (must be done after window realized) - gdk_window_set_cursor(gdkwin,cursor); - imgl_cursorpos = 0; - - zdialog_wait(imgl_zd); // wait for completion - - if (imgl_zd->zstat != 1) { // cancelled - zdialog_free(imgl_zd); // kill dialog - image_gallery(0,"close"); // close image gallery window - return 0; - } + zthreadcrash(); // thread usage not allowed - textBuff = gtk_text_view_get_buffer(GTK_TEXT_VIEW(imgl_files)); - nlines = gtk_text_buffer_get_line_count(textBuff); - - filelist = (char **) zmalloc((nlines+1) * sizeof(char *),"imgl.getfiles"); + err = stat(fpath,&statf); // fpath status info + if (err) return 0; - for (ii = line = 0; line < nlines; line++) // get list of files from dialog - { - gtk_text_buffer_get_iter_at_line(textBuff,&iter1,line); // iter at line start - iter2 = iter1; - gtk_text_iter_forward_to_line_end(&iter2); - imagefile = gtk_text_buffer_get_text(textBuff,&iter1,&iter2,0); // get line of text - if (imagefile && *imagefile == '/') { - filelist[ii] = strdupz(imagefile,0,"imgl.getfiles"); // >> next file in list - free(imagefile); - ii++; - } + if (S_ISDIR(statf.st_mode)) { // if directory, return folder image + bpath = zmalloc(500); + strncatv(bpath,499,zicondir,"/folder256.png",null); + thumbpxb = gdk_pixbuf_new_from_file_at_size(bpath,size,size,&gerror); + zfree(bpath); + return thumbpxb; } - filelist[ii] = 0; // mark EOL - zdialog_free(imgl_zd); // kill dialog - image_gallery(0,"close"); // close image gallery window - - if (! ii) { - zfree(filelist); // file list is empty - return 0; - } - - return filelist; // return file list + thumbpxb = gdk_pixbuf_new_from_file_at_size(fpath,size,size,&gerror); + return thumbpxb; // return pixbuf to caller } -// imgl dialog event function +// make a cursor from a graphic file in application's icon directory -int imgl_dialog_event(zdialog *zd, cchar *event) +GdkCursor * zmakecursor(cchar *iconfile) { - GtkTextBuffer *textBuff; - GtkTextIter iter1, iter2; - char *ftemp; - static char *imagefile = 0; - int line, posn; - - if (strEqu(event,"delete")) // delete file at cursor position - { - if (imagefile) zfree(imagefile); - imagefile = 0; - - textBuff = gtk_text_view_get_buffer(GTK_TEXT_VIEW(imgl_files)); - line = imgl_cursorpos; - gtk_text_buffer_get_iter_at_line(textBuff,&iter1,line); // iter at line start - iter2 = iter1; - gtk_text_iter_forward_to_line_end(&iter2); // iter at line end - - ftemp = gtk_text_buffer_get_text(textBuff,&iter1,&iter2,0); // get selected file - if (! ftemp || *ftemp != '/') { - if (ftemp) free(ftemp); - return 0; - } + using namespace zfuncs; - imagefile = strdupz(ftemp,0,"imgl.getfiles"); // save deleted file for poss. insert - free(ftemp); - - gtk_text_buffer_delete(textBuff,&iter1,&iter2); // delete file text - gtk_text_buffer_get_iter_at_line(textBuff,&iter2,line+1); - gtk_text_buffer_delete(textBuff,&iter1,&iter2); // delete empty line (\n) + GError *gerror = 0; + GdkPixbuf *pixbuf; + GdkDisplay *display; + GdkCursor *cursor = 0; + char iconpath[200]; - imgl_showthumb(); // thumbnail = next file - } + zthreadcrash(); // thread usage not allowed - if (strEqu(event,"insert")) // insert last deleted file - { // at current cursor position - if (! imagefile) return 0; - imgl_insert_file(imagefile); - zfree(imagefile); - imagefile = 0; - } + display = gdk_display_get_default(); + *iconpath = 0; + strncatv(iconpath,199,zicondir,"/",iconfile,null); + pixbuf = gdk_pixbuf_new_from_file(iconpath,&gerror); + if (pixbuf && display) + cursor = gdk_cursor_new_from_pixbuf(display,pixbuf,0,0); + else printf("%s \n",gerror->message); + return cursor; +} - if (strEqu(event,"addall")) // insert all files in image gallery - { - textBuff = gtk_text_view_get_buffer(GTK_TEXT_VIEW(imgl_files)); - posn = 0; - while (true) - { - imagefile = image_gallery(0,"find",posn); // get first or next file - if (! imagefile) break; - posn++; - gtk_text_buffer_get_iter_at_line(textBuff,&iter1,imgl_cursorpos); - gtk_text_buffer_insert(textBuff,&iter1,"\n",1); // insert new blank line - gtk_text_buffer_get_iter_at_line(textBuff,&iter1,imgl_cursorpos); - gtk_text_buffer_insert(textBuff,&iter1,imagefile,-1); // insert image file - zfree(imagefile); - imgl_cursorpos++; // advance cursor position - } - } +// move the mouse pointer to given position - return 0; +int gdk_window_move_pointer(GdkWindow *window, int px, int py) // v.5.0 +{ + GdkDisplay *display; + GdkScreen *screen; + int rpx, rpy; + + display = gdk_drawable_get_display(GDK_DRAWABLE(window)); + if (! display) return 0; + screen = gdk_drawable_get_screen(GDK_DRAWABLE(window)); + if (! screen) return 0; + gdk_window_get_root_coords(window,px,py,&rpx,&rpy); + gdk_display_warp_pointer(display,screen,rpx,rpy); + return 1; } -// add image file to list at current cursor position, set thumbnail = file +/************************************************************************** -void imgl_insert_file(cchar *imagefile) -{ - GtkTextIter iter; - GtkTextBuffer *textBuff; - - textBuff = gtk_text_view_get_buffer(GTK_TEXT_VIEW(imgl_files)); - gtk_text_buffer_get_iter_at_line(textBuff,&iter,imgl_cursorpos); - gtk_text_buffer_insert(textBuff,&iter,"\n",1); // insert new blank line - gtk_text_buffer_get_iter_at_line(textBuff,&iter,imgl_cursorpos); - gtk_text_buffer_insert(textBuff,&iter,imagefile,-1); // insert image file + GdkPixbuf * gdk_pixbuf_rotate(GdkPixbuf *pixbuf, double angle, int acolor) - imgl_showthumb(); // update thumbnail - imgl_cursorpos++; // advance cursor position + Rotate a pixbuf through an arbitrary angle (degrees). - return; -} + The returned image has the same size as the original, but the + pixbuf envelope is increased to accomodate the rotated original + (e.g. a 100x100 pixbuf rotated 45 deg. needs a 142x142 pixbuf). + Pixels added around the rotated image have all RGB values = acolor. + Angle is in degrees. Positive direction is clockwise. + Pixbuf must have 8 bits per channel and 3 or 4 channels. + Loss of resolution is about 1/2 pixel. + Speed is about 28 million pixels/sec. on my 3.3 GHz CPU. // v.5.0 + (i.e. a 10 megapix image needs about 10/28 = 0.36 seconds) + + NULL is returned if the function fails for one of the following: + - pixbuf not 8 bits/channel or < 3 channels + - unable to create output pixbuf (lack of memory?) + + Algorithm: + create output pixbuf big enough for rotated input pixbuf + compute coefficients for affine transform + loop all output pixels + get next output pixel (px2,py2) + convert to input pixel (px1,py1) using affine transform + if outside of pixmap + output pixel = black + continue + for 4 input pixels based at (px0,py0) = (int(px1),int(py1)) + compute overlap (0 to 1) with (px1,py1) + sum RGB values * overlap + output aggregate RGB to pixel (px2,py2) -// called from image gallery window when a thumbnail is clicked -// add image file to list at current cursor position, set thumbnail = file +***/ -void imgl_gallery_file(int Nth, int button) // v.4.7 +GdkPixbuf * gdk_pixbuf_rotate(GdkPixbuf *pixbuf1, double angle, int acolor) { - int ftyp; - char *imagefile; - - if (Nth == -2) { - showz_userguide(zfuncs::F1_help_topic); // F1 context help - return; - } - - imagefile = image_gallery(0,"find",Nth); // get file at clicked position - if (! imagefile) return; - - ftyp = image_file_type(imagefile); // ignore directories v.3.9 - if (ftyp == 2) imgl_insert_file(imagefile); // insert file at current position - zfree(imagefile); + typedef unsigned char *pixel; // 3 RGB values, 0-255 each - return; -} + GdkPixbuf *pixbuf2; + GdkColorspace color; + int nch, nbits, alpha; + int ww1, hh1, rs1, ww2, hh2, rs2; + int px2, py2, px0, py0; + pixel ppix1, ppix2, pix0, pix1, pix2, pix3; + double px1, py1; + double f0, f1, f2, f3, red, green, blue, tran = 0; + double a, b, d, e, ww15, hh15, ww25, hh25; + double pi = 3.141593; -// process mouse click in files window: -// set new cursor position and set thumbnail = clicked file + zthreadcrash(); // thread usage not allowed -int imgl_mouseclick(GtkWidget *, GdkEventButton *event, void *) -{ - int mpy; - GtkWidget *scrollwin; - GtkAdjustment *scrolladj; - double scrollpos; + nch = gdk_pixbuf_get_n_channels(pixbuf1); + nbits = gdk_pixbuf_get_bits_per_sample(pixbuf1); + if (nch < 3) return 0; // must have 3+ channels (colors) + if (nbits != 8) return 0; // must be 8 bits per channel - if (event->type != GDK_BUTTON_PRESS) return 0; - mpy = int(event->y); - scrollwin = zdialog_widget(imgl_zd,"scrwin"); // window scroll position - scrolladj = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(scrollwin)); - scrollpos = gtk_adjustment_get_value(scrolladj); - imgl_cursorpos = (mpy + scrollpos) / imgl_fontheight; // line selected - imgl_showthumb(); // show thumbnail image - return 0; -} + color = gdk_pixbuf_get_colorspace(pixbuf1); // get input pixbuf1 attributes + alpha = gdk_pixbuf_get_has_alpha(pixbuf1); + ww1 = gdk_pixbuf_get_width(pixbuf1); + hh1 = gdk_pixbuf_get_height(pixbuf1); + rs1 = gdk_pixbuf_get_rowstride(pixbuf1); + while (angle < -180) angle += 360; // normalize, -180 to +180 + while (angle > 180) angle -= 360; + angle = angle * pi / 180; // radians, -pi to +pi + + if (fabs(angle) < 0.001) { // bugfix 0.01 >> 0.001 + pixbuf2 = gdk_pixbuf_copy(pixbuf1); // angle is zero within my precision + return pixbuf2; + } -// show thumbnail for file at current cursor position + ww2 = int(ww1*fabs(cos(angle)) + hh1*fabs(sin(angle))); // rectangle containing rotated image + hh2 = int(ww1*fabs(sin(angle)) + hh1*fabs(cos(angle))); -int imgl_showthumb() -{ - int line; - char *imagefile; - GtkTextBuffer *textBuff; - GtkTextIter iter1, iter2; - GdkPixbuf *thumbnail = 0; + pixbuf2 = gdk_pixbuf_new(color,alpha,nbits,ww2,hh2); // create output pixbuf2 + if (! pixbuf2) return 0; + rs2 = gdk_pixbuf_get_rowstride(pixbuf2); + + ppix1 = gdk_pixbuf_get_pixels(pixbuf1); // input pixel array + ppix2 = gdk_pixbuf_get_pixels(pixbuf2); // output pixel array + + ww15 = 0.5 * ww1; + hh15 = 0.5 * hh1; + ww25 = 0.5 * ww2; + hh25 = 0.5 * hh2; - gdk_window_clear(imgl_drawarea->window); + a = cos(angle); // affine transform coefficients + b = sin(angle); + d = - sin(angle); + e = cos(angle); + + for (py2 = 0; py2 < hh2; py2++) // loop through output pixels + for (px2 = 0; px2 < ww2; px2++) + { + px1 = a * (px2 - ww25) + b * (py2 - hh25) + ww15; // (px1,py1) = corresponding + py1 = d * (px2 - ww25) + e * (py2 - hh25) + hh15; // point within input pixels - line = imgl_cursorpos; - textBuff = gtk_text_view_get_buffer(GTK_TEXT_VIEW(imgl_files)); - gtk_text_buffer_get_iter_at_line(textBuff,&iter1,line); // iter at line start - iter2 = iter1; - gtk_text_iter_forward_to_line_end(&iter2); // iter at line end - - imagefile = gtk_text_buffer_get_text(textBuff,&iter1,&iter2,0); // get selected file - if (*imagefile != '/') { - free(imagefile); - return 0; - } + px0 = int(px1); // pixel containing (px1,py1) + py0 = int(py1); + + if (px1 < 0 || px0 >= ww1-1 || py1 < 0 || py0 >= hh1-1) { // if outside input pixel array + pix2 = ppix2 + py2 * rs2 + px2 * nch; // output is acolor + pix2[0] = pix2[1] = pix2[2] = acolor; + continue; + } - thumbnail = image_thumbnail(imagefile,256); // get thumbnail increased v.3.9 - free(imagefile); + pix0 = ppix1 + py0 * rs1 + px0 * nch; // 4 input pixels based at (px0,py0) + pix1 = pix0 + rs1; + pix2 = pix0 + nch; + pix3 = pix0 + rs1 + nch; - if (thumbnail) { - gdk_draw_pixbuf(imgl_drawarea->window,0,thumbnail,0,0,0,0,-1,-1,NODITHER,0,0); - g_object_unref(thumbnail); + f0 = (px0+1 - px1) * (py0+1 - py1); // overlap of (px1,py1) + f1 = (px0+1 - px1) * (py1 - py0); // in each of the 4 pixels + f2 = (px1 - px0) * (py0+1 - py1); + f3 = (px1 - px0) * (py1 - py0); + + red = f0 * pix0[0] + f1 * pix1[0] + f2 * pix2[0] + f3 * pix3[0]; // sum the weighted inputs + green = f0 * pix0[1] + f1 * pix1[1] + f2 * pix2[1] + f3 * pix3[1]; + blue = f0 * pix0[2] + f1 * pix1[2] + f2 * pix2[2] + f3 * pix3[2]; + if (alpha) + tran = f0 * pix0[3] + f1 * pix1[3] + f2 * pix2[3] + f3 * pix3[3]; // 4th color = alpha + + if (red == acolor && green == acolor && blue == acolor) { // avoid acolor in image + if (blue == 0) blue = 1; + else blue--; + } + + pix2 = ppix2 + py2 * rs2 + px2 * nch; // output pixel + pix2[0] = int(red); + pix2[1] = int(green); + pix2[2] = int(blue); + if (alpha) pix2[3] = int(tran); // bugfix } - return 0; + + return pixbuf2; } @@ -8857,7 +7401,7 @@ // edit parameters with a GUI // textWin != null enables button to list parameters in window // addp != 0 enables button to add new parameters -// return: 0 if cancel, else parameter count // v.2.7 +// return: 0 if cancel, else parameter count int editParms(GtkWidget *textWin, int addp) { @@ -8870,7 +7414,7 @@ if (! parmlistvalid) zappcrash("parmlistvalid = 0"); - zthreadcrash(); // thread usage not allowed v.3.9 + zthreadcrash(); // thread usage not allowed build_dialog: // build parameter edit dialog @@ -8900,7 +7444,7 @@ ZTX("load\nfile"),bload, ZTX("save\nfile"),bsave, ZTX("cancel"),bcancel, ZTX("apply"),bapply, null); - gtk_window_set_position(GTK_WINDOW(peDialog),GTK_WIN_POS_MOUSE); // v.2.7.1 + gtk_window_set_position(GTK_WINDOW(peDialog),GTK_WIN_POS_MOUSE); for (ii = 0; ii < parmlist.count; ii++) // labels and edit boxes side by side { // (parm names and parm values) @@ -8932,7 +7476,7 @@ if (zstat <= bcancel) // kill, cancel { if (floaded) { - zstat = zmessageYN(null,ZTX("apply?")); // if file loaded, clarify v.2.9 + zstat = zmessageYN(null,ZTX("apply?")); // if file loaded, clarify if (! zstat) { gtk_widget_destroy(peDialog); return 0; @@ -8960,7 +7504,7 @@ if (zstat == bapply) // apply new values { - for (ii = 0; ii < parmlist.count; ii++) // capture inputs and save them v.2.7 + for (ii = 0; ii < parmlist.count; ii++) // capture inputs and save them { pchval = gtk_entry_get_text(GTK_ENTRY(peEdit[ii])); err = convSD(pchval,parmlist.value[ii]); @@ -8971,7 +7515,7 @@ if (zstat == bsave) // save to file { - for (ii = 0; ii < parmlist.count; ii++) // apply new values v.2.9 + for (ii = 0; ii < parmlist.count; ii++) // apply new values { pchval = gtk_entry_get_text(GTK_ENTRY(peEdit[ii])); err = convSD(pchval,parmlist.value[ii]); @@ -8992,7 +7536,7 @@ pname = zdialog_text(null,ZTX("add parameter"),ZTX("(new parm name)")); if (! pname) goto run_dialog; setParm(pname,0.0); - zfree(pname); // v.3.7 + zfree(pname); floaded = 1; iie = parmlist.count - 1; // focus on new parm gtk_widget_destroy(peDialog); diff -Nru fotoxx-11.11.1/zfuncs.h fotoxx-12.01.2/zfuncs.h --- fotoxx-11.11.1/zfuncs.h 2011-11-05 05:30:36.000000000 +0000 +++ fotoxx-12.01.2/zfuncs.h 2012-01-04 08:47:11.000000000 +0000 @@ -39,6 +39,9 @@ #include #include +#include +#include + #define int8 char // number types #define int16 short #define int32 long @@ -47,9 +50,9 @@ #define uint16 unsigned short #define uint32 unsigned long #define uint64 unsigned long long +#define dub double #define uchar unsigned char #define cchar const char -#define dub double #define wstrerror(err) strerror(WEXITSTATUS(err)) // get text status for child process @@ -67,9 +70,9 @@ // system functions ====================================================== -void zappcrash(cchar *pMessage, ...); // crash with popup message in text window void apppause(); // output message and wait for user void apppause(cchar * pMess, ... ); // same, works like printf +void zappcrash(cchar *pMessage, ...); // crash with popup message in text window void catch_signals(); // catch signals and do backtrace dump void beroot(int argc = 0, char *argv[] = 0); // restart image as root if password OK @@ -112,6 +115,7 @@ int parsefile(cchar *path, char **dir, char **file, char **ext); // parse a filespec // measure CPU time spent in a function or code block within a function + extern volatile double cpu_profile_timer; // internal data tables extern volatile double cpu_profile_table[100]; extern volatile double cpu_profile_elapsed; @@ -212,7 +216,8 @@ // search and sort functions ============================================= -int bsearch(int element, int nn, int list[]); // binary search sorted list[nn] +int bsearch(int seekint, int nn, int list[]); // binary search sorted list[nn] +int bsearch(char *seekrec, char *allrecs, int recl, int nrecs); // binary search sorted records typedef int HeapSortUcomp(cchar * rec1, cchar * rec2); // return -1/0/+1 if rec1 rec2 void HeapSort(int vv[], int nn); // Heap Sort - integer @@ -244,7 +249,7 @@ #define ZTXmaxcc 4000 // max. cc per string int zinitapp(cchar *appname, ...); // initz. app directories and files v.4.1 -cchar * get_zinstalloc(); // get /usr or /usr/local ... v.4.1 +cchar * get_zprefix(); // get /usr or /usr/local ... v.4.1 cchar * get_zuserdir(); // get /home/user/.appname/ cchar * get_zdatadir(); // get install directory cchar * get_zdocdir(); // get document directory v.3.8 @@ -255,21 +260,14 @@ void showz_translations(); // show TRANSLATIONS file in popup window void showz_doctext(cchar *file); // show text file (or .gz) in a popup window void zmake_menu_launcher(cchar *command, cchar *cats, cchar *generic); // add desktop menu and launcher v.4.1 - -void ZTXinit(cchar *lang); // setup for message translation -cchar *ZTX(cchar *english); // get translation for English message -void ZTX_translation_start(); // start online translation +void showz_html(cchar *url); // show html via preferred browser v.2.18 /************************************************************************** GTK utility functions ***************************************************************************/ -#include -#include - -#define zdcbmax 100 // max. combo box drop-down list - void zmainloop(int skip = 0); // do main loop, process menu events +void zthreadcrash(); // crash if thread is not main() thread // text window print and read utilities void wprintx(GtkWidget *Win, int line, cchar *mess, cchar *font = 0); // write text to line, optional font @@ -287,7 +285,10 @@ // functions to simplify building menus, tool bars, status bars -#define G_SIGNAL(window,event,func,arg) g_signal_connect(G_OBJECT(window),event,G_CALLBACK(func),(void *) arg); +#define G_SIGNAL(window,event,func,arg) \ + g_signal_connect(G_OBJECT(window),event,G_CALLBACK(func),(void *) arg) + +#define zdcbmax 100 // max. combo box drop-down list typedef void mtFunc(GtkWidget *, cchar *mname); // menu or button response function @@ -394,12 +395,19 @@ /**************************************************************************/ -// GTK misc. utility functioins +// translation functions + +void ZTXinit(cchar *lang); // setup for message translation +cchar *ZTX(cchar *english); // get translation for English message +void ZTX_translation_start(GtkWidget *parent); // start online translation // write text to popup window, shell command to popup window + int write_popup_text(cchar *action, cchar *text = 0, int ww = 0, int hh = 0, GtkWidget *parent = 0); int popup_command(cchar *command, int ww = 400, int hh = 300, GtkWidget *parent = 0); +// popup message dialogs + void zmessageACK(GtkWidget *parent, cchar *pMess, ... ); // display message, wait for OK void zmessLogACK(GtkWidget *parent, cchar *pMess, ... ); // same, with log to STDOUT int zmessageYN(GtkWidget *parent, cchar *pMess, ... ); // display message, wait for YES or NO @@ -408,37 +416,28 @@ char * zdialog_text(GtkWidget *parent, cchar * title, cchar * initext); // get short text input from user int zdialog_choose(cchar *title, GtkWidget *parent, cchar *mess, ...); // show message and return choice button -// file chooser dialogs for 1 file or multiple files +// file chooser dialogs for one file or multiple files + char * zgetfile1(cchar *title, cchar *action, cchar *file, cchar *butt = 0); char ** zgetfileN(cchar *title, cchar *action, cchar *file, cchar *butt = 0); -void showz_html(cchar *url); // show html via preferred browser v.2.18 - -typedef void drag_drop_func(int x, int y, char *text); // user function, get drag_drop text v.2.19 -void drag_drop_connect(GtkWidget *window, drag_drop_func); // connect window to user function - -GdkCursor * zmakecursor(cchar *iconfile); // make a cursor from an image file v.3.7 - -/**************************************************************************/ +// print image file -// GDK/GTK image file utility functions -// for functions returning char *, caller responsible for zfree() - -void print_image_paper_setup(); // paper setup for printing an image file -void print_image_margins_setup(); // setup print margins +void print_image_paper_setup(GtkWidget *parent); // paper setup for printing an image file +void print_image_margins_setup(GtkWidget *parent); // setup print margins void print_image_file(cchar *imagefile); // print the image file -GdkPixbuf * gdk_pixbuf_rotate(GdkPixbuf *, double deg, int alfa = 0); // rotate pixbuf through any angle +// drag and drop functions -char * image_gallery(cchar *filez, cchar *action, int Nth = 0, // display image gallery window, navigate, - void ufunc(int Nth, int butt) = 0, GtkWidget *parent = 0); // do callback for clicked thumbnails +typedef void drag_drop_func(int x, int y, char *text); // user function, get drag_drop text v.2.19 +void drag_drop_connect(GtkWidget *window, drag_drop_func); // connect window to user function -int image_gallery_position(cchar *file, int Nth); // get relative position of file in gallery -int image_file_type(cchar *file); // determine if directory or image file type -char * image_thumbfile(char *imagefile); // get thumbnail filespec, create if missing -GdkPixbuf * image_thumbnail(char *imagefile, int size = 0); // get thumbnail pixbuf, create if missing +// miscellaneous GDK/GTK functions -char ** image_gallery_getfiles(char *startdir, GtkWidget *parent = 0); // select files from gallery window +GdkPixbuf * get_thumbnail(char *fpath, int size); // get sized thumbnail for image file +GdkCursor * zmakecursor(cchar *iconfile); // make a cursor from an image file v.3.7 +int gdk_window_move_pointer(GdkWindow *, int px, int py); // move the mouse pointer to px, py +GdkPixbuf * gdk_pixbuf_rotate(GdkPixbuf *, double deg, int alfa = 0); // rotate pixbuf through any angle /**************************************************************************/
           /annotations/
        -
        annotazioni raccolte dalla funzione Trasforma->testo sull'immagine
        - +
        annotazioni raccolte +dalla funzione Trasforma->testo sull'immagine
           /collections/
        -
        collezioni d'immagini create con le funzioni per le collezioni
        - +
        collezioni d'immagini +create con le funzioni per le collezioni
           /saved_areas/
        -
        dati di aree salvate dalle funzioni di selezione aree (men [Seleziona])
        - +
        dati di aree salvate +dalle funzioni di selezione aree (menù [Seleziona])
           /saved_curves
        -
        dati delle curve salvate dalle funzioni del men [Ritocco]
        - +
        dati delle curve salvate +dalle funzioni del menù [Ritocco]
           fotoxx.log
        -
        giornale di Fotoxx che pu servire a fini diagnostici
        - +
        giornale di Fotoxx che +può servire a fini diagnostici
           parameters
        -
        parametri d'impostazione che Fotoxx salva tra una sessione e l'altra
        - +
        parametri d'impostazione +che Fotoxx salva tra una sessione e l'altra
           printfile.jpg
        -
        l'ultimo file stampato da Fotoxx
        - +
        l'ultimo file stampato da +Fotoxx
           recent_files
        -
        una lista degli ultimi 100 file aperti da Fotoxx, salvati all'uscita
        - +
        una lista degli ultimi +100 file aperti da Fotoxx, salvati all'uscita
           search_results
        -
        una lista degli ultimi file trovati con [Info -> Ricerca immagini]
        - +
        una lista degli ultimi +file trovati con [Info -> Ricerca immagini]
           tags_defined
        -
        la lista di tutte le etichette e categorie usate in tutte le immagini
        - +
        la lista di tutte le +etichette e categorie usate in tutte le immagini
           search_index
        -
        un grosso file di testo contenente dati ricercabili per tutte le immagini
        - +
        un grosso file di testo +contenente dati ricercabili per tutte le immagini