001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.imaging.formats.jpeg.segments;
018
019import static org.apache.commons.imaging.common.BinaryFunctions.read2Bytes;
020import static org.apache.commons.imaging.common.BinaryFunctions.readByte;
021
022import java.io.ByteArrayInputStream;
023import java.io.IOException;
024import java.io.InputStream;
025import java.util.logging.Level;
026import java.util.logging.Logger;
027
028import org.apache.commons.imaging.ImagingException;
029import org.apache.commons.imaging.common.Allocator;
030import org.apache.commons.imaging.formats.jpeg.JpegConstants;
031
032public final class SofnSegment extends AbstractSegment {
033
034    public static class Component {
035        static final int SHALLOW_SIZE = 32;
036        public final int componentIdentifier;
037        public final int horizontalSamplingFactor;
038        public final int verticalSamplingFactor;
039        public final int quantTabDestSelector;
040
041        public Component(final int componentIdentifier, final int horizontalSamplingFactor, final int veritcalSamplingFactor, final int quantTabDestSelector) {
042            this.componentIdentifier = componentIdentifier;
043            this.horizontalSamplingFactor = horizontalSamplingFactor;
044            this.verticalSamplingFactor = veritcalSamplingFactor;
045            this.quantTabDestSelector = quantTabDestSelector;
046        }
047    }
048
049    private static final Logger LOGGER = Logger.getLogger(SofnSegment.class.getName());
050    public final int width;
051    public final int height;
052    public final int numberOfComponents;
053    public final int precision;
054
055    private final Component[] components;
056
057    public SofnSegment(final int marker, final byte[] segmentData) throws IOException, ImagingException {
058        this(marker, segmentData.length, new ByteArrayInputStream(segmentData));
059    }
060
061    public SofnSegment(final int marker, final int markerLength, final InputStream is) throws IOException, ImagingException {
062        super(marker, markerLength);
063
064        if (LOGGER.isLoggable(Level.FINEST)) {
065            LOGGER.finest("SOF0Segment markerLength: " + markerLength);
066        }
067
068        precision = readByte("precision", is, "Not a Valid JPEG File");
069        height = read2Bytes("height", is, "Not a Valid JPEG File", getByteOrder());
070        width = read2Bytes("width", is, "Not a Valid JPEG File", getByteOrder());
071        numberOfComponents = readByte("numberOfComponents", is, "Not a Valid JPEG File");
072        if (numberOfComponents < 0) {
073            throw new ImagingException("The number of components in a SOF0Segment cannot be less than 0!");
074        }
075        components = Allocator.array(numberOfComponents, Component[]::new, Component.SHALLOW_SIZE);
076        for (int i = 0; i < numberOfComponents; i++) {
077            final int componentIdentifier = readByte("ComponentIdentifier", is, "Not a Valid JPEG File");
078
079            final int hvSamplingFactors = readByte("SamplingFactors", is, "Not a Valid JPEG File");
080            final int horizontalSamplingFactor = hvSamplingFactors >> 4 & 0xf;
081            final int verticalSamplingFactor = hvSamplingFactors & 0xf;
082            final int quantTabDestSelector = readByte("QuantTabDestSel", is, "Not a Valid JPEG File");
083            components[i] = new Component(componentIdentifier, horizontalSamplingFactor, verticalSamplingFactor, quantTabDestSelector);
084        }
085    }
086
087    /**
088     * Returns a copy of all the components.
089     *
090     * @return the components
091     */
092    public Component[] getComponents() {
093        return components.clone();
094    }
095
096    /**
097     * Returns the component at the specified index.
098     *
099     * @param index the array index
100     * @return the component
101     */
102    public Component getComponents(final int index) {
103        return components[index];
104    }
105
106    @Override
107    public String getDescription() {
108        return "SOFN (SOF" + (marker - JpegConstants.SOF0_MARKER) + ") (" + getSegmentType() + ")";
109    }
110
111}