Knowledge Base - Render the content of a PDF file reflowed on the screen using PDFLayout from RadaeePDF (Android)

Reflow mode allows you to see the content of each page in a way more similar to an ePUB than a common PDF file.

Text is extracted with its color, font family and size and just printed on the screen just removing text' cages on the page.

To support Reflow rendering based on PDFLayout, You need to create the following class 

Note:

  • In reflow mode Search and annotations are not supported.
  • Using the following code you need to enable reflow view mode by calling
    mPDFManager = new RadaeePDFManager();
    mPDFManager.setReaderViewMode(5);
    in MainActivity.onCreate (in the demo project module RDPDFReader)

PDFLayoutReflow (package com.radaee.view):

public class PDFLayoutReflow extends PDFLayout {

private int m_pageno = 0;
private int mCellSize = 0;
private Paint m_paint = new Paint();
static private int BUTTON_SIZE = 60;
private BMP m_draw_bmp = new BMP();

public PDFLayoutReflow(Context context) {
super(context);
m_paint.setARGB(96, 128, 128, 128);

if(mCellSize <= 0) {
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics dm = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(dm);
mCellSize = dm.widthPixels;
if(mCellSize > dm.heightPixels) mCellSize = dm.heightPixels;
}
}

@Override
public void vOpen(Document doc, LayoutListener listener) {
super.vOpen(doc, listener);
m_pageno = 0;
m_scale = 2;
m_scale_min = 2;
m_scale_max = 4;
}

@Override
public void vClose()
{
super.vClose();
m_pageno = 0;
}

@Override
public void vLayout() {
if( m_doc == null || m_w <= m_page_gap || m_h <= m_page_gap ) return;

m_scale_min = ((m_w - m_page_gap) << 1) / m_doc.GetPageWidth(m_pageno);
if( m_scale < m_scale_min ) m_scale = m_scale_min;
if( m_scale > m_scale_max ) m_scale = m_scale_max;
if( m_pages == null )
{
int cnt = m_doc.GetPageCount();
m_pages = new VPage[cnt];
int cur = 0;
int clipw = (m_w > m_h) ? m_h : m_w - m_page_gap;
for( cur = 0; cur < cnt; cur++ ) {
m_pages[cur] = new VPage(m_doc, cur, clipw, clipw, m_bmp_format);
}
}
if( m_bmp != null ) m_bmp.recycle();
m_bmp = reflow(m_w - m_page_gap, m_scale, true);
if( m_bmp != null )
{
m_tw = m_bmp.getWidth();
m_th = m_bmp.getHeight();
if( m_dark )
{
m_draw_bmp.Create(m_bmp);
m_draw_bmp.Invert();
m_draw_bmp.Free(m_bmp);
}
}
else
{
m_tw = 0;
m_th = 0;
}
m_scroller.forceFinished(true);
m_scroller.setFinalX(0);
m_scroller.setFinalY(0);
m_scroller.computeScrollOffset();
}
@Override
public int vGetPage(int vx, int vy)
{
return m_pageno;
}

@Override
public PDFPos vGetPos( int vx, int vy )
{
if( m_doc == null || m_w <= 0 || m_h <= 0 ) return null;
PDFPos m_pos = new PDFPos();
m_pos.pageno = m_pageno;
m_pos.x = 0;
m_pos.y = m_doc.GetPageHeight(m_pageno);
return m_pos;
}
private boolean m_dark = false;

@Override
public void vDraw(Canvas canvas, boolean zooming) {
if (m_listener != null) m_listener.OnCacheRendered(m_pageno);
if( m_dark )
canvas.drawColor(m_back_color^0xFFFFFF);
else
canvas.drawColor(m_back_color);
if( m_bmp != null )
{
if( m_dark != Global.dark_mode )
{
m_dark = Global.dark_mode;
m_draw_bmp.Create(m_bmp);
m_draw_bmp.Invert();
m_draw_bmp.Free(m_bmp);
}
canvas.drawBitmap(m_bmp, m_page_gap / 2 - m_scroller.getCurrX(), m_page_gap / 2 - m_scroller.getCurrY(), null);
}

Path path = new Path();
path.moveTo(4, m_h/2);
path.lineTo(BUTTON_SIZE + 4, m_h/2 - BUTTON_SIZE);
path.lineTo(BUTTON_SIZE + 4, m_h/2 + BUTTON_SIZE);
path.close();
canvas.drawPath(path, m_paint);
path.reset();
path.moveTo(m_w - 4, m_h/2);
path.lineTo(m_w - BUTTON_SIZE - 4, m_h/2 - BUTTON_SIZE);
path.lineTo(m_w - BUTTON_SIZE - 4, m_h/2 + BUTTON_SIZE);
path.close();
canvas.drawPath(path, m_paint);
}

@Override
public void vSetPos(int vx, int vy, PDFPos pos) {
if( pos == null ) return;
vGotoPage(pos.pageno);
}

@Override
public void vGotoPage( int pageno )
{
if( m_doc == null || pageno < 0 || pageno >= m_doc.GetPageCount() ) return;
if( m_pageno == pageno ) return;
m_pageno = pageno;
vLayout();
if( m_listener != null )
{
m_listener.OnPageChanged(m_pageno);
}
}

@Override
protected void vFindGoto()
{
if( m_pages == null ) return;
vGotoPage( m_finder.find_get_page() );
}

public boolean vSingleTap( float x, float y )
{
if( x > 4 && x < BUTTON_SIZE + 4 && y > m_h/2 - BUTTON_SIZE && y < m_h/2 + BUTTON_SIZE )
{
vGotoPage(m_pageno - 1);
return true;
}
if( x < m_w - 4 && x > m_w - BUTTON_SIZE - 4 && y > m_h/2 - BUTTON_SIZE && y < m_h/2 + BUTTON_SIZE )
{
vGotoPage(m_pageno + 1);
return true;
}
return false;
}

@Override
public boolean vFling(int holdx, int holdy, float dx, float dy, float vx, float vy) {
float ddx = dx;
float ddy = dy;
if( ddx < 0 ) ddx = -ddx;
if( ddy < 0 ) ddy = -ddy;
if( ddx < ddy ) return false;

if( dx < 0 )
vGotoPage(m_pageno + 1);
else
vGotoPage(m_pageno - 1);
return true;
}

static private int size_limit = 3<<20;
public Bitmap reflow(int w, float scale, boolean render_images) {
size_limit = mCellSize * mCellSize * 4;
Page page = m_doc.GetPage(m_pageno);
int height = (int)page.ReflowStart(w, scale, render_images);
if( w * height > size_limit )
height = size_limit / w;
if( w * height <= 0 ) return null;
Bitmap bmp = Bitmap.createBitmap( w, height, Bitmap.Config.ARGB_8888 );
bmp.eraseColor(0xFFFFFFFF);
page.ReflowToBmp(bmp, 0, 0);
page.Close();
return bmp;
}
}


Apply the following modifications to PDFLayoutView (package com.radaee.reader)

In PDFSetView:

...
case 5:
PDFLayoutReflow view = new PDFLayoutReflow(this.getContext());
m_layout = view;
break;
...

In onSingleTapConfirmed:

public boolean onSingleTapConfirmed(MotionEvent e) {
if (m_layout == null) return false;
if(m_layout instanceof PDFLayoutReflow) {
if(((PDFLayoutReflow) m_layout).vSingleTap(e.getX(), e.getY())) {
invalidate();
return true;
}
}
.....

Applies To

RadaeePDF SDK for Android

Details

Created : 2018-08-08 11:30:56, Last Modified : 2021-05-27 13:46:53