# -*- encoding: utf-8 -*- # #-- # This file is part of HexaPDF. # # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby # Copyright (C) 2014-2017 Thomas Leitner # # HexaPDF is free software: you can redistribute it and/or modify it # under the terms of the GNU Affero General Public License version 3 as # published by the Free Software Foundation with the addition of the # following permission added to Section 15 as permitted in Section 7(a): # FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY # THOMAS LEITNER, THOMAS LEITNER DISCLAIMS THE WARRANTY OF NON # INFRINGEMENT OF THIRD PARTY RIGHTS. # # HexaPDF 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 Affero General Public # License for more details. # # You should have received a copy of the GNU Affero General Public License # along with HexaPDF. If not, see . # # The interactive user interfaces in modified source and object code # versions of HexaPDF must display Appropriate Legal Notices, as required # under Section 5 of the GNU Affero General Public License version 3. # # In accordance with Section 7(b) of the GNU Affero General Public # License, a covered work must retain the producer line in every PDF that # is created or manipulated using HexaPDF. #++ require 'hexapdf/data_dir' require 'hexapdf/type/font_simple' require 'hexapdf/font/type1' module HexaPDF module Type # Represents a Type1 font. # # PDF provides 14 built-in fonts that all PDF readers must understand. These 14 fonts are # known as the "Standard 14 Fonts" and are all Type1 fonts. HexaPDF supports these fonts. class FontType1 < FontSimple # Provides the names and additional mappings of the Standard 14 Fonts. module StandardFonts # The mapping from font name to Standard 14 Font name, since Adobe allows some # additional names for the the Standard 14 Fonts. # # See: ADB1.7 sH.5.5.1 @mapping = { %s(CourierNew) => %s(Courier), %s(CourierNew,Italic) => %s(Courier-Oblique), %s(CourierNew,Bold) => %s(Courier-Bold), %s(CourierNew,BoldItalic) => %s(Courier-BoldOblique), %s(Arial) => %s(Helvetica), %s(Arial,Italic) => %s(Helvetica-Oblique), %s(Arial,Bold) => %s(Helvetica-Bold), %s(Arial,BoldItalic) => %s(Helvetica-BoldOblique), %s(TimesNewRoman) => %s(Times-Roman), %s(TimesNewRoman,Italic) => %s(Times-Italic), %s(TimesNewRoman,Bold) => %s(Times-Bold), %s(TimesNewRoman,BoldItalic) => %s(Times-BoldItalic), } %i(Times-Roman Times-Bold Times-Italic Times-BoldItalic Helvetica Helvetica-Bold Helvetica-Oblique Helvetica-BoldOblique Courier Courier-Bold Courier-Oblique Courier-BoldOblique Symbol ZapfDingbats).each {|name| @mapping[name] = name} # Returns +true+ if the given name is the name of a standard font. def self.standard_font?(name) @mapping.include?(name) end # Returns the standard name of the font in case an additional name is used, or +nil+ if # the given name doesn't belong to a standard font. def self.standard_name(name) @mapping[name] end @cache = {} # Returns the Type1 font object for the given standard font name, or +nil+ if the given name # doesn't belong to a standard font. def self.font(name) name = @mapping[name] if !standard_font?(name) nil elsif @cache.key?(name) @cache[name] else file = File.join(HexaPDF.data_dir, 'afm', "#{name}.afm") @cache[name] = HexaPDF::Font::Type1::Font.from_afm(file) end end end define_field :Subtype, type: Symbol, required: true, default: :Type1 # Returns the unscaled width of the given code point in glyph units, or 0 if the width for the # code point is missing. def width(code) if StandardFonts.standard_font?(self[:BaseFont]) StandardFonts.font(self[:BaseFont]).width(encoding.name(code)) || 0 else super end end # Returns the bounding box of the font or +nil+ if it is not found. def bounding_box bbox = super if bbox bbox elsif StandardFonts.standard_font?(self[:BaseFont]) StandardFonts.font(self[:BaseFont]).bounding_box else nil end end # Returns +true+ if the font is a symbolic font, +false+ if it is not, and +nil+ if it is # not known. def symbolic? symbolic = super if !symbolic.nil? symbolic elsif StandardFonts.standard_font?(self[:BaseFont]) name = StandardFonts.standard_name(self[:BaseFont]) name == :ZapfDingbats || name == :Symbol else nil end end private # Reads the encoding from an embedded font file and handles the special case of the Standard # 14 fonts. def encoding_from_font if StandardFonts.standard_font?(self[:BaseFont]) StandardFonts.font(self[:BaseFont]).encoding elsif (obj = self[:FontDescriptor][:FontFile]) HexaPDF::Font::Type1::PFBParser.encoding(obj.stream) else raise HexaPDF::Error, "Can't read encoding because Type1 font is not embedded" end end # Validates the Type1 font dictionary. def perform_validation super(ignore_missing_font_fields: StandardFonts.standard_font?(self[:BaseFont])) end end end end