rasterize method
Rasterizes the measured lines into a list of TxSprite objects.
Each sprite represents one line of text.
Implementation
Future<void> rasterize() async {
// If rasterization is already complete or is currently in progress, do nothing.
// This prevents race conditions from concurrent calls.
if (isRasterized || _isRasterizing) return;
_isRasterizing = true;
try {
// This check is now mostly for safety; measureNextPage should prevent empty lines.
for (final lineData in _lines) {
if (lineData.text.isEmpty || lineData.lineHeight <= 0) {
continue; // Skip invalid lines.
}
final paragraphBuilder = ui.ParagraphBuilder(ui.ParagraphStyle(
textAlign: layout.textAlign,
fontFamily: layout.fontFamily,
fontSize: layout.fontSize.toDouble(),
));
paragraphBuilder.addText(lineData.text);
final paragraph = paragraphBuilder.build();
// Layout with the specific width calculated for this line.
paragraph.layout(ui.ParagraphConstraints(width: lineData.width.toDouble()));
final lineMetrics = paragraph.computeLineMetrics();
if (lineMetrics.isEmpty) {
continue; // No line metrics available, skip.
}
final firstLineMetrics = lineMetrics.first;
// The canvas for the sprite should span the full width of the layout
// to ensure consistent sprite dimensions.
final int spriteWidth = firstLineMetrics.width.ceil();
final int spriteHeight = lineData.lineHeight;
if (spriteWidth <= 0 || spriteHeight <= 0) {
continue; // Skip invalid sprite sizes.
}
final recorder = ui.PictureRecorder();
final canvas = ui.Canvas(recorder);
// Draw the paragraph at its calculated horizontal offset.
canvas.drawParagraph(paragraph, ui.Offset(-firstLineMetrics.left, 0));
final picture = recorder.endRecording();
final image = await picture.toImage(spriteWidth, spriteHeight);
final byteData = await image.toByteData(format: ui.ImageByteFormat.rawRgba);
if (byteData == null) continue;
// Convert the 32-bit RGBA image to a 1-bit monochrome sprite.
final pixels = Uint8List(spriteWidth * spriteHeight);
final rgba = byteData.buffer.asUint8List();
for (int i = 0; i < pixels.length; ++i) {
// Use the red channel to determine color (assuming grayscale text).
// A threshold of 128 determines black or white.
pixels[i] = rgba[i * 4] >= 128 ? 1 : 0;
}
// After rasterizing, update the lineData with the final sprite geometry
lineData.xOffset = (lineData.xOffset + firstLineMetrics.left).toInt();
lineData.width = spriteWidth;
_sprites.add(TxSprite(
width: spriteWidth,
height: spriteHeight,
numColors: 2,
paletteData: TxTextPage._getPalette().data,
pixelData: pixels,
));
}
} finally {
// Ensure the flag is always reset, even if an error occurs.
_isRasterizing = false;
}
}