Source code for PyDvi.Font.VirtualFontParser

####################################################################################################
# 
# PyDvi - A Python Library to Process DVI Stream
# Copyright (C) 2014 Fabrice Salvaire
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
# 
####################################################################################################

"""The VirtualFontParser module provides a tool to parse virtual font files.  They have the ".vf"
extension.

"""

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

__all__ = ['VirtualFontParser']

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

import logging

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

from ..Dvi.DviMachine import DviFont
from ..OpcodeParser import OpcodeParserSet, OpcodeParser
from ..Tools.EnumFactory import EnumFactory
from ..Tools.Stream import to_fix_word, AbstractStream, FileStream
from .VirtualCharacter import VirtualCharacter

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

_module_logger = logging.getLogger(__name__)

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

vf_opcodes_tuple = ['SHORT_CHAR_%03u' % (i) for i in xrange(242)]

vf_opcodes_tuple += [
    'LONG_CHAR', # 242
    'FNT_DEF1', 'FNT_DEF2', 'FNT_DEF3', 'FNT_DEF4', # 243 to 246
    'PRE', # 247
    'POST', # 248
    ]

vf_opcodes = EnumFactory('VfOpcodes', vf_opcodes_tuple)

VF_ID = 202

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

class OpcodeParser_char(OpcodeParser):

    """ This class parse the ``char`` opcode. """

    _logger = _module_logger.getChild('OpcodeParser_char')

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

    def __init__(self, opcode):

        super(OpcodeParser_char, self).__init__(opcode,
                                                'char', 'define a virtual character number')

        self._long_char = opcode == vf_opcodes.LONG_CHAR

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

    def read_parameters(self, virtual_font_parser):

        stream = virtual_font_parser.stream

        self._logger.debug("opcode {}".format(self.opcode))

        if self._long_char:
            dvi_length = stream.read_unsigned_byte4()
            char_code = stream.read_unsigned_byte4()
            width = stream.read_unsigned_byte4()
        else:
            dvi_length = self.opcode
            char_code = stream.read_unsigned_byte1()
            width = stream.read_unsigned_byte3()
        dvi = stream.read(dvi_length)

        character = VirtualCharacter(char_code, width, dvi)
        virtual_font_parser.virtual_font.register_character(character)

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

class OpcodeParser_fnt_def(OpcodeParser):

    """ This class parse the ``fnt_def`` opcode. """

    # The code is identical to one of DviParser.

    base_opcode = vf_opcodes.FNT_DEF1

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

    def __init__(self, opcode):

        super(OpcodeParser_fnt_def, self).__init__(opcode,
                                                   'fnt def', 'define the meaning of a font number')

        self.read_unsigned_byten = AbstractStream.read_unsigned_byten[opcode - self.base_opcode]

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

    def read_parameters(self, virtual_font_parser):

        stream = virtual_font_parser.stream

        font_id = self.read_unsigned_byten(stream)
        checksum = stream.read_unsigned_byte4()
        scale_factor = stream.read_unsigned_byte4()
        design_size = stream.read_unsigned_byte4()
        name = str(stream.read(stream.read_unsigned_byte1() + stream.read_unsigned_byte1()))

        virtual_font = virtual_font_parser.virtual_font
        # The font scale factor is relative to the design size of the virtual font, thus 2**20 means
        # the font has the same size than the virtual font.
        # Fixme: right?
        scale_factor = int(to_fix_word(scale_factor) * design_size / virtual_font.design_font_size)
        dvi_font = DviFont(font_id, name, checksum, scale_factor, design_size)
        virtual_font.register_font(dvi_font)

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

opcode_definitions = (
    ( [vf_opcodes.SHORT_CHAR_000,
       vf_opcodes.LONG_CHAR], OpcodeParser_char ),
    ( [vf_opcodes.FNT_DEF1,
       vf_opcodes.FNT_DEF4], OpcodeParser_fnt_def ),
    ( vf_opcodes.PRE, 'pre', 'preamble', (), None ),
    ( vf_opcodes.POST, 'post', 'postamble beginning', None, None ),
    )

[docs]class VirtualFontParser(object): _logger = _module_logger.getChild('VirtualFontParser') opcode_parser_set = OpcodeParserSet(opcode_definitions) ############################################## @staticmethod
[docs] def parse(virtual_font): VirtualFontParser(virtual_font)
############################################## def __init__(self, virtual_font): self.virtual_font = virtual_font self.stream = FileStream(virtual_font.filename) self._process_preambule() self._process_file() ##############################################
[docs] def _process_preambule(self): """ Process the preamble. """ stream = self.stream stream.seek(0) if stream.read_unsigned_byte1() != vf_opcodes.PRE: raise NameError("Virtual font file don't start by PRE opcode") file_id = stream.read_unsigned_byte1() if file_id != VF_ID: raise NameError("Unknown file ID") comment = stream.read(stream.read_unsigned_byte1()) checksum = stream.read_signed_byte4() design_font_size = stream.read_fix_word() # string_template = ''' # Preambule # - Vf ID %u # - Comment '%s' # - Design size %.1f pt # - Checksum %u # ''' # print string_template % ( # file_id, # comment, # design_font_size, # checksum, # ) self.virtual_font._set_preambule_data(file_id, comment, design_font_size, checksum)
##############################################
[docs] def _process_file(self): """ Process the characters. """ stream = self.stream # Fixme: to incorporate pre, check here pre is the first code while True: byte = stream.read_unsigned_byte1() if byte == vf_opcodes.POST: break else: # Fixme: self.opcode_parsers[byte]() opcode_parser = self.opcode_parser_set[byte] opcode_parser.read_parameters(self) # Fixme: return where
#################################################################################################### # # End # ####################################################################################################