printReceipt static method

Future<bool> printReceipt({
  1. required List<Map<String, dynamic>> items,
  2. String? header,
  3. String? footer,
  4. String fontFamily = 'Siemreap',
  5. double fontSize = 20,
  6. FontWeight fontWeight = FontWeight.normal,
  7. int? printerWidth,
  8. double lineSpacing = 5.0,
  9. Map<String, double>? columnWidths,
})

Print receipt with multiple rows of data.

  • items: List of maps where each map represents a row
  • header: Optional header text
  • footer: Optional footer text
  • fontFamily: Font family to use
  • fontSize: Font size in points
  • fontWeight: Font weight (normal, bold, etc.)
  • printerWidth: Printer width in dots
  • lineSpacing: Space between lines
  • columnWidths: Map of column names to widths

Returns true if printing was successful.

Implementation

static Future<bool> printReceipt({
  required List<Map<String, dynamic>> items,
  String? header,
  String? footer,
  String fontFamily = 'Siemreap',
  double fontSize = 20,
  FontWeight fontWeight = FontWeight.normal,
  int? printerWidth,
  double lineSpacing = 5.0,
  Map<String, double>? columnWidths,
}) async {
  try {
    final directory = await getTemporaryDirectory();
    final tempPath =
        '${directory.path}/receipt_${DateTime.now().millisecondsSinceEpoch}.png';

    // Set up default printer width
    final width = printerWidth ?? 576;

    // Calculate total height based on number of items
    double totalHeight = 0;
    if (header != null) totalHeight += 60; // Space for header
    if (footer != null) totalHeight += 60; // Space for footer

    // Add height for each item row
    totalHeight += (items.length * (fontSize + lineSpacing)) + 20;

    // Create recorder and canvas
    final recorder = PictureRecorder();
    final canvas = Canvas(recorder);

    // Draw white background
    canvas.drawRect(
      Rect.fromLTWH(0, 0, width.toDouble(), totalHeight),
      Paint()..color = Colors.white,
    );

    // Set up text painter
    TextPainter textPainter = TextPainter(
      textDirection: TextDirection.ltr,
    );

    // Current Y position for drawing
    double yPos = 10;

    // Draw header if provided
    if (header != null) {
      textPainter.text = TextSpan(
        text: header,
        style: TextStyle(
          fontFamily: fontFamily,
          fontSize: fontSize + 2, // Slightly larger for header
          fontWeight: FontWeight.bold,
          color: Colors.black,
        ),
      );

      textPainter.textAlign = TextAlign.center;
      textPainter.layout(maxWidth: width.toDouble());

      // Center header
      final dx = (width - textPainter.width) / 2;
      textPainter.paint(canvas, Offset(dx > 0 ? dx : 0, yPos));

      yPos +=
          textPainter.height + lineSpacing + 10; // Extra spacing after header
    }

    // Set up default column widths if not provided
    Map<String, double> columns = columnWidths ?? {};
    if (items.isNotEmpty && items[0].isNotEmpty) {
      final keys = items[0].keys.toList();
      final defaultWidth = width.toDouble() / keys.length;

      for (String key in keys) {
        if (!columns.containsKey(key)) {
          columns[key] = defaultWidth;
        }
      }
    }

    // Draw items
    for (var item in items) {
      double xPos = 0;
      double rowHeight = 0;

      // Process each column in the row
      item.forEach((key, value) {
        String text = value.toString();
        double colWidth = columns[key] ?? 100.0;

        textPainter.text = TextSpan(
          text: text,
          style: TextStyle(
            fontFamily: fontFamily,
            fontSize: fontSize,
            fontWeight: fontWeight,
            color: Colors.black,
          ),
        );

        textPainter.textAlign = TextAlign.left;
        textPainter.layout(maxWidth: colWidth - 10); // Subtract padding

        textPainter.paint(canvas, Offset(xPos + 5, yPos));

        xPos += colWidth;
        rowHeight = math.max(rowHeight, textPainter.height);
      });

      yPos += rowHeight + lineSpacing;
    }

    // Draw footer if provided
    if (footer != null) {
      yPos += 10; // Extra spacing before footer

      textPainter.text = TextSpan(
        text: footer,
        style: TextStyle(
          fontFamily: fontFamily,
          fontSize: fontSize,
          fontWeight: fontWeight,
          color: Colors.black,
        ),
      );

      textPainter.textAlign = TextAlign.center;
      textPainter.layout(maxWidth: width.toDouble());

      // Center footer
      final dx = (width - textPainter.width) / 2;
      textPainter.paint(canvas, Offset(dx > 0 ? dx : 0, yPos));

      yPos += textPainter.height + lineSpacing;
    }

    // Convert to image - adjust the height to actual content
    final picture = recorder.endRecording();
    final img = await picture.toImage(width, yPos.ceil());
    final byteData = await img.toByteData(format: ImageByteFormat.png);
    final buffer = byteData!.buffer.asUint8List();

    // Save to temp file
    await File(tempPath).writeAsBytes(buffer);

    // Print the image
    return await PrinterCore.printImage(
      tempPath,
      width: width,
      alignment: TextFormatter.convertAlignment(Alignment.center),
    );
  } catch (e) {
    print('Error printing receipt: $e');
    return false;
  }
}