Frequently Asked Question
Render the content of a PDF file reflowed on the screen using PDFLayout from RadaeePDF
Last Updated 11 months ago
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; } } .....