Search code examples
imagemagick

To change density so that image will be printed at the specified print size, in inches


The followig script creates a copy of the input image and changes its density so that the copy will be printed at a specified print size, in inches. For example, if you have a 100x200 pixel image and you want it to be printed so that it will fit 2x3 inch box, you need to specify outputPrintSize="2x3" and then run script.sh input.jpg output.jpg.

outputPrintSize="2x3" # In inches. E. g., 1x2, 1x, or x2.
                      # Currently, both width and height must be specified

IFS='x' read -rA ADDR <<< "$outputPrintSize"
outputPrintW=${ADDR[1]}
outputPrintH=${ADDR[2]}

units=$(magick identify -format %U $1)
if [[ $units = "Undefined" ]]; then
  input=$(mktemp ./$1~)
  cp $1 $input
  inputDensity=$( magick identify -format %xx%y $input )
  magick $input -units PixelsPerInch -density $inputDensity $input
else
  input=$1
fi

inputPrintW=$(magick identify -format "%[fx:w/resolution.x]" $input)
inputPrintH=$(magick identify -format "%[fx:h/resolution.y]" $input)

if [[ $inputPrintW -gt $inputPrintH ]]; then
  inputDensityX=$(magick identify -format %x $input)
  # https://math.stackexchange.com/q/4936540
  outputDensityX=$(( inputDensityX / outputPrintW * inputPrintW ))
  magick $input -units PixelsPerInch -density $outputDensityX $2
else
  inputDensityY=$(magick identify -format %y $input)
  outputDensityY=$(( inputDensityY / outputPrintH * inputPrintH ))
  magick $input -units PixelsPerInch -density $outputDensityY $2
fi

if [[ $units = "Undefined" ]]; then rm $input; fi

The problem I'm trying to solve is that in some cases the density of the output file and therefore its print size are not correct: since outputPrintSize="2x3", print width must not exceed 2 inches and print height must not exceed 3 inches. Why is it so?

Test command:

magick identify -format "density: %xx%y-%U\nprint size: %[fx:w/resolution.x]x%[fx:h/resolution.y]" $TestFile

Results:

| input file              | output file             | works correctly? |
|-------------------------|-------------------------|------------------|
| test1.jpg               | test1_.jpg              | yes              |
| 72x72-PixelsPerInch     | 159x159-PixelsPerInch   |                  |
| 4.44444x1.90278         | 2.01258x0.861635        |                  |
|- - - - - - - - - - - - -| - - - - - - - - - - - - |- - - - - - - - - |
| test2.jpg               | test2_.jpg              | yes              |
| 72x72-PixelsPerInch     | 106x106-PixelsPerInch   |                  |
| 1.90278x4.44444         | 1.29245x3.01887         |                  |
|- - - - - - - - - - - - -| - - - - - - - - - - - - |- - - - - - - - - |
| test3.png               | test3_.png              | no               |
| 28.34x28.34-PixelsPerCm | 62.99x62.99-PixelsPerCm |                  |
| 11.2915x4.83416         | 5.08017x2.1749          |                  |
|- - - - - - - - - - - - -| - - - - - - - - - - - - |- - - - - - - - - |
| test4.png               | test4_.png              | no               |
| 72x72-Undefined         | 62.99x62.99-PixelsPerCm |                  |
| 3.2e+14x1.37e+14        | 5.08017x2.17495         |                  |
|- - - - - - - - - - - - -| - - - - - - - - - - - - |- - - - - - - - - |
| test5.jpg               | test5_.jpg              | yes              |
| 72x72-Undefined         | 16x16-PixelsPerInch     |                  |
| 4.8e+13x4.8e+13         | 3x3                     |                  |
|- - - - - - - - - - - - -| - - - - - - - - - - - - |- - - - - - - - - |

Test files: https://github.com/jsx97/test/blob/main/density.zip

ImageMagick 7.1.1


Solution

  • The answer is that

    inputPrintW=$(magick identify -format "%[fx:w/resolution.x]" $input)
    inputPrintH=$(magick identify -format "%[fx:h/resolution.y]" $input)
    

    should be replaced with

    if [[ $(magick identify -format %m $input) == PNG ]]; then
      inputPrintW=$(magick identify -format "%[fx:(w/resolution.x)*2.54]" $input)
      inputPrintH=$(magick identify -format "%[fx:(h/resolution.y)*2.54]" $input)
    else
      inputPrintW=$(magick identify -format "%[fx:w/resolution.x]" $input)
      inputPrintH=$(magick identify -format "%[fx:h/resolution.y]" $input)
    fi
    

    The full version; works fine for me:

    outputPrintSize=2x3 # In inches. E. g., 1x2, 1x, or x2.
                        # Currently, both width and height must be specified
    
    # -----------------------
    
    IFS=x read -rA ADDR <<< $outputPrintSize
    outputPrintW=${ADDR[1]}
    outputPrintH=${ADDR[2]}
    
    units=$(magick identify -format %U $1)
    if [[ $units == Undefined ]]; then
      input=$(mktemp ./$1~)
      cp $1 $input
      inputDensity=$(magick identify -format %xx%y $input)
      magick $input -units PixelsPerInch -density $inputDensity $input
    else
      input=$1
    fi
    
    if [[ $(magick identify -format %m $input) == PNG ]]; then
      inputPrintW=$(magick identify -format "%[fx:(w/resolution.x)*2.54]" $input)
      inputPrintH=$(magick identify -format "%[fx:(h/resolution.y)*2.54]" $input)
    else
      inputPrintW=$(magick identify -format "%[fx:w/resolution.x]" $input)
      inputPrintH=$(magick identify -format "%[fx:h/resolution.y]" $input)
    fi
    
    if [[ $inputPrintW -gt $inputPrintH ]]; then
      inputDensityX=$(magick identify -format %x $input)
      outputDensityX=$(( inputDensityX / outputPrintW * inputPrintW ))
      magick $input -units PixelsPerInch -density $outputDensityX $2
    else
      inputDensityY=$(magick identify -format %y $input)
      outputDensityY=$(( inputDensityY / outputPrintH * inputPrintH ))
      magick $input -units PixelsPerInch -density $outputDensityY $2
    fi
    
    # To test whether the script works properly
    magick identify -format "%[fx:w/resolution.x]x%[fx:h/resolution.y]" $2
    
    if [[ $units == Undefined ]]; then rm $input; fi