Class: Fontisan::Collection::DfontBuilder

Inherits:
Object
  • Object
show all
Defined in:
lib/fontisan/collection/dfont_builder.rb

Overview

DfontBuilder creates Apple dfont (Data Fork Font) resource fork structures

Main responsibility: Build complete dfont binary from multiple fonts by creating a resource fork structure containing ‘sfnt’ resources.

dfont is an Apple-specific format that stores Mac font suitcase resources in the data fork instead of the resource fork. It can contain multiple fonts.

Examples:

Build dfont from multiple fonts

builder = DfontBuilder.new([font1, font2, font3])
binary = builder.build

Write directly to file

builder = DfontBuilder.new([font1, font2])
builder.build_to_file("family.dfont")

Constant Summary collapse

NO_NAME_OFFSET =

Constants for resource reference packing

[-1].freeze
ZERO_ATTRIBUTES =
[0].freeze
ZERO_RESERVED =
[0].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(fonts, options = {}) ⇒ DfontBuilder

Initialize builder with fonts

Parameters:

  • fonts (Array<TrueTypeFont, OpenTypeFont>)

    Fonts to pack into dfont

  • options (Hash) (defaults to: {})

    Builder options

Raises:

  • (ArgumentError)

    if fonts array is invalid



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/fontisan/collection/dfont_builder.rb', line 43

def initialize(fonts, options = {})
  if fonts.nil? || fonts.empty?
    raise ArgumentError, "fonts cannot be nil or empty"
  end
  raise ArgumentError, "fonts must be an array" unless fonts.is_a?(Array)

  unless fonts.all? { |f| f.respond_to?(:table_data) }
    raise ArgumentError, "all fonts must respond to table_data"
  end

  @fonts = fonts
  @options = options
  @result = nil

  validate_fonts!
end

Instance Attribute Details

#fontsArray<TrueTypeFont, OpenTypeFont> (readonly)

Source fonts

Returns:



27
28
29
# File 'lib/fontisan/collection/dfont_builder.rb', line 27

def fonts
  @fonts
end

#resultHash? (readonly)

Build result (populated after build)

Returns:

  • (Hash, nil)


31
32
33
# File 'lib/fontisan/collection/dfont_builder.rb', line 31

def result
  @result
end

Instance Method Details

#buildHash

Build dfont and return binary

Executes the complete dfont creation process:

  1. Serialize each font to SFNT binary

  2. Build resource data section

  3. Calculate resource map size

  4. Build resource map

  5. Build resource fork header

  6. Assemble complete dfont binary

Returns:

  • (Hash)

    Build result with:

    • :binary [String] - Complete dfont binary

    • :num_fonts [Integer] - Number of fonts packed

    • :total_size [Integer] - Total size in bytes



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
# File 'lib/fontisan/collection/dfont_builder.rb', line 74

def build
  # Step 1: Serialize all fonts to SFNT binaries
  sfnt_binaries = serialize_fonts

  # Step 2: Build resource data section
  resource_data = build_resource_data(sfnt_binaries)

  # Step 3: Calculate expected resource map size
  # Map header: 28 bytes
  # Type list header: 2 bytes
  # Type entry: 8 bytes
  # References: 12 bytes each
  map_size = 28 + 2 + 8 + (sfnt_binaries.size * 12)

  # Step 4: Build resource map
  resource_map = build_resource_map(sfnt_binaries,
                                    resource_data.bytesize, map_size)

  # Step 5: Build header
  header = build_header(resource_data.bytesize, resource_map.bytesize)

  # Step 6: Assemble complete dfont binary
  binary = header + resource_data + resource_map

  # Store result
  @result = {
    binary: binary,
    num_fonts: @fonts.size,
    total_size: binary.bytesize,
    format: :dfont,
  }

  @result
end

#build_to_file(path) ⇒ Hash

Build dfont and write to file

Parameters:

  • path (String)

    Output file path

Returns:

  • (Hash)

    Build result (same as build method)



113
114
115
116
117
118
# File 'lib/fontisan/collection/dfont_builder.rb', line 113

def build_to_file(path)
  result = build
  File.binwrite(path, result[:binary])
  result[:output_path] = path
  result
end