Mostafa Fathi
Mostafa Fathi

Reputation: 13

How to Match ASS Subtitle Font Size with Flutter Text Size for a 1080p Video?

I’m working on a project where I need to synchronize the font size of ASS subtitles with the text size a user sees in a Flutter application. The goal is to ensure that the text size in a 1080p video matches what the user sees in the app.

What I've Tried:

  1. Calculating font size using height ratio (PlayResY/DeviceHeight):
FontSize_ASS = FontSize_Flutter * (PlayResY / DeviceHeight)
  1. Adding a scaling factor:
  1. Using force_style in FFmpeg:
ffmpeg -i input.mp4 -vf "subtitles=subtitle.ass:force_style='FontSize=90'" -c:a copy output.mp4
  1. Aligning PlayResX and PlayResY in the ASS file: I ensured that these parameters matched the target video resolution (1920×1080):
PlayResX: 1920
PlayResY: 1080
  1. Reading font metrics from the font file dynamically: To improve precision, I wrote a function in Flutter that reads font metrics (units per EM, ascender, and descender) from the TTF font file and calculates a more accurate scaling factor:
Future<double?> readFontMetrics(
      String fontFilePath, 
      double originalFontSize,
) async {
  final fontData = await File(fontFilePath).readAsBytes();
  final fontBytes = fontData.buffer.asUint8List();
  final byteData = ByteData.sublistView(fontBytes);

  int numTables = readUInt16BE(byteData, 4);
  int offsetTableStart = 12;
  Map<String, Map<String, int>> tables = {};

  for (int i = 0; i < numTables; i++) {
    int recordOffset = offsetTableStart + i * 16;
    String tag =
        utf8.decode(fontBytes.sublist(recordOffset, recordOffset          + 4));
    int offset = readUInt32BE(byteData, recordOffset + 8);
    int length = readUInt32BE(byteData, recordOffset + 12);

    tables[tag] = {
      'offset': offset,
      'length': length,
    };
  }

  if (!tables.containsKey('head') || !tables.containsKey('hhea'){
    print('Required tables not found in the font file.');
    return null;
  }

  int headOffset = tables['head']!['offset']!;
  int unitsPerEm = readUInt16BE(byteData, headOffset + 18);

  int hheaOffset = tables['hhea']!['offset']!;
  int ascender = readInt16BE(byteData, hheaOffset + 4);
  int descender = readInt16BE(byteData, hheaOffset + 6);

  print('unitsPerEm: $unitsPerEm');
  print('ascender: $ascender');
  print('descender: $descender');

  int nominalSize = unitsPerEm;
  int realDimensionSize = ascender - descender;
  double scaleFactor = realDimensionSize / nominalSize;
  double realFontSize = originalFontSize * scaleFactor;

  print('Scale Factor: $scaleFactor');
  print('Real Font Size: $realFontSize');

  return realFontSize;
}

Question: How can I ensure that the font size in the ASS file accurately reflects the size the user sees in Flutter? Is there a reliable method to calculate or align the sizes correctly across both systems? Any insights or suggestions would be greatly appreciated.

Thank you! 🙏

Upvotes: 0

Views: 166

Answers (0)

Related Questions