Example usage for org.apache.pdfbox.cos COSArray toList

List of usage examples for org.apache.pdfbox.cos COSArray toList

Introduction

In this page you can find the example usage for org.apache.pdfbox.cos COSArray toList.

Prototype

public List<? extends COSBase> toList() 

Source Link

Document

Return contents of COSArray as a Java List.

Usage

From source file:com.esri.geoportal.commons.pdf.PdfUtils.java

License:Apache License

/**
 * Extracts the geospatial metadata from a GeoPDF
 * //from  w  ww.  j  a v a2s  .  c o  m
 * @param page the PDF page to read geospatial metadata from
 * @param geometryServiceUrl url of a <a href="https://developers.arcgis.com/rest/services-reference/geometry-service.htm">geometry service</a> for reprojecting coordinates. 
 * 
 * @see <a href="https://www.loc.gov/preservation/digital/formats/fdd/fdd000312.shtml">Library of Congress information on GeoPDF</a>
 * @see <a href="https://www.adobe.com/content/dam/acom/en/devnet/pdf/pdfs/PDF32000_2008.pdf">The PDF specification</a>, section 8, for instructions for translating coordinates.
 * 
 * @returns the bounding box of the GeoPDF as "yMin xMin, yMax xMax"
 */
private static String extractGeoPDFProps(PDPage page, String geometryServiceUrl) {

    // The LGI dictionary is an array, we'll loop through all entries and pull the first one for a bounding box
    COSArray lgi = (COSArray) page.getCOSObject().getDictionaryObject("LGIDict");

    List<String> bBoxes = new ArrayList<>();

    lgi.iterator().forEachRemaining(item -> {

        String currentBbox = null;

        // Set up the Coordinate Transformation Matrix (used to translate PDF coords to geo coords)
        Double[][] ctmValues = null;

        COSDictionary dictionary = (COSDictionary) item;
        if (dictionary.containsKey("CTM")) {
            ctmValues = new Double[3][3];

            // The last column in the matrix is always constant
            ctmValues[0][2] = 0.0;
            ctmValues[1][2] = 0.0;
            ctmValues[2][2] = 1.0;

            COSArray ctm = (COSArray) dictionary.getDictionaryObject("CTM");
            for (int i = 0; i < ctm.toList().size(); i += 2) {
                int ctmRow = i / 2;
                ctmValues[ctmRow][0] = Double.parseDouble(((COSString) ctm.get(i)).getString());
                ctmValues[ctmRow][1] = Double.parseDouble(((COSString) ctm.get(i + 1)).getString());
            }
        }

        // Get the neatline (i.e. the bounding box in *PDF* coordinates)
        Double[][] neatLineValues = null;
        int neatLineLength = 0;
        if (dictionary.containsKey("Neatline")) {

            COSArray neatline = (COSArray) dictionary.getDictionaryObject("Neatline");
            neatLineLength = neatline.toList().size();
            neatLineValues = new Double[neatLineLength / 2][3];

            for (int i = 0; i < neatline.toList().size(); i += 2) {
                int neatLineRow = i / 2;
                neatLineValues[neatLineRow][0] = Double.parseDouble(((COSString) neatline.get(i)).getString());
                neatLineValues[neatLineRow][1] = Double
                        .parseDouble(((COSString) neatline.get(i + 1)).getString());
                neatLineValues[neatLineRow][2] = 1.0;
            }
        }

        // Translate the PDF coordinates to Geospatial coordintates by multiplying the two matricies
        MultiPoint mp = new MultiPoint();
        if (ctmValues != null && neatLineValues != null) {
            Double[][] resultCoords = new Double[neatLineLength / 2][3];
            for (int z = 0; z < neatLineLength / 2; z++) {
                for (int i = 0; i < 3; i++) {
                    resultCoords[z][i] = neatLineValues[z][0] * ctmValues[0][i]
                            + neatLineValues[z][1] * ctmValues[1][i] + neatLineValues[z][2] * ctmValues[2][i];
                }
                mp.add(resultCoords[z][0], resultCoords[z][1]);
            }
        }

        // Project the geospatial coordinates to WGS84 for the Dublin-Core metadata
        if (dictionary.containsKey("Projection")) {
            COSDictionary projectionDictionary = (COSDictionary) dictionary.getDictionaryObject("Projection");
            String projectionType = projectionDictionary.getString("ProjectionType");

            try (GeometryService svc = new GeometryService(HttpClients.custom().useSystemProperties().build(),
                    new URL(geometryServiceUrl));) {

                // UTM projections require slightly different processing
                if ("UT".equals(projectionType)) {
                    String zone = Integer.toString(projectionDictionary.getInt("Zone"));
                    String hemisphere = projectionDictionary.getString("Hemisphere");

                    // Get the wkt for the geospatial coordinate system
                    String wkt = datumTranslation(projectionDictionary.getItem("Datum"));

                    if (zone != null && hemisphere != null && wkt != null) {
                        // Generate a list of UTM strings
                        List<String> utmCoords = new ArrayList<>();
                        for (Point2D pt : mp.getCoordinates2D()) {
                            String coord = String.format("%s%s %s %s", zone, hemisphere, Math.round(pt.x),
                                    Math.round(pt.y));
                            utmCoords.add(coord);
                        }

                        MultiPoint reproj = svc.fromGeoCoordinateString(utmCoords, WGS84_WKID);

                        currentBbox = generateBbox(reproj);

                    } else {
                        LOG.warn("Missing UTM argument: zone: {}, hemisphere: {}, datum: {}", zone, hemisphere,
                                wkt);
                        LOG.debug("Projection dictionary {}", projectionDictionary);
                    }
                } else {
                    // Generate Well Known Text for projection and re-projects the points to WGS 84
                    String wkt = getProjectionWKT(projectionDictionary, projectionType);

                    if (wkt != null) {
                        MultiPoint reproj = svc.project(mp, wkt, WGS84_WKID);

                        currentBbox = generateBbox(reproj);

                    } else if (LOG.isDebugEnabled()) {
                        // Print out translated coordinates for debugging purposes
                        LOG.debug("Translated Coordinates");
                        for (Point2D pt : mp.getCoordinates2D()) {
                            LOG.debug(String.format("\t%s, %s", pt.x, pt.y));
                        }
                    }
                }
            } catch (Exception e) {
                // If something goes wrong, just try the next set of coordinates
                LOG.error("Exception reprojecting geometry, skipping this geopdf dictionary instance...", e);
            }
        }

        if (currentBbox != null) {
            bBoxes.add(currentBbox);
        }

    });

    return bBoxes.get(0);
}

From source file:net.padaf.preflight.font.SimpleFontValidator.java

License:Apache License

/**
 * Check if the widths array contains integer and if its length is valid. If
 * the validation fails, the FontContainer is updated.
 * /* w ww  . j a va2  s  .  co m*/
 * @param cDoc
 */
protected boolean checkWidthsArray(COSDocument cDoc) {
    // ---- the Widths value can be a reference to an object
    // ---- Access the object using the COSkey
    COSArray wArr = COSUtils.getAsArray(this.widths, cDoc);

    if (wArr == null) {
        this.fontContainer.addError(
                new ValidationError(ERROR_FONTS_DICTIONARY_INVALID, "The Witdhs array is unreachable"));
        return false;
    }

    // ---- firstChar and lastChar must be integer.
    int fc = ((COSInteger) this.firstChar).intValue();
    int lc = ((COSInteger) this.lastChar).intValue();

    // ---- wArr length = (lc - fc) +1 and it is an array of int.
    // ---- If FirstChar is greater than LastChar, the validation will fail
    // because of
    // ---- the array will have an expected size <= 0.
    int expectedLength = (lc - fc) + 1;
    if (wArr.size() != expectedLength) {
        this.fontContainer.addError(new ValidationError(ERROR_FONTS_DICTIONARY_INVALID,
                "The length of Witdhs array is invalid. Expected : \"" + expectedLength + "\" Current : \""
                        + wArr.size() + "\""));
        return false;
    }

    for (Object arrContent : wArr.toList()) {
        boolean isInt = false;
        if (arrContent instanceof COSBase) {
            isInt = COSUtils.isInteger((COSBase) arrContent, cDoc);
        }

        if (!isInt) {
            this.fontContainer.addError(new ValidationError(ERROR_FONTS_DICTIONARY_INVALID,
                    "The Witdhs array is invalid. (some element aren't integer)"));
            return false;
        }
    }

    return true;
}

From source file:net.padaf.preflight.font.TrueTypeFontValidator.java

License:Apache License

/**
 * This method checks the metric consistency. If the validation fails, the
 * FontContainer is updated. If the validation is a success, the
 * FontContainer.cidKnownByFont map is updated.
 * /*from  w  ww.j  av  a 2 s. com*/
 * @param ttf
 * @return
 * @throws IOException
 */
protected boolean checkFontMetrics(TrueTypeFont ttf) throws IOException, ValidationException {

    int firstChar = pFont.getFirstChar();
    float defaultGlyphWidth = this.pFontDesc.getMissingWidth();

    List<?> pdfWidths = this.pFont.getWidths();
    COSArray widths = null;
    if (pdfWidths instanceof COSArrayList) {
        widths = ((COSArrayList) pdfWidths).toList();
    } else {
        widths = ((COSArray) pdfWidths);
    }

    ((TrueTypeFontContainer) this.fontContainer).setWidthsArray(widths.toList());
    ((TrueTypeFontContainer) this.fontContainer).setFirstCharInWidthsArray(firstChar);
    ((TrueTypeFontContainer) this.fontContainer).setDefaultGlyphWidth(defaultGlyphWidth);
    ((TrueTypeFontContainer) this.fontContainer).setFontObjectAndInitializeInnerFields(ttf);
    ((TrueTypeFontContainer) this.fontContainer).setCMap(getCMapOfFontProgram(ttf));

    return true;
}

From source file:net.padaf.preflight.font.Type1FontValidator.java

License:Apache License

/**
 * Type1C is a CFF font format, extract all CFFFont object from the stream
 * /* ww w.j  av a2s  .com*/
 * @param fontStream
 * @return
 * @throws ValidationException
 */
protected boolean checkCIDFontWidths(PDStream fontStream) throws ValidationException {
    try {
        CFFParser cffParser = new CFFParser();
        List<CFFFont> lCFonts = cffParser.parse(fontStream.getByteArray());

        if (lCFonts == null || lCFonts.isEmpty()) {
            this.fontContainer.addError(new ValidationResult.ValidationError(ERROR_FONTS_CID_DAMAGED,
                    "The FontFile can't be read"));
            return false;
        }

        ((Type1FontContainer) this.fontContainer).setCFFFontObjects(lCFonts);

        List<?> pdfWidths = this.pFont.getWidths();
        int firstChar = pFont.getFirstChar();
        float defaultGlyphWidth = pFontDesc.getMissingWidth();

        COSArray widths = null;
        if (pdfWidths instanceof COSArrayList) {
            widths = ((COSArrayList) pdfWidths).toList();
        } else {
            widths = ((COSArray) pdfWidths);
        }

        ((Type1FontContainer) this.fontContainer).setWidthsArray(widths.toList());
        ((Type1FontContainer) this.fontContainer).setFirstCharInWidthsArray(firstChar);
        ((Type1FontContainer) this.fontContainer).setDefaultGlyphWidth(defaultGlyphWidth);

        return true;
    } catch (IOException e) {
        this.fontContainer.addError(
                new ValidationResult.ValidationError(ERROR_FONTS_CID_DAMAGED, "The FontFile can't be read"));
        return false;
    }
}

From source file:net.padaf.preflight.font.Type1FontValidator.java

License:Apache License

/**
 * This method checks the metric consistency and adds the FontContainer in the
 * DocumentHandler./*ww  w  . j a  v a 2s  . co  m*/
 * 
 * @param fontStream
 * @return
 * @throws ValidationException
 */
protected boolean checkFontMetricsDataAndFeedFontContainer(PDStream fontStream) throws ValidationException {
    try {

        // ---- Parse the Type1 Font program
        ByteArrayInputStream bis = new ByteArrayInputStream(fontStream.getByteArray());
        COSStream streamObj = fontStream.getStream();
        int length1 = streamObj.getInt(COSName.getPDFName(FONT_DICTIONARY_KEY_LENGTH1));
        int length2 = streamObj.getInt(COSName.getPDFName(FONT_DICTIONARY_KEY_LENGTH2));

        Type1Parser parserForMetrics = Type1Parser.createParserWithEncodingObject(bis, length1, length2,
                pFont.getFontEncoding());
        Type1 parsedData = parserForMetrics.parse();

        ((Type1FontContainer) this.fontContainer).setFontObject(parsedData);

        List<?> pdfWidths = this.pFont.getWidths();
        int firstChar = pFont.getFirstChar();
        float defaultGlyphWidth = pFontDesc.getMissingWidth();

        COSArray widths = null;
        if (pdfWidths instanceof COSArrayList) {
            widths = ((COSArrayList) pdfWidths).toList();
        } else {
            widths = ((COSArray) pdfWidths);
        }

        ((Type1FontContainer) this.fontContainer).setWidthsArray(widths.toList());
        ((Type1FontContainer) this.fontContainer).setFirstCharInWidthsArray(firstChar);
        ((Type1FontContainer) this.fontContainer).setDefaultGlyphWidth(defaultGlyphWidth);

        return true;
    } catch (IOException e) {
        throw new ValidationException("Unable to check Type1 metrics due to : " + e.getMessage(), e);
    }
}

From source file:net.padaf.preflight.helpers.TrailerValidationHelper.java

License:Apache License

/**
 * Return true if the ID of the first dictionary is the same as the id of the
 * last dictionary Return false otherwise.
 * /*from  w  w w .j  av a  2 s .  c o  m*/
 * @param first
 * @param last
 * @return
 */
protected boolean compareIds(COSDictionary first, COSDictionary last, COSDocument doc) {
    COSBase idFirst = first.getItem(COSName.getPDFName(TRAILER_DICTIONARY_KEY_ID));
    COSBase idLast = last.getItem(COSName.getPDFName(TRAILER_DICTIONARY_KEY_ID));

    if (idFirst == null || idLast == null) {
        return false;
    }

    // ---- cast two COSBase to COSArray.
    COSArray af = COSUtils.getAsArray(idFirst, doc);
    COSArray al = COSUtils.getAsArray(idLast, doc);

    // ---- if one COSArray is null, the PDF/A isn't valid
    if ((af == null) || (al == null)) {
        return false;
    }

    // ---- compare both arrays
    boolean isEqual = true;
    for (Object of : af.toList()) {
        boolean oneIsEquals = false;
        for (Object ol : al.toList()) {
            // ---- according to PDF Reference 1-4, ID is an array containing two
            // strings
            if (!oneIsEquals)
                oneIsEquals = ((COSString) ol).getString().equals(((COSString) of).getString());
        }
        isEqual = isEqual && oneIsEquals;
    }
    return isEqual;
}