3 # 2001-2 Sey <nakajima@netstock.co.jp>
10 use vars qw($VERSION @EXFUNC %Default);
15 PDFJ::TextStyle::TStyle PDFJ::Text::Text
16 PDFJ::NewLine::NewLine PDFJ::Outline::Outline PDFJ::Dest::Dest
17 PDFJ::ParagraphStyle::PStyle PDFJ::Paragraph::Paragraph
18 PDFJ::BlockStyle::BStyle PDFJ::Block::Block PDFJ::NewBlock::NewBlock
20 PDFJ::ShapeStyle::SStyle PDFJ::Color::Color
24 my($pkg, $code, $prefix) = @_;
26 croak "code argument '$code' must be 'SJIS' or 'EUC'"
27 unless $code =~ /^(SJIS|EUC)$/;
28 $Default{Jcode} = $code;
31 for my $name(@EXFUNC) {
34 ($from, $name) = $name =~ /^(.+)::([^:]+)$/;
36 *{"${to}::$prefix$name"} = \&{"${from}::$name"};
40 $Default{Jcode} = 'SJIS';
42 $Default{AFontEncoding} = 'WinAnsiEncoding';
43 $Default{BaseAFont} = 'Times-Roman';
44 $Default{JFontEncoding} = '90ms-RKSJ-H';
45 $Default{BaseJFont} = 'Ryumin-Light';
47 # $Default{BBox} = [-200,-331,1116,962];
48 $Default{BBox} = [-150,-331,1143,962];
50 $Default{SBoxH} = [0,-125,1000,875];
51 $Default{SBoxV} = [-500,-1000,500,0];
53 $Default{ULine} = -200;
54 $Default{OLine} = 900;
55 $Default{LLine} = -550;
56 $Default{RLine} = 550;
58 $Default{ORuby} = 950;
59 $Default{RRuby} = 750;
61 $Default{HBaseShift} = 0.125;
62 $Default{HBaseHeight} = 0.875;
64 $Default{ParaPreSkipRatio} = 0.5;
65 $Default{ParaPostSkipRatio} = 0.5;
67 $Default{SlantRatio} = 0.2;
69 $Default{HDotXShift} = 0;
70 $Default{HDotYShift} = 0.7;
71 $Default{HDot}{SJIS} = "\x81\x45";
72 $Default{HDot}{EUC} = "\xa1\xa6";
74 $Default{VDotXShift} = 0.5;
75 $Default{VDotYShift} = -0.3;
76 $Default{VDot}{SJIS} = "\x81\x41";
77 $Default{VDot}{EUC} = "\xa1\xa2";
79 $Default{VHShift} = 0.8;
80 $Default{VAShift} = -0.33;
82 $Default{SuffixSize} = 0.6;
83 $Default{USuffixRise} = 0.5;
84 $Default{LSuffixRise} = -0.15;
86 $Default{HNote} = 990;
87 $Default{VNote} = 750;
89 $Default{Fonts} = {qw(
96 Helvetica-BoldOblique a
106 $Default{Encodings} = {qw(
121 $Default{JFD}{'Ryumin-Light'} =
123 Type => name('FontDescriptor'),
128 FontBBox => [-170,-331,1024,903],
129 FontName => name('Ryumin-Light'),
135 value => '010502020300000000000000',
136 outputtype => 'hexliteral')
140 $Default{JFD}{'GothicBBB-Medium'} =
142 Type => name('FontDescriptor'),
147 FontBBox => [-174,-268,1001,944],
148 FontName => name('GothicBBB-Medium'),
154 value => '0801020b0500000000000000',
155 outputtype => 'hexliteral')
159 # character class (based on JIS X 4051)
162 # 2: not at top of line
178 $Default{Class}{SJIS} = {
180 "\x81\x65" => 0, "\x81\x67" => 0, "\x81\x69" => 0, "\x81\x6b" => 0,
181 "\x81\x6d" => 0, "\x81\x6f" => 0, "\x81\x71" => 0, "\x81\x73" => 0,
182 "\x81\x75" => 0, "\x81\x77" => 0, "\x81\x79" => 0,
184 "\x81\x41" => 1, "\x81\x43" => 1,
185 "\x81\x66" => 1, "\x81\x68" => 1, "\x81\x6a" => 1, "\x81\x6c" => 1,
186 "\x81\x6e" => 1, "\x81\x70" => 1, "\x81\x72" => 1, "\x81\x74" => 1,
187 "\x81\x76" => 1, "\x81\x78" => 1, "\x81\x7a" => 1,
189 "\x81\x52" => 2, "\x81\x53" => 2, "\x81\x54" => 2, "\x81\x55" => 2,
190 "\x81\x58" => 2, "\x81\x5b" => 2,
191 "\x82\x9f" => 2, "\x82\xa1" => 2, "\x82\xa3" => 2, "\x82\xa5" => 2,
192 "\x82\xa7" => 2, "\x82\xc1" => 2, "\x82\xe1" => 2, "\x82\xe3" => 2,
193 "\x82\xe5" => 2, "\x82\xec" => 2,
194 "\x83\x40" => 2, "\x83\x42" => 2, "\x83\x44" => 2, "\x83\x46" => 2,
195 "\x83\x48" => 2, "\x83\x62" => 2, "\x83\x83" => 2, "\x83\x85" => 2,
196 "\x83\x87" => 2, "\x83\x8e" => 2, "\x83\x95" => 2, "\x83\x96" => 2,
198 "\x81\x48" => 3, "\x81\x49" => 3,
200 "\x81\x45" => 4, "\x81\x46" => 4, "\x81\x47" => 4,
202 "\x81\x42" => 5, "\x81\x44" => 5,
204 "\x81\x5c" => 6, "\x81\x63" => 6, "\x81\x64" => 6,
206 "\x81\x8f" => 7, "\x81\x90" => 7, "\x81\x92" => 7,
208 "\x81\x8b" => 8, "\x81\x8c" => 8, "\x81\x8d" => 8,
209 "\x81\x91" => 8, "\x81\x93" => 8, "\x81\xf1" => 8,
214 $Default{PreShift}{SJIS} = {
216 "\x81\x65" => 500, "\x81\x67" => 500, "\x81\x69" => 500, "\x81\x6b" => 500,
217 "\x81\x6d" => 500, "\x81\x6f" => 500, "\x81\x71" => 500, "\x81\x73" => 500,
218 "\x81\x75" => 500, "\x81\x77" => 500, "\x81\x79" => 500,
220 "\x81\x45" => 250, "\x81\x46" => 250, "\x81\x47" => 250,
223 $Default{PostShift}{SJIS} = {
225 "\x81\x41" => 500, "\x81\x43" => 500,
226 "\x81\x66" => 500, "\x81\x68" => 500, "\x81\x6a" => 500, "\x81\x6c" => 500,
227 "\x81\x6e" => 500, "\x81\x70" => 500, "\x81\x72" => 500, "\x81\x74" => 500,
228 "\x81\x76" => 500, "\x81\x78" => 500, "\x81\x7a" => 500,
230 "\x81\x45" => 250, "\x81\x46" => 250, "\x81\x47" => 250,
232 "\x81\x42" => 500, "\x81\x44" => 500,
234 "\x81\x8b" => 500, "\x81\x8c" => 500, "\x81\x8d" => 500,
237 $Default{Class}{EUC} = {
239 "\xa1\xc6" => 0, "\xa1\xc8" => 0, "\xa1\xca" => 0, "\xa1\xcc" => 0,
240 "\xa1\xce" => 0, "\xa1\xd0" => 0, "\xa1\xd2" => 0, "\xa1\xd4" => 0,
241 "\xa1\xd6" => 0, "\xa1\xd8" => 0, "\xa1\xda" => 0,
243 "\xa1\xa2" => 1, "\xa1\xa4" => 1,
244 "\xa1\xc7" => 1, "\xa1\xc9" => 1, "\xa1\xcb" => 1, "\xa1\xcd" => 1,
245 "\xa1\xcf" => 1, "\xa1\xd1" => 1, "\xa1\xd3" => 1, "\xa1\xd5" => 1,
246 "\xa1\xd7" => 1, "\xa1\xd9" => 1, "\xa1\xdb" => 1,
248 "\xa1\xb3" => 2, "\xa1\xb4" => 2, "\xa1\xb5" => 2, "\xa1\xb6" => 2,
249 "\xa1\xb9" => 2, "\xa1\xbc" => 2,
250 "\xa4\xa1" => 2, "\xa4\xa3" => 2, "\xa4\xa5" => 2, "\xa4\xa7" => 2,
251 "\xa4\xa9" => 2, "\xa4\xc3" => 2, "\xa4\xe3" => 2, "\xa4\xe5" => 2,
252 "\xa4\xe7" => 2, "\xa4\xee" => 2,
253 "\xa5\xa1" => 2, "\xa5\xa3" => 2, "\xa5\xa5" => 2, "\xa5\xa7" => 2,
254 "\xa5\xa9" => 2, "\xa5\xc3" => 2, "\xa5\xe3" => 2, "\xa5\xe5" => 2,
255 "\xa5\xe7" => 2, "\xa5\xee" => 2, "\xa5\xf5" => 2, "\xa5\xf6" => 2,
257 "\xa1\xa9" => 3, "\xa1\xaa" => 3,
259 "\xa1\xa6" => 4, "\xa1\xa7" => 4, "\xa1\xa8" => 4,
261 "\xa1\xa3" => 5, "\xa1\xa5" => 5,
263 "\xa1\xbd" => 6, "\xa1\xc4" => 6, "\xa1\xc5" => 6,
265 "\xa1\xef" => 7, "\xa1\xf0" => 7, "\xa1\xf2" => 7,
267 "\xa1\xeb" => 8, "\xa1\xec" => 8, "\xa1\xed" => 8, "\xa1\xf1" => 8,
268 "\xa1\xf3" => 8, "\xa2\xf3" => 8,
273 $Default{PreShift}{EUC} = {
275 "\xa1\xc6" => 500, "\xa1\xc8" => 500, "\xa1\xca" => 500, "\xa1\xcc" => 500,
276 "\xa1\xce" => 500, "\xa1\xd0" => 500, "\xa1\xd2" => 500, "\xa1\xd4" => 500,
277 "\xa1\xd6" => 500, "\xa1\xd8" => 500, "\xa1\xda" => 500,
279 "\xa1\xa6" => 250, "\xa1\xa7" => 250, "\xa1\xa8" => 250,
282 $Default{PostShift}{EUC} = {
284 "\xa1\xa2" => 500, "\xa1\xa4" => 500,
285 "\xa1\xc7" => 500, "\xa1\xc9" => 500, "\xa1\xcb" => 500, "\xa1\xcd" => 500,
286 "\xa1\xcf" => 500, "\xa1\xd1" => 500, "\xa1\xd3" => 500, "\xa1\xd5" => 500,
287 "\xa1\xd7" => 500, "\xa1\xd9" => 500, "\xa1\xdb" => 500,
289 "\xa1\xa6" => 250, "\xa1\xa7" => 250, "\xa1\xa8" => 250,
291 "\xa1\xa3" => 500, "\xa1\xa5" => 500,
293 "\xa1\xeb" => 500, "\xa1\xec" => 500, "\xa1\xed" => 500, "\xa1\xf1" => 500,
297 # each element means [min, normal, max, preference]
298 # ruby overlap feature is omitted
299 sub GlueNon { [0, 0, 0] }
300 sub Glue004 { [0, 0, 250] }
301 sub Glue0443 { [0, 250, 250, 3] }
302 sub Glue0223 { [0, 500, 500, 3] }
303 sub Glue0222 { [0, 500, 500, 2] }
304 sub Glue222 { [500, 500, 500] }
305 sub Glue844 { [125, 250, 250] }
306 sub Glue8421 { [125, 250, 500, 1] }
307 sub Glue266 { [500, 750, 750] }
312 GlueNon, # 0: begin paren
313 GlueNon, # 1: end paren
314 GlueNon, # 2: not at top of line
319 GlueNon, # 7: pre unit
320 GlueNon, # 8: post unit
321 GlueNon, # 9: zenkaku space
322 GlueNon, # 10: hirakana
323 GlueNon, # 11: japanese
324 GlueNon, # 12: suffixed
325 GlueNon, # 13: rubied
326 GlueNon, # 14: number
333 Glue0222, # 0: begin paren
334 GlueNon, # 1: end paren
335 Glue0222, # 2: not at top of line
339 Glue0222, # 6: leader
340 Glue0222, # 7: pre unit
341 Glue0222, # 8: post unit
342 GlueNon, # 9: zenkaku space
343 Glue0222, # 10: hirakana
344 Glue0222, # 11: japanese
345 Glue0222, # 12: suffixed
346 Glue0222, # 13: rubied
347 Glue0222, # 14: number
349 Glue0222, # 16: space
350 Glue0222, # 17: ascii
352 # 2: not at top of line
354 Glue0222, # 0: begin paren
355 GlueNon, # 1: end paren
356 Glue004, # 2: not at top of line
361 Glue004, # 7: pre unit
362 Glue004, # 8: post unit
363 GlueNon, # 9: zenkaku space
364 Glue004, # 10: hirakana
365 Glue004, # 11: japanese
366 Glue8421, # 12: suffixed
367 Glue004, # 13: rubied
368 Glue8421, # 14: number
371 Glue8421, # 17: ascii
375 Glue0222, # 0: begin paren
376 GlueNon, # 1: end paren
377 GlueNon, # 2: not at top of line
382 GlueNon, # 7: pre unit
383 GlueNon, # 8: post unit
384 GlueNon, # 9: zenkaku space
385 GlueNon, # 10: hirakana
386 GlueNon, # 11: japanese
387 Glue8421, # 12: suffixed
388 GlueNon, # 13: rubied
389 Glue8421, # 14: number
392 Glue8421, # 17: ascii
396 Glue0443, # 0: begin paren
397 Glue0443, # 1: end paren
398 Glue0443, # 2: not at top of line
402 Glue0443, # 6: leader
403 Glue0443, # 7: pre unit
404 Glue0443, # 8: post unit
405 Glue0443, # 9: zenkaku space
406 Glue0443, # 10: hirakana
407 Glue0443, # 11: japanese
408 Glue0443, # 12: suffixed
409 Glue0443, # 13: rubied
410 Glue0443, # 14: number
412 Glue0443, # 16: space
413 Glue0443, # 17: ascii
417 Glue222, # 0: begin paren
418 GlueNon, # 1: end paren
419 Glue222, # 2: not at top of line
424 Glue222, # 7: pre unit
425 Glue222, # 8: post unit
426 Glue222, # 9: zenkaku space
427 Glue222, # 10: hirakana
428 Glue222, # 11: japanese
429 Glue222, # 12: suffixed
430 Glue222, # 13: rubied
431 Glue222, # 14: number
438 Glue0222, # 0: begin paren
439 GlueNon, # 1: end paren
440 Glue004, # 2: not at top of line
445 Glue004, # 7: pre unit
446 Glue004, # 8: post unit
447 GlueNon, # 9: zenkaku space
448 Glue004, # 10: hirakana
449 Glue004, # 11: japanese
450 Glue004, # 12: suffixed
451 Glue004, # 13: rubied
452 Glue004, # 14: number
459 Glue0222, # 0: begin paren
460 GlueNon, # 1: end paren
461 Glue004, # 2: not at top of line
466 Glue004, # 7: pre unit
467 Glue004, # 8: post unit
468 GlueNon, # 9: zenkaku space
469 Glue004, # 10: hirakana
470 Glue004, # 11: japanese
471 Glue004, # 12: suffixed
472 Glue004, # 13: rubied
473 GlueNon, # 14: number
480 Glue0222, # 0: begin paren
481 GlueNon, # 1: end paren
482 Glue004, # 2: not at top of line
487 Glue004, # 7: pre unit
488 Glue004, # 8: post unit
489 GlueNon, # 9: zenkaku space
490 Glue004, # 10: hirakana
491 Glue004, # 11: japanese
492 Glue004, # 12: suffixed
493 Glue004, # 13: rubied
494 Glue004, # 14: number
501 GlueNon, # 0: begin paren
502 GlueNon, # 1: end paren
503 GlueNon, # 2: not at top of line
508 GlueNon, # 7: pre unit
509 GlueNon, # 8: post unit
510 GlueNon, # 9: zenkaku space
511 GlueNon, # 10: hirakana
512 GlueNon, # 11: japanese
513 GlueNon, # 12: suffixed
514 GlueNon, # 13: rubied
515 GlueNon, # 14: number
522 Glue0222, # 0: begin paren
523 GlueNon, # 1: end paren
524 Glue004, # 2: not at top of line
529 Glue004, # 7: pre unit
530 Glue004, # 8: post unit
531 GlueNon, # 9: zenkaku space
532 Glue004, # 10: hirakana
533 Glue004, # 11: japanese
534 Glue8421, # 12: suffixed
535 Glue004, # 13: rubied
536 Glue8421, # 14: number
539 Glue8421, # 17: ascii
543 Glue0222, # 0: begin paren
544 GlueNon, # 1: end paren
545 Glue004, # 2: not at top of line
550 Glue004, # 7: pre unit
551 Glue004, # 8: post unit
552 GlueNon, # 9: zenkaku space
553 Glue004, # 10: hirakana
554 Glue004, # 11: japanese
555 Glue8421, # 12: suffixed
556 Glue004, # 13: rubied
557 Glue8421, # 14: number
560 Glue8421, # 17: ascii
564 Glue0222, # 0: begin paren
565 GlueNon, # 1: end paren
566 Glue004, # 2: not at top of line
571 Glue004, # 7: pre unit
572 Glue004, # 8: post unit
573 GlueNon, # 9: zenkaku space
574 Glue8421, # 10: hirakana
575 Glue8421, # 11: japanese
576 GlueNon, # 12: suffixed
577 Glue8421, # 13: rubied
578 Glue004, # 14: number
585 Glue0222, # 0: begin paren
586 GlueNon, # 1: end paren
587 Glue004, # 2: not at top of line
592 Glue004, # 7: pre unit
593 Glue004, # 8: post unit
594 GlueNon, # 9: zenkaku space
595 Glue004, # 10: hirakana
596 Glue004, # 11: japanese
597 Glue8421, # 12: suffixed
598 GlueNon, # 13: rubied
599 Glue8421, # 14: number
602 Glue8421, # 17: ascii
606 Glue0222, # 0: begin paren
607 GlueNon, # 1: end paren
608 GlueNon, # 2: not at top of line
613 Glue004, # 7: pre unit
614 GlueNon, # 8: post unit
615 GlueNon, # 9: zenkaku space
616 Glue8421, # 10: hirakana
617 Glue8421, # 11: japanese
618 Glue004, # 12: suffixed
619 Glue8421, # 13: rubied
620 GlueNon, # 14: number
627 Glue0222, # 0: begin paren
628 GlueNon, # 1: end paren
629 GlueNon, # 2: not at top of line
634 Glue004, # 7: pre unit
635 Glue004, # 8: post unit
636 GlueNon, # 9: zenkaku space
637 Glue8421, # 10: hirakana
638 Glue8421, # 11: japanese
639 Glue004, # 12: suffixed
640 Glue8421, # 13: rubied
641 Glue8421, # 14: number
648 Glue0222, # 0: begin paren
649 Glue004, # 1: end paren
650 Glue004, # 2: not at top of line
655 Glue004, # 7: pre unit
656 Glue004, # 8: post unit
657 Glue004, # 9: zenkaku space
658 Glue004, # 10: hirakana
659 Glue004, # 11: japanese
660 Glue004, # 12: suffixed
661 Glue004, # 13: rubied
662 Glue004, # 14: number
669 Glue0222, # 0: begin paren
670 GlueNon, # 1: end paren
671 GlueNon, # 2: not at top of line
676 Glue004, # 7: pre unit
677 Glue004, # 8: post unit
678 GlueNon, # 9: zenkaku space
679 Glue8421, # 10: hirakana
680 Glue8421, # 11: japanese
681 Glue844, # 12: suffixed
682 Glue8421, # 13: rubied
683 GlueNon, # 14: number
690 $Default{Splittable} = [
691 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
692 [1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
693 [1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
694 [1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
695 [1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
696 [1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
697 [1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
698 [1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1],
699 [1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
700 [1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
701 [1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
702 [1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
703 [1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1],
704 [1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1],
705 [1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1],
706 [1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0],
707 [1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
708 [1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0],
711 # 1 if not at begin of line
713 [0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
715 # 1 if not at end of line
717 [1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
720 #--------------------------------------------------------------------------
731 $TeXHyphenObj = TeX::Hyphen->new unless $TeXHyphenObj;
732 $TeXHyphenObj->hyphenate($word);
737 $str =~ s/([^;\/?:@&=+\$,A-Za-z0-9\-_.!~*'()])/sprintf("%%%02X",ord($1))/ge
738 unless $str =~ /%[0-9a-fA-F]{2}/;
744 unless( $SubsetTag ) {
746 $SubsetTag .= chr(ord('A') + int(rand(26)));
753 my($ttffile, $encoding) = @_;
756 if( $ttffile =~ /(\.ttc):(\d)$/i ) {
759 my $ttc = new PDFJ::TTC $ttcfile;
760 $ttf = $ttc->select($num);
762 $ttf = new PDFJ::TTF $ttffile;
764 croak "cannot open $ttffile" unless $ttf;
765 $ttf->read_table(':all');
771 my $reader = reader($src) or return;
772 eval { require Compress::Zlib; };
775 my $OK = Compress::Zlib::Z_OK();
776 my $d = Compress::Zlib::deflateInit() or return;
777 my($len, $data, $result);
778 while( $len = &$reader($data, 1024) ) {
779 my($deflated, $status) = $d->deflate($data);
780 return unless $status == $OK;
781 $result .= $deflated;
783 my($deflated, $status) = $d->flush();
784 return unless $status == $OK;
785 $result .= $deflated;
789 sub deflate_ascii85encode {
791 my($result, $deflated);
792 my $temp = deflate($src);
794 $result = ascii85encode(\$temp);
797 $result = ascii85encode($src);
799 ($result, $deflated);
804 my $reader = reader($src) or return;
805 my($len, $data, $result);
806 while( $len = &$reader($data, 4) ) {
808 my $resultchunk = ascii85chunk($data);
809 $resultchunk = 'z' if $resultchunk eq '!!!!!';
810 $result .= $resultchunk;
812 for( my $j = 4; $j > $len; $j-- ) {
815 $result .= substr ascii85chunk($data), 0, $len + 1;
825 $chunk = unpack("N", $chunk);
827 $resultchunk .= chr(int($chunk / (85 ** 4)) + 33);
828 $chunk = $chunk % (85 ** 4);
829 $resultchunk .= chr(int($chunk / (85 ** 3)) + 33);
830 $chunk = $chunk % (85 ** 3);
831 $resultchunk .= chr(int($chunk / (85 ** 2)) + 33);
832 $chunk = $chunk % (85 ** 2);
833 $resultchunk .= chr(int($chunk / 85) + 33);
834 $chunk = $chunk % 85;
835 $resultchunk .= chr($chunk + 33);
840 my($str, $init) = @_;
841 require PDFJ::Unicode;
842 my $result = $init ? "\xfe\xff" : "";
843 if( $PDFJ::Default{Jcode} eq 'SJIS' ) {
844 $result .= PDFJ::Unicode::sjistounicode($str);
845 } elsif( $PDFJ::Default{Jcode} eq 'EUC' ) {
846 $result .= PDFJ::Unicode::euctounicode($str);
853 if( ref($src) eq 'SCALAR' ) {
856 $_[0] = substr $$src, $pos, $_[1];
857 my $len = length $_[0];
862 my $handle = FileHandle->new($src) or return;
865 read $handle, $_[0], $_[1];
870 #--------------------------------------------------------------------------
878 my($class, $version, $pagewidth, $pageheight) = @_;
879 my $objtable = PDFJ::ObjTable->new;
882 objtable => $objtable,
883 pagewidth => $pagewidth,
884 pageheight => $pageheight,
889 jcidsysteminfo => undef,
890 jfontdescriptor => {},
891 filter => 'f', # a:ascii85, f:flate, af:both
892 subsettag => PDFJ::Util::subsettag(),
894 $self->{pagetree} = $self->indirect(dictionary({
895 Type => name('Pages'),
899 $self->{catalog} = $self->indirect(dictionary({
900 Type => name('Catalog'),
901 Pages => $self->{pagetree},
907 my($self, $flag) = @_;
908 if( defined $flag ) {
909 $self->{filter} = $flag; # a:ascii85, f:flate, af:both
915 my($self, $title, $dest, $parent) = @_;
916 $title = PDFJ::Util::tounicode($title, 1) if $title =~ /[\x80-\xff]/;
917 my $lastitem = $parent->get('Last');
920 $newitem = $self->indirect(dictionary({
921 Title => string($title),
926 $newitem->set('Dest', $dest) if $dest;
927 $lastitem->set('Next', $newitem);
928 $parent->set('Last', $newitem);
930 $newitem = $self->indirect(dictionary({
931 Title => string($title),
935 $newitem->set('Dest', $dest) if $dest;
936 $parent->set('First', $newitem);
937 $parent->set('Last', $newitem);
940 $parent->get('Count')->add(1);
941 $parent = $parent->get('Parent');
947 my($self, $title, $dest, $level) = @_;
948 unless( $self->{outline} ) {
949 $self->{outline} = $self->indirect(dictionary({
950 Type => name('Outlines'),
953 $self->{catalog}->set('Outlines', $self->{outline});
954 $self->{catalog}->set('PageMode', name('UseOutlines'));
956 my $parent = $self->{outline};
958 $parent = $parent->get('Last') ?
959 $parent->get('Last') :
960 $self->_add_outline('', undef, $parent);
962 $self->_add_outline($title, $dest, $parent);
966 my($self, $name, $dest) = @_;
967 $self->{dest}{$name} = $dest;
971 my($self, $name) = @_;
972 $self->{dest}{$name};
976 my($self, $obj) = @_;
977 $obj->indirect($self->{objtable});
981 my($self, $filename) = @_;
983 $self->_complete_subsetfont;
984 my $handle = FileHandle->new(">$filename");
985 return unless $handle;
986 my $fobj = PDFJ::File->new($self->{version}, $handle, $self->{objtable},
994 PDFJ::Page->new($self, @_);
998 my($self, $idx) = @_;
999 $self->{pageobjlist}->[$idx];
1002 sub get_lastpagenum {
1004 scalar @{$self->{pagelist}};
1015 sub new_singlefont {
1016 my($self, $basefont, $encoding) = @_;
1017 $basefont ||= $PDFJ::Default{BaseAFont};
1018 my $type = $PDFJ::Default{Fonts}{$basefont};
1019 if( $type eq 'a' ) {
1020 new_afont($self, $basefont, $encoding);
1021 } elsif( $type eq 'j' ) {
1022 new_jfont($self, $basefont, $encoding);
1023 } elsif( $basefont =~ /\.ttf$/i || $basefont =~ /\.ttc:\d$/i ) {
1024 if( $PDFJ::Default{Encodings}{$encoding} eq 'a' ) {
1025 new_afont($self, $basefont, $encoding);
1027 new_jfont($self, $basefont, $encoding);
1030 croak "unknown font: $basefont";
1035 my($self, $zbase, $zenc, $hbase, $henc) = @_;
1036 my $hfont = UNIVERSAL::isa($hbase, "PDFJ::AFont") ? $hbase :
1037 new_afont($self, $hbase, $henc);
1038 new_jfont($self, $zbase, $zenc, $hfont);
1042 my($self, $basefont, $encoding) = @_;
1043 $basefont ||= $PDFJ::Default{BaseAFont};
1044 $encoding ||= $PDFJ::Default{AFontEncoding};
1045 croak "encoding type mismatch"
1046 unless $PDFJ::Default{Encodings}{$encoding} eq 'a';
1047 if( $basefont =~ /\.ttf$/i || $basefont =~ /\.ttc:\d$/i ) {
1048 PDFJ::AFont->new_ttf($self, $basefont, $encoding);
1050 PDFJ::AFont->new_std($self, $basefont, $encoding);
1055 my($self, $basefont, $encoding, $hfont) = @_;
1056 $basefont ||= $PDFJ::Default{BaseJFont};
1057 $encoding ||= $PDFJ::Default{JFontEncoding};
1058 croak "encoding type mismatch"
1059 unless $PDFJ::Default{Encodings}{$encoding} eq
1060 ($PDFJ::Default{Jcode} eq 'SJIS' ? 'js' : 'je');
1061 if( $basefont =~ /\.ttf$/i || $basefont =~ /\.ttc:\d$/i ) {
1062 PDFJ::JFont->new_ttf($self, $basefont, $encoding, $hfont);
1064 PDFJ::JFont->new_std($self, $basefont, $encoding, $hfont);
1069 my($self, $src, $pxwidth, $pxheight, $width, $height, $padding, $colorspace)
1071 PDFJ::Image->new($self, $src, $pxwidth, $pxheight, $width, $height,
1072 $padding, $colorspace);
1076 my($self, @args) = @_;
1077 $self->_deco('italic', @args);
1081 my($self, @args) = @_;
1082 $self->_deco('bold', @args);
1087 my($self, $style, @args) = @_; # $style: italic, bold
1088 croak "arguments must be even" if @args % 2;
1090 my $base = shift @args;
1091 my $deco = shift @args;
1092 if( $base->isa("PDFJ::AFont") ) {
1093 croak "font type mismatch" unless $deco->isa("PDFJ::AFont");
1094 $self->{$style}{$base->{name}} = $deco->{name};
1095 } elsif( $base->isa("PDFJ::JFont") ) {
1096 croak "font type mismatch" unless $deco->isa("PDFJ::JFont");
1097 if( $base->{combo} ) {
1098 croak "font combo type mismatch" unless $deco->{combo};
1099 $self->{$style}{$base->{zname}, $base->{hname}} =
1100 join($;, $deco->{zname}, $deco->{hname});
1102 croak "font combo type mismatch" if $deco->{combo};
1103 $self->{$style}{$base->{zname}} = $deco->{zname};
1109 sub _bolditalicname {
1110 my($self, $name, $style) = @_; # $style: PDFJ::TStyle object
1112 $dname = $self->{italic}{$dname} || $dname if $style->{italic};
1113 $dname = $self->{bold}{$dname} || $dname if $style->{bold};
1118 my($self, $name) = @_;
1119 $self->{fontlist}{$self->{bold}{$name}}
1124 for my $pageobj(@{$self->{pageobjlist}}) {
1125 $pageobj->solve_link;
1129 sub _complete_subsetfont {
1131 for my $name(keys %{$self->{subsetttf}}) {
1132 my $sttf = $self->{subsetttf}{$name};
1133 my $ttf = $sttf->{ttf};
1134 my $direction = $sttf->{direction};
1135 my @unicodes = sort keys %{$sttf->{subset_unicodes}};
1136 my $font = $self->{fontlist}{$name};
1137 my($subset, $c2g, $cidset) = $ttf->subset($direction, @unicodes);
1138 my $size = length $subset;
1139 my($encoded, $filter) = $self->_makestream(\$subset);
1140 croak "cannot encode ttf subset data" unless $encoded;
1141 $font->get('DescendantFonts')->get(0)->get('FontDescriptor')->set(
1142 FontFile2 => $self->indirect(stream(dictionary => {
1144 Length => length($encoded),
1146 }, stream => $encoded)));
1147 ($encoded, $filter) = $self->_makestream(\$c2g);
1148 croak "cannot encode ttf subset cidtogidmap" unless $encoded;
1149 $font->get('DescendantFonts')->get(0)->set(
1150 CIDToGIDMap => $self->indirect(stream(dictionary => {
1152 Length => length($encoded),
1153 }, stream => $encoded)));
1155 ($encoded, $filter) = $self->_makestream(\$cidset);
1156 croak "cannot encode ttf subset cidset" unless $encoded;
1157 $font->get('DescendantFonts')->get(0)->get('FontDescriptor')->set(
1158 CIDSet => $self->indirect(stream(dictionary => {
1160 Length => length($encoded),
1161 }, stream => $encoded)));
1167 my($self, $src, @addfilters) = @_;
1168 my($encoded, $deflated, @filters);
1169 if( $self->filter =~ /af/ ) {
1170 ($encoded, $deflated) = PDFJ::Util::deflate_ascii85encode($src);
1171 return unless $encoded;
1172 @filters = $deflated ? qw(ASCII85Decode FlateDecode) :
1174 } elsif( $self->filter =~ /f/ ) {
1175 $encoded = PDFJ::Util::deflate($src) or return;
1176 @filters = qw(FlateDecode);
1177 } elsif( $self->filter =~ /a/ ) {
1178 $encoded = PDFJ::Util::ascii85encode($src) or return;
1179 @filters = qw(ASCII85Decode);
1183 push @filters, @addfilters if @addfilters;
1184 my $filter = @filters > 1 ? [map {name($_)} @filters] : name($filters[0]);
1185 ($encoded, $filter);
1188 sub _nextsubsettag {
1190 $self->{subsettag}++;
1195 1 + scalar keys %{$self->{fontlist}};
1199 my($self, $fontobj) = @_;
1200 my $baseorttf = $fontobj->{ttffile} || $fontobj->{basefont};
1201 my $encoding = $fontobj->{encoding};
1202 my $name = $fontobj->{name} || $fontobj->{zname};
1203 my $font = $fontobj->{font} || $fontobj->{zfont};
1204 $self->{fontname}{$baseorttf, $encoding} = $name;
1205 $self->{fontlist}{$name} = $font;
1206 if( $fontobj->{combo} ) {
1207 $self->{fontobjlist}{$name, $fontobj->{hname}} = $fontobj;
1209 $self->{fontobjlist}{$name} = $fontobj;
1214 my($self, %args) = @_;
1215 $args{subset_unicodes} = {};
1216 $self->{subsetttf}{$args{name}} = \%args;
1220 my($self, $name) = @_;
1221 $self->{subsetttf}{$name};
1225 my($self, $baseorttf, $encoding) = @_;
1226 $self->{fontname}{$baseorttf, $encoding};
1230 my($self, $name) = @_;
1231 $self->{fontlist}{$name};
1235 my($self, $name, $hname) = @_;
1237 $self->{fontobjlist}{$name, $hname} :
1238 $self->{fontobjlist}{$name};
1241 sub _jcidsysteminfo {
1243 unless( $self->{jcidsysteminfo} ) {
1244 $self->{jcidsysteminfo} = $self->indirect(dictionary({
1245 Registry => 'Adobe',
1246 Ordering => 'Japan1',
1250 $self->{jcidsysteminfo};
1253 sub _jfontdescriptor {
1254 my($self, $basefont) = @_;
1255 unless( $self->{jfontdescriptor}->{$basefont} ) {
1256 $self->{jfontdescriptor}->{$basefont} =
1257 $self->indirect($PDFJ::Default{JFD}{$basefont});
1259 $self->{jfontdescriptor}->{$basefont};
1264 1 + scalar keys %{$self->{imagelist}};
1268 my($self, $name, $image) = @_;
1269 $self->{imagelist}->{$name} = $image;
1272 #--------------------------------------------------------------------------
1276 #--------------------------------------------------------------------------
1277 package PDFJ::AFont;
1283 @ISA = qw(PDFJ::Font);
1286 my($class, $docobj, $basefont, $encoding) = @_;
1287 croak "illegal ascii font name: $basefont"
1288 unless $PDFJ::Default{Fonts}{$basefont} eq 'a';
1289 my $name = $docobj->_fontname($basefont, $encoding);
1290 return $docobj->_fontobj($name) if $name;
1291 $name = "F".$docobj->_nextfontnum;
1292 my $font = $docobj->indirect(dictionary({
1293 Type => name('Font'),
1294 Name => name($name),
1295 BaseFont => name($basefont),
1296 Subtype => name('Type1'),
1297 Encoding => name($encoding),
1299 my $width = fontwidth($basefont);
1300 my $self = bless {docobj => $docobj, basefont => $basefont,
1301 encoding => $encoding, font => $font, name => $name, width => $width,
1302 direction => 'H'}, $class;
1303 $docobj->_registfont($self);
1308 my($class, $docobj, $ttffile, $encoding) = @_;
1309 my $name = $docobj->_fontname($ttffile, $encoding);
1310 return $docobj->_fontobj($name) if $name;
1311 $name = "F".$docobj->_nextfontnum;
1312 my $ttf = PDFJ::Util::ttfopen($ttffile);
1313 my $info = $ttf->pdf_info_ascii($encoding);
1314 croak "'$ttffile' embedding inhibited"
1315 if $info->{EmbedFlag} == 2 || $info->{EmbedFlag} & 0x200;
1316 my $size = -s $ttffile;
1317 my($encoded, $filter) = $docobj->_makestream($ttffile);
1318 my $basefont = $info->{BaseFont};
1319 my @widths = @{$info->{Widths}};
1320 my $font = $docobj->indirect(dictionary({
1321 Type => name('Font'),
1322 Name => name($name),
1323 BaseFont => name($basefont),
1324 Subtype => name('TrueType'),
1325 Encoding => name($info->{Encoding}),
1326 FirstChar => $info->{FirstChar},
1327 LastChar => $info->{LastChar},
1328 Widths => $docobj->indirect(array(\@widths)),
1329 FontDescriptor => $docobj->indirect(dictionary({
1330 Type => name('FontDescriptor'),
1331 Ascent => $info->{Ascent},
1332 CapHeight => $info->{CapHeight},
1333 Descent => $info->{Descent},
1334 Flags => $info->{Flags},
1335 FontBBox => $info->{FontBBox},
1336 FontName => name($info->{FontName}),
1337 ItalicAngle => $info->{ItalicAngle},
1339 FontFile2 => $docobj->indirect(stream(dictionary => {
1341 Length => length($encoded),
1343 }, stream => $encoded)),
1346 my $self = bless {docobj => $docobj, # basefont => $basefont,
1347 encoding => $encoding, ttffile => $ttffile,
1348 font => $font, name => $name, width => $info->{Widths},
1349 direction => 'H'}, $class;
1350 $docobj->_registfont($self);
1355 my($self, $style) = @_;
1356 my $docobj = $self->{docobj};
1357 $docobj->_bolditalicname($self->{name}, $style);
1362 ($self->{name}, $self->{font});
1365 sub string_fontwidth {
1366 my($self, $string) = @_;
1367 my $fontwidth = $self->{width};
1369 for my $c(split '', $string) {
1370 $width += $fontwidth->[ord $c];
1375 sub astring_fontwidth {
1383 $basefont =~ s/-/_/g;
1384 return $FontWidth{$basefont} if $FontWidth{$basefont};
1385 my $func = "fontwidth_$basefont";
1386 my $result = eval { no strict 'refs'; &$func(); };
1388 $FontWidth{$basefont} = $result if $result;
1392 #--------------------------------------------------------------------------
1393 package PDFJ::JFont;
1398 @ISA = qw(PDFJ::Font);
1401 my($class, $docobj, $basefont, $encoding, $hfontobj) = @_;
1402 croak "illegal japanese font name: $basefont"
1403 unless $PDFJ::Default{Fonts}{$basefont} eq 'j';
1404 croak "ascii font type mismatch"
1405 if $hfontobj && !UNIVERSAL::isa($hfontobj, "PDFJ::AFont");
1406 my $name = $docobj->_fontname($basefont, $encoding);
1407 my $hname = $hfontobj ? $hfontobj->{name} : undef;
1408 return $docobj->_fontobj($name, $hname)
1409 if $name && $docobj->_fontobj($name, $hname);
1411 my $code = $PDFJ::Default{Jcode};
1412 my($direction) = $encoding =~ /-(\w+)$/;
1416 $zfont = $docobj->_font($name);
1418 my $jcidsi = $docobj->_jcidsysteminfo;
1419 my $jfd = $docobj->_jfontdescriptor($basefont);
1420 $zname = "F".$docobj->_nextfontnum;
1421 $zfont = $docobj->indirect(dictionary({
1422 Name => name($zname),
1423 Type => name("Font"),
1424 Subtype => name('Type0'),
1425 Encoding => name($encoding),
1426 BaseFont => name("$basefont-$encoding"),
1427 DescendantFonts => [{
1428 Type => name('Font'),
1429 Subtype => name('CIDFontType0'),
1430 BaseFont => name($basefont),
1431 CIDSystemInfo => $jcidsi,
1433 W => [231, 389, 500, 631, [500]],
1434 FontDescriptor => $jfd,
1442 $hname = $hfontobj->{name};
1443 $hfont = $hfontobj->{font};
1451 basefont => $basefont,
1452 encoding => $encoding,
1457 direction => $direction,
1460 hfontobj => $hfontobj,
1462 $docobj->_registfont($self);
1467 my($class, $docobj, $ttffile, $encoding, $hfontobj) = @_;
1468 croak "TrueType subset embedding requires PDF version 1.3 or above"
1469 if $docobj->{version} < 1.3;
1470 croak "ascii font type mismatch"
1471 if $hfontobj && !UNIVERSAL::isa($hfontobj, "PDFJ::AFont");
1472 my $name = $docobj->_fontname($ttffile, $encoding);
1473 my $hname = $hfontobj ? $hfontobj->{name} : undef;
1474 return $docobj->_fontobj($name, $hname)
1475 if $name && $docobj->_fontobj($name, $hname);
1477 my $code = $PDFJ::Default{Jcode};
1478 my($direction) = $encoding =~ /-(\w+)$/;
1482 $zfont = $docobj->_font($name);
1484 my $ttf = PDFJ::Util::ttfopen($ttffile);
1485 my $info = $ttf->pdf_info_japan($encoding);
1486 croak "'$ttffile' embedding inhibited ($info->{EmbedFlag})"
1487 if $info->{EmbedFlag} == 2 || $info->{EmbedFlag} & 0x100 ||
1488 $info->{EmbedFlag} & 0x200;
1489 my $subsetname = $docobj->_nextsubsettag . '+' . $info->{BaseFont};
1490 my $basefont = $info->{BaseFont};
1491 my $jcidsi = $docobj->_jcidsysteminfo;
1492 $zname = "F".$docobj->_nextfontnum;
1493 $zfont = $docobj->indirect(dictionary({
1494 Name => name($zname),
1495 Type => name("Font"),
1496 Subtype => name('Type0'),
1497 Encoding => name($encoding),
1498 BaseFont => name($subsetname),
1499 DescendantFonts => [$docobj->indirect(dictionary({
1500 Type => name('Font'),
1501 Subtype => name('CIDFontType2'), # TrueType
1502 BaseFont => name($basefont),
1503 CIDSystemInfo => $jcidsi,
1505 W => [231, 389, 500, 631, [500]],
1506 FontDescriptor => $docobj->indirect(dictionary({
1507 Type => name('FontDescriptor'),
1508 Ascent => $info->{Ascent},
1509 CapHeight => $info->{CapHeight},
1510 Descent => $info->{Descent},
1511 Flags => $info->{Flags},
1512 FontBBox => $info->{FontBBox},
1513 FontName => name($subsetname),
1514 ItalicAngle => $info->{ItalicAngle},
1516 # FontFile2 added later
1518 # CIDToGIDMap added later
1521 $docobj->_registsubset(
1522 name => $zname, ttf => $ttf, direction => $direction);
1524 my $subset_unicodes = $docobj->_subsetttf($zname)->{subset_unicodes};
1529 $hname = $hfontobj->{name};
1530 $hfont = $hfontobj->{font};
1538 #basefont => $basefont,
1539 encoding => $encoding,
1540 ttffile => $ttffile,
1545 direction => $direction,
1548 hfontobj => $hfontobj,
1549 subset_unicodes => $subset_unicodes,
1551 $docobj->_registfont($self);
1556 my($self, $style, $mode) = @_;
1557 my $docobj = $self->{docobj};
1558 if( $self->{combo} ) {
1559 split $;, $docobj->_bolditalicname(
1560 join($;, $self->{zname}, $self->{hname}), $style);
1562 $docobj->_bolditalicname($self->{zname}, $style);
1568 ($self->{zname}, $self->{zfont}, $self->{hname}, $self->{hfont});
1571 sub astring_fontwidth {
1572 my($self, $string) = @_;
1573 my $combo = $self->{combo};
1574 my $hfont = $self->{hfontobj};
1576 $hfont->string_fontwidth($string);
1578 length($string) / 2;
1582 #--------------------------------------------------------------------------
1583 package PDFJ::BlockElement;
1590 sub postnobreak { 0 }
1594 #--------------------------------------------------------------------------
1595 package PDFJ::Showable;
1599 @ISA = qw(PDFJ::BlockElement);
1602 my($self, $page, $x, $y, $align, $transtype, @args) = @_;
1604 if( $transtype eq 'magnify' ) {
1605 my($xmag, $ymag) = @args;
1606 $page->addcontents("q $xmag 0 0 $ymag $x $y cm");
1607 } elsif( $transtype eq 'rotate' ) {
1609 my $sin = sin($rad);
1610 my $cos = cos($rad);
1612 $page->addcontents("q $cos $sin $msin $cos $x $y cm");
1613 } elsif( $transtype eq 'distort' ) {
1614 my($xtan, $ytan) = @args;
1615 $page->addcontents("q 1 $xtan $ytan 1 $x $y cm");
1617 croak "unknown transformation type";
1622 if( $align =~ /l/ ) {
1624 } elsif( $align =~ /r/ ) {
1626 } elsif( $align =~ /c/ ) {
1627 $x -= ($self->left + $self->right) / 2;
1629 if( $align =~ /t/ ) {
1631 } elsif( $align =~ /b/ ) {
1632 $y -= $self->bottom;
1633 } elsif( $align =~ /m/ ) {
1634 $y -= ($self->top + $self->bottom) / 2;
1637 $self->_show($page, $x, $y);
1639 $page->addcontents("Q");
1643 #--------------------------------------------------------------------------
1644 package PDFJ::Style;
1649 my($class, @args) = @_;
1651 $class = ref($class);
1654 if( @args == 1 && ref($args[0]) eq 'HASH' ) {
1655 %$self = %{$args[0]};
1659 bless $self, $class;
1663 my($self, @args) = @_;
1664 my $clone = $self->new(%$self);
1667 if( @args == 1 && ref($args[0]) eq 'HASH' ) {
1668 %args = %{$args[0]};
1672 for my $key(keys %args) {
1673 $clone->{$key} = $args{$key};
1680 my($self, $from) = @_;
1681 for my $key(keys %$from) {
1682 $self->{$key} = $from->{$key} unless exists $self->{$key};
1687 #--------------------------------------------------------------------------
1688 package PDFJ::TextStyle;
1692 @ISA = qw(PDFJ::Style);
1694 sub TStyle { PDFJ::TextStyle->new(@_) }
1697 my($self, $from) = @_;
1698 if( $self->{suffix} ) {
1699 $self->{fontsize} = $from->{fontsize} *
1700 $PDFJ::Default{SuffixSize};
1702 $self->{suffix} eq 'u' ? $from->{fontsize} *
1703 $PDFJ::Default{USuffixRise} :
1704 $self->{suffix} eq 'l' ? $from->{fontsize} *
1705 $PDFJ::Default{LSuffixRise} :
1708 $self->SUPER::merge($from);
1711 sub selectfontname {
1712 my($self, $mode) = @_;
1713 my $font = $self->{font} or return;
1714 $font->selectname($self, $mode);
1717 #--------------------------------------------------------------------------
1718 package PDFJ::TextSpec;
1723 my($class, @args) = @_;
1724 my $self = bless {}, $class;
1725 $self->set(@args) if @args;
1732 for my $key(qw(fontsize render rise mode)) {
1733 print "$key => $self->{$key}, ";
1739 my($self, $style, $fontname) = @_;
1741 for my $key(qw(fontsize render rise shapestyle)) {
1742 if( exists $style->{$key} ) {
1743 $self->{$key} = $style->{$key};
1746 $self->{fontname} = $fontname;
1750 my($self, $from) = @_;
1755 my($self, $other) = @_;
1756 for my $key(qw(fontname fontsize render rise shapestyle)) {
1757 return 0 if ($self->{$key} || "") ne ($other->{$key} || "");
1764 croak "no fontsize specification" unless $self->{fontsize};
1765 my $fontname = $self->{fontname};
1766 my $fontsize = $self->{fontsize};
1767 my $rise = $self->{rise} || 0;
1768 my $render = $self->{render} || 0;
1769 my $shapepdf = $self->{shapestyle} ? $self->{shapestyle}->pdf : "";
1771 $pdf .= "$shapepdf " if $shapepdf;
1772 $pdf .= "BT /$fontname $fontsize Tf $rise Ts $render Tr ";
1776 #--------------------------------------------------------------------------
1777 package PDFJ::NewLine;
1781 sub NewLine { PDFJ::NewLine->new(@_) }
1785 bless \$class, $class;
1788 #--------------------------------------------------------------------------
1789 package PDFJ::Outline;
1793 sub Outline { PDFJ::Outline->new(@_) }
1796 my($class, $title, $level) = @_;
1797 bless {outlinetitle => $title, outlinelevel => $level}, $class;
1800 #--------------------------------------------------------------------------
1805 sub Dest { PDFJ::Dest->new(@_) }
1808 my($class, $name) = @_;
1809 bless {destname => $name}, $class;
1812 #--------------------------------------------------------------------------
1817 @ISA = qw(PDFJ::Showable);
1819 sub Text { PDFJ::Text->new(@_) }
1823 my $style = pop; # not shift
1824 if( UNIVERSAL::isa($style, 'PDFJ::TextStyle') ) {
1825 $style = $style->clone;
1826 } elsif( ref($style) eq 'HASH' ) {
1827 $style = PDFJ::TextStyle->new($style);
1829 croak "style argument must be a PDFJ::TextStyle object or HASHref";
1832 my $texts = (@texts == 1 && ref($texts[0]) eq 'ARRAY') ? $texts[0] : \@texts;
1833 my $self = bless { texts => $texts, style => $style }, $class;
1837 $self->makerubytext;
1843 my $style = $self->style;
1844 return unless $style->{font};
1845 for my $text(@{$self->texts}) {
1846 if( UNIVERSAL::isa($text, 'PDFJ::Text') ) {
1847 $text->style->merge($style);
1855 my($self, $indent) = @_;
1856 my $style = $self->style;
1857 print $indent,join(',',%$style),"\n";
1858 for my $text(@{$self->texts}) {
1859 if( UNIVERSAL::isa($text, 'PDFJ::Text') ) {
1860 $text->print("$indent ");
1862 print "$indent\[$text]\n";
1869 my $style = $self->style;
1870 return unless $style->{font};
1871 $self->{chunks} = [];
1872 $self->{lines} = [];
1873 for my $text(@{$self->texts}) {
1874 if( UNIVERSAL::isa($text, 'PDFJ::Text') ) {
1875 $text->makechunks unless $text->chunks;
1876 $self->catchunks($text->chunks);
1877 } elsif( UNIVERSAL::isa($text, 'PDFJ::Showable') ) {
1878 $self->catchunks([_objchunk($text, $self->style)]);
1879 # } elsif( UNIVERSAL::isa($text, 'PDFJ::Image') ) {
1880 # $self->catchunks([_imagechunk($text, $self->style)]);
1881 # } elsif( UNIVERSAL::isa($text, 'PDFJ::Shape') ) {
1882 # $self->catchunks([_shapechunk($text, $self->style)]);
1883 } elsif( UNIVERSAL::isa($text, 'PDFJ::NewLine') ) {
1884 $self->catchunks([_newlinechunk($self->style)]);
1885 } elsif( UNIVERSAL::isa($text, 'PDFJ::Outline') ) {
1886 $self->catchunks([_outlinechunk($text, $self->style)]);
1887 } elsif( UNIVERSAL::isa($text, 'PDFJ::Dest') ) {
1888 $self->catchunks([_destchunk($text, $self->style)]);
1890 $self->catchunks($self->splittext($text));
1897 return unless $self->style->{font};
1898 for my $chunk(@{$self->chunks}) {
1899 my $style = $chunk->{Style};
1900 if( $style->{ruby} ) {
1901 croak "ruby class mismatch"
1902 unless $chunk->{Class} == 11 || $chunk->{Class} == 17;
1903 my $rubystyle = $style->clone;
1904 delete $rubystyle->{ruby};
1905 delete $rubystyle->{withbox};
1906 delete $rubystyle->{withline};
1907 $rubystyle->{fontsize} /= 2;
1908 my $rubytext = PDFJ::Text->new($style->{ruby}, $rubystyle);
1909 my $rubysize = $rubytext->size;
1910 my $chunksize = _chunksize($chunk, 1);
1911 if( $rubysize < $chunksize ) {
1912 my $alt = PDFJ::Paragraph->new($rubytext,
1913 PDFJ::ParagraphStyle->new(size => $chunksize,
1914 align => 'ruby', linefeed => 0));
1915 $chunk->{RubyText} = $alt;
1916 } elsif( $rubysize > $chunksize ) {
1917 my $altstyle = $style->clone;
1918 delete $altstyle->{ruby};
1919 delete $altstyle->{withbox};
1920 delete $altstyle->{withline};
1921 my $alt = PDFJ::Paragraph->new(
1922 PDFJ::Text->new($chunk->{String}, $altstyle),
1923 PDFJ::ParagraphStyle->new(size => $rubysize,
1924 align => 'ruby', linefeed => 0));
1925 $chunk->{AltObj} = $alt;
1926 $chunk->{RubyText} = $rubytext;
1928 $chunk->{RubyText} = $rubytext;
1934 sub texts { $_[0]->{texts} }
1935 sub chunks { $_[0]->{chunks} }
1936 sub chunksnum { scalar(@{$_[0]->{chunks}}) }
1937 sub chunk { $_[0]->{chunks}[$_[1]] }
1938 sub style { $_[0]->{style} }
1939 sub direction { $_[0]->{style}{font}{direction} }
1940 sub fontsize { $_[0]->{style}{fontsize} }
1944 $self->direction eq 'H' ?
1945 _chunkssize($self->{chunks}) :
1951 $self->direction eq 'H' ?
1953 _chunkssize($self->{chunks});
1958 $self->direction eq 'H' ?
1960 - ($self->fontsize / 2);
1965 $self->direction eq 'H' ?
1966 _chunkssize($self->{chunks}) :
1967 $self->fontsize / 2;
1972 $self->direction eq 'H' ?
1973 $self->fontsize * (1 - $PDFJ::Default{HBaseShift}) :
1979 $self->direction eq 'H' ?
1980 $self->fontsize * (- $PDFJ::Default{HBaseShift}) :
1981 _chunkssize($self->{chunks});
1985 my($self, $direction) = @_; # neglect $direction
1986 _chunkssize($self->{chunks});
1990 my($self, $start, $count, $fixedglues) = @_;
1991 _chunksfixsize($self->{chunks}, $start, $count, $fixedglues);
1996 _chunkscount($self->{chunks});
2001 return unless $self->{hyphened};
2002 my $chunks = $self->chunks;
2003 for( my $j = 0; $j < @$chunks; $j++ ) {
2004 my $chunk = $chunks->[$j];
2005 my $hyphened = $chunk->{Hyphened};
2006 if( $hyphened && $j < @$chunks - 1 ) {
2007 $chunk->{String} =~ s/-$// if $hyphened == 2;
2008 $chunk->{String} .= $chunks->[$j + 1]->{String};
2009 $chunk->{Count} = length $chunk->{String};
2010 $chunk->{Hyphened} = 0;
2011 splice @$chunks, $j + 1, 1;
2014 $self->{hyphened} = 0;
2017 my %TextLineIndex = (
2025 my($self, $linesize, $align) = @_;
2026 my $chunks = $self->chunks;
2027 return unless @$chunks;
2030 my @linesizes = ref($linesize) eq 'ARRAY' ? @$linesize : ($linesize);
2031 my $lastlinesize = $linesizes[$#linesizes];
2033 if( $align eq 'ruby' ) {
2034 $rubyshift = ($linesizes[0] - _chunkssize($chunks)) / $self->count;
2035 $linesizes[0] -= $rubyshift;
2040 while( $start < @$chunks ) {
2041 $linesize = @linesizes ? shift(@linesizes) : $lastlinesize;
2042 croak "not enough paragraph size" if $linesize < 0;
2045 my $foldpos = $start;
2046 my $canpos = $start;
2048 for( my $j = $start; $j < @$chunks; $j++ ) {
2049 my $chunk = $chunks->[$j];
2050 if( $chunk->{Splittable} == 2 ) {
2055 my($chunksize, $decchunksize) = _chunksize($chunk, ($j == $start));
2056 $size += $chunksize;
2057 $decsize += $decchunksize unless $j == $start;
2059 if( $k == @$chunks || ($chunks->[$k]{Splittable} &&
2060 !_isnoeol($chunks, $k) && !_isnobol($chunks, $k)) ) {
2061 if( $size == $linesize ) {
2064 } elsif( $size < $linesize ) {
2066 } else { # $size > $linesize
2068 if( $align =~ /w/i &&
2069 $size - $decsize <= $linesize ) {
2071 } elsif( ($hyphenpos =
2072 _hyphenpos($chunks->[$j], $size - $linesize)) ) {
2073 _inshyphen($chunks, $j, $hyphenpos);
2074 $self->{hyphened} = 1;
2076 } elsif( $k == $start + 1 ) {
2084 #print "$j:$start:($chunk->{Splittable})[$chunk->{String}] $chunksize(-$decchunksize) $size(-$decsize) $canpos\n";
2086 if( $foldpos == $start && $size > $linesize &&
2087 !($align =~ /w/i && $size - $decsize <= $linesize) ) {
2090 $foldpos = @$chunks if $foldpos == $start;
2091 my $nextpos = $foldpos;
2093 while( $nextpos < @$chunks && $chunks->[$nextpos]{Class} eq 16 ) {
2097 while( $foldpos > 0 && ($chunks->[$foldpos - 1]{Class} eq 16 ||
2098 $chunks->[$foldpos - 1]{Splittable} == 2) ) {
2101 my $count = $foldpos - $start;
2102 $size = _chunkssize($chunks, $start, $count);
2104 my $fixedglues = [];
2105 if( $align eq 'e' ) {
2106 $shift = $linesize - $size;
2107 } elsif( $align eq 'm' ) {
2108 $shift = ($linesize - $size) / 2;
2109 } elsif( $align eq 'W' || ($align eq 'w' && $count &&
2110 (($nextpos < @$chunks && $chunks->[$foldpos]{Splittable} != 2)
2111 || $size > $linesize)) ) {
2112 $fixedglues = $self->fixglue($start, $count, $linesize - $size);
2114 $shift = $rubyshift + ($linesize -
2115 $self->fixsize($start, $count, $fixedglues)) / 2;
2118 push @lines, [\%TextLineIndex, $start, $count, $shift, $fixedglues];
2125 my($chunk, $decsize) = @_;
2126 return unless $chunk->{Class} == 17 && !$chunk->{Style}{nohyphen} &&
2127 !$chunk->{Style}{ruby};
2128 my $string = $chunk->{String};
2129 #print "$string, $decsize\n";
2130 my($can, $canleft, $pre, $word);
2131 if( $string =~ /([A-Za-z]-)([A-Za-z])/ ) {
2134 } elsif( $string =~ /[A-Za-z]{5,}/ ) {
2138 return unless $can || $word;
2139 my $fontobj = $chunk->{Style}{font};
2140 my $fontsize = $chunk->{Style}{fontsize};
2141 $decsize /= $fontsize;
2143 if( $fontobj->astring_fontwidth($canleft) >= $decsize ) {
2144 return length($can);
2149 my $size = $fontobj->astring_fontwidth($word);
2150 return if $size <= $decsize;
2151 my $maxsize = $size - $decsize;
2152 for my $pos(reverse PDFJ::Util::hyphenate($word)) {
2153 return length($pre) + $pos
2154 if $fontobj->astring_fontwidth($pre.substr($word, 0, $pos).'-')
2161 my($chunks, $idx, $hyphenpos) = @_;
2162 my $chunk = $chunks->[$idx];
2163 my $string = $chunk->{String};
2165 @$inschunk = @$chunk;
2166 my $work = substr $string, 0, $hyphenpos;
2167 if( $work =~ /-$/ ) {
2168 $chunk->{Hyphened} = 1;
2170 $chunk->{Hyphened} = 2;
2173 $chunk->{String} = $work;
2174 $chunk->{Count} = length $chunk->{String};
2175 $inschunk->{String} = substr $string, $hyphenpos;
2176 $inschunk->{Count} = length $inschunk->{String};
2177 splice @$chunks, $idx + 1, 0, $inschunk;
2181 my($chunks, $start, $count) = @_;
2183 $start = 0 if $start < 0;
2184 $count ||= @$chunks - $start;
2186 for(my $j = 0; $j < $count && $start + $j < @$chunks; $j++ ) {
2187 $result += _chunksize($chunks->[$start + $j], ($j == 0));
2192 sub _chunksfixsize {
2193 my($chunks, $start, $count, $fixedglues) = @_;
2195 $start = 0 if $start < 0;
2196 $count ||= @$chunks - $start;
2198 for(my $j = 0; $j < $count && $start + $j < @$chunks; $j++ ) {
2199 $result += _chunkfixsize($chunks->[$start + $j], $fixedglues->[$j]);
2205 my($chunks, $start, $count) = @_;
2207 $start = 0 if $start < 0;
2208 $count ||= @$chunks - $start;
2210 for(my $j = 0; $j < $count && $start + $j < @$chunks; $j++ ) {
2211 $result += _chunkcount($chunks->[$start + $j]);
2216 # check if last chunk is NoEOL
2218 my($chunks, $pos) = @_;
2219 while( $pos > 0 && $chunks->[$pos - 1]{Class} == 16 ) {
2222 return unless $pos > 0;
2223 $PDFJ::Default{NoEOL}[$chunks->[$pos - 1]{Class}];
2226 # check if next chunk is NoBOL
2228 my($chunks, $pos) = @_;
2229 while( $pos < @$chunks && $chunks->[$pos]{Class} == 16 ) {
2232 return unless $pos < @$chunks;
2233 $PDFJ::Default{NoBOL}[$chunks->[$pos]{Class}];
2242 my($chunk, $noglue) = @_;
2243 my $fontobj = $chunk->{Style}{font};
2244 my $fontsize = $chunk->{Style}{fontsize};
2245 my $direction = $fontobj->{direction};
2246 my $size = $direction eq 'H' ?
2247 _chunkfontsizeH($fontobj, $fontsize, $chunk) :
2248 _chunkfontsizeV($fontobj, $fontsize, $chunk);
2249 $size += $fontsize * (($noglue ? 0 : $chunk->{Glue}) -
2250 $chunk->{PreShift} - $chunk->{PostShift});
2252 my $decsize = $chunk->{GlueDec} * $fontsize;
2253 my $incsize = $chunk->{GlueInc} * $fontsize;
2254 ($size, $decsize, $incsize);
2261 my($chunk, $fixedglue) = @_;
2263 my $fontobj = $chunk->{Style}{font};
2264 my $fontsize = $chunk->{Style}{fontsize};
2265 my $direction = $fontobj->{direction};
2266 my $size = $direction eq 'H' ?
2267 _chunkfontsizeH($fontobj, $fontsize, $chunk) :
2268 _chunkfontsizeV($fontobj, $fontsize, $chunk);
2269 $size += $fontsize * ($fixedglue -
2270 $chunk->{PreShift} - $chunk->{PostShift});
2274 sub _chunkfontsizeH {
2275 my($fontobj, $fontsize, $chunk) = @_;
2276 return $chunk->{AltObj}->size('H') if $chunk->{AltObj};
2278 if( UNIVERSAL::isa($fontobj, "PDFJ::JFont") ) {
2279 my $combo = $fontobj->{combo};
2280 my $hfont = $fontobj->{hfontobj};
2281 my $mode = $chunk->{Mode};
2282 if( $mode eq 'z' ) {
2283 $size = $chunk->{Count};
2284 } elsif( $mode eq 'h' ) {
2285 $size = $chunk->{Count} / 2;
2287 $size = $hfont->string_fontwidth($chunk->{String});
2289 $size = $chunk->{Count} / 2;
2291 } elsif( UNIVERSAL::isa($fontobj, "PDFJ::AFont") ) {
2292 $size = $fontobj->string_fontwidth($chunk->{String});
2294 croak "internal error: missing font object";
2300 sub _chunkfontsizeV {
2301 my($fontobj, $fontsize, $chunk) = @_;
2302 return $chunk->{AltObj}->size('V') if $chunk->{AltObj};
2304 if( UNIVERSAL::isa($fontobj, "PDFJ::JFont") ) {
2305 my $combo = $fontobj->{combo};
2306 my $hfont = $fontobj->{hfontobj};
2307 my $mode = $chunk->{Mode};
2308 if( $mode eq 'z' ) {
2309 $size = $chunk->{Count};
2310 } elsif( $mode eq 'h' ) {
2311 $size = $chunk->{Count};
2313 $size = $chunk->{Class} == 11 ? 1 :
2314 $hfont->string_fontwidth($chunk->{String});
2316 $size = $chunk->{Count};
2318 } elsif( UNIVERSAL::isa($fontobj, "PDFJ::AFont") ) {
2319 $size = $fontobj->string_fontwidth($chunk->{String});
2321 croak "internal error: missing font object";
2329 my($self, $start, $count, $incsize) = @_;
2330 return unless $incsize;
2331 if( $incsize > 0 ) {
2339 my($self, $start, $count, $incsize) = @_;
2342 my $chunksnum = $self->chunksnum;
2343 # start counter is not 0 but 1 because first chunk glue is not used
2344 for( my $j = 1; $j < $count && $start + $j < $chunksnum; $j++ ) {
2345 my $chunk = $self->chunk($start + $j);
2346 if( $chunk->{GlueInc} ) {
2347 $incgluesum{$chunk->{GluePref} + 0} +=
2348 $chunk->{GlueInc} * $chunk->{Style}{fontsize};
2351 for my $pref(reverse sort keys %incgluesum) {
2352 last if $incsize <= 0;
2353 my $incgluesum = $incgluesum{$pref};
2354 my $ratio = $incgluesum > $incsize ? $incsize / $incgluesum : 1;
2355 for( my $j = 1; $j < $count && $start + $j < $chunksnum; $j++ ) {
2356 my $chunk = $self->chunk($start + $j);
2357 if( $chunk->{GlueInc} && $chunk->{GluePref} == $pref ) {
2358 #$chunk->{GlueFix} = $chunk->{GlueInc} * $ratio;
2359 $fixedglues[$j] = $chunk->{GlueInc} * $ratio;
2362 #$incsize -= $incgluesum * $ratio;
2363 $incsize -= $incgluesum;
2365 if( $incsize > 0 ) {
2366 my $splittables = 0;
2367 for( my $j = 1; $j < $count && $start + $j < $chunksnum; $j++ ) {
2368 $splittables++ if $self->chunk($start + $j)->{Splittable};
2370 if( $splittables ) {
2371 for( my $j = 1; $j < $count && $start + $j < $chunksnum; $j++ ) {
2372 my $chunk = $self->chunk($start + $j);
2373 if( $chunk->{Splittable} ) {
2374 #$chunk->{GlueFix} += $incsize / $chunk->{Style}{fontsize} /
2376 $fixedglues[$j] += $incsize / $chunk->{Style}{fontsize} /
2386 my($self, $start, $count, $incsize) = @_;
2387 my $decsize = -$incsize;
2390 my $chunksnum = $self->chunksnum;
2391 # start counter is not 0 but 1 because first chunk glue is not used
2392 for( my $j = 1; $j < $count && $start + $j < $chunksnum; $j++ ) {
2393 my $chunk = $self->chunk($start + $j);
2394 if( $chunk->{GlueDec} ) {
2395 $decgluesum{$chunk->{GluePref} + 0} +=
2396 $chunk->{GlueDec} * $chunk->{Style}{fontsize};
2399 for my $pref(reverse sort keys %decgluesum) {
2400 last if $decsize <= 0;
2401 my $decgluesum = $decgluesum{$pref};
2402 my $ratio = $decgluesum > $decsize ? $decsize / $decgluesum : 1;
2403 for( my $j = 1; $j < $count && $start + $j < $chunksnum; $j++ ) {
2404 my $chunk = $self->chunk($start + $j);
2405 if( $chunk->{GlueDec} && $chunk->{GluePref} == $pref ) {
2406 #$chunk->{GlueFix} = -$chunk->{GlueDec} * $ratio;
2407 $fixedglues[$j] = -$chunk->{GlueDec} * $ratio;
2410 #$decsize -= $decgluesum * $ratio;
2411 $decsize -= $decgluesum;
2417 my($self, $page, $x, $y) = @_;
2418 $self->_showpart($page, $x, $y, 0, $self->chunksnum);
2421 # This mega subroutine is too complex and patchy, needs refactering!
2423 my($self, $page, $x, $y, $start, $count, $fixedglues) = @_;
2424 my $docobj = $page->docobj;
2425 my $chunksnum = $self->chunksnum;
2427 my($tj, $dotpdf, $shapepdf) = ("") x 3;
2428 my $lasttextspec = PDFJ::TextSpec->new;
2429 my($ulx, $uly, $bxx, $bxy);
2430 my($lastfontsize, $postshift, $slant, $lastfrx, $lastfry, $va) = (0) x 6;
2431 my($lastfontname, $withlinestyle, $withbox, $withboxstyle) = ("") x 4;
2432 for( my $j = 0; $j < $count && $start + $j < $chunksnum; $j++ ) {
2433 my $chunk = $self->chunk($start + $j);
2434 my $mode = $chunk->{Mode};
2435 my $class = $chunk->{Class};
2436 # my $style = $chunk->{Style};
2437 my $style = $chunk->{Style}->clone;
2438 my $direction = $style->{font}->{direction};
2439 my($fontname, $hname) = $style->selectfontname($mode);
2440 my $fontobj = $style->{font} = $docobj->_fontobj($fontname, $hname);
2441 my $combo = $fontobj->{combo};
2442 my $usefname = $mode eq 'a' && $hname ? $hname : $fontname;
2443 $usefontname{$usefname}++;
2444 my $fontsize = $style->{fontsize};
2445 $postshift *= $lastfontsize / $fontsize;
2446 $style->{slant} = 1 if $mode eq 'z' && $style->{italic};
2447 my $textspec = PDFJ::TextSpec->new($style, $usefname);
2448 if( $direction eq 'V' && $combo && $mode eq 'a' ) {
2449 if( $va != $class ) {
2450 my($vax, $vay) = $class == 11 ?
2451 ($x - _chunkfontsizeH($fontobj, $fontsize, $chunk) / 2,
2452 $y - $fontsize * $PDFJ::Default{VHShift}) :
2453 ($x + $fontsize * $PDFJ::Default{VAShift}, $y);
2454 $tj .= "] TJ ET Q " if $tj;
2455 $tj .= $class == 11 ?
2456 $textspec->pdf."$vax $vay Td [" :
2457 $textspec->pdf."0 -1 1 0 $vax $vay Tm [";
2458 $lasttextspec->copy($textspec);
2462 $tj .= "] TJ ET Q " if $tj;
2463 $tj .= $textspec->pdf."$x $y Td [";
2464 $lasttextspec->copy($textspec);
2467 if( $style->{slant} ) {
2468 #croak "slant style for ascii not allowed"
2471 my($sx, $sy) = $direction eq 'H' ?
2472 (0, $PDFJ::Default{SlantRatio}) :
2473 ($PDFJ::Default{SlantRatio}, 0);
2474 $tj .= "] TJ ET Q " if $tj;
2475 $tj .= $textspec->pdf."1 $sx $sy 1 $x $y Tm [";
2476 $lasttextspec->copy($textspec);
2480 $tj .= "] TJ ET Q " if $tj;
2481 $tj .= $textspec->pdf."$x $y Td [";
2482 $lasttextspec->copy($textspec);
2485 unless( $lasttextspec->equal($textspec) ) {
2486 $tj .= "] TJ ET Q " if $tj;
2487 $tj .= $textspec->pdf."$x $y Td [";
2488 $lasttextspec->copy($textspec);
2490 my $shift = $va == 11 ? 0 : $j == 0 ? $chunk->{PreShift} :
2491 $postshift + $chunk->{PreShift} -
2492 ($fixedglues ? $chunk->{Glue} + ($fixedglues->[$j] || 0):
2494 $shift = -$shift if $direction eq 'V';
2497 my $vs = $va ? -$shift : $shift;
2500 my($flx, $fly) = ($x, $y);
2501 my($frx, $fry) = ($x, $y);
2502 my($fcx, $fcy) = ($x, $y);
2503 if( $direction eq 'H' ) {
2504 $flx -= ($postshift - ($j == 0 ? 0 :
2505 ($fixedglues ? $chunk->{Glue} + ($fixedglues->[$j] || 0):
2506 $chunk->{Glue}))) * $fontsize;
2507 $frx = $flx + (_chunkfontsizeH($fontobj, $fontsize, $chunk) -
2508 ($chunk->{PreShift} + $chunk->{PostShift}) * $fontsize);
2509 $fcx = $flx + (_chunkfontsizeH($fontobj, $fontsize, $chunk) -
2510 ($chunk->{PreShift} + $chunk->{PostShift}) * $fontsize) /
2513 $fly += ($postshift - ($j == 0 ? 0 :
2514 ($fixedglues ? $chunk->{Glue} + ($fixedglues->[$j] || 0):
2515 $chunk->{Glue}))) * $fontsize;
2516 $fry = $fly - (_chunkfontsizeV($fontobj, $fontsize, $chunk) -
2517 ($chunk->{PreShift} + $chunk->{PostShift}) * $fontsize);
2518 $fcy = $fly - (_chunkfontsizeV($fontobj, $fontsize, $chunk) -
2519 ($chunk->{PreShift} + $chunk->{PostShift}) * $fontsize) /
2522 if( $mode eq 'O' || $mode eq 'D' ) { # Outline or Dest
2523 my($ox, $oy) = ($flx, $fly);
2524 if( $direction eq 'H' ) {
2525 $oy += (1 - $PDFJ::Default{HBaseShift}) * $fontsize;
2527 $ox -= $fontsize / 2;
2529 if( $mode eq 'O' ) {
2530 my $title = $style->{outlinetitle};
2531 my $level = $style->{outlinelevel};
2532 $docobj->add_outline($title, $page->dest('XYZ', $ox, $oy, 0),
2534 } elsif( $mode eq 'D' ) {
2535 my $name = $style->{destname};
2536 $docobj->add_dest($name, $page->dest('XYZ', $ox, $oy, 0));
2539 if( $chunk->{AltObj} ) {
2540 my $altobj = $chunk->{AltObj};
2541 my $altsize = $altobj->size($direction);
2542 my $objalign = $style->{objalign} || "";
2544 my($asx, $asy) = (0, 0);
2545 if( $direction eq 'H' ) {
2546 if( $objalign =~ /t/ ) {
2548 $asy += (1 - $PDFJ::Default{HBaseShift}) * $fontsize;
2549 } elsif( $objalign =~ /m/ ) {
2551 $asy += (0.5 - $PDFJ::Default{HBaseShift}) * $fontsize;
2554 $asy += (- $PDFJ::Default{HBaseShift}) * $fontsize;
2557 if( $objalign =~ /l/ ) {
2559 $asx -= $fontsize / 2;
2560 } elsif( $objalign =~ /r/ ) {
2562 $asx += $fontsize / 2;
2567 $altsize = $altsize * 1000 / $fontsize;
2568 $altsize = -$altsize if $direction eq 'H';
2570 $altobj->show($page, $flx + $asx, $fly + $asy, $align);
2571 } elsif( $chunk->{String} =~ /[^\x20-\x7e]/ ) {
2572 my $ss = unpack('H*', $chunk->{String});
2575 my $ss = $chunk->{String};
2581 $postshift = $chunk->{PostShift};
2582 if( $style->{withline} ) {
2583 ($ulx, $uly) = ($flx, $fly) unless defined $ulx;
2584 $withlinestyle = $style->{withlinestyle};
2585 if( $j == $count - 1 || $start + $j == $chunksnum - 1 ) {
2586 $shapepdf .= $direction eq 'H' ?
2587 _withlinepdf($direction, $ulx, $uly, $frx - $ulx,
2588 $fontsize, $withlinestyle) :
2589 _withlinepdf($direction, $ulx, $uly, $fry - $uly,
2590 $fontsize, $withlinestyle);
2592 } elsif( defined $ulx ) {
2593 $shapepdf .= $direction eq 'H' ?
2594 _withlinepdf($direction, $ulx, $uly, $lastfrx - $ulx,
2595 $lastfontsize, $withlinestyle) :
2596 _withlinepdf($direction, $ulx, $uly, $lastfry - $uly,
2597 $lastfontsize, $withlinestyle);
2601 if( $style->{withbox} ) {
2602 ($bxx, $bxy) = ($flx, $fly) unless defined $bxx;
2603 $withbox = $style->{withbox};
2604 $withboxstyle = $style->{withboxstyle};
2605 if( $j == $count - 1 || $start + $j == $chunksnum - 1 ) {
2606 $shapepdf .= $direction eq 'H' ?
2607 _withboxpdf($page, $direction, $bxx, $bxy, $frx - $bxx,
2608 $fontsize, $withbox, $withboxstyle) :
2609 _withboxpdf($page, $direction, $bxx, $bxy, $fry - $bxy,
2610 $fontsize, $withbox, $withboxstyle);
2612 } elsif( defined $bxx ) {
2613 $shapepdf .= $direction eq 'H' ?
2614 _withboxpdf($page, $direction, $bxx, $bxy, $lastfrx - $bxx,
2615 $lastfontsize, $withbox, $withboxstyle) :
2616 _withboxpdf($page, $direction, $bxx, $bxy, $lastfry - $bxy,
2617 $lastfontsize, $withbox, $withboxstyle);
2621 if( $style->{withdot} ) {
2622 croak "withdot style needs JFont"
2623 unless UNIVERSAL::isa($fontobj, "PDFJ::JFont");
2624 my($dx, $dy, $ds, $dcode);
2625 if( $direction eq 'H' ) {
2627 $fcx - $fontsize / 2 + $fontsize * $PDFJ::Default{HDotXShift},
2628 $fcy + $fontsize * $PDFJ::Default{HDotYShift},
2630 $dcode = unpack('H*', $PDFJ::Default{HDot}{$PDFJ::Default{Jcode}})
2633 ($fcx + $fontsize * $PDFJ::Default{VDotXShift},
2634 $fcy + $fontsize / 2 + $fontsize * $PDFJ::Default{VDotYShift},
2636 $dcode = unpack('H*', $PDFJ::Default{VDot}{$PDFJ::Default{Jcode}})
2638 my $fontname = $fontobj->{zname};
2639 $dotpdf .= "BT 0 Ts 0 Tr /$fontname $ds Tf $dx $dy Td <$dcode> Tj ET ";
2641 if( $chunk->{RubyText} ) {
2642 my $rubytext = $chunk->{RubyText};
2643 if( $direction eq 'H' ) {
2644 $rubytext->show($page, $flx,
2645 $fly + $PDFJ::Default{ORuby} * $fontsize / 1000);
2647 $rubytext->show($page,
2648 $flx + $PDFJ::Default{RRuby} * $fontsize / 1000,
2652 if( $style->{withnote} ) {
2653 my $notetext = $style->{withnote};
2654 my $notesize = $notetext->size;
2655 if( $direction eq 'H' ) {
2656 $notetext->show($page, $frx - $notesize,
2657 $fry + $PDFJ::Default{HNote} * $fontsize / 1000);
2659 $notetext->show($page,
2660 $frx + $PDFJ::Default{VNote} * $fontsize / 1000,
2664 ($lastfrx, $lastfry) = ($frx, $fry);
2665 $lastfontsize = $fontsize;
2666 if( $direction eq 'H' ) {
2667 $x += _chunkfontsizeH($fontobj, $fontsize, $chunk) -
2668 $shift * $fontsize / 1000;
2670 $y -= _chunkfontsizeV($fontobj, $fontsize, $chunk) +
2671 $shift * $fontsize / 1000;
2674 $tj .= "] TJ ET Q " if $tj;
2677 $page->addcontents($shapepdf);
2678 $page->addcontents($tj);
2679 $page->addcontents($dotpdf);
2680 $page->usefonts(keys %usefontname);
2684 my($direction, $x, $y, $w, $fontsize, $style) = @_;
2685 my $shape = PDFJ::Shape->new;
2686 if( $direction eq 'H' ) {
2687 $shape->textuline($x, $y, $w, $fontsize, $style);
2689 $shape->textrline($x, $y, $w, $fontsize, $style);
2695 my($page, $direction, $x, $y, $w, $fontsize, $spec, $style) = @_;
2696 my $shape = PDFJ::Shape->new;
2697 $shape->textbox($direction, $x, $y, $w, $fontsize, $spec,
2699 $shape->show_link($page);
2705 # character classes are
2708 # 2: not at top of line
2726 # 'z': zenkaku Japanese
2727 # 'h': hankaku Japanese
2736 Style => 1, # PDFJ::TextStyle object
2737 Mode => 2, # description as above
2738 Class => 3, # description as above
2739 Splittable => 4, # 1 for splittable at pre-postion
2740 Glue => 5, # normal glue width
2741 GlueDec => 6, # decrease adjustable glue width
2742 GlueInc => 7, # increase adjustable glue width
2743 GluePref => 8, # glue preference
2744 Count => 9, # characters count
2745 String => 10, # characters string
2746 PreShift => 11, # postion shift at pre-postion
2747 PostShift => 12, # postion shift at post-postion
2748 GlueFix => 13, # fixed glue (to be calculated)
2749 Hyphened => 14, # 1 for splitted, 2 for hyphened
2750 RubyText => 15, # ruby PDFJ::Text object
2751 AltObj => 16, # alternative object for String
2755 my($style, $mode, $class, $splittable) = @_;
2756 [\%ChunkIndex, $style, $mode, $class, $splittable,
2757 0, 0, 0, 0, 0, "", 0, 0];
2761 my($textstyle) = @_;
2762 _specialchunk($textstyle, 'N', 11, 2);
2766 my($outlineobj, $textstyle) = @_;
2767 my $style = $textstyle->clone(%$outlineobj);
2768 _specialchunk($style, 'O', 11, 1);
2772 my($destobj, $textstyle) = @_;
2773 my $style = $textstyle->clone(%$destobj);
2774 _specialchunk($style, 'D', 11, 1);
2778 my($obj, $textstyle) = @_;
2779 my $chunk = _specialchunk($textstyle, 'S', 11, 1);
2780 $chunk->{AltObj} = $obj;
2786 my($img, $textstyle) = @_;
2787 my $chunk = _specialchunk($textstyle, 'I', 11, 1);
2788 $chunk->{AltObj} = $img;
2794 my($shape, $textstyle) = @_;
2795 my $chunk = _specialchunk($textstyle, 'S', 11, 1);
2796 $chunk->{AltObj} = $shape;
2797 my($left, $bottom) = ($shape->left, $shape->bottom);
2802 my($self, $src) = @_;
2803 my $dest = $self->chunks;
2804 if( @$dest && @$src ) {
2805 my($splittable, $glue, $gluedec, $glueinc, $gluepref);
2806 my $lastclass = _lastclass($dest);
2807 my $lastmode = _lastmode($dest);
2808 my $fchunk = $src->[0];
2809 my $class = $fchunk->{Class};
2810 my $mode = $fchunk->{Mode};
2811 my $style = $fchunk->{Style};
2812 $splittable = $fchunk->{Splittable} == 2 ? 2 :
2813 $style->{suffix} ? 0 :
2814 $lastmode eq 'O' ? 0 :
2815 $PDFJ::Default{Splittable}->[$lastclass][$class];
2816 $glue = ($lastmode =~ /^[ON]$/ || $mode =~ /^[ON]$/) ?
2818 $PDFJ::Default{Glue}->[$lastclass][$class];
2819 ($glue, $gluedec, $glueinc, $gluepref) = _calcglue($glue);
2820 $fchunk->{Splittable} = $splittable;
2821 $fchunk->{Glue} = $glue;
2822 $fchunk->{GlueDec} = $gluedec;
2823 $fchunk->{GlueInc} = $glueinc;
2824 $fchunk->{GluePref} = $gluepref;
2830 my($chunks, $style, $mode, $class, $char, $preshift, $postshift) = @_;
2833 my($splittable, $glue, $gluedec, $glueinc, $gluepref) = (0) x 5;
2834 if( exists $style->{font} && exists $style->{font}{subset_unicodes} ) {
2835 my $unicode = $PDFJ::Default{Jcode} eq 'SJIS' ?
2836 PDFJ::Unicode::s2u($char) : PDFJ::Unicode::e2u($char);
2837 $style->{font}{subset_unicodes}{$unicode}++;
2840 my $lastchunk = $chunks->[$#$chunks];
2841 my $lastmode = $lastchunk->{Mode};
2842 my $lastclass = $lastchunk->{Class};
2843 my $lastruby = $lastchunk->{Style}{ruby};
2844 $splittable = $style->{suffix} ? 0 :
2845 $lastmode eq 'O' ? 0 :
2846 $PDFJ::Default{Splittable}->[$lastclass][$class];
2847 $glue = ($lastmode =~ /^[ON]$/ || $mode =~ /^[ON]$/) ?
2849 $PDFJ::Default{Glue}->[$lastclass][$class];
2850 if( ($mode eq 'a' && $lastmode eq 'a' && $class == $lastclass &&
2851 ($class == 11 || (!@$glue && !$splittable))) ||
2852 ($style->{ruby} && $style->{ruby} eq $lastruby &&
2853 ($class == 11 || $class == 17) && $class == $lastclass)
2855 $lastchunk->{Count}++;
2856 $lastchunk->{String} .= $char;
2859 ($glue, $gluedec, $glueinc, $gluepref) = _calcglue($glue);
2861 push @$chunks, [\%ChunkIndex, $style, $mode, $class, $splittable,
2862 $glue, $gluedec, $glueinc, $gluepref, 1, $char,
2863 $preshift, $postshift];
2868 my($gluedec, $glueinc, $gluepref) = (0, 0, 0);
2870 my($gmin, $gnormal, $gmax, $gpref) = @$glue;
2871 ($glue, $gluedec, $glueinc) = (
2873 ($gnormal - $gmin) / 1000,
2874 ($gmax - $gnormal) / 1000
2876 $gluepref = $gpref || 0;
2878 ($glue, $gluedec, $glueinc, $gluepref) = (0, 0, 0, 0);
2880 ($glue, $gluedec, $glueinc, $gluepref);
2885 @$chunks ? $chunks->[$#$chunks]{Class} : undef;
2890 @$chunks ? $chunks->[$#$chunks]{Mode} : undef;
2894 my($self, $str) = @_;
2895 if( UNIVERSAL::isa($self->style->{font}, "PDFJ::AFont") ) {
2897 } elsif( $PDFJ::Default{Jcode} eq 'SJIS' ) {
2904 sub splittext_ASCII {
2905 my($self, $str) = @_;
2906 my $style = $self->style;
2908 my @c = split('', $str);
2909 for( my $j = 0; $j <= $#c; $j++ ) {
2912 _appendchunks($result, $style, 'a', 16, $c);
2914 if( $style->{vh} ) {
2915 _appendchunks($result, $style, 'a', 11, $c);
2916 } elsif( $c =~ /[0-9]/ ) {
2917 _appendchunks($result, $style, 'a', 14, $c);
2918 } elsif( $c =~ /[,. ]/ && _lastclass($result) == 14 &&
2919 $c[$j+1] =~ /[0-9]/ ) {
2920 _appendchunks($result, $style, 'a', 14, $c);
2922 _appendchunks($result, $style, 'a', 17, $c);
2930 my($self, $str) = @_;
2931 my $style = $self->style;
2933 my @c = split('', $str);
2934 for( my $j = 0; $j <= $#c; $j++ ) {
2936 if( $c eq "\x8e" ) {
2937 _appendchunks($result, $style, 'h', 11, $c.$c[$j+1]);
2939 } elsif( $c eq "\x8f" ) {
2940 _appendchunks($result, $style, 'z', 11, $c.$c[$j+1].$c[$j+2]);
2942 } elsif( $c eq " " ) {
2943 _appendchunks($result, $style, 'a', 16, $c);
2944 } elsif( $c lt "\xa0" ) {
2945 if( $style->{vh} ) {
2946 _appendchunks($result, $style, 'a', 11, $c);
2947 } elsif( $c =~ /[0-9]/ ) {
2948 _appendchunks($result, $style, 'a', 14, $c);
2949 } elsif( $c =~ /[,. ]/ && _lastclass($result) == 14 &&
2950 $c[$j+1] =~ /[0-9]/ ) {
2951 _appendchunks($result, $style, 'a', 14, $c);
2953 _appendchunks($result, $style, 'a', 17, $c);
2956 my $k = $c.$c[$j+1];
2958 my $class = $PDFJ::Default{Class}{EUC}{$k};
2959 unless( defined $class ) {
2960 if( $k ge "\xa4\xa1" && $k le "\xa4\xf3" ) {
2966 my $preshift = ($PDFJ::Default{PreShift}{EUC}{$k} || 0) / 1000;
2967 my $postshift = ($PDFJ::Default{PostShift}{EUC}{$k} || 0) / 1000;
2968 _appendchunks($result, $style, 'z', $class, $k, $preshift, $postshift);
2974 sub splittext_SJIS {
2975 my($self, $str) = @_;
2976 my $style = $self->style;
2978 my @c = split('', $str);
2979 for( my $j = 0; $j <= $#c; $j++ ) {
2981 if( $c ge "\x81" && $c le "\x9f" || $c ge "\xe0" && $c le "\xfc" ) {
2982 my $k = $c.$c[$j+1];
2984 my $class = $PDFJ::Default{Class}{SJIS}{$k};
2985 unless( defined $class ) {
2986 if( $k ge "\x82\x9f" && $k le "\x82\xf1" ) {
2992 my $preshift = ($PDFJ::Default{PreShift}{SJIS}{$k} || 0) / 1000;
2993 my $postshift = ($PDFJ::Default{PostShift}{SJIS}{$k} || 0) / 1000;
2994 _appendchunks($result, $style, 'z', $class, $k, $preshift, $postshift);
2995 } elsif( $c eq " " ) {
2996 _appendchunks($result, $style, 'a', 16, $c);
2997 } elsif( $c ge "\xa1" && $c le "\xdf" ) {
2998 _appendchunks($result, $style, 'h', 11, $c);
3000 if( $style->{vh} ) {
3001 _appendchunks($result, $style, 'a', 11, $c);
3002 } elsif( $c =~ /[0-9]/ ) {
3003 _appendchunks($result, $style, 'a', 14, $c);
3004 } elsif( $c =~ /[,. ]/ && _lastclass($result) == 14 &&
3005 defined $c[$j+1] && $c[$j+1] =~ /[0-9]/ ) {
3006 _appendchunks($result, $style, 'a', 14, $c);
3008 _appendchunks($result, $style, 'a', 17, $c);
3015 #--------------------------------------------------------------------------
3016 package PDFJ::ParagraphStyle;
3020 @ISA = qw(PDFJ::Style);
3022 sub PStyle { PDFJ::ParagraphStyle->new(@_) }
3024 #--------------------------------------------------------------------------
3025 package PDFJ::Paragraph;
3029 @ISA = qw(PDFJ::Showable);
3031 sub Paragraph { PDFJ::Paragraph->new(@_) }
3034 my($class, $text, $style) = @_;
3035 croak "paragraph text argument must be a PDFJ::Text object"
3036 unless UNIVERSAL::isa($text, 'PDFJ::Text');
3037 croak "paragraph style argument must be a PDFJ::ParagraphStyle object"
3038 unless UNIVERSAL::isa($style, 'PDFJ::ParagraphStyle');
3039 croak "size specification missing" unless $style->{size};
3040 croak "linefeed specification missing" unless exists $style->{linefeed};
3041 croak "align specification missing" unless $style->{align};
3042 my $self = bless { text => $text, style => $style }, $class;
3043 $self->{linefeed} = $style->{linefeed} =~ /(\d+)%/ ?
3044 $text->fontsize * $1 / 100 : $style->{linefeed};
3045 my $lineskip = $self->{linefeed} - $text->fontsize;
3046 $lineskip = 0 if $lineskip < 0;
3047 $self->{preskip} = exists $style->{preskip} ?
3048 $style->{preskip} : $lineskip * $PDFJ::Default{ParaPreSkipRatio};
3049 $self->{postskip} = exists $style->{postskip} ?
3050 $style->{postskip} : $lineskip * $PDFJ::Default{ParaPostSkipRatio};
3051 my $labeltext = $style->{labeltext};
3052 my $firstminindent = 0;
3054 if( UNIVERSAL::isa($labeltext, 'PDFJ::Showable') ) {
3055 $self->{labelobj} = $labeltext;
3056 } elsif( ref($labeltext) eq 'CODE' ) {
3057 $self->{labelobj} = &$labeltext();
3058 } elsif( ref($labeltext) eq 'ARRAY' &&
3059 ref($labeltext->[0]) eq 'CODE' ) {
3060 my($func, @args) = @$labeltext;
3061 $self->{labelobj} = &$func(@args);
3062 } elsif( ref($labeltext) ) {
3063 croak "unknown labeltext type";
3065 $self->{labelobj} = $labeltext;
3067 $self->{labelobj} = PDFJ::Text->new($self->{labelobj}, $text->style)
3068 unless ref($self->{labelobj});
3069 my $labelobjsize = $self->{labelobj}->size($self->text->direction);
3070 $firstminindent = $labelobjsize + $self->labelskip - $self->labelsize;
3071 $firstminindent = 0 if $firstminindent < 0;
3073 $self->{beginindent} =
3074 exists $style->{beginindent} ?
3075 ref($style->{beginindent}) eq 'ARRAY' ?
3076 [@{$style->{beginindent}}] :
3077 [$style->{beginindent}] :
3079 if( $self->{beginindent}[0] < $firstminindent ) {
3080 $self->{beginindent}[1] = $self->{beginindent}[0]
3081 if @{$self->{beginindent}} == 1;
3082 $self->{beginindent}[0] = $firstminindent;
3084 $self->{endindent} =
3085 exists $style->{endindent} ?
3086 ref($style->{endindent}) eq 'ARRAY' ?
3087 [@{$style->{endindent}}] :
3088 [$style->{endindent}] :
3090 my @lines = $text->_fold($self->linesizes, $style->{align});
3091 $self->{lines} = \@lines;
3095 sub text { $_[0]->{text} }
3096 sub linesnum { scalar(@{$_[0]->{lines}}) }
3097 sub line { $_[0]->{lines}->[$_[1]] }
3098 sub labelsize { $_[0]->{style}->{labelsize} || 0 }
3099 sub labelskip { $_[0]->{style}->{labelskip} || 0 }
3100 sub beginpadding { $_[0]->{style}->{beginpadding} || 0 }
3101 sub beginindents { scalar @{$_[0]->{beginindent}} }
3103 my($self, $idx) = @_;
3104 my $count = @{$self->{beginindent}};
3105 if( $idx < $count ) {
3106 $self->{beginindent}[$idx];
3108 $self->{beginindent}[$count - 1];
3111 sub endindents { scalar @{$_[0]->{endindent}} }
3113 my($self, $idx) = @_;
3114 my $count = @{$self->{endindent}};
3115 if( $idx < $count ) {
3116 $self->{endindent}[$idx];
3118 $self->{endindent}[$count - 1];
3121 sub _size { $_[0]->{style}{size} }
3125 my $count = $self->beginindents > $self->endindents ?
3126 $self->beginindents :
3128 for( my $j = 0; $j < $count; $j++ ) {
3129 push @linesizes, $self->_size - $self->beginpadding - $self->labelsize -
3130 $self->beginindent($j) - $self->endindent($j);
3134 sub linefeed { $_[0]->{linefeed} }
3135 sub preskip { $_[0]->{preskip} || 0 }
3136 sub postskip { $_[0]->{postskip} || 0 }
3137 sub nobreak { $_[0]->{style}->{nobreak} }
3138 sub postnobreak { $_[0]->{style}->{postnobreak} }
3139 sub float { $_[0]->{style}->{float} || "" }
3141 my($self, $blockdirection) = @_;
3142 return 0 if $self->nobreak;
3143 my $direction = $self->text->direction;
3144 if( $direction eq 'H' ) {
3145 $blockdirection eq 'V' ? 1 : 0;
3147 $blockdirection eq 'V' ? 0 : 1;
3154 $self->text->fontsize + ($self->linesnum - 1) * $self->linefeed : 0;
3158 my($self, @sizes) = @_;
3159 my $unbreakable = $self->nobreak;
3160 my $lastsize = $sizes[$#sizes];
3162 my @lines = @{$self->{lines}};
3163 my @beginindents = @{$self->{beginindent}};
3164 my @endindents = @{$self->{endindent}};
3167 my $size = @sizes ? shift(@sizes) : $lastsize;
3168 my $count = $unbreakable ?
3169 ($size < $self->_linessize ? 0 : scalar(@lines)) :
3170 ($size < $self->text->fontsize ? 0 :
3171 int(($size - $self->text->fontsize) / $self->linefeed) + 1);
3172 return if !$count && !@sizes;
3173 my @blines = splice @lines, 0, $count;
3174 my @bbi = splice @beginindents, 0, $count;
3175 @beginindents = ($bbi[$#bbi]) unless @beginindents;
3176 my @bei = splice @endindents, 0, $count;
3177 @endindents = ($bei[$#bei]) unless @endindents;
3178 my $bpara = bless {text => $self->{text},
3179 style => $self->{style},
3180 linefeed => $self->{linefeed}, preskip => $self->{preskip},
3181 postskip => $self->{postskip},
3182 beginindent => \@bbi, endindent => \@bei,
3183 labelobj => ($second ? undef : $self->{labelobj}),
3184 lines => \@blines}, ref($self);
3185 $second = 1 if @blines;
3186 push @result, $bpara;
3193 $self->text->direction eq 'H' ?
3200 $self->text->direction eq 'H' ?
3207 $self->text->direction eq 'H' ?
3209 - ($self->_linessize - $self->text->fontsize / 2);
3214 $self->text->direction eq 'H' ?
3216 $self->text->fontsize / 2;
3221 $self->text->direction eq 'H' ?
3222 $self->text->fontsize * $PDFJ::Default{HBaseHeight} :
3228 $self->text->direction eq 'H' ?
3229 - ($self->_linessize -
3230 $self->text->fontsize * $PDFJ::Default{HBaseHeight}) :
3235 my($self, $direction) = @_;
3236 if( $direction eq 'H' ) {
3238 } elsif( $direction eq 'V' ) {
3246 my($self, $page, $x, $y) = @_;
3247 for( my $j = 0; $j < $self->linesnum; $j++ ) {
3248 ($x, $y) = $self->_showline($page, $x, $y, $j);
3254 my($self, $page, $x, $y, $line) = @_;
3255 return unless $line < $self->linesnum;
3256 my $style = $self->{style};
3257 my $start = $self->line($line)->{Start};
3258 my $count = $self->line($line)->{Count};
3259 my $fixedglues = $self->line($line)->{FixedGlues};
3260 my $shift = $self->line($line)->{Shift} + $self->beginpadding +
3261 $self->labelsize + $self->beginindent($line);
3262 my $linefeed = $self->linefeed;
3263 my $text = $self->text;
3264 my $tstyle = $text->style;
3265 croak "no font specification" unless exists $tstyle->{font};
3266 my $direction = $tstyle->{font}{direction};
3267 if( $line == 0 && $self->{labelobj} ) {
3268 my($lx, $ly) = $direction eq 'H' ? ($x + $self->beginpadding, $y) :
3269 ($x, $y - $self->beginpadding);
3270 $self->{labelobj}->show($page, $lx, $ly);
3273 if( $direction eq 'H' ) {
3274 ($nextx, $nexty) = ($x, $y - $linefeed);
3277 ($nextx, $nexty) = ($x - $linefeed, $y);
3280 $text->_showpart($page, $x, $y, $start, $count, $fixedglues);
3284 #--------------------------------------------------------------------------
3285 package PDFJ::NewBlock;
3289 @ISA = qw(PDFJ::BlockElement);
3291 sub NewBlock { PDFJ::NewBlock->new(@_) }
3295 bless \$class, $class;
3298 #--------------------------------------------------------------------------
3299 package PDFJ::BlockSkip;
3303 @ISA = qw(PDFJ::BlockElement);
3306 my($class, $skip) = @_;
3307 bless {skip => $skip}, $class;
3310 sub size { $_[0]->{skip} || 0 }
3312 #--------------------------------------------------------------------------
3313 package PDFJ::BlockStyle;
3317 @ISA = qw(PDFJ::Style);
3319 sub BStyle { PDFJ::BlockStyle->new(@_) }
3321 #--------------------------------------------------------------------------
3322 package PDFJ::Block;
3326 @ISA = qw(PDFJ::Showable);
3328 sub Block { PDFJ::Block->new(@_); }
3332 my $direction = shift;
3333 my $style = pop; # not shift
3334 croak "block direction argument must be H or V or R"
3335 unless $direction =~ /^H|V|R$/;
3336 croak "block style argument must be a PDFJ::BlockStyle object"
3337 unless UNIVERSAL::isa($style, 'PDFJ::BlockStyle');
3338 my @objects = (@_ == 1 && ref($_[0]) eq 'ARRAY') ? @{$_[0]} : @_;
3339 for( my $j = 0; $j < @objects; $j++ ) {
3340 if( UNIVERSAL::isa($objects[$j], 'PDFJ::BlockElement') ) {
3342 } elsif( $objects[$j] =~ /^\d+$/ ) {
3343 $objects[$j] = PDFJ::BlockSkip->new($objects[$j]);
3345 croak "illegal Block element: $objects[$j]"
3348 my $self = bless { direction => $direction, objects => \@objects,
3349 xpreshift => 0, xpostshift => 0, ypreshift => 0, ypostshift => 0,
3350 style => $style }, $class;
3352 $self->adjustwidth($style->{width}) if $style->{width};
3353 $self->adjustheight($style->{height}) if $style->{height};
3358 my($self, @sizes) = @_;
3359 my $unbreakable = $self->nobreak;
3360 my $nofirstfloat = $self->nofirstfloat;
3361 my $repeatheader = $self->repeatheader;
3362 my $lastsize = $sizes[$#sizes];
3363 my $direction = $self->{direction} eq 'V' ? 'V' : 'H';
3365 my @objects = @{$self->{objects}};
3366 my @repeatheader = $repeatheader ?
3367 @objects[0..($repeatheader - 1)] : ();
3369 while( @objects || @reserve ) {
3370 my $size = @sizes ? shift(@sizes) : $lastsize;
3371 unshift @objects, splice(@reserve);
3373 if( $unbreakable ) {
3374 @bobjects = splice @objects if $size >= $self->size($direction);
3376 my $bsize = $self->padding * 2;
3377 while( $bsize < $size && @objects ) {
3378 my $obj = $objects[0];
3379 my $float = $obj->float;
3380 if( $float && @reserve ) {
3381 push @reserve, shift(@objects);
3384 if( $float eq 'b' && $nofirstfloat && !@result ) {
3385 push @reserve, shift(@objects);
3388 my $inspos = _inspos(\@bobjects, $float);
3390 if( $inspos == 0 ) {
3391 $skipsize = $obj->postskip + $bobjects[$inspos]->preskip
3393 } elsif( $inspos == @bobjects ) {
3394 $skipsize = $bobjects[$inspos - 1]->postskip + $obj->preskip;
3396 $skipsize = $obj->preskip + $obj->postskip;
3398 my $osize = $obj->size($direction);
3399 if( UNIVERSAL::isa($obj, 'PDFJ::NewBlock') ) {
3402 } elsif( $bsize + $skipsize + $osize <= $size ) {
3403 splice @bobjects, $inspos, 0, shift(@objects);
3404 $bsize += $skipsize + $osize;
3405 } elsif( $obj->breakable($self->{direction}) ) {
3406 my @bsizes = ($size - $bsize - $skipsize,
3407 map {$_ - $self->padding * 2}
3408 (@sizes ? (@sizes) : ($lastsize)));
3409 my @parts = $obj->break(@bsizes);
3412 my $osize = $obj->size($direction);
3414 $bsize += $skipsize + $osize;
3416 unshift @objects, @parts;
3417 splice @bobjects, $inspos, 0, shift(@objects);
3421 unshift @objects, @parts;
3429 push @reserve, shift(@objects);
3436 while( @bobjects && $bobjects[$#bobjects]->postnobreak && @objects ) {
3437 unshift @objects, pop(@bobjects);
3439 return if !@bobjects && !@sizes;
3440 if( $repeatheader && (@bobjects >= $repeatheader) && @objects ) {
3441 unshift @objects, @repeatheader;
3445 $bobj->{objects} = \@bobjects;
3446 delete $bobj->{indents};
3447 bless $bobj, ref($self);
3449 push @result, $bobj;
3454 sub _inspos { # NOT method
3455 my($objects, $float) = @_;
3457 if( $float eq 'b' ) {
3459 while( $inspos < @$objects && $objects->[$inspos]->float eq 'b' ) {
3462 } elsif( $float eq 'e' ) {
3463 $inspos = @$objects;
3465 $inspos = @$objects;
3466 while( $inspos > 0 && $objects->[$inspos - 1]->float eq 'e' ) {
3475 my($width, $height) = (0, 0);
3476 my $objnum = @{$self->{objects}};
3477 my $adjust = $self->{style}{adjust};
3478 my $align = $self->align;
3479 if( $self->{direction} eq 'V' ) {
3480 for( my $j = 0; $j < $objnum; $j++ ) {
3481 my $obj = $self->{objects}->[$j];
3483 $height += $self->{objects}->[$j-1]->postskip + $obj->preskip;
3485 if( UNIVERSAL::isa($obj, 'PDFJ::Showable') ) {
3486 $width = $width < $obj->width ? $obj->width : $width;
3487 $height += $obj->height;
3488 } elsif( UNIVERSAL::isa($obj, 'PDFJ::BlockElement') ) {
3489 $height += $obj->size($self->{direction});
3491 croak "illegal block element";
3495 for my $obj(@{$self->{objects}}) {
3496 $obj->adjustwidth($width) if UNIVERSAL::isa($obj, 'PDFJ::Block');
3500 if( $align =~ /c/ ) {
3501 for( my $j = 0; $j < $objnum; $j++ ) {
3502 my $obj = $self->{objects}->[$j];
3503 if( UNIVERSAL::isa($obj, 'PDFJ::Showable') ) {
3504 $indents[$j] = ($width - $obj->width) / 2;
3507 } elsif( $align =~ /r/ ) {
3508 for( my $j = 0; $j < $objnum; $j++ ) {
3509 my $obj = $self->{objects}->[$j];
3510 if( UNIVERSAL::isa($obj, 'PDFJ::Showable') ) {
3511 $indents[$j] = $width - $obj->width;
3515 $self->{indents} = \@indents;
3517 for( my $j = 0; $j < $objnum; $j++ ) {
3518 my $obj = $self->{objects}->[$j];
3520 $width += $self->{objects}->[$j-1]->postskip + $obj->preskip;
3522 if( UNIVERSAL::isa($obj, 'PDFJ::Showable') ) {
3523 $height = $height < $obj->height ? $obj->height : $height;
3524 $width += $obj->width;
3525 } elsif( UNIVERSAL::isa($obj, 'PDFJ::BlockElement') ) {
3526 $width += $obj->size($self->{direction});
3528 croak "illegal block element";
3532 for my $obj(@{$self->{objects}}) {
3533 $obj->adjustheight($height)
3534 if UNIVERSAL::isa($obj, 'PDFJ::Block');
3538 if( $align =~ /m/ ) {
3539 for( my $j = 0; $j < $objnum; $j++ ) {
3540 my $obj = $self->{objects}->[$j];
3541 if( UNIVERSAL::isa($obj, 'PDFJ::Showable') ) {
3542 $indents[$j] = ($height - $obj->height) / 2;
3545 } elsif( $align =~ /b/ ) {
3546 for( my $j = 0; $j < $objnum; $j++ ) {
3547 my $obj = $self->{objects}->[$j];
3548 if( UNIVERSAL::isa($obj, 'PDFJ::Showable') ) {
3549 $indents[$j] = $height - $obj->height;
3553 $self->{indents} = \@indents;
3555 $self->{width} = $width;
3556 $self->{height} = $height;
3559 sub padding { $_[0]->{style}{padding} || 0 }
3563 $self->{width} + $self->padding * 2
3564 + $self->{xpreshift} + $self->{xpostshift}
3565 + ($self->direction eq 'H' ? 0 : $self->beginpadding);
3569 $self->{height} + $self->padding * 2
3570 + $self->{ypreshift} + $self->{ypostshift}
3571 + ($self->direction eq 'H' ? $self->beginpadding : 0);
3574 my($self, $direction) = @_;
3575 if( $direction eq 'H' ) {
3582 sub right { $_[0]->width }
3584 sub bottom { - $_[0]->height }
3585 sub preskip { $_[0]->{style}{preskip} || 0 }
3586 sub postskip { $_[0]->{style}{postskip} || 0 }
3587 sub align { $_[0]->{style}{align} || "" }
3588 sub nobreak { $_[0]->{style}{nobreak} }
3589 sub postnobreak { $_[0]->{style}{postnobreak} }
3590 sub repeatheader { $_[0]->{style}{repeatheader} || 0 }
3591 sub float { $_[0]->{style}->{float} || "" }
3592 sub nofirstfloat { $_[0]->{style}{nofirstfloat} }
3593 sub beginpadding { $_[0]->{style}{beginpadding} || 0 }
3594 sub direction { $_[0]->{direction} }
3596 my($self, $blockdirection) = @_;
3597 $self->nobreak ? 0 :
3598 $blockdirection eq $self->{direction} ? 1 :
3603 my($self, $size) = @_;
3604 return unless $size;
3605 my $align = $self->align;
3606 return $self if $self->width >= $size;
3607 $size -= $self->width;
3608 if( $align =~ /r/ ) {
3609 $self->{xpreshift} = $size;
3610 } elsif( $align =~ /c/ ) {
3611 $self->{xpreshift} = $size / 2;
3612 $self->{xpostshift} = $size / 2;
3614 $self->{xpostshift} = $size;
3620 my($self, $size) = @_;
3621 return unless $size;
3622 my $align = $self->align;
3623 return $self if $self->height >= $size;
3624 $size -= $self->height;
3625 if( $align =~ /b/ ) {
3626 $self->{ypreshift} = $size;
3627 } elsif( $align =~ /m/ ) {
3628 $self->{ypreshift} = $size / 2;
3629 $self->{ypostshift} = $size / 2;
3631 $self->{ypostshift} = $size;
3637 my($self, $page, $x, $y) = @_;
3638 if( $self->direction eq 'H' ) {
3639 $y -= $self->beginpadding;
3641 $x += $self->beginpadding;
3643 my $style = $self->{style};
3644 if( $style->{withbox} ) {
3645 my $withbox = $style->{withbox};
3646 my $withboxstyle = $style->{withboxstyle};
3647 my $shape = PDFJ::Shape->new;
3648 $shape->box(0, 0, $self->width, - $self->height, $withbox,
3650 $shape->show($page, $x, $y);
3652 $x += $self->padding + $self->{xpreshift};
3653 $y -= $self->padding + $self->{ypreshift};
3654 my $objnum = @{$self->{objects}};
3655 if( $self->{direction} eq 'V' ) {
3656 for( my $j = 0; $j < $objnum; $j++ ) {
3657 my $obj = $self->{objects}->[$j];
3658 my $indent = $self->{indents}->[$j] || 0;
3660 $y -= $self->{objects}->[$j-1]->postskip + $obj->preskip;
3662 if( UNIVERSAL::isa($obj, 'PDFJ::Showable') ) {
3663 $obj->show($page, $x + $indent, $y, 'tl');
3665 } elsif( UNIVERSAL::isa($obj, 'PDFJ::BlockElement') ) {
3666 $y -= $obj->size($self->{direction});
3667 } elsif( $obj =~ /^\d+$/ ) {
3670 croak "illegal block element";
3673 } elsif( $self->{direction} eq 'H' ) {
3674 for( my $j = 0; $j < $objnum; $j++ ) {
3675 my $obj = $self->{objects}->[$j];
3676 my $indent = $self->{indents}->[$j] || 0;
3678 $x += $self->{objects}->[$j-1]->postskip + $obj->preskip;
3680 if( UNIVERSAL::isa($obj, 'PDFJ::Showable') ) {
3681 $obj->show($page, $x, $y - $indent, 'tl');
3683 } elsif( UNIVERSAL::isa($obj, 'PDFJ::BlockElement') ) {
3684 $x += $obj->size($self->{direction});
3686 croak "illegal block element";
3689 } elsif( $self->{direction} eq 'R' ) {
3690 $x += $self->{width};
3691 for( my $j = 0; $j < $objnum; $j++ ) {
3692 my $obj = $self->{objects}->[$j];
3693 my $indent = $self->{indents}->[$j] || 0;
3695 $x -= $self->{objects}->[$j-1]->postskip + $obj->preskip;
3697 if( UNIVERSAL::isa($obj, 'PDFJ::Showable') ) {
3698 $obj->show($page, $x, $y - $indent, 'tr');
3700 } elsif( UNIVERSAL::isa($obj, 'PDFJ::BlockElement') ) {
3701 $x -= $obj->size($self->{direction});
3703 croak "illegal block element";
3709 #--------------------------------------------------------------------------
3710 package PDFJ::Image;
3715 @ISA = qw(PDFJ::Showable);
3718 my($class, $docobj, $src, $pxwidth, $pxheight, $width, $height, $padding,
3720 my($ext) = $src =~ /([^\.]+)$/;
3721 # croak "unknown image file extention: $ext"
3722 # unless $ext =~ /^jpe?g$/i;
3723 if( $src =~ /^http:/i ) {
3724 new_url($class, $docobj, $src, $pxwidth, $pxheight, $width,
3725 $height, $padding, $colorspace);
3727 new_file($class, $docobj, $src, $pxwidth, $pxheight, $width,
3728 $height, $padding, $colorspace);
3733 my($class, $docobj, $url, $pxwidth, $pxheight, $width, $height, $padding,
3735 $width ||= $pxwidth;
3736 $height ||= $pxheight;
3737 $colorspace ||= 'DeviceRGB';
3738 $colorspace = $colorspace =~ /^rgb$/i ? 'DeviceRGB' :
3739 $colorspace =~ /^gray$/i ? 'DeviceGray' :
3740 $colorspace =~ /^cmyk$/i ? 'DeviceCMYK' :
3742 my $num = $docobj->_nextimagenum;
3744 my $image = $docobj->indirect(stream(dictionary => {
3745 Name => name($name),
3746 Type => name("XObject"),
3747 Subtype => name("Image"),
3748 Width => number($pxwidth),
3749 Height => number($pxheight),
3750 BitsPerComponent => 8,
3751 ColorSpace => name($colorspace),
3752 FFilter => name("DCTDecode"),
3760 $docobj->_registimage($name, $image);
3761 bless { name => $name, image => $image, width => $width,
3762 height => $height, padding => $padding }, $class;
3766 my($class, $docobj, $file, $pxwidth, $pxheight, $width, $height, $padding,
3768 $width ||= $pxwidth;
3769 $height ||= $pxheight;
3770 $colorspace ||= 'DeviceRGB';
3771 $colorspace = $colorspace =~ /^rgb$/i ? 'DeviceRGB' :
3772 $colorspace =~ /^gray$/i ? 'DeviceGray' :
3773 $colorspace =~ /^cmyk$/i ? 'DeviceCMYK' :
3775 my $num = $docobj->_nextimagenum;
3777 my($encoded, $filter) = $docobj->_makestream($file, "DCTDecode");
3778 my $image = $docobj->indirect(stream(dictionary => {
3779 Name => name($name),
3780 Type => name("XObject"),
3781 Subtype => name("Image"),
3782 Width => number($pxwidth),
3783 Height => number($pxheight),
3784 BitsPerComponent => 8,
3785 ColorSpace => name($colorspace),
3787 Length => length($encoded),
3788 }, stream => $encoded));
3789 $docobj->_registimage($name, $image);
3790 bless { name => $name, image => $image, width => $width,
3791 height => $height, padding => $padding }, $class;
3794 sub image { $_[0]->{image} }
3795 sub width { $_[0]->{width} + $_[0]->padding * 2 }
3796 sub height { $_[0]->{height} + $_[0]->padding * 2 }
3797 sub padding { $_[0]->{padding} || 0 }
3799 sub right { $_[0]->width }
3800 sub top { $_[0]->height }
3804 my($self, $direction) = @_;
3805 $direction eq 'H' ? $self->width : $self->height;
3809 my($self, $width, $height) = @_;
3810 $self->{width} = $width;
3811 $self->{height} = $height;
3816 my($self, $padding) = @_;
3817 $self->{padding} = $padding;
3821 my($self, $page, $x, $y) = @_;
3822 $x += $self->padding;
3823 $y += $self->padding;
3824 my $width = $self->{width};
3825 my $height = $self->{height};
3826 my $name = $self->{name};
3827 $page->addcontents("q $width 0 0 $height $x $y cm /$name Do Q");
3828 $page->useimage($self);
3831 #--------------------------------------------------------------------------
3832 package PDFJ::Color;
3836 sub Color { PDFJ::Color->new(@_) }
3843 if( $value =~ /^#([A-Fa-f0-9]{2})([A-Fa-f0-9]{2})([A-Fa-f0-9]{2})$/ ) {
3844 my(@rgb) = map {oct("0x$_")/256} ($1,$2,$3);
3845 $self = bless { type => 'rgb', value => \@rgb }, $class;
3847 $self = bless { type => 'gray', value => $value }, $class;
3849 } elsif( @_ == 3 ) {
3851 $self = bless { type => 'rgb', value => \@rgb }, $class;
3853 croak "Color arguments must be one or three";
3860 if( $self->{type} eq 'gray' ) {
3861 "$self->{value} g ";
3863 my @rgb = @{$self->{value}};
3870 if( $self->{type} eq 'gray' ) {
3871 "$self->{value} G ";
3873 my @rgb = @{$self->{value}};
3878 #--------------------------------------------------------------------------
3879 package PDFJ::ShapeStyle;
3883 @ISA = qw(PDFJ::Style);
3885 sub SStyle { PDFJ::ShapeStyle->new(@_) }
3890 $result .= $self->{fillcolor}->fill if $self->{fillcolor};
3891 $result .= $self->{strokecolor}->stroke if $self->{strokecolor};
3892 $result .= "$self->{linewidth} w " if $self->{linewidth};
3893 if( $self->{linedash} ) {
3894 my($dash, $gap, $phase) = @{$self->{linedash}};
3896 $result .= "[$dash $gap] $phase d ";
3901 #--------------------------------------------------------------------------
3902 package PDFJ::Shape;
3906 @ISA = qw(PDFJ::Showable);
3908 sub Shape { PDFJ::Shape->new(@_) }
3911 my($class, $style) = @_;
3913 { left => 0, top => 0, right => 0, bottom => 0, pdf => "" }, $class;
3914 $self->style($style) if $style;
3918 sub padding { $_[0]->{style}{padding} || 0 }
3919 sub left { $_[0]->{left} - $_[0]->padding }
3920 sub right { $_[0]->{right} + $_[0]->padding }
3921 sub top { $_[0]->{top} + $_[0]->padding }
3922 sub bottom { $_[0]->{bottom} - $_[0]->padding }
3923 sub width { $_[0]->{right} - $_[0]->{left} + $_[0]->padding * 2 }
3924 sub height { $_[0]->{top} - $_[0]->{bottom} + $_[0]->padding * 2 }
3925 sub preskip { $_[0]->{style}{preskip} || 0 }
3926 sub postskip { $_[0]->{style}{postskip} || 0 }
3927 sub postnobreak { $_[0]->{style}{postnobreak} }
3928 sub float { $_[0]->{style}->{float} || "" }
3929 sub pdf { $_[0]->{pdf} }
3932 my($self, $direction) = @_;
3933 $direction eq 'H' ? $self->width : $self->height;
3937 my($self, $x, $y) = @_;
3938 if( $x < $self->{left} ) {
3940 } elsif( $x > $self->{right} ) {
3941 $self->{right} = $x;
3943 if( $y < $self->{bottom} ) {
3944 $self->{bottom} = $y;
3945 } elsif( $y > $self->{top} ) {
3951 my($self, $pdf) = @_;
3952 $pdf .= " " unless $pdf =~ / $/;
3953 $self->{pdf} .= $pdf;
3958 my($self, $obj, @args) = @_;
3959 push @{$self->{objects}}, [$obj, @args];
3964 my($self, $rect, $name) = @_;
3965 $self->{link}{join(',', @$rect)} = $name;
3969 my($self, $page, $x, $y) = @_;
3972 for my $rect(keys %{$self->{link}}) {
3973 my $name = $self->{link}{$rect};
3974 my @rect = split(',', $rect);
3979 $page->add_link(\@rect, $name);
3984 my($self, $page, $x, $y) = @_;
3985 $x += $self->padding;
3986 $y += $self->padding;
3988 if( $self->{style} ) {
3989 $stylepdf = $self->{style}->pdf if UNIVERSAL::can($self->{style}, 'pdf');
3991 $page->addcontents("q 1 0 0 1 $x $y cm $stylepdf $self->{pdf}");
3992 if( $self->{objects} ) {
3993 for my $objspec(@{$self->{objects}}) {
3994 my($obj, @args) = @$objspec;
3995 $obj->show($page, @args);
3998 $page->addcontents("Q");
3999 $self->show_link($page, $x, $y);
4003 my($self, $style) = @_;
4004 croak "shape style argument must be a PDFJ::ShapeStyle object"
4005 unless UNIVERSAL::isa($style, 'PDFJ::ShapeStyle');
4006 $self->{style} = $style;
4010 # General Graphic State operators
4014 $self->appendpdf("q");
4019 $self->appendpdf("Q");
4024 $self->appendpdf("$w w");
4028 my($self, $dash, $gap, $phase) = @_;
4030 $self->appendpdf("[$dash $gap] $phase d");
4034 my($self, @array) = @_;
4035 croak "ctm array must have 6 elements" unless @array == 6;
4036 $self->appendpdf("@array cm");
4042 my($self, $color) = @_;
4043 croak "color argument must be a PDFJ::Color object"
4044 unless UNIVERSAL::isa($color, 'PDFJ::Color');
4045 $self->appendpdf($color->fill);
4049 my($self, $color) = @_;
4050 croak "color argument must be a PDFJ::Color object"
4051 unless UNIVERSAL::isa($color, 'PDFJ::Color');
4052 $self->appendpdf($color->stroke);
4057 $self->appendpdf("$g g");
4062 $self->appendpdf("$g G");
4066 my($self, $r, $g, $b) = @_;
4067 $self->appendpdf("$r $g $b rg");
4071 my($self, $r, $g, $b) = @_;
4072 $self->appendpdf("$r $g $b RG");
4075 # Path segment operators
4077 # moves the current point to (x, y), omitting any connecting line segment
4079 my($self, $x, $y) = @_;
4080 $self->setboundary($x, $y);
4081 $self->appendpdf("$x $y m");
4084 # appends a straight line segment from the current point to (x, y).
4085 # The current point becomes (x, y).
4087 my($self, $x, $y) = @_;
4088 $self->setboundary($x, $y);
4089 $self->appendpdf("$x $y l");
4092 # appends a Bezier curve to the path. The curve extends
4093 # from the current point to (x3 ,y3) using (x1 ,y1) and (x2 ,y2)
4094 # as the Bezier control points.
4095 # The current point becomes (x3 ,y3).
4097 my($self, $x1, $y1, $x2, $y2, $x3, $y3) = @_;
4098 $self->setboundary($x1, $y1);
4099 $self->setboundary($x2, $y2);
4100 $self->setboundary($x3, $y3);
4101 $self->appendpdf("$x1 $y1 $x2 $y2 $x3 $y3 c");
4106 # adds a rectangle to the current path
4108 my($self, $x, $y, $w, $h) = @_;
4109 $self->setboundary($x, $y);
4110 $self->setboundary($x + $w, $y + $h);
4111 $self->appendpdf("$x $y $w $h re");
4114 # closes the current subpath by appending a straight line segment
4115 # from the current point to the starting point of the subpath.
4118 $self->appendpdf("h");
4121 # ends the path without filling or stroking it
4124 $self->appendpdf("n");
4130 $self->appendpdf("S");
4133 # closes and strokes the path
4136 $self->appendpdf("s");
4139 # fills the path using the non-zero winding number rule
4142 $self->appendpdf("f");
4145 # fills the path using the even-odd rule
4148 $self->appendpdf("f*");
4154 my($self, $x, $y, $w, $h, $style) = @_;
4156 $stylepdf = $style->pdf if $style;
4157 my($x1, $y1, $x2, $y2) = ($x, $y, $x + $w, $y + $h);
4158 $self->setboundary($x1, $y1);
4159 $self->setboundary($x2, $y2);
4160 $self->appendpdf("q $stylepdf") if $stylepdf;
4161 $self->appendpdf("$x1 $y1 m $x2 $y2 l S");
4162 $self->appendpdf("Q") if $stylepdf;
4167 my($self, $x, $y, $size, $fontsize, $style) = @_;
4168 my $yshift = $PDFJ::Default{ULine} * $fontsize / 1000;
4169 $self->line($x, $y + $yshift, $size, 0, $style);
4173 my($self, $x, $y, $size, $fontsize, $style) = @_;
4174 my $yshift = $PDFJ::Default{OLine} * $fontsize / 1000;
4175 $self->line($x, $y + $yshift, $size, 0, $style);
4179 my($self, $x, $y, $size, $fontsize, $style) = @_;
4180 my $xshift = $PDFJ::Default{LLine} * $fontsize / 1000;
4181 $self->line($x + $xshift, $y, 0, $size, $style);
4185 my($self, $x, $y, $size, $fontsize, $style) = @_;
4186 my $xshift = $PDFJ::Default{RLine} * $fontsize / 1000;
4187 $self->line($x + $xshift, $y, 0, $size, $style);
4191 my($self, $x, $y, $w, $h, $spec, $style) = @_;
4192 $spec = "s" unless $spec;
4194 $stylepdf = $style->pdf if $style;
4196 if( $spec =~ s/r(\d+)// ) {
4198 croak "too big radius for round box"
4199 if $r * 2 > abs($w) || $r * 2 > abs($h);
4207 $self->setboundary($x, $y);
4208 $self->setboundary($x + $w, $y + $h);
4209 if( $spec ne 'n' ) {
4210 $self->appendpdf("q $stylepdf") if $stylepdf;
4212 my $bz = $r * 0.55228475;
4214 $x+$w, $y+$h-$r, 'm',
4215 $x+$w, $y+$h-$r+$bz,
4216 $x+$w-$r+$bz, $y+$h,
4217 $x+$w-$r, $y+$h, 'c',
4230 $x+$w, $y+$h-$r, 'l'
4232 $self->appendpdf("@work ");
4234 $self->appendpdf("$x $y m $x $y $w $h re ");
4236 if( $spec eq 'sf' ) {
4237 $self->appendpdf("B");
4238 } elsif( $spec eq 's' ) {
4239 $self->appendpdf("S");
4240 } elsif( $spec eq 'f' ) {
4241 $self->appendpdf("f");
4242 } elsif( $spec =~ /^([lrtb]+)(f?)$/ ) {
4243 croak "'lrtb' is inconsistent with 'rX'" if $r;
4244 my($side, $fill) = ($1, $2);
4245 if( $fill eq 'f' ) {
4246 $self->appendpdf("f");
4248 $self->appendpdf("n");
4250 $self->line($x, $y, 0, $h) if $side =~ /l/;
4251 $self->line($x + $w, $y, 0, $h) if $side =~ /r/;
4252 $self->line($x, $y + $h, $w, 0) if $side =~ /t/;
4253 $self->line($x, $y, $w, 0) if $side =~ /b/;
4254 } elsif( $spec eq 'n' ) {
4255 $self->appendpdf("n");
4257 croak "illegal strokefill argument: $spec";
4259 $self->appendpdf("Q") if $stylepdf;
4261 if( $style && $style->{link} ) {
4262 $self->add_link([$x, $y, $x + $w, $y + $h], $style->{link});
4268 my($self, $direction, $x, $y, $size, $fontsize, $spec,
4270 my(@bbox) = @{$PDFJ::Default{"SBox$direction"}};
4271 grep {$_ = $_ * $fontsize / 1000} @bbox;
4272 if( $direction eq 'H' ) {
4276 $size + $bbox[2] - $bbox[0] - $fontsize,
4277 $bbox[3] - $bbox[1],
4284 $bbox[2] - $bbox[0] ,
4285 $size + $bbox[3] - $bbox[1] - $fontsize,
4292 my($self, $x, $y, $r, $spec, $arcarea, $style) = @_;
4293 $self->ellipse($x, $y, $r, $r, $spec, $arcarea, $style);
4297 my($self, $x, $y, $xr, $yr, $spec, $arcarea, $style) = @_;
4298 $spec = "s" unless $spec;
4300 $stylepdf = $style->pdf if $style;
4301 $self->appendpdf("q $stylepdf") if $stylepdf;
4302 my $xbz = $xr * 0.55228475;
4303 my $ybz = $yr * 0.55228475;
4306 $x+$xr, $y+$ybz, $x+$xbz, $y+$yr, $x, $y+$yr,
4307 $x-$xbz, $y+$yr, $x-$xr, $y+$ybz, $x-$xr, $y,
4308 $x-$xr, $y-$ybz, $x-$xbz, $y-$yr, $x, $y-$yr,
4309 $x+$xbz, $y-$yr, $x+$xr, $y-$ybz, $x+$xr, $y,
4314 $self->setboundary(@pt[$arcarea * 6, $arcarea * 6 + 1]);
4315 $self->setboundary(@pt[$arcarea * 6 + 6, $arcarea * 6 + 7]);
4316 $self->appendpdf(join(' ',splice(@pt, $arcarea * 6, 2))." m ");
4317 $self->appendpdf(join(' ',splice(@pt, $arcarea * 6, 6))." c ");
4319 $self->setboundary($x - $xr, $y - $yr);
4320 $self->setboundary($x + $xr, $y + $yr);
4321 $self->appendpdf(join(' ',splice(@pt, 0, 2))." m ");
4322 $self->appendpdf(join(' ',splice(@pt, 0, 6))." c ");
4323 $self->appendpdf(join(' ',splice(@pt, 0, 6))." c ");
4324 $self->appendpdf(join(' ',splice(@pt, 0, 6))." c ");
4325 $self->appendpdf(join(' ',splice(@pt, 0, 6))." c ");
4327 if( $spec eq 'sf' ) {
4328 $self->appendpdf("B");
4329 } elsif( $spec eq 's' ) {
4330 $self->appendpdf("S");
4331 } elsif( $spec eq 'f' ) {
4332 $self->appendpdf("f");
4334 $self->appendpdf("Q") if $stylepdf;
4339 my($self, $coords, $spec, $style) = @_;
4340 croak "coords argument must be an array ref"
4341 unless ref($coords) eq 'ARRAY';
4342 croak "coords argument must have even elements"
4345 for( my $j = 0; $j < @$coords; $j += 2 ) {
4346 push @work, $coords->[$j], $coords->[$j + 1];
4347 push @work, ($j == 0) ? 'm' : 'l';
4350 $stylepdf = $style->pdf if $style;
4351 $self->appendpdf("q $stylepdf") if $stylepdf;
4352 $self->appendpdf("@work ");
4353 if( $spec eq 'sf' ) {
4354 $self->appendpdf("B");
4355 } elsif( $spec eq 's' ) {
4356 $self->appendpdf("S");
4357 } elsif( $spec eq 'f' ) {
4358 $self->appendpdf("f");
4360 $self->appendpdf("Q") if $stylepdf;
4365 my($self, $obj, @showargs) = @_;
4366 $self->appendobj($obj, @showargs);
4370 #--------------------------------------------------------------------------
4377 my($class, $docobj, $pagewidth, $pageheight) = @_;
4378 my $pagetree = $docobj->{pagetree};
4379 $pagewidth ||= $docobj->{pagewidth};
4380 $pageheight ||= $docobj->{pageheight};
4381 my $page = $docobj->indirect(dictionary({
4382 Type => name('Page'),
4383 Parent => $pagetree,
4384 Resources => {ProcSet => [name('PDF'), name('Text')], Font => {}},
4385 MediaBox => [0, 0, $pagewidth, $pageheight],
4386 Contents => $docobj->indirect(
4387 contents_stream(dictionary => {}, stream => [])),
4389 push @{$docobj->{pagelist}}, $page;
4390 my $pagenum = @{$docobj->{pagelist}};
4391 $pagetree->get('Kids')->push($page);
4392 $pagetree->get('Count')->add(1);
4395 pagenum => $pagenum,
4396 parent => $pagetree,
4400 push @{$docobj->{pageobjlist}}, $self;
4425 my($self, $str) = @_;
4426 $str .= " " unless $str =~ / $/;
4427 $self->page->get('Contents')->append($str, $self->getlayer);
4431 my($self, $layer) = @_;
4432 $self->{layer} = $layer;
4437 my($self, @names) = @_;
4438 my $docobj = $self->docobj;
4439 my $resources = $self->page->get('Resources');
4440 for my $name(@names) {
4441 $resources->get('Font')->set($name, $docobj->_font($name));
4446 my($self, $imageobj) = @_;
4447 my $resources = $self->page->get('Resources');
4448 $resources->get('ProcSet')->add(name('ImageC'));
4449 $resources->set(XObject => {}) unless $resources->exists('XObject');
4450 $resources->get('XObject')->set($imageobj->{name}, $imageobj->{image});
4454 my($self, $argtype, @args) = @_;
4455 array([$self->page, name($argtype), map {$_ eq '' ? null : $_} @args]);
4459 my($self, $rect, $name) = @_;
4460 $self->{link}{join(',', @$rect)} = $name;
4464 my($self, %spec) = @_;
4465 $spec{Type} = name('Annot');
4466 my $docobj = $self->docobj;
4467 unless( $self->page->exists('Annots') ) {
4468 $self->page->set(Annots => []);
4470 $self->page->get('Annots')->push($docobj->indirect(dictionary(\%spec)));
4475 my $docobj = $self->docobj;
4476 for my $rect(keys %{$self->{link}}) {
4477 my $name = $self->{link}{$rect};
4478 my @rect = split(',', $rect);
4479 if( $name =~ /^URI:(.+)/ ) {
4482 Subtype => name('Link'),
4486 Type => name('Action'),
4488 URI => string(PDFJ::Util::uriencode($uri))
4492 my $dest = $docobj->dest($name)
4493 or croak "missing dest '$name'";
4495 Subtype => name('Link'),
4504 #--------------------------------------------------------------------------
4510 my($class, $version, $handle, $objtable, $rootobj) = @_;
4513 version => $version, # PDF version
4514 handle => $handle, # file handle
4515 objtable => $objtable, # PDFJ::ObjTable object
4516 rootobj => $rootobj, # document catalog object
4524 $self->print_header;
4527 $self->print_trailer;
4532 my $handle = $self->{handle};
4533 my $version = $self->{version};
4534 print $handle "%PDF-$version\n";
4539 my $handle = $self->{handle};
4540 my $objtable = $self->{objtable};
4541 return unless $objtable->lastobjnum;
4542 for my $objnum(1 .. $objtable->lastobjnum) {
4543 $self->{objposlist}->[$objnum] = $handle->tell;
4544 $objtable->get($objnum)->print($handle);
4550 my $handle = $self->{handle};
4551 $self->{xrefpos} = $handle->tell;
4552 print $handle "xref\n";
4553 my $objtable = $self->{objtable};
4554 my $lastobjnum = $objtable->lastobjnum;
4555 my $entries = $lastobjnum + 1;
4556 print $handle "0 $entries\n";
4557 print $handle "0000000000 65535 f \n";
4559 for my $objnum(1 .. $lastobjnum) {
4560 printf $handle "%010.10d %05.5d n \n",
4561 $self->{objposlist}->[$objnum],
4562 $objtable->get($objnum)->{gennum};
4570 my $handle = $self->{handle};
4571 my $xrefpos = $self->{xrefpos};
4572 my $objtable = $self->{objtable};
4573 my $traildic = dictionary({
4574 Size => $objtable->lastobjnum + 1,
4575 Root => $self->{rootobj}
4577 print $handle "trailer\n", $traildic->output,
4578 "\nstartxref\n$xrefpos\n%%EOF\n";
4581 #--------------------------------------------------------------------------
4582 package PDFJ::ObjTable;
4587 bless {objlist => [undef]}, $class;
4592 $#{$self->{objlist}};
4596 my($self, $idx) = @_;
4597 $self->{objlist}->[$idx];
4601 my($self, $idx, $obj) = @_;
4602 $self->{objlist}->[$idx] = $obj;
4606 #--------------------------------------------------------------------------
4607 # for SelfLoader in PDFJ::AFont
4608 package PDFJ::AFont;
4610 sub fontwidth_Courier { [
4611 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4612 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4613 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4614 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4615 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4616 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4617 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4618 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4619 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4620 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4621 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4622 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4623 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4624 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4625 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4626 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4627 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4628 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4629 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4630 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4631 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4632 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4633 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4636 sub fontwidth_Courier_Bold { [
4637 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4638 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4639 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4640 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4641 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4642 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4643 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4644 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4645 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4646 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4647 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4648 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4649 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4650 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4651 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4652 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4653 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4654 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4655 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4656 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4657 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4658 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4659 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4662 sub fontwidth_Courier_BoldOblique { [
4663 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4664 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4665 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4666 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4667 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4668 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4669 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4670 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4671 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4672 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4673 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4674 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4675 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4676 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4677 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4678 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4679 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4680 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4681 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4682 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4683 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4684 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4685 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4688 sub fontwidth_Courier_Oblique { [
4689 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4690 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4691 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4692 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4693 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4694 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4695 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4696 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4697 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4698 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4699 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4700 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4701 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4702 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4703 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4704 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4705 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4706 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4707 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4708 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4709 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4710 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4711 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
4714 sub fontwidth_Helvetica { [
4715 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
4716 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
4717 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
4718 278, 355, 556, 556, 889, 667, 221, 333, 333, 389, 584,
4719 278, 333, 278, 278, 556, 556, 556, 556, 556, 556, 556,
4720 556, 556, 556, 278, 278, 584, 584, 584, 556, 1015, 667,
4721 667, 722, 722, 667, 611, 778, 722, 278, 500, 667, 556,
4722 833, 722, 778, 667, 778, 722, 667, 611, 722, 667, 944,
4723 667, 667, 611, 278, 278, 278, 469, 556, 222, 556, 556,
4724 500, 556, 556, 278, 556, 556, 222, 222, 500, 222, 833,
4725 556, 556, 556, 556, 333, 500, 278, 556, 500, 722, 500,
4726 500, 500, 334, 260, 334, 584, 278, 278, 278, 278, 278,
4727 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
4728 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
4729 278, 278, 278, 278, 278, 278, 278, 333, 556, 556, 167,
4730 556, 556, 556, 556, 191, 333, 556, 333, 333, 500, 500,
4731 278, 556, 556, 556, 278, 278, 537, 350, 222, 333, 333,
4732 556, 1000, 1000, 278, 611, 278, 333, 333, 333, 333, 333,
4733 333, 333, 333, 278, 333, 333, 278, 333, 333, 333, 1000,
4734 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
4735 278, 278, 278, 278, 278, 1000, 278, 370, 278, 278, 278,
4736 278, 556, 778, 1000, 365, 278, 278, 278, 278, 278, 889,
4737 278, 278, 278, 278, 278, 278, 222, 611, 944, 611, 278,
4740 sub fontwidth_Helvetica_Bold { [
4741 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
4742 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
4743 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
4744 333, 474, 556, 556, 889, 722, 278, 333, 333, 389, 584,
4745 278, 333, 278, 278, 556, 556, 556, 556, 556, 556, 556,
4746 556, 556, 556, 333, 333, 584, 584, 584, 611, 975, 722,
4747 722, 722, 722, 667, 611, 778, 722, 278, 556, 722, 611,
4748 833, 722, 778, 667, 778, 722, 667, 611, 722, 667, 944,
4749 667, 667, 611, 333, 278, 333, 584, 556, 278, 556, 611,
4750 556, 611, 556, 333, 611, 611, 278, 278, 556, 278, 889,
4751 611, 611, 611, 611, 389, 556, 333, 611, 556, 778, 556,
4752 556, 500, 389, 280, 389, 584, 278, 278, 278, 278, 278,
4753 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
4754 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
4755 278, 278, 278, 278, 278, 278, 278, 333, 556, 556, 167,
4756 556, 556, 556, 556, 238, 500, 556, 333, 333, 611, 611,
4757 278, 556, 556, 556, 278, 278, 556, 350, 278, 500, 500,
4758 556, 1000, 1000, 278, 611, 278, 333, 333, 333, 333, 333,
4759 333, 333, 333, 278, 333, 333, 278, 333, 333, 333, 1000,
4760 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
4761 278, 278, 278, 278, 278, 1000, 278, 370, 278, 278, 278,
4762 278, 611, 778, 1000, 365, 278, 278, 278, 278, 278, 889,
4763 278, 278, 278, 278, 278, 278, 278, 611, 944, 611, 278,
4766 sub fontwidth_Helvetica_BoldOblique { [
4767 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
4768 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
4769 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
4770 333, 474, 556, 556, 889, 722, 278, 333, 333, 389, 584,
4771 278, 333, 278, 278, 556, 556, 556, 556, 556, 556, 556,
4772 556, 556, 556, 333, 333, 584, 584, 584, 611, 975, 722,
4773 722, 722, 722, 667, 611, 778, 722, 278, 556, 722, 611,
4774 833, 722, 778, 667, 778, 722, 667, 611, 722, 667, 944,
4775 667, 667, 611, 333, 278, 333, 584, 556, 278, 556, 611,
4776 556, 611, 556, 333, 611, 611, 278, 278, 556, 278, 889,
4777 611, 611, 611, 611, 389, 556, 333, 611, 556, 778, 556,
4778 556, 500, 389, 280, 389, 584, 278, 278, 278, 278, 278,
4779 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
4780 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
4781 278, 278, 278, 278, 278, 278, 278, 333, 556, 556, 167,
4782 556, 556, 556, 556, 238, 500, 556, 333, 333, 611, 611,
4783 278, 556, 556, 556, 278, 278, 556, 350, 278, 500, 500,
4784 556, 1000, 1000, 278, 611, 278, 333, 333, 333, 333, 333,
4785 333, 333, 333, 278, 333, 333, 278, 333, 333, 333, 1000,
4786 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
4787 278, 278, 278, 278, 278, 1000, 278, 370, 278, 278, 278,
4788 278, 611, 778, 1000, 365, 278, 278, 278, 278, 278, 889,
4789 278, 278, 278, 278, 278, 278, 278, 611, 944, 611, 278,
4792 sub fontwidth_Helvetica_Oblique { [
4793 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
4794 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
4795 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
4796 278, 355, 556, 556, 889, 667, 222, 333, 333, 389, 584,
4797 278, 333, 278, 278, 556, 556, 556, 556, 556, 556, 556,
4798 556, 556, 556, 278, 278, 584, 584, 584, 556, 1015, 667,
4799 667, 722, 722, 667, 611, 778, 722, 278, 500, 667, 556,
4800 833, 722, 778, 667, 778, 722, 667, 611, 722, 667, 944,
4801 667, 667, 611, 278, 278, 278, 469, 556, 222, 556, 556,
4802 500, 556, 556, 278, 556, 556, 222, 222, 500, 222, 833,
4803 556, 556, 556, 556, 333, 500, 278, 556, 500, 722, 500,
4804 500, 500, 334, 260, 334, 584, 278, 278, 278, 278, 278,
4805 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
4806 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
4807 278, 278, 278, 278, 278, 278, 278, 333, 556, 556, 167,
4808 556, 556, 556, 556, 191, 333, 556, 333, 333, 500, 500,
4809 278, 556, 556, 556, 278, 278, 537, 350, 222, 333, 333,
4810 556, 1000, 1000, 278, 611, 278, 333, 333, 333, 333, 333,
4811 333, 333, 333, 278, 333, 333, 278, 333, 333, 333, 1000,
4812 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
4813 278, 278, 278, 278, 278, 1000, 278, 370, 278, 278, 278,
4814 278, 556, 778, 1000, 365, 278, 278, 278, 278, 278, 889,
4815 278, 278, 278, 278, 278, 278, 222, 611, 944, 611, 278,
4818 # The chracter #39 (single quote) in Times-* fonts has 333 width
4819 # in afm files. But Acrobat uses a width nallower than it. I use an
4820 # experimental value 222.
4821 sub fontwidth_Times_Bold { [
4822 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250,
4823 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250,
4824 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250,
4825 # 333, 555, 500, 500, 1000, 833, 333, 333, 333, 500, 570,
4826 333, 555, 500, 500, 1000, 833, 222, 333, 333, 500, 570,
4827 250, 333, 250, 278, 500, 500, 500, 500, 500, 500, 500,
4828 500, 500, 500, 333, 333, 570, 570, 570, 500, 930, 722,
4829 667, 722, 722, 667, 611, 778, 778, 389, 500, 778, 667,
4830 944, 722, 778, 611, 778, 722, 556, 667, 722, 722, 1000,
4831 722, 722, 667, 333, 278, 333, 581, 500, 333, 500, 556,
4832 444, 556, 444, 333, 500, 556, 278, 333, 556, 278, 833,
4833 556, 500, 556, 556, 444, 389, 333, 556, 500, 722, 500,
4834 500, 444, 394, 220, 394, 520, 250, 250, 250, 250, 250,
4835 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250,
4836 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250,
4837 250, 250, 250, 250, 250, 250, 250, 333, 500, 500, 167,
4838 500, 500, 500, 500, 278, 500, 500, 333, 333, 556, 556,
4839 250, 500, 500, 500, 250, 250, 540, 350, 333, 500, 500,
4840 500, 1000, 1000, 250, 500, 250, 333, 333, 333, 333, 333,
4841 333, 333, 333, 250, 333, 333, 250, 333, 333, 333, 1000,
4842 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250,
4843 250, 250, 250, 250, 250, 1000, 250, 300, 250, 250, 250,
4844 250, 667, 778, 1000, 330, 250, 250, 250, 250, 250, 722,
4845 250, 250, 250, 278, 250, 250, 278, 500, 722, 556, 250,
4848 sub fontwidth_Times_BoldItalic { [
4849 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250,
4850 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250,
4851 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250,
4852 # 389, 555, 500, 500, 833, 778, 333, 333, 333, 500, 570,
4853 389, 555, 500, 500, 833, 778, 222, 333, 333, 500, 570,
4854 250, 333, 250, 278, 500, 500, 500, 500, 500, 500, 500,
4855 500, 500, 500, 333, 333, 570, 570, 570, 500, 832, 667,
4856 667, 667, 722, 667, 667, 722, 778, 389, 500, 667, 611,
4857 889, 722, 722, 611, 722, 667, 556, 611, 722, 667, 889,
4858 667, 611, 611, 333, 278, 333, 570, 500, 333, 500, 500,
4859 444, 500, 444, 333, 500, 556, 278, 278, 500, 278, 778,
4860 556, 500, 500, 500, 389, 389, 278, 556, 444, 667, 500,
4861 444, 389, 348, 220, 348, 570, 250, 250, 250, 250, 250,
4862 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250,
4863 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250,
4864 250, 250, 250, 250, 250, 250, 250, 389, 500, 500, 167,
4865 500, 500, 500, 500, 278, 500, 500, 333, 333, 556, 556,
4866 250, 500, 500, 500, 250, 250, 500, 350, 333, 500, 500,
4867 500, 1000, 1000, 250, 500, 250, 333, 333, 333, 333, 333,
4868 333, 333, 333, 250, 333, 333, 250, 333, 333, 333, 1000,
4869 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250,
4870 250, 250, 250, 250, 250, 944, 250, 266, 250, 250, 250,
4871 250, 611, 722, 944, 300, 250, 250, 250, 250, 250, 722,
4872 250, 250, 250, 278, 250, 250, 278, 500, 722, 500, 250,
4875 sub fontwidth_Times_Italic { [
4876 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250,
4877 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250,
4878 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250,
4879 # 333, 420, 500, 500, 833, 778, 333, 333, 333, 500, 675,
4880 333, 420, 500, 500, 833, 778, 222, 333, 333, 500, 675,
4881 250, 333, 250, 278, 500, 500, 500, 500, 500, 500, 500,
4882 500, 500, 500, 333, 333, 675, 675, 675, 500, 920, 611,
4883 611, 667, 722, 611, 611, 722, 722, 333, 444, 667, 556,
4884 833, 667, 722, 611, 722, 611, 500, 556, 722, 611, 833,
4885 611, 556, 556, 389, 278, 389, 422, 500, 333, 500, 500,
4886 444, 500, 444, 278, 500, 500, 278, 278, 444, 278, 722,
4887 500, 500, 500, 500, 389, 389, 278, 500, 444, 667, 444,
4888 444, 389, 400, 275, 400, 541, 250, 250, 250, 250, 250,
4889 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250,
4890 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250,
4891 250, 250, 250, 250, 250, 250, 250, 389, 500, 500, 167,
4892 500, 500, 500, 500, 214, 556, 500, 333, 333, 500, 500,
4893 250, 500, 500, 500, 250, 250, 523, 350, 333, 556, 556,
4894 500, 889, 1000, 250, 500, 250, 333, 333, 333, 333, 333,
4895 333, 333, 333, 250, 333, 333, 250, 333, 333, 333, 889,
4896 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250,
4897 250, 250, 250, 250, 250, 889, 250, 276, 250, 250, 250,
4898 250, 556, 722, 944, 310, 250, 250, 250, 250, 250, 667,
4899 250, 250, 250, 278, 250, 250, 278, 500, 667, 500, 250,
4902 sub fontwidth_Times_Roman { [
4903 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250,
4904 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250,
4905 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250,
4906 # 333, 408, 500, 500, 833, 778, 333, 333, 333, 500, 564,
4907 333, 408, 500, 500, 833, 778, 222, 333, 333, 500, 564,
4908 250, 333, 250, 278, 500, 500, 500, 500, 500, 500, 500,
4909 500, 500, 500, 278, 278, 564, 564, 564, 444, 921, 722,
4910 667, 667, 722, 611, 556, 722, 722, 333, 389, 722, 611,
4911 889, 722, 722, 556, 722, 667, 556, 611, 722, 722, 944,
4912 722, 722, 611, 333, 278, 333, 469, 500, 333, 444, 500,
4913 444, 500, 444, 333, 500, 500, 278, 278, 500, 278, 778,
4914 500, 500, 500, 500, 333, 389, 278, 500, 500, 722, 500,
4915 500, 444, 480, 200, 480, 541, 250, 250, 250, 250, 250,
4916 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250,
4917 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250,
4918 250, 250, 250, 250, 250, 250, 250, 333, 500, 500, 167,
4919 500, 500, 500, 500, 180, 444, 500, 333, 333, 556, 556,
4920 250, 500, 500, 500, 250, 250, 453, 350, 333, 444, 444,
4921 500, 1000, 1000, 250, 444, 250, 333, 333, 333, 333, 333,
4922 333, 333, 333, 250, 333, 333, 250, 333, 333, 333, 1000,
4923 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250,
4924 250, 250, 250, 250, 250, 889, 250, 276, 250, 250, 250,
4925 250, 611, 722, 889, 310, 250, 250, 250, 250, 250, 667,
4926 250, 250, 250, 278, 250, 250, 278, 500, 722, 500, 250,