package ONO::Lib::PDF::ToolBox;
################################################################################
# COPYRIGHT / LICENSE #
################################################################################
#
# This file is part of the ONO Software Project.
#
# Copyright (C) 2000-2025 Jos KIRPS [ www.kirps.com | jos_AT_kirps_DOT_com ]
# and The Joopita Project [ www.joopita.org | contact_AT_joopita_DOT_com ]
#
# This file, as well as other parts of the ONO Software Project or related
# elements, are FREE SOFTWARE available under the ARTISTIC LICENSE 2.0.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
# For the full license, see /ono/osr/license/LICENSE.txt, or write to
# jos_AT_kirps_DOT_com or contact_AT_joopita_DOT_com.
#
################################################################################
# END OF COPYRIGHT / LICENSE, HERE COMES THE CODE ... #
################################################################################
use strict;
use ONO::IO;
use ONO::Lib::PDF::Draw;
use ONO::Lib::Data::Geo;
use ONO::Lib::Code::RandomID;
use ONO::ToolBox::DomainLang;
use ONO::Lib::UI::Animation;
use ONO::Lib::UI::Check;
use ONO::Lib::UI::Select;
###############################################################################
# sizes
###############################################################################
sub mm_pdf_ratio {
#: Returns default papersize data.
return 2.8334;
}
sub papersize_a4 {
#: Returns default papersize data.
return (595,842);
}
sub papersize_us {
#: Returns default papersize data.
return (612,792);
}
sub papersize_q170 {
#: Returns default papersize data.
return (482,482);
}
sub papersize_q170_48 {
#: Returns default papersize data.
return (482,135);
}
sub papersize_q170_190 {
#: Returns default papersize data.
return (482,539);
}
sub papersize_q200 {
#: Returns default papersize data.
return (567,567);
}
sub papersize_get {
my (
$self,
$file,
) = @_;
#: Get the size of an existing PDF document.
my @dims = (0,0,0,0,0);
eval "use PDF::API2";
if (!$@) {
my $vpath = ONO::IO->path();
if (ONO::IO->exists($file)) {
my $pdf = PDF::API2->open("$vpath/$file");
my $page = $pdf->open_page(1);
@dims = $page->get_mediabox();
@dims = (1,@dims);
}
}
return @dims;
}
sub papersize_get_mm {
#: Get default papersize in mm format.
my (
$self,
$file,
) = @_;
my $ratio = &mm_pdf_ratio();
my @dims = &papersize_get("",$file);
my @mm = ($dims[0],int(($dims[3]-$dims[1])/$ratio),int(($dims[4]-$dims[2])/$ratio));
return @mm;
}
sub papersize {
#: Get default papersize.
my @size = &papersize_a4();
if ($_[1] eq "us") {
@size = &papersize_us();
}
if ($_[1] eq "q170") {
@size = &papersize_q170();
}
if ($_[1] eq "q170/48") {
@size = &papersize_q170_48();
}
if ($_[1] eq "q170/190") {
@size = &papersize_q170_190();
}
if ($_[1] eq "q200") {
@size = &papersize_q200();
}
return @size;
}
sub papersize_mm {
#: Get default papersize in mm format.
#:
#: -D use default values instead of calculating (-R not supported)
#: -L landscape
#: -R round up/down to mm
my @size = &papersize("",$_[1]);
if ($_[2] =~ /D/) {
if ($_[1] eq "us") {
@size = &papersize_mm_us();
} else {
@size = &papersize_mm_a4();
}
if ($_[1] eq "q170") {
@size = &papersize_mm_q170();
}
if ($_[1] eq "q170/48") {
@size = &papersize_mm_q170_48();
}
if ($_[1] eq "q170/190") {
@size = &papersize_mm_q170_190();
}
if ($_[1] eq "q200") {
@size = &papersize_mm_q200();
}
} else {
@size = &pdf2mm("","",$size[0],$size[1]);
if ($_[2] =~ /R/) {
$size[0] = int $size[0];
$size[1] = int $size[1];
}
}
if ($_[2] =~ /L/) {
return ($size[1],$size[0]);
} else {
return ($size[0],$size[1]);
}
}
sub papersize_mm_a4 {
#: Returns default papersize data in mm.
return (210,297);
}
sub papersize_mm_us {
#: Returns default papersize data in mm.
return (215.9,279.4);
}
sub papersize_mm_q170 {
#: Returns default papersize data in mm.
return (170,170);
}
sub papersize_mm_q170_48 {
#: Returns default papersize data in mm.
return (170,48);
}
sub papersize_mm_q170_190 {
#: Returns default papersize data in mm.
return (170,190);
}
sub papersize_mm_q200 {
#: Returns default papersize data in mm.
return (200,200);
}
sub mm2pdf {
my (
$self,
$canvas,
$x,
$y,
) = @_;
#: Convert mm to PDF size.
#: 1. transform millimeters to PDF units
#: 2. recalc values so that we'll start top left
my $ratio = &mm_pdf_ratio;
my @size = &papersize_a4;
if ($canvas =~ /^us:/) {
@size = &papersize_us;
}
if ($canvas =~ /^q170:/) {
@size = &papersize_q170;
}
if ($canvas =~ /^q170\/48:/) {
@size = &papersize_q170_48;
}
if ($canvas =~ /^q170\/190:/) {
@size = &papersize_q170_190;
}
if ($canvas =~ /^q200:/) {
@size = &papersize_q200;
}
return ($x*$ratio,$size[1]-($y*$ratio));
}
sub pdf2mm {
my (
$self,
$canvas,
$x,
$y,
) = @_;
#: Convert PDF size to mm.
#: 1. transform PDF units to millimeters
#: 2. recalc values so that we'll start top left
my $ratio = &mm_pdf_ratio;
if ($ratio) {
return ($x/$ratio,$y/$ratio);
} else {
return (1,1);
}
}
sub pages {
my $file = $_[1];
my $pages = 1;
#: Count the number of pages in a PDF document, default = 1, even if the document doesn't exist.
eval "use PDF::API2";
if (!$@) {
my $vpath = ONO::IO->path();
if (ONO::IO->exists($file)) {
my $pdf = PDF::API2->open("$vpath/$file");
$pages = $pdf->pages;
}
}
return $pages;
}
###############################################################################
# canvas
###############################################################################
sub canvas_init {
my @dims = @_;
#: Encode the canvas (0 = format (a4/us/...), 1 = top_x, 2 = top_y, 3 = bottom_x, 4 = bottom_y)
if (!$dims[1]) {
$dims[1] = "a4";
}
for (my $i = 2; $i < 6; $i++) {
if ($dims[$i] < 0.01) {
$dims[$i] = 0;
}
}
return "$dims[1]:$dims[2]:$dims[3]:$dims[4]:$dims[5]:";
}
sub canvas_init_max {
my (
$self,
$format,
$switches,
) = @_;
#: Encode the canvas
#: -L landscape
my ($x,$y) = (210,297);
if ($format eq "us") {
($x,$y) = (215.9,279.4);
}
if ($format eq "q170") {
($x,$y) = (170,170);
}
if ($format eq "q170/48") {
($x,$y) = (170,48);
}
if ($format eq "q170/190") {
($x,$y) = (170,190);
}
if ($switches =~ /L/) {
my $a = 0;
my $b = 87.5;
if ($format eq "us") {
$b = 63.5;
}
$x = $x + $a;
$y = $y + $b;
return "$format:$a:$b:$y:$x";
} else {
return "$format:0:0:$x:$y";
}
}
sub canvas_test {
#: Canvas test print, this will only work on a Devstation.
if (ONO::IO->devstation) {
my @cp = split(/:/,$_[1]);
ONO::Lib::PDF::Draw->rect("$cp[0]:0:0:0:0",$cp[1],$cp[2],$cp[1]+$cp[3],$cp[2]+$cp[4]);
# ONO::Lib::PDF::Draw->rect($_[1],170/3, 0, 170/3*2, 190 );
ONO::Lib::PDF::Draw->rect($_[1],0, 0, 5, 190 );
ONO::Lib::PDF::Draw->rect($_[1],50, 0, 65, 190 );
ONO::Lib::PDF::Draw->rect($_[1],110, 0, 125, 190 );
ONO::Lib::PDF::Draw->rect($_[1],0, 190/4, 170, 190/4*2 );
ONO::Lib::PDF::Draw->rect($_[1],0, 190/4*2, 170, 190/4*3 );
}
}
sub canvas_auto {
#: Automatic canvas size / paper format detection, will return 0 in Europe/UK (A4),
#: or 1 elsewhere (Letter/US).
my (
$self,
$lang,
$country,
) = @_;
if (ONO::Lib::Data::Geo->is_eu($country) || ONO::Lib::Data::Geo->is_eu_lang($lang)) {
return 0;
} else {
return 1;
}
}
sub canvas {
#: Decode the canvas data.
my (
$self,
$canvas,
$x1,
$y1,
$x2,
$y2,
) = @_;
# decode the canvas (0 = format (a4/us), 1 = top_x, 2 = top_y, 3 = bottom_x, 4 = bottom_y)
my @cp = split(/:/,$canvas);
return ($x1+$cp[1],$y1+$cp[2],$x2+$cp[1],$y2+$cp[2])
}
sub canvas_split {
#: Split the canvas string, return data as array.
return split(/:/,$_[1]);
}
sub format {
my (
$self,
$ID,
$BLK_ref,
$vars_ref,
$button_switches,
$switches,
) = @_;
#: Paper format selection (US/A4, and maybe others).
#:
#: -Q offer q200 format selection
my %BLK = %$BLK_ref;
my %vars = %$vars_ref;
my @tabs = ("a4:green:A4 ($BLK{'Europe'})","us:green:Letter (US)");
if (ONO::ToolBox::DomainLang->get eq "en" && !ONO::IO->devstation) {
@tabs = ("us:green:Letter (US)","a4:green:A4 ($BLK{'Europe'})");
}
my $qconf;
if ($vars{'username'}) {
if (ONO::IO->exists("etc/print/special/q200/$vars{'username'}.conf")) {
$switches .= "Q";
$qconf++;
}
}
if ($switches =~ /Q/) {
@tabs = ("a4:green:A4 ($BLK{'Europe'})","us:green:Letter (US)","q200:green:q200");
if ($qconf) {
@tabs = ("q200:green:q200","a4:green:A4 ($BLK{'Europe'})","us:green:Letter (US)");
}
}
return ONO::Lib::UI::Select->buttons(
$ID,
$vars{$ID},
\@tabs,
"",
"f$button_switches",
$BLK_ref,
);
}
###############################################################################
# merge pages
###############################################################################
sub merge_pages {
my (
$self,
$files_ref,
$target,
) = @_;
#: Merge PDF documents (list must be provided).
my $REPORT = "ONO_Lib_PDF_ToolBox_merge_pages, ";
eval "use PDF::API2";
if (!$@) {
my $vpath = ONO::IO->path();
my @files = @$files_ref;
my $new = PDF::API2->new;
foreach my $file (@files) {
if ($file =~ /\.pdf$/i && ONO::IO->exists($file)) {
$REPORT .= "add page '$vpath/$file', ";
my $pdf = PDF::API2->open("$vpath/$file");
$new->importpage($pdf, $_) foreach 1 .. $pdf->pages;
}
}
$REPORT .= "save to file '$vpath/$target' (DONE).";
$new->saveas("$vpath/$target");
}
return $REPORT;
}
sub overlay_pages {
my (
$self,
$source1,
$source2,
$target,
$allow_overwrite,
) = @_;
#: Overlay pages, which will actually put the content of one page over the other page's content.
#: NOTE THAT THIS REQUIRES PDFTK (PDF-TOOLKIT) TO BE INSTALLED!
my $pdftk = &detect_pdftk();
my $REPORT = "ONO_Lib_PDF_ToolBox_overlay_pages, path to pdftk = '$pdftk', ";
if ($pdftk && ONO::IO->exists($source1) && ONO::IO->exists($source2) && (!ONO::IO->exists($target) || $allow_overwrite)) {
my $vpath = ONO::IO->path();
my $COM = "$pdftk '$vpath/$source1' multibackground '$vpath/$source2' output '$vpath/$target'";
$REPORT .= "running: $COM\n";
system("$COM");
if (ONO::IO->exists($target)) {
$REPORT .= "'$target' found, SUCCESS!\n";
} else {
$REPORT .= "'$target' not found, ERROR!\n";
}
}
return $REPORT;
}
###############################################################################
# HTML to PDF
###############################################################################
sub html_to_pdf {
my (
$self,
$source,
$target,
$allow_overwrite,
$format,
$margin,
$style,
$PRE,
$POST,
) = @_;
#: Convert HTML to PDF, works with both input data and external files.
#:
#: NOTE THAT THIS REQUIRES WKHTMLTOPDF (WEBKIT-HTML-TO-PDF) TO BE INSTALLED!
#:
#: format should support A4, A3, Letter and Legal, and maybe even more, or "W:H" in mm
#:
#: margin can be a number (will be interpreted in 'mm', or in 'T:R:B:L' format
#:
#: HTML to JPG -> see ONO_Lib_Image_Magick_convert
my $wkhtmltopdf = &detect_wkhtmltopdf();
my $HOST = ONO::IO->http_domain_base();
my $REPORT = "ONO_Lib_PDF_ToolBox_html_to_pdf, path to wkhtmltopdf = '$wkhtmltopdf', HOST = '$HOST', ";
my $TMP_FILE;
# pure text/html stream as source
if ($source =~ m~^\<~) {
my $PATH = "tmp/var/html-pdf-convert";
ONO::IO->mkpath($PATH);
ONO::IO->dirprotect($PATH);
my $source_file = $target;
$source_file =~ s~\.pdf$~\.txt~;
ONO::IO->store($source_file,$source);
$source = $source_file;
}
# local TXT or HTML file as input
if ($source !~ m~^(http|https)://~ && $source =~ /\.(txt|html)$/ && ONO::IO->exists($source)) {
$REPORT .= "converting TXT to HTML, ";
my $DATA = ONO::IO->load($source);
my $bytes = length $DATA;
$REPORT .= "$bytes bytes loaded, ";
if ($source =~ /\.txt$/) {
$REPORT .= "converting TXT to HTML, ";
$DATA =~ s~(\n|\r)~<br>~g;
$DATA = qq~<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="$HOST/ono/osr/css/ono.css" media="all">
<style>
p {padding:0px;margin:0px;$style}
</style>
</head>
<body>
$PRE
$DATA
$POST
</body>
</html>
~;
} else {
$REPORT .= "file is HTML, ";
}
my $DIR = "tmp/var/html-pdf-convert";
ONO::IO->mkpath($DIR);
ONO::IO->dirprotect($DIR);
$REPORT .= "creating and protecting '$DIR', ";
my $ID = ONO::Lib::Code::RandomID->make(32);
$TMP_FILE = "$DIR/$ID.html";
ONO::IO->store($TMP_FILE,$DATA);
$REPORT .= "store data into '$TMP_FILE', ";
my $TMP_SOURCE = "$HOST/$TMP_FILE";
$REPORT .= "TMP FILE = '$TMP_FILE', converting FILE to URL = '$TMP_SOURCE', ";
$source = $TMP_SOURCE;
}
# local or remote HTTP/S website as source
if ($wkhtmltopdf && $source =~ m~^(http|https)://~ && $target =~ /\.pdf$/ && (!ONO::IO->exists($target) || $allow_overwrite)) {
my $vpath = ONO::IO->path();
my ($FORMAT,$MARGIN);
if ($format =~ /[A-Za-z0-9]/) {
$format =~ s~us~Letter~i;
$FORMAT = "--page-size $format";
}
if ($format =~ /^(.*?):(.*?)$/) {
$FORMAT = "--page-width $1 --page-height $2";
}
if ($margin =~ /[0-9]/) {
$margin =~ s~[^0-9\:]~~g;
$MARGIN = "-T $margin -R $margin -B $margin -L $margin";
if ($margin =~ /^(.*?):(.*?):(.*?):(.*?)$/) {
$MARGIN = "-T $1 -R $2 -B $3 -L $4";
}
}
$REPORT .= "ready to process, source = '$source', vpath = '$vpath', target = '$target', ";
my $COM = "$wkhtmltopdf -q $FORMAT $MARGIN '$source' '$vpath/$target'";
$REPORT .= "running: $COM, ";
system($COM);
if (ONO::IO->exists($target)) {
$REPORT .= "'$target' found, SUCCESS!\n";
} else {
$REPORT .= "'$target' not found, ERROR!\n";
}
}
ONO::IO->store("tmp/var/html-pdf-convert/__report.txt",$REPORT);
if ($TMP_FILE && !ONO::IO->devstation) {
ONO::IO->rm($TMP_FILE);
}
return $REPORT;
}
###############################################################################
# detect server scripts
###############################################################################
sub detect_xvfb_run {
#: External library detection, returns path to binary.
my $xvfb_run;
foreach my $path (ONO::IO->binary_dirs()) {
if (-e "$path/xvfb-run") {
$xvfb_run = "$path/xvfb-run";
}
}
return $xvfb_run;
}
sub detect_pdftk {
#: External library detection, returns path to binary.
my $pdftk;
foreach my $path (ONO::IO->binary_dirs()) {
if (-e "$path/pdftk") {
$pdftk = "$path/pdftk";
}
}
return $pdftk;
}
sub detect_wkhtmltopdf {
#: External library detection, returns path to binary.
my $wkhtmltopdf;
foreach my $path (ONO::IO->binary_dirs()) {
if (-e "$path/wkhtmltopdf") {
$wkhtmltopdf = "$path/wkhtmltopdf";
my $xvfb_run = &detect_xvfb_run();
if ($xvfb_run) {
$wkhtmltopdf = "$xvfb_run $path/wkhtmltopdf";
}
}
}
return $wkhtmltopdf;
}
sub detect_gs {
#: External library detection, returns path to binary.
my $gs;
foreach my $path (ONO::IO->binary_dirs()) {
if (-e "$path/gs") {
$gs = "$path/gs";
}
}
return $gs;
}
###############################################################################
# multi page logic
###############################################################################
sub multi_page_logic_one {
my (
$self,
$canvas,
$line,
$pdf_x,
$pdf_y,
$font_size,
$line_report,
$line_height,
$line_font_offset,
$para_offset,
) = @_;
#: The multi_page_logic code allows to generate multi-page PDF files with
#: floating text, based on the ONO_Lib_PDF:Draw->text code and its options.
#:
#: The code has been split in two, in otder to allow creating custom page
#: designs.
#:
#: Note that this is FLAWED, as it relies on text flags that do NOT allow to
#: have paragraphs bigger than 1 page.
#:
#: Also see multi_page_logic_two().
#
# ($pdf_y,$line_report,$lines_limit) = ONO_Lib_PDF_ToolBox->multi_page_logic_one(...);
# if ($pdf_y > canvas_height) {
# ... generate new page code here
# ($pdf_y,$line_report) = ONO_Lib_PDF_ToolBox->multi_page_logic_two(...);
# }
#
my $DEBUG = "MPL PARA";
my ($max_y,$lines_limit) = &multi_page_logic_zero("",$canvas,$line_height,$pdf_y);
my $lines = ONO::Lib::PDF::Draw->text($canvas,$pdf_x,$pdf_y+$line_height-$line_font_offset,$line,"","","AaCc",$lines_limit,0,$line_height,$font_size);
if ($lines > $lines_limit) {
$line_report = $lines_limit;
}
if ($lines > 1) {
$pdf_y = $pdf_y + ($lines-1)*$line_height;
}
$pdf_y = $pdf_y + $line_height*$para_offset;
return ($pdf_y,$line_report,$lines_limit,"$DEBUG<br>");
}
sub multi_page_logic_two {
my (
$self,
$canvas,
$line,
$pdf_x,
$pdf_y,
$font_size,
$line_report,
$line_height,
$line_font_offset,
$para_offset,
) = @_;
#: The multi_page_logic code, part II.
#: Also see multi_page_logic_one().
my $DEBUG = "MPL NEW PAGE";
$pdf_y = 0;
if ($line_report) {
my ($max_y,$lines_limit) = &multi_page_logic_zero("",$canvas,$line_height,$pdf_y);
my $lines = ONO::Lib::PDF::Draw->text($canvas,$pdf_x,$pdf_y+$line_height-$line_font_offset,$line,"","","ABaCcR",$lines_limit,$line_report,$line_height,$font_size);
$pdf_y = $pdf_y + ($lines-$line_report+$para_offset-1)*$line_height;
$DEBUG .= ", with line report = $line_report, limit = $lines_limit, lines = $lines, new pdf_y = $pdf_y";
$line_report = 0;
}
return ($pdf_y,$line_report,"$DEBUG<br>");
}
sub multi_page_logic_zero {
my (
$self,
$canvas,
$line_height,
$pdf_y,
) = @_;
#: The multi_page_logic code, part ZERO.
#: Also see multi_page_logic_one().
my @cp = &canvas_split("",$canvas);
my $max_y = $cp[4]-($line_height*1.5)-1;
my $lines_limit = int((($max_y-$pdf_y)/$line_height))+1;
return ($max_y,$lines_limit);
}
###############################################################################
# stickers
###############################################################################
sub stickers_sel {
my (
$self,
$sel,
$BLK_ref,
$switches,
$ALT,
) = @_;
#: Stickers: select.
#:
#: -A alt button is selected
#: -J alt button kicks off javascript (_enable), default buttons kick off anti-javascript (_disable)
#: -L margin left 10
#: -s selector javascript
my %BLK = %$BLK_ref;
my ($sel1,$sel2,$sel3) = ('_dark','','');
if ($sel) {
($sel1,$sel2) = ('','_dark');
}
my ($SEL1,$SEL2,$SEL3,$ML,$BUTTON_ALT);
if ($switches =~ /s/) {
($SEL1,$SEL2,$SEL3) = ("onojs_hide('print_stickers_setup_id');","onojs_block('print_stickers_setup_id');","onojs_hide('print_stickers_setup_id');");
}
if ($switches =~ /L/) {
$ML = " ml10";
}
if ($ALT) {
my @ap = split(/:/,$ALT);
my $value = 0;
if ($switches =~ /A/) {
($sel1,$sel2,$sel3) = ('','','_dark');
$value = 1;
}
if ($switches =~ /J/) {
$SEL1 .= qq~$ap[0]_disable();~;
$SEL2 .= qq~$ap[0]_disable();~;
$SEL3 .= qq~$ap[0]_enable();~;
}
$BUTTON_ALT = qq~<input type="hidden" id="$ap[0]_id" name="$ap[0]" value="$value">
<a id="print_stickers_sel_3" href="javascript:void(0);" class="button$sel3 button_middle"
onclick="onojs_setvalue('print_stickers_id','0');onojs_setvalue('$ap[0]_id','1');$SEL3
onojs_class('print_stickers_sel_3','button_dark button_middle');
onojs_class('print_stickers_sel_1','button button_left');
onojs_class('print_stickers_sel_2','button button_right');">$ap[1]</a>
~;
$SEL1 .= qq~onojs_class('print_stickers_sel_3','button button_middle');onojs_setvalue('$ap[0]_id','0');~;
$SEL2 .= qq~onojs_class('print_stickers_sel_3','button button_middle');onojs_setvalue('$ap[0]_id','0');~;
}
return qq~<input type="hidden" id="print_stickers_id" name="print_stickers" value="$sel">
<a id="print_stickers_sel_1" href="javascript:void(0);" class="button$sel1 button_left$ML"
onclick="onojs_setvalue('print_stickers_id','0');$SEL1
onojs_class('print_stickers_sel_1','button_dark button_left');onojs_class('print_stickers_sel_2','button button_right')">$BLK{'list'}</a>
$BUTTON_ALT
<a id="print_stickers_sel_2" href="javascript:void(0);" class="button$sel2 button_right"
onclick="onojs_setvalue('print_stickers_id','1');$SEL2
onojs_class('print_stickers_sel_1','button button_left');onojs_class('print_stickers_sel_2','button_dark button_right')">$BLK{'stickers'}</a>
~;
}
sub stickers_setup {
my (
$self,
$lang,
$BLK_ref,
$vars_ref,
$switches,
) = @_;
#: Stickers: setup.
#: -h hide by default
my %BLK = %$BLK_ref;
my @txt = (
"print grid",
);
if ($lang eq "de") {
@txt = (
"Raster drucken",
);
}
if ($lang eq "lu") {
@txt = (
"Raster printen",
);
}
if ($lang eq "fr") {
@txt = (
"imprimer grille",
);
}
my (%SEL,$CLASS);
for (my $i = 0; $i < 33; $i++) {
my ($sel1,$sel2);
if ($i == 3) {
$sel1 = " selected";
}
if ($i == 8) {
$sel2 = " selected";
}
if ($i && $i < 5) {
$SEL{'cols'} .= qq~<option value="$i"$sel1>$i</option>~;
}
if ($i > 3 && $i < 13) {
$SEL{'rows'} .= qq~<option value="$i"$sel2>$i</option>~;
}
$SEL{'top'} .= qq~<option value="$i">$i mm</option>~;
$SEL{'bottom'} .= qq~<option value="$i">$i mm</option>~;
$SEL{'left'} .= qq~<option value="$i">$i mm</option>~;
$SEL{'right'} .= qq~<option value="$i">$i mm</option>~;
}
if ($switches =~ /h/) {
$CLASS .= " hide";
}
my $SWITCH = ONO::Lib::UI::Check->switch("print_stickers_grid",0,"r");
return qq~<div id="print_stickers_setup_id" class="$CLASS">
<div class="inline w100 bt mt10">
<div class="w33 fl w100_800 fn_800 mt10">
<table class="default_table">
<tr>
<td class="tar">$BLK{'columns'}:</td>
<td><div class="select"><select name="print_stickers_cols">$SEL{'cols'}</select></div></td>
</tr>
<tr>
<td class="tar">$BLK{'rows'}:</td>
<td><div class="select"><select name="print_stickers_rows">$SEL{'rows'}</select></div></td>
</tr>
<tr>
<td>$SWITCH</td>
<td>$txt[0] ($BLK{'lines'})</td>
</tr>
</table>
</div>
<div class="w33 fl w100_800 fn_800 mt10">
<table class="default_table">
<tr>
<td class="tar">$BLK{'top'}:</td>
<td><div class="select"><select name="print_stickers_margin_top">$SEL{'top'}</select></div></td>
</tr>
<tr>
<td class="tar">$BLK{'bottom'}:</td>
<td><div class="select"><select name="print_stickers_margin_bottom">$SEL{'bottom'}</select></div></td>
</tr>
</table>
</div>
<div class="w33 fl w100_800 fn_800 mt10">
<table class="default_table">
<tr>
<td class="tar">$BLK{'left'}:</td>
<td><div class="select"><select name="print_stickers_margin_left">$SEL{'left'}</select></div></td>
</tr>
<tr>
<td class="tar">$BLK{'right'}:</td>
<td><div class="select"><select name="print_stickers_margin_right">$SEL{'right'}</select></div></td>
</tr>
</table>
</div>
</div>
</div>
~;
}
sub stickers_logic {
my (
$self,
$format,
$vars_ref,
) = @_;
#: Stickers: logic.
my %vars = %$vars_ref;
my ($total,$width,$height) = (1,1,1);
if ($vars{'print_stickers_cols'} && $vars{'print_stickers_rows'}) {
$total = $vars{'print_stickers_cols'} * $vars{'print_stickers_rows'};
my (@paper) = &papersize_mm("",$format);
$width = (int((($paper[0]-$vars{'print_stickers_margin_left'}-$vars{'print_stickers_margin_right'})/$vars{'print_stickers_cols'})*100))/100;
$height = (int((($paper[1]-$vars{'print_stickers_margin_top'}-$vars{'print_stickers_margin_bottom'})/$vars{'print_stickers_rows'})*100))/100;
}
return ($total,$width,$height);
}
sub stickers_logic_complete {
my (
$self,
$format,
$vars_ref,
) = @_;
my %vars = %$vars_ref;
#: Stickers: logic, complete.
# 0.01 IS IMPORTANT IN CANVAS INIT HERE !!!
my ($total,$width,$height) = &stickers_logic("",$format,$vars_ref);
my ($pwidth,$pheight) = &papersize_mm("",$format);
my $canvas = &canvas_init(
"",
$format,
$vars{'print_stickers_margin_left'}+0.01,
$vars{'print_stickers_margin_top'}+0.01,
$pwidth-$vars{'print_stickers_margin_left'}-$vars{'print_stickers_margin_right'}-0.01,
$pheight-$vars{'print_stickers_margin_top'}-$vars{'print_stickers_margin_bottom'}-0.01,
);
return ($canvas,$pwidth,$pheight,$total,$width,$height);
}
sub stickers_grid {
my (
$self,
$canvas,
$pwidth,
$pheight,
$width,
$height,
$vars_ref,
) = @_;
#: Stickers: grid.
my %vars = %$vars_ref;
if ($vars{'print_stickers_grid'} || ONO::IO->devstation) {
if ($vars{'print_stickers_margin_top'} || $vars{'print_stickers_margin_bottom'} || $vars{'print_stickers_margin_left'} || $vars{'print_stickers_margin_right'}) {
ONO::Lib::PDF::Draw->rect(
$canvas,
0,
0,
$pwidth-$vars{'print_stickers_margin_left'}-$vars{'print_stickers_margin_right'},
$pheight-$vars{'print_stickers_margin_top'}-$vars{'print_stickers_margin_bottom'},
0.5,
);
}
for (my $c = 1; $c < $vars{'print_stickers_cols'}; $c++) {
ONO::Lib::PDF::Draw->line($canvas,$c*$width,0,$c*$width,$pheight-$vars{'print_stickers_margin_top'}-$vars{'print_stickers_margin_bottom'},0.5);
}
for (my $r = 1; $r < $vars{'print_stickers_rows'}; $r++) {
ONO::Lib::PDF::Draw->line($canvas,0,$r*$height,$pwidth-$vars{'print_stickers_margin_left'}-$vars{'print_stickers_margin_right'},$r*$height,0.5);
}
}
}
sub stickers_position {
#: Stickers: position.
my (
$self,
$pdf_x,
$pdf_y,
$pwidth,
$pheight,
$width,
$height,
$vars_ref,
) = @_;
my %vars = %$vars_ref;
$pdf_x = $pdf_x + $width;
if ($pdf_x > $pwidth-$vars{'print_stickers_margin_left'}-$vars{'print_stickers_margin_right'}-$width) {
$pdf_x = 0;
$pdf_y = $pdf_y + $height;
}
return ($pdf_x,$pdf_y);
}
sub design_coords {
#: PDF page design coordinates.
my $top1 = 8;
my $top2 = 262.5;
my $top3 = 0;
my $width = 210;
if ($_[1] eq "us") {
$top1 = 26;
$top2 = 263.5;
$top3 = 17;
$width = 216;
}
return ($top1,$top2,$top3,$width);
}
sub design_print {
my (
$self,
$community,
$design,
$format,
) = @_;
#: PDF page design, will add graphics to the top and the bottom of a page.
if ($format !~ /^q/) {
my $Community = ucfirst $community;
my ($top1,$top2,$top3,$width) = &design_coords("",$format);
my $height = int($width/5.4);
my $DESIGN = "ono-data/$community/pdf/design/$design/header.jpg";
if (ONO::IO->exists($DESIGN)) {
ONO::Lib::PDF::Draw->image("",0,$top3,$width,$height,$DESIGN);
}
my $DESIGN = "ono-data/$community/pdf/design/$design/footer.jpg";
if (ONO::IO->exists($DESIGN)) {
ONO::Lib::PDF::Draw->image("",0,262,$width,$height,$DESIGN);
}
}
}
sub print_please_wait {
#: PDF please wait message.
my @txt = ("Your exercises are being generated","please be patient");
if ($_[1] eq "de") {
@txt = ("Deine Aufgaben werden generiert","bitte etwas Geduld");
}
if ($_[1] eq "lu") {
@txt = ("Deng Aufgabe gi generéiert","e bësse Gedold w.e.g.");
}
if ($_[1] eq "fr") {
@txt = ("Vos exercises vont être générés","veuillez patienter");
}
my @RAND;
for (my $r = 0; $r < 2; $r++) {
for (my $s = 0; $s < 10; $s++) {
my @rnd = (int(rand(60)),int(rand(100)),2+int(rand(100)),2+int(rand(10)),int(rand(10)),int(rand(10)),int(rand(10)));
$RAND[$r] .= qq~<div class="abs" style="top:$rnd[0]px;left:$rnd[1]px;width:$rnd[2]px;height:$rnd[3]px;background-color:#$rnd[4]$rnd[5]$rnd[6]"></div>~;
}
}
my $BASE = ONO::IO->base();
my $DOTS = ONO::Lib::UI::Animation->dots(5);
return qq~<div class="p20 center">
<h3 class="m0"><span class="bold green">$txt[0],</span></h3>
<h3 class="m0"><span class="bold lightgreen">$txt[1] $DOTS</span></h3>
<div class="inline auto">
<div class="p20 rel">
<img class="block256" src="$BASE/ono/osr/images/icons/crystal/256x256/devices/printer1.png" alt="printing">
<div class="abs trans50" style="top:30px;left:90px;width:120px;height:70px;overflow:hidden">$RAND[0]</div>
<div class="abs trans50" style="top:200px;left:80px;width:140px;height:40px;overflow:hidden">$RAND[1]</div>
</div>
</div>
</div>
~;
}
sub icon {
#: PDF file type icon, will kick off thumbnail generation if thumb doesn't exist.
my $FILE = $_[1];
my $ICON = "ono/osr/images/icons/crystal/128x128/mimetypes/pdf.png";
$FILE =~ s~^/~~;
my ($dir,$file,$ext) = ONO::IO->getdirfileext($FILE);
if (ONO::IO->exists("$dir/.pr_$file.jpg")) {
$ICON = qq~$dir/.pr_$file.jpg~;
} else {
my $ID = ONO::Lib::Code::RandomID->make();
ONO::IO->mkpath("var/tmp/cronsync/pdf2thumbqueue");
ONO::IO->chmod("var/tmp/cronsync/pdf2thumbqueue",777);
ONO::IO->store("var/tmp/cronsync/pdf2thumbqueue/$ID.txt","$FILE");
ONO::IO->chmod("var/tmp/cronsync/pdf2thumbqueue/$ID.txt",777);
}
return "$_[2]$ICON";
}
sub rgb_to_cmyk {
my (
$self,
$source,
$target,
$switches,
) = @_;
#: PDF RGB to CMYK conversion, using Ghostscript.
my $gs = &detect_gs;
my $DEBUG = "ONO_Lib_PDF_ToolBox_rgb_to_cmyk, Ghostscript is '$gs', ";
if ($gs && $source =~ /\.pdf/ && $target =~ /\.pdf/) {
$source =~ s~[^A-Za-z0-9\/\-\_\.]~~g;
$target =~ s~[^A-Za-z0-9\/\-\_\.]~~g;
if ($source !~ /\.\./ && $target !~ /\.\./ && $source !~ /\/\./ && $target !~ /\/\./ && $source ne $target) {
my $vpath = ONO::IO->path();
my $COM = "$gs -sDEVICE=pdfwrite -dSAFER -dBATCH -dNOPAUSE -dNOCACHE -dPDFX -sColorConversionStrategy=CMYK -sOutputFile=$vpath/$target '$vpath/$source'";
$DEBUG .= qq~vpath = '$vpath', command = '$COM', ~;
ONO::IO->exec3($COM);
}
}
if (ONO::IO->devstation) {
return "$DEBUG done";
} else {
return "";
}
}
sub compress {
my (
$self,
$source,
$target,
$switches,
) = @_;
#: PDF file compression, using Ghostscript. This may reduce the size of files generated by ONO by a factor of up to 10.
#:
#: -a always execute, even if sysload higher than 33%
#: -A always execute, even if sysload higher than 66%
#: -d delete source after successful compression
#: -E do not check if source exists, this may be required in faster generation situations
#: -o allow overwriting source if target = source
#: -O allow overwrite if target exists
#: -p quality = printer (default)
#: -s quality = screen (lower quality, higher compression)
my $gs = &detect_gs;
my $DEBUG = "ONO_Lib_PDF_ToolBox_compress, Ghostscript is '$gs', ";
my $SYSLOAD = ONO::IO->sysload();
my $sysload_exclude;
if (!ONO::IO->devstation) {
if ($SYSLOAD > 33 && $switches !~ /(a|A)/) {
$sysload_exclude = 1;
}
if ($SYSLOAD > 66 && $switches !~ /A/) {
$sysload_exclude = 1;
}
}
if ($gs && $source =~ /\.pdf/ && $target =~ /\.pdf/ && !$sysload_exclude) {
$source =~ s~[^A-Za-z0-9\/\-\_\.]~~g;
$target =~ s~[^A-Za-z0-9\/\-\_\.]~~g;
$DEBUG .= qq~GS found, sysload = '$SYSLOAD', source and target are PDF files ($source, $target), ~;
if ($source !~ /\.\./ && $target !~ /\.\./ && $source !~ /\/\./ && $target !~ /\/\./) {
$DEBUG .= qq~looks good, ~;
if (ONO::IO->exists($source) || $switches =~ /E/) {
$DEBUG .= qq~source validated, ~;
if (!ONO::IO->exists($target) || $switches =~ /O/) {
$DEBUG .= qq~target validated, ~;
if ($target ne $source || $switches =~ /o/) {
$DEBUG .= qq~write conditions validated, ~;
my $quality = "printer";
if ($switches =~ /s/) {
$quality = "screen";
}
my $use_target = $target;
if ($target eq $source && $switches =~ /o/) {
ONO::IO->mkpath("var/tmp/pdf-compress");
my $RAND = 9000000000+int(rand(999999999));
$use_target = "var/tmp/pdf-compress/tmp-$RAND.pdf";
}
my $vpath = ONO::IO->path();
my $COM = "$gs -sDEVICE=pdfwrite -dCompatibilityLevel=1.4 -dPDFSETTINGS=/$quality -dNOPAUSE -dQUIET -dBATCH -sOutputFile=$vpath/$use_target '$vpath/$source'";
$DEBUG .= qq~quality is '$quality', vpath = '$vpath', command = '$COM', ~;
ONO::IO->exec3($COM);
if ($use_target =~ m~^var/tmp/~) {
ONO::IO->exists_wait($use_target);
if (ONO::IO->exists($use_target)) {
ONO::IO->mv($use_target,$target);
}
}
if ($switches =~ /d/ && $source ne $target) {
$DEBUG .= qq~deleting resources, ~;
ONO::IO->rm($source);
}
} else {
$DEBUG .= "ABORT, ";
}
} else {
$DEBUG .= "ABORT, ";
}
} else {
$DEBUG .= "ABORT, ";
}
} else {
$DEBUG .= "ABORT, ";
}
} else {
$DEBUG .= "ABORT, ";
}
if (ONO::IO->devstation) {
return "$DEBUG done";
} else {
return "";
}
}
###############################################################################
# end of script
###############################################################################
1;
__END__