Eu preciso criar um loop no bash para unir imagens verticalmente e descarregar várias páginas associadas para impressão

1

Estou executando o Ubuntu 18.04. Eu tenho um diretório cheio de imagens de storyboard no formato .jpg , conforme abaixo.

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

Mesclar 13 imagens verticalmente me dá uma página única. Então eu acho que preciso usar o comando abaixo, usando um intervalo de 13 números de cada vez em um loop e salvar em um diretório "./Merged" .

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

My experiment and thought process is as below.

Estou tentando usar um loop for aninhado e seq -w como abaixo. Mas eu sou incapaz de entender, como fazer o loop do script de tal forma que leva 13 primeiros arquivos (from image-0000 to image-0012) , mescla-os e salva na pasta ./Merged/ . Então saia do loop e novamente pegue os próximos 13 arquivos (from image-0013 to image-0025) e assim por diante. Até que todos os arquivos .jpg na pasta atual sejam finalizados ou até que 300 páginas sejam geradas.

Meu 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
    
por user3025253 13.06.2018 / 00:49

4 respostas

1

com 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]=()
}

Observe que, como há 3901 imagens (13 × 300 + 1), a última página terá apenas uma imagem.

Você pode fazer algo semelhante com bash como:

#! /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, supondo que haja arquivos correspondentes e fazendo uma verificação ainda menos próxima nos nomes de arquivos:

#! /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 que, enquanto aqui os nomes dos arquivos são muito domados (sem espaços em branco, caracteres especiais ...), cuidados especiais foram tomados nesses códigos para manipular caracteres arbitrários. No entanto, note que convert e outros utilitários imagemagick podem ter problemas com nomes de arquivos começando com - (mesmo quando usando -- ) ou contendo : , então o melhor é prefixar caminhos de arquivo com ./ para evitar esses problemas (por exemplo, use ./*.jpg em vez de *.jpg ).

    
por 13.06.2018 / 17:51
1

Então, digamos que você tenha esses arquivos em um intervalo contínuo de image-0000.jpg a image-2999.jpg . Isso deve demonstrar o princípio em ação aqui:

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

Então, solte isso no seu caso de uso:

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

Observe que {01..02} expandindo para 01 02 em vez de 1 2 requer bash 4.

    
por 13.06.2018 / 00:56
0

Você pode fazer isso usando o argumento xargs -n e enviar o resultado para um loop while read .

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)
    
por 13.06.2018 / 16:22
0

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

DopeGhoti

Philip Kendall

Stéphane Chazelas

RoVo

Isso é o que eu consegui criar e funcionou. Ainda gostaria de verificar outras soluções também. Talvez sua solução seja mais rápida que o meu script básico.

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
    
por 14.06.2018 / 08:53

Tags