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

org.sejda.sambox.pdmodel.font.FontUtils Maven / Gradle / Ivy

Go to download

An Apache PDFBox fork intended to be used as PDF processor for Sejda and PDFsam related projects

There is a newer version: 3.0.21
Show newest version
/*
 * 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.sejda.sambox.pdmodel.font;

import static java.util.Optional.ofNullable;

import java.io.IOException;
import java.util.Map;

import org.apache.fontbox.ttf.OS2WindowsMetricsTable;
import org.apache.fontbox.ttf.TrueTypeFont;

/**
 * @author Andrea Vacondio
 */
public final class FontUtils
{
    private static final String BASE25 = "BCDEFGHIJKLMNOPQRSTUVWXYZ";

    private FontUtils()
    {
        // util
    }

    /**
     * @return true if the fsType in the OS/2 table permits embedding.
     */
    public static boolean isEmbeddingPermitted(TrueTypeFont ttf) throws IOException
    {
        if (ttf.getOS2Windows() != null)
        {
            int fsType = ttf.getOS2Windows().getFsType();

            int maskedFsType = fsType & 0x000F;
            // PDFBOX-5191: don't check the bit because permissions are exclusive
            if (maskedFsType == OS2WindowsMetricsTable.FSTYPE_RESTRICTED)
            {
                // restricted License embedding
                return false;
            }
            // bitmap embedding only
            return (fsType & OS2WindowsMetricsTable.FSTYPE_BITMAP_ONLY)
                    != OS2WindowsMetricsTable.FSTYPE_BITMAP_ONLY;
        }
        return true;
    }

    /**
     * @return true if the fsType in the OS/2 table permits subsetting.
     */
    public static boolean isSubsettingPermitted(TrueTypeFont ttf) throws IOException
    {
        if (ttf.getOS2Windows() != null)
        {
            int fsType = ttf.getOS2Windows().getFsType();
            return (fsType & OS2WindowsMetricsTable.FSTYPE_NO_SUBSETTING)
                    != OS2WindowsMetricsTable.FSTYPE_NO_SUBSETTING;
        }
        return true;
    }

    /**
     * @return an uppercase 6-character unique tag for the given subset.
     */
    public static String getTag(Map gidToCid)
    {
        // deterministic
        long num = gidToCid.hashCode();

        // base25 encode
        StringBuilder sb = new StringBuilder();
        do
        {
            long div = num / 25;
            int mod = (int) (num % 25);
            sb.append(BASE25.charAt(mod));
            num = div;
        } while (num != 0 && sb.length() < 6);

        // pad
        while (sb.length() < 6)
        {
            sb.insert(0, 'A');
        }

        return sb.append('+').toString();
    }

    /**
     * @return an uppercase 6-character unique tag randomly created
     */
    public static String getTag()
    {
        StringBuilder sb = new StringBuilder();
        for (int k = 0; k < 6; ++k)
        {
            sb.append((char) (Math.random() * 26 + 'A'));
        }
        return sb.append('+').toString();
    }

    /**
     * @param name a font name
     * @return true if the name denotes a subset font Ex. ABCDEF+Verdana
     */
    public static boolean isSubsetFontName(String name)
    {
        String[] nameFragments = ofNullable(name).map(String::trim).map(s -> s.split("\\+"))
                .orElseGet(() -> new String[0]);
        return (nameFragments.length == 2 && nameFragments[0].length() == 6);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy