Combine images with ImageMagick using Applescript in Automator - shell

So i have a PDF file and i'm using Automator to generate JPG files from each slide. Then i want to loop through each of these images and create side-by-side photos from them. So page 1 and page 2 will create an image, then page 3 and 4 too, and so on... I have an Applescript action so far where the input is all of the image files:
on run {input, parameters}
set selectedFiles to {}
repeat with i in input
copy (POSIX path of i) to end of selectedFiles
end repeat
return selectedFiles
end run
The function what i want to do is this, which is an ImageMagick function two merge to images next to eachother:
do shell script "convert " +append 01.jpg 02.jpg 01&2.jpg
How can i add this function inside my Applescript above?
Or maybe it would be easier to do with Shell script?

I'm in a bit of rush so not my best piece of code, but you can do it in bash like this:
#!/bin/bash
# pdfsheets
#
# Passs the name of a PDF as parameter and get it as a bunch of double-page spreads called "sheet-0.jpg" ... "sheet-n.jpg"
#
# Pick up parameter
pdf=$1
echo "Processing document: $pdf"
# Split document into individual pages each as JPEG
convert "$pdf" page-$$-%03d.jpg
# Get names of pages into array and see how many we got
pages=( $(ls page-$$-*.jpg) )
npages=${#pages[#]}
echo DEBUG:npages:$npages
# Check if odd number of pages - synthesize empty white one at end if odd
if [ $((npages%2)) -ne 0 ]; then
lastpage=${pages[#]:(-1)}
echo DEBUG:lastpage:$lastpage
newlast=$(printf "page-$$-%03d.jpg" $npages)
convert "$lastpage" -threshold -1 $newlast
pages=( $(ls page-$$-*.jpg) )
npages=${#pages[#]}
fi
s=0
for ((i=0;i<npages;i+=2)) do
a=${pages[i]}
b=${pages[((i+1))]}
out=$(printf "sheet-%d.jpg" $s)
echo Converting $a and $b to $out
convert $a $b +append $out
((s++))
done
Run it like this and get output as follows:
./pdfsheets document.pdf
Processing document: document.pdf
DEBUG:npages:5
DEBUG:lastpage:page-49169-004.jpg
Converting page-49169-000.jpg and page-49169-001.jpg to sheet-0.jpg
Converting page-49169-002.jpg and page-49169-003.jpg to sheet-1.jpg
Converting page-49169-004.jpg and page-49169-005.jpg to sheet-2.jpg

Related

shell - How to define a variable in a C-type for loop?

I want to iterate over an array of file names stored in files_arr to create a terminal-based file manager in the POSIX shell.
A reduced version of the functions list_directory looks like this:
# Presents the user with the files in the directory
list_directory() {
# Iterate over each element in array `files_arr` by index, not by filename!
# And outputs the file name one on each line
for file in "${!files_arr[#]}"; do
echo "${files_arr[file]}"
done
}
I want to implement a way to exclude the first n files from the array files_arr.
n is defined by how often the user scrolls past the current terminal window size to create an effect of scrolling through the files, highlighting the file where the cursor is currently on.
On a directory (e.g. the home directory) that looks like this:
To Implement this I try to create an C-like for loop like so:
for ((file=$first_file; file<=${!files_arr[#]}; file=$((file+1))); do
or as the whole function:
# Presents the user with the files in the directory
list_directory() {
# Iterate over each element in array `files_arr` by index, not by filename!
#for file in "${!files_arr[#]}"; do
for ((file=$first_file; file<=${!files_arr[#]}; file=$((file+1))); do
# Highlighted file is echoed with background color
if [ $file -eq $highlight_index ]; then
echo "${BG_BLUE}${files_arr[file]}${BG_NC}"
# Colorize output based on filetype (directory, executable,...)
else
if [ -d "${files_arr[file]}" ]; then
echo "$FG_DIRECTORY${files_arr[file]}$FG_NC"
elif [ -x "${files_arr[file]}" ]; then
echo "$FG_EXECUTABLE${files_arr[file]}$FG_NC"
else
echo "${files_arr[file]}"
fi
fi
# $LINES is the terminal height (e.g. 23 lines)
if [ "$file" = "$LINES"]; then
break
fi
done
}
which returns the error:
./scroll.sh: line 137: syntax error near `;'
./scroll.sh: line 137: ` for ((file=$first_file; $file<=${!files_arr[#]}; file=$((file+1))); do'
How can I iterate over the array files_arr, defining the start-index of $file?
You can iterate over the array with:
for (( i = $first_file; i < ${#files_arr[#]}; i++ )); do
echo ${files_arr[i]}
done
but it seems cleaner to use:
for file in ${files_arr[#]:$first_file}; do
echo "$file"
done

How can I pass a variable as a string into a function in bash?

I have a small bash script that does simple file modifications and I want to rewrite the code to be more readable. My goal is to pass Commands as strings into a function that loops the command over a Directory.
I've tried to use different methods to escape the "$" or different """ combinations but none really work.
#!/bin/bash
process="/Users/Gernot/Tools/.Process"
output="/Users/Gernot/Tools/2 Output"
input="/Users/Gernot/Tools/1 Input/"
function run {
for file in "$input$1"/*
do
echo "running procedure $1" #echoes which procedure is running
$2 #does the command for every file in the directory
done
}
run "PDF Komprimieren" "magick convert \$file -density 110 -compress jpeg -quality 100 \$file"
This is the error I get:
running procedure PDF Komprimieren
convert: unable to open image '$file': No such file or directory # error/blob.c/OpenBlob/3497.
convert: no decode delegate for this image format `' # error/constitute.c/ReadImage/556.
convert: no images defined `$file' # error/convert.c/ConvertImageCommand/3273.
Try using functions like
pdf_komprimieren() {
find "PDF Komprimieren" -maxdepth 2 -type f -print0 |
xargs --null -n1 -Ifile magick convert "file" -density 110 -compress jpeg -quality 100 "file"
}

A bash script to split a data file into many sub-files as per an index file using dd

I have a large data file that contains many joint files.
It has an separate index file has that file name, start + end byte of each file within the data file.
I'm needing help in creating a bash script to split the large file into it's 1000's of sub files.
Data File : fileafilebfilec etc
Index File:
filename.png<0>3049
folder\filename2.png<3049>6136.
I guess this needs to loop through each line of the index file, then using dd to extract the relevant bytes into a file. Maybe a fiddly part might be the folder structure bracket being windows style rather than linux style.
Any help much appreciated.
while read p; do
q=${p#*<}
startbyte=${q%>*}
endbyte=${q#*>}
filename=${p%<*}
count=$(($endbyte - $startbyte))
toprint="processing $filename startbyte: $startbyte endbyte: $endbyte count: $c$
echo $toprint
done <indexfile
Worked it out :-) FYI:
while read p; do
#sort out variables
q=${p#*<}
startbyte=${q%>*}
endbyte=${q#*>}
filename=${p%<*}
count=$(($endbyte - $startbyte))
#let it know we're working
toprint="processing $filename startbyte: $startbyte endbyte: $endbyte count: $c$
echo $toprint
if [[ $filename == *"/"* ]]; then
echo "have found /"
directory=${filename%/*}
#if no directory exists, create it
if [ ! -d "$directory" ]; then
# Control will enter here if $directory doesn't exist.
echo "directory not found - creating one"
mkdir ~/etg/$directory
fi
fi
dd skip=$startbyte count=$count if=~/etg/largefile of=~/etg/$filename bs=1
done <indexfile

extract raster and vector images from pdf with a bash script

I needed a bash script which extracts all the raster and vector images from the pdf and convert them to jpg format.
I checked many posts on the web and I got most of the ideas from these
How can I extract images from a PDF file?
Count the number of the raster images in the pdf
How to extract a vector figure from pdf?
It works and I share it because I didn't find a solution on the web like this.
But there are 2 small issues that I couldn't fix so far.
If there is a page with texts then pdf2svg will determine the texts as vector images and will generate an extra image with the texts.
Is there any way to distinguish the text from the real vector images?
If there are multiple vector images on one page then pdf2svg will generate one SVG image which contains all the vector images (same like a page contains text). Is it possible to extract them into separated images?
the bash script
#!/bin/bash
TMP_DIR=$1
SOURCE_PDF=$2
MAX_WIDTH=1920
MAX_HEIGHT=1080
echo "source: $SOURCE_PDF"
function burst
{
local source=$1
# explodes the pages to pdf files (it is necessary for the vector images export)
`/usr/bin/pdftk $source burst`
# removes the source pdf (we do not need it any more)
`rm $source`
# and the txt files which were generated by the pdftk
`rm *.txt`
}
# finds the pages as pdf files and call check_for_images function
function process_pages {
local tmp_dir=$1
local pnum=1
for f in `find . -type f -name "*.pdf"`
do
echo "processing page $f"
check_for_images $f $pnum
let "pnum++"
done
}
function check_for_images {
local pdf_page=$1
local pnum=$2
# checks whether the page contains a raster image
list_raster_images=`/usr/bin/pdfimages -list $pdf_page | grep -E "(jpeg|png|gif)"`
is_raster_images=${#list_raster_images}
if (( $is_raster_images > 0 )); then
# it contains raster image(s), extract them
extract_raster_images $pdf_page $pnum
else
# it does not contain raster image(s), try to extract vector images
extract_vector_images $pdf_page $pnum
fi;
rm $pdf_page
}
function extract_raster_images {
local pdf_page=$1
local pnum=$2
pdf_file="${pdf_page%.*}"
echo "extract all raster image(s) from this page";
`/usr/bin/pdfimages -all $pdf_page ./`
# we need to use a very same file name convention so this part renames them
# who knows it might be useful later
for f in `find . -regextype sed -regex ".*/-[0-9]\{3\}\.jpg"`
do
path=$(dirname $f)
img_file=$(basename $f)
img_ext="${img_file##*.}"
img_num="${img_file%.*}"
mv $f $path/$pdf_file$img_num.$img_ext
done
}
function extract_vector_images {
local pdf_page=$1
local pnum=$2
pdf_file="${pdf_page%.*}"
echo "extract vector image from the page as SVG"
`/usr/bin/pdf2svg $pdf_page $pdf_page.svg`
# just to be sure it is not a raster image
is_raster_image=`grep -c -i "data:image" $pdf_page.svg`
if (( $is_raster_images == 0 )); then
# convert SVG to PNG (it doesn't know JPG format) with fixed sizes, but keep the aspect ratio
`/usr/bin/rsvg-convert -a -w $MAX_WIDTH -h $MAX_HEIGHT -f png -o $pdf_page.png $pdf_page.svg`
# convert PNG to JPG
`convert $pdf_page.png -background white -flatten -alpha off $pdf_file-000.jpg`
fi;
`rm *.svg`
`rm *.png`
}
cd $TMP_DIR
burst $SOURCE_PDF
process_pages $TMP_DIR
executing it from php
$tmpName = basename($file['tmp_name']);
$tmpDir = '/path-of-tmp-dir' . $tmpName . '_extraction';
mkdir($tmpDir);
$command = "extract_pdf_images.sh $tmpDir ".$file['tmp_name'];
exec($command);
requirements
apt-get install pdftk pdfimages pdf2svg librsvg2-bin imagick

How do you find the paths of linked images in Adobe Illustrator 9? [closed]

Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 10 years ago.
Improve this question
I have an Illustrator file with linked images. I'd actually like to instead embed the images. I first have to know which files they are. How do I find out? I'm using Illustrator 9.
The first Illustrator version I ever used was 10, but, is there a links pallete in version 9? Try the window menu and look for "links". It has a few options there to search for the image you want, relink, open the original, etc.
Great to know the poster is set, but this doesn't answer the question. In CS3, if you double-click on the image in links palette, ti will bring up Link Info for the linked element, which shows the path to the file (provided it isn't longer than the window).
Maybe the older versions allow you to do this too.
Unfortunately, if you're dealing with a missing link element (which you ignored to fix upon opening the file), this field is blank. Illustrator sucks in comparison to InDesign for file packaging and linking. It would be nice if it could package files like InDesign, and store relative references to the external resources.
With newer versions of Illustrator you might be able to replace links to broken images using this script:
http://techblog.willshouse.com/2011/01/16/update-illustrator-linked-files-script/
I just had this problem in Illustrator CS4; a lot of my stuff was archived recently.
Click on the "missing" image in the artboard.
In the top left you will see the file name displayed.
Click "edit original" in the subsequent drop down menu. Illustrator will attempt to find the file, and flash a warning window "windows cannot find file" etc giving you the full file location.
This is useful as edit original is greyed out in the links window. And very useful for people like me who have a vast library of files.
I use the following perl script to keep track of linked images in Illustrator files. This is especially helpful for broken links, because it will still tell you the full path to the linked image by peeking inside the Illustrator file. It obviously does more than anyone here needs, but perhaps it will be useful. The help should explain how to use it. On my machine I have called it ailinkedfiles.pl and I have put it in ~/bin which is in my PATH.
#!/usr/bin/perl
# program to find the linked files inside an Adobe Illustrator file
require 5.004;
use File::Basename; # to extract a filename from a full path
use File::Find; # to build a list of files
use File::Spec; # Platform independent way to build paths
use vars qw/ %opt /; # for command line options - see init()
use strict;
init(); # process command line options
# Autoflush stdout
$|=1;
if ($opt{p}){
die "Did you really mean to call your script ".$opt{p}."!\n" if($opt{p} =~ /\.ai$/i);
print "Generating script file $opt{p}\n" if $opt{v};
open SCRIPT, "> $opt{p}";
}
die "No input specified; use ".basename($0)." -h for help\n" if(#ARGV==0);
my $arg; foreach $arg (#ARGV){
if(-d $arg){
# nb it is necesary to convert the directory specification
# to an absolute path to ensure that the open in &findLinkedFiles
# works properly during multi directory traversal
my $InDir=File::Spec->rel2abs($arg);
find(\&handleFind,$InDir);
} elsif (-f $arg) {
my $InDir=File::Spec->rel2abs(dirname($ARGV[0]));
&findLinkedFiles(File::Spec->rel2abs($ARGV[0]),$InDir) ;
# &findLinkedFiles(File::Spec->rel2abs($arg)) ;
}
}
sub init()
# copied from: http://www.cs.mcgill.ca/~abatko/computers/programming/perl/howto/getopts
{
use Getopt::Std; # to handle command line options
my $opt_string = 'hvlzdsftnp:ux:';
getopts( "$opt_string", \%opt ) or usage();
usage() if $opt{h};
}
# Print out usage information
sub usage()
{
print STDERR << "EOF";
Usage: $0 [OPTIONS] <AIFILE/DIR>
Parse an Adobe Illustrator file or (recursively) parse a directory of ai files
and print a list of the linked files to STDOUT. These could be piped to xargs eg:
$0 aifile.ai | xargs -I {} ln -vs
-h print this help
-v verbose ouput
-s print file names with short path
-d print current directory on each line
-n no-print (suppresses printing of linked file names)
-x <regex> exclude files whose full path matches regex
-l symlink in current directory if file linked from Illustrator file exists somewhere else
-f force symlink to overwrite existing target file
-t test run
-p <file> write commands to a script file
-u status of src and target
- doesn't exist
F plain file
L symbolic link
E exists (unknown file type)
Note that src is the link contained in the Illustrator file and
target is a file of the same name in the same directory as the Illustrator file
If the status is -- you will have problems in Illustrator
If the status is -F Illustrator will substitute the local file for the unavailable linked file
If the status is F- you can run this script with the -s option to make a symlink
If the status is FF then Illustrator will be happy
EOF
exit();
}
sub mysymlink{
my ($src,$targetdir)=#_;
my $target=File::Spec->catdir($targetdir,basename($src));
if(File::Spec->rel2abs($src) eq File::Spec->rel2abs($target)){
print "src and target identical for src=$src\n" if $opt{v};
return;
}
if(-e $src){
my $opts=$opt{f}?"-fsv":"-sv";
my $cmd="ln $opts \"$src\" \"$target\"";
myexec("$cmd");
} else {
print "No link made: $src doesn't exist\n" if $opt{v};
}
}
sub myexec {
my ($cmd) = #_;
if ($opt{t}){
print STDERR "test: $cmd\n";
} elsif ($opt{p}){
print SCRIPT $cmd,"\n";
} else {
# should get to see output with system
print STDERR "run: $cmd\n" if $opt{v};
return system $cmd;
}
}
sub mystatus{
my ($src,$targetdir)=#_;
my $target=File::Spec->catdir($targetdir,basename($src));
my ($ss,$ts)=("-","-");
$ss = "E" if(-e $src);
$ss = "F" if(-f $src);
$ss = "L" if(-l $src);
$ts = "E" if(-e $target);
$ts = "F" if(-f $target);
$ts = "L" if(-l $target);
return ($ss.$ts);
}
# This extracts the file info from the header
sub handleFind{
# get the file name
my $FullFoundFile = $File::Find::name;
#print $FullFoundFile,"\n";
return if ($opt{x} and $FullFoundFile =~ /$opt{x}/i);
# parse if it ends in ai
findLinkedFiles($FullFoundFile, $File::Find::dir) if ($FullFoundFile =~ /\.ai$/i);
}
# This does the actual parsing of the Illustrator Files
sub findLinkedFiles{
my ($InFile,$InDir)=#_;
# protect with escaped quotes for shell if non-empty
my $ProtectedInDir=$InDir?"\"$InDir\"":$InDir;
die "Can't open $InFile \: $!\n" unless open(AIFILE, "<$InFile");
binmode(AIFILE);
# %%DocumentFiles is the starting point
$/="%%";
my #lines = readline<AIFILE>;
if(#lines==0){
print STDERR "can't read header of $InFile\n" if $opt{v} ; # the header length
return;
}
print "################\n";
if ($opt{s}){
print "# FILE = ",basename($InFile),"\n";
} else {
print "# FILE = ",$InFile,"\n";
}
for my $i ( 0 .. $#lines ){
# if ( $lines[$i]=~/^DocumentFiles\:(.*?)\W+%%/){
# not sure why we need two % signs here
if ( $lines[$i]=~/^DocumentFiles\:(.*?)\W+%/){
print mystatus($1,$InDir)," " if $opt{u} and not $opt{n};
print "\"$1\" ",$opt{d}?$ProtectedInDir:"","\n" unless $opt{n};
$i++;
mysymlink($1,$InDir) if $opt{l};
while($lines[$i]=~/^[+](.*?)\W\%.*$/){
# print "\"$1\" $InDir\n"; $i++;
print mystatus($1,$InDir)," " if $opt{u} and not $opt{n};
print "\"$1\" ",$opt{d}?$ProtectedInDir:"","\n"unless $opt{n};
$i++;
mysymlink($1,$InDir) if $opt{l};
}
}
}
}

Resources