Write to PDF using PHP API from android device

Jyotishgher Astrology
By -
0

Write to PDF using PHP API from android device

To generate a PDF report in an Android application using a PHP API, you must build a PHP backend that generates the PDF and streams it as raw binary data, and then write Android frontend code to download and save the file.

Write to PDF using PHP API from android device

1. Updated PHP API (generate_pdf_data.php)

This updated script retrieves URG_IMG, converts the BLOB if you have to a Base64-encoded string, and returns it alongside the rest of the details.

<?php

header('Content-Type: application/json');

include_once($_SERVER['DOCUMENT_ROOT']."/header.php");

$cert_id = isset($_REQUEST['CERT_ID']) ? trim($_REQUEST['CERT_ID']) : '';

if (empty($cert_id)) {

    echo json_encode(array("success" => false, "message" => "CERT_ID is required"));

    exit;

}

$sql = oci_parse($conn, "

    SELECT 

        CERT_ID, CERT_NO, TO_CHAR(CREATED_DT, 'DD-MM-YYYY') AS CREATED_DT,

        PL_NUMBER, ITEM_DESC, REQ_QTY, FIRM_NAME, INSPECTION_AGENCY, INDENT_NO,

        CURRENT_STATUS, APRV_BY_AWM, APRV_BY_DYCMM, APRV_BY_CWE, APRV_BY_DYCME,

        TO_CHAR(APRV_DT_AWM, 'DD-MM-YYYY') AS APRV_DT_AWM,

        TO_CHAR(APRV_DT_DYCMM, 'DD-MM-YYYY') AS APRV_DT_DYCMM,

        TO_CHAR(APRV_DT_CWE, 'DD-MM-YYYY') AS APRV_DT_CWE,

        TO_CHAR(APRV_DT_DYCME, 'DD-MM-YYYY') AS APRV_DT_DYCME,

        URG_IMG

    FROM IOS.URG_PL_DTL

    WHERE CERT_ID = :cert_id

");


oci_bind_by_name($sql, ":cert_id", $cert_id);


if (oci_execute($sql)) {

    $row = oci_fetch_array($sql, OCI_ASSOC + OCI_RETURN_NULLS + OCI_RETURN_LOBS);

    if ($row) {

        if (strtoupper($row['CURRENT_STATUS']) !== 'APPROVED') {

            echo json_encode(array(

                "success" => false, 

                "message" => "PDF generation allowed only for APPROVED certificates."

            ));

        } else {

            // Encode BLOB image to Base64

            if (!empty($row['URG_IMG'])) {

                $row['URG_IMG'] = base64_encode($row['URG_IMG']);

            } else {

                $row['URG_IMG'] = "";

            }

            echo json_encode(array("success" => true, "data" => $row));

        }

    } else {

        echo json_encode(array("success" => false, "message" => "Record not found"));

    }

} else {

    $e = oci_error($sql);

    echo json_encode(array("success" => false, "message" => $e['message']));

}

oci_free_statement($sql);

oci_close($conn);

?>

2. Android PdfGenerator.java

This version decodes the Base64 image from the API, constructs Page 1 with certificate text/signatures, and adds Page 2 containing the "Referenced Documents" heading and the decoded URG_IMG scaled to fit the page cleanly.

public class PdfGenerator {


    public interface PdfCallback {

        void onSuccess(File pdfFile, Uri contentUri);

        void onError(String error);

    }

    public static void generateAndSavePdf(Context context, String certId, PdfCallback callback) {

        String fetchUrl = "https://jyotishgher.in/generate_pdf_data.php?CERT_ID=" + certId;

        RequestQueue queue = Volley.newRequestQueue(context.getApplicationContext());


        JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET, fetchUrl, null,

                response -> {

                    try {

                        if (response.getBoolean("success")) {

                            JSONObject data = response.getJSONObject("data");

                            fetchSignaturesAndDraw(context.getApplicationContext(), data, callback);

                        } else {

                            callback.onError(response.optString("message", "Certificate not approved."));

                        }

                    } catch (Exception e) {

                        callback.onError("Parsing error: " + e.getMessage());

                    }

                },

                error -> callback.onError("Network error fetching certificate details")

        );


        queue.add(request);

    }


    private static void fetchSignaturesAndDraw(Context context, JSONObject data, PdfCallback callback) {

        ExecutorService executor = Executors.newSingleThreadExecutor();

        Handler handler = new Handler(Looper.getMainLooper());


        executor.execute(() -> {

            try {

                Bitmap sigAwm = downloadSignature(data.optString("APRV_BY_AWM"));

                Bitmap sigDycmm = downloadSignature(data.optString("APRV_BY_DYCMM"));

                Bitmap sigCwe = downloadSignature(data.optString("APRV_BY_CWE"));

                Bitmap sigDycme = downloadSignature(data.optString("APRV_BY_DYCME"));


                // Decode URG_IMG Base64 String

                Bitmap urgImgBitmap = null;

                String base64Img = data.optString("URG_IMG", "");

                if (!base64Img.isEmpty() && !base64Img.equalsIgnoreCase("null")) {

                    try {

                        byte[] decodedString = Base64.decode(base64Img, Base64.DEFAULT);

                        urgImgBitmap = BitmapFactory.decodeByteArray(decodedString, 0, decodedString.length);

                    } catch (Exception e) {

                        Log.e("URG_IMG_ERR", "Error decoding BLOB image: " + e.getMessage());

                    }

                }


                String fileName = "Urgency_Certificate_" + data.optString("CERT_ID") + ".pdf";


                // Save PDF

                File outputFile = buildPdfFile(context, data, sigAwm, sigDycmm, sigCwe, sigDycme, urgImgBitmap, fileName);

                Uri contentUri = saveToDownloads(context, outputFile, fileName);


                handler.post(() -> callback.onSuccess(outputFile, contentUri));

            } catch (Exception e) {

                Log.e("PDF_GEN_ERR", "Error building PDF", e);

                handler.post(() -> callback.onError("PDF Build failed: " + e.getMessage()));

            }

        });

    }


    private static Bitmap downloadSignature(String empNo) {

        if (empNo == null || empNo.isEmpty() || empNo.equalsIgnoreCase("null")) return null;

        try {

            String sigUrl = "https://rcfkapurthala.in/cmms/urgency/signatureimage.php?EMPNO=" + empNo;

            URL url = new URL(sigUrl);

            HttpURLConnection connection = (HttpURLConnection) url.openConnection();

            connection.setConnectTimeout(5000);

            connection.setReadTimeout(5000);

            connection.setDoInput(true);

            connection.connect();

            InputStream input = connection.getInputStream();

            return BitmapFactory.decodeStream(input);

        } catch (Exception e) {

            Log.e("SIG_ERR", "Error loading signature for " + empNo, e);

            return null;

        }

    }


    private static File buildPdfFile(Context context, JSONObject data, Bitmap sigAwm, Bitmap sigDycmm, Bitmap sigCwe, Bitmap sigDycme, Bitmap urgImgBitmap, String fileName) throws Exception {

        PdfDocument pdfDocument = new PdfDocument();


        // ================= PAGE 1 =================

        PdfDocument.PageInfo page1Info = new PdfDocument.PageInfo.Builder(595, 842, 1).create(); // A4 Standard

        PdfDocument.Page page1 = pdfDocument.startPage(page1Info);

        Canvas canvas1 = page1.getCanvas();


        Paint paint = new Paint();

        Paint titlePaint = new Paint();

        Paint subTitlePaint = new Paint();


        titlePaint.setTextSize(18);

        titlePaint.setFakeBoldText(true);

        titlePaint.setColor(Color.BLACK);


        subTitlePaint.setTextSize(14);

        subTitlePaint.setFakeBoldText(true);

        subTitlePaint.setColor(Color.BLACK);


        paint.setTextSize(11);

        paint.setColor(Color.BLACK);


        int x = 40;

        int y = 50;


        // Header

        canvas1.drawText("RCF", x, y, titlePaint);

        y += 40;


        canvas1.drawText("RAIL COACH FACTORY - (KAPURTHALA)", x + 80, y, subTitlePaint);

        canvas1.drawLine(x + 80, y + 4, x + 380, y + 4, paint);

        y += 30;


        canvas1.drawText("No. " + data.optString("CERT_ID"), x, y, paint);

        canvas1.drawText("Date: " + data.optString("CREATED_DT"), x + 350, y, paint);

        y += 40;


        canvas1.drawText("Sub: Urgency.", x + 60, y, paint);

        y += 30;


        canvas1.drawText("The following item is urgent and is not available at Shop Floor.", x, y, paint);

        y += 30;


        canvas1.drawText("1. PL.No. : " + data.optString("PL_NUMBER"), x, y, paint);

        y += 25;


        canvas1.drawText("2. Item : " + data.optString("ITEM_DESC"), x, y, paint);

        y += 35;


        canvas1.drawText("You are requested to issue " + data.optString("CERT_NO"), x, y, paint);

        canvas1.drawLine(x + 160, y + 2, x + 500, y + 2, paint);

        y += 25;


        canvas1.drawText("immediately so that work does not suffer. Coaches are held up. Coaches are", x, y, paint);

        y += 20;

        canvas1.drawText("suffering in want of said material.", x, y, paint);

        y += 70;


        // Signatures Layout

        int col1 = x;

        int col2 = x + 130;

        int col3 = x + 260;

        int col4 = x + 390;


        drawSignatureSlot(canvas1, sigDycmm, "Dy.CMM/D", data.optString("APRV_DT_DYCMM"), col1, y, paint);

        drawSignatureSlot(canvas1, sigCwe, "CWE/FUR", data.optString("APRV_DT_CWE"), col2, y, paint);

        drawSignatureSlot(canvas1, sigDycme, "Dy.CME/FF", data.optString("APRV_DT_DYCME"), col3, y, paint);

        drawSignatureSlot(canvas1, sigAwm, "AWM/FP", data.optString("APRV_DT_AWM"), col4, y, paint);


        y += 90;


        // Footer Metadata

        canvas1.drawText("Firm: " + data.optString("FIRM_NAME"), x, y, paint);

        canvas1.drawText("Recd.On: ___________", x + 260, y, paint);

        y += 30;


        canvas1.drawText("Inspection: " + data.optString("INSPECTION_AGENCY"), x, y, paint);

        canvas1.drawText("Qty: " + data.optString("REQ_QTY"), x + 260, y, paint);

        y += 30;


        canvas1.drawText("Qty earlier drawn on urgency: ___________", x, y, paint);

        canvas1.drawText("Dated: ___________", x + 260, y, paint);


        pdfDocument.finishPage(page1);


        // ================= PAGE 2 (Referenced Documents) =================

        PdfDocument.PageInfo page2Info = new PdfDocument.PageInfo.Builder(595, 842, 2).create();

        PdfDocument.Page page2 = pdfDocument.startPage(page2Info);

        Canvas canvas2 = page2.getCanvas();


        int p2Y = 50;

        canvas2.drawText("Referenced Documents", x, p2Y, titlePaint);

        canvas2.drawLine(x, p2Y + 6, x + 220, p2Y + 6, titlePaint);

        p2Y += 40;


        String referenceDocNo = data.optString("INDENT_NO", "N/A");

        canvas2.drawText("Reference Doc / Indent No: " + referenceDocNo, x, p2Y, subTitlePaint);

        p2Y += 30;


        // Render URG_IMG BLOB on Page 2

        if (urgImgBitmap != null) {

            int maxImgWidth = 515;  // 595 page width - 80 margins

            int maxImgHeight = 650; // Max available vertical space on page 2


            int imgWidth = urgImgBitmap.getWidth();

            int imgHeight = urgImgBitmap.getHeight();


            float scale = Math.min((float) maxImgWidth / imgWidth, (float) maxImgHeight / imgHeight);


            int scaledWidth = Math.round(imgWidth * scale);

            int scaledHeight = Math.round(imgHeight * scale);


            Bitmap scaledImg = Bitmap.createScaledBitmap(urgImgBitmap, scaledWidth, scaledHeight, true);

            canvas2.drawBitmap(scaledImg, x, p2Y, paint);

        } else {

            canvas2.drawText("No image document attached.", x, p2Y, paint);

        }


        pdfDocument.finishPage(page2);


        // Output File Writing

        File pdfDir = new File(context.getCacheDir(), "pdfs");

        if (!pdfDir.exists()) pdfDir.mkdirs();


        File outputFile = new File(pdfDir, fileName);

        FileOutputStream fos = new FileOutputStream(outputFile);

        pdfDocument.writeTo(fos);

        fos.flush();

        fos.close();

        pdfDocument.close();


        return outputFile;

    }


    private static Uri saveToDownloads(Context context, File sourceFile, String fileName) {

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {

            ContentValues values = new ContentValues();

            values.put(MediaStore.MediaColumns.DISPLAY_NAME, fileName);

            values.put(MediaStore.MediaColumns.MIME_TYPE, "application/pdf");

            values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS);


            Uri uri = context.getContentResolver().insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, values);

            if (uri != null) {

                try (OutputStream os = context.getContentResolver().openOutputStream(uri);

                     InputStream is = new java.io.FileInputStream(sourceFile)) {

                    byte[] buffer = new byte[1024];

                    int len;

                    while ((len = is.read(buffer)) > 0) {

                        os.write(buffer, 0, len);

                    }

                    os.flush();

                    return uri;

                } catch (Exception e) {

                    Log.e("SAVE_DOWNLOAD_ERR", "Error saving via MediaStore", e);

                }

            }

        } else {

            File downloadsDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);

            File destFile = new File(downloadsDir, fileName);

            try (InputStream is = new java.io.FileInputStream(sourceFile);

                 OutputStream os = new FileOutputStream(destFile)) {

                byte[] buffer = new byte[1024];

                int len;

                while ((len = is.read(buffer)) > 0) {

                    os.write(buffer, 0, len);

                }

                os.flush();

                return Uri.fromFile(destFile);

            } catch (Exception e) {

                Log.e("SAVE_DOWNLOAD_ERR", "Error saving legacy file", e);

            }

        }

        return FileProvider.getUriForFile(context, context.getPackageName() + ".fileprovider", sourceFile);

    }


    private static void drawSignatureSlot(Canvas canvas, Bitmap sig, String title, String dateStr, int x, int y, Paint paint) {

        if (sig != null) {

            Bitmap scaledSig = Bitmap.createScaledBitmap(sig, 80, 40, false);

            canvas.drawBitmap(scaledSig, x, y - 45, paint);

        }

        canvas.drawText(title, x, y, paint);

        if (dateStr != null && !dateStr.isEmpty() && !dateStr.equalsIgnoreCase("null")) {

            canvas.drawText(dateStr, x, y + 15, paint);

        }

    }


    public static void openOrSharePdf(Context context, Uri uri) {

        Intent intent = new Intent(Intent.ACTION_VIEW);

        intent.setDataAndType(uri, "application/pdf");

        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_ACTIVITY_NEW_TASK);


        try {

            context.startActivity(Intent.createChooser(intent, "Open Urgency Certificate PDF"));

        } catch (Exception e) {

            Log.e("OPEN_PDF_ERR", "No PDF viewer found", e);

        }

    }

