123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496 |
- /* ====================================================================
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- ==================================================================== */
-
- package org.apache.poi.hemf.record.emf;
-
- import java.io.IOException;
- import java.nio.charset.StandardCharsets;
- import java.util.ArrayList;
- import java.util.List;
-
- import org.apache.poi.common.usermodel.fonts.FontCharset;
- import org.apache.poi.hwmf.record.HwmfFont;
- import org.apache.poi.util.LittleEndian;
- import org.apache.poi.util.LittleEndianConsts;
- import org.apache.poi.util.LittleEndianInputStream;
-
- public class HemfFont extends HwmfFont {
- private static final int LOGFONT_SIZE = 92;
- private static final int LOGFONTPANOSE_SIZE = 320;
-
- protected interface LogFontDetails {}
-
- protected static class LogFontExDv implements LogFontDetails {
- protected int[] designVector;
-
- @Override
- public String toString() {
- return "{ designVectorLen: " + (designVector == null ? 0 : designVector.length) + " }";
- }
- }
-
- protected static class LogFontPanose implements LogFontDetails {
- enum FamilyType {
- PAN_ANY,
- PAN_NO_FIT,
- PAN_FAMILY_TEXT_DISPLAY,
- PAN_FAMILY_SCRIPT,
- PAN_FAMILY_DECORATIVE,
- PAN_FAMILY_PICTORIAL
- }
-
- enum SerifType {
- PAN_ANY,
- PAN_NO_FIT,
- PAN_SERIF_COVE,
- PAN_SERIF_OBTUSE_COVE,
- PAN_SERIF_SQUARE_COVE,
- PAN_SERIF_OBTUSE_SQUARE_COVE,
- PAN_SERIF_SQUARE,
- PAN_SERIF_THIN,
- PAN_SERIF_BONE,
- PAN_SERIF_EXAGGERATED,
- PAN_SERIF_TRIANGLE,
- PAN_SERIF_NORMAL_SANS,
- PAN_SERIF_OBTUSE_SANS,
- PAN_SERIF_PERP_SANS,
- PAN_SERIF_FLARED,
- PAN_SERIF_ROUNDED
- }
-
- enum FontWeight {
- PAN_ANY,
- PAN_NO_FIT,
- PAN_WEIGHT_VERY_LIGHT,
- PAN_WEIGHT_LIGHT,
- PAN_WEIGHT_THIN,
- PAN_WEIGHT_BOOK,
- PAN_WEIGHT_MEDIUM,
- PAN_WEIGHT_DEMI,
- PAN_WEIGHT_BOLD,
- PAN_WEIGHT_HEAVY,
- PAN_WEIGHT_BLACK,
- PAN_WEIGHT_NORD
- }
-
- enum Proportion {
- PAN_ANY,
- PAN_NO_FIT,
- PAN_PROP_OLD_STYLE,
- PAN_PROP_MODERN,
- PAN_PROP_EVEN_WIDTH,
- PAN_PROP_EXPANDED,
- PAN_PROP_CONDENSED,
- PAN_PROP_VERY_EXPANDED,
- PAN_PROP_VERY_CONDENSED,
- PAN_PROP_MONOSPACED
- }
-
- enum Contrast {
- PAN_ANY,
- PAN_NO_FIT,
- PAN_CONTRAST_NONE,
- PAN_CONTRAST_VERY_LOW,
- PAN_CONTRAST_LOW,
- PAN_CONTRAST_MEDIUM_LOW,
- PAN_CONTRAST_MEDIUM,
- PAN_CONTRAST_MEDIUM_HIGH,
- PAN_CONTRAST_HIGH,
- PAN_CONTRAST_VERY_HIGH
- }
-
- enum StrokeVariation {
- PAN_ANY,
- PAN_NO_FIT,
- PAN_STROKE_GRADUAL_DIAG,
- PAN_STROKE_GRADUAL_TRAN,
- PAN_STROKE_GRADUAL_VERT,
- PAN_STROKE_GRADUAL_HORZ,
- PAN_STROKE_RAPID_VERT,
- PAN_STROKE_RAPID_HORZ,
- PAN_STROKE_INSTANT_VERT
- }
-
- enum ArmStyle {
- PAN_ANY,
- PAN_NO_FIT,
- PAN_STRAIGHT_ARMS_HORZ,
- PAN_STRAIGHT_ARMS_WEDGE,
- PAN_STRAIGHT_ARMS_VERT,
- PAN_STRAIGHT_ARMS_SINGLE_SERIF,
- PAN_STRAIGHT_ARMS_DOUBLE_SERIF,
- PAN_BENT_ARMS_HORZ,
- PAN_BENT_ARMS_WEDGE,
- PAN_BENT_ARMS_VERT,
- PAN_BENT_ARMS_SINGLE_SERIF,
- PAN_BENT_ARMS_DOUBLE_SERIF
- }
-
- enum Letterform {
- PAN_ANY,
- PAN_NO_FIT,
- PAN_LETT_NORMAL_CONTACT,
- PAN_LETT_NORMAL_WEIGHTED,
- PAN_LETT_NORMAL_BOXED,
- PAN_LETT_NORMAL_FLATTENED,
- PAN_LETT_NORMAL_ROUNDED,
- PAN_LETT_NORMAL_OFF_CENTER,
- PAN_LETT_NORMAL_SQUARE,
- PAN_LETT_OBLIQUE_CONTACT,
- PAN_LETT_OBLIQUE_WEIGHTED,
- PAN_LETT_OBLIQUE_BOXED,
- PAN_LETT_OBLIQUE_FLATTENED,
- PAN_LETT_OBLIQUE_ROUNDED,
- PAN_LETT_OBLIQUE_OFF_CENTER,
- PAN_LETT_OBLIQUE_SQUARE
- }
-
- enum MidLine {
- PAN_ANY,
- PAN_NO_FIT,
- PAN_MIDLINE_STANDARD_TRIMMED,
- PAN_MIDLINE_STANDARD_POINTED,
- PAN_MIDLINE_STANDARD_SERIFED,
- PAN_MIDLINE_HIGH_TRIMMED,
- PAN_MIDLINE_HIGH_POINTED,
- PAN_MIDLINE_HIGH_SERIFED,
- PAN_MIDLINE_CONSTANT_TRIMMED,
- PAN_MIDLINE_CONSTANT_POINTED,
- PAN_MIDLINE_CONSTANT_SERIFED,
- PAN_MIDLINE_LOW_TRIMMED,
- PAN_MIDLINE_LOW_POINTED,
- PAN_MIDLINE_LOW_SERIFED
- }
-
- enum XHeight {
- PAN_ANY,
- PAN_NO_FIT,
- PAN_XHEIGHT_CONSTANT_SMALL,
- PAN_XHEIGHT_CONSTANT_STD,
- PAN_XHEIGHT_CONSTANT_LARGE,
- PAN_XHEIGHT_DUCKING_SMALL,
- PAN_XHEIGHT_DUCKING_STD,
- PAN_XHEIGHT_DUCKING_LARGE
- }
-
- protected int styleSize;
- protected int vendorId;
- protected int culture;
- protected FamilyType familyType;
- protected SerifType serifStyle;
- protected FontWeight weight;
- protected Proportion proportion;
- protected Contrast contrast;
- protected StrokeVariation strokeVariation;
- protected ArmStyle armStyle;
- protected Letterform letterform;
- protected MidLine midLine;
- protected XHeight xHeight;
-
- @Override
- public String toString() {
- return
- "{ styleSize: " + styleSize +
- ", vendorId: " + vendorId +
- ", culture: " + culture +
- ", familyType: '" + familyType + "'" +
- ", serifStyle: '" + serifStyle + "'" +
- ", weight: '" + weight + "'" +
- ", proportion: '" + proportion + "'" +
- ", contrast: '" + contrast + "'" +
- ", strokeVariation: '" + strokeVariation + "'" +
- ", armStyle: '" + armStyle + "'" +
- ", letterform: '" + letterform + "'" +
- ", midLine: '" + midLine + "'" +
- ", xHeight: '" + xHeight + "'" +
- "}";
- }
- }
-
- protected String fullname;
- protected String style;
- protected String script;
-
- protected LogFontDetails details;
-
- @Override
- public int init(LittleEndianInputStream leis, long recordSize) throws IOException {
- // A 32-bit signed integer that specifies the height, in logical units, of the font's
- // character cell or character. The character height value, also known as the em size, is the
- // character cell height value minus the internal leading value. The font mapper SHOULD
- // interpret the value specified in the Height field in the following manner.
- //
- // 0x00000000 < value:
- // The font mapper transforms this value into device units and matches it against
- // the cell height of the available fonts.
- //
- // 0x00000000
- // The font mapper uses a default height value when it searches for a match.
- //
- // value < 0x00000000:
- // The font mapper transforms this value into device units and matches its
- // absolute value against the character height of the available fonts.
- //
- // For all height comparisons, the font mapper SHOULD look for the largest font that does not
- // exceed the requested size.
- height = leis.readInt();
-
- // A 32-bit signed integer that specifies the average width, in logical units, of
- // characters in the font. If the Width field value is zero, an appropriate value SHOULD be
- // calculated from other LogFont values to find a font that has the typographer's intended
- // aspect ratio.
- width = leis.readInt();
-
- // A 32-bit signed integer that specifies the angle, in tenths of degrees,
- // between the escapement vector and the x-axis of the device. The escapement vector is
- // parallel to the baseline of a row of text.
- //
- // When the graphics mode is set to GM_ADVANCED, the escapement angle of the string can
- // be specified independently of the orientation angle of the string's characters.
- escapement = leis.readInt();
-
- // A 32-bit signed integer that specifies the angle, in tenths of degrees,
- // between each character's baseline and the x-axis of the device.
- orientation = leis.readInt();
-
- // A 32-bit signed integer that specifies the weight of the font in the range zero through 1000.
- // For example, 400 is normal and 700 is bold. If this value is zero, a default weight can be used.
- weight = leis.readInt();
-
- // An 8-bit unsigned integer that specifies an italic font if set to 0x01;
- // otherwise, it MUST be set to 0x00.
- italic = (leis.readUByte() != 0x00);
-
- // An 8-bit unsigned integer that specifies an underlined font if set to 0x01;
- // otherwise, it MUST be set to 0x00.
- underline = (leis.readUByte() != 0x00);
-
- // An 8-bit unsigned integer that specifies a strikeout font if set to 0x01;
- // otherwise, it MUST be set to 0x00.
- strikeOut = (leis.readUByte() != 0x00);
-
- // An 8-bit unsigned integer that specifies the set of character glyphs.
- // It MUST be a value in the WMF CharacterSet enumeration.
- // If the character set is unknown, metafile processing SHOULD NOT attempt
- // to translate or interpret strings that are rendered with that font.
- // If a typeface name is specified in the Facename field, the CharSet field
- // value MUST match the character set of that typeface.
- charSet = FontCharset.valueOf(leis.readUByte());
-
- // An 8-bit unsigned integer that specifies the output precision.
- // The output precision defines how closely the font is required to match the requested height, width,
- // character orientation, escapement, pitch, and font type.
- // It MUST be a value from the WMF OutPrecision enumeration.
- // Applications can use the output precision to control how the font mapper chooses a font when the
- // operating system contains more than one font with a specified name. For example, if an operating
- // system contains a font named Symbol in rasterized and TrueType forms, an output precision value
- // of OUT_TT_PRECIS forces the font mapper to choose the TrueType version.
- // A value of OUT_TT_ONLY_PRECIS forces the font mapper to choose a TrueType font, even if it is
- // necessary to substitute a TrueType font with another name.
- outPrecision = WmfOutPrecision.valueOf(leis.readUByte());
-
- // An 8-bit unsigned integer that specifies the clipping precision.
- // The clipping precision defines how to clip characters that are partially outside the clipping region.
- // It can be one or more of the WMF ClipPrecision Flags
- clipPrecision.init(leis);
-
- // An 8-bit unsigned integer that specifies the output quality. The output quality defines how closely
- // to attempt to match the logical-font attributes to those of an actual physical font.
- // It MUST be one of the values in the WMF FontQuality enumeration
- quality = WmfFontQuality.valueOf(leis.readUByte());
-
- // A WMF PitchAndFamily object that specifies the pitch and family of the font.
- // Font families describe the look of a font in a general way.
- // They are intended for specifying a font when the specified typeface is not available.
- pitchAndFamily = leis.readUByte();
-
- int size = 5* LittleEndianConsts.INT_SIZE+8*LittleEndianConsts.BYTE_SIZE;
-
- StringBuilder sb = new StringBuilder();
-
- // A string of no more than 32 Unicode characters that specifies the typeface name of the font.
- // If the length of this string is less than 32 characters, a terminating NULL MUST be present,
- // after which the remainder of this field MUST be ignored.
- int readBytes = readString(leis, sb, 32);
- if (readBytes == -1) {
- throw new IOException("Font facename can't be determined.");
- }
- facename = sb.toString();
- size += readBytes;
-
- if (recordSize <= LOGFONT_SIZE) {
- return size;
- }
-
- // A string of 64 Unicode characters that contains the font's full name.
- // Ifthe length of this string is less than 64 characters, a terminating
- // NULL MUST be present, after which the remainder of this field MUST be ignored.
- readBytes = readString(leis, sb, 64);
- if (readBytes == -1) {
- throw new IOException("Font fullname can't be determined.");
- }
- fullname = sb.toString();
- size += readBytes;
-
- // A string of 32 Unicode characters that defines the font's style. If the length of
- // this string is less than 32 characters, a terminating NULL MUST be present,
- // after which the remainder of this field MUST be ignored.
- readBytes = readString(leis, sb, 32);
- if (readBytes == -1) {
- throw new IOException("Font style can't be determined.");
- }
- style = sb.toString();
- size += readBytes;
-
- if (recordSize == LOGFONTPANOSE_SIZE) {
- // LogFontPanose Object
-
- LogFontPanose logPan = new LogFontPanose();
- details = logPan;
-
- int version = leis.readInt();
-
- // A 32-bit unsigned integer that specifies the point size at which font
- //hinting is performed. If set to zero, font hinting is performed at the point size corresponding
- //to the Height field in the LogFont object in the LogFont field.
- logPan.styleSize = (int)leis.readUInt();
-
- int match = leis.readInt();
-
- int reserved = leis.readInt();
-
- logPan.vendorId = leis.readInt();
-
- logPan.culture = leis.readInt();
-
- // An 8-bit unsigned integer that specifies the family type.
- // The value MUST be in the FamilyType enumeration table.
- logPan.familyType = LogFontPanose.FamilyType.values()[leis.readUByte()];
-
- // An 8-bit unsigned integer that specifies the serif style.
- // The value MUST be in the SerifType enumeration table.
- logPan.serifStyle = LogFontPanose.SerifType.values()[leis.readUByte()];
-
- // An 8-bit unsigned integer that specifies the weight of the font.
- // The value MUST be in the Weight enumeration table.
- logPan.weight = LogFontPanose.FontWeight.values()[leis.readUByte()];
-
- // An 8-bit unsigned integer that specifies the proportion of the font.
- // The value MUST be in the Proportion enumeration table.
- logPan.proportion = LogFontPanose.Proportion.values()[leis.readUByte()];
-
- // An 8-bit unsigned integer that specifies the proportion of the font.
- // The value MUST be in the Proportion enumeration table.
- logPan.contrast = LogFontPanose.Contrast.values()[leis.readUByte()];
-
- // An 8-bit unsigned integer that specifies the stroke variation for the font.
- // The value MUST be in the StrokeVariation enumeration table.
- logPan.strokeVariation = LogFontPanose.StrokeVariation.values()[leis.readUByte()];
-
- // An 8-bit unsigned integer that specifies the arm style of the font.
- // The value MUST be in the ArmStyle enumeration table.
- logPan.armStyle = LogFontPanose.ArmStyle.values()[leis.readUByte()];
-
- // An 8-bit unsigned integer that specifies the letterform of the font.
- // The value MUST be in the Letterform enumeration table.
- logPan.letterform = LogFontPanose.Letterform.values()[leis.readUByte()];
-
- // An 8-bit unsigned integer that specifies the midline of the font.
- // The value MUST be in the MidLine enumeration table.
- logPan.midLine = LogFontPanose.MidLine.values()[leis.readUByte()];
-
- // An 8-bit unsigned integer that specifies the x height of the font.
- // The value MUST be in the XHeight enumeration table.
- logPan.xHeight = LogFontPanose.XHeight.values()[leis.readUByte()];
-
- // skip 2 byte to ensure 32-bit alignment of this structure.
- leis.skip(2);
-
- size += 6*LittleEndianConsts.INT_SIZE+10* LittleEndianConsts.BYTE_SIZE+2;
- } else {
- // LogFontExDv Object
-
- LogFontExDv logEx = new LogFontExDv();
- details = logEx;
-
- // A string of 32 Unicode characters that defines the character set of the font.
- // If the length of this string is less than 32 characters, a terminating NULL MUST be present,
- // after which the remainder of this field MUST be ignored.
- readBytes = readString(leis, sb, 32);
- if (readBytes == -1) {
- throw new IOException("Font script can't be determined.");
- }
- script = sb.toString();
- size += readBytes;
-
- // Design Vector
-
- // A 32-bit unsigned integer that MUST be set to the value 0x08007664.
- int signature = leis.readInt();
- // some non-conformant applications don't write the magic code in
- // assert (signature == 0x08007664);
-
- // A 32-bit unsigned integer that specifies the number of elements in the
- // Values array. It MUST be in the range 0 to 16, inclusive.
- int numAxes = leis.readInt();
- assert (0 <= numAxes && numAxes <= 16);
-
- // An optional array of 32-bit signed integers that specify the values of the font axes of a
- // multiple master, OpenType font. The maximum number of values in the array is 16.
- if (numAxes > 0) {
- logEx.designVector = new int[numAxes];
- for (int i=0; i<numAxes; i++) {
- logEx.designVector[i] = leis.readInt();
- }
- }
- size += (2+numAxes)*LittleEndianConsts.INT_SIZE;
- }
-
- return size;
- }
-
- @Override
- public String toString() {
- return
- "{ fullname: '" + (fullname == null ? "" : fullname) + "'" +
- ", style: '" + (style == null ? "" : style) + "'" +
- ", script: '" + (script == null ? "" : script) + "'" +
- ", details: " + details +
- "," + super.toString().substring(1);
- }
-
- @Override
- protected int readString(LittleEndianInputStream leis, StringBuilder sb, int limit) throws IOException {
- sb.setLength(0);
- byte buf[] = new byte[limit*2];
- leis.readFully(buf);
-
- int b1, b2, readBytes = 0;
- do {
- if (readBytes == limit*2) {
- return -1;
- }
-
- b1 = buf[readBytes++];
- b2 = buf[readBytes++];
- } while ((b1 != 0 || b2 != 0) && b1 != -1 && b2 != -1 && readBytes <= limit*2);
-
- sb.append(new String(buf, 0, readBytes-2, StandardCharsets.UTF_16LE));
-
- return limit*2;
- }
- }
|