modifyBaseColor static method

Uint8List modifyBaseColor(
  1. Uint8List fontBytes,
  2. Color newBaseColor
)

Replaces the black base color (text layer) with newBaseColor, leaving tajweed colors intact.

Used for dark mode: black → white.

Implementation

static Uint8List modifyBaseColor(Uint8List fontBytes, Color newBaseColor) {
  final bd = ByteData.view(
    fontBytes.buffer,
    fontBytes.offsetInBytes,
    fontBytes.lengthInBytes,
  );

  if (fontBytes.length < 12) return fontBytes;
  final numTables = bd.getUint16(4);

  int? cpalOffset;
  int? cpalLength;
  const cpalTag = 0x4350414C; // 'CPAL'
  for (int t = 0; t < numTables; t++) {
    final recordOffset = 12 + t * 16;
    if (recordOffset + 16 > fontBytes.length) break;
    final tag = bd.getUint32(recordOffset);
    if (tag == cpalTag) {
      cpalOffset = bd.getUint32(recordOffset + 8);
      cpalLength = bd.getUint32(recordOffset + 12);
      break;
    }
  }

  if (cpalOffset == null || cpalLength == null) return fontBytes;
  if (cpalOffset + cpalLength > fontBytes.length) return fontBytes;
  if (cpalOffset + 12 > fontBytes.length) return fontBytes;

  final numColorRecords = bd.getUint16(cpalOffset + 6);
  final colorRecordsArrayOffset = bd.getUint32(cpalOffset + 8);
  final absColorRecordsOffset = cpalOffset + colorRecordsArrayOffset;

  final newR = (newBaseColor.r * 255).round();
  final newG = (newBaseColor.g * 255).round();
  final newB = (newBaseColor.b * 255).round();
  final newA = (newBaseColor.a * 255).round();

  for (int c = 0; c < numColorRecords; c++) {
    final colorOffset = absColorRecordsOffset + c * 4;
    if (colorOffset + 4 > fontBytes.length) break;

    final b = fontBytes[colorOffset];
    final g = fontBytes[colorOffset + 1];
    final r = fontBytes[colorOffset + 2];
    final a = fontBytes[colorOffset + 3];

    // Detect black: RGB ≤ 30 and Alpha ≥ 200
    if (r <= 30 && g <= 30 && b <= 30 && a >= 200) {
      fontBytes[colorOffset] = newB;
      fontBytes[colorOffset + 1] = newG;
      fontBytes[colorOffset + 2] = newR;
      fontBytes[colorOffset + 3] = newA;
    }
  }

  return fontBytes;
}