Creating multiple thumbnails in ImageMagick / GraphicsMagick - imagemagick

I'm currently writing a shellscript for Bash, that will create different size thumbnails for some rather massive amounts of large images.
I was wondering if it's possible to get GM/IM to create multiple sizes of thumbs in one run, to avoid loading the same image over and over again to create different thumbnails, thus saving memory and time in executing the script ?

According to this post you can use -write filename with GraphicsMagick to "write the current image to the specified filename and then continue processing ... to produce the various smaller sizes while reading the original image just once".

You can do it with the ImageMagick Perl bindings, or bindings into any other language of your choice:
#!/usr/bin/perl
use Image::Magick;
my($image, $x);
$image = Image::Magick->new;
$x = $image->Read('sars.png');
warn "$x" if "$x";
$x = $image->Resize(geometry=>'600x600');
warn "$x" if "$x";
$x = $image->Write('x.png');
warn "$x" if "$x";
$x = $image->Resize(geometry=>'400x400');
warn "$x" if "$x";
$x = $image->Write('y.png');
warn "$x" if "$x";
$x = $image->Resize(geometry=>'100x100');
warn "$x" if "$x";
$x = $image->Write('z.png');
warn "$x" if "$x";
The conjure command supports an XML-formatted Magick Scripting Language, but it's harder on my eyes than the Perl version, and the documentation on the Perl bindings is definitely better.

Related

How can I access a memory mapped device, synthesized on fpga, with a Lauterbach script?

on a ZCU106 board with MPSoC Zynq Ultrascale+, I have developed a simple test application that performs reads and writes to a memory-mapped device register. The device in question is a GPIO peripheral, synthesized to fpga and accessed in memory with address (0xA0010000) configured via Vivado tool. The application does not use MMU. If I try to launch and run my application from the Vitis debugger, everything works correctly, with no problems. However, I need to launch the application from Lauterbach's Trace32. By doing the launch with a practice script (Lauterbach's scripting language), the application loads correctly, but upon reading or writing to the memory address where the synthesized device is mapped to fpga, a "debug port fail" type problem is returned. I therefore analyzed the tcl script automatically generated by Vitis to see if there are any hardware configurations that are made in tcl, but which I do not predict with the practice script (Lauterbach). My suspicion is that there are special instructions to enable the mapping of memory addresses that a processor can access. I attach the tcl script generated by Vitis, perhaps the "offending" instruction is the 'loadhw -hw'? Thanks in advance to anyone who can help me.
# In Vitis IDE create a Single Application Debug launch configuration,
# change the debug type to 'Attach to running target' and provide this
# tcl script in 'Execute Script' option.
# Path of this script: /home/daniele/vitis_workspace/interr_measurement_test_system/_ide/scripts/debugger_interr_measurement_test-default.tcl
#
#
# Usage with xsct:
# To debug using xsct, launch xsct and run below command
# source /home/daniele/vitis_workspace/interr_measurement_test_system/_ide/scripts/debugger_interr_measurement_test-default.tcl
#
connect -url tcp:127.0.0.1:3121
source /tools/Xilinx/Vitis/2021.2/scripts/vitis/util/zynqmp_utils.tcl
targets -set -nocase -filter {name =~"APU*"}
rst -system
after 3000
targets -set -filter {jtag_cable_name =~ "Xilinx HW-FTDI-TEST FT232H 49619" && level==0 && jtag_device_ctx=="jsn-HW-FTDI-TEST FT232H-49619-14730093-0"}
fpga -file /home/daniele/vitis_workspace/interr_measurement_test/_ide/bitstream/zcu106_int_meas_plat_wrapper.bit
targets -set -nocase -filter {name =~"APU*"}
loadhw -hw /home/daniele/vitis_workspace/zcu106_int_meas_plat_wrapper/export/zcu106_int_meas_pp
lat_wrapper/hw/zcu106_int_meas_plat_wrapper.xsa -mem-ranges [list {0x80000000 0xbfffffff} {0x400000000 0x5ffffffff} {0x1000000000 0x7fffffffff}] -regs
configparams force-mem-access 1
targets -set -nocase -filter {name =~"APU*"}
set mode [expr [mrd -value 0xFF5E0200] & 0xf]
targets -set -nocase -filter {name =~ "*A53*#0"}
rst -processor
dow /home/daniele/vitis_workspace/zcu106_int_meas_plat_wrapper/export/zcu106_int_meas_plat_wrapper/sw/zcu106_int_meas_plat_wrapper/boot/fsbl.elf
set bp_30_4_fsbl_bp [bpadd -addr &XFsbl_Exit]
con -block -timeout 60
bpremove $bp_30_4_fsbl_bp
targets -set -nocase -filter {name =~ "*A53*#0"}
rst -processor
dow /home/daniele/vitis_workspace/interr_measurement_test/Debug/interr_measurement_test.elf
configparams force-mem-access 0
bpadd -addr &main

