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