extractSvsTileAsImage function

Future<Image?> extractSvsTileAsImage(
  1. SvsFile svs,
  2. int layerIndex,
  3. int tileX,
  4. int tileY, {
  5. bool applyColorScheme = true,
  6. bool applyDisplayColor = true,
  7. int? displayColor,
  8. CancellationToken? cancelToken,
})

Extracts a specific tile from a resolution layer in the SVS file and returns it as a decoded img.Image.

Handles decompression (JPEG tiles with JPEGTables, JPEG 2000, LZW with predictor, uncompressed RGB, Deflate).

svs is the open SvsFile. layerIndex is the resolution layer index (0 is the highest resolution / baseline level). tileX and tileY are the 0-based horizontal and vertical tile coordinates (not pixel coordinates). applyColorScheme if true, applies the appropriate color scheme interpretation (e.g., treating RGB JPEG as RGB instead of default YCbCr, WhiteIsZero inversion, palette mapping). If false, extracts the tile image as-is. applyDisplayColor if true, applies the DisplayColor color tinting/mapping if present in metadata or passed explicitly. displayColor optional explicit display color override (e.g., 0xRRGGBB). cancelToken optional cancellation token to abort the operation. Returns the decoded img.Image, or null if the tile coordinates or layer are invalid, failed to decode, or cancelled.

Implementation

Future<img.Image?> extractSvsTileAsImage(
  SvsFile svs,
  int layerIndex,
  int tileX,
  int tileY, {
  bool applyColorScheme = true,
  bool applyDisplayColor = true,
  int? displayColor,
  CancellationToken? cancelToken,
}) async {
  if (cancelToken?.isCancelled == true) {
    return null;
  }

  if (svs is HamamatsuFile) {
    final level = svs.levelAt(layerIndex, tileX, tileY);
    try {
      final image = await level?.readTileImage(tileX, tileY,
          applyColorScheme: applyColorScheme, cancelToken: cancelToken);
      if (cancelToken?.isCancelled == true) return null;
      if (image != null && applyDisplayColor && displayColor != null && displayColor != 0) {
        return _applyDisplayColorToImage(image, displayColor);
      }
      return image;
    } catch (_) {
      return null;
    }
  }

  final collected = await _getOrCollectTiledLevels(svs);
  if (cancelToken?.isCancelled == true) {
    return null;
  }
  final levels = collected.levels;

  if (layerIndex < 0 || layerIndex >= levels.length) {
    return null;
  }

  final targetLevel = levels[layerIndex];
  final fullData = await _getOrLoadLevelFullData(svs, targetLevel, collected.globalJpegTables, collected.globalDisplayColor);
  if (fullData == null || cancelToken?.isCancelled == true) {
    return null;
  }

  if (tileX < 0 || tileX >= targetLevel.tilesAcross || tileY < 0 || tileY >= targetLevel.tilesDown) {
    return null;
  }

  final tileIndex = tileY * targetLevel.tilesAcross + tileX;
  if (tileIndex >= fullData.tileOffsets.length) {
    return null;
  }

  final offset = fullData.tileOffsets[tileIndex];
  final byteCount = tileIndex < fullData.tileByteCounts.length ? fullData.tileByteCounts[tileIndex] : 0;

  final effectiveDisplayColor = displayColor ?? fullData.displayColor;

  // Handle empty / sparse tiles (e.g. background)
  if (byteCount == 0 || offset == 0) {
    if (cancelToken?.isCancelled == true) {
      return null;
    }
    final blank = img.Image(
      width: targetLevel.tileWidth,
      height: targetLevel.tileHeight,
      numChannels: fullData.samplesPerPixel > 0 ? fullData.samplesPerPixel : 3,
    );
    blank.clear(img.ColorRgb8(255, 255, 255));
    if (applyDisplayColor && effectiveDisplayColor != null && effectiveDisplayColor != 0) {
      return _applyDisplayColorToImage(blank, effectiveDisplayColor);
    }
    return blank;
  }

  if (cancelToken?.isCancelled == true) {
    return null;
  }

  final rawTileBytes = await svs.readBytesAt(offset, byteCount, cancelToken: cancelToken);

  if (cancelToken?.isCancelled == true) {
    return null;
  }

  if (rawTileBytes.isEmpty) {
    final blank = img.Image(
      width: targetLevel.tileWidth,
      height: targetLevel.tileHeight,
      numChannels: fullData.samplesPerPixel > 0 ? fullData.samplesPerPixel : 3,
    );
    blank.clear(img.ColorRgb8(255, 255, 255));
    if (applyDisplayColor && effectiveDisplayColor != null && effectiveDisplayColor != 0) {
      return _applyDisplayColorToImage(blank, effectiveDisplayColor);
    }
    return blank;
  }

  return _decodeTileBytes(
    rawTileBytes: rawTileBytes,
    tileWidth: targetLevel.tileWidth,
    tileHeight: targetLevel.tileHeight,
    compression: fullData.compression,
    samplesPerPixel: fullData.samplesPerPixel,
    predictor: fullData.predictor,
    photometricInterpretation: fullData.photometricInterpretation,
    applyColorScheme: applyColorScheme,
    applyDisplayColor: applyDisplayColor,
    displayColor: effectiveDisplayColor,
    jpegTables: fullData.jpegTables,
    iccProfile: fullData.iccProfile,
    colorMap: fullData.colorMap,
    cancelToken: cancelToken,
  );
}