origami 1.2.2 → 1.2.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -184,6 +184,8 @@ module Origami
184
184
  alias value to_h
185
185
 
186
186
  def method_missing(field, *args) #:nodoc:
187
+ raise NoMethodError, "No method `#{field}' for #{self.class}" unless field.to_s[0,1] =~ /[A-Z]/
188
+
187
189
  if field.to_s[-1,1] == '='
188
190
  self[field.to_s[0..-2].to_sym] = args.first
189
191
  else
@@ -302,6 +302,8 @@ module Origami
302
302
  attr_writer :stm_algo
303
303
  attr_writer :str_algo
304
304
 
305
+ private
306
+
305
307
  def physicalize(options = {})
306
308
 
307
309
  def build(obj, revision, options) #:nodoc:
@@ -1357,9 +1359,7 @@ module Origami
1357
1359
  end
1358
1360
 
1359
1361
  def password_to_utf8(passwd) #:nodoc:
1360
- p=Origami::ByteString.new(passwd).to_utf8[0, 127]
1361
- hexprint p
1362
- p
1362
+ Origami::ByteString.new(passwd).to_utf8[0, 127]
1363
1363
  end
1364
1364
 
1365
1365
  end
data/lib/origami/file.rb CHANGED
@@ -48,12 +48,18 @@ module Origami
48
48
  fd = path
49
49
  params[:EmbeddedName] ||= ''
50
50
  else
51
- fd = File.open(path, 'r').binmode
51
+ fd = File.open(File.expand_path(path), 'r').binmode
52
52
  params[:EmbeddedName] ||= File.basename(path)
53
53
  end
54
54
 
55
55
  fstream = EmbeddedFileStream.new
56
- fstream.data = fd.read
56
+
57
+ if ''.respond_to? :force_encoding
58
+ fstream.data = fd.read.force_encoding('binary') # 1.9
59
+ else
60
+ fstream.data = fd.read
61
+ end
62
+
57
63
  fstream.setFilter(params[:Filter])
58
64
 
59
65
  name = params[:EmbeddedName]
@@ -78,6 +78,17 @@ module Origami
78
78
  @instructions
79
79
  end
80
80
 
81
+ def draw_image(name, attr = {})
82
+ load! if @instructions.nil?
83
+
84
+ x, y = attr[:x], attr[:y]
85
+
86
+ @instructions << PDF::Instruction.new('q')
87
+ @instructions << PDF::Instruction.new('cm', 300, 0, 0, 300, x, y)
88
+ @instructions << PDF::Instruction.new('Do', name)
89
+ @instructions << PDF::Instruction.new('Q')
90
+ end
91
+
81
92
  #
82
93
  # Draw a straight line from the point at coord _from_, to the point at coord _to_.
83
94
  #
@@ -492,6 +503,50 @@ module Origami
492
503
  field :Measure, :Type => Dictionary, :Version => "1.7", :ExtensionLevel => 3
493
504
  field :PtData, :Type => Dictionary, :Version => "1.7", :ExtensionLevel => 3
494
505
 
506
+ def self.from_image_file(path, format = nil)
507
+
508
+ if path.respond_to?(:read)
509
+ fd = path
510
+ else
511
+ fd = File.open(File.expand_path(path), 'r').binmode
512
+ format ||= File.extname(path)
513
+ format.slice!(0) if format and format[0,1] == '.'
514
+ end
515
+
516
+ if ''.respond_to? :force_encoding
517
+ data = fd.read.force_encoding('binary') # 1.9
518
+ else
519
+ data = fd.read
520
+ end
521
+
522
+ fd.close
523
+
524
+ image = ImageXObject.new
525
+
526
+ raise ArgumentError, "Missing file format" if format.nil?
527
+ case format.downcase
528
+ when 'jpg', 'jpeg', 'jpe', 'jif', 'jfif', 'jfi'
529
+ image.setFilter :DCTDecode
530
+ image.rawdata = data
531
+
532
+ image
533
+
534
+ when 'jp2','jpx','j2k','jpf','jpm','mj2'
535
+ image.setFilter :JPXDecode
536
+ image.rawdata = data
537
+
538
+ image
539
+
540
+ when 'jb2', 'jbig', 'jbig2'
541
+ image.setFilter :JBIG2Decode
542
+ image.rawdata = data
543
+
544
+ image
545
+ else
546
+ raise NotImplementedError, "Unknown file format: '#{format}'"
547
+ end
548
+ end
549
+
495
550
  #
496
551
  # Converts an ImageXObject stream into an image file data.
497
552
  # Output format depends on the stream encoding:
@@ -211,7 +211,7 @@ module Origami
211
211
 
212
212
  acro_method 'read',
213
213
  Arg[:name => 'nBytes', :type => Numeric, :required => true] do |nBytes|
214
- @data.slice!(0, nBytes)
214
+ @data.slice!(0, nBytes).unpack("H*")[0]
215
215
  end
216
216
  end
217
217
 
data/lib/origami/name.rb CHANGED
@@ -128,6 +128,8 @@ module Origami
128
128
  def self.contract(name) #:nodoc:
129
129
 
130
130
  i = 0
131
+ name = name.dup
132
+
131
133
  while i < name.length
132
134
 
133
135
  if name[i,1] == "#"
@@ -156,11 +158,9 @@ module Origami
156
158
 
157
159
  forbiddenchars = /[ #\t\r\n\0\[\]<>()%\/]/
158
160
 
159
- name.gsub!(forbiddenchars) do |c|
161
+ name.gsub(forbiddenchars) do |c|
160
162
  "#" + c[0].ord.to_s(16).rjust(2,"0")
161
163
  end
162
-
163
- name
164
164
  end
165
165
 
166
166
  def real_type ; Name end
data/lib/origami/page.rb CHANGED
@@ -423,6 +423,16 @@ module Origami
423
423
  end
424
424
  end
425
425
 
426
+ #
427
+ # Returns the array of Annotation objects of the Page.
428
+ #
429
+ def annotations
430
+ annots = self.Annots
431
+ return [] unless annots.is_a?(Array)
432
+
433
+ annots.map{|annot| annot.solve}
434
+ end
435
+
426
436
  #
427
437
  # Embed a SWF Flash application in the page.
428
438
  #
data/lib/origami/pdf.rb CHANGED
@@ -61,8 +61,8 @@ require 'origami/parsers/pdf'
61
61
 
62
62
  module Origami
63
63
 
64
- VERSION = "1.2.2"
65
- REVISION = "$Revision: rev 135/, 2011/10/17 11:59:41 $" #:nodoc:
64
+ VERSION = "1.2.3"
65
+ REVISION = "$Revision: rev 143/, 2011/10/20 16:22:40 $" #:nodoc:
66
66
 
67
67
  #
68
68
  # Global options for Origami.
@@ -264,13 +264,6 @@ module Origami
264
264
  self
265
265
  end
266
266
 
267
- #
268
- # Returns the virtual file size as it would be taking on disk.
269
- #
270
- def filesize
271
- self.to_bin(:rebuildxrefs => false).size
272
- end
273
-
274
267
  #
275
268
  # Saves the current document.
276
269
  # _filename_:: The path where to save this PDF.
@@ -301,9 +294,9 @@ module Origami
301
294
 
302
295
  intents_as_pdfa1 if options[:intent] =~ /pdf[\/-]?A1?/i
303
296
  self.delinearize! if options[:delinearize] and self.is_linearized?
304
- self.compile(options) if options[:recompile]
297
+ compile(options) if options[:recompile]
305
298
 
306
- fd.write self.to_bin(options)
299
+ fd.write output(options)
307
300
  fd.close
308
301
 
309
302
  self
@@ -541,6 +534,130 @@ module Origami
541
534
  object.reference
542
535
  end
543
536
 
537
+ #
538
+ # Ends the current Revision, and starts a new one.
539
+ #
540
+ def add_new_revision
541
+
542
+ root = @revisions.last.trailer[:Root] unless @revisions.empty?
543
+
544
+ @revisions << Revision.new(self)
545
+ @revisions.last.trailer = Trailer.new
546
+ @revisions.last.trailer.Root = root
547
+
548
+ self
549
+ end
550
+
551
+ #
552
+ # Removes a whole document revision.
553
+ # _index_:: Revision index, first is 0.
554
+ #
555
+ def remove_revision(index)
556
+ if index < 0 or index > @revisions.size
557
+ raise IndexError, "Not a valid revision index"
558
+ end
559
+
560
+ if @revisions.size == 1
561
+ raise InvalidPDFError, "Cannot remove last revision"
562
+ end
563
+
564
+ @revisions.delete_at(index)
565
+ self
566
+ end
567
+
568
+ #
569
+ # Looking for an object present at a specified file offset.
570
+ #
571
+ def get_object_by_offset(offset) #:nodoc:
572
+ self.indirect_objects.find { |obj| obj.file_offset == offset }
573
+ end
574
+
575
+ #
576
+ # Remove an object.
577
+ #
578
+ def delete_object(no, generation = 0)
579
+
580
+ case no
581
+ when Reference
582
+ target = no
583
+ when ::Integer
584
+ target = Reference.new(no, generation)
585
+ else
586
+ raise TypeError, "Invalid parameter type : #{no.class}"
587
+ end
588
+
589
+ @revisions.each do |rev|
590
+ rev.body.delete(target)
591
+ end
592
+
593
+ end
594
+
595
+ #
596
+ # Search for an indirect object in the document.
597
+ # _no_:: Reference or number of the object.
598
+ # _generation_:: Object generation.
599
+ #
600
+ def get_object(no, generation = 0, use_xrefstm = true) #:nodoc:
601
+ case no
602
+ when Reference
603
+ target = no
604
+ when ::Integer
605
+ target = Reference.new(no, generation)
606
+ when Origami::Object
607
+ return no
608
+ else
609
+ raise TypeError, "Invalid parameter type : #{no.class}"
610
+ end
611
+
612
+ set = indirect_objects_table
613
+
614
+ #
615
+ # Search through accessible indirect objects.
616
+ #
617
+ if set.include?(target)
618
+ set[target]
619
+ elsif use_xrefstm == true
620
+ # Look into XRef streams.
621
+
622
+ if @revisions.last.has_xrefstm?
623
+ xrefstm = @revisions.last.xrefstm
624
+
625
+ done = []
626
+ while xrefstm.is_a?(XRefStream) and not done.include?(xrefstm)
627
+ xref = xrefstm.find(target.refno)
628
+
629
+ #
630
+ # We found a matching XRef.
631
+ #
632
+ if xref.is_a?(XRefToCompressedObj)
633
+ objstm = get_object(xref.objstmno, 0, false)
634
+
635
+ object = objstm.extract_by_index(xref.index)
636
+ if object.is_a?(Origami::Object) and object.no == target.refno
637
+ return object
638
+ else
639
+ return objstm.extract(target.refno)
640
+ end
641
+ elsif xrefstm.has_field?(:Prev)
642
+ done << xrefstm
643
+ xrefstm = get_object_by_offset(xrefstm.Prev)
644
+ else
645
+ break
646
+ end
647
+ end
648
+ end
649
+
650
+ #
651
+ # Lastly search directly into Object streams (might be very slow).
652
+ #
653
+ stream = set.values.find_all{|obj| obj.is_a?(ObjectStream)}.find do |objstm| objstm.include?(target.refno) end
654
+ stream && stream.extract(target.refno)
655
+ end
656
+
657
+ end
658
+
659
+ alias :[] :get_object
660
+
544
661
  #
545
662
  # Returns a new number/generation for future object.
546
663
  #
@@ -561,6 +678,37 @@ module Origami
561
678
  [ no, 0 ]
562
679
  end
563
680
 
681
+ ##########################
682
+ private
683
+ ##########################
684
+
685
+ #
686
+ # Compute and update XRef::Section for each Revision.
687
+ #
688
+ def rebuildxrefs
689
+
690
+ size = 0
691
+ startxref = @header.to_s.size
692
+
693
+ @revisions.each do |revision|
694
+
695
+ revision.objects.each do |object|
696
+ startxref += object.to_s.size
697
+ end
698
+
699
+ size += revision.body.size
700
+ revision.xreftable = buildxrefs(revision.objects)
701
+
702
+ revision.trailer ||= Trailer.new
703
+ revision.trailer.Size = size + 1
704
+ revision.trailer.startxref = startxref
705
+
706
+ startxref += revision.xreftable.to_s.size + revision.trailer.to_s.size
707
+ end
708
+
709
+ self
710
+ end
711
+
564
712
  #
565
713
  # This method is meant to recompute, verify and correct main PDF structures, in order to output a proper file.
566
714
  # * Allocates objects references.
@@ -596,90 +744,192 @@ module Origami
596
744
  end
597
745
 
598
746
  #
599
- # Returns the final binary representation of the current document.
600
- # _rebuildxrefs_:: Computes xrefs while writing objects (default true).
601
- # _obfuscate_:: Do some basic syntactic object obfuscation.
747
+ # Cleans the document from its references.
748
+ # Indirects objects are made direct whenever possible.
749
+ # TODO: Circuit-checking to avoid infinite induction
602
750
  #
603
- def to_bin(params = {})
604
-
605
- has_objstm = self.indirect_objects.any?{|obj| obj.is_a?(ObjectStream)}
606
-
607
- options =
608
- {
609
- :rebuildxrefs => true,
610
- :noindent => false,
611
- :obfuscate => false,
612
- :use_xrefstm => has_objstm,
613
- :use_xreftable => (not has_objstm),
614
- :up_to_revision => @revisions.size
615
- }
616
- options.update(params)
617
-
618
- options[:up_to_revision] = @revisions.size if options[:up_to_revision] > @revisions.size
751
+ def logicalize #:nodoc:
619
752
 
620
- # Reset to default params if no xrefs are chosen (hybrid files not supported yet)
621
- if options[:use_xrefstm] == options[:use_xreftable]
622
- options[:use_xrefstm] = has_objstm
623
- options[:use_xreftable] = (not has_objstm)
624
- end
753
+ fail "Not yet supported"
625
754
 
626
- # Get trailer dictionary
627
- trailer_info = get_trailer_info
628
- if trailer_info.nil?
629
- raise InvalidPDFError, "No trailer information found"
630
- end
631
- trailer_dict = trailer_info.dictionary
632
-
633
- prev_xref_offset = nil
634
- xrefstm_offset = nil
635
- xreftable_offset = nil
636
-
637
- # Header
638
- bin = ""
639
- bin << @header.to_s
755
+ processed = []
640
756
 
641
- # For each revision
642
- @revisions[0, options[:up_to_revision]].each do |rev|
643
-
644
- # Create xref table/stream.
645
- if options[:rebuildxrefs] == true
646
- lastno_table, lastno_stm = 0, 0
647
- brange_table, brange_stm = 0, 0
648
-
649
- xrefs_stm = [ XRef.new(0, 0, XRef::FREE) ]
650
- xrefs_table = [ XRef.new(0, XRef::FIRSTFREE, XRef::FREE) ]
757
+ def convert(root) #:nodoc:
651
758
 
652
- if options[:use_xreftable] == true
653
- xrefsection = XRef::Section.new
654
- end
759
+ replaced = []
760
+ if root.is_a?(Dictionary) or root.is_a?(Array)
761
+
762
+ root.each { |obj|
763
+ convert(obj)
764
+ }
655
765
 
656
- if options[:use_xrefstm] == true
657
- xrefstm = rev.xrefstm || XRefStream.new
658
- if xrefstm == rev.xrefstm
659
- xrefstm.clear
766
+ root.map! { |obj|
767
+ if obj.is_a?(Reference)
768
+ target = obj.solve
769
+ # Streams can't be direct objects
770
+ if target.is_a?(Stream)
771
+ obj
772
+ else
773
+ replaced << obj
774
+ target
775
+ end
660
776
  else
661
- add_to_revision(xrefstm, rev)
777
+ obj
662
778
  end
663
- end
779
+ }
780
+
664
781
  end
665
-
666
- objset = rev.objects
667
-
668
- objset.find_all{|obj| obj.is_a?(ObjectStream)}.each do |objstm|
669
- objset |= objstm.objects
670
- end if options[:rebuildxrefs] == true and options[:use_xrefstm] == true
671
782
 
672
- # For each object, in number order
673
- objset.sort.each do |obj|
674
-
675
- # Create xref entry.
676
- if options[:rebuildxrefs] == true
677
-
678
- # Adding subsections if needed
679
- if options[:use_xreftable] and (obj.no - lastno_table).abs > 1
680
- xrefsection << XRef::Subsection.new(brange_table, xrefs_table)
783
+ replaced
784
+ end
681
785
 
682
- xrefs_table.clear
786
+ @revisions.each do |revision|
787
+ revision.objects.each do |obj|
788
+ processed.concat(convert(obj))
789
+ end
790
+ end
791
+
792
+ end
793
+
794
+ #
795
+ # Converts a logical PDF view into a physical view ready for writing.
796
+ #
797
+ def physicalize
798
+
799
+ #
800
+ # Indirect objects are added to the revision and assigned numbers.
801
+ #
802
+ def build(obj, revision) #:nodoc:
803
+
804
+ #
805
+ # Finalize any subobjects before building the stream.
806
+ #
807
+ if obj.is_a?(ObjectStream)
808
+ obj.each do |subobj|
809
+ build(subobj, revision)
810
+ end
811
+ end
812
+
813
+ obj.pre_build
814
+
815
+ if obj.is_a?(Dictionary) or obj.is_a?(Array)
816
+
817
+ obj.map! do |subobj|
818
+ if subobj.is_indirect?
819
+ if get_object(subobj.reference)
820
+ subobj.reference
821
+ else
822
+ ref = add_to_revision(subobj, revision)
823
+ build(subobj, revision)
824
+ ref
825
+ end
826
+ else
827
+ subobj
828
+ end
829
+ end
830
+
831
+ obj.each do |subobj|
832
+ build(subobj, revision)
833
+ end
834
+
835
+ elsif obj.is_a?(Stream)
836
+ build(obj.dictionary, revision)
837
+ end
838
+
839
+ obj.post_build
840
+
841
+ end
842
+
843
+ indirect_objects_by_rev.each do |obj, revision|
844
+ build(obj, revision)
845
+ end
846
+
847
+ self
848
+ end
849
+
850
+ #
851
+ # Returns the final binary representation of the current document.
852
+ #
853
+ def output(params = {})
854
+
855
+ has_objstm = self.indirect_objects.any?{|obj| obj.is_a?(ObjectStream)}
856
+
857
+ options =
858
+ {
859
+ :rebuildxrefs => true,
860
+ :noindent => false,
861
+ :obfuscate => false,
862
+ :use_xrefstm => has_objstm,
863
+ :use_xreftable => (not has_objstm),
864
+ :up_to_revision => @revisions.size
865
+ }
866
+ options.update(params)
867
+
868
+ options[:up_to_revision] = @revisions.size if options[:up_to_revision] > @revisions.size
869
+
870
+ # Reset to default params if no xrefs are chosen (hybrid files not supported yet)
871
+ if options[:use_xrefstm] == options[:use_xreftable]
872
+ options[:use_xrefstm] = has_objstm
873
+ options[:use_xreftable] = (not has_objstm)
874
+ end
875
+
876
+ # Get trailer dictionary
877
+ trailer_info = get_trailer_info
878
+ if trailer_info.nil?
879
+ raise InvalidPDFError, "No trailer information found"
880
+ end
881
+ trailer_dict = trailer_info.dictionary
882
+
883
+ prev_xref_offset = nil
884
+ xrefstm_offset = nil
885
+ xreftable_offset = nil
886
+
887
+ # Header
888
+ bin = ""
889
+ bin << @header.to_s
890
+
891
+ # For each revision
892
+ @revisions[0, options[:up_to_revision]].each do |rev|
893
+
894
+ # Create xref table/stream.
895
+ if options[:rebuildxrefs] == true
896
+ lastno_table, lastno_stm = 0, 0
897
+ brange_table, brange_stm = 0, 0
898
+
899
+ xrefs_stm = [ XRef.new(0, 0, XRef::FREE) ]
900
+ xrefs_table = [ XRef.new(0, XRef::FIRSTFREE, XRef::FREE) ]
901
+
902
+ if options[:use_xreftable] == true
903
+ xrefsection = XRef::Section.new
904
+ end
905
+
906
+ if options[:use_xrefstm] == true
907
+ xrefstm = rev.xrefstm || XRefStream.new
908
+ if xrefstm == rev.xrefstm
909
+ xrefstm.clear
910
+ else
911
+ add_to_revision(xrefstm, rev)
912
+ end
913
+ end
914
+ end
915
+
916
+ objset = rev.objects
917
+
918
+ objset.find_all{|obj| obj.is_a?(ObjectStream)}.each do |objstm|
919
+ objset.concat objstm.objects
920
+ end if options[:rebuildxrefs] == true and options[:use_xrefstm] == true
921
+
922
+ # For each object, in number order
923
+ objset.sort.each do |obj|
924
+
925
+ # Create xref entry.
926
+ if options[:rebuildxrefs] == true
927
+
928
+ # Adding subsections if needed
929
+ if options[:use_xreftable] and (obj.no - lastno_table).abs > 1
930
+ xrefsection << XRef::Subsection.new(brange_table, xrefs_table)
931
+
932
+ xrefs_table.clear
683
933
  brange_table = obj.no
684
934
  end
685
935
  if options[:use_xrefstm] and (obj.no - lastno_stm).abs > 1
@@ -774,265 +1024,6 @@ module Origami
774
1024
  bin
775
1025
  end
776
1026
 
777
- #
778
- # Compute and update XRef::Section for each Revision.
779
- #
780
- def rebuildxrefs
781
-
782
- size = 0
783
- startxref = @header.to_s.size
784
-
785
- @revisions.each do |revision|
786
-
787
- revision.objects.each do |object|
788
- startxref += object.to_s.size
789
- end
790
-
791
- size += revision.body.size
792
- revision.xreftable = buildxrefs(revision.objects)
793
-
794
- revision.trailer ||= Trailer.new
795
- revision.trailer.Size = size + 1
796
- revision.trailer.startxref = startxref
797
-
798
- startxref += revision.xreftable.to_s.size + revision.trailer.to_s.size
799
- end
800
-
801
- self
802
- end
803
-
804
- #
805
- # Ends the current Revision, and starts a new one.
806
- #
807
- def add_new_revision
808
-
809
- root = @revisions.last.trailer[:Root] unless @revisions.empty?
810
-
811
- @revisions << Revision.new(self)
812
- @revisions.last.trailer = Trailer.new
813
- @revisions.last.trailer.Root = root
814
-
815
- self
816
- end
817
-
818
- #
819
- # Removes a whole document revision.
820
- # _index_:: Revision index, first is 0.
821
- #
822
- def remove_revision(index)
823
- if index < 0 or index > @revisions.size
824
- raise IndexError, "Not a valid revision index"
825
- end
826
-
827
- if @revisions.size == 1
828
- raise InvalidPDFError, "Cannot remove last revision"
829
- end
830
-
831
- @revisions.delete_at(index)
832
- self
833
- end
834
-
835
- #
836
- # Looking for an object present at a specified file offset.
837
- #
838
- def get_object_by_offset(offset) #:nodoc:
839
- self.indirect_objects.find { |obj| obj.file_offset == offset }
840
- end
841
-
842
- #
843
- # Remove an object.
844
- #
845
- def delete_object(no, generation = 0)
846
-
847
- case no
848
- when Reference
849
- target = no
850
- when ::Integer
851
- target = Reference.new(no, generation)
852
- else
853
- raise TypeError, "Invalid parameter type : #{no.class}"
854
- end
855
-
856
- @revisions.each do |rev|
857
- rev.body.delete(target)
858
- end
859
-
860
- end
861
-
862
- #
863
- # Search for an indirect object in the document.
864
- # _no_:: Reference or number of the object.
865
- # _generation_:: Object generation.
866
- #
867
- def get_object(no, generation = 0, use_xrefstm = true) #:nodoc:
868
- case no
869
- when Reference
870
- target = no
871
- when ::Integer
872
- target = Reference.new(no, generation)
873
- when Origami::Object
874
- return no
875
- else
876
- raise TypeError, "Invalid parameter type : #{no.class}"
877
- end
878
-
879
- set = indirect_objects_table
880
-
881
- #
882
- # Search through accessible indirect objects.
883
- #
884
- if set.include?(target)
885
- set[target]
886
- elsif use_xrefstm == true
887
- # Look into XRef streams.
888
-
889
- if @revisions.last.has_xrefstm?
890
- xrefstm = @revisions.last.xrefstm
891
-
892
- done = []
893
- while xrefstm.is_a?(XRefStream) and not done.include?(xrefstm)
894
- xref = xrefstm.find(target.refno)
895
-
896
- #
897
- # We found a matching XRef.
898
- #
899
- if xref.is_a?(XRefToCompressedObj)
900
- objstm = get_object(xref.objstmno, 0, false)
901
-
902
- object = objstm.extract_by_index(xref.index)
903
- if object.is_a?(Origami::Object) and object.no == target.refno
904
- return object
905
- else
906
- return objstm.extract(target.refno)
907
- end
908
- elsif xrefstm.has_field?(:Prev)
909
- done << xrefstm
910
- xrefstm = get_object_by_offset(xrefstm.Prev)
911
- else
912
- break
913
- end
914
- end
915
- end
916
-
917
- #
918
- # Lastly search directly into Object streams (might be very slow).
919
- #
920
- stream = set.values.find_all{|obj| obj.is_a?(ObjectStream)}.find do |objstm| objstm.include?(target.refno) end
921
- stream && stream.extract(target.refno)
922
- end
923
-
924
- end
925
-
926
- alias :[] :get_object
927
-
928
- #
929
- # Converts a logical PDF view into a physical view ready for writing.
930
- #
931
- def physicalize
932
-
933
- #
934
- # Indirect objects are added to the revision and assigned numbers.
935
- #
936
- def build(obj, revision) #:nodoc:
937
-
938
- #
939
- # Finalize any subobjects before building the stream.
940
- #
941
- if obj.is_a?(ObjectStream)
942
- obj.each do |subobj|
943
- build(subobj, revision)
944
- end
945
- end
946
-
947
- obj.pre_build
948
-
949
- if obj.is_a?(Dictionary) or obj.is_a?(Array)
950
-
951
- obj.map! do |subobj|
952
- if subobj.is_indirect?
953
- if get_object(subobj.reference)
954
- subobj.reference
955
- else
956
- ref = add_to_revision(subobj, revision)
957
- build(subobj, revision)
958
- ref
959
- end
960
- else
961
- subobj
962
- end
963
- end
964
-
965
- obj.each do |subobj|
966
- build(subobj, revision)
967
- end
968
-
969
- elsif obj.is_a?(Stream)
970
- build(obj.dictionary, revision)
971
- end
972
-
973
- obj.post_build
974
-
975
- end
976
-
977
- indirect_objects_by_rev.each do |obj, revision|
978
- build(obj, revision)
979
- end
980
-
981
- self
982
- end
983
-
984
- #
985
- # Cleans the document from its references.
986
- # Indirects objects are made direct whenever possible.
987
- # TODO: Circuit-checking to avoid infinite induction
988
- #
989
- def logicalize #:nodoc:
990
-
991
- fail "Not yet supported"
992
-
993
- processed = []
994
-
995
- def convert(root) #:nodoc:
996
-
997
- replaced = []
998
- if root.is_a?(Dictionary) or root.is_a?(Array)
999
-
1000
- root.each { |obj|
1001
- convert(obj)
1002
- }
1003
-
1004
- root.map! { |obj|
1005
- if obj.is_a?(Reference)
1006
- target = obj.solve
1007
- # Streams can't be direct objects
1008
- if target.is_a?(Stream)
1009
- obj
1010
- else
1011
- replaced << obj
1012
- target
1013
- end
1014
- else
1015
- obj
1016
- end
1017
- }
1018
-
1019
- end
1020
-
1021
- replaced
1022
- end
1023
-
1024
- @revisions.each do |revision|
1025
- revision.objects.each do |obj|
1026
- processed.concat(convert(obj))
1027
- end
1028
- end
1029
-
1030
- end
1031
-
1032
- ##########################
1033
- private
1034
- ##########################
1035
-
1036
1027
  #
1037
1028
  # Instanciates basic structures required for a valid PDF file.
1038
1029
  #
@@ -1044,6 +1035,10 @@ module Origami
1044
1035
  self
1045
1036
  end
1046
1037
 
1038
+ def filesize #:nodoc:
1039
+ output(:rebuildxrefs => false).size
1040
+ end
1041
+
1047
1042
  def version_required #:nodoc:
1048
1043
 
1049
1044
  max = [ 1.0, 0 ]
@@ -196,7 +196,7 @@ module Origami
196
196
  #
197
197
  # Flattening the PDF to get file view.
198
198
  #
199
- self.compile
199
+ compile
200
200
 
201
201
  #
202
202
  # Creating an empty Xref table to compute signature byte range.
@@ -218,7 +218,7 @@ module Origami
218
218
  #
219
219
  rebuildxrefs
220
220
 
221
- filedata = self.to_bin
221
+ filedata = output()
222
222
  signable_data = filedata[digsig.ByteRange[0],digsig.ByteRange[1]] + filedata[digsig.ByteRange[2],digsig.ByteRange[3]]
223
223
 
224
224
  signature =
@@ -321,7 +321,7 @@ module Origami
321
321
  #
322
322
  # Flattening the PDF to get file view.
323
323
  #
324
- self.compile
324
+ compile
325
325
 
326
326
  #
327
327
  # Creating an empty Xref table to compute signature byte range.
@@ -343,7 +343,7 @@ module Origami
343
343
  #
344
344
  rebuildxrefs
345
345
 
346
- filedata = self.to_bin
346
+ filedata = output()
347
347
  signable_data = filedata[digsig.ByteRange[0],digsig.ByteRange[1]] + filedata[digsig.ByteRange[2],digsig.ByteRange[3]]
348
348
 
349
349
  signature = OpenSSL::PKCS7.sign(certificate, key, signable_data, [], OpenSSL::PKCS7::DETACHED | OpenSSL::PKCS7::BINARY).to_der
@@ -336,6 +336,15 @@ module Origami
336
336
  @xrefs = nil
337
337
  end
338
338
 
339
+ def entries
340
+ load! if @xrefs.nil?
341
+
342
+ @xrefs
343
+ end
344
+
345
+ #
346
+ # Returns XRef entries present in this stream.
347
+ #
339
348
  def pre_build #:nodoc:
340
349
  load! if @xrefs.nil?
341
350
 
@@ -386,7 +395,7 @@ module Origami
386
395
  end
387
396
 
388
397
  def clear
389
- @rawdata, @data = nil, ''
398
+ self.data = ''
390
399
  @xrefs = []
391
400
  self.Index = []
392
401
  end
@@ -410,11 +419,11 @@ module Origami
410
419
  entrymask = "B#{type_w << 3}B#{field1_w << 3}B#{field2_w << 3}"
411
420
  size = @data.size / (type_w + field1_w + field2_w)
412
421
 
413
- entries = @data.unpack(entrymask * size).map!{|field| field.to_i(2) }
422
+ xentries = @data.unpack(entrymask * size).map!{|field| field.to_i(2) }
414
423
 
415
424
  @xrefs = []
416
425
  size.times do |i|
417
- type,field1,field2 = entries[i*3],entries[i*3+1],entries[i*3+2]
426
+ type,field1,field2 = xentries[i*3].ord,xentries[i*3+1].ord,xentries[i*3+2].ord
418
427
  case type
419
428
  when XREF_FREE
420
429
  @xrefs << XRef.new(field1, field2, XRef::FREE)
@@ -430,7 +439,7 @@ module Origami
430
439
  end
431
440
 
432
441
  def save! #:nodoc:
433
- @data = ""
442
+ self.data = ""
434
443
 
435
444
  type_w, field1_w, field2_w = self.W
436
445
  @xrefs.each do |xref| @data << xref.to_xrefstm_data(type_w, field1_w, field2_w) end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: origami
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
4
+ hash: 25
5
5
  prerelease: false
6
6
  segments:
7
7
  - 1
8
8
  - 2
9
- - 2
10
- version: 1.2.2
9
+ - 3
10
+ version: 1.2.3
11
11
  platform: ruby
12
12
  authors:
13
13
  - "Guillaume Delugr\xC3\xA9"
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-10-18 00:00:00 +02:00
18
+ date: 2011-10-20 00:00:00 +02:00
19
19
  default_executable:
20
20
  dependencies: []
21
21
 
@@ -51,20 +51,18 @@ files:
51
51
  - lib/origami/boolean.rb
52
52
  - lib/origami/catalog.rb
53
53
  - lib/origami/destinations.rb
54
- - lib/origami/dictionary.rb
55
54
  - lib/origami/export.rb
56
- - lib/origami/file.rb
57
55
  - lib/origami/filters.rb
58
56
  - lib/origami/filters/ascii.rb
59
57
  - lib/origami/filters/crypt.rb
60
58
  - lib/origami/filters/dct.rb
61
59
  - lib/origami/filters/flate.rb
62
- - lib/origami/filters/jbig2.rb
63
- - lib/origami/filters/jpx.rb
64
60
  - lib/origami/filters/lzw.rb
65
61
  - lib/origami/filters/predictors.rb
66
62
  - lib/origami/filters/runlength.rb
67
63
  - lib/origami/filters/ccitt.rb
64
+ - lib/origami/filters/jpx.rb
65
+ - lib/origami/filters/jbig2.rb
68
66
  - lib/origami/font.rb
69
67
  - lib/origami/functions.rb
70
68
  - lib/origami/graphics.rb
@@ -77,16 +75,13 @@ files:
77
75
  - lib/origami/graphics/colors.rb
78
76
  - lib/origami/graphics/xobject.rb
79
77
  - lib/origami/header.rb
80
- - lib/origami/javascript.rb
81
78
  - lib/origami/linearization.rb
82
79
  - lib/origami/metadata.rb
83
- - lib/origami/name.rb
84
80
  - lib/origami/null.rb
85
81
  - lib/origami/numeric.rb
86
82
  - lib/origami/obfuscation.rb
87
83
  - lib/origami/outline.rb
88
84
  - lib/origami/outputintents.rb
89
- - lib/origami/page.rb
90
85
  - lib/origami/parsers/pdf/linear.rb
91
86
  - lib/origami/parsers/pdf.rb
92
87
  - lib/origami/parsers/fdf.rb
@@ -101,12 +96,17 @@ files:
101
96
  - lib/origami/object.rb
102
97
  - lib/origami/extensions/fdf.rb
103
98
  - lib/origami/extensions/ppklite.rb
104
- - lib/origami/xreftable.rb
105
99
  - lib/origami/parser.rb
106
- - lib/origami/encryption.rb
100
+ - lib/origami/javascript.rb
107
101
  - lib/origami/signature.rb
108
- - lib/origami/pdf.rb
102
+ - lib/origami/xreftable.rb
103
+ - lib/origami/page.rb
109
104
  - lib/origami/acroform.rb
105
+ - lib/origami/name.rb
106
+ - lib/origami/encryption.rb
107
+ - lib/origami/dictionary.rb
108
+ - lib/origami/pdf.rb
109
+ - lib/origami/file.rb
110
110
  - lib/origami.rb
111
111
  - bin/config/pdfcop.conf.yml
112
112
  - bin/gui/about.rb