Button Click Event Implementation

btnOfficialPDF.setOnClickListener(v -> {
    if (progressDialog != null && !isFinishing()) {
        progressDialog.setMessage("Downloading PDF...");
        progressDialog.show();
    }

    PdfGenerator.generateAndSavePdf(awm_fp_request_view_for_action.this, CERT_ID, new PdfGenerator.PdfCallback() {
        @Override
        public void onSuccess(File pdfFile, Uri contentUri) {
            if (!isFinishing() && progressDialog != null && progressDialog.isShowing()) {
                progressDialog.dismiss();
            }

            Toast.makeText(awm_fp_request_view_for_action.this, 
                    "PDF Downloaded to Downloads Folder!", Toast.LENGTH_LONG).show();

            // Open or share the downloaded PDF directly
            PdfGenerator.openOrSharePdf(awm_fp_request_view_for_action.this, contentUri);
        }

        @Override
        public void onError(String error) {
            if (!isFinishing() && progressDialog != null && progressDialog.isShowing()) {
                progressDialog.dismiss();
            }

            Toast.makeText(awm_fp_request_view_for_action.this, error, Toast.LENGTH_LONG).show();
        }
    });

 Android PDF Generation & Sharing Handler

Add FileProvider to your AndroidManifest.xml:

<provider
    android:name="androidx.core.content.FileProvider"
    android:authorities="${applicationId}.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths" />
</provider>

Create res/xml/file_paths.xml:
<?xml version="1.0" encoding="utf-8"?>
<paths>
    <cache-path name="pdf_cache" path="." />
</paths>


Post a Comment

0Comments

Post a Comment (0)