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;
        }
    }
.....


Loading ...