private void sampleDimensions()

in incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/CoverageBuilder.java [509:654]


    private void sampleDimensions(final boolean full) throws DataStoreException {
        final int nc = (model          == null) ? 0 : model.components.length;
        final int nt = (componentTypes == null) ? 0 : componentTypes.length;
        final int ns = (bitsPerChannel == null) ? 0 : bitsPerChannel.length;
        final int numBands = Math.max(Math.max(nc, nt), ns);
        if (numBands == 0) {
            if (tileBuilder != null) {
                if (tileBuilder.sampleDimensions == null) {
                    tileBuilder.sampleDimensions(full);
                }
                sampleDimensions = tileBuilder.sampleDimensions;
                sampleModel      = tileBuilder.sampleModel;
                colorModel       = tileBuilder.colorModel;
                dataType         = tileBuilder.dataType;
            }
            return;
        }
        final int[] bitsPerSample = new int[numBands];
        final var sd = full ? new SampleDimension[numBands] : null;
        final var sb = full ? new SampleDimension.Builder() : null;
        int numBits=0, redMask=0, greenMask=0, blueMask=0, alphaMask=0;
        int grayBand = -1, indexBand = -1, alphaBand = -1;    // Negative value means none.
        for (int band=0; band<numBands; band++) {
            /*
             * `colorType` can be an enumeration value such as `RED`, `GREEN`, `BLUE`,
             * or an URI, or an Integer value. The same value can appear in two boxes.
             * `bitDepth` can also appear in two boxes. The ISO 23001-17:2024 standard
             * said that when the component type information appears in the two boxes,
             * `ComponentDefinitionBox` shall precede `UncompressedFrameConfigBox`.
             */
            var colorType = (band < nt) ? componentTypes[band] : null;  // From `ComponentDefinition`.
            int bitDepth  = (band < ns) ? Byte.toUnsignedInt(bitsPerChannel[band]) : 0;
            if (band < nc) {
                final Component c = model.components[band];
                if (colorType == null) colorType = c.type;              // From `UncompressedFrameConfig`
                if (dataType == null) {
                    dataType = c.getDataType();
                } else if (dataType != c.getDataType()) {
                    throw new RasterFormatException("All bands shall be of the same data type.");
                }
                bitDepth = Short.toUnsignedInt(c.bitDepth);
                /*
                 * Example: 10-bit unaligned RGB components followed by a 1-byte aligned 7-bit alpha component.
                 * Stored as 30 consecutive bits containing R, G and B, followed by 2 pre-alignment padding bits
                 * for byte alignment, followed by one alignment padding bit then followed by the 7-bit alpha value.
                 */
                final int alignSize = Byte.toUnsignedInt(c.alignSize) * Byte.SIZE;
                if (alignSize != 0) {
                    numBits = Numerics.snapToCeil(numBits,  alignSize)
                            + Numerics.snapToCeil(bitDepth, alignSize) - bitDepth;
                }
            }
            /*
             * Create the sample dimension and derive metadata from it.
             * TODO: parse CellPropertyTypeProperty and CellPropertyCategoriesProperty boxes.
             */
            if (full) {
                if (colorType != null) {
                    sb.setName(colorType.toString());
                } else {
                    sb.setName(band);
                }
                var source = new CoverageModifier.BandSource(store, imageIndex, band, numBands, dataType);
                metadata().addNewBand(sd[band] = store.customizer.customize(source, sb));
                sb.clear();
            }
            if (bitDepth == 0) {
                bitDepth = Component.DEFAULT_BIT_DEPTH;
            } else if (full) {
                metadata().setBitPerSample(bitDepth);
            }
            /*
             * Identify the bands that we can map to RGBA.
             * Will be used for building the color model.
             */
            bitsPerSample[band] = bitDepth;
            numBits += bitDepth;
            if (full && colorType instanceof ComponentType ct) {
                int mask = 0;
                if (numBits < Integer.SIZE) {
                    mask = ((1 << bitDepth) - 1) << (Integer.SIZE - numBits);
                }
                switch (ct) {
                    case RED:        redMask   |= mask; break;
                    case GREEN:      greenMask |= mask; break;
                    case BLUE:       blueMask  |= mask; break;
                    case ALPHA:      alphaMask |= mask; alphaBand = band; break;
                    case MONOCHROME: grayBand   = band; break;
                    case PALETTE:    indexBand  = band; break;
                }
            }
        }
        final boolean isRGB = (redMask | greenMask | blueMask) != 0;
        if (isRGB && numBits < Integer.SIZE) {
            final int n = Integer.SIZE - numBits;   // Number of unused bits.
            redMask   >>>= n;
            greenMask >>>= n;
            blueMask  >>>= n;
            alphaMask >>>= n;
        }
        /*
         * Build a sample model. The `InterleavingMode.COMPONENT` default value is arbitrary,
         * as the `UncompressedFrameConfig` box is mandatory according ISO/IEC 23001-17:2024.
         */
        if (sampleModel == null && dataType != null) {
            InterleavingMode interleaveType = InterleavingMode.COMPONENT;
            final var tileSize = new Dimension(width, height);
            if (model != null) {
                tileSize.width  /= model.numTileCols;
                tileSize.height /= model.numTileRows;
                interleaveType = model.interleaveType;
            }
            final boolean isBanded;
            switch (interleaveType) {
                case COMPONENT: isBanded = true;  break;    // Java2D: BandedSampleModel
                case PIXEL:     isBanded = false; break;    // Java2D: PixelInterleavedSampleModel
                default: throw new RasterFormatException("Unsupported interleave type: " + interleaveType);
            }
            sampleModel = new SampleModelBuilder(dataType, tileSize, bitsPerSample, isBanded).build();
        }
        /*
         * Build a RGB(A) or indexed color model compatible with the sample model.
         * The gray scale is used as a fallback for all unrecognized color models.
         */
        if (full) {
            if (indexBand >= 0 && palette != null) {
                colorModel = palette.toARGB(dataType, bitsPerSample[indexBand], numBands, indexBand);   // May be null.
            }
            if (colorModel == null && sampleModel != null) {
                if (grayBand < 0 && (grayBand = indexBand) < 0) {
                    grayBand = ColorModelFactory.DEFAULT_VISIBLE_BAND;
                }
                final var cb = new ColorModelBuilder(isRGB)
                                .dataType(dataType)
                                .bitsPerSample(bitsPerSample)
                                .alphaBand(alphaBand)
                                .visibleBand(grayBand, sd[grayBand].getSampleRange().orElse(null));
                if (isRGB) {
                    cb.componentMasks(redMask, greenMask, blueMask, alphaMask);
                    // TODO: use another color space if not RGB.
                }
                colorModel = cb.createRGB(sampleModel);
            }
        }
        sampleDimensions = sd;
    }