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



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/fontisan/collection/dfont_builder.rb', line 39

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:



23
24
25
# File 'lib/fontisan/collection/dfont_builder.rb', line 23

def fonts
  @fonts
end

#resultHash? (readonly)

Build result (populated after build)

Returns:

  • (Hash, nil)


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

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


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

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)



109
110
111
112
113
114
# File 'lib/fontisan/collection/dfont_builder.rb', line 109

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