Distribuindo automaticamente páginas coloridas e preto-branco para a impressora correspondente

Este script permite a distribuição de páginas coloridas de um documento a ser impresso numa impressora colorida e as página preto/branco na impressora correspondente. É necessária a instalação do ImageMajick, sed e awk.

Para executar:

colorpages.sh <arquivo> <tipo de impressão>

  • <arquivo>: Localização do arquivo a ser impresso
  • <tipo de impressão>:
    • rascunho : Páginas coloridas consecutivas são impressas frente e verso. O mesmo ocorre para páginas preto e branco. Se uma página é preto e branco e a seguinte é colorida, elas são impressas em folhas separadas
    • tese : Páginas consecutivas Ímpar/Par são impressas frente e verso. As páginas consecutivas coloridas serão impressas na impressora a cor e as preto e branco na respectiva impressora. Se uma página ímpar é preto e branco e a seguinte é colorida, serão, primeiramente impressas as páginas preto e branco. O usuário deve retirá-las e colocá-las em ordem dentro da impressora colorida. Recomendada quando a impressora colorida usa mistura de cores para gerar preto
    • lazy : Semelhante a 'tese', mas o usuário não retira o restante da impressora PB. Aqui, as páginas Ímpar/Par que possuam um lado colorido e outro PB são impressas na impressora colorida. Se a impressora colorida possui toner próprio para preto, fica mais simples usar esta opção.

OBS: Não testei com arquivos que não estejam em formato PDF.

Código-Fonte

Dois arquivos são necessários: colorpages.sh e alg.awk.

colorpages.sh

#!/bin/bash

function colorpages {
 file="$1"
 i=0;
 j=0;
 for page in $(identify -format '%p ' "$file") ; do
  if [ -n "`convert "$file[$((page-1))]" -colorspace RGB -unique-colors txt:- | sed -e 1d | awk -f alg.awk | head -n 1`" ]
  then
   COLOR[i]=$page;
   i=$((i+1))     
  else
   BW[j]=$page;
   j=$((j+1))
  fi
 done
} 

