androidandroid-pdf-api

Coordinates and clipping on Android PdfDocument


I have been happily producing a PDF document in the Android PDF class PdfDocument. After puzzling over the "subtle" documentation I divined that the coordinate system was in PostScript (1/72")

private static final int A4_WIDTH = 595;
private static final int A4_HEIGHT = 842;
private static final int CM = 28;
private static final int footer_height = CM;



void startPage() {
    if (currentPage != null) {
        finishPage(currentPage);
    }
    PageInfo.Builder pageBuilder = new PageInfo.Builder(A4_WIDTH, A4_HEIGHT, page++);
    Rect rect = new Rect(0, 0, A4_WIDTH, A4_HEIGHT);
    rect.inset(CM, 2 * CM);
    pageBuilder.setContentRect(rect);
    PageInfo pageInfo = pageBuilder.create();
    pagePosition = 0.0f;
    pageWidth = rect.width();
    pageHeight = rect.height();
    currentPage = super.startPage(pageInfo);
    page_count++;
    if (has_footer)
        putFooter();

}

This worked fine on my Nexus 10 but I was rather surprised when on the Samsung S6 the coordinate system seemed messed up, so on the Nexus 10 I put text at 0,0 and it fits nicely 2cm down and 1cm across, but on the S6 it appears 4cm down and 2cm across. Further, bottom and right are clipped by 2cm and 1cm. In other words, the clipping rectangle is in the right place, but it appears the coordinate system has been doubly offset.

My draw code looks like this:

        canvas.save();
        canvas.translate(0, pagePosition);
        staticLayout.draw(canvas);
        canvas.restore();

where pagePosition is a simple ps counter driven by measuring text from the results of staticLayout.getHeight();

To be clear, layout is spot on with no foibles on a reasonably complex mix of text, line drawing and images, just got this device-dependent foible.

Bug or my brain?

Edit: Left is Nexus, Right is S6

Left Nexus - Right S6

Code to produce:

 import android.annotation.TargetApi;
 import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.pdf.PdfDocument;
 import android.support.v4.content.ContextCompat;

 import uk.co.spennycycles.pocketcycletech.PocketCycleTechApp;
 import uk.co.spennycycles.pocketcycletech.R;



  @TargetApi(19)

public class TestReport extends PdfDocument {
private static final String TAG = SpennyPdfDocument.class.getSimpleName();
private static final int A4_WIDTH = 595;
private static final int A4_HEIGHT = 842;
private static final int CM = 28;
int pageWidth;
int pageHeight;


public void generateReport() {
PageInfo.Builder pageBuilder = new PageInfo.Builder(A4_WIDTH, A4_HEIGHT, 1);
Rect rect = new Rect(0, 0, A4_WIDTH, A4_HEIGHT);
rect.inset(CM, 2 * CM);
pageBuilder.setContentRect(rect);
PageInfo pageInfo = pageBuilder.create();
Page page = super.startPage(pageInfo);

pageWidth = rect.width();
pageHeight = rect.height();
Canvas canvas = page.getCanvas();

RectF r = new RectF((float) 0, 0, pageWidth, pageHeight);
r.inset(1.0f, 1.0f);
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setDither(true);
paint.setStyle(Paint.Style.FILL);

paint.setColor(ContextCompat.getColor(PocketCycleTechApp.getContext(), R.color.lt_gray));
canvas.drawRect(r, paint);

paint.setColor(ContextCompat.getColor(PocketCycleTechApp.getContext(), R.color.black));

paint.setStrokeWidth(2.0f);
paint.setStyle(Paint.Style.STROKE);
canvas.drawRect(r, paint);
paint.setStyle(Paint.Style.FILL_AND_STROKE);

canvas.drawLine(r.left, r.top, r.right, r.bottom, paint);
canvas.drawLine(r.right, r.top, r.left, r.bottom, paint);

finishPage(page);
}
}

Solution

  • Workaround:

        currentPage = super.startPage(pageInfo);
        Canvas canvas = currentPage.getCanvas();
        canvas.translate(CM, CM*2);
        canvas.clipRect(0, 0, rect.width(), rect.height());
    

    leaves the canvas in exactly the same state.