/*
Copyright 2006,2007,2008 Stefano Chizzolini. http://clown.stefanochizzolini.it
Contributors:
* Stefano Chizzolini (original code developer, http://www.stefanochizzolini.it)
This file should be part of the source code distribution of "PDF Clown library"
(the Program): see the accompanying README files for more info.
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 2 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, either expressed or implied; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the License for more details.
You should have received a copy of the GNU General Public License along with this
Program (see README files); if not, go to the GNU website (http://www.gnu.org/).
Redistribution and use, with or without modification, are permitted provided that such
redistributions retain the above copyright notice, license and disclaimer, along with
this list of conditions.
*/
using it.stefanochizzolini.clown;
using it.stefanochizzolini.clown.documents;
using it.stefanochizzolini.clown.files;
using it.stefanochizzolini.clown.objects;
using System;
using System.Collections.Generic;
using System.Text;
namespace it.stefanochizzolini.clown.documents.contents.fonts{
/**
<summary>Abstract font [PDF:1.6:5.4].</summary>
*/
public abstract class Font
: PdfObjectWrapper<PdfDictionary>
{
#region nested types
/**
<summary>Font descriptor flags [PDF:1.6:5.7.1].</summary>
*/
public enum FlagsEnum
{
/**
<summary>All glyphs have the same width.</summary>
*/
FixedPitch = 0x1,
/**
<summary>Glyphs have serifs.</summary>
*/
Serif = 0x2,
/**
<summary>Font contains glyphs outside the Adobe standard Latin character set.</summary>
*/
Symbolic = 0x4,
/**
<summary>Glyphs resemble cursive handwriting.</summary>
*/
Script = 0x8,
/**
<summary>Font uses the Adobe standard Latin character set.</summary>
*/
Nonsymbolic = 0x20,
/**
<summary>Glyphs have dominant vertical strokes that are slanted.</summary>
*/
Italic = 0x40,
/**
<summary>Font contains no lowercase letters.</summary>
*/
AllCap = 0x10000,
/**
<summary>Font contains both uppercase and lowercase letters.</summary>
*/
SmallCap = 0x20000,
/**
<summary>Thicken bold glyphs at small text sizes.</summary>
*/
ForceBold = 0x40000
}
#endregion
#region static
#region interface
#region public
/**
<summary>Gets the scaling factor to be applied to unscaled metrics to get actual
measures.</summary>
*/
public static double GetScalingFactor(
double size
)
{return (0.001 * size);}
/**
<summary>Wraps a font reference into a font object.</summary>
<param name="reference">Reference to a font object.</param>
<returns>Font object associated to the reference.</returns>
*/
public static Font Wrap(
PdfReference reference
)
{
/*
NOTE: This is a factory method for any font-derived object.
*/
if(reference == null)
return null;
PdfDictionary fontData = (PdfDictionary)reference.DataObject;
PdfName fontType = (PdfName)fontData[PdfName.Subtype];
{
// Has the font been already instantiated?
/*
NOTE: Font structures are reified as complex objects, both IO- and CPU-intensive to load.
So, it's convenient to retrieve them from a common cache whenever possible.
*/
Dictionary<PdfReference,object> cache = reference.IndirectObject.File.Document.Cache;
if(cache.ContainsKey(reference))
{return (Font)cache[reference];}
}
// Is it a Type 1 font?
if(fontType.Equals(PdfName.Type1)) // Type 1.
{
// Is it a standard Type 1 font?
if(!fontData.ContainsKey(PdfName.FontDescriptor)) // Standard Type 1.
{return new StandardType1Font(reference);}
else // Custom Type 1.
{
PdfDictionary fontDescriptor = (PdfDictionary)File.Resolve(fontData[PdfName.FontDescriptor]);
// Is it an OpenType-wrapped CFF (Compact Font Format) Type 1 font?
if(fontDescriptor.ContainsKey(PdfName.FontFile3)
&& ((PdfName)((PdfStream)File.Resolve(fontDescriptor[PdfName.FontFile3])).Header[PdfName.Subtype]).Equals(PdfName.OpenType)
) // OpenType-wrapped CFF.
{return new OpenTypeFont(reference);}
else // Non-OpenType Type 1 font.
{return new Type1Font(reference);}
}
}
// Is it a TrueType font?
else if(fontType.Equals(PdfName.TrueType)) // TrueType.
{return new OpenTypeFont(reference);}
else // Unknown.
{return null;}
}
#endregion
#endregion
#endregion
#region dynamic
#region constructors
protected Font(
Document context
) : base(
context.File,
new PdfDictionary(
new PdfName[1]{PdfName.Type},
new PdfDirectObject[1]{PdfName.Font}
)
)
{Initialize();}
protected Font(
PdfDirectObject baseObject
) : base(
baseObject,
null // NO container. NOTE: this is a simplification (the spec [PDF:1.6] doesn't apparently prescribe the use of an indirect object for font dictionary, whilst the general practice is as such. If an exception occurs, you'll need to specify the proper container).
)
{Initialize();}
#endregion
#region interface
#region public
/**
<summary>Gets the text from the given internal representation.</summary>
<param name="code">Internal representation to decode.</param>
*/
public abstract string Decode(
byte[] code
);
/**
<summary>Gets the internal representation of the given text.</summary>
<param name="text">Text to encode.</param>
*/
public abstract byte[] Encode(
string text
);
public bool Equals(
Font obj
)
{
return (
this.Type == obj.Type
&& this.Name == obj.Name
);
}
/**
<summary>Gets the font descriptor flags.</summary>
*/
public virtual FlagsEnum Flags
{
get
{
return (FlagsEnum)Enum.ToObject(
typeof(FlagsEnum),
((IPdfNumber)File.Resolve(
Descriptor[PdfName.Flags]
)).Value
);
}
}
/**
<summary>Gets the vertical offset from the baseline to the ascender line (ascent).</summary>
*/
public virtual double GetAscent(
double size
)
{
return ((IPdfNumber)File.Resolve(
Descriptor[PdfName.Ascent]
)).RawValue * GetScalingFactor(size);
}
/**
<summary>Gets the vertical offset from the baseline to the descender line (descent).</summary>
*/
public virtual double GetDescent(
double size
)
{
return ((IPdfNumber)File.Resolve(
Descriptor[PdfName.Descent]
)).RawValue * GetScalingFactor(size);
}
/**
<summary>Gets the width (kerning inclusive) of the given text, scaled to the given font size.</summary>
*/
public double GetKernedWidth(
string text,
double size
)
{return (GetWidth(text) + GetKerning(text)) * GetScalingFactor(size);}
/**
<summary>Gets the unscaled kerning width between two given characters.</summary>
*/
public abstract int GetKerning(
char textChar1,
char textChar2
);
/**
<summary>Gets the unscaled kerning width inside the given text.</summary>
*/
public abstract int GetKerning(
string text
);
/**
<summary>Gets the kerning width inside the given text, scaled to the given font size.</summary>
*/
public double GetKerning(
string text,
double size
)
{return GetKerning(text) * GetScalingFactor(size);}
/**
<summary>Gets the actual line height.</summary>
*/
public virtual double GetLineHeight(
double size
)
{
PdfDictionary descriptor = Descriptor;
return (
((IPdfNumber)File.Resolve(
descriptor[PdfName.Ascent]
)).RawValue
+ Math.Abs(((IPdfNumber)File.Resolve(
descriptor[PdfName.Descent]
)).RawValue)
) * GetScalingFactor(size);
}
/**
<summary>Gets the PostScript name of the font.</summary>
*/
public string Name
{
get{return ((PdfName)BaseDataObject[PdfName.BaseFont]).ToString();}
}
/**
<summary>Gets the font type.</summary>
*/
public string Type
{
get{return ((PdfName)BaseDataObject[PdfName.Subtype]).ToString();}
}
/**
<summary>Gets the unscaled width of the given character.</summary>
*/
public abstract int GetWidth(
char textChar
);
/**
<summary>Gets the unscaled width (kerning exclusive) of the given text.</summary>
*/
public abstract int GetWidth(
string text
);
/**
<summary>Gets the width (kerning exclusive) of the given text, scaled to the given font
size.</summary>
*/
public double GetWidth(
string text,
double size
)
{return GetWidth(text) * GetScalingFactor(size);}
#endregion
#region protected
protected virtual PdfDictionary Descriptor
{get{return (PdfDictionary)File.Resolve(BaseDataObject[PdfName.FontDescriptor]);}}
#endregion
#region private
private void Initialize(
)
{
// Put the newly-instantiated font into the common cache!
/*
NOTE: Font structures are reified as complex objects, both IO- and CPU-intensive to load.
So, it's convenient to put them into a common cache for later reuse.
*/
Document.Cache[(PdfReference)BaseObject] = this;
}
#endregion
#endregion
#endregion
}
}
|