When images have transparent areas, we can append such that opaque areas abut each other.
Graphics images may have transparent areas. We might want to squish two images together, appending vertically or horizontally but with an overlap. And we might want to maximise the overlap so that opaque pixels from one image don't quite overlap opaque pixels from the other image.
This is like the "-append" operator but ignoring transparent pixels.
After I wrote this page, the "ashlar:" coder has been developed in ImageMagick. See Image Sequence Laid Out in Continuous Irregular Courses.
%IMG7%magick ^ -size 300x200 xc:None ^ -fill Blue -draw "circle 20,-20 20,150" ^ sqi_src1.png |
|
%IMG7%magick ^ -size 500x300 xc:None ^ -fill Green -draw "circle 400,400 400,20" ^ sqi_src2.png |
The method adjusts the vertical position so the lower opaque image doesn't quite touch the upper image. We find the solution by trial and error.
Because of anti-aliasing, touching or not touching isn't really a binary condition. There are degrees of touching:
This script uses a middle definition: touching has occurred when the sum of the opacities of any overlapping pixels exceeds 110%. To avoid a need for HDRI, we divide opacity by 2 and test for a limit of 55%.
The script squishAppend.bat extracts the alpha and levels it, so black represents transparent and 50% gray represents opaque, and then calls whatSquish.bat. This conducts trial overlaps of N rows, where N increases from one. For each trial, it crops the bottom N rows from the first image and the top N rows from the second, then adds the two cropped images together. When the maximum pixel in the addition is more than 55%, we have gone too far, so we back off one.
call %PICTBAT%squishAppend sqi_src1.png sqi_src2.png |
If the two objects had no overlap horizontally, then the images could be made to overlap to any degree. The script limits the overlap to the minimum height of the two images.
These scripts will find only a vertical overlap. If a horizontal overlap is wanted instead, the inputs and output should be rotated.
This simple linear search gives adequate performance for my needs. More sophisticated searches could improve performance.
We can apply the method to complex shapes like text. First, we create a simple text file:
( echo Hello world. echo How is echo your echo world? ) >sqi_text.txt
The file contains:
Hello world. How is your world?
Here is a non-squished example. The script textAutoWi.bat creates images for the lines, setting the pointsizes to make the lines roughly the same width. Then it trims and appends vertically, using the ordinary "-append" operation.
call %PICTBAT%textAutoWi ^ sqi_text.txt . sqi_text_taw.png |
In the last two lines, the bottom of "your" lines up with the top of "world" but a gap could be closed.
We can close all the gaps between text, so that text on one line doesn't quite ovelap text on the previous line. The script textAutoWiSquish.bat creates one image per line of text, appending it to the image made so far by calling squishAppend.bat.
call %PICTBAT%textAutoWiSquish ^ sqi_text.txt |
The result generally has the appearance of a gap of around 1 pixel. Aesthetically, it may be better to either have a deliberate overlap between objects, or a clear gap between them. We do this by reducing or increasing the gap between the lines of text:
Use gap of -2 (overlap). call %PICTBAT%textAutoWiSquish ^ sqi_text.txt . -2 sqi_text_taws2.png |
|
Use gap of +2 (separation). call %PICTBAT%textAutoWiSquish ^ sqi_text.txt . 2 sqi_text_taws3.png |
Perhaps we also want to squish the characters within each word such as "your". First, we find the pointsize that gives the required width.
for /F "usebackq" %%L in (`%IMG7%magick ^ -size 300 label:your -format "PNT_SZ=%%[label:pointsize]" ^ info:`) do set %%L echo PNT_SZ=%PNT_SZ%
PNT_SZ=152
(Versions v6.9.2-5 and v7.0.1-4 give slightly different pointsizes.)
Using "label:" at this pointsize, we make an image for each letter, rotate them 90° clockwise, and store them in a single miff file.
%IMG7%magick ^ -pointsize %PNT_SZ% ^ -background None ^ label:y label:o label:u label:r ^ -rotate 90 ^ sqi_your.miff
We squish the four images together, and rotate anticlockwise.
set GAP=0 call %PICTBAT%squishAppend ^ sqi_your.miff[0] ^ sqi_your.miff[1] ^ %GAP% ^ sqi_your_out.miff call %PICTBAT%squishAppend ^ sqi_your_out.miff ^ sqi_your.miff[2] ^ %GAP% ^ sqi_your_out.miff call %PICTBAT%squishAppend ^ sqi_your_out.miff ^ sqi_your.miff[3] ^ %GAP% ^ sqi_your_out.miff %IMG7%magick sqi_your_out.miff -rotate -90 sqi_your_out.png
sqi_your_out.png |
We can put this together in a script, squishStr.bat.
call %PICTBAT%squishStr ^ "World's Away." . . ^ sqi_ss.png |
The space character has been squished away. We can set sqsSPACE_GAP, which will be used instead of the gap parameter when the previous character was a space.
set sqsSPACE_GAP=5 call %PICTBAT%squishStr ^ "World's Away." . . ^ sqi_ss2.png set sqsSPACE_GAP= |
For convenience, .bat scripts are also available in a single zip file. See Zipped BAT files.
rem Given two images %1 and %2 with binary (more or less) transparency, rem how much can we overlap them vertically? rem %3 is amount to increase y-gap (or decrease if negative). rem %4 is output. @rem @rem Updated: @rem 11-August-2022 for IM v7 @rem @if "%2"=="" findstr /B "rem @rem" %~f0 & exit /B 1 @setlocal enabledelayedexpansion @call echoOffSave call %PICTBAT%setInOut %1 sa set INFILE1=%1 set INFILE2=%2 set deltaY=%3 if "%deltaY%"=="." set deltaY= if "%deltaY%"=="" set deltaY=0 if not "%4"=="" set OUTFILE=%4 %IMG7%magick ^ %INFILE1% ^ %INFILE2% ^ -alpha extract ^ +level 0,50%% ^ sa_tmp.miff call %PiCTBAT%whatSquish sa_tmp.miff[0] sa_tmp.miff[1] echo wsOver=%wsNover% wsGX=%wsGX% wsGY=%wsGY% set /A wsGY+=%deltaY% %IMG7%magick ^ %INFILE1% ^ ( %INFILE2% -repage +%wsGX%+%wsGY% ) ^ -background None ^ -layers merge ^ +repage ^ %OUTFILE% call echoRestore endlocal & set saOUTFILE=%OUTFILE%
rem Given images %1 and %2 each with maximum values 0.5, rem how much can we overlap them vertically? @rem @rem Updated: @rem 11-August-2022 for IM v7 @rem @if "%2"=="" findstr /B "rem @rem" %~f0 & exit /B 1 @setlocal enabledelayedexpansion @call echoOffSave call %PICTBAT%setInOut %1 ws set INFILE1=%1 set INFILE2=%2 set WW1= for /F "usebackq" %%L in (`%IMG7%magick identify ^ -format "WW1=%%w\nHH1=%%h" ^ %INFILE1%`) do set %%L if "%WW1%"=="" exit /B 1 set WW2= for /F "usebackq" %%L in (`%IMG7%magick identify ^ -format "WW2=%%w\nHH2=%%h" ^ %INFILE2%`) do set %%L if "%WW2%"=="" exit /B 1 echo %WW1%x%HH1% %WW2%x%HH2% set MIN_H=%HH1% if %MIN_H% GTR %HH2% set MIN_H=%HH2% set N=0 :loop set /A N+=1 for /F "usebackq" %%L in (`%IMG7%magick ^ ^( %INFILE1% ^ -gravity South ^ -crop %WW1%x%N%+0+0 +repage ^) ^ ^( %INFILE2% ^ -gravity North ^ -crop %WW2%x%N%+0+0 +repage ^) ^ -gravity Center ^ -compose Add -composite ^ -format "mx=%%[fx:maxima]\nIsWhite=%%[fx:(maxima>0.55)?1:0]" ^ info:`) do set %%L if %N% LSS %MIN_H% if %IsWhite%==0 goto loop rem FIXME: Do we need a limit? set /A N-=1 set /A gy=%HH1%-%N% set /A gx=(%WW1%-%WW2%)/2 echo N=%N% call echoRestore @endlocal & set wsNover=%N%& set wsGX=%gx%& set wsGY=%gy%
rem From text file %1, rem make image up to %2 pixels wide. rem Output to %3. @rem @rem Updated: @rem 6-August-2022 for IM v7 @rem @if "%3"=="" findstr /B "rem @rem" %~f0 & exit /B 1 @setlocal enabledelayedexpansion @call echoOffSave call %PICTBAT%setInOut %1 taw set WW=%2 if "%WW%"=="." set WW= if "%WW%"=="" set WW=300 if not "%2"=="" if not "%2"=="." set OUTFILE=%3 set SCR_FILE=textaw.scr echo xc: +delete >%SCR_FILE% echo off ( for /F "tokens=*" %%L in (%INFILE%) do ( echo -size %WW%x label:"%%L" ) echo -trim +repage +write info: -verbose -gravity Center -append +write "%OUTFILE%" ) >>%SCR_FILE% echo on %IMG7%magick -script %SCR_FILE% type %SCR_FILE% call echoRestore @endlocal & set tawOUTFILE=%OUTFILE%
rem From text file %1, rem make image up to %2 pixels wide. rem Text will be black, on transparent background. rem Squishes, with extra gap %3. rem Output to %4. @rem @rem Updated: @rem 6-August-2022 for IM v7 @rem @if "%1"=="" findstr /B "rem @rem" %~f0 & exit /B 1 @setlocal enabledelayedexpansion @call echoOffSave call %PICTBAT%setInOut %1 taws set WW=%2 if "%WW%"=="." set WW= if "%WW%"=="" set WW=300 set deltaY=%3 if "%deltaY%"=="." set deltaY= if "%deltaY%"=="" set deltaY=0 if not "%4"=="" set OUTFILE=%4 set TMP0=taws_tmp0.miff set TMP1=taws_tmp1.miff set N=0 for /F "tokens=*" %%L in (%INFILE%) do ( if !N!==0 ( %IMG7%magick -background None -size %WW%x label:"%%L" -trim +repage %TMP0% ) else ( %IMG7%magick -background None -size %WW%x label:"%%L" -trim +repage %TMP1% call %PICTBAT%squishAppend %TMP0% %TMP1% %deltaY% %TMP0% ) set /A N+=1 ) %IMG7%magick %TMP0% %OUTFILE% call echoRestore @endlocal & set tawOUTFILE=%OUTFILE%
rem Given string %1 (possibly quoted) rem makes image approx %2 pixels wide rem then squishes characters with gap %3 rem Output to image %4. rem rem Also uses: rem sqsSPACE_GAP Gap to be used when previous character is space. [0] @if "%~1"=="" findstr /B "rem @rem" %~f0 & exit /B 1 @setlocal enabledelayedexpansion @call echoOffSave rem call %PICTBAT%setInOut %1 sqs set STR=%1 set strNq=%~1 set WW=%2 if "%WW%"=="." set WW= if "%WW%"=="" set WW=300 set GAP=%3 if "%GAP%"=="." set GAP= if "%GAP%"=="" set GAP=0 set OUTFILE=%4 if "%OUTFILE%"=="." set OUTFILE= if "%OUTFILE%"=="" set OUTFILE=sqs_out.png if "%sqsSPACE_GAP%"=="" set sqsSPACE_GAP=0 set LETTERS_MIFF=sqs_your.miff set OUT_MIFF=sqs_out.miff for /F "usebackq" %%L in (`%IMG7%magick ^ -size 300 label:%STR% -format "PNT_SZ=%%[label:pointsize]" ^ info:`) do set %%L set N=0 set sLABELS= :loop set C=!strNq:~%N%,1! if defined C ( set sLABELS=%sLABELS% label:"%C%" set /A N+=1 goto loop ) echo N=%N% sLABELS=%sLABELS% %IMG7%magick ^ -pointsize %PNT_SZ% ^ -background None ^ %sLABELS% ^ -rotate 90 ^ %LETTERS_MIFF% set /A Nm1=%N%-1 set PREV_SP=0 for /L %%I in (1,1,%Nm1%) do ( if %%I==1 ( set fZero=%LETTERS_MIFF%[0] ) else ( set fZero=%OUT_MIFF% ) set GP=%GAP% if !PREV_SP!==1 ( set GP=%sqsSPACE_GAP% set PREV_SP=0 ) set C=!strNq:~%%I,1! if "!C!"==" " set PREV_SP=1 call %PICTBAT%squishAppend ^ !fZero! ^ %LETTERS_MIFF%[%%I] ^ !GP! ^ %OUT_MIFF% ) %IMG7%magick %OUT_MIFF% -rotate -90 %OUTFILE% call echoRestore @endlocal & set sqsOUTFILE=%OUTFILE%
All images on this page were created by the commands shown, using:
%IMG7%magick -version
Version: ImageMagick 7.1.0-42 Q16-HDRI x64 396d87c:20220709 https://imagemagick.org Copyright: (C) 1999 ImageMagick Studio LLC License: https://imagemagick.org/script/license.php Features: Cipher DPC HDRI OpenCL Delegates (built-in): bzlib cairo freetype gslib heic jng jp2 jpeg jxl lcms lqr lzma openexr pangocairo png ps raqm raw rsvg tiff webp xml zip zlib Compiler: Visual Studio 2022 (193231332)
To improve internet download speeds, some images may have been automatically converted (by ImageMagick, of course) from PNG or TIFF or MIFF to JPG.
Source file for this web page is squishimg.h1. To re-create this web page, run "procH1 squishimg".
This page, including the images, is my copyright. Anyone is permitted to use or adapt any of the code, scripts or images for any purpose, including commercial use.
Anyone is permitted to re-publish this page, but only for non-commercial use.
Anyone is permitted to link to this page, including for commercial use.
Page version v1.0 31-March-2016.
Page created 24-Aug-2022 20:54:49.
Copyright © 2022 Alan Gibson.