Class: Prawn::Fonts::ToUnicodeCMap
- Inherits:
-
Object
- Object
- Prawn::Fonts::ToUnicodeCMap
- Defined in:
- lib/prawn/fonts/to_unicode_cmap.rb
Overview
This class generates ToUnicode CMap for embedde TrueType/OpenType fonts. It’s a separate format and is somewhat complicated so it has its own place.
Instance Method Summary collapse
-
#generate ⇒ String
Generate CMap.
-
#initialize(mapping, code_space_size = nil) ⇒ ToUnicodeCMap
constructor
mapping is expected to be a hash with keys being character codes (in broad sense, as used in the showing operation strings) and values being Unicode code points.
Constructor Details
#initialize(mapping, code_space_size = nil) ⇒ ToUnicodeCMap
mapping is expected to be a hash with keys being character codes (in broad sense, as used in the showing operation strings) and values being Unicode code points.
14 15 16 17 |
# File 'lib/prawn/fonts/to_unicode_cmap.rb', line 14 def initialize(mapping, code_space_size = nil) @mapping = mapping @code_space_size = code_space_size end |
Instance Method Details
#generate ⇒ String
Generate CMap.
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/prawn/fonts/to_unicode_cmap.rb', line 22 def generate chunks = [] # Header chunks << <<~HEADER.chomp /CIDInit /ProcSet findresource begin 12 dict begin begincmap /CIDSystemInfo 3 dict dup begin /Registry (Adobe) def /Ordering (UCS) def /Supplement 0 def end def /CMapName /Adobe-Identity-UCS def /CMapType 2 def HEADER max_glyph_index = mapping.keys.max # Range code_space_size = (max_glyph_index.bit_length / 8.0).ceil used_code_space_size = @code_space_size || code_space_size # In CMap codespaces are not sequentional, they're ranges in # a multi-dimentional space. Each byte is considered separately. So we # have to maximally extend the lower bytes in order to allow for # continuos mapping. # We only keep the highest byte because usually it's lower than # maximally allowed and we don't want to cover that unused space. code_space_max = max_glyph_index | ('ff' * (code_space_size - 1)).to_i(16) chunks << '1 begincodespacerange' chunks << format("<%0#{used_code_space_size * 2}X><%0#{used_code_space_size * 2}X>", 0, code_space_max) chunks << 'endcodespacerange' # Mapping all_spans = mapping_spans(mapping.reject { |gid, cid| gid.zero? || (0xd800..0xdfff).cover?(cid) }) short_spans, long_spans = all_spans.partition { |span| span[0] == :short } long_spans .each_slice(100) do |spans| chunks << "#{spans.length} beginbfrange" spans.each do |type, span| # rubocop: disable Lint/FormatParameterMismatch # false positive case type when :fully_sorted chunks << format( "<%0#{code_space_size * 2}X><%0#{code_space_size * 2}X><%s>", span.first[0], span.last[0], span.first[1].chr(::Encoding::UTF_16BE).unpack1('H*'), ) when :index_sorted chunks << format( "<%0#{code_space_size * 2}X><%0#{code_space_size * 2}X>[%s]", span.first[0], span.last[0], span.map { |_, cid| "<#{cid.chr(::Encoding::UTF_16BE).unpack1('H*')}>" }.join(''), ) end # rubocop: enable Lint/FormatParameterMismatch end chunks << 'endbfrange' end short_spans .map { |_type, slice| slice.flatten(1) } .each_slice(100) do |mapping| chunks << "#{mapping.length} beginbfchar" chunks.concat( mapping.map { |(gid, cid)| # rubocop: disable Lint/FormatParameterMismatch # false positive format( "<%0#{code_space_size * 2}X><%s>", gid, cid.chr(::Encoding::UTF_16BE).unpack1('H*'), ) # rubocop: enable Lint/FormatParameterMismatch }, ) chunks << 'endbfchar' end # Footer chunks << <<~FOOTER.chomp endcmap CMapName currentdict /CMap defineresource pop end end FOOTER chunks.join("\n") end |