All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.docx4j.fonts.foray.font.format.Panose Maven / Gradle / Ivy

/*
 * Copyright 2006 The FOray Project.
 *      http://www.foray.org
 *
 * Licensed 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.
 *
 * This work is in part derived from the following work(s), used with the
 * permission of the licensor:
 *      Apache FOP, licensed by the Apache Software Foundation
 *
 */

/*
 * $LastChangedRevision: 10482 $
 * $LastChangedDate: 2008-03-23 02:59:39 +1100 (Sun, 23 Mar 2008) $
 * $LastChangedBy$
 */

/* NOTICE: This file has been changed by Plutext Pty Ltd for use in docx4j.
 * 
 * This notice is included to meet the condition in clause 4(b) of the License. 
 */

//package org.foray.font.format;
package org.docx4j.fonts.foray.font.format;

import java.io.Serializable;



/**
 * A PANOSE-1 classification number.
 *
 * 

References:

* */ public final class Panose implements Serializable { private static final long serialVersionUID = -6678392067062344333L; /** * Enumeration of the fields that comprise a PANOSE description. * @see "http://fonts.apple.com/TTRefMan/RM06/Chap6OS2.html" */ public enum Field { /** The bFamilyType field. */ FAMILY_TYPE ((byte) 0, (byte) 5), /** The bSerifStyle field. */ SERIF_STYLE ((byte) 1, (byte) 15), /** The bWeight field. */ WEIGHT ((byte) 2, (byte) 11), /** The bProportion field. */ PROPORTION ((byte) 3, (byte) 9), /** The bContrast field. */ CONTRAST ((byte) 4, (byte) 9), /** The bStrokeVariatoon field. */ STROKE_VARIATION ((byte) 5, (byte) 8), /** The bArmStyle field. */ ARM_STYLE ((byte) 6, (byte) 11), /** The bLetterform field. */ LETTERFORM ((byte) 7, (byte) 15), /** The bMidline field. */ MIDLINE ((byte) 8, (byte) 13), /** The bXHeight field. */ X_HEIGHT ((byte) 9, (byte) 7); /** The 0-based index of this element in the PANOSE array. */ private byte index; /** The maximum value that is permissible for this element. */ private byte maxValue; /** * Private Constructor. * @param index The 0-based index of this element in the PANOSE array. * @param maxValue The maximum value that is permissible for this element. */ private Field(final byte index, final byte maxValue) { this.index = index; this.maxValue = maxValue; } /** * Returns the 0-based index of this element in the PANOSE array. * @return The 0-based index of this element in the PANOSE array. */ public byte getIndex() { return this.index; } /** * Returns the maximum valid value for this field. * @return The maximum valid value for this field. */ public byte getMaxValue() { return this.maxValue; } } /** * Constant indicating the minimum italic value for the letterform field. * This is based on an analysis of the MS ClearType Collection fonts: *
    *
  • consolas [ 2 11 6 9 2 2 4 3 2 4 ] bold 6 ital 3
  • *
  • consolas-bold [ 2 11 7 9 2 2 4 3 2 4 ] bold 7 ital 3
  • *
  • consolas-italic [ 2 11 6 9 2 2 4 10 2 4 ] bold 6 ital 10
  • *
  • consolas-bolditalic [ 2 11 7 9 2 2 4 10 2 4 ] bold 7 ital 10
  • * *
  • cordianew [ 2 11 3 4 2 2 2 2 2 4 ] bold 3 ital 2
  • *
  • cordianew-bolditalic [ 2 11 6 4 2 2 2 9 2 4 ] bold 6 ital 9
  • * *
  • calibri [ 2 15 5 2 2 2 4 3 2 4 ] bold 5 ital 3
  • *
  • calibri-bold [ 2 15 7 2 3 4 4 3 2 4 ] bold 7 ital 3
  • *
  • calibri-bolditalic [ 2 15 7 2 3 4 4 10 2 4 ] bold 7 ital 10
  • * *
  • constantia [ 2 3 6 2 5 3 6 3 3 3 ] bold 6 ital 3
  • *
  • constantia-bold [ 2 3 7 2 6 3 6 3 3 3 ] bold 7 ital 3 (note the 6 at index 4)
  • *
  • constantia-italic [ 2 3 6 2 5 3 6 10 3 3 ] bold 6 ital 10
  • * *
  • candara-bold [ 2 14 7 2 3 3 3 2 2 4 ] bold 7 ital 2
  • *
  • candara-italic [ 2 14 5 2 3 3 3 9 2 4 ] bold 5 ital 9
  • *
  • candara-bolditalic [ 2 14 7 2 3 3 3 9 2 4 ] bold 7 ital 9
  • * *
  • cambria-bold [ 2 4 8 3 5 4 6 3 2 4 ] bold 8 ital 3
  • *
  • cambria-italic [ 2 4 5 3 5 4 6 10 2 4 ] bold 5 ital 10
  • *
*/ private static final byte LETTERFORM_MIN_ITALIC = 9; /** * Constant indicating the minimum bold value for the weight field. * This is based on an analysis of the MS ClearType Collection fonts, which can be found at * {@link #LETTERFORM_MIN_ITALIC}. */ private static final byte WEIGHT_MIN_BOLD = 7; /** An array of weights indicating that all elements in a comparison between two PANOSE values * shall be considered to be of the same weight. */ private static final byte[] NEUTRAL_WEIGHTS = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; /* Caveat: It is tempting to make NEUTRAL_WEIGHTS public and allow client apps to use it as a * parameter. However, there is no way to protect the data inside it from corruption, so we * have elected to keep it private and to allow "null" to be interpreted as the same value. */ /** The encapsulated array of PANOSE numbers. */ private byte[] panoseArray; /** * Private Constructor. Use {@link #makeInstance(byte[])} to create an instance of this class. * @param panoseArray The array of bytes recording the PANOSE classification. */ private Panose(final byte[] panoseArray) { /* Clone the incoming array to protect our data from subsequent changes made to the original * array. */ this.panoseArray = panoseArray.clone(); } /** * Creates a new Panose instance, first checking it for validity. * @param panoseArray The array of bytes recording the PANOSE * classification. * @return The newly-created instance. * @throws FontException If panoseArray contains an illegal value. * @see #forceInstance(byte[]) */ public static Panose makeInstance(final byte[] panoseArray) { final String panoseValidationMessage = Panose.validPanose(panoseArray); if (panoseValidationMessage != null) { throw new IllegalArgumentException("Illegal Panose Array: " + panoseValidationMessage); } return new Panose(panoseArray); } /** * Creates a new Panose instance without any error checking. * @param panoseArray The array of bytes recording the PANOSE classification. * @return The newly-created instance. * @see #makeInstance(byte[]) */ public static Panose forceInstance(final byte[] panoseArray) { return new Panose(panoseArray); } /** * Returns a clone of the the array of bytes representing the PANOSE number. * To avoid the cost of this cloning operation, use {@link #getElement(int)} to obtain the * value of individual elements in the array. * @return The PANOSE array. */ public byte[] getPanoseArray() { return this.panoseArray.clone(); } /** * Returns a given element from the underlying Panose array. * @param index The index to the element desired. * @return The value of the element at index. */ public byte getElement(final int index) { return this.panoseArray[index]; } /** * Returns a given element from the underlying Panose array. * @param field The field for which the value is desired. * @return The value of the element at field. */ public byte getElement(final Panose.Field field) { final int index = field.getIndex(); return getElement(index); } /** * Computes the weighted "closeness" of another Panose to this value. * @param otherPanose Another Panose instance which is being compared to this. * @param weights 10-element byte array of weights that should be used for each of the elements * in the comparison. * Values in this array must be between 0 and 127 inclusive. * (This constant is documented at http://www.w3.org/Fonts/Panose/pan2.html#StaticDigits). * Use null if all elements are to be weighted equally. * @return The weighted difference between the two Panose values. * A smaller value indicates that the two values are closer, and a larger * value indicates that they are farther apart. */ public long difference(final Panose otherPanose, final byte[] weights) { /* This is a partial implementation of the "PANOSE Matching Heuristic" documented at: * http://www.w3.org/Fonts/Panose/pan2.html#Heuristic. **/ byte[] weightsToUse = null; if (weights == null) { weightsToUse = Panose.NEUTRAL_WEIGHTS; } else { validateWeights(weights); weightsToUse = weights; } long difference = 0; for (int i = 0; i < Panose.Field.values().length; i++) { // final int digit = panoseDescription.length - i; // final int weight = (int) Math.round(Math.pow(2, digit - 1)); final int weight = weightsToUse[i]; final int thisDifference = this.getElement(i) - otherPanose.getElement(i); difference += weight * thisDifference * thisDifference; } return difference; } /** * Examines an array of weights, throwing various unchecked exceptions if the data is not valid. * @param weights The array of weights to be tested. */ private static void validateWeights(final byte[] weights) { if (weights == null) { throw new NullPointerException("Weights may not be null"); } if (weights.length != Panose.Field.values().length) { throw new IllegalArgumentException("Weights size expected: " + Panose.Field.values().length + ", actual: " + weights.length); } for (int i = 0; i < weights.length; i++) { final byte weight = weights[i]; if (weight < 0 || weight > Byte.MAX_VALUE) { throw new IllegalArgumentException("Weight element " + i + " is outside the range " + "of 0 thru 127."); } } } /** * Tests the validity of a panose description. * @param panoseDescription The panose values to be tested. * @return Null for a valid PANOSE description. For an invalid PANOSE description, returns a * descriptive message indicating which element is invalid. */ public static String validPanose(final byte[] panoseDescription) { if (panoseDescription == null) { return "Panose description cannot be null."; } if (panoseDescription.length != Panose.Field.values().length) { return "Illegal Panose description size: " + panoseDescription.length; } for (int i = 0; i < panoseDescription.length; i++) { final byte theByte = panoseDescription[i]; final Panose.Field panoseField = Panose.Field.values()[i]; final byte maxValue = panoseField.getMaxValue(); if (theByte < 0 || theByte > maxValue) { return "Invalid value " + theByte + " > " + maxValue + " in position " + i + " of " + toString(panoseDescription); } } return null; } /** * {@inheritDoc} */ public String toString() { return toString(this.panoseArray); } /** * Returns a String representation of a Panose array. * @param panoseArray The Panose array to be expressed as a String. * @return The String representation of panoseArray. */ private static String toString(final byte[] panoseArray) { final StringBuilder sb = new StringBuilder(30); sb.append("[ "); for (int i = 0; i < panoseArray.length; i++) { final byte theByte = panoseArray[i]; sb.append(theByte + " "); } sb.append("]"); return sb.toString(); } /** * Returns the bold version of this Panose instance. * @return If this already describes a bold font, returns this. Otherwise, returns a new * Panose instance that is identical to this, except describing a bold font. */ public Panose getBold() { final byte weightValue = this.getElement(Panose.Field.WEIGHT); if (weightValue >= Panose.WEIGHT_MIN_BOLD) { /* This Panose value is already bold. */ return this; } final byte[] newArray = this.panoseArray.clone(); newArray[Panose.Field.WEIGHT.getIndex()] = Panose.WEIGHT_MIN_BOLD; return Panose.forceInstance(newArray); } /** * Returns the italic version of this Panose instance. * @return If this already describes an italic font, returns this. Otherwise, returns a new * Panose instance that is identical to this, except describing an italic font. */ public Panose getItalic() { final byte letterformValue = this.getElement(Panose.Field.LETTERFORM); if (letterformValue >= Panose.LETTERFORM_MIN_ITALIC) { /* This Panose value is already italic. */ return this; } final byte[] newArray = this.panoseArray.clone(); newArray[Panose.Field.LETTERFORM.getIndex()] = Panose.LETTERFORM_MIN_ITALIC; return Panose.forceInstance(newArray); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy