| /** |
| * 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.pdfbox.jbig2.segments; |
| |
| import java.awt.Rectangle; |
| import java.io.IOException; |
| import java.util.ArrayList; |
| |
| import org.apache.pdfbox.jbig2.Bitmap; |
| import org.apache.pdfbox.jbig2.Dictionary; |
| import org.apache.pdfbox.jbig2.SegmentHeader; |
| import org.apache.pdfbox.jbig2.err.InvalidHeaderValueException; |
| import org.apache.pdfbox.jbig2.image.Bitmaps; |
| import org.apache.pdfbox.jbig2.io.SubInputStream; |
| import org.apache.pdfbox.jbig2.util.log.Logger; |
| import org.apache.pdfbox.jbig2.util.log.LoggerFactory; |
| |
| /** |
| * This class represents the segment type "Pattern dictionary", 7.4.4. |
| */ |
| public class PatternDictionary implements Dictionary |
| { |
| |
| private final Logger log = LoggerFactory.getLogger(PatternDictionary.class); |
| |
| private SubInputStream subInputStream; |
| |
| /** Segment data structure (only necessary if MMR is used) */ |
| private long dataHeaderOffset; |
| private long dataHeaderLength; |
| private long dataOffset; |
| private long dataLength; |
| |
| private short[] gbAtX = null; |
| private short[] gbAtY = null; |
| |
| /** Pattern dictionary flags, 7.4.4.1.1 */ |
| private boolean isMMREncoded; |
| private byte hdTemplate; |
| |
| /** Width of the patterns in the pattern dictionary, 7.4.4.1.2 */ |
| private short hdpWidth; |
| |
| /** Height of the patterns in the pattern dictionary, 7.4.4.1.3 */ |
| private short hdpHeight; |
| |
| /** Decoded bitmaps, stored to be used by segments, that refer to it */ |
| private ArrayList<Bitmap> patterns; |
| |
| /** |
| * Largest gray-scale value, 7.4.4.1.4 |
| * |
| * Value: one less than the number of patterns defined in this pattern dictionary |
| */ |
| private int grayMax; |
| |
| private void parseHeader() throws IOException, InvalidHeaderValueException |
| { |
| /* Bit 3-7 */ |
| subInputStream.readBits(5); // Dirty read ... |
| |
| /* Bit 1-2 */ |
| readTemplate(); |
| |
| /* Bit 0 */ |
| readIsMMREncoded(); |
| |
| readPatternWidthAndHeight(); |
| |
| readGrayMax(); |
| |
| /* Segment data structure */ |
| computeSegmentDataStructure(); |
| |
| this.checkInput(); |
| } |
| |
| private void readTemplate() throws IOException |
| { |
| /* Bit 1-2 */ |
| hdTemplate = (byte) subInputStream.readBits(2); |
| } |
| |
| private void readIsMMREncoded() throws IOException |
| { |
| /* Bit 0 */ |
| if (subInputStream.readBit() == 1) |
| { |
| isMMREncoded = true; |
| } |
| } |
| |
| private void readPatternWidthAndHeight() throws IOException |
| { |
| hdpWidth = subInputStream.readByte(); |
| hdpHeight = subInputStream.readByte(); |
| } |
| |
| private void readGrayMax() throws IOException |
| { |
| grayMax = (int) (subInputStream.readBits(32) & 0xffffffff); |
| } |
| |
| private void computeSegmentDataStructure() throws IOException |
| { |
| dataOffset = subInputStream.getStreamPosition(); |
| dataHeaderLength = dataOffset - dataHeaderOffset; |
| dataLength = subInputStream.length() - dataHeaderLength; |
| } |
| |
| private void checkInput() throws InvalidHeaderValueException |
| { |
| if (hdpHeight < 1 || hdpWidth < 1) |
| { |
| throw new InvalidHeaderValueException("Width/Heigth must be greater than zero."); |
| } |
| |
| if (isMMREncoded) |
| { |
| if (hdTemplate != 0) |
| { |
| log.info("hdTemplate should contain the value 0"); |
| } |
| } |
| } |
| |
| /** |
| * This method decodes a pattern dictionary segment and returns an array of {@link Bitmap} s. Each of this |
| * {@link Bitmap}s is a pattern.<br> |
| * The procedure is described in 6.7.5 (page 43). |
| * |
| * @return An array of {@link Bitmap}s as result of the decoding procedure. |
| */ |
| public ArrayList<Bitmap> getDictionary() throws IOException, InvalidHeaderValueException |
| { |
| if (null == patterns) |
| { |
| |
| if (!isMMREncoded) |
| { |
| setGbAtPixels(); |
| } |
| |
| // 2) |
| final GenericRegion genericRegion = new GenericRegion(subInputStream); |
| genericRegion.setParameters(isMMREncoded, dataOffset, dataLength, hdpHeight, |
| (grayMax + 1) * hdpWidth, hdTemplate, false, false, gbAtX, gbAtY); |
| |
| final Bitmap collectiveBitmap = genericRegion.getRegionBitmap(); |
| |
| // 4) |
| extractPatterns(collectiveBitmap); |
| } |
| |
| return patterns; |
| } |
| |
| private void extractPatterns(Bitmap collectiveBitmap) |
| { |
| // 3) |
| int gray = 0; |
| patterns = new ArrayList<Bitmap>(grayMax + 1); |
| |
| // 4) |
| while (gray <= grayMax) |
| { |
| // 4) a) Retrieve a pattern bitmap by extracting it out of the collective bitmap |
| final Rectangle roi = new Rectangle(hdpWidth * gray, 0, hdpWidth, hdpHeight); |
| final Bitmap patternBitmap = Bitmaps.extract(roi, collectiveBitmap); |
| patterns.add(patternBitmap); |
| |
| // 4) b) |
| gray++; |
| } |
| } |
| |
| private void setGbAtPixels() |
| { |
| if (hdTemplate == 0) |
| { |
| gbAtX = new short[4]; |
| gbAtY = new short[4]; |
| gbAtX[0] = (short) -hdpWidth; |
| gbAtY[0] = 0; |
| gbAtX[1] = -3; |
| gbAtY[1] = -1; |
| gbAtX[2] = 2; |
| gbAtY[2] = -2; |
| gbAtX[3] = -2; |
| gbAtY[3] = -2; |
| |
| } |
| else |
| { |
| gbAtX = new short[1]; |
| gbAtY = new short[1]; |
| gbAtX[0] = (short) -hdpWidth; |
| gbAtY[0] = 0; |
| } |
| } |
| |
| public void init(SegmentHeader header, SubInputStream sis) |
| throws InvalidHeaderValueException, IOException |
| { |
| this.subInputStream = sis; |
| parseHeader(); |
| } |
| |
| protected boolean isMMREncoded() |
| { |
| return isMMREncoded; |
| } |
| |
| protected byte getHdTemplate() |
| { |
| return hdTemplate; |
| } |
| |
| protected short getHdpWidth() |
| { |
| return hdpWidth; |
| } |
| |
| protected short getHdpHeight() |
| { |
| return hdpHeight; |
| } |
| |
| protected int getGrayMax() |
| { |
| return grayMax; |
| } |
| } |