Plugin to resize an image
authorColin Clark <colin.clark@cclark.uk>
Tue, 10 Oct 2023 15:47:19 +0000 (16:47 +0100)
committerColin Clark <colin.clark@cclark.uk>
Tue, 10 Oct 2023 15:47:19 +0000 (16:47 +0100)
Use the Downsize script
(http://www.fmwconcepts.com/imagemagick/downsize/index.php) to reduce
the size of an image to a specified memory size.

doc/docbook/GuideReferenceStandardPlugins.xml
plugins/meson.build
plugins/resize-image/downsize [new file with mode: 0755]
plugins/resize-image/geeqie-resize-image [new file with mode: 0755]
plugins/resize-image/geeqie-resize-image.sh [new symlink]
plugins/resize-image/meson.build [new file with mode: 0644]
plugins/resize-image/resize-help.sh [new file with mode: 0755]
plugins/resize-image/resize-image.desktop.in [new file with mode: 0644]

index 2c60bda..ec2dec1 100644 (file)
       menu.
     </para>
   </section>
+  <section id="downsize">
+    <title>Resize image</title>
+    <para>Reduce the size of an image.</para>
+    <table frame="all">
+      <tgroup cols="2" rowsep="1" colsep="1">
+        <thead>
+          <row>
+            <entry>Option</entry>
+            <entry>Meaning</entry>
+          </row>
+        </thead>
+        <tbody>
+          <row>
+            <entry>Required size kB</entry>
+            <entry>desired output file size in kilobytes</entry>
+          </row>
+          <row>
+            <entry>Tolerance %</entry>
+            <entry>tolerance or allowed size of result greater than desired size expressed as percent of desired</entry>
+          </row>
+          <row>
+            <entry>Max. iterations</entry>
+            <entry>maximum number of iterations to stop</entry>
+          </row>
+          <row>
+            <entry>Copy if unchanged</entry>
+            <entry>
+              copy to output when not downsizing and no image
+              format change
+            </entry>
+          </row>
+          <row>
+            <entry>Strip metadata</entry>
+            <entry>strip all meta data</entry>
+          </row>
+          <row>
+            <entry>Show computation</entry>
+            <entry>show the values of each iteration</entry>
+          </row>
+          <row>
+            <entry>Open output file in Geeqie</entry>
+            <entry>on successful conversion set Geeqie focus to the file</entry>
+          </row>
+        </tbody>
+      </tgroup>
+    </table>
+    <para>
+      This plugin uses the Downsize script. The original may be found
+      <ulink url="http://www.fmwconcepts.com/imagemagick/downsize/index.php">here.</ulink>
+      It is subject to the following copyright:
+    </para>
+    <programlisting>
+      Copyright © Fred Weinhaus
+
+      My scripts are available free of charge for non-commercial (non-profit) use, ONLY.
+
+      For use of my scripts in commercial (for-profit) environments or non-free applications,
+      please contact me (Fred Weinhaus) for licensing arrangements. My email address is fmw at
+      alink dot net.
+
+      If you:
+      1) redistribute,
+      2) incorporate any of these scripts into other free applications or
+      3) reprogram them in another scripting language, then you must contact me for permission,
+      especially if the result might be used in a commercial or for-profit environment.
+
+      Usage, whether stated or not in the script, is restricted to the above licensing
+      arrangements. It is also subject, in a subordinate manner, to the ImageMagick license, which
+      can be found at: http://www.imagemagick.org/script/license.php
+    </programlisting>
+    <para />
+  </section>
 </section>
index 0c0abcd..2476acd 100644 (file)
@@ -17,6 +17,7 @@ subdir('geocode-parameters')
 subdir('image-crop')
 subdir('lens')
 subdir('random-image')
+subdir('resize-image')
 subdir('rotate')
 subdir('symlink')
 subdir('tethered-photography')