function printArray {
  declare -a ARR=("${!1}")
  TAM=${#ARR[@]}
  for ((k=0;k<$((TAM-1));k++))
  do
    echo -n ${ARR[k]}","
  done
  if [ $TAM -gt 0 ]; then
    echo -n ${ARR[$((TAM-1))]}
  fi
}

function divideSingleDouble {
  declare -a ARR=("${!1}")
  ARR_DOUBLE=( )
  ARR_SINGLE=( )
  TAM=${#ARR[@]}
  declare -i ind=0
  declare -i ind2=0
  for ((k=0;k<$TAM;))
  do
    if [ "${ARR[$((k+1))]}" == $((${ARR[$k]}+1)) ];
    then
      ARR_DOUBLE[$ind1]=${ARR[$k]}
      ARR_DOUBLE[$((ind1+1))]=${ARR[$((k+1))]}
      ind1=$((ind1+2))
      k=$((k+2));
    else
      ARR_SINGLE[$ind2]=${ARR[$k]}
      ind2=$((ind2+1))
      k=$((k+1));
    fi
  done
}

function divideSingleDoubleOdd {
  declare -a ARR=("${!1}")
  ARR_DOUBLE=( )
  ARR_SINGLE=( )
  TAM=${#ARR[@]}
  declare -i ind=0
  declare -i ind2=0
  for ((k=0;k<$TAM;))
  do
    if [ $((${ARR[$k]} % 2)) == 1 -a "${ARR[$((k+1))]}" == $((${ARR[$k]}+1)) ];
    then
      ARR_DOUBLE[$ind1]=${ARR[$k]}
      ARR_DOUBLE[$((ind1+1))]=${ARR[$((k+1))]}
      ind1=$((ind1+2))
      k=$((k+2));
    else
      ARR_SINGLE[$ind2]=${ARR[$k]}
      ind2=$((ind2+1))
      k=$((k+1));
    fi
  done
}

function createCOLORandBWpages {
  divideSingleDouble COLOR[@]
  COLOR_DOUBLE=(${ARR_DOUBLE[@]})
  COLOR_SINGLE=(${ARR_SINGLE[@]})
  divideSingleDouble BW[@]
  BW_DOUBLE=(${ARR_DOUBLE[@]})
  BW_SINGLE=(${ARR_SINGLE[@]})
} 

function createCOLORandBWpagesOdd {
  divideSingleDoubleOdd COLOR[@]
  COLOR_DOUBLE=(${ARR_DOUBLE[@]})
  COLOR_SINGLE=(${ARR_SINGLE[@]})
  divideSingleDoubleOdd BW[@]
  BW_DOUBLE=(${ARR_DOUBLE[@]})
  BW_SINGLE=(${ARR_SINGLE[@]})
}

function printHelp {
  echo "colorpages.sh <arquivo> <tipo de impressão>"
  echo "  arquivo: Localização do arquivo a ser impresso"
  echo "  tipo de impressão: "
  echo "    - rascunho : Páginas coloridas consecutivas são impressas frente e verso"
  echo "                 O mesmo ocorre para páginas preto e branco. Se uma página é"
  echo "                 preto e branco e  a seguinte é colorida, elas são impressas"
  echo "                 em folhas separadas"
  echo "    - tese : Páginas consecutivas Ímpar/Par são impressas frente e verso.  As"
  echo "             páginas consecutivas  coloridas serão impressas  na impressora a"
  echo "             cor e as preto e branco na respectiva impressora. Se uma  página"
  echo "             ímpar é preto e branco e a seguinte é colorida, serão, primeira-"
  echo "             mente impressas as páginas  preto e branco. O usuário deve reti-"
  echo "             rá-las e colocá-las em ordem dentro da impressora colorida.  Re-"
  echo "             comendada quando a impressora colorida usa mistura de cores para"
  echo "             gerar preto"
  echo "    - lazy : Semelhante a 'tese', mas o  usuário não retira o restante da im-"
  echo "             pressora PB. Aqui, as páginas Ímpar/Par que possuam um lado  co-"
  echo "             lorido e outro PB são impressas na impressora colorida. Se a im-"
  echo "             pressora  colorida  possuir  toner próprio para preto, fica mais"
  echo "             simples usar esta opção."
} 

function testando {
  TAM=50
  declare -i ind1=0
  declare -i ind2=0
  for((k=1;k<=$TAM;k++))
  do
    if [ $RANDOM -lt $((32767*25/100)) ]
    then
      COLOR[$ind1]=$k;
      ind1=$((ind1+1));
    else
      BW[$ind2]=$k;
      ind2=$((ind2+1));
    fi
  done
} 

function mergeCOLORandBW_SINGLE {
  declare -a ARR1=(${COLOR[@]});
  declare -a ARR2=(${BW_SINGLE[@]});
  TAM1=${#ARR1[@]}
  TAM2=${#ARR2[@]}
  N=$((${#BW[@]}+${#COLOR[@]})); 

  # N pode ser par ou ímpar
  # Se for par, BW_SINGLE e COLOR terão tamanhos iguais
  # Se for ímpar, apenas um entre COLOR e BW_SINGLE
  # será ímpar. Se for BW_SINGLE, ele tem um elemento a mais
  # que COLOR.
  if [ $((N % 2)) == 1 -a $((TAM2 % 2)) == 1 ]; then
    BW_SINGLE=(${ARR2[$((TAM2-1))]})
  else
    BW_SINGLE=()
  fi 

  COLOR_DOUBLE=(); 

  #Aqui é semelhante ao Merge do Mergesort
  for ((k=0;k<TAM1;k++))
  do
    if [ "${ARR1[k]}" != "" -a "${ARR2[k]}" != "" ]; then
      if [ ${ARR1[k]} -lt ${ARR2[k]} ]; then
        COLOR_DOUBLE[$((k*2))]=${ARR1[k]}
        COLOR_DOUBLE[$((k*2+1))]=${ARR2[k]}
      else
        COLOR_DOUBLE[$((k*2))]=${ARR2[k]}
        COLOR_DOUBLE[$((k*2+1))]=${ARR1[k]}
      fi
    fi
  done 

  #se COLOR for maior que BW_SINGLE, adicionar o último a COLOR
  if [ $TAM2 -lt $TAM1 ]; then
    COLOR_DOUBLE[$((2*TAM1))]=${COLOR[$((TAM1-1))]}
  fi
  COLOR_SINGLE=();
} 

COLOR_PRINTER=matisse
BW_PRINTER=degas 

if [ "$1" == "" -o "$2" == "" ]; then
  printHelp;
  exit;
fi

colorpages $1

### Descomente abaixo para depuração ###
# testando; echo BW = ${BW[@]}; echo COLOR = ${COLOR[@]};  
###       Fim Depurapção             ###  

if [ $2 == "rascunho" ]; then
  createCOLORandBWpages;
elif [ $2 == "tese" ]; then
  createCOLORandBWpagesOdd;
elif [ $2 == "lazy" ]; then
  divideSingleDoubleOdd BW[@]
  BW_DOUBLE=(${ARR_DOUBLE[@]})
  BW_SINGLE=(${ARR_SINGLE[@]})
  mergeCOLORandBW_SINGLE;
else
  printHelp;
  exit;
fi

#Print Double Sided Color Pages 
if [ ${#COLOR_DOUBLE[@]} -gt 0 ]; then
  lpr -P $COLOR_PRINTER -o page-ranges=`printArray COLOR_DOUBLE[@]` -o Duplex=DuplexNoTumble $1;
fi 

#Print Double Sided BW Pages 
if [ ${#BW_DOUBLE[@]} -gt 0 ]; then
  lpr -P $BW_PRINTER -o page-ranges=`printArray BW_DOUBLE[@]` -o Duplex=DuplexNoTumble $1;
fi 

#Print Single Sided BW Pages
if [ ${#BW_SINGLE[@]} -gt 0 ]; then
  lpr -P $BW_PRINTER -o page-ranges=`printArray BW_SINGLE[@]` -o Duplex=None $1; 
fi 

if [ $2 == "rascunho" -o  $2 == "lazy" ]; then
  #Print Single Sided Color Pages
  if [ ${#COLOR_SINGLE[@]} -gt 0 ]; then
    lpr -P $COLOR_PRINTER -o page-ranges=`printArray COLOR_SINGLE[@]` -o Duplex=None $1;
  fi
elif [ $2 == "tese" ]; then
  #Print Single Sided Color Pages
  if [ ${#COLOR_SINGLE[@]} -gt 0 ]; then
    echo 
    echo "+-------------------------------------------------------------------------+"
    echo "| Coloque as páginas com verso em branco da impressora preto e branco (as |"
    echo "| últimas que saíram) na impressora colorida. Depois de colocadas, aperte |"
    echo "| ENTER para começar a impressão no verso delas.                          |"
    echo "+-------------------------------------------------------------------------+"
    read;
    lpr -P $COLOR_PRINTER -o page-ranges=`printArray COLOR_SINGLE[@]` -o Duplex=None $1;
  fi
else
  printHelp;
  exit;
fi 

alg.awk

{
  match($0,/\(\ *[0-9]+,\ *[0-9]+,\ *[0-9]+\)/);
  STR=substr($0,RSTART+1,RLENGTH-2);
  split(STR, A,",")
  mean=(A[1]+A[2]+A[3])/3
  a_mean1 = A[1]-mean;
  a_mean2 = A[2]-mean;
  a_mean3 = A[3]-mean;
  value=sqrt(a_mean1*a_mean1 + a_mean2*a_mean2 + a_mean3*a_mean3);
  if (value > 653) {print $0}
}

Funcionamento

O script colorpages.sh possui dois array principais: BW e COLOR, a lista das páginas preto/branco e coloridas de um arquivo, respectivamente. As funções printBW e printCOLOR imprimem este vetores com seus elementos separados por vírgulas.

A função colorpages carrega o arquivo dado como argumento e preenche BW e COLOR com as páginas preto/branco e coloridas, respectivamente. Para cada página do arquivo PDF, ele lista todos os pixels únicos da página em formato RGB (usando convert do ImageMajick).

Os valores RGB são representados em valores de 0 a 65355. Para verificar se existe páginas coloridas, verifica-se se existe algum pixel cujos valores possuem desvio padrão maior que 653 (1% do valor máximo permitido). O código alg.awk realiza esta verificação.

Os vetores BW e COLOR a depender da opção fornecida pode ser dividido em dois vetores cada. BW é dividido em BW_DOUBLE, que possui pares de números consecutivos e BW_SINGLE, formado pelos números que sobraram, ordenados, de BW (ou seja, BW_SINGLE = BW - BW_DOUBLE). Similarmente ocorre com COLOR, COLOR_SINGLE e COLOR_DOUBLE.

Se a opção fornecida for tese ou lazy, os vetores _DOUBLE devem ser formados por duplas de números começados por números ímpares. Na opção rascunho, não é necessário. Isto ocorre porque em teses as folhas começam com números ímpares.

O código foi escrito de tal forma que no máximo quatro jobs sejam enviados para as duas impressoras. É fornecido a cada job as listas das páginas a serem impressas, a impressora correspondente e se é para ser impresso frente e verso ou um lado apenas.

tutoriais/impressao.txt · Última modificação: 2011/06/16 22:29 por yuri