modifyBaseColor static method
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;
}