diff --git a/plugins/resize-image/downsize b/plugins/resize-image/downsize
new file mode 100755 (executable)
index 0000000..ceeea75
--- /dev/null
@@ -0,0 +1,484 @@
+#!/bin/bash
+#
+# Developed by Fred Weinhaus 12/24/2009 .......... revised 8/1/2021
+#
+# ------------------------------------------------------------------------------
+# 
+# Licensing:
+# 
+# Copyright © Fred Weinhaus
+# 
+# My scripts are available free of charge for non-commercial use, ONLY.
+# 
+# For use of my scripts in commercial (for-profit) environments or 
+# non-free applications, please contact me (Fred Weinhaus) for 
+# licensing arrangements. My email address is fmw at alink dot net.
+# 
+# If you: 1) redistribute, 2) incorporate any of these scripts into other 
+# free applications or 3) reprogram them in another scripting language, 
+# then you must contact me for permission, especially if the result might 
+# be used in a commercial or for-profit environment.
+# 
+# My scripts are also subject, in a subordinate manner, to the ImageMagick 
+# license, which can be found at: http://www.imagemagick.org/script/license.php
+# 
+# ------------------------------------------------------------------------------
+# 
+####
+#
+# USAGE: downsize [-s size] [-t toler] [-m maxiter] [-c copy] [-S strip] 
+# infile outfile
+# USAGE: downsize [-help]
+#
+# OPTIONS:
+#
+# -s      size         desired output file size in kilobytes; float>0; 
+#                       default=200
+# -t      toler         tolerance or allowed size of result greater than 
+#                       desired size expressed as percent of desired size; 
+#                       float>=0; default=10
+# -m      maxiter       maximum number of iterations to stop; integer>1; 
+#                       default=20
+# -c      copy          copy to output when not downsizing and no image 
+#                       format change; yes (y) or no (n); default=yes
+# -S      strip         strip all meta data; yes (y) or no (n); default=yes
+#
+###
+#
+# NAME: DOWNSIZE 
+# 
+# PURPOSE: To downsize (reduce) an image to a specified file size.
+# 
+# DESCRIPTION: DOWNSIZE reduces an image's dimensions to achieve a specified 
+# file size. For non-JPG images, processing will continue until either the 
+# desired tolerance is achieved or the maximum number of iterations is reached. 
+# For JPG images, processing will continue as above, but may stop when no 
+# change of file size (or quality) occurs. Thus the desired file size may not 
+# full be achieved to within the specified tolerance. Approximately 1% 
+# tolerance is practical amount that can be achieved for non-JPG images. For 
+# JPG images, the value may or may not be achieved. When strip is no, 
+# processing will be skipped, if the input file size is less than or equal to 
+# the combined desired file size plus the size of the meta data or if the  
+# desired size is less than the meta data size.
+# 
+# OPTIONS: 
+# 
+# -s size ... SIZE is the desired output image size in kilobytes. Values are 
+# floats>0. The default=200
+# 
+# -t toler ... TOLER is allowed size of the result within than the desire 
+# size expressed as a percent of the desired size. Values are floats>=0. 
+# The default=10. Processing will iterate until the resulting image size 
+# is within the tolerance. If the tolerance is too low, then iterations will  
+# stop when it reaches a value of maxiter. The default=10 (10%). If both toler 
+# and maxiter are too small, then iteration could continue indefinitely, 
+# since the algorithm may not be able to get as close as desired.
+# 
+# -m maxiter ... MAXITER is the maximum number of iterations to stop. Values 
+# are integer>1. The default=20. If both toler and maxiter are too small, 
+# then iteration could continue indefinitely, since the algorithm may not 
+# be able to get as close as desired.
+# 
+# -c copy ... COPY will copy the input to the output when both no downsize 
+# processing happens and the input and output formats are the same.
+# Values are either: yes (y) or no (n). Yes means make a copy of the input 
+# with the output name and no means simply skip processing and do not copy 
+# The input data to the output file. The default=yes.
+# 
+# -S strip ... STRIP all meta data. Choices are: yes (y) or no (n). The 
+# default=yes. Note that if you do not strip, the file size will be limited 
+# to the size of the meta data.
+#
+# NOTE: Images will be converted to 8 bits/pixel/channel.
+# 
+# CAVEAT: No guarantee that this script will work on all platforms, 
+# nor that trapping of inconsistent parameters is complete and 
+# foolproof. Use At Your Own Risk. 
+# 
+######
+#
+
+# set default values
+size=200               # desired output filesize in kilobytes
+toler=10               # tolerance as percent of size; toler>=0
+maxiter=20             # maximum iterations
+copy="yes"             # copy to output when not downsizing if no image format change
+strip="yes"            # strip meta data; yes or no
+toler1=10              # initial iteration for jpg; final iteration uses toler
+
+
+# set directory for temporary files
+dir="/tmp"    # suggestions are dir="." or dir="/tmp"
+
+# set up functions to report Usage and Usage with Description
+PROGNAME=`type $0 | awk '{print $3}'`  # search for executable on path
+PROGDIR=`dirname $PROGNAME`            # extract directory of program
+PROGNAME=`basename $PROGNAME`          # base name of program
+usage1() 
+       {
+       echo >&2 ""
+       echo >&2 "$PROGNAME:" "$@"
+       sed >&2 -e '1,/^####/d;  /^###/g;  /^#/!q;  s/^#//;  s/^ //;  4,$p' "$PROGDIR/$PROGNAME"
+       }
+usage2() 
+       {
+       echo >&2 ""
+       echo >&2 "$PROGNAME:" "$@"
+       sed >&2 -e '1,/^####/d;  /^######/g;  /^#/!q;  s/^#*//;  s/^ //;  4,$p' "$PROGDIR/$PROGNAME"
+       }
+
+
+# function to report error messages
+errMsg()
+       {
+       echo ""
+       echo $1
+       echo ""
+       usage1
+       exit 1
+       }
+
+
+# function to test for minus at start of value of second part of option 1 or 2
+checkMinus()
+       {
+       test=`echo "$1" | grep -c '^-.*$'`   # returns 1 if match; 0 otherwise
+    [ $test -eq 1 ] && errMsg "$errorMsg"
+       }
+
+# test for correct number of arguments and get values
+if [ $# -eq 0 ]
+       then
+       # help information
+   echo ""
+   usage2
+   exit 0
+elif [ $# -gt 12 ]
+       then
+       errMsg "--- TOO MANY ARGUMENTS WERE PROVIDED ---"
+else
+       while [ $# -gt 0 ]
+               do
+                       # get parameter values
+                       case "$1" in
+                    -help)    # help information
+                                          echo ""
+                                          usage2
+                                          exit 0
+                                          ;;
+                               -c)    # get copy
+                                          shift  # to get the next parameter
+                                          # test if parameter starts with minus sign 
+                                          errorMsg="--- INVALID COPY SPECIFICATION ---"
+                                          checkMinus "$1"
+                                          copy=`echo "$1" | tr '[A-Z]' '[a-z]'`
+                                          case "$copy" in 
+                                                       yes|y) copy="yes";;
+                                                       no|n) copy="no";;
+                                                       *) errMsg "--- COPY=$copy IS AN INVALID VALUE ---" 
+                                               esac
+                                          ;;
+                               -s)    # get size
+                                          shift  # to get the next parameter
+                                          # test if parameter starts with minus sign 
+                                          errorMsg="--- INVALID SIZE SPECIFICATION ---"
+                                          checkMinus "$1"
+                                          size=`expr "$1" : '\([.0-9]*\)'`
+                                          sizetest=`echo "$size <= 0" | bc`
+                                          [ $sizetest -eq 1 ] && errMsg "--- SIZE=$size MUST BE A FLOAT GREATER THAN 0 ---"
+                                          ;;
+                               -t)    # get toler
+                                          shift  # to get the next parameter
+                                          # test if parameter starts with minus sign 
+                                          errorMsg="--- INVALID TOLER SPECIFICATION ---"
+                                          checkMinus "$1"
+                                          toler=`expr "$1" : '\([.0-9]*\)'`
+                                          tolertest=`echo "$toler < 0" | bc`
+                                          [ $tolertest -eq 1 ] && errMsg "--- TOLER=$toler MUST BE A NON-NEGATIVE FLOAT ---"
+                                          ;;
+                               -m)    # get maxiter
+                                          shift  # to get the next parameter
+                                          # test if parameter starts with minus sign 
+                                          errorMsg="--- INVALID MAXITER SPECIFICATION ---"
+                                          checkMinus "$1"
+                                          maxiter=`expr "$1" : '\([0-9]*\)'`
+                                          maxitertest=`echo "$maxiter < 1" | bc`
+                                          [ $maxitertest -eq 1 ] && errMsg "--- MAXITER=$maxiter MUST BE A POSITIVE INTEGER ---"
+                                          ;;
+                               -S)    # get strip
+                                          shift  # to get the next parameter
+                                          # test if parameter starts with minus sign 
+                                          errorMsg="--- INVALID STRIP SPECIFICATION ---"
+                                          checkMinus "$1"
+                                          strip=`echo "$1" | tr '[A-Z]' '[a-z]'`
+                                          case "$strip" in 
+                                                       yes|y) strip="yes";;
+                                                       no|n) strip="no";;
+                                                       *) errMsg "--- STRIP=$strip IS AN INVALID VALUE ---" 
+                                               esac
+                                          ;;
+                                -)    # STDIN and end of arguments
+                                          break
+                                          ;;
+                               -*)    # any other - argument
+                                          errMsg "--- UNKNOWN OPTION ---"
+                                          ;;
+                        *)    # end of arguments
+                                          break
+                                          ;;
+                       esac
+                       shift   # next option
+       done
+       #
+       # get infile and outfile
+       infile="$1"
+       outfile="$2"
+fi
+
+# test that infile provided
+[ "$infile" = "" ] && errMsg "NO INPUT FILE SPECIFIED"
+
+# test that outfile provided
+[ "$outfile" = "" ] && errMsg "NO OUTPUT FILE SPECIFIED"
+
+
+# setup for stripping meta data
+if [ "$strip" = "yes" ]; then
+       stripping="-strip"
+else
+       stripping=""
+fi
+
+# get file type of input
+# ftypes are: JPEG, TIFF, PNG and GIF
+ftype=`convert "$infile" -ping -format "%m" info:`
+
+# get suffix of outfile
+outlist=`echo $outfile | tr "." " "`
+partsArray=($outlist)
+numparts=${#partsArray[*]}
+suffix=${partsArray[$numparts-1]}
+suffix=`echo $suffix | tr "[:lower:]" "[:upper:]"`
+[ "$suffix" = "JPG" ] && suffix="JPEG"
+[ "$suffix" = "TIF" ] && suffix="TIFF"
+
+# if ftype != suffix, set ftype to suffix
+# IM can deal with ftype TIFF or TIF and JPEG or JPG
+[ "$ftype" != "$suffix" ] && changetype="yes" || changetype="no"
+[ "$ftype" != "$suffix" ] && ftype=$suffix
+
+# if JPG, then set quality to 100
+if [ "$ftype" = "JPEG" ]; then
+       setquality="-quality 100"
+       setunits="-units pixelsperinch"
+else
+       setquality=""
+       setunits=""
+fi
+
+# get input compression
+compression=`convert "$infile" -ping -format "%C" info:`
+
+if [ "$ftype" = "TIFF" -a "$compresson" = "JPEG" ]; then
+       setcompression="-compress none"
+elif [ "$ftype" = "TIFF" -a "$compresson" != "JPEG" ]; then
+       setcompression="-compress $compression"
+else
+       setcompression=""
+fi
+
+# if strip is no, get size of meta data in bytes
+if [ "$strip" = "no" ]; then
+       meta_list=`identify -verbose "$infile" | grep "Profile-" | sed 's/^[ ]*//' | cut -d\  -f2`
+       meta_sum=0
+       for amt in $meta_list; do
+       meta_sum=$((meta_sum+amt))
+       done
+fi
+
+# set up temp file
+tmpA1="$dir/downsize_1_$$.$suffix"
+
+trap "rm -f $tmpA1;" 0
+trap "rm -f $tmpA1; exit 1" 1 2 3 15
+#trap "rm -f $tmpA1; exit 1" ERR
+
+# read the input image into the temp files and test validity.
+convert -quiet "$infile"[0] $stripping -depth 8 $setcompression $setquality $setunits +repage ${ftype}:$tmpA1 ||
+       errMsg "--- FILE $infile DOES NOT EXIST OR IS NOT AN ORDINARY FILE, NOT READABLE OR HAS ZERO SIZE  ---"
+
+# get filesize
+# fullsize is converted to bytes
+# size2 is size converted to bytes
+test1=`convert $tmpA1 -ping -format "%b" info:- | grep "MB"`
+test2=`convert $tmpA1 -ping -format "%b" info:- | grep "KB"`
+test3=`convert $tmpA1 -ping -format "%b" info:- | grep "B"`
+fullsize=`convert -ping $tmpA1 -format "%b" info: | tr -d "[:alpha:]"`
+if [ "$test1" != "" ]; then
+       fullsize=`convert xc: -format "%[fx:$fullsize*1000000]" info:`
+elif [ "$test2" != "" ]; then
+       fullsize=`convert xc: -format "%[fx:$fullsize*1000]" info:`
+elif [ "$test3" != "" ]; then
+       fullsize=$fullsize
+else
+       errMsg="--- UNRECOGNIZED FILESIZE SUFFIX ---"
+fi
+size2=`convert xc: -format "%[fx:$size*1000]" info:`
+#echo "test1=$test1; test2=$test2; test3=$test3; ftype=$ftype; fullsize=$fullsize; size2=$size2;"
+
+# process image for strip=yes, if input size > desired size
+# process image for strip=no, if input size > desired size + meta size 
+# and the desired size is greater than the meta size
+if [ "$strip" = "yes" ]; then
+       test4=`convert xc: -format "%[fx:($fullsize>$size2)?1:0]" info:`
+elif [ "$strip" = "no" ]; then
+       test4=`convert xc: -format "%[fx:($fullsize>$size2+$meta_size) && ($size2>=$meta_size)?1:0]" info:`
+       size2=$((size2+meta_size))
+fi
+
+if [ $test4 -eq 1 ]; then
+       # iterate
+       i=1
+       diffsize=0
+       iterate=1
+       newsize=$fullsize
+       if [ "$ftype" = "JPEG" ]; then
+               # iterate from previous image to new image as outfile
+               # this may give blurry results but close values
+               # so get the final images size and resize one last time from the original
+               # also use -define jpeg:extent=${size}KB which will change the quality to get closer
+               # if used the alternate method below with JPEG, sometimes got overshoots and pratio=nan since newsize became negative
+               convert $tmpA1 "$outfile"
+               while [ $iterate -eq 1 -a $i -lt $maxiter ]; do
+                       # get sqrt size ratio in percent
+                       pratio=`convert xc: -format "%[fx:100*sqrt($size/$newsize)]" info:`
+                       #echo "i=$i; fullsize=$fullsize; size=$size; size2=$size2; newsize=${newsize}kB; pratio=$pratio;"
+               
+                       # resize image
+                       convert "$outfile" -resize ${pratio}% -depth 8 $setquality $setunits ${ftype}:"$outfile"
+               
+                       # set newsize in KB
+                       testa=`convert "$outfile" -ping -format "%b" info:- | grep "MB"`
+                       testb=`convert "$outfile" -ping -format "%b" info:- | grep "KB"`
+                       testc=`convert "$outfile" -ping -format "%b" info:- | grep "B"`
+                       if [ "$testa" != "" ]; then
+                               newsize=`convert "$outfile" $setquality ${ftype}:- | convert - -format "%b" info: | tr -d "[:alpha:]"`
+                               newsize=`convert xc: -format "%[fx:$newsize*1000]" info:`
+                       elif [ "$testb" != "" ]; then
+                               newsize=`convert "$outfile" $setquality ${ftype}:- | convert - -format "%b" info: | tr -d "[:alpha:]"`
+                       elif [ "$testc" != "" ]; then
+                               newsize=`convert "$outfile" $setquality ${ftype}:- | convert - -format "%b" info: | tr -d "[:alpha:]"`
+                               newsize=`convert xc: -format "%[fx:$newsize/1000]" info:`
+                       fi              
+                       echo "i=$i newsize=${newsize}kB quality=100"
+                       diffsize=`convert xc: -format "%[fx:($newsize-$size)]" info:`
+                       iterate=`convert xc: -format "%[fx:abs($diffsize)>($toler1*$size/100)?1:0]" info:`
+                       #echo "PART1: i=$i; newsize=${newsize}kB; diffsize=$diffsize; iterate=$iterate;"
+                       i=$(($i+1))
+               done
+
+               # get final size of iterated outfile and then use that to resize the original
+               dim=`convert "$outfile" -format "%wx%h" info:`
+               convert $tmpA1 -resize $dim -define jpeg:extent=${size}KB -depth 8 $setquality $setunits ${ftype}:"$outfile"
+               # set newsize in KB
+               testa=`convert "$outfile" -ping -format "%b" info:- | grep "MB"`
+               testb=`convert "$outfile" -ping -format "%b" info:- | grep "KB"`
+               testc=`convert "$outfile" -ping -format "%b" info:- | grep "B"`
+               oldsize=$newsize
+               if [ "$testa" != "" ]; then
+                       newsize=`convert -ping "$outfile" -format "%b" info: | tr -d "[:alpha:]"`
+                       newsize=`convert xc: -format "%[fx:$newsize*1000]" info:`
+               elif [ "$testb" != "" ]; then
+                       newsize=`convert -ping "$outfile" -format "%b" info: | tr -d "[:alpha:]"`
+               elif [ "$testc" != "" ]; then
+                       newsize=`convert -ping "$outfile" -format "%b" info: | tr -d "[:alpha:]"`
+                       newsize=`convert xc: -format "%[fx:$newsize/1000]" info:`
+               fi              
+               quality=`convert -ping "$outfile" -format "%Q" info:`
+               echo "i=$i newsize=${newsize}kB quality=$quality"
+               diffsize=`convert xc: -format "%[fx:($size-$newsize)]" info:`
+               #newsign=`convert xc: -format "%[fx:sign($size-$newsize)]" info:`
+               #oldsign=$newsign
+               size1=`convert xc: -format "%[fx:$size+$diffsize]" info:`
+               iterate=`convert xc: -format "%[fx:abs($diffsize)>($toler*$size/100)?1:0]" info:`
+               #echo "PART2: i=$i; newsign=$newsign; oldsign=$oldsign; quality=$quality; size1=${size1}KB; newsize=${newsize}KB; diffsize=$diffsize; iterate=$iterate;"
+               i=$((i+1))
+               
+               # iterate again changing jpeg write extent size
+#              while [ $iterate -eq 1 -a $i -lt $maxiter -a $newsign -eq $oldsign -a "$newsize" != "$oldsize" ]; do
+               while [ $iterate -eq 1 -a $i -lt $maxiter -a "$newsize" != "$oldsize" ]; do
+                       convert $tmpA1 -resize $dim -define jpeg:extent=${size1}KB -depth 8 $setquality $setunits ${ftype}:"$outfile"
+                       # set newsize in KB
+                       testa=`convert "$outfile" -ping -format "%b" info:- | grep "MB"`
+                       testb=`convert "$outfile" -ping -format "%b" info:- | grep "KB"`
+                       testc=`convert "$outfile" -ping -format "%b" info:- | grep "B"`
+                       oldsize=$newsize
+                       if [ "$testa" != "" ]; then
+                               newsize=`convert -ping "$outfile" -format "%b" info: | tr -d "[:alpha:]"`
+                               newsize=`convert xc: -format "%[fx:$newsize*1000]" info:`
+                       elif [ "$testb" != "" ]; then
+                               newsize=`convert -ping "$outfile" -format "%b" info: | tr -d "[:alpha:]"`
+                       elif [ "$testc" != "" ]; then
+                               newsize=`convert -ping "$outfile" -format "%b" info: | tr -d "[:alpha:]"`
+                               newsize=`convert xc: -format "%[fx:$newsize/1000]" info:`
+                       fi
+                       quality=`convert -ping "$outfile" -format "%Q" info:`
+                       echo "i=$i newsize=${newsize}kB quality=$quality"
+                       diffsize=`convert xc: -format "%[fx:($size-$newsize)]" info:`
+                       #oldsign=$newsign
+                       #newsign=`convert xc: -format "%[fx:sign($size-$newsize)]" info:`
+                       size1=`convert xc: -format "%[fx:0.5*($size+$newsize)]" info:`
+                       iterate=`convert xc: -format "%[fx:abs($diffsize)>($toler*$size/100)?1:0]" info:`
+                       #echo "PART3: i=$i; newsign=$newsign; oldsign=$oldsign; quality=$quality; size1=${size1}KB; newsize=${newsize}KB; diffsize=$diffsize; iterate=$iterate;"
+                       i=$(($i+1))
+               done
+
+               
+
+       else
+               while [ $iterate -eq 1 -a $i -lt $maxiter ]; do
+                       # get sqrt size ratio in percent
+                       size2=`convert xc: -format "%[fx:max($size2-($diffsize*1000),0)]" info:`
+                       pratio=`convert xc: -format "%[fx:100*sqrt($size2/$fullsize)]" info:`
+                       #echo "i=$i; fullsize=$fullsize; size=$size; size2=$size2; pratio=$pratio;"
+                       
+                       testd=`convert xc: -format "%[fx:$size2<($toler*$size/100)?1:0]" info:`
+                       [ $testd -eq 1 ] && break
+               
+                       # resize image
+                       convert $tmpA1 -resize ${pratio}% -depth 8 $setcompression $setquality $setunits ${ftype}:"$outfile"
+                       printsize=`convert "$outfile" -ping -format "%b" info:`
+                       echo "i=$i; size=${printsize}"
+                                               
+                       testa=`convert "$outfile" -ping -format "%b" info:- | grep -i "MB"`
+                       testb=`convert "$outfile" -ping -format "%b" info:- | grep -i "KB"`
+                       testc=`convert "$outfile" -ping -format "%b" info:- | grep -i "B"`
+                       if [ "$testa" != "" ]; then
+                               newsize=`convert "$outfile" -depth 8 $setcompression $setquality $setunits ${ftype}:- | convert - -ping -format "%b" info: | tr -d "[:alpha:]"`
+                               newsize=`convert xc: -format "%[fx:$newsize*1000]" info:`
+                       elif [ "$testb" != "" ]; then
+                               newsize=`convert "$outfile" -depth 8 $setcompression $setquality $setunits ${ftype}:- | convert - -ping -format "%b" info: | tr -d "[:alpha:]"`
+                       elif [ "$testc" != "" ]; then
+                               newsize=`convert "$outfile" -depth 8 $setcompression $setquality $setunits ${ftype}:- | convert - -ping -format "%b" info: | tr -d "[:alpha:]"`
+                               #newsize=`convert xc: -format "%[fx:$fullsize/1000]" info:`
+                               newsize=`convert xc: -format "%[fx:$newsize/1000]" info:`
+                       fi              
+                       #echo "i=$i; newsize=${newsize}kB"
+                       diffsize=`convert xc: -format "%[fx:($newsize-$size)]" info:`
+                       iterate=`convert xc: -format "%[fx:abs($diffsize)>($toler*$size/100)?1:0]" info:`
+                       #echo "i=$i; newsize=${newsize}kB; diffsize=$diffsize; iterate=$iterate;"
+                       i=$(($i+1))
+               done
+       fi
+       
+elif [ "$changetype" = "no" -a "$copy" = "yes" ]; then
+       convert "$infile" "$outfile"
+
+else
+       convert $tmpA1 -depth 8 $setcompression $setquality $setunits "$outfile"
+fi
+
+finalsize=`convert "$outfile" -format "%b" info:`
+echo "final size = $finalsize"
+
+exit
diff --git a/plugins/resize-image/geeqie-resize-image b/plugins/resize-image/geeqie-resize-image
new file mode 100755 (executable)
index 0000000..72b13f2
--- /dev/null
@@ -0,0 +1,145 @@
+#!/bin/sh
+
+## @file
+## @brief Resize an image to a specified value.
+##
+## Requires:
+## yad
+## ImageMagick
+##
+
+current_dir=$(dirname "$(readlink -f "$0")")
+
+if ! command -v yad > /dev/null
+then
+       zenity --window-icon=/usr/local/share/pixmaps/geeqie.png --width=400 --info --title "Geeqie Resize" --text="yad and ImageMagick are required\n\nyad is not installed"
+       exit 0
+fi
+
+if ! command -v convert > /dev/null
+then
+       zenity --window-icon=/usr/local/share/pixmaps/geeqie.png --width=400 --info --title "Geeqie Resize" --text="yad and ImageMagick are required\n\nImageMagick is not installed"
+       exit 0
+fi
+
+if [ -z "$1" ]
+then
+       yad --window-icon=/usr/local/share/pixmaps/geeqie.png --geometry=400 --image dialog-warning --title "Geeqie Resize" --button=gtk-ok:0 --text "\nNo input file was given."
+       exit 0
+fi
+
+basefile=$(basename "$1")
+base=${basefile%.*}
+ext=${basefile#*.}
+
+default_filename=$(printf %s "/tmp/$base-resized.$ext")
+if [ -f "$default_filename" ]
+then
+       i=1
+       while true
+       do
+               default_filename=$(printf %s%d%s "/tmp/$base-resized-" "$i" ".$ext")
+               if [ -f "$default_filename" ]
+               then
+                       i=$(( i + 1 ))
+               else
+                       break
+               fi
+       done
+fi
+
+
+selection=$(yad --window-icon=/usr/local/share/pixmaps/geeqie.png \
+--center                                                          \
+--title="Resize $1"                                               \
+--button=gtk-help:"$current_dir"/resize-help.sh                   \
+--button=gtk-cancel:1                                             \
+--button=gtk-ok:0                                                 \
+--text="<b>Reduce image size:</b>\n"                              \
+--form                                                            \
+--field="Required size kB":NUM           '100!1..100000!1!'       \
+--field="Tolerance %":NUM                '10!1..100!1!'           \
+--field="Max. iterations":NUM            '20!1..100!1!'           \
+--field="Copy if unchanged":CHK          'FALSE'                  \
+--field="Strip metadata":CHK             'TRUE'                   \
+--field="Show computation":CHK           'FALSE'                  \
+--field="Open output file in Geeqie":CHK 'FALSE'                  \
+--field="":LBL                                                    \
+--field="Output file":SFL                                         \
+--field="Default: $default_filename":LBL )
+
+if [ -z "$selection" ]
+then
+       exit 0
+fi
+
+size=$(printf %s "$selection" | cut --delimiter="|" --fields=1 -)
+tolerance=$(printf %s "$selection" | cut --delimiter="|" --fields=2 -)
+iterations=$(printf %s "$selection" | cut --delimiter="|" --fields=3 -)
+copy_unchanged=$(printf %s "$selection" | cut --delimiter="|" --fields=4 -)
+strip_metadata=$(printf %s "$selection" | cut --delimiter="|" --fields=5 -)
+show_computation=$(printf %s "$selection" | cut --delimiter="|" --fields=6 -)
+open_geeqie=$(printf %s "$selection" | cut --delimiter="|" --fields=7 -)
+file=$(printf %s "$selection" | cut --delimiter="|" --fields=9 -)
+
+if [ -z "$file" ]
+then
+       new_filename="$default_filename"
+else
+       if [ -f "$file" ]
+       then
+               if ! yad --window-icon=/usr/local/share/pixmaps/geeqie.png --geometry=300 --image dialog-warning --title "Geeqie Resize" --text "\nOutput file already exists.\nOverwrite?"
+               then
+                       exit 0
+               fi
+       fi
+       new_filename="$file"
+fi
+
+if [ "$copy_unchanged" = "FALSE" ]
+then
+       copy="n"
+else
+       copy="y"
+fi
+
+if [ "$strip_metadata" = "FALSE" ]
+then
+       strip="n"
+else
+       strip="y"
+fi
+
+tmp_file=$(mktemp "${TMPDIR:-/tmp}/geeqie.XXXXXXXXXX")
+
+yad --window-icon=/usr/local/share/pixmaps/geeqie.png --geometry=300 --image dialog-information --title "Geeqie Resize" --button=OK:0 --text "Running Downsize...." &
+info_id="$!"
+
+result=$("$current_dir"/downsize -s "$size" -t "$tolerance" -m "$iterations" -c "$copy" -S "$strip" "$1" "$new_filename" > "$tmp_file" 2>/dev/null)
+
+if [ "$?" -eq 1 ]
+then
+       kill "$info_id"
+       rm "$tmp_file"
+
+       yad --window-icon=/usr/local/share/pixmaps/geeqie.png --geometry=400 --image dialog-warning --title "Geeqie Resize" --button=gtk-ok:0 --text "Downsize failed.\n\nIf the filetype is not supported by Downsize,\ntry the Export plugin to get a jpeg.\n\nDownsize error message:\n$result"
+       exit 0
+fi
+
+kill "$info_id"
+
+if [ "$open_geeqie" = "TRUE" ]
+then
+       geeqie --remote "$new_filename"
+fi
+
+
+if [ "$show_computation" = "TRUE" ]
+then
+       yad --window-icon=/usr/local/share/pixmaps/geeqie.png --title "Geeqie Resize computation" --text="$new_filename\n\n$(cat "$tmp_file")" --button=gtk-ok:0
+fi
+
+rm "$tmp_file"
+
+exit 0
+
diff --git a/plugins/resize-image/geeqie-resize-image.sh b/plugins/resize-image/geeqie-resize-image.sh
new file mode 120000 (symlink)
index 0000000..ee7112f
--- /dev/null
@@ -0,0 +1 @@
+geeqie-resize-image
\ No newline at end of file
diff --git a/plugins/resize-image/meson.build b/plugins/resize-image/meson.build
new file mode 100644 (file)
index 0000000..23db14b
--- /dev/null
@@ -0,0 +1,24 @@
+# This file is a part of Geeqie project (https://www.geeqie.org/).
+# Copyright (C) 2008 - 2022 The Geeqie Team
+#
+# 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 2 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
+#
+
+install_data('geeqie-resize-image', 'downsize', 'resize-help.sh', install_dir : gq_bindir)
+
+i18n.merge_file(
+    input : 'resize-image.desktop.in',
+    output : 'resize-image.desktop',
+    type : 'desktop',
+    po_dir : podir,
+    install : true,
+    install_dir : desktopdir)
+
+script_sources += files('geeqie-resize-image')
diff --git a/plugins/resize-image/resize-help.sh b/plugins/resize-image/resize-help.sh
new file mode 100755 (executable)
index 0000000..de9659d
--- /dev/null
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+## @file
+## @brief Call browser from the Resize Help button
+##
+
+xdg-open https://www.geeqie.org/help/GuideReferenceStandardPlugins.html#downsize
diff --git a/plugins/resize-image/resize-image.desktop.in b/plugins/resize-image/resize-image.desktop.in
new file mode 100644 (file)
index 0000000..bbd12be
--- /dev/null
@@ -0,0 +1,16 @@
+[Desktop Entry]
+Version=1.0
+Type=Application
+Name=Resize image
+Comment=Downsize an image
+
+Exec=geeqie-resize-image %f
+
+# Desktop files that are usable only in Geeqie should be marked like this:
+Categories=X-Geeqie;
+OnlyShowIn=X-Geeqie;
+
+# It can be made verbose
+#X-Geeqie-Verbose=true
+
+Icon=geeqie