extractSvsImage function

Future<Uint8List?> extractSvsImage(
  1. SvsFile svs,
  2. String type
)

Extracts the raw image bytes for an associated image (e.g. 'thumbnail', 'label', or 'macro') from an SVS file.

svs is the open SvsFile. type is the image type identifier to extract ('thumbnail', 'label', or 'macro'). Returns the raw byte data, or null if the requested image type was not found.

Implementation

Future<Uint8List?> extractSvsImage(SvsFile svs, String type) async {
  if (svs is HamamatsuFile) {
    svs.ensureOpen();
    try {
      return await svs.associations[type]?.readImage();
    } catch (_) {
      return null;
    }
  }
  return await svs.synchronized(() async {
    final raf = svs.raf;
    final endian = svs.endian;
    final isBigTiff = svs.isBigTiff;
    int ifdOffset = svs.firstIfdOffset;

    while (ifdOffset != 0) {
      final header = await _readIfdHeader(raf, ifdOffset, endian, isBigTiff);
      if (header == null) break;

      int width = 0;
      int height = 0;
      int? tileWidth;
      int? tileHeight;
      String? description;
      List<int> stripOffsets = [];
      List<int> stripByteCounts = [];

      for (var i = 0; i < header.numEntries; i++) {
        final entry = await _readIfdEntry(raf, endian, isBigTiff);
        if (entry == null) break;

        if (entry.tag == 256) {
          width = _readTiffValue(entry.dataType, entry.count, entry.valueOffset, entry.entryBd, entry.offsetInEntry, endian);
        } else if (entry.tag == 257) {
          height = _readTiffValue(entry.dataType, entry.count, entry.valueOffset, entry.entryBd, entry.offsetInEntry, endian);
        } else if (entry.tag == 322) {
          tileWidth = _readTiffValue(entry.dataType, entry.count, entry.valueOffset, entry.entryBd, entry.offsetInEntry, endian);
        } else if (entry.tag == 323) {
          tileHeight = _readTiffValue(entry.dataType, entry.count, entry.valueOffset, entry.entryBd, entry.offsetInEntry, endian);
        } else if (entry.tag == 273) {
          stripOffsets = await _readTiffArray(raf, entry.dataType, entry.count, entry.valueOffset, endian, inlineMaxBytes: entry.inlineMaxBytes, entryBd: entry.entryBd, offsetInEntry: entry.offsetInEntry);
        } else if (entry.tag == 279) {
          stripByteCounts = await _readTiffArray(raf, entry.dataType, entry.count, entry.valueOffset, endian, inlineMaxBytes: entry.inlineMaxBytes, entryBd: entry.entryBd, offsetInEntry: entry.offsetInEntry);
        } else if (entry.tag == 270) {
          description = await _readTiffString(raf, entry.count, entry.valueOffset, inlineMaxBytes: entry.inlineMaxBytes, entryBd: entry.entryBd, offsetInEntry: entry.offsetInEntry);
        }
      }

      String? currentImageType = _determineImageType(description, width, height, tileWidth, tileHeight);

      if (currentImageType == type) {
        if (stripOffsets.isEmpty || stripByteCounts.isEmpty) {
          return null;
        }

        final bb = BytesBuilder();
        for (int i = 0; i < stripOffsets.length; i++) {
          final offset = stripOffsets[i];
          final count = stripByteCounts[i];
          await raf.setPosition(offset);
          final bytes = await raf.read(count);
          bb.add(bytes);
        }
        return bb.takeBytes();
      }

      ifdOffset = await _readNextIfdOffset(raf, header.nextIfdOffsetPos, endian, isBigTiff);
    }

    return null;
  });
}