Using muPDF with curl/flip effect

2.8k views Asked by At

I'm using muPDF for reading PDFs in my application. I don't like its default animation (Switching horizontally). In other side i found this brilliant library for curl effect on images, and this project for flip-flap effect on layouts.

In curl sample project, in CurlActivity, all of data are images and set in PageProvider like this:

private class PageProvider implements CurlView.PageProvider {

    // Bitmap resources.
    private int[] mBitmapIds = { R.drawable.image1, R.drawable.image2,
            R.drawable.image3, R.drawable.image4};

And use it like this:

private CurlView mCurlView;
mCurlView = (CurlView) findViewById(R.id.curl);
mCurlView.setPageProvider(new PageProvider());

And CurlView extends from GLSurfaceView and implements View.OnTouchListener, CurlRenderer.Observer

But in muPDF if i'm not mistaken, data are in core object. core is instance of MuPDFCore. And using it like this:

MuPDFReaderView mDocView;
MuPDFView pageView = (MuPDFView) mDocView.getDisplayedView();
mDocView.setAdapter(new MuPDFPageAdapter(this, this, core));

MuPDFReaderView extends ReaderView and ReaderView extends AdapterView<Adapter> and implements GestureDetector.OnGestureListener, ScaleGestureDetector.OnScaleGestureListener, Runnable.

My question is where how can I using curl effect in muPDF? Where should I get pages one by one and converting them to bitmaps? and then changing aspects of the Adapter in muPDF to CurlView.

In flip-flap sample project, in FlipHorizontalLayoutActivity (I like this effect too), we have these:

private FlipViewController flipView;
flipView = new FlipViewController(this, FlipViewController.HORIZONTAL);
flipView.setAdapter(new TravelAdapter(this));
setContentView(flipView);

And FlipViewController extends AdapterView<Adapter>, and data set in TravelAdapter that extends BaseAdapter.

No one has done this before? Or can help me to do that?!

EDIT:

I found another good open source PDF reader with curl effect called fbreaderJ. its developer says "An additional module that allows to open PDF files in FBReader. Based on radaee pdf library."

I got confused! cause radaeepdf is closed source and downloadable project is just for demo and inserted username and password is for this package. People want to change whole fbreader project such as package name.

Another issue for make me confused is where is this additional module source code?!

Anyway, if someone wants to help me, fbreader has done it very well.

EDIT:

I talked to Robin Watts, who developed muPDF (or one of developers), and he said:

Have you read platform/android/ClassStructure.txt ? MuPDF is primarily a C library. The standard api is therefore a C one. Rather than exposing that api exactly as is to Java (which would be the nicest solution, and something that I've done some work on, but have not completed due to lack of time), we've implemented MuPDFCore to wrap up just the bits we needed. MuPDFCore handles opening a PDF file, and getting bitmaps from it to be used in views. or rather, MuPDFCore returns 'views', not 'bitmaps'. If you need bitmaps, then you're going to need to make changes in MuPDFCore.

There are too many errors when changing a little part of MuPDFReaderView class. I get confused! These are related to each other.

Please answer more precisely.

EDIT:

And bounty has expired.

2

There are 2 answers

0
A.D. On BEST ANSWER

Where should i get pages one by one and converting them to bitmaps?

In our application (newspaper app) we use MuPDF to render PDFs. The workflow goes like this:

  1. Download PDF file (we have one PDF per newspaper page)
  2. Render it with MuPDF
  3. Save the bitmap to the filesystem
  4. Load the Bitmap from filesystem as background image to a view

So, finally, what we use is MuPDFCore.java and its methods drawPage(...) and onDestroy()

Is this what you want to know or do i miss the point?

EDIT

1.) I think it is not necessary to post code how to download a file. But after downloading i add a RenderTask (extends from Runnable) to a Renderqueue and trigger that queue. The RenderTask needs some information for rendering:

/**
 * constructs a new RenderTask instance
 * @param context: you need Context for MuPdfCore instance
 * @param pageNumber
 * @param pathToPdf 
 * @param renderCallback: callback to set bitmap to the view after    
 * rendering
 * @param heightOfRenderedBitmap: this is the target height
 * @param widthOfRenderedBitmap: this is the target width
 */
public RenderTask (Context context, Integer pageNumber, String pathToPdf, IRenderCallback,    
                   renderCallback, int heightOfRenderedBitmap, 
                   int widthOfRenderedBitmap) {

    //store things in fields
}

2.) + 3.) The Renderqueue wraps the RenderTask in a new Thread and starts it. So the run-method of the RenderTask will be invoked:

@Override
public void run () {

    //do not render it if file exists
    if (exists () == true) {

        finish();
        return;
    }


    Bitmap bitmap = render();

    //if something went wrong, we can't store the bitmap
    if (bitmap == null) {

        finish();
        return;
    }

    //now save the bitmap
    // in my case i save the destination path in a String field
    imagePath = save(bitmap, new File("path/to/your/destination/folder/" + pageNumber + ".jpg"));

    bitmap.recycle();
    finish();
}

/**
 * let's trigger the callback
 */
private void finish () {

    if (renderCallback != null) {

        // i send the whole Rendertask to callback
        // maybe in your case it is enough to send the pageNumber or path to    
        // renderend bitmap   
        renderCallback.finished(this); 
    }

}

/**
 * renders a bitmap
 * @return
 */
private Bitmap render() {

    MuPDFCore core = null;
    try {
        core = new MuPDFCore(context, pathToPdf);
    } catch (Exception e) {

        return null;
    }

    Bitmap bm = Bitmap.createBitmap(widthOfRenderedBitmap, heightOfRenderedBitmap, Config.ARGB_8888);
    // here you render the WHOLE pdf cause patch-x/-y == 0
    core.drawPage(bm, 0, widthOfRenderedBitmap, heightOfRenderedBitmap, 0, 0, widthOfRenderedBitmap, heightOfRenderedBitmap, core.new Cookie());
    core.onDestroy();
    core = null;
    return bm;
}

/**
 * saves bitmap to filesystem
 * @param bitmap
 * @param image
 * @return
 */
private String save(Bitmap bitmap, File image) {

    FileOutputStream out = null;
    try {
        out = new FileOutputStream(image.getAbsolutePath());
        bitmap.compress(Bitmap.CompressFormat.JPEG, 80, out);
        return image.getAbsolutePath();

    } catch (Exception e) {

        return null;
    }

    finally {
        try {
            if (out != null) {
                out.close();
            }
        } catch(Throwable ignore) {}

    }
}  

}

4.) I think it is not necessary to post code how to set a bitmap as background of a view

1
DKIT On

If the muPDF does not support rendering to a bitmap, you have no other choice than rendering to a regular view and take a screen dump to a bitmap like this:

View content = findViewById(R.id.yourPdfView);
Bitmap bitmap = content.getDrawingCache();

Then use this bitmap as input to your other library.