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.readByte;
020
021import java.io.ByteArrayInputStream;
022import java.io.IOException;
023import java.io.InputStream;
024import java.util.logging.Level;
025import java.util.logging.Logger;
026
027public class SosSegment extends Segment {
028
029    private static final Logger LOGGER = Logger.getLogger(SosSegment.class.getName());
030
031    public final int numberOfComponents;
032    private final Component[] components;
033    public final int startOfSpectralSelection;
034    public final int endOfSpectralSelection;
035    public final int successiveApproximationBitHigh;
036    public final int successiveApproximationBitLow;
037
038    public static class Component {
039        public final int scanComponentSelector;
040        public final int dcCodingTableSelector;
041        public final int acCodingTableSelector;
042
043        public Component(final int scanComponentSelector, final int dcCodingTableSelector,
044                final int acCodingTableSelector) {
045            this.scanComponentSelector = scanComponentSelector;
046            this.dcCodingTableSelector = dcCodingTableSelector;
047            this.acCodingTableSelector = acCodingTableSelector;
048        }
049    }
050
051    public SosSegment(final int marker, final byte[] segmentData) throws IOException {
052        this(marker, segmentData.length, new ByteArrayInputStream(segmentData));
053    }
054
055    public SosSegment(final int marker, final int markerLength, final InputStream is) throws IOException {
056        super(marker, markerLength);
057
058        if (LOGGER.isLoggable(Level.FINEST)) {
059            LOGGER.finest("SosSegment marker_length: " + markerLength);
060        }
061
062        // Debug.debug("SOS", marker_length);
063
064        numberOfComponents = readByte("number_of_components_in_scan", is,
065                "Not a Valid JPEG File");
066        // Debug.debug("number_of_components_in_scan",
067        // numberOfComponents);
068
069        components = new Component[numberOfComponents];
070        for (int i = 0; i < numberOfComponents; i++) {
071            final int scanComponentSelector = readByte("scanComponentSelector", is, "Not a Valid JPEG File");
072            // Debug.debug("scanComponentSelector", scanComponentSelector);
073
074            final int acDcEntropyCodingTableSelector = readByte(
075                    "acDcEntropyCodingTableSelector", is,
076                    "Not a Valid JPEG File");
077            // Debug.debug("ac_dc_entrooy_coding_table_selector",
078            // acDcEntropyCodingTableSelector);
079
080            final int dcCodingTableSelector = (acDcEntropyCodingTableSelector >> 4) & 0xf;
081            final int acCodingTableSelector = acDcEntropyCodingTableSelector & 0xf;
082            components[i] = new Component(scanComponentSelector,
083                    dcCodingTableSelector, acCodingTableSelector);
084        }
085
086        startOfSpectralSelection = readByte("start_of_spectral_selection", is,
087                "Not a Valid JPEG File");
088        // Debug.debug("start_of_spectral_selection", startOfSpectralSelection);
089        endOfSpectralSelection = readByte("end_of_spectral_selection", is,
090                "Not a Valid JPEG File");
091        // Debug.debug("end_of_spectral_selection", endOfSpectralSelection);
092        final int successiveApproximationBitPosition = readByte(
093                "successive_approximation_bit_position", is,
094                "Not a Valid JPEG File");
095        // Debug.debug("successive_approximation_bit_position",
096        // successive_approximation_bit_position);
097        successiveApproximationBitHigh = (successiveApproximationBitPosition >> 4) & 0xf;
098        successiveApproximationBitLow = successiveApproximationBitPosition & 0xf;
099    }
100
101    /**
102     * Returns a copy of all the components.
103     * @return all the components
104     */
105    public Component[] getComponents() {
106        return components.clone();
107    }
108
109    /**
110     * Return a component at the specified index.
111     * @param index the component index
112     * @return the component
113     */
114    public Component getComponents(final int index) {
115        return components[index];
116    }
117
118    @Override
119    public String getDescription() {
120        return "SOS (" + getSegmentType() + ")";
121    }
122
123}