Merge remote-tracking branch 'origin/new/bug_7986'
[koha.git] / C4 / Creators / PDF.pm
1 package C4::Creators::PDF;
2
3 # Copyright 2009 Foundations Bible College.
4 #
5 # This file is part of Koha.
6 #
7 # Koha is free software; you can redistribute it and/or modify it under the
8 # terms of the GNU General Public License as published by the Free Software
9 # Foundation; either version 2 of the License, or (at your option) any later
10 # version.
11 #
12 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14 # A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License along
17 # with Koha; if not, write to the Free Software Foundation, Inc.,
18 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20 use strict;
21 use warnings;
22 use PDF::Reuse;
23 use PDF::Reuse::Barcode;
24 use File::Temp;
25
26 BEGIN {
27     use version; our $VERSION = qv('3.07.00.049');
28 }
29
30 sub _InitVars {
31     my $self = shift;
32     my $param = shift;
33     prInitVars($param);
34 }
35
36 sub new {
37     my $invocant = shift;
38     my $type = ref($invocant) || $invocant;
39     my %opts = @_;
40     my $self = {};
41     _InitVars() if ($opts{InitVars} == 0);
42     _InitVars($opts{InitVars}) if ($opts{InitVars} > 0);
43     delete($opts{InitVars});
44     prDocDir($opts{'DocDir'}) if $opts{'DocDir'};
45     delete($opts{'DocDir'});
46
47     my $fh = File::Temp->new( UNLINK => 0, SUFFIX => '.pdf' );
48     $opts{Name} = $self->{filename} = "$fh"; # filename
49     close $fh; # we need just filename
50
51     prFile(\%opts);
52     bless ($self, $type);
53     return $self;
54 }
55
56 sub End {
57     my $self = shift;
58     # if the pdf stream is utf8, explicitly set it to utf8; this avoids at lease some wide character errors -chris_n
59     utf8::encode($PDF::Reuse::stream) if utf8::is_utf8($PDF::Reuse::stream);
60     prEnd();
61
62     # slurp temporary filename and print it out for plack to pick up
63     local $/ = undef;
64     open(my $fh, '<', $self->{filename}) || die "$self->{filename}: $!";
65     print <$fh>;
66     close $fh;
67     unlink $self->{filename};
68 }
69
70 sub Add {
71     my $self = shift;
72     my $string = shift;
73     prAdd($string);
74 }
75
76 sub Bookmark {
77     my $self = shift;
78     my $reference = shift;
79     prBookmark($reference);
80 }
81
82 sub Compress {
83     my $self = shift;
84     my $directive = shift;
85     prCompress($directive);
86 }
87
88 sub Doc {
89     my $self = shift;
90     my %params = @_;
91     prDoc(%params);
92 }
93
94 sub DocForm {
95     my $self = shift;
96     my %params = @_;
97     return prDocForm(%params);
98 }
99
100 sub Extract {
101     my $self = shift;
102     my ($pdfFile, $pageNo, $oldInternalName) = @_;
103     return prExtract($pdfFile, $pageNo, $oldInternalName);
104 }
105
106 sub Field {
107     my $self = shift;
108     my ($fieldName, $value) = @_;
109     prField($fieldName, $value);
110 }
111
112 sub Font {
113     my $self = shift;
114     my $fontName = shift;
115     return prFont($fontName);
116 }
117
118 sub FontSize {
119     my $self = shift;
120     my $size = shift;
121     return prFontSize($size);
122 }
123
124 sub Form {
125     my $self = shift;
126     my %params = @_;
127     return prForm(%params);
128 }
129
130 sub GetLogBuffer {
131     my $self = shift;
132     return prGetLogBuffer();
133 }
134
135 sub GraphState {
136     my $self = shift;
137     my $string = shift;
138     prGraphState($string);
139 }
140
141 sub Image {
142     my $self = shift;
143     my %params = @_;
144     return prImage(%params);
145 }
146
147 sub Init {
148     my $self = shift;
149     my ($string, $duplicateCode) = @_;
150     prInit($string, $duplicateCode);
151 }
152
153 sub AltJpeg {
154     my $self = shift;
155     my ($imageData, $width, $height, $imageFormat, $altImageData, $altImageWidth, $altImageHeight, $altImageFormat) = @_;
156     return prAltJpeg($imageData, $width, $height, $imageFormat, $altImageData, $altImageWidth, $altImageHeight, $altImageFormat);
157 }
158
159 sub Jpeg {
160     my $self = shift;
161     my ($imageData, $width, $height, $imageFormat) = @_;
162     return prJpegBlob($imageData, $width, $height, $imageFormat);
163 }
164
165 # FIXME: This magick foo is an absolute hack until the maintainer of PDF::Reuse releases the next version which will include these features
166
167 sub prAltJpeg
168 {  my ($iData, $iWidth, $iHeight, $iFormat,$aiData, $aiWidth, $aiHeight, $aiFormat) = @_;
169    my ($namnet, $utrad);
170    if (! $PDF::Reuse::pos)                    # If no output is active, it is no use to continue
171    {   return;
172    }
173    prJpegBlob($aiData, $aiWidth, $aiHeight, $aiFormat);
174    my $altObjNr = $PDF::Reuse::objNr;
175    $PDF::Reuse::imageNr++;
176    $namnet = 'Ig' . $PDF::Reuse::imageNr;
177    $PDF::Reuse::objNr++;
178    $PDF::Reuse::objekt[$PDF::Reuse::objNr] = $PDF::Reuse::pos;
179    $utrad = "$PDF::Reuse::objNr 0 obj\n" .
180             "[ << /Image $altObjNr 0 R\n" .
181             "/DefaultForPrinting true\n" .
182             ">>\n" .
183             "]\n" .
184             "endobj\n";
185    $PDF::Reuse::pos += syswrite *PDF::Reuse::UTFIL, $utrad;
186    if ($PDF::Reuse::runfil)
187    {  $PDF::Reuse::log .= "Jpeg~AltImage\n";
188    }
189    $PDF::Reuse::objRef{$namnet} = $PDF::Reuse::objNr;
190    $namnet = prJpegBlob($iData, $iWidth, $iHeight, $iFormat, $PDF::Reuse::objNr);
191    if (! $PDF::Reuse::pos)
192    {  errLog("No output file, you have to call prFile first");
193    }
194    return $namnet;
195 }
196
197 sub prJpegBlob
198 {  my ($iData, $iWidth, $iHeight, $iFormat, $altArrayObjNr) = @_;
199    my ($iLangd, $namnet, $utrad);
200    if (! $PDF::Reuse::pos)                    # If no output is active, it is no use to continue
201    {   return;
202    }
203    my $checkidOld = $PDF::Reuse::checkId;
204    if (!$iFormat)
205    {   my ($iFile, $checkId) = findGet($iData, $checkidOld);
206        if ($iFile)
207        {  $iLangd = (stat($iFile))[7];
208           $PDF::Reuse::imageNr++;
209           $namnet = 'Ig' . $PDF::Reuse::imageNr;
210           $PDF::Reuse::objNr++;
211           $PDF::Reuse::objekt[$PDF::Reuse::objNr] = $PDF::Reuse::pos;
212           open (my $fh, '<', "$iFile") || errLog("Couldn't open $iFile, $!, aborts");
213           binmode $fh;
214           my $iStream;
215           sysread $fh, $iStream, $iLangd;
216           $utrad = "$PDF::Reuse::objNr 0 obj\n<</Type/XObject/Subtype/Image/Name/$namnet" .
217                     "/Width $iWidth /Height $iHeight /BitsPerComponent 8 " .
218                     ($altArrayObjNr ? "/Alternates $altArrayObjNr 0 R " : "") .
219                     "/Filter/DCTDecode/ColorSpace/DeviceRGB"
220                     . "/Length $iLangd >>stream\n$iStream\nendstream\nendobj\n";
221           close $fh;
222           $PDF::Reuse::pos += syswrite $PDF::Reuse::UTFIL, $utrad;
223           if ($PDF::Reuse::runfil)
224           {  $PDF::Reuse::log .= "Cid~$PDF::Reuse::checkId\n";
225              $PDF::Reuse::log .= "Jpeg~$iFile~$iWidth~$iHeight\n";
226           }
227           $PDF::Reuse::objRef{$namnet} = $PDF::Reuse::objNr;
228        }
229        undef $checkId;
230    }
231    elsif ($iFormat == 1)
232    {  my $iBlob = $iData;
233       $iLangd = length($iBlob);
234       $PDF::Reuse::imageNr++;
235       $namnet = 'Ig' . $PDF::Reuse::imageNr;
236       $PDF::Reuse::objNr++;
237       $PDF::Reuse::objekt[$PDF::Reuse::objNr] = $PDF::Reuse::pos;
238       $utrad = "$PDF::Reuse::objNr 0 obj\n<</Type/XObject/Subtype/Image/Name/$namnet" .
239                 "/Width $iWidth /Height $iHeight /BitsPerComponent 8 " .
240                 ($altArrayObjNr ? "/Alternates $altArrayObjNr 0 R " : "") .
241                 "/Filter/DCTDecode/ColorSpace/DeviceRGB"
242                 . "/Length $iLangd >>stream\n$iBlob\nendstream\nendobj\n";
243       $PDF::Reuse::pos += syswrite *PDF::Reuse::UTFIL, $utrad;
244       if ($PDF::Reuse::runfil)
245       {  $PDF::Reuse::log .= "Jpeg~Blob~$iWidth~$iHeight\n";
246       }
247       $PDF::Reuse::objRef{$namnet} = $PDF::Reuse::objNr;
248    }
249    if (! $PDF::Reuse::pos)
250    {  errLog("No output file, you have to call prFile first");
251    }
252    return $namnet;
253 }
254
255 sub Js {
256     my $self = shift;
257     my $string_or_fileName = shift;
258     prJs($string_or_fileName);
259 }
260
261 sub Link {
262     my $self = shift;
263     my %params = @_;
264     prLink(%params);
265 }
266
267 sub Log {
268     my $self = shift;
269     my $string = shift;
270     prLog($string);
271 }
272
273 sub LogDir {
274     my $self = shift;
275     my $directory = shift;
276     prLogDir($directory);
277 }
278
279 sub Mbox {
280     my $self = shift;
281     my ($lowerLeftX, $lowerLeftY, $upperRightX, $upperRightY) = @_;
282     prMbox($lowerLeftX, $lowerLeftY, $upperRightX, $upperRightY);
283 }
284
285 sub Page {
286     my $self = shift;
287     my $noLog = shift;
288     prPage($noLog);
289 }
290
291 sub SinglePage {
292     my $self = shift;
293     my ($file, $pageNumber) = @_;
294     return prSinglePage($file, $pageNumber);
295 }
296
297 sub StrWidth {
298     my $self = shift;
299     my ($string, $font, $fontSize) = @_;
300     return prStrWidth($string, $font, $fontSize);
301 }
302
303 sub Text {
304     my $self = shift;
305     my ($x, $y, $string, $align, $rotation) = @_;
306     return prText($x, $y, $string, $align, $rotation);
307 }
308
309 sub TTFont {
310     my $self = shift;
311     my $path = shift;
312     return prTTFont($path);
313 }
314
315 sub Code128 {
316     my $self = shift;
317     my %opts = @_;
318     PDF::Reuse::Barcode::Code128(%opts);
319 }
320
321 sub Code39 {
322     my $self = shift;
323     my %opts = @_;
324     PDF::Reuse::Barcode::Code39(%opts);
325 }
326
327 sub COOP2of5 {
328     my $self = shift;
329     my %opts = @_;
330     PDF::Reuse::Barcode::COOP2of5(%opts);
331 }
332
333 sub EAN13 {
334     my $self = shift;
335     my %opts = @_;
336     PDF::Reuse::Barcode::EAN13(%opts);
337 }
338
339 sub EAN8 {
340     my $self = shift;
341     my %opts = @_;
342     PDF::Reuse::Barcode::EAN8(%opts);
343 }
344
345 sub IATA2of5 {
346     my $self = shift;
347     my %opts = @_;
348     PDF::Reuse::Barcode::IATA2of5(%opts);
349 }
350
351 sub Industrial2of5 {
352     my $self = shift;
353     my %opts = @_;
354     PDF::Reuse::Barcode::Industrial2of5(%opts);
355 }
356
357 sub ITF {
358     my $self = shift;
359     my %opts = @_;
360     PDF::Reuse::Barcode::ITF(%opts);
361 }
362
363 sub Matrix2of5 {
364     my $self = shift;
365     my %opts = @_;
366     PDF::Reuse::Barcode::Matrix2of5(%opts);
367 }
368
369 sub NW7 {
370     my $self = shift;
371     my %opts = @_;
372     PDF::Reuse::Barcode::NW7(%opts);
373 }
374
375 sub UPCA {
376     my $self = shift;
377     my %opts = @_;
378     PDF::Reuse::Barcode::UPCA(%opts);
379 }
380
381 sub UPCE {
382     my $self = shift;
383     my %opts = @_;
384     PDF::Reuse::Barcode::UPCE(%opts);
385 }
386
387 1;
388 __END__
389
390
391 =head1 NAME
392
393 C4::Creators::PDF -   A class wrapper for PDF::Reuse and PDF::Reuse::Barcode to allow usage as a psuedo-object. For usage see
394                     PDF::Reuse documentation and C4::Creators::PDF code.
395
396 =cut
397
398 =head1 AUTHOR
399
400 Chris Nighswonger <cnighswonger AT foundations DOT edu>
401
402 =cut