Automatically generate random compositions by layering source images **without creating duplicates**

This is a follow on from this question asked by ign and expertly answered by Marc Setchell
It works perfectly, though I am hoping to find a way to avoid duplicates forming in the randomisation process. I am going to be doing hundreds of variations of a bunch of layers, with subtle differences, so I can't really go in and spot duplicates in a fail-safe way.
Here is the code I'm using, as per above - all credit to Marc Setchell!
#!/bin/bash
# Number of output files - edit freely :-)
NFILES=10
# Build arrays of filenames in each layer, assume directories are "Layer0", "Layer1" etc
IFS=$'\n' L0files=($(find "Layer 0" -name "*.png"))
IFS=$'\n' L1files=($(find "Layer 1" -name "*.png"))
IFS=$'\n' L2files=($(find "Layer 2" -name "*.png"))
IFS=$'\n' L3files=($(find "Layer 3" -name "*.png"))
# Produce NFILES output files
for i in `seq 1 $NFILES`; do
# Choose random index into each array of filenames
index0=$( jot -r 1 0 $((${#L0files[#]} - 1)) )
index1=$( jot -r 1 0 $((${#L1files[#]} - 1)) )
index2=$( jot -r 1 0 $((${#L2files[#]} - 1)) )
index3=$( jot -r 1 0 $((${#L3files[#]} - 1)) )
# Pick up files as specified by the random index
f0=${L0files[index0]}
f1=${L1files[index1]}
f2=${L2files[index2]}
f3=${L3files[index3]}
# Generate output filename, "output-nnn.png"
# ... where nnn starts at 0 and goes up till no clash
i=0
while :; do
out="output-$i.png"
[ ! -f "$out" ] && break
((i++))
done
echo $f0, $f1, $f2, $f3 "=> $out"
convert "$f0" "$f1" -composite "$f2" -composite "$f3" -composite "$out"
done
IMHO nothing to do with IM or PS. Just name your files so that they include the index of the layers you are using to create them, and skip if you see that you are creating the same file again.
out="output-$index0-$index1-$index2-$index3.png"
[[ ! -f "$out" ]] && continue
((i++))
This also requires that you don't use seq 1 $NFILES to iterate your files since you want to increment the counter only when you don't skip(*).
When you are done you rename your files to a sequence, if necessary.
Another method in bash is to declare an associative array and put an element in it for each file that you create:
# declare associative array
declare -A doneFiles
# when creating a file:
combination=$index0-$index1-$index2-$index3
donefiles[$combination]="done" # or any info
# testing:
[[ -n ${doneFiles[$combination]} ]] && continue # already done
(*) By the way using i for both the outer and inner loops is crazy even if you don't use the outer variable explicitly. But then the inner loop is terrible code, since you can use the outer i.

Convert multiple images with ImageMagick

I want to convert all my PNGs to PNG using ImageMagick (I need this because AndroidStudio has some issue with the original PNGs. ImageMagick is able to fix this issue by re-exporting the PNG.)
If I do: convert a.png a.png it works.
But how do I do this for many files (including files from sub directories)?
For Windows users -- you can try this in a cmd.exe window:
for %i in (*.png *\*.png *\*\*.png *\*\*\*.png) do (
convert.exe %i %~pni---repaired.png
)
This will loop through the current dir's PNGs as well as the ones in the sub directories 3 levels deep.
You have to make sure that your convert.exe really is the one from ImageMagick -- set up your environment variable %PATH% accordingly. Otherwise you may run into an error when the command wants to use the identically named disk format conversion convert.exe command.
If unsure, use the full path to the IM convert.exe, e.g.:
D:\programs\imagemagick-install-dir\convert.exe %i %~pni---repaired.png
Also, remember: If you put the above command into a *.bat file, you have to double up each occurrence of %. So %i from the direct command becomes %%i in the batch file!
If you are on Vista/Windows7/2008/8 (or on Windows XP with the Resource Kit installed) you'll have the ForFiles.exe available, which can be used to loop through files:
forfiles.exe ^
/p <path> ^
/m *.png ^
/s ^
/C "convert.exe #file #fname---repaired.png"
Try this command. Start it from the top-most directory from where you want to convert all images:
find . -name "*.png" \
| while read image; do \
convert "${image}" "${image/.png/---repaired.png}
done
Caveats: Should you have PNG files with the suffix .PNG or .pNg or similar, the command will not work for these. For such cases, the command needs some modifications...

Creating a tar stream of arbitrary data and size

I need to create an arbitrarily large tarfile for testing but don't want it to hit the disk.
What's the easiest way to do this?
You can easily use python to generate such a tarfile:
mktar.py:
#!/usr/bin/python
import datetime
import sys
import tarfile
tar = tarfile.open(fileobj=sys.stdout, mode="w|")
info = tarfile.TarInfo(name="fizzbuzz.data")
info.mode = 0644
info.size = 1048576 * 16
info.mtime = int(datetime.datetime.now().strftime('%s'))
rand = open('/dev/urandom', 'r')
tar.addfile(info,rand)
tar.close()
michael#challenger:~$ ./mktar.py | tar tvf -
-rw-r--r-- 0/0 16777216 2012-08-02 13:39 fizzbuzz.data
You can use tar with -O option tar -O, like this tar -xOzf foo.tgz bigfile | process
https://www.gnu.org/software/tar/manual/html_node/Writing-to-Standard-Output.html
PS: However, it could be, that you will not get the benefits you intend to gain as tar starts writing stdout only after it has read through the entire compressed file. You can demonstrate this behavior by starting a large file extraction and following the file size over time; it should be zero most of the processing time and start growing at very late stage. On the other hand I haven't researched this extensively, there might be some work around, or I might be just plain wrong with my first hand out-of-memory experience.

How to find the path to ImageMagick config files

I'm attempting to load a ICM color profile file that is stored with the main ImageMagick config files (colors.xml, etc.) using RMagick. I want to make sure that I always provide the correct path to the file across deployments using slightly different ImageMagick setups and/or versions. Is there a way to find to get this location from ImageMagick (something like Magick-config)?
This is what I have now, but it seems brittle:
MAGICK_PREFIX = `Magick-config --prefix`.strip!
MAGICK_VERSION = `Magick-config --version`.strip!.split(/\s/).first
RGB_COLOR_PROFILE = "#{MAGICK_PREFIX}/share/ImageMagick-#{MAGICK_VERSION}/config/sRGB.icm"
I have no perfect anwser, but you can
$ convert -list color | grep Path: | awk '{print $2}'
/usr/lib/ImageMagick-6.3.7/config/colors.xml
If response is [built-in] try another -list value.
try these and parse stdout / stderr. the first one should work always
convert -debug configure rose: info:
convert -list configure

Resources