Thursday, April 18, 2013

Ֆայլեր։ Pixmap պատկերի խոշորացում

Ենթադրենք տրված է pixmap պատկեր պարունակող պարզեցված ֆայլ և պահանջվում է գրել մի ծրագիր, որը պատկերը կխոշորացնի տրված գործակցով։ Օրինակ, ստորև բերված են հայերեն "Բ" տառի սկզբնական pixmap պատկերը և նրա երկու անգամ խոշորտացված տարբերակը։
......
..##..
.#..#.
.#..#.
.#....
.####.
.#....
.#....
.#....
......
                 
............
............
....####....
....####....
..##....##..
..##....##..
..##....##..
..##....##..
..##........
..##........
..########..
..########..
..##........
..##........
..##........
..##........
..##........
..##........
............
............
Ծրագիրը պետք կարդա ձախ կողմի պատկերը պարունակող ֆայլը և ստեղծի նոր ֆայլ՝ աջ պատկերի պարունակմամբ։

Թող ամբողջ աշխատանքը կատարող պրոցեդուրան կոչվի enlarge, որը ստանում է երկու արգումենտ. պատկերը պարունակող ֆայլի անունը՝ pixmap և խոշորացման գործակիցը՝ sc։
proc enlarge { pixmap {sc 2} } {
Հետո պետք է բացել ֆայլը, նրա պարունակությունը կարդալ որևէ փոփոխականի մեջ, ապա նորից փակել ֆայլը։ Tcl լեզվում ֆայը բացվում է open պրոցեդուրայով, որի առաջին արգումենտը ֆալի անունն է, իսկ երկրորդով որոշվում է, թե ինչ գործողություն է կատարվելու ֆայլի հետ՝ գրել (w), կարդալ (r) և այլն։ open պրոցեդուրան վերադարձնում է ֆայլային հոսք, որից կարելի է կարդալ, կամ նրա մեջ կարելի է գրել։
  set inp [open $pixmap r]
Ֆայլի պարունակությունը ամբողջությամբ կարդում է read պրոցեդուրան։ Այն ստանում է կարդալու համար բացված ֆայլային հոսք և վերադարձնում է հոսքի ամբողջ պարունակությունը։
  set img [read $inp]
Դե, իսկ close պրոցեդուրան փակում է բացված ֆայլային հոսքը։
  close $inp
Պատկերը \(n\) անգամ խոշորացնելու համար պետք է նրա ամեն մի կետը հորիզոնական և ուղղահայաց ուղղություններով ընդարձակել \(n\) անգամ։ Դրա համար պետք է վերցնել սկզբնական պատկերի ամեն մի տողը և, \(n\) անգամ կրկնելով նրա ամեն մի սիմվոլը, ստանալ նոր տող։ ՈՒղղահայաց ընդարձակման համար պետք է \(n\) անգամ կրկնել կառուցված տողը։

Արդյունքը կուտակելու համար նախատեսենք result փոփոխականը որպես դատարկ ցուցակ։
  set result [list]
Քանի որ տրված ֆայլի ամբողջ պարունակությունը կարդացվել էր img փոփոխականի մեջ, պետք է այն split պրոցեդուրայով տրոհել տողերի ու իտերացիա կազմակերպել տողերով։ split պրոցեդուրայի երկրորդ արգումենտով տրվում է այն բաժանիչը, ըստ որի պետք է տողը տրոհել ցուցակի։
  foreach line [split $img \n] {
Տողի սիմվոլներով իտերացիայի համար այն կարող ենք սիմվոլների ցուցակի վերածել split պրոցեդուրայով և ցուցակով անցնել foreach պրոցեդուրայով։ Հերթական սիմվոլը դիտարկելիս string repeat հրամանով այն պետք է բազմապատկել պահանջված քանակով ու կցել կառուցվող տողին՝ str փոփոխականին: Իսկ բոլոր սիմվոլներով անցնելուց հետո կառուցված տողին կցենք նոր տողի սիմվոլը։
    set str {}
    foreach char [split $line {}] {
      append str [string repeat $char $sc]
    }
    append str \n
Կառուցված տողը բազմապատկելու համար նորից օգտագործենք string repeat հրաման հրամանը և result ցուցակին կցենք lappend պրոցեդուրայով։
    lappend result [string repeat $str $sc]
  }
Այս դրությամբ արդեն result փոփոխականը պարունակում է նախնական պատկերի խոշորացված տարբերակը։ open հրամանով բացենք ֆայլ գրելու համար։
  set out [open sc$sc$pixmap w]
Այդ ֆայլի մեջ արտածենք կառուցված տողերի ցուցակը՝ դրանք նախապես իրար կցելով join պրոցեդուրայով։
  puts $out [join $result {}]
ՈՒ փակենք ֆայլը։
  close $out
}
Վերջ։ Հիմա կարող ենք կանչել enlarge պրոցեդուրան՝ նրան տալով pixmap ֆայլը և խոշորացման գործակիցը։


Ամբողջական պրոցեդուրան։
proc enlarge { pixmap {sc 2} } {
  set inp [open $pixmap r]
  set img [read $inp]
  close $inp

  set result [list]
  foreach line [split $img \n] {
    set str {}
    foreach char [split $line {}] {
      append str [string repeat $char $sc]
    }
    append str \n
    lappend result [string repeat $str $sc]
  }

  set out [open sc$sc$pixmap w]
  puts $out [join $result {}]
  close $out
}

Sunday, April 7, 2013

Bash: Հայկական ժողովրդական հեքիաթներ

Վերջերս հայտնաբերեցի մի հղում՝ http://serials.flib.sci.am/openreader/, որը տանում է ՀՀ ԳԱԱ ինչ-որ բաժնի կողմից սկանավորված գրքերի բավականին մեծ պաշարի։ Ցուցակում ինձ հետաքրքրեցին «Հայկական Ժողովրդական Հեքիաթներ»-ի ակադեմիական հրատարակության 15 հատորները։ Դես ու դեն քչփորելուց հետո պարզեցի, որ չեմ կարողանալու հատորները ներբեռնել ամբողջական ֆայլի տեսքով։ Միակ տարբերակը մնում էր էջ առ էջ ներբեռնելը։ Հետո պարզեցի, որ ամեն մի գրքի համար առանձնացված է մի պանակ, իսկ այդ պանակում գրքի էջերը եռանիշ թվերով համարակալված JPG ֆայլեր են։ Օրինակ, առաջին հատորի էջերի պանակը հետևյալն է․
http://serials.flib.sci.am/openreader/jox_heqiatner_1/book/
Մյուս հատորների համար պարզապես 1-15 միջակայքում փոխվում է «jox_heqiatner_» պանակի համարը։

Գրեցի մի սկրիպտ, որի արգումենտում պետք է տալ, թե որ հատորն եմ ուզում ներբեռնել և այն կստեղծի առանձին պանակ ու դրա մեջ կներբեռնի տրված հատորի էջերի բոլոր JPG ֆայլերը։ Սկրիպտի սկզբում նախ ստուգում եմ, որ տրված լինի միայն մեկ արգումենտ և այդ արգումենտը լինի ամբողջ թիվ։
#!/bin/bash

if [[ $# -ne 1 ]]
then 
  echo Enter book number, an integer between 1 and 15.
  exit 1
fi

if ! [[ $1 =~ ^[0-9]+$ ]]
then
  echo Argument is not an integer.
  exit 2
fi
Հետո ձևավորում եմ երկու հասցե՝ bookurl - էջերի հասցեն, և destdir - ներբեռնված ֆայլերի հասցեն։ Եթե արդեն գոյություն ունի destdir պանակը, ապա այն ջնջում եմ ու ստեղծում եմ նորը։
bookurl="http://serials.flib.sci.am/openreader/jox_heqiatner_$1/book/"
destdir=$(pwd)$(printf "/T-%.3d/" $1)

rm -rf ${destdir}
mkdir ${destdir}
Էջերը հերթականությամբ ներբեռնելու համար page փոփոխականը արժեքավորում եմ 1 սկզբնական արժեքով․ այն ցույց է տալու հերթական էջը։ Հետո կազմակերպում եմ անվերջ ցիկլ, որի մարմնում wget ծրագրով բեռնում եմ հերթական ֆայլը։ Ցիկլի կատարում ընդհատվում է այն ժամանակ, երբ wget ծրագիրը չի կարողանում բեռնել ֆայլը և վերադարձնում է զրոյից տարբեր ավարտի կոդ։
page=1
while true
do
  # էջի համարը դարձնել եռանի
  num=$(printf "%.3d.jpg" ${page})
  # բեռնել հերթական էջը
  wget -q ${bookurl}${num} -O ${destdir}${num}
  # ստուգել wget-ի ավարտի կոդը
  if [[ $? -ne 0 ]]
  then
    # ընդհատել ցիկլը
    echo Done
    # ջնջել զրոյական ֆայլը
    rm -rf ${destdir}${num}
    break
  fi
  echo -n ${page} ' '
  # հաշվել հաջորդ էջի համարը
  page=$(expr ${page} + 1)
done
Այսքանը։ Հիմա արդեն մնում է ստացված էջերը միացնել իրար ու կազմել ամբողջական գրքի ֆայլը։