Pdf file is not viewing in android app - pdf

Anyone can help in this code, the pdf file is not loading in app and just showing blank white screen, Logcat showing FileNotFoundExeeption: /storage/sdcard/raw/ourpdf.pdf.
i am trying to make an app that will show information while i click buttons and every button will be active for specific pdf file reading. Any specific help please.
Thanks for help
part1
package com.code.androidpdf;
public class MainActivity extends Activity {
//Globals:
private WebView wv;
private int ViewSize = 0;
//OnCreate Method:
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Settings
PDFImage.sShowImages = true; // show images
PDFPaint.s_doAntiAlias = true; // make text smooth
HardReference.sKeepCaches = true; // save images in cache
//Setup above
wv = (WebView)findViewById(R.id.webView1);
wv.getSettings().setBuiltInZoomControls(true);//show zoom buttons
wv.getSettings().setSupportZoom(true);//allow zoom
//get the width of the webview
wv.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener()
{
#Override
public void onGlobalLayout()
{
ViewSize = wv.getWidth();
wv.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
});
pdfLoadImages();//load images
}
private void pdfLoadImages() {
try
{
// run async
new AsyncTask<Void, Void, Void>()
{
// create and show a progress dialog
ProgressDialog progressDialog = ProgressDialog.show(MainActivity.this, "", "Opening...");
#Override
protected void onPostExecute(Void result)
{
//after async close progress dialog
progressDialog.dismiss();
}
#Override
protected Void doInBackground(Void... params)
{
try
{
// select a document and get bytes
File file = new File(Environment.getExternalStorageDirectory().getPath()+"/randompdf.pdf");
RandomAccessFile raf = new RandomAccessFile(file, "r");
FileChannel channel = raf.getChannel();
net.sf.andpdf.nio.ByteBuffer bb = null ;
raf.close();
// create a pdf doc
PDFFile pdf = new PDFFile(bb);
//Get the first page from the pdf doc
PDFPage PDFpage = pdf.getPage(1, true);
//create a scaling value according to the WebView Width
final float scale = ViewSize / PDFpage.getWidth() * 0.95f;
//convert the page into a bitmap with a scaling value
Bitmap page = PDFpage.getImage((int)(PDFpage.getWidth() * scale), (int)(PDFpage.getHeight() * scale), null, true, true);
//save the bitmap to a byte array
ByteArrayOutputStream stream = new ByteArrayOutputStream();
page.compress(Bitmap.CompressFormat.PNG, 100, stream);
stream.close();
byte[] byteArray = stream.toByteArray();
//convert the byte array to a base64 string
String base64 = Base64.encodeToString(byteArray, Base64.DEFAULT);
//create the html + add the first image to the html
String html = "<!DOCTYPE html><html><body bgcolor=\"#7f7f7f\"><img src=\"data:image/png;base64,"+base64+"\" hspace=10 vspace=10><br>";
//loop through the rest of the pages and repeat the above
for(int i = 2; i <= pdf.getNumPages(); i++)
{
PDFpage = pdf.getPage(i, true);
page = PDFpage.getImage((int)(PDFpage.getWidth() * scale), (int)(PDFpage.getHeight() * scale), null, true, true);
stream = new ByteArrayOutputStream();
page.compress(Bitmap.CompressFormat.PNG, 100, stream);
stream.close();
byteArray = stream.toByteArray();
base64 = Base64.encodeToString(byteArray, Base64.DEFAULT);
html += "<img src=\"data:image/png;base64,"+base64+"\" hspace=10 vspace=10><br>";
}
html += "</body></html>";
//load the html in the webview
wv.loadDataWithBaseURL("", html, "text/html","UTF-8", "");
}
catch (Exception e)
{
Log.d("CounterA", e.toString());
}
return null;
}
}.execute();
System.gc();// run GC
}
catch (Exception e)
{
Log.d("error", e.toString());
}
}
}

It is (sadly) not possible to view a PDF that is stored locally in your devices. Android L has introduced the feature. So, to display a PDF , you have two options:
See this answer for using webview
How to open local pdf file in webview in android? (note that this requires an internet connection)
Use a third party pdf Viewer.
You can also send an intent for other apps to handle your pdf.

You can get an InputStream for the file using
getResources().openRawResource(R.raw.ourpdf)
Docs: http://developer.android.com/reference/android/content/res/Resources.html#openRawResource(int)

Related

How to generate the Thumbnail of the PDF first page in Xamarin Forms

I'm using the Syncfusion PDF viewer for Xamarin Forms to display a collection of PDF files and it seems the conversion from PDF to PNG (to extract the first page (the cover) of the PDF file to show it, to the user, into a carousel) didn't work in Xamarin [see https://www.syncfusion.com/kb/9112/how-to-convert-pdf-to-png]
I wonder if there is a way to convert PDF into PNG on the Xamarin platform or if I should convert it on the server side.
Thank you.
You can export PDF pages to images without using Syncfusion PDF Viewer control by consuming the PdfRenderer , CGPDFDocument, and PdfDocument classes.
Xamarin.Forms.Android:
//initialize PDFRenderer by passing PDF file from location.
PdfRenderer renderer = new PdfRenderer(GetSeekableFileDescriptor());
int pageCount = renderer.PageCount;
for(int i=0;i<pageCount;i++)
{
// Use `openPage` to open a specific page in PDF.
Page page = renderer.OpenPage(i);
//Creates bitmap
Bitmap bmp = Bitmap.CreateBitmap(page.Width, page.Height, Bitmap.Config.Argb8888);
//renderes page as bitmap, to use portion of the page use second and third parameter
page.Render(bmp, null, null, PdfRenderMode.ForDisplay);
//Save the bitmap
SaveImage(bmp);
page.Close();
}
//Method to retrieve PDF file from the location
private ParcelFileDescriptor GetSeekableFileDescriptor()
{
ParcelFileDescriptor fileDescriptor = null;
try
{
string root = Android.OS.Environment.ExternalStorageDirectory.ToString()+ "/Syncfusion/sample.pdf";
fileDescriptor = ParcelFileDescriptor.Open(new Java.IO.File(root),ParcelFileMode.ReadOnly
);
}
catch (FileNotFoundException e)
{
}
return fileDescriptor;
}
Xamarin.Forms.iOS:
public void ConvertToImage(Stream fileStream) //Pass PDF stream
{
MemoryStream stream = new MemoryStream();
// Create memory stream from file stream.
fileStream.CopyTo(stream);
// Create data provider from bytes.
CGDataProvider provider = new CGDataProvider(stream.ToArray());
try
{
//Load a PDF file.
m_pdfDcument = new CGPDFDocument(provider);
}
catch (Exception)
{
}
//Get PDF's page and convert as image.
using (CGPDFPage pdfPage = m_pdfDcument.GetPage(2))
{
//initialise image context.
UIGraphics.BeginImageContext(pdfPage.GetBoxRect(CGPDFBox.Media).Size);
// get current context.
CGContext context = UIGraphics.GetCurrentContext();
context.SetFillColor(1.0f, 1.0f, 1.0f, 1.0f);
// Gets page's bounds.
CGRect bounds = new CGRect(pdfPage.GetBoxRect(CGPDFBox.Media).X, pdfPage.GetBoxRect(CGPDFBox.Media).Y, pdfPage.GetBoxRect(CGPDFBox.Media).Width, pdfPage.GetBoxRect(CGPDFBox.Media).Height);
if (pdfPage != null)
{
context.FillRect(bounds);
context.TranslateCTM(0, bounds.Height);
context.ScaleCTM(1.0f, -1.0f);
context.ConcatCTM(pdfPage.GetDrawingTransform(CGPDFBox.Crop, bounds, 0, true));
context.SetRenderingIntent(CGColorRenderingIntent.Default);
context.InterpolationQuality = CGInterpolationQuality.Default;
// Draw PDF page in the context.
context.DrawPDFPage(pdfPage);
// Get image from current context.
pdfImage = UIGraphics.GetImageFromCurrentImageContext();
UIGraphics.EndImageContext();
}
}
// Get bytes from UIImage object.
using (var imageData = pdfImage.AsPNG())
{
imageBytes = new byte[imageData.Length];
System.Runtime.InteropServices.Marshal.Copy(imageData.Bytes, imageBytes, 0, Convert.ToInt32(imageData.Length));
//return bytes;
}
//Create image from bytes.
imageStream = new MemoryStream(imageBytes);
//Save the image. It is a custom method to save the image
Save("PDFtoImage.png", "image/png", imageStream);
}
Xamarin.Forms.UWP
public async void ConvertToImage(Stream fileStream) //Pass PDF stream
{
StorageFile file = null;
//Creates file picker to choose PDF file.
FileOpenPicker filePicker = new FileOpenPicker();
filePicker.FileTypeFilter.Add(".pdf");
filePicker.ViewMode = PickerViewMode.Thumbnail;
filePicker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;
filePicker.SettingsIdentifier = "picker1";
filePicker.CommitButtonText = "Open Pdf File";
//Open file picker option
file = await filePicker.PickSingleFileAsync();
// Load selected PDF file from the file picker.
PdfDocument pdfDocument = await PdfDocument.LoadFromFileAsync(file);
if (pdfDocument != null && pdfDocument.PageCount > 0)
{
for (int pageIndex = 0; pageIndex < pdfDocument.PageCount; pageIndex++)
{
//Get page from a PDF file.
var pdfPage = pdfDocument.GetPage((uint)pageIndex);
if (pdfPage != null)
{
//Create temporary folder to store images.
StorageFolder tempFolder = ApplicationData.Current.TemporaryFolder;
//Create image file.
StorageFile destinationFile = await KnownFolders.CameraRoll.CreateFileAsync(Guid.NewGuid().ToString() + ".jpg");
if (destinationFile != null)
{
IRandomAccessStream randomStream = await destinationFile.OpenAsync(FileAccessMode.ReadWrite);
//Crerate PDF rendering options
PdfPageRenderOptions pdfPageRenderOptions = new PdfPageRenderOptions();
pdfPageRenderOptions.DestinationWidth = (uint)(300);
// Render the PDF's page as stream.
await pdfPage.RenderToStreamAsync(randomStream, pdfPageRenderOptions);
await randomStream.FlushAsync();
//Dispose the random stream
randomStream.Dispose();
//Dispose the PDF's page.
pdfPage.Dispose();
}
}
}
}
}
I work for Syncfusion.

Generating PDF with iText and batik

I'm trying to export text and SVG graphs to a PDF. I found out that iText and batik can do this. So I tried doing that, but everytime I put in a graph, it would become extraordinary small.
I thought it might be something with my code, so I figured I would try an examplecode from Vaadin.
public class PdfExportDemo {
private String fontDirectory = null;
private final String baseFont = "Arial";
private PdfWriter writer;
private Document document;
private Font captionFont;
private Font normalFont;
private String svgStr;
/**
* Writes a PDF file with some static example content plus embeds the chart
* SVG.
*
* #param pdffilename
* PDF's filename
* #param svg
* SVG as a String
* #return PDF File
*/
public File writePdf(String pdffilename, String svg) {
svgStr = svg;
document = new Document();
document.addTitle("PDF Sample");
document.addCreator("Vaadin");
initFonts();
File file = null;
try {
file = writeToFile(pdffilename, document);
document.open();
writePdfContent();
document.close();
} catch (DocumentException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return file;
}
/**
* Get Font directory that will be checked for custom fonts.
*
* #return Path to fonts
*/
public String getFontDirectory() {
return fontDirectory;
}
/**
* Set Font directory that will be checked for custom fonts.
*
* #param fontDirectory
* Path to fonts
*/
public void setFontDirectory(String fontDirectory) {
this.fontDirectory = fontDirectory;
}
private void initFonts() {
if (fontDirectory != null) {
FontFactory.registerDirectory(fontDirectory);
}
captionFont = FontFactory.getFont(baseFont, 10, Font.BOLD, new Color(0,
0, 0));
normalFont = FontFactory.getFont(baseFont, 10, Font.NORMAL, new Color(
0, 0, 0));
}
private File writeToFile(String filename, Document document)
throws DocumentException {
File file = null;
try {
file = File.createTempFile(filename, ".pdf");
file.deleteOnExit();
FileOutputStream fileOut = new FileOutputStream(file);
writer = PdfWriter.getInstance(document, fileOut);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return file;
}
private void writePdfContent() throws DocumentException, IOException {
Paragraph caption = new Paragraph();
caption.add(new Chunk("Vaadin Charts Export Demo PDF", captionFont));
document.add(caption);
Paragraph br = new Paragraph(Chunk.NEWLINE);
document.add(br);
Paragraph paragraph = new Paragraph();
paragraph.add(new Chunk("This PDF is rendered with iText 2.1.7.",
normalFont));
document.add(paragraph);
paragraph = new Paragraph();
paragraph
.add(new Chunk(
"Chart below is originally an SVG image created with Vaadin Charts and rendered with help of Batik SVG Toolkit.",
normalFont));
document.add(paragraph);
document.add(createSvgImage(writer.getDirectContent(), 400, 400));
document.add(createExampleTable());
}
private PdfPTable createExampleTable() throws BadElementException {
PdfPTable table = new PdfPTable(2);
table.setHeaderRows(1);
table.setWidthPercentage(100);
table.setTotalWidth(100);
// Add headers
table.addCell(createHeaderCell("Browser"));
table.addCell(createHeaderCell("Percentage"));
// Add rows
table.addCell(createCell("Firefox"));
table.addCell(createCell("45.0"));
table.addCell(createCell("IE"));
table.addCell(createCell("26.8"));
table.addCell(createCell("Chrome"));
table.addCell(createCell("12.8"));
table.addCell(createCell("Safari"));
table.addCell(createCell("8.5"));
table.addCell(createCell("Opera"));
table.addCell(createCell("6.2"));
table.addCell(createCell("Others"));
table.addCell(createCell("0.7"));
return table;
}
private PdfPCell createHeaderCell(String caption)
throws BadElementException {
Chunk chunk = new Chunk(caption, captionFont);
Paragraph p = new Paragraph(chunk);
p.add(Chunk.NEWLINE);
p.add(Chunk.NEWLINE);
PdfPCell cell = new PdfPCell(p);
cell.setBorder(0);
cell.setBorderWidthBottom(1);
cell.setHorizontalAlignment(PdfPCell.ALIGN_LEFT);
cell.setVerticalAlignment(PdfPCell.ALIGN_MIDDLE);
return cell;
}
private PdfPCell createCell(String value) throws BadElementException {
PdfPCell cell = new PdfPCell(new Phrase(new Chunk(value, normalFont)));
cell.setBorder(0);
cell.setHorizontalAlignment(PdfPCell.ALIGN_LEFT);
return cell;
}
private Image drawUnscaledSvg(PdfContentByte contentByte)
throws IOException {
// First, lets create a graphics node for the SVG image.
GraphicsNode imageGraphics = buildBatikGraphicsNode(svgStr);
// SVG's width and height
float width = (float) imageGraphics.getBounds().getWidth();
float height = (float) imageGraphics.getBounds().getHeight();
// Create a PDF template for the SVG image
PdfTemplate template = contentByte.createTemplate(width, height);
// Create Graphics2D rendered object from the template
Graphics2D graphics = template.createGraphics(width, height);
try {
// SVGs can have their corner at coordinates other than (0,0).
Rectangle2D bounds = imageGraphics.getBounds();
graphics.translate(-bounds.getX(), -bounds.getY());
// Paint SVG GraphicsNode with the 2d-renderer.
imageGraphics.paint(graphics);
// Create and return a iText Image element that contains the SVG
// image.
return new ImgTemplate(template);
} catch (BadElementException e) {
throw new RuntimeException("Couldn't generate PDF from SVG", e);
} finally {
// Manual cleaning (optional)
graphics.dispose();
}
}
/**
* Use Batik SVG Toolkit to create GraphicsNode for the target SVG.
* <ol>
* <li>Create SVGDocument</li>
* <li>Create BridgeContext</li>
* <li>Build GVT tree. Results to GraphicsNode</li>
* </ol>
*
* #param svg
* SVG as a String
* #return GraphicsNode
* #throws IOException
* Thrown when SVG could not be read properly.
*/
private GraphicsNode buildBatikGraphicsNode(String svg) throws IOException {
UserAgent agent = new UserAgentAdapter();
SVGDocument svgdoc = createSVGDocument(svg, agent);
DocumentLoader loader = new DocumentLoader(agent);
BridgeContext bridgeContext = new BridgeContext(agent, loader);
bridgeContext.setDynamicState(BridgeContext.STATIC);
GVTBuilder builder = new GVTBuilder();
GraphicsNode imageGraphics = builder.build(bridgeContext, svgdoc);
return imageGraphics;
}
private SVGDocument createSVGDocument(String svg, UserAgent agent)
throws IOException {
SVGDocumentFactory documentFactory = new SAXSVGDocumentFactory(
agent.getXMLParserClassName(), true);
SVGDocument svgdoc = documentFactory.createSVGDocument(null,
new StringReader(svg));
return svgdoc;
}
private Image createSvgImage(PdfContentByte contentByte,
float maxPointWidth, float maxPointHeight) throws IOException {
Image image = drawUnscaledSvg(contentByte);
image.scaleToFit(maxPointWidth, maxPointHeight);
return image;
}
}
But when I do this, I still get the small graph. I tried debugging the app, and the size og the graph is actually 10000x600, and then it tries to scale it to fit.
So I tried manually setting the size to like 400x600, no dice. I tried forcing the size on the SVG - no dice. And if I make it, I think, too big then it simply shows a small 1x1cm box with shadows. The output from the example is as follows.
I really hope someone can help.
UPDATE
When I remove these two lines:
Rectangle2D bounds = imageGraphics.getBounds();
graphics.translate(-bounds.getX(), -bounds.getY());
and hardcode the sizes, It kinda works. But the image itself is stil enourmous, and can't seem to fit it.
see for example:

Pdf generation in arabic language is printing garbage values

I am using component one library to generate pdf document and save in phone storage. Here is my code to print just one line.
public ViewStatementDetails()
{
this.InitializeComponent();
this.navigationHelper = new NavigationHelper(this);
this.navigationHelper.LoadState += this.NavigationHelper_LoadState;
this.navigationHelper.SaveState += this.NavigationHelper_SaveState;
pdf = new C1PdfDocument(PaperKind.Letter);
pdf.Clear();
}
private void Print_Click(object sender, RoutedEventArgs e)
{
LoadingProgress.Visibility = Windows.UI.Xaml.Visibility.Visible;
PDFTest_Loaded();
}
async void PDFTest_Loaded()
{
try
{
WriteableBitmap writeableBmp = await initializeImage();
pdf = new C1PdfDocument(PaperKind.Letter);
CreateDocumentText(pdf);
StorageFile Assets = await Windows.Storage.ApplicationData.Current.LocalFolder.CreateFileAsync("Salik Statement.pdf", CreationCollisionOption.GenerateUniqueName);
PdfUtils.Save(pdf, Assets);
LoadingProgress.Visibility = Visibility.Collapsed;
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
Debugger.Break();
LoadingProgress.Visibility = Visibility.Collapsed;
}
}
async void CreateDocumentText(C1PdfDocument pdf)
{
try
{
pdf.Landscape = false;
// measure and show some text
var text = App.GetResource("RoadAndSafetyheading")
var font = new Font("Segoe UI Light", 36, PdfFontStyle.Bold);
var fmt = new StringFormat();
fmt.Alignment = HorizontalAlignment.Center;
// measure it
var sz = pdf.MeasureString(text, font, 72 * 3, fmt);
var rc = new Rect(0, 0, pdf.PageRectangle.Width, sz.Height);
rc = PdfUtils.Offset(rc, 0, 0);
// draw the text
pdf.DrawString(text, font, Colors.Orange, rc, fmt);
}
catch (Exception e)
{
}
}
The above code is working perfect but my application supports two languages, English and Arabic. And when I am in arabic mode and generate same pdf it prints garbage values in pdf file. attaching image of printed characters.
Use of Arabic characters would require to use Unicode symbols and embed the Unicode font into PDF (as PDF format does not provide support for Unicode using its built-in fonts). If you are using ComponentOne then try to set .EmbedTrueTypeFonts = true (see details here)

Screenshot does not take the latest, current or updated view (Android)

I'm trying to switch a banner adView to imageView just before I take a screenshot so that users can share this screenshot through share intent.
However, when I take the screenshot, it does not include the imageView.
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
....
adView1 = new AdView(this, AdSize.BANNER, MY_AD_UNIT_ID1);
LinearLayout.LayoutParams childParam2 = new
LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 0, 0.10f);
adView1.setLayoutParams(childParam2);
adView1.loadAd(new AdRequest());
ll.addView(adView1);
setContentView(ll);
myAdView = new ImageView(this);
LinearLayout.LayoutParams childParam1 = new
LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 0, 0.10f);
myAdView.setLayoutParams(childParam1);
....
View.OnClickListener handler = new View.OnClickListener() {
public void onClick(View v) {
switch (v.getId()) {
...
case R.id.menu3:
share();
break;
...
}
}
Here's share() function.
private void share(){
List<Intent> targetedShareIntents = new ArrayList<Intent>();
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("*/*");
List<ResolveInfo> resInfo =
this.getPackageManager().queryIntentActivities(intent, 0);
for (ResolveInfo resolveInfo : resInfo) {
........
if (packageName.toLowerCase().contains("twitter")){
targetedShareIntent.setType("*/*");
String location = "file://" + takeScreen(ll);
...
}
...
}
This is takeScreen(View v) function.
public String takeScreen(View c_view){
ll.removeView(adView1);
ll.addView(myAdView);
// create bitmap screen capture
Bitmap bitmap;
View v1 = c_view.getRootView();
v1.setDrawingCacheEnabled(true);
bitmap = v1.getDrawingCache();
String extr = Environment.getExternalStorageDirectory().toString();
File imageFile = new File(extr, "screen_" + System.currentTimeMillis() + ".jpg");
OutputStream fout = null;
try {
fout = new FileOutputStream(imageFile);
boolean saved = bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fout);
//Log.e("bitmap saved ?", saved + "!");
fout.flush();
fout.close();
MediaStore.Images.Media.insertImage(getContentResolver(), bitmap, "Screen", "screen");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
ll.removeView(myAdView);
ll.addView(adView1);
return imageFile.getPath();
}
As you can see, I'm removing adView and adding myAdView(imageView) just before the screenshot is taken in takeScreen() function. adView IS removed but imageVies is NOT added to the screenshot.
The imageView DOES appear on the screen just before chooserIntent(share intent) pop-up screen is displayed.
I have tried many other options like
added both views and just switched visibility. setVisibility(View.Gone, View.Visible)
tried creating bitmap with canvas instead of getDrawingCache (thinking that it could be a cache related problem)
Is taking screenshot or 'share intent' too much of work for the UI thread to be blocked?
Can anyone shed a light here? I am completely at a loss.
I found a way to get around this. I created a composite bitmap out of the background bitmap and the overlay(my ad image) bitmap. In case anyone is interested, here's the code.
public Bitmap screenShot(View view) {
Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
view.draw(canvas);
Bitmap overlay = BitmapFactory.decodeResource(this.getResources() , R.drawable.my_ad);
canvas.drawBitmap(overlay, 100, 100, null);
return bitmap;
}

Waiting for camera to save photo, what is better than thread.sleep?

I have a custom OpenCV camera activity that takes a photo when the screen is tapped. The activity is started with a startActivityForResult intent, and the filepath of the photo is handed back to the MainActivity after the activity is finished. However, the camera saves the photo asynchronously and therefore the filepath shouldn't be checked until the photo is taken. I am using the filepath to set an imageView, and calling it immediately gives an empty image. I have managed to make it work by using Thread.sleep(3000); but this is a horrible option as it just stalls the UI which, as I've read countless times, is a big no no! Is there a way I can wait until the photo is saved before calling the return to MainActivity intent? I understand there is a callback from the camera but I don't understand how it works or how to use it, perhaps that is the best way to go?
Here's some code anyway.
in MainActivity extends FragmentActivity:
rootView.findViewById(R.id.button_start_camera).setOnClickListener(new View.OnClickListener() {
// Listen for Take Photo button Click, start app's openCV camera
#Override
public void onClick(View view) {
// Start Camera app
Intent intentCamera = new Intent(getActivity(), CameraActivity.class);
startActivityForResult(intentCamera, 2);
}
});
In CameraActivity extends Activity implements CvCameraViewListener2, OnTouchListener:
#Override
public boolean onTouch(View v, MotionEvent event) {
Log.i(TAG,"onTouch event");
if (takePicture) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd-HHmmss");
String currentDateandTime = sdf.format(new Date());
fileName = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getPath() +
"/MatCom_" + currentDateandTime + ".jpg";
mOpenCvCameraView.takePicture(fileName);
Toast.makeText(this, fileName + " saved", Toast.LENGTH_SHORT).show();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Intent returnIntent = new Intent();
returnIntent.putExtra("result", fileName);
setResult(RESULT_OK, returnIntent);
finish();
}
return false;
}
And then back to MainActivity:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent)
{
super.onActivityResult(requestCode, resultCode, intent);
Log.i(TAG, "onActivityResult. resultCode = " + requestCode);
if (requestCode == 1) {//My other startActivityForResult...}
if (requestCode == 131074 && resultCode == RESULT_OK){
Bundle bundle = intent.getExtras();
filepath = bundle.getString("result");
Log.i(TAG, filepath);
imageView = (ImageView) findViewById(R.id.imageView);
bmp = BitmapFactory.decodeFile(filepath);
imageView.setBackgroundResource(0);
imageView.setImageBitmap(bmp);
}
}
NOTICE: As an aside, for some reason my requestCode comes back as 131074 every time despite setting it at 2 for the startActivityForResult - let me know if you know why that is.
Finally, in case it's necessary to see, here's the takePicture method from the CameraView class:
public void takePicture(final String fileName) {
Log.i(TAG, "Taking picture");
PictureCallback callback = new PictureCallback() {
private String mPictureFileName = fileName;
#Override
public void onPictureTaken(byte[] data, Camera camera) {
Log.i(TAG, "Saving a bitmap to file");
Bitmap picture = BitmapFactory.decodeByteArray(data, 0, data.length);
try {
FileOutputStream out = new FileOutputStream(mPictureFileName);
picture.compress(Bitmap.CompressFormat.JPEG, 90, out);
picture.recycle();
// Open the image for analysis
// Read in the image from the file
Mat mOriginalImage = Highgui.imread(fileName);
// Only process the image if it actually exists!
if (mOriginalImage != null) {
// Find the size of the image
org.opencv.core.Size mSizeReadImage = mOriginalImage.size();
// From the number of rows and columns get the coordinates of the largest possible centralised square
double height = mSizeReadImage.height;
double width = mSizeReadImage.width;
double minDim = Math.min(height, width);
double top = height/2.0 - 2.0*minDim/5.0;
double left = width/2.0 - 2.0*minDim/5.0;
// Create a submat of the image based on the centralised square
Mat mOriginalImageSubmat = mOriginalImage.submat((int)Math.round(top), (int)Math.round(top + 4.0*minDim/5.0), (int)Math.round(left), (int)Math.round(left + 4.0*minDim/5.0));
// Create another Mat the required size but same type as mOriginalImageSubmat and resize mOriginalImageSubmat to fit into it
Mat mDrawableSubmat = new Mat(new Size(480.0, 480.0), mOriginalImageSubmat.type());
Imgproc.resize(mOriginalImageSubmat, mDrawableSubmat, mDrawableSubmat.size());
Mat mColourSourceSubmat = mDrawableSubmat.clone();
Mat mCannyOutput = mDrawableSubmat.clone();
double minLineLength = 300.0;
ColourMatrix matrix = new ColourMatrix();
matrix.setColourMatch(colourMatch);
matrix.setColourOrder(colourOrder);
matrix.setComparison(comparison);
matrix.setDisplayHotspots(displayHotspots);
matrix.setDisplayOutline(displayOutline);
matrix.setIntensity(intensity);
matrix.setMatrixType(matrixType);
String output = matrix.decode(mColourSourceSubmat, mCannyOutput, mDrawableSubmat, minLineLength);
Log.i(TAG, "DJH - decoded: " + output);
}
mCamera.startPreview();
} catch (Exception e) {
e.printStackTrace();
}
}
};
mCamera.takePicture(null, null, callback);
}
Thread.sleep isn't bad per se. You can use a loop to 30 with thread.sleep(100). Then you'll only be pausing .1 second at a time, and the CPU still won't spike.