source: trunk/data/pdf/fpdi.php @ 17232

Revision 17232, 14.4 KB checked in by satou, 14 years ago (diff)

納品書発行機能 by Yammy (merge r17182)

Line 
1<?php
2//
3//  FPDI - Version 1.2
4//
5//    Copyright 2004-2007 Setasign - Jan Slabon
6//
7//  Licensed under the Apache License, Version 2.0 (the "License");
8//  you may not use this file except in compliance with the License.
9//  You may obtain a copy of the License at
10//
11//      http://www.apache.org/licenses/LICENSE-2.0
12//
13//  Unless required by applicable law or agreed to in writing, software
14//  distributed under the License is distributed on an "AS IS" BASIS,
15//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16//  See the License for the specific language governing permissions and
17//  limitations under the License.
18//
19
20define('FPDI_VERSION','1.2');
21
22ini_set('auto_detect_line_endings',1); // Strongly required!
23
24require_once("fpdf_tpl.php");
25require_once("fpdi_pdf_parser.php");
26
27
28class FPDI extends FPDF_TPL {
29    /**
30     * Actual filename
31     * @var string
32     */
33    var $current_filename;
34
35    /**
36     * Parser-Objects
37     * @var array
38     */
39    var $parsers;
40   
41    /**
42     * Current parser
43     * @var object
44     */
45    var $current_parser;
46   
47    /**
48     * Highest version of imported PDF
49     * @var double
50     */
51    var $importVersion = 1.3;
52
53    /**
54     * object stack
55     * @var array
56     */
57    var $_obj_stack;
58   
59    /**
60     * done object stack
61     * @var array
62     */
63    var $_don_obj_stack;
64
65    /**
66     * Current Object Id.
67     * @var integer
68     */
69    var $_current_obj_id;
70   
71    /**
72     * The name of the last imported page box
73     * @var string
74     */
75    var $lastUsedPageBox;
76   
77    /**
78     * Constructor
79     * See FPDF-Manual
80     */
81    function FPDI($orientation='P',$unit='mm',$format='A4') {
82        parent::FPDF_TPL($orientation,$unit,$format);
83    }
84   
85    /**
86     * Set a source-file
87     *
88     * @param string $filename a valid filename
89     * @return int number of available pages
90     */
91    function setSourceFile($filename) {
92        $this->current_filename = $filename;
93        $fn =& $this->current_filename;
94
95        if (!isset($this->parsers[$fn]))
96            $this->parsers[$fn] =& new fpdi_pdf_parser($fn,$this);
97        $this->current_parser =& $this->parsers[$fn];
98       
99        return $this->parsers[$fn]->getPageCount();
100    }
101   
102    /**
103     * Import a page
104     *
105     * @param int $pageno pagenumber
106     * @return int Index of imported page - to use with fpdf_tpl::useTemplate()
107     */
108    function importPage($pageno, $boxName='/CropBox') {
109        if ($this->_intpl) {
110            return $this->error("Please import the desired pages before creating a new template.");
111        }
112       
113        $fn =& $this->current_filename;
114       
115        $parser =& $this->parsers[$fn];
116        $parser->setPageno($pageno);
117
118        $this->tpl++;
119        $this->tpls[$this->tpl] = array();
120        $tpl =& $this->tpls[$this->tpl];
121        $tpl['parser'] =& $parser;
122        $tpl['resources'] = $parser->getPageResources();
123        $tpl['buffer'] = $parser->getContent();
124       
125        if (!in_array($boxName, $parser->availableBoxes))
126            return $this->Error(sprintf("Unknown box: %s", $boxName));
127        $pageboxes = $parser->getPageBoxes($pageno);
128       
129        /**
130         * MediaBox
131         * CropBox: Default -> MediaBox
132         * BleedBox: Default -> CropBox
133         * TrimBox: Default -> CropBox
134         * ArtBox: Default -> CropBox
135         */
136        if (!isset($pageboxes[$boxName]) && ($boxName == "/BleedBox" || $boxName == "/TrimBox" || $boxName == "/ArtBox"))
137            $boxName = "/CropBox";
138        if (!isset($pageboxes[$boxName]) && $boxName == "/CropBox")
139            $boxName = "/MediaBox";
140       
141        if (!isset($pageboxes[$boxName]))
142            return false;
143        $this->lastUsedPageBox = $boxName;
144       
145        $box = $pageboxes[$boxName];
146        $tpl['box'] = $box;
147       
148        // To build an array that can be used by PDF_TPL::useTemplate()
149        $this->tpls[$this->tpl] = array_merge($this->tpls[$this->tpl],$box);
150        // An imported page will start at 0,0 everytime. Translation will be set in _putformxobjects()
151        $tpl['x'] = 0;
152        $tpl['y'] = 0;
153       
154        $page =& $parser->pages[$parser->pageno];
155       
156        // fix for rotated pages
157        $rotation = $parser->getPageRotation($pageno);
158        if (isset($rotation[1]) && ($angle = $rotation[1] % 360) != 0) {
159            $steps = $angle / 90;
160               
161            $_w = $tpl['w'];
162            $_h = $tpl['h'];
163            $tpl['w'] = $steps % 2 == 0 ? $_w : $_h;
164            $tpl['h'] = $steps % 2 == 0 ? $_h : $_w;
165           
166            if ($steps % 2 != 0) {
167                $x = $y = ($steps == 1 || $steps == -3) ? $tpl['h'] : $tpl['w'];
168            } else {
169                $x = $tpl['w'];
170                $y = $tpl['h'];
171            }
172           
173            $cx=($x/2+$tpl['box']['x'])*$this->k;
174            $cy=($y/2+$tpl['box']['y'])*$this->k;
175           
176            $angle*=-1;
177           
178            $angle*=M_PI/180;
179            $c=cos($angle);
180            $s=sin($angle);
181           
182            $tpl['buffer'] = sprintf('q %.5f %.5f %.5f %.5f %.2f %.2f cm 1 0 0 1 %.2f %.2f cm %s Q',$c,$s,-$s,$c,$cx,$cy,-$cx,-$cy, $tpl['buffer']);
183        }
184       
185        return $this->tpl;
186    }
187   
188    function getLastUsedPageBox() {
189        return $this->lastUsedPageBox;
190    }
191   
192    function useTemplate($tplidx, $_x=null, $_y=null, $_w=0, $_h=0) {
193        $this->_out('q 0 J 1 w 0 j 0 G'); // reset standard values
194        $s = parent::useTemplate($tplidx, $_x, $_y, $_w, $_h);
195        $this->_out('Q');
196        return $s;
197    }
198   
199    /**
200     * Private method, that rebuilds all needed objects of source files
201     */
202    function _putimportedobjects() {
203        if (is_array($this->parsers) && count($this->parsers) > 0) {
204            foreach($this->parsers AS $filename => $p) {
205                $this->current_parser =& $this->parsers[$filename];
206                if (is_array($this->_obj_stack[$filename])) {
207                    while($n = key($this->_obj_stack[$filename])) {
208                        $nObj = $this->current_parser->pdf_resolve_object($this->current_parser->c,$this->_obj_stack[$filename][$n][1]);
209                       
210                        $this->_newobj($this->_obj_stack[$filename][$n][0]);
211                       
212                        if ($nObj[0] == PDF_TYPE_STREAM) {
213                            $this->pdf_write_value ($nObj);
214                        } else {
215                            $this->pdf_write_value ($nObj[1]);
216                        }
217                       
218                        $this->_out('endobj');
219                        $this->_obj_stack[$filename][$n] = null; // free memory
220                        unset($this->_obj_stack[$filename][$n]);
221                        reset($this->_obj_stack[$filename]);
222                    }
223                }
224            }
225        }
226    }
227   
228    /**
229     * Sets the PDF Version to the highest of imported documents
230     */
231    function setVersion() {
232        $this->PDFVersion = max($this->importVersion, $this->PDFVersion);
233    }
234   
235    /**
236     * Put resources
237     */
238    function _putresources() {
239        $this->_putfonts();
240        $this->_putimages();
241        $this->_putformxobjects();
242        $this->_putimportedobjects();
243        //Resource dictionary
244        $this->offsets[2]=strlen($this->buffer);
245        $this->_out('2 0 obj');
246        $this->_out('<<');
247        $this->_putresourcedict();
248        $this->_out('>>');
249        $this->_out('endobj');
250    }
251   
252    /**
253     * Private Method that writes the form xobjects
254     */
255    function _putformxobjects() {
256        $filter=($this->compress) ? '/Filter /FlateDecode ' : '';
257        reset($this->tpls);
258        foreach($this->tpls AS $tplidx => $tpl) {
259            $p=($this->compress) ? gzcompress($tpl['buffer']) : $tpl['buffer'];
260            $this->_newobj();
261            $this->tpls[$tplidx]['n'] = $this->n;
262            $this->_out('<<'.$filter.'/Type /XObject');
263            $this->_out('/Subtype /Form');
264            $this->_out('/FormType 1');
265           
266            $this->_out(sprintf('/BBox [%.2f %.2f %.2f %.2f]',
267                ($tpl['x'] + (isset($tpl['box']['x'])?$tpl['box']['x']:0))*$this->k,
268                ($tpl['h'] + (isset($tpl['box']['y'])?$tpl['box']['y']:0) - $tpl['y'])*$this->k,
269                ($tpl['w'] + (isset($tpl['box']['x'])?$tpl['box']['x']:0))*$this->k,
270                ($tpl['h'] + (isset($tpl['box']['y'])?$tpl['box']['y']:0) - $tpl['y']-$tpl['h'])*$this->k)
271            );
272           
273            if (isset($tpl['box']))
274                $this->_out(sprintf('/Matrix [1 0 0 1 %.5f %.5f]',-$tpl['box']['x']*$this->k, -$tpl['box']['y']*$this->k));
275           
276            $this->_out('/Resources ');
277
278            if (isset($tpl['resources'])) {
279                $this->current_parser =& $tpl['parser'];
280                $this->pdf_write_value($tpl['resources']);
281            } else {
282                $this->_out('<</ProcSet [/PDF /Text /ImageB /ImageC /ImageI]');
283                if (isset($this->_res['tpl'][$tplidx]['fonts']) && count($this->_res['tpl'][$tplidx]['fonts'])) {
284                    $this->_out('/Font <<');
285                    foreach($this->_res['tpl'][$tplidx]['fonts'] as $font)
286                        $this->_out('/F'.$font['i'].' '.$font['n'].' 0 R');
287                    $this->_out('>>');
288                }
289                if(isset($this->_res['tpl'][$tplidx]['images']) && count($this->_res['tpl'][$tplidx]['images']) ||
290                   isset($this->_res['tpl'][$tplidx]['tpls']) && count($this->_res['tpl'][$tplidx]['tpls']))
291                {
292                    $this->_out('/XObject <<');
293                    if (isset($this->_res['tpl'][$tplidx]['images']) && count($this->_res['tpl'][$tplidx]['images'])) {
294                        foreach($this->_res['tpl'][$tplidx]['images'] as $image)
295                            $this->_out('/I'.$image['i'].' '.$image['n'].' 0 R');
296                    }
297                    if (isset($this->_res['tpl'][$tplidx]['tpls']) && count($this->_res['tpl'][$tplidx]['tpls'])) {
298                        foreach($this->_res['tpl'][$tplidx]['tpls'] as $i => $tpl)
299                            $this->_out($this->tplprefix.$i.' '.$tpl['n'].' 0 R');
300                    }
301                    $this->_out('>>');
302                }
303                $this->_out('>>');
304            }
305
306            $this->_out('/Length '.strlen($p).' >>');
307            $this->_putstream($p);
308            $this->_out('endobj');
309        }
310    }
311
312    /**
313     * Rewritten to handle existing own defined objects
314     */
315    function _newobj($obj_id=false,$onlynewobj=false) {
316        if (!$obj_id) {
317            $obj_id = ++$this->n;
318        }
319
320        //Begin a new object
321        if (!$onlynewobj) {
322            $this->offsets[$obj_id] = strlen($this->buffer);
323            $this->_out($obj_id.' 0 obj');
324            $this->_current_obj_id = $obj_id; // for later use with encryption
325        }
326       
327    }
328
329    /**
330     * Writes a value
331     * Needed to rebuild the source document
332     *
333     * @param mixed $value A PDF-Value. Structure of values see cases in this method
334     */
335    function pdf_write_value(&$value)
336    {
337
338        switch ($value[0]) {
339
340            case PDF_TYPE_NUMERIC :
341            case PDF_TYPE_TOKEN :
342                // A numeric value or a token.
343                // Simply output them
344                $this->_out($value[1]." ", false);
345                break;
346
347            case PDF_TYPE_ARRAY :
348
349                // An array. Output the proper
350                // structure and move on.
351
352                $this->_out("[",false);
353                for ($i = 0; $i < count($value[1]); $i++) {
354                    $this->pdf_write_value($value[1][$i]);
355                }
356
357                $this->_out("]");
358                break;
359
360            case PDF_TYPE_DICTIONARY :
361
362                // A dictionary.
363                $this->_out("<<",false);
364
365                reset ($value[1]);
366
367                while (list($k, $v) = each($value[1])) {
368                    $this->_out($k . " ",false);
369                    $this->pdf_write_value($v);
370                }
371
372                $this->_out(">>");
373                break;
374
375            case PDF_TYPE_OBJREF :
376
377                // An indirect object reference
378                // Fill the object stack if needed
379                $cpfn =& $this->current_parser->filename;
380                if (!isset($this->_don_obj_stack[$cpfn][$value[1]])) {
381                    $this->_newobj(false,true);
382                    $this->_obj_stack[$cpfn][$value[1]] = array($this->n, $value);
383                    $this->_don_obj_stack[$cpfn][$value[1]] = array($this->n, $value);
384                }
385                $objid = $this->_don_obj_stack[$cpfn][$value[1]][0];
386
387                $this->_out("{$objid} 0 R"); //{$value[2]}
388                break;
389
390            case PDF_TYPE_STRING :
391
392                // A string.
393                $this->_out('('.$value[1].')');
394
395                break;
396
397            case PDF_TYPE_STREAM :
398
399                // A stream. First, output the
400                // stream dictionary, then the
401                // stream data itself.
402                $this->pdf_write_value($value[1]);
403                $this->_out("stream");
404                $this->_out($value[2][1]);
405                $this->_out("endstream");
406                break;
407            case PDF_TYPE_HEX :
408           
409                $this->_out("<".$value[1].">");
410                break;
411
412            case PDF_TYPE_NULL :
413                // The null object.
414
415                $this->_out("null");
416                break;
417        }
418    }
419   
420   
421    /**
422     * Private Method
423     */
424    function _out($s,$ln=true) {
425       //Add a line to the document
426       if ($this->state==2) {
427           if (!$this->_intpl)
428               $this->pages[$this->page] .= $s.($ln == true ? "\n" : '');
429           else
430               $this->tpls[$this->tpl]['buffer'] .= $s.($ln == true ? "\n" : '');
431       } else {
432           $this->buffer.=$s.($ln == true ? "\n" : '');
433       }
434    }
435
436    /**
437     * rewritten to close opened parsers
438     *
439     */
440    function _enddoc() {
441        parent::_enddoc();
442        $this->_closeParsers();
443    }
444   
445    /**
446     * close all files opened by parsers
447     */
448    function _closeParsers() {
449        if ($this->state > 2 && count($this->parsers) > 0) {
450            foreach ($this->parsers as $k => $_){
451                $this->parsers[$k]->closeFile();
452                $this->parsers[$k] = null;
453                unset($this->parsers[$k]);
454            }
455            return true;
456        }
457        return false;
458    }
459
460}
461
462// for PHP5
463if (!class_exists('fpdi')) {
464    class fpdi extends FPDI {}
465}
466?>
Note: See TracBrowser for help on using the repository browser.