Search code examples
androidandroid-studiokotlinitextitext7

App halts for a while when creating pdf and adding image to it in itextpdf: itext7


I am creating an app to make pdf and write text and bitmap image to it using Storage Access Framework.

The bitmap image is captured from chart generated using MPAndroidChart which is placed inside framelayout. When adding only text, the process is fast. But when I add bitmap image, activity screen turns black and becomes unresponsive for ~10 seconds.

In pdf, I added image in starting page. Even though there is ample space, the chart appears on next page.

How can I add chart to the page without page break remove the unresponsive screen ?

var newpdfhandle = registerForActivityResult(ActivityResultContracts.StartActivityForResult()){
    resultData: ActivityResult ->
    val uri = resultData.data?.data
    if (resultData.resultCode == Activity.RESULT_OK){
        if (uri != null){
            var bitmap = getBitmapFromView(fragFrame)     // fragFrame = framelayout containing chart
            if (bitmap != null) {                    
                CreateNewPdf.newPdf(this, uri, framelist, bitmap)                    
            }
        }
    }
}

private fun getBitmapFromView(view: View): Bitmap{
    var bitmap = Bitmap.createBitmap(view.width, view.height, Bitmap.Config.ARGB_8888)
    var canvas = Canvas(bitmap)
    view.draw(canvas)
    return bitmap
}

Class to create pdf is as follows:

class CreateNewPdf {

    companion object {    

    val thick_ls = LineSeparator(SolidLine(2f))
    val thin_ls = LineSeparator(SolidLine(1f))
    val tempcolor = DeviceRgb(255, 192, 192)
    val humidcolor = DeviceRgb(0, 172, 192)

    fun newPdf(context: Context, uri: Uri, dataframe: MutableList<DataFrame>, bitmap: Bitmap) {

        val mintemp = dataframe.minBy { it.temperature }?.temperature
        val maxtemp = dataframe.maxBy { it.temperature }?.temperature
        val avgtemp = (dataframe.map { it.temperature }.average() * 10f).toInt().toFloat() / 10f
        val minhumid = dataframe.minBy { it.humidity }?.humidity
        val maxhumid = dataframe.maxBy { it.humidity }?.humidity
        val avghumid = (dataframe.map { it.humidity }.average() * 10f).toInt().toFloat() / 10f

        val filename = queryName(context.contentResolver, uri)

        try {

            var writeStream: OutputStream? = context.contentResolver.openOutputStream(uri, "w")
            val pdf = PdfDocument(PdfWriter(writeStream))
            val document = Document(pdf, PageSize.A4, false)

            val reportTitle = Paragraph("DATA LOGGER REPORT").setFontSize(20f)
                .setTextAlignment(TextAlignment.CENTER)
            document.add(reportTitle)
            document.add(thick_ls)

            var header = Paragraph("1. Summary")
            document.add(header)

            val summary_font = 12f
            val data_font = 8f
            val page_font = 6f

            val table = Table(4, false)
            table.setHorizontalAlignment(HorizontalAlignment.CENTER)

            var cell11: Cell = Cell(1, 1).setBackgroundColor(ColorConstants.LIGHT_GRAY)
                .setTextAlignment(TextAlignment.CENTER)
                .add(Paragraph("List").setFontSize(summary_font))
            var cell12: Cell = Cell(1, 1).setBackgroundColor(ColorConstants.LIGHT_GRAY)
                .setTextAlignment(TextAlignment.CENTER)
                .add(Paragraph("Maximum").setFontSize(summary_font))
            var cell13: Cell = Cell(1, 1).setBackgroundColor(ColorConstants.LIGHT_GRAY)
                .setTextAlignment(TextAlignment.CENTER)
                .add(Paragraph("Minimum").setFontSize(summary_font))
            var cell14: Cell = Cell(1, 1).setBackgroundColor(ColorConstants.LIGHT_GRAY)
                .setTextAlignment(TextAlignment.CENTER)
                .add(Paragraph("Average").setFontSize(summary_font))

            val cell21: Cell = Cell(1, 1).setBackgroundColor(ColorConstants.WHITE)
                .setTextAlignment(TextAlignment.CENTER)
                .add(Paragraph("Temperature °C").setFontSize(summary_font))
            val cell22: Cell = Cell(1, 1).setBackgroundColor(ColorConstants.WHITE)
                .setTextAlignment(TextAlignment.CENTER)
                .add(Paragraph(maxtemp.toString()).setFontSize(summary_font))
            val cell23: Cell = Cell(1, 1).setBackgroundColor(ColorConstants.WHITE)
                .setTextAlignment(TextAlignment.CENTER)
                .add(Paragraph(mintemp.toString()).setFontSize(summary_font))
            val cell24: Cell = Cell(1, 1).setBackgroundColor(ColorConstants.WHITE)
                .setTextAlignment(TextAlignment.CENTER)
                .add(Paragraph(avgtemp.toString()).setFontSize(summary_font))

            val cell31: Cell = Cell(1, 1).setBackgroundColor(ColorConstants.WHITE)
                .setTextAlignment(TextAlignment.CENTER).add(Paragraph("Humidity %"))
            val cell32: Cell = Cell(1, 1).setBackgroundColor(ColorConstants.WHITE)
                .setTextAlignment(TextAlignment.CENTER)
                .add(Paragraph(maxhumid.toString()).setFontSize(summary_font))
            val cell33: Cell = Cell(1, 1).setBackgroundColor(ColorConstants.WHITE)
                .setTextAlignment(TextAlignment.CENTER)
                .add(Paragraph(minhumid.toString()).setFontSize(summary_font))
            val cell34: Cell = Cell(1, 1).setBackgroundColor(ColorConstants.WHITE)
                .setTextAlignment(TextAlignment.CENTER)
                .add(Paragraph(avghumid.toString()).setFontSize(summary_font))

            table.addCell(cell11)
            table.addCell(cell12)
            table.addCell(cell13)
            table.addCell(cell14)
            table.addCell(cell21)
            table.addCell(cell22)
            table.addCell(cell23)
            table.addCell(cell24)
            table.addCell(cell31)
            table.addCell(cell32)
            table.addCell(cell33)
            table.addCell(cell34)
            document.add(table)

            /*************** BITMAP INSERTION STARTS HERE ***************/

            header = Paragraph("2. Real time chart data").setFontSize(12f)
            document.add(header)

            var stream: ByteArrayOutputStream = ByteArrayOutputStream()
            bitmap.compress(Bitmap.CompressFormat.JPEG, 50, stream)
            var img: Image = Image(ImageDataFactory.create(stream.toByteArray()))
            document.add(img)
            
            /*************** BITMAP INSERTION ENDS HERE***************/

            header = Paragraph("3. Log Details").setFontSize(12f)
            document.add(header)
            var dTable = Table(4, false)
            var celld1 = Cell()
            var celld2 = Cell()
            var celld3 = Cell()
            var celld4 = Cell()
            var row = 0
            cell11 = Cell(1, 1).setBackgroundColor(ColorConstants.LIGHT_GRAY)
                .setTextAlignment(TextAlignment.CENTER).add(Paragraph("List").setFontSize(data_font))
            cell12 = Cell(1, 1).setBackgroundColor(ColorConstants.LIGHT_GRAY)
                .setTextAlignment(TextAlignment.CENTER)
                .add(Paragraph("Date Time").setFontSize(data_font))
            cell13 = Cell(1, 1).setBackgroundColor(ColorConstants.LIGHT_GRAY)
                .setTextAlignment(TextAlignment.CENTER)
                .add(Paragraph("Temperature").setFontSize(data_font))
            cell14 = Cell(1, 1).setBackgroundColor(ColorConstants.LIGHT_GRAY)
                .setTextAlignment(TextAlignment.CENTER)
                .add(Paragraph("Humidity").setFontSize(data_font))
            dTable.addCell(cell11)
            dTable.addCell(cell12)
            dTable.addCell(cell13)
            dTable.addCell(cell14)
            dataframe.forEach {
                row++
                celld1 = Cell(row, 1).setBackgroundColor(ColorConstants.WHITE).setTextAlignment(TextAlignment.CENTER).
                            add(Paragraph(it.count.toString()).setFontSize(data_font)).setWidth(30f)
                celld2 = Cell(row, 1).setBackgroundColor(ColorConstants.WHITE).setTextAlignment(TextAlignment.CENTER).
                            add(Paragraph(it.datetime).
                            setFontSize(data_font)).setWidth(85f)
                celld3 = Cell(row, 1).setBackgroundColor(tempcolor).setTextAlignment(TextAlignment.CENTER).
                            add(Paragraph("${it.temperature.toString()} °C")
                                .setFontSize(data_font)).setWidth(60f)
                celld4 = Cell(row, 1).setBackgroundColor(humidcolor).setTextAlignment(TextAlignment.CENTER).
                            add(Paragraph("${it.humidity.toString()} %")
                                .setFontSize(data_font)).setWidth(60f)

                dTable.addCell(celld1)
                dTable.addCell(celld2)
                dTable.addCell(celld3)
                dTable.addCell(celld4)
            }
            document.add(dTable)

            val n: Int = pdf.numberOfPages
            for (i in 1..n) {
                document.showTextAligned(
                    Paragraph(String.format("Page $i of $n")).setFontSize(page_font),
                    559f, 836f, i,
                    TextAlignment.RIGHT,
                    VerticalAlignment.TOP,
                    0f
                )
            }
            document.flush()

            document.close()
        } catch (e: Exception){
            Toast.makeText(context, "Error when $filename.pdf", Toast.LENGTH_SHORT).show()
        }
    }
}
}

Solution

  • I implemented Runnable interface and called the pdf creating function inside it. My implementation is as follows:

    var newpdfhandle = registerForActivityResult(ActivityResultContracts.StartActivityForResult()){
        resultData: ActivityResult ->
        val uri = resultData.data?.data
        if (resultData.resultCode == Activity.RESULT_OK){
            if (uri != null){
                var bitmap = getBitmapFromView(fragFrame)     // fragFrame = framelayout containing chart
                if (bitmap != null) {                    
                    
                    val myRunnable = Runnable {
                        Handler(Looper.getMainLooper()).post {
                            pdfProgressbar.visibility = View.VISIBLE
                        }
                        CreateNewPdf.newPdf(this, uri, framelist, bitmap)
                        Handler(Looper.getMainLooper()).post {
                            pdfProgressbar.visibility = View.GONE
                        }
                    }
                    val thread = Thread(myRunnable).start()
    
                }
            }
        }
    }