origami 1.2.2 → 1.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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