Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Not support Unicode Khmer with "Coeng" sign (្) #1698

Open
2 of 5 tasks
DyDev-1 opened this issue Jul 16, 2024 · 0 comments
Open
2 of 5 tasks

Not support Unicode Khmer with "Coeng" sign (្) #1698

DyDev-1 opened this issue Jul 16, 2024 · 0 comments
Labels
bug Something isn't working needs triage

Comments

@DyDev-1
Copy link

DyDev-1 commented Jul 16, 2024

Describe the bug

When generating a PDF invoice using the pdf package, the Khmer script's "Khmer Sign Coeng" (្) is not rendering correctly with Khmer letters. This diacritical mark, essential for forming certain consonant clusters, fails to combine properly with the preceding and following Khmer characters, resulting in incorrect and unreadable text.
Example
Correct Rendering: បន្ទាត់ (a valid Khmer word)
Incorrect Rendering:
image
(shows the issue with "Khmer Sign Coeng" not combining correctly)

To Reproduce
Code snippet to reproduce the behavior:

  Future<String> generatePdfInvoice(PdfPageFormat format, List<Invoice> invoiceItems) async {
    final pdf = pw.Document();
    final img = await rootBundle.load('assets/images/header_invoice.png');
    final imageBytes = img.buffer.asUint8List();
    // final khmerFont = pw.Font.ttf(await rootBundle.load('assets/fonts/Khmer-OS-Siemreap-Regular.ttf'));
    final Uint8List fontData = base64Decode(khmerFontBase64);
    final khmerFont = pw.Font.ttf(fontData.buffer.asByteData());


    // Define the maximum number of items per page
    const int itemsPerPage = 33;

    // Split the invoice items into chunks of itemsPerPage
    List<List<Invoice>> chunks = [];
    for (var i = 0; i < invoiceItems.length; i += itemsPerPage) {
      chunks.add(invoiceItems.sublist(
        i,
        i + itemsPerPage > invoiceItems.length ? invoiceItems.length : i + itemsPerPage,
      ));
    }

    // Add a page for each chunk of invoice items
    for (var i = 0; i < chunks.length; i++) {
      final chunk = chunks[i];
      pdf.addPage(

        pw.MultiPage(
          theme: pw.ThemeData.withFont(
            base: khmerFont,
          ),
          pageFormat: PdfPageFormat.a4,
          build: (pw.Context context) {
            return <pw.Widget>[
              if (i == 0)
                pw.Container(
                  alignment: pw.Alignment.center,
                  child: pw.Image(pw.MemoryImage(imageBytes)),
                ),
              if (i == 0)
                pw.Container(
                  child: pw.Divider(
                    height: 1,
                    thickness: 1,
                    indent: 1,
                    endIndent: 0,
                    color: PdfColor.fromHex("#000000"),
                  ),
                ),
              pw.SizedBox(height: 20),
              if (i == 0)
                pw.Row(
                  children: [
                    pw.Container(
                      child: pw.Row(
                        children: [
                          pw.Column(
                              crossAxisAlignment: pw.CrossAxisAlignment.start,
                              children: [
                                pw.Text("Billed To", style: pw.TextStyle(color: PdfColor.fromHex("#5453C6"))),
                                pw.Text("Client Name : ${nameController.text.toString()}"),
                                pw.Text("Address : ${addressController.text.toString()}"),
                                pw.Text("Tel: ${telController.text.toString()}"),
                              ]
                          ),
                          pw.SizedBox(width: 80), // Add horizontal space between text elements
                          pw.Column(
                              mainAxisAlignment: pw.MainAxisAlignment.center,
                              children: [
                                pw.Text("Date Issued", style: pw.TextStyle(color: PdfColor.fromHex("#5453C6"))),
                                pw.Text("${dateController.text.toString()}"),
                              ]
                          ),
                          pw.SizedBox(width: 15),
                          pw.Column(
                              mainAxisAlignment: pw.MainAxisAlignment.center,
                              children: [
                                pw.Text("Invoice Number", style: pw.TextStyle(color: PdfColor.fromHex("#5453C6"))),
                                pw.Text("${numController.text.toString()}"),
                              ]
                          ),
                        ],
                      ),
                    ),
                  ],
                ),
              pw.SizedBox(height: 20),

              // Table construction using pw.Table.fromTextArray
              pw.Table.fromTextArray(
                border: null,
                cellAlignment: pw.Alignment.center,
                headerDecoration: pw.BoxDecoration(color: PdfColors.grey300),
                headerHeight: 30,
                cellHeight: 30,
                headerStyle: pw.TextStyle(fontWeight: pw.FontWeight.bold, font: khmerFont),

                headers: ['No', 'Description', 'Qty', 'Unit Price', 'Amount'],
                data: List<List<dynamic>>.generate(
                  chunk.length,
                      (index) => [
                    '${index + 1}',
                    chunk[index].description,
                    chunk[index].qty,
                    pw.Text(
                      '${chunk[index].price} ${chunk[index].cur == "R" ? "\R" : "\$"}',
                      style: pw.TextStyle(fontSize: 12),
                    ),
                    '${chunk[index].qty * chunk[index].price} ${chunk[index].cur == "R" ? "\R" : "\$"}',
                  ],
                ),
              ),

              pw.SizedBox(height: 20),
              if (i == chunks.length - 1)
                pw.Row(
                    mainAxisAlignment: pw.MainAxisAlignment.end,
                    children: [
                      pw.Column(
                        mainAxisAlignment: pw.MainAxisAlignment.end,
                        children: [
                          pw.Text('Total Amount Riel: ${totalRController.text} R',
                              style: pw.TextStyle(fontWeight: pw.FontWeight.bold)),
                          pw.Text('Total Amount USD : ${totalUController.text} \$',
                              style: pw.TextStyle(fontWeight: pw.FontWeight.bold)),
                          pw.Text('Total Due Amount Riel : ${totalDueRController.text} R',
                              style: pw.TextStyle(fontWeight: pw.FontWeight.bold)),
                          pw.Text('Total Due Amount USD : ${totalDueUController.text} \$',
                              style: pw.TextStyle(fontWeight: pw.FontWeight.bold)),
                        ],
                      )
                    ]
                )

            ];
          },
        ),
      );
    }

    final output = await getTemporaryDirectory();
    final invoice_num =  numController.text;
    final file = File("${output.path}/${invoice_num.toString()}.pdf");
    await file.writeAsBytes(await pdf.save());
    return file.path;
  }

Expected behavior

The "Khmer Sign Coeng" (្) should combine seamlessly with preceding and following Khmer letters to form valid consonant clusters, ensuring that the text is rendered correctly and is readable.

Screenshots

image

Flutter Doctor

Desktop (please complete the following information):

  • iOS
  • Android
  • Browser
  • Windows
  • Linux

Smartphone (please complete the following information):

  • Device: [e.g. iPhone6]
  • OS: [e.g. iOS8.1]
  • Browser [e.g. stock browser, safari]
  • Version [e.g. 22]

Additional context

@DyDev-1 DyDev-1 added bug Something isn't working needs triage labels Jul 16, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working needs triage
Projects
None yet
Development

No branches or pull requests

1 participant