mpietrzak / apv

Automatically exported from code.google.com/p/apv
GNU General Public License v3.0
12 stars 2 forks source link

Problem with file descriptor loading in Assets folder #53

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
Steps that reproduce the problem
1. Place PDF files in assets folder and change their extension to .png to avoid 
compression.
2. The file descriptors can be obtained by using getAssets()
3. When open any of the file, it shows only 1 file (similar pdf file). 

Running on Samsung Galaxy S I9000

Original issue reported on code.google.com by Ncjle...@gmail.com on 6 Aug 2011 at 5:51

GoogleCodeExporter commented 9 years ago
I am confused.  Are you viewing the file by using an intent from your own app?

Original comment by arpruss on 7 Aug 2011 at 4:49

GoogleCodeExporter commented 9 years ago
Yes. However I'm able to view it properly by using File (External folder), but 
not FileDescriptor (Internal resource). 
What I'm doing is, I put both application (my app and this app) into 1 
application. And my app will tell this pdf reader to read the file from 
FileDescriptor by using intent. 

PS: I store the pdf file inside assets folder. 

Original comment by Ncjle...@gmail.com on 7 Aug 2011 at 4:55

GoogleCodeExporter commented 9 years ago
Could you please attach sample code or at least logs?

Original comment by mpietrzak on 7 Aug 2011 at 10:59

GoogleCodeExporter commented 9 years ago
I have attached 2 files, with TestPDF.java will run as main activity, and 
slight modification code for OpenFileActivity.java

Both activities are bundle into 1 apk file.

1. Make sure you put the PDF files in "assets" folder with their extension 
changed to .png (to avoid compression) 
2. Rename those pdf files as shown in the filenames array (1.pdf, 2.pdf, 3.pdf 
... )
3. And make sure all the pdf files have different content.
4. Run the activity and open each of the file. On my device, it render only the 
1.png file.

Thank you. 

Original comment by Ncjle...@gmail.com on 7 Aug 2011 at 11:38

Attachments:

GoogleCodeExporter commented 9 years ago
This is still a problem. Using an internal Intent with a FileDescriptor, rather 
than a File will result in the viewer showing an arbitrary file in the assets 
folder (the same each time) instead of the one given in the FileDescriptor.

When there is only one file in the asset folder, this is obviously not a 
problem, but with more than one file there, it will only view one of them, and 
I have no idea why exactly.

I could not find a solution for this problem. While it would be possible to 
create an InputStream from the AssetFileDescriptor, and extract the bytes of 
the correct file, the constructor in PDF.java that allows a byte array is 
commented out and will not work.

A solution would be greatly appreciated.

Original comment by Kim.Scho...@gmail.com on 23 Dec 2011 at 3:10

GoogleCodeExporter commented 9 years ago
Good day all,

I found the solution to the problem after extensive debugging on MUPDF code. 
The problem is caused by the 0 offset.

  The APK File (Data allocation) 
 ---------------------------------------------
|                      |                      |
|   Compressed Files   |  Uncompressed Files  |
|                      |                      |
 ---------------------------------------------
(0)bytes               (m)bytes              (n)bytes

1. Every time the native code read the asset file, it's actually reading the 
apk file itself. Which means it always pointing to itself whenever the file is 
within the apk. 

2. To read the pdf files inside the Asset without unzipping the .apk file, one 
way to work around is to prevent the .pdf to be zipped. As suggested here 
http://groups.google.com/group/android-ndk/browse_thread/thread/8274a4c51cc9cc1d
?pli=1 , we can change the file extension like .png, .mp3, etc.

3. Then we can use the *AssetFileDescriptor* to retrieve the pdf file *offset* 
and *size* within the apk file and pass it to native code.

  AssetFileDescriptor afd = this.getAssets().openFd("Test File.pdf");
  PDF pdf = new PDF(afd.getFileDescriptor(), this.box, afd.getStartOffset(), afd.getLength());
  *Note: Modification is needed for the pdfview2.c jni code to get *offset* and *filesize* and slowly pass them to *pdf_open_xref_with_stream* (The MUPDF code)

4. Modification of MUPDF code ( apv-0.3.1dev13 )
- Added in fitz.h "extern int asset_offset;" dirty hack to keep least code 
changes as possible
- Added in base_object.c "int asset_offset = 0;"
- Changed in pdf_xref.c (line 20) "fz_seek(xref->file, asset_offset, 0);"
- Changed in pdf_xref.c (line 31) "pdf_read_start_xref(pdf_xref *xref, int 
filesize)"
- Changed in pdf_xref.c (line 37) "fz_seek(xref->file, asset_offset, 2);"
- Changed in pdf_xref.c (line 39) "xref->file_size = (filesize > 
0)?filesize:fz_tell(xref->file);"
- Changed in pdf_xref.c (line 41) "t = MAX(0, xref->file_size - (int)sizeof 
buf) + asset_offset;"
- Changed in pdf_xref.c (line 140) "fz_seek(xref->file, xref->startxref + 
asset_offset, 0);"
- Changed in pdf_xref.c (line 395) "fz_seek(xref->file, ofs + asset_offset, 0);"
- Changed in pdf_xref.c (line 667) "pdf_open_xref_with_stream(pdf_xref **xrefp, 
fz_stream *file, char *password, int offset, int filesize)"
- Changed in pdf_xref.c (line 882) "first = fz_to_int(fz_dict_gets(objstm, 
"First")) + asset_offset;"
- Changed in pdf_xref.c (line 986) "fz_seek(xref->file, x->ofs + asset_offset, 
0);"
- Added in pdf_xref.c (pdf_open_xref_with_stream) "asset_offset = offset;" 

This solution is a little bit dirty as it needs global variable to store the 
asset_offset value. But it works. 

Original comment by Ncjle...@gmail.com on 9 Feb 2012 at 2:30

GoogleCodeExporter commented 9 years ago
Correction for number 3,
AssetFileDescriptor afd = this.getAssets().openFd("Test File.pdf.png");

Hope this helps. 

Original comment by Ncjle...@gmail.com on 10 Feb 2012 at 1:37

GoogleCodeExporter commented 9 years ago
One more correction, do not apply this line
"- Changed in pdf_xref.c (line 882) "first = fz_to_int(fz_dict_gets(objstm, 
"First")) + asset_offset;""

Attached is my modified pdf_xref.c from (apv-0.3.1dev13)
PS: be sure to update pdf_open_xref_with_stream's header in mupdf.h

Original comment by Ncjle...@gmail.com on 15 Feb 2012 at 2:57

Attachments: