1

I am running Ubuntu 18.04. I have a directory full of storyboard images in .jpg format as below.

image-0000.jpg
image-0001.jpg
image-0002.jpg
image-0003.jpg
image-0004.jpg
.
.
image-3898.jpg
image-3899.jpg

Merging 13 images vertically gives me a Single page. So I think I need to use below command, using a range of 13 numbers at a time in a loop and save to a directory "./Merged".

convert -append image-{range of 13}.jpg ./Merged/page_001.jpg

My experiment and thought process is as below.

I am trying to use a nested for loop and seq -w as below. But I am unable understand, how to loop the scrip in such a way that it takes first 13 files (from image-0000 to image-0012), merges them and saves in the ./Merged/ folder. Then come out of the loop and again take the next 13 files (from image-0013 to image-0025) and so on. Till all .jpg files in the current folder are finished or till 300 pages are generated.

My Script

#!/bin/bash

# As 3899 image slices will be converted to 300 pages
# I thought to run for loop 300 times

for ((page=1; page<=300; page++))
do
   # As images are slices of pages.
   for slices in $(seq -w 0 3899)
   do

    # We need to merge 13 times so...
    # Should i use for loop with increment as below?
    # for ((smerge=1; smerge<=13; smerge++))
    # do
    #   convert "SOME LOGIC" ./Merged/page_001.jpg
    # done

    # **OR**
    # somehow take 13 numbers from sequence

        convert image-$slices_{RANGE}.jpg -append ./Merged/page_$page.jpg 

   done

done
  • Do you "need" to create a nested loop, or would using montage solve the problem for you? – Philip Kendall Jun 12 '18 at 22:56
  • Hello Philip kendall I dont know montage. I think a loop will help. Still i will check montage too. Thanks in advance. – user3025253 Jun 12 '18 at 23:18
  • I checked Montage. it is not for my problem. Still thanks for the quick reply. – user3025253 Jun 13 '18 at 1:30
1

With zsh:

#! /bin/zsh -

typeset -Z3 page
files=(image-<0-3900>.jpg)
for ((page = 1; $#files; page++)) {
  convert $files[1,13] -append ./Merged/page_$page.jpg
  files[1,13]=()
}

Note that since there are 3901 images (13 × 300 + 1), the last page will have only one image.

You can do something similar with bash like:

#! /bin/bash -
shopt -s extglob
shopt -s failglob
set -- image-+([[:digit:]]).jpg
for ((page = 1; $#; page++)) {
  printf -v padded_page %03d "$page"
  convert "${@:1:13}" -append "./Merged/page_$padded_page.jpg"
  (($# > 13)) || break
  shift 13
}

POSIXly, assuming there are matching files and doing a yet less close check on file names:

#! /bin/sh -
set -- image-*.jpg

# disable split+glob, only retain empty removal on unquoted expansions:
set -o noglob; IFS=

page=1; while [ "$#" -gt 0 ]; do
  padded_page=000$page
  padded_page=${padded_page#"${padded_page%???}"}
  convert $1 $2 $3 $4 $5 $6 $7 $8 $9 ${10} ${11} ${12} ${13} \
    -append "./Merged/page_$padded_page.jpg"
  [ "$#" -gt 13 ] || break
  shift 13
  page=$((page + 1))
done

Note that while here the file names are very tamed (no blanks, special characters...), special care has been taken in those codes to handle arbitrary characters. However note that convert and other imagemagick utilities could have problems with file names starting with - (even when using --) or containing :, so best is to prefix file paths with ./ to avoid those problems (for instance, use ./*.jpg instead of *.jpg).

  • Thank you Stéphane Chazelas. I was able to solve yesterday morning. Still I would like to check your solution too. Soon I will post my solution too. – user3025253 Jun 14 '18 at 6:28
  • As the file naming starts from 0000 it ends at 3899, Sorry about that i Corrected it. – user3025253 Jun 14 '18 at 6:36
  • is there anything after IFS= – user3025253 Jun 20 '18 at 14:54
  • @user3025253, no. That's the point. We empty $IFS (the internal field separator), to disable word splitting. – Stéphane Chazelas Jun 20 '18 at 14:59
  • zsh script failed with errors POSIX script is creating only one file "page_001.jpg". Script is working but it is overwriting on to one file. – user3025253 Jun 20 '18 at 15:42
1

So let's say you have these files in a continuous range from image-0000.jpg to image-2999.jpg. This should demonstrate the principle at work here:

#!/bin/bash
for page in {000..001}; do
  echo image-${page}{0..9}.jpg
done

So, do drop this into your use-case:

#!/bin/bash
for page in {000..001}; do
  convert image-${page}{0..9}.jpg --append ./Merged/page-${page}.jpg
done

Note that {01..02} expanding to 01 02 rather than 1 2 requires bash 4.

  • Hi DopeGhoti, Thank you very much. Your solution works with 10 perfectly. But While posting I made a mistake. I need 13 increments. I have corrected my question too. Thanks for your time. – user3025253 Jun 12 '18 at 23:14
0

You can do this using xargs -n argument and push the result to a while read loop.

page=1
while IFS= read -r row; do
    convert $row -append ./Merged/page_$page.jpg
    page=$((page + 1))
done < <(echo image-{0000..3900}.jpg | xargs -n13)
  • Thank you RoVo. I was able to solve yesterday morning. Still I would like to check your solution too. Soon I will post my solution too. – user3025253 Jun 14 '18 at 6:34
  • what is this IFS variable? any special system variable? IFS Means? – user3025253 Jun 16 '18 at 14:14
  • This means internal field separator and defines how word splitting is done. In this case not at all because I unset it. See unix.stackexchange.com/a/184867 – pLumo Jun 17 '18 at 6:49
  • Your Script worked perfectly and took less time than my solution. almost half the time. real 0m7.284s – user3025253 Jun 20 '18 at 16:09
  • But only problem was that I need to keep changing the range, {0000..3899} , for different situations. – user3025253 Jun 20 '18 at 16:14
0

Hello everyone. Thank you very much for your time and replies.

DopeGhoti

Philip Kendall

Stéphane Chazelas

RoVo

This is What I was able to create, and it worked. Still I would like to check others Solution too. Maybe your solution is faster than my basic Script.

NOTE: This Script will/might fail if there are spaces in file names!

only script

#!/bin/bash

# NOTE: This Script will/might fail if there are spaces in file names!

mkdir Finished;
mkdir Merged;

for paGe in $(seq -w 1 300)
do
   ls *.jpg | head -n 13 > filesData.txt;
   paGeData=$(sed ':a;N;$!ba;s/\n/ /g' filesData.txt);
   convert $paGeData -append ./Merged/Page_$paGe.jpg;

   while read -r line
   do
      mv $line ./Finished/
   done < filesData.txt
done

Script with comments

#!/bin/bash

# NOTE: This Script will/might fail if there are spaces in file names!
# I random capitalize letters in a variable to make them unique,
# As i can't be sure.

mkdir Finished;
mkdir Merged;

for paGe in $(seq -w 1 300)
do
   # Selecting only 13 files from the current directory
   ls *.jpg | head -n 13 > filesData.txt;

   # Replace newline (\n) with space and place "file names"
   # in one line and storing "sed" output to a variable.
   # So that we use it with "convert" command.
   paGeData=$(sed ':a;N;$!ba;s/\n/ /g' filesData.txt);

   # Merge different images to one long image
   convert $paGeData -append ./Merged/Page_$paGe.jpg;

   # Move files to different directory,
   # So that we can work with next range/batch of files.
   while read -r line
   do
      mv $line ./Finished/
   done < filesData.txt

done

A long thought process. If someone might be interested in how I tried to improvise the code. This might have some mistakes.

#!/bin/bash

mkdir Finished;
mkdir Merged;

for paGe in $(seq -w 1 300)
do

   # Selecting only 13 files from the current directory
   ls *.jpg | head -n 13 > filesData.txt;

   # Replace newline (\n) with space and
   # place file names in one line for the convert command in while loop
#   sed ':a;N;$!ba;s/\n/ /g' filesData.txt > paGeData.txt;
   # We can remove below loop by storing sed (above) output to a variable
   # and substituting it later in the command.
   paGeData=$(sed ':a;N;$!ba;s/\n/ /g' filesData.txt);

   # Merge different images to one long image
   # "line" is a system variable
#   while read -r line
#   do
#      convert $line -append ./Merged/Page_$paGe.jpg
#   done < paGeData.txt
   convert $paGeData -append ./Merged/Page_$paGe.jpg;

   # Move files to different directory,
   # So that we can work with next range/batch of files.
   while read -r line
   do
      mv $line ./Finished/
   done < filesData.txt

done

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.