public void visitSos()

in src/main/java/org/apache/commons/imaging/formats/jpeg/decoder/JpegDecoder.java [416:547]


    public void visitSos(final int marker, final byte[] markerBytes, final byte[] imageData) {
        try (ByteArrayInputStream is = new ByteArrayInputStream(imageData)) {
            // read the scan header
            final int segmentLength = read2Bytes("segmentLength", is,"Not a Valid JPEG File", getByteOrder());
            final byte[] sosSegmentBytes = readBytes("SosSegment", is, segmentLength - 2, "Not a Valid JPEG File");
            sosSegment = new SosSegment(marker, sosSegmentBytes);
            // read the payload of the scan, this is the remainder of image data after the header
            // the payload contains the entropy-encoded segments (or ECS) divided by RST markers
            // or only one ECS if the entropy-encoded data is not divided by RST markers
            // length of payload = length of image data - length of data already read
            final int[] scanPayload = Allocator.intArray(imageData.length - segmentLength);
            int payloadReadCount = 0;
            while (payloadReadCount < scanPayload.length) {
                scanPayload[payloadReadCount] = is.read();
                payloadReadCount++;
            }

            int hMax = 0;
            int vMax = 0;
            for (int i = 0; i < sofnSegment.numberOfComponents; i++) {
                hMax = Math.max(hMax,
                        sofnSegment.getComponents(i).horizontalSamplingFactor);
                vMax = Math.max(vMax,
                        sofnSegment.getComponents(i).verticalSamplingFactor);
            }
            final int hSize = 8 * hMax;
            final int vSize = 8 * vMax;

            final int xMCUs = (sofnSegment.width + hSize - 1) / hSize;
            final int yMCUs = (sofnSegment.height + vSize - 1) / vSize;
            final Block[] mcu = allocateMcuMemory();
            final Block[] scaledMCU = Allocator.array(mcu.length, Block[]::new, Block.SHALLOW_SIZE);
            Arrays.setAll(scaledMCU, i -> new Block(hSize, vSize));
            final int[] preds = Allocator.intArray(sofnSegment.numberOfComponents);
            ColorModel colorModel;
            WritableRaster raster;
            Allocator.check(Integer.BYTES * sofnSegment.width * sofnSegment.height);
            switch (sofnSegment.numberOfComponents) {
            case 4:
                colorModel = new DirectColorModel(24, 0x00ff0000, 0x0000ff00, 0x000000ff);
                final int[] bandMasks = { 0x00ff0000, 0x0000ff00, 0x000000ff };
                raster = Raster.createPackedRaster(DataBuffer.TYPE_INT, sofnSegment.width, sofnSegment.height, bandMasks, null);
                break;
            case 3:
                colorModel = new DirectColorModel(24, 0x00ff0000, 0x0000ff00, 0x000000ff);
                raster = Raster.createPackedRaster(DataBuffer.TYPE_INT, sofnSegment.width, sofnSegment.height, new int[] { 0x00ff0000, 0x0000ff00, 0x000000ff },
                        null);
                break;
            case 1:
                colorModel = new DirectColorModel(24, 0x00ff0000, 0x0000ff00, 0x000000ff);
                raster = Raster.createPackedRaster(DataBuffer.TYPE_INT, sofnSegment.width, sofnSegment.height, new int[] { 0x00ff0000, 0x0000ff00, 0x000000ff },
                        null);
                // FIXME: why do images come out too bright with CS_GRAY?
                // colorModel = new ComponentColorModel(
                // ColorSpace.getInstance(ColorSpace.CS_GRAY), false, true,
                // Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
                // raster = colorModel.createCompatibleWritableRaster(
                // sofnSegment.width, sofnSegment.height);
                break;
            default:
                throw new ImagingException(sofnSegment.numberOfComponents + " components are invalid or unsupported");
            }
            final DataBuffer dataBuffer = raster.getDataBuffer();

            final JpegInputStream[] bitInputStreams = splitByRstMarkers(scanPayload);
            int bitInputStreamCount = 0;
            JpegInputStream bitInputStream = bitInputStreams[0];

            for (int y1 = 0; y1 < vSize * yMCUs; y1 += vSize) {
                for (int x1 = 0; x1 < hSize * xMCUs; x1 += hSize) {
                    // Provide the next interval if an interval is read until it's end
                    // as long there are unread intervals available
                    if (!bitInputStream.hasNext()) {
                        bitInputStreamCount++;
                        if (bitInputStreamCount < bitInputStreams.length) {
                            bitInputStream = bitInputStreams[bitInputStreamCount];
                        }
                    }

                    readMcu(bitInputStream, preds, mcu);
                    rescaleMcu(mcu, hSize, vSize, scaledMCU);
                    int srcRowOffset = 0;
                    int dstRowOffset = y1 * sofnSegment.width + x1;
                    for (int y2 = 0; y2 < vSize && y1 + y2 < sofnSegment.height; y2++) {
                        for (int x2 = 0; x2 < hSize
                                && x1 + x2 < sofnSegment.width; x2++) {
                            if (scaledMCU.length == 4) {
                                final int c = scaledMCU[0].samples[srcRowOffset + x2];
                                final int m = scaledMCU[1].samples[srcRowOffset + x2];
                                final int y = scaledMCU[2].samples[srcRowOffset + x2];
                                final int k = scaledMCU[3].samples[srcRowOffset + x2];
                                final int rgb = ColorConversions.convertCmykToRgb(c, m, y, k);
                                dataBuffer.setElem(dstRowOffset + x2, rgb);
                            } else if (scaledMCU.length == 3) {
                                final int y = scaledMCU[0].samples[srcRowOffset + x2];
                                final int cb = scaledMCU[1].samples[srcRowOffset + x2];
                                final int cr = scaledMCU[2].samples[srcRowOffset + x2];
                                final int rgb = YCbCrConverter.convertYCbCrToRgb(y,
                                        cb, cr);
                                dataBuffer.setElem(dstRowOffset + x2, rgb);
                            } else if (mcu.length == 1) {
                                final int y = scaledMCU[0].samples[srcRowOffset + x2];
                                dataBuffer.setElem(dstRowOffset + x2, (y << 16)
                                        | (y << 8) | y);
                            } else {
                                throw new ImagingException(
                                        "Unsupported JPEG with " + mcu.length
                                                + " components");
                            }
                        }
                        srcRowOffset += hSize;
                        dstRowOffset += sofnSegment.width;
                    }
                }
            }
            image = new BufferedImage(colorModel, raster,
                    colorModel.isAlphaPremultiplied(), new Properties());
            // byte[] remainder = super.getStreamBytes(is);
            // for (int i = 0; i < remainder.length; i++)
            // {
            // System.out.println("" + i + " = " +
            // Integer.toHexString(remainder[i]));
            // }
        } catch (final ImagingException imageReadEx) {
            imageReadException = imageReadEx;
        } catch (final IOException ioEx) {
            ioException = ioEx;
        } catch (final RuntimeException ex) {
            // Corrupt images can throw NPE and IOOBE
            imageReadException = new ImagingException("Error parsing JPEG", ex);
        }
    }