Skip to content

Commit

Permalink
Fixed virtual font support and cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
FabriceSalvaire committed Sep 18, 2014
1 parent 719306c commit b021653
Show file tree
Hide file tree
Showing 8 changed files with 131 additions and 104 deletions.
78 changes: 38 additions & 40 deletions PyDvi/Dvi/DviMachine.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,12 +142,17 @@ def append(self, char_code):

def run(self, dvi_machine, compute_bounding_box=False):

registers = dvi_machine.registers
font = dvi_machine.current_font
dvi_font = dvi_machine.current_dvi_font
if font.is_virtual:
# Fixme: bounding_box
for char_code in self.characters:
virtual_character = font._characters[char_code]
dvi_machine.run_subroutine(virtual_character.subroutine)
tfm_char = font.tfm[char_code]
char_width = dvi_font.char_scaled_width(tfm_char)
registers.h += char_width
else:
self._run(dvi_machine, compute_bounding_box)

Expand All @@ -161,16 +166,18 @@ def _run(self, dvi_machine, compute_bounding_box=False):

bounding_box = None
for char_code in self.characters:
try: # Fixme:
if font.tfm is not None:
tfm_char = font.tfm[char_code]

char_width = dvi_font.char_scaled_width(tfm_char)
char_depth = dvi_font.char_scaled_depth(tfm_char)
char_height = dvi_font.char_scaled_height(tfm_char)
except:
char_width = 10
char_depth = 10
char_height = 10
else: # Fixme:
size = dvi_font.magnification * sp2pt(dvi_font.design_size)
glyph = font.get_glyph(char_code, size)
print glyph.advance, glyph.size, glyph.width_px
char_width = glyph.px_to_mm(glyph.width_px)
char_depth = glyph.px_to_mm(glyph.height_px - glyph.horizontal_bearing_y_px)
char_height = glyph.px_to_mm(glyph.horizontal_bearing_y_px)

char_bounding_box = Interval2D([registers.h, registers.h + char_width],
[registers.v - char_height, registers.v + char_depth])
Expand Down Expand Up @@ -637,7 +644,7 @@ def __init__(self, font_id, name, checksum, scale_factor, design_size):
self.name = name
self.checksum = checksum
self.scale_factor = scale_factor
self.design_size = design_size
self.design_size = design_size # pt

self.magnification = fractions.Fraction(scale_factor, design_size)

Expand Down Expand Up @@ -1177,16 +1184,13 @@ def _load_dvi_fonts(self):
self.virtual_fonts[dvi_font.id] = font
font.load_dvi_fonts()

# Fixme: We should merge the fonts
# if font is not in self.fonts
# generate a new font id
# Merge the embedded fonts in the virtual fonts
last_font_id = max([font_id for font_id in self.fonts])
for virtual_font in self.virtual_fonts.itervalues():
for font in virtual_font.fonts.itervalues():
last_font_id += 1
font_id = last_font_id
font.global_id = font_id
self.fonts[font_id] = font
font.global_id = last_font_id
self.fonts[last_font_id] = font
virtual_font.update_font_id_map()
for font_id, dvi_font in virtual_font.dvi_fonts.iteritems():
global_font_id = virtual_font.font_id_map[font_id]
Expand All @@ -1195,20 +1199,9 @@ def _load_dvi_fonts(self):

if self.virtual_fonts:
# Fixme: program_page vs opcode_program
for program_page in self.dvi_program:
self._adjust_opcode_counts_for_virtual_characters(program_page)

# Process the virtual fonts
# for virtual_font in self.virtual_fonts.itervalues():
# print virtual_font
# print virtual_font.fonts
# for character in virtual_font._characters.itervalues():
# print character

# if self.virtual_fonts:
# # Fixme: should be done on demand for long document
# for program_page in self.dvi_program:
# self._merge_virtual_font(program_page)
for program_page in self.dvi_program:
self._adjust_opcode_counts_for_virtual_characters(program_page)
# self._merge_virtual_font(program_page)

##############################################

Expand Down Expand Up @@ -1268,18 +1261,23 @@ def _adjust_opcode_counts_for_virtual_characters(self, opcode_program):
elif isinstance(opcode, Opcode_putset_char) and is_virtual:
virtual_font = self.current_font
opcode_program.number_of_chars[current_font_id] -= 1
for char_code in opcode.characters:
character = virtual_font[char_code]
subroutine = character.subroutine
opcode_program.number_of_rules += subroutine.number_of_rules
for local_font_id, count in subroutine.number_of_chars.iteritems():
if local_font_id is None:
local_font_id = virtual_font.first_font
global_font_id = virtual_font.font_id_map[local_font_id]
if global_font_id in opcode_program.number_of_chars:
opcode_program.number_of_chars[global_font_id] += count
else:
opcode_program.number_of_chars[global_font_id] = count
self._adjust_opcode_counts(opcode_program, virtual_font, opcode.characters)

##############################################

def _adjust_opcode_counts(self, opcode_program, virtual_font, characters):

for char_code in characters:
subroutine = virtual_font[char_code].subroutine
opcode_program.number_of_rules += subroutine.number_of_rules
for local_font_id, count in subroutine.number_of_chars.iteritems():
if local_font_id is None:
local_font_id = virtual_font.first_font
global_font_id = virtual_font.font_id_map[local_font_id]
if global_font_id in opcode_program.number_of_chars:
opcode_program.number_of_chars[global_font_id] += count
else:
opcode_program.number_of_chars[global_font_id] = count

##############################################

Expand Down Expand Up @@ -1315,7 +1313,7 @@ def run_subroutine(self, subroutine):
self._current_font_id = self._virtual_font.font_id_map[self._virtual_font.first_font]
self.push_registers(reset=True) # colour ?

# Fixme: dimension are * design size
# Fixme: dimension are 2**-20 * virtual font design size
for opcode in subroutine:
self._logger.info(opcode)
opcode.run(self)
Expand Down
8 changes: 5 additions & 3 deletions PyDvi/Font/Font.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ def sort_font_class(*args):
class FontNotFound(NameError):
pass

class FontMetricNotFound(NameError):
pass

####################################################################################################

class Font(object):
Expand Down Expand Up @@ -130,9 +133,8 @@ def _find_tfm(self):

tfm_file = kpsewhich(self.name, file_format='tfm')
if tfm_file is None:
# Fixme: look for afm instead
# raise NameError("TFM file %s not found" % (self.name))
self.tfm_file = None
# raise FontMetricNotFound("TFM file was not found for font {}".format(self.name))
self.tfm = None
else:
self.tfm = TfmParser.parse(self.name, tfm_file)

Expand Down
70 changes: 48 additions & 22 deletions PyDvi/Font/Type1Font.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,6 @@
#
####################################################################################################

####################################################################################################
#
# Audit
#
# - 18/12/2011 fabrice
# char code 0 -> 127 + 1 = 128
#
####################################################################################################

####################################################################################################

__all__ = ['Type1Font']
Expand All @@ -42,7 +33,8 @@

####################################################################################################

from .Font import Font, font_types
from ..Kpathsea import kpsewhich
from .Font import Font, font_types, FontMetricNotFound

####################################################################################################

Expand Down Expand Up @@ -83,11 +75,14 @@ def __init__(self, font_manager, font_id, name):
self._face = freetype.Face(self.filename)
except:
raise NameError("Freetype can't open file %s" % (self.filename))

if self.tfm is None:
self._find_afm()

encodings = [charmap.encoding_name for charmap in self._face.charmaps]
if 'FT_ENCODING_ADOBE_CUSTOM' in encodings:
encodings = [charmap.encoding for charmap in self._face.charmaps]
if freetype.FT_ENCODING_ADOBE_CUSTOM in encodings:
encoding = freetype.FT_ENCODING_ADOBE_CUSTOM
elif 'FT_ENCODING_ADOBE_STANDARD' in encodings:
elif freetype.FT_ENCODING_ADOBE_STANDARD in encodings:
encoding = freetype.FT_ENCODING_ADOBE_STANDARD
else:
# encoding = freetype.FT_ENCODING_UNICODE
Expand All @@ -103,6 +98,22 @@ def __init__(self, font_manager, font_id, name):

##############################################

def _find_afm(self):

# try:
# super(Type1Font, self)._find_tfm()
# except FontMetricNotFound:

afm_file = kpsewhich(self.name, file_format='afm')
print afm_file
if afm_file is None:
raise NameError("AFM file was not found for font {}".format(self.name))
else:
self._logger.info("Attach AFM {}".format(afm_file))
self._face.attach_file(afm_file)

##############################################

def _init_index(self):

self._index_to_charcode = {}
Expand Down Expand Up @@ -328,17 +339,18 @@ def load_glyph(self, glyph_index, lcd=False):
flags |= freetype.FT_LOAD_TARGET_LCD

face.load_glyph(glyph_index, flags)
slot = face.glyph

bitmap = face.glyph.bitmap # a list
width = face.glyph.bitmap.width
rows = face.glyph.bitmap.rows
pitch = face.glyph.bitmap.pitch # stride / number of bytes taken by one bitmap row
bitmap = slot.bitmap # a list
width = slot.bitmap.width
rows = slot.bitmap.rows
pitch = slot.bitmap.pitch # stride / number of bytes taken by one bitmap row
# left: The left-side bearing, i.e., the horizontal distance from the current pen position
# to the left border of the glyph bitmap.
# top: The top-side bearing, i.e., the vertical distance from the current pen position to
# the top border of the glyph bitmap. This distance is positive for upwards y!
left = face.glyph.bitmap_left
top = face.glyph.bitmap_top
left = slot.bitmap_left
top = slot.bitmap_top

# Remove padding
data = np.array(bitmap.buffer).reshape(rows, pitch)
Expand All @@ -354,8 +366,16 @@ def load_glyph(self, glyph_index, lcd=False):
# Build glyph
size = glyph_bitmap.shape[1], glyph_bitmap.shape[0]
offset = left, top
advance = face.glyph.advance.x, face.glyph.advance.y
glyph = Glyph(self, glyph_index, size, offset, advance)
advance = slot.advance.x, slot.advance.y

metrics = slot.metrics
metrics_px = [from_64th_point(x) for x in (metrics.width,
metrics.height,
metrics.horiBearingX,
metrics.horiBearingY,
metrics.horiAdvance)]

glyph = Glyph(self, glyph_index, size, offset, advance, metrics_px)
glyph.glyph_bitmap = glyph_bitmap # Fixme:
self._glyphs[glyph_index] = glyph

Expand Down Expand Up @@ -405,7 +425,7 @@ class Glyph(object):
of a single character. It is generally built automatically by a Font.
"""

def __init__(self, font_size, glyph_index, size, offset, advance):
def __init__(self, font_size, glyph_index, size, offset, advance, metrics):

"""
Expand All @@ -425,6 +445,12 @@ def __init__(self, font_size, glyph_index, size, offset, advance):
self.offset = offset
self.advance = advance

(self.width_px,
self.height_px,
self.horizontal_bearing_x_px,
self.horizontal_bearing_y_px,
self.horizontal_advance_px) = metrics

##############################################

def px_to_mm(self, x):
Expand Down
Loading

0 comments on commit b021653

Please sign in to comment.