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

com.itextpdf.io.font.CMapEncoding Maven / Gradle / Ivy

There is a newer version: 9.0.0
Show newest version
/*
    This file is part of the iText (R) project.
    Copyright (c) 1998-2023 Apryse Group NV
    Authors: Apryse Software.

    This program is offered under a commercial and under the AGPL license.
    For commercial licensing, contact us at https://itextpdf.com/sales.  For AGPL licensing, see below.

    AGPL licensing:
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 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; 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 this program.  If not, see .
 */
package com.itextpdf.io.font;

import com.itextpdf.io.font.cmap.CMapCidToCodepoint;
import com.itextpdf.io.font.cmap.CMapCodepointToCid;
import com.itextpdf.io.font.cmap.CMapLocationFromBytes;
import com.itextpdf.io.font.cmap.CMapParser;
import com.itextpdf.io.logs.IoLogMessageConstant;
import com.itextpdf.io.source.ByteBuffer;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import org.slf4j.LoggerFactory;

public class CMapEncoding {

    private static final List IDENTITY_H_V_CODESPACE_RANGES = Arrays.asList(new byte[] {0, 0}, new byte[] {(byte)0xff, (byte)0xff});

    private final String cmap;
    private String uniMap;

    // true if CMap is Identity-H/V
    private boolean isDirect;

    private CMapCidToCodepoint cid2Code;

    private CMapCodepointToCid code2Cid;

    private List codeSpaceRanges;

    /**
     *
     * @param cmap CMap name.
     */
    public CMapEncoding(String cmap) {
        this.cmap = cmap;
        if (cmap.equals(PdfEncodings.IDENTITY_H) || cmap.equals(PdfEncodings.IDENTITY_V)) {
            isDirect = true;
        }
        // Actually this constructor is only called for Identity-H/V cmaps currently.
        // Even for hypothetical case of non-Identity-H/V, let's use Identity-H/V ranges (two byte ranges) for compatibility with previous behavior
        this.codeSpaceRanges = IDENTITY_H_V_CODESPACE_RANGES;
    }

    /**
     *
     * @param cmap CMap name.
     * @param uniMap CMap to convert Unicode value to CID.
     */
    public CMapEncoding(String cmap, String uniMap) {
        this.cmap = cmap;
        this.uniMap = uniMap;
        if (cmap.equals(PdfEncodings.IDENTITY_H) || cmap.equals(PdfEncodings.IDENTITY_V)) {
            isDirect = true;
            this.codeSpaceRanges = IDENTITY_H_V_CODESPACE_RANGES;
        } else {
            cid2Code = FontCache.getCidToCodepointCmap(cmap);
            code2Cid = CMapEncoding.getCodeToCidCmap(cmap, cid2Code);
            this.codeSpaceRanges = cid2Code.getCodeSpaceRanges();
        }
    }

    public CMapEncoding(String cmap, byte[] cmapBytes) {
        this.cmap = cmap;
        cid2Code = new CMapCidToCodepoint();
        try {
            CMapParser.parseCid(cmap, cid2Code, new CMapLocationFromBytes(cmapBytes));
            code2Cid = CMapEncoding.getCodeToCidCmap(cmap, cid2Code);
            this.codeSpaceRanges = cid2Code.getCodeSpaceRanges();
        } catch (IOException e) {
            LoggerFactory.getLogger(getClass()).error(IoLogMessageConstant.FAILED_TO_PARSE_ENCODING_STREAM);
        }
    }

    public boolean isDirect() {
        return isDirect;
    }

    public boolean hasUniMap() {
        return uniMap != null && uniMap.length() > 0;
    }

    public String getRegistry() {
        if (isDirect()) {
            return "Adobe";
        } else {
            return cid2Code.getRegistry();
        }
    }

    public String getOrdering() {
        if (isDirect()) {
            return "Identity";
        } else {
            return cid2Code.getOrdering();
        }
    }

    public int getSupplement() {
        if (isDirect()) {
            return 0;
        } else {
            return cid2Code.getSupplement();
        }
    }

    public String getUniMapName() {
        return uniMap;
    }

    public String getCmapName() {
        return cmap;
    }

    /**
     * Checks whether the {@link CMapEncoding} was built with corresponding cmap name.
     *
     * @param cmap a CMAP
     * @return true, if the CMapEncoding was built with the cmap. Otherwise false.
     */
    public boolean isBuiltWith(String cmap) {
        return Objects.equals(cmap, this.cmap);
    }

    public byte[] getCmapBytes(int cid) {
        int length = getCmapBytesLength(cid);
        byte[] result = new byte[length];
        fillCmapBytes(cid, result, 0);
        return result;
    }

    public int fillCmapBytes(int cid, byte[] array, int offset) {
        if (isDirect) {
            array[offset++] = (byte)((cid & 0xff00) >> 8);
            array[offset++] = (byte)(cid & 0xff);
        } else {
            byte[] bytes = cid2Code.lookup(cid);
            for (int i = 0; i < bytes.length; i++) {
                array[offset++] = bytes[i];
            }
        }
        return offset;
    }

    public void fillCmapBytes(int cid, ByteBuffer buffer) {
        if (isDirect) {
            buffer.append((byte)((cid & 0xff00) >> 8));
            buffer.append((byte)(cid & 0xff));
        } else {
            byte[] bytes = cid2Code.lookup(cid);
            buffer.append(bytes);
        }
    }

    public int getCmapBytesLength(int cid) {
        if (isDirect) {
            return 2;
        } else {
            return cid2Code.lookup(cid).length;
        }
    }

    public int getCidCode(int cmapCode) {
        if (isDirect) {
            return cmapCode;
        } else {
            return code2Cid.lookup(cmapCode);
        }
    }

    public List getCodeSpaceRanges() {
        return codeSpaceRanges;
    }

    private static CMapCodepointToCid getCodeToCidCmap(String cmap, CMapCidToCodepoint cid2Code) {
        try {
            return FontCache.getCodepointToCidCmap(cmap);
        } catch (com.itextpdf.io.exceptions.IOException ex) {
            // if not found, fall back to reversing
            return new CMapCodepointToCid(cid2Code);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy