I want to convert webview into PDF document and save the document in external storage. The pdf should be similar to the one which we can generate we we print the webview and chose save as pdf instead of printing.
Code for Webview:
WebView ww = (WebView) findViewById(R.id.ww);
ww.getSettings().setUserAgentString("Mozilla/5.0 Chrome/53.0.2785.116");
ww.getSettings().setDefaultTextEncodingName("en-US,en;q=0.8");
WebSettings webSettings = ww.getSettings();
webSettings.setJavaScriptEnabled(true);
ww.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
ww.getSettings().setBuiltInZoomControls(true);
ww.getSettings().setDisplayZoomControls(false);
ww.getSettings().setLoadWithOverviewMode(true);
ww.getSettings().setUseWideViewPort(true);
ww.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
You can convert the webview into a bitmap and then into a PDF document. The advantage of not converting directly to PDF is that you can scale the image to fit the PDF in any way you want.
This code converts a webview into a pdf page and then shares it, asking the user to select his printer app:
public static void sharePdfFile(WebView webView, Context context)
{
Bitmap bitmap = webviewToBitmap( webView );
PrintedPdfDocument pdf = bitmapToPdf( bitmap, context );
File file = pdfToFile( pdf, context );
shareFile( file,"application/pdf", context );
}
private static void shareFile(File file, String contentType, Context context)
{
Uri uri = FileProvider.getUriForFile(
context,
context.getPackageName() + ".fileprovider",
file);
Intent shareIntent = new Intent(android.content.Intent.ACTION_SEND);
shareIntent.setType(contentType);
shareIntent.putExtra(Intent.EXTRA_STREAM, uri);
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Toast.makeText(
context,
"Choose your printer app",
Toast.LENGTH_LONG
).show();
context.startActivity( shareIntent );
}
private static File pdfToFile(PrintedPdfDocument printedPdfDocument, Context context)
{
File file = new File(context.getFilesDir(), "share.pdf");
try {
FileOutputStream outputStream = new FileOutputStream(file);
printedPdfDocument.writeTo(outputStream);
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
printedPdfDocument.close();
return file;
}
private static PrintedPdfDocument bitmapToPdf(Bitmap bitmap, Context context)
{
PrintAttributes printAttributes = new PrintAttributes.Builder()
.setColorMode(PrintAttributes.COLOR_MODE_COLOR)
.setMediaSize(PrintAttributes.MediaSize.ISO_A4)
.setMinMargins(PrintAttributes.Margins.NO_MARGINS)
.setResolution(new PrintAttributes.Resolution("1", "label", 300, 300))
.build();
PrintedPdfDocument printedPdfDocument = new PrintedPdfDocument(context, printAttributes);
PdfDocument.Page pdfDocumentPage = printedPdfDocument.startPage(1);
Canvas pdfCanvas = pdfDocumentPage.getCanvas();
bitmap = scaleBitmapToHeight(bitmap, pdfCanvas.getHeight());
pdfCanvas.drawBitmap(bitmap, 0f, 0f, null);
printedPdfDocument.finishPage(pdfDocumentPage);
return printedPdfDocument;
}
private static Bitmap webviewToBitmap(WebView webView) {
webView.measure(
View.MeasureSpec.makeMeasureSpec(
0,
View.MeasureSpec.UNSPECIFIED
),
View.MeasureSpec.makeMeasureSpec(
0,
View.MeasureSpec.UNSPECIFIED
)
);
int webViewWidth = webView.getMeasuredWidth();
int webViewHeight = webView.getMeasuredHeight();
webView.layout(0,0, webViewWidth, webViewHeight );
Bitmap bitmap = Bitmap.createBitmap(webViewWidth, webViewHeight, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.drawBitmap(bitmap, 0, bitmap.getHeight(), new Paint());
webView.draw(canvas);
return bitmap;
}
private static Bitmap scaleBitmapToHeight(Bitmap bitmap, int maxHeight) {
int height = bitmap.getHeight();
if(height > maxHeight) {
int width = bitmap.getWidth();
float scalePercentage = ((float)maxHeight) / height;
return Bitmap.createScaledBitmap(bitmap, (int) (width * scalePercentage), maxHeight, false);
}
return bitmap;
}
Related
I was using RecyclerView to create PDF previously. I want to add share and print functionality for which I want to create PDF with content in it. The method I was using was
public static void generatePDF(RecyclerView view, boolean isShareTrue, Context context, boolean isWeekly) {
RecyclerView.Adapter adapter = view.getAdapter();
Bitmap bigBitmap = null;
if (adapter != null) {
int size = adapter.getItemCount();
int height = 0;
Paint paint = new Paint();
int iHeight = 0;
final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
// Use 1/8th of the available memory for this memory cache.
final int cacheSize = maxMemory / 8;
LruCache<String, Bitmap> bitmaCache = new LruCache<>(cacheSize);
for (int i = 0; i < size; i++) {
RecyclerView.ViewHolder holder = adapter.createViewHolder(view, adapter.getItemViewType(i));
adapter.onBindViewHolder(holder, i);
holder.itemView.measure(View.MeasureSpec.makeMeasureSpec(view.getWidth(), View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
holder.itemView.layout(0, 0, holder.itemView.getMeasuredWidth(), holder.itemView.getMeasuredHeight());
holder.itemView.setDrawingCacheEnabled(true);
holder.itemView.buildDrawingCache();
Bitmap drawingCache = holder.itemView.getDrawingCache();
if (drawingCache != null) {
bitmaCache.put(String.valueOf(i), drawingCache);
}
height += holder.itemView.getMeasuredHeight();
}
bigBitmap = Bitmap.createBitmap(view.getMeasuredWidth(), height, Bitmap.Config.ARGB_8888);
Canvas bigCanvas = new Canvas(bigBitmap);
bigCanvas.drawColor(Color.WHITE);
Document document = new Document(PageSize.A4);
File file;
if (isWeekly)
file = new File(Environment.getExternalStorageDirectory(), "Weekly_list_" + AppPreferences.INSTANCE.getUserId() + ".pdf");
else
file = new File(Environment.getExternalStorageDirectory(), "Open_Cycle_List_" + AppPreferences.INSTANCE.getUserId() + ".pdf");
try {
PdfWriter.getInstance(document, new FileOutputStream(file));
} catch (DocumentException | FileNotFoundException e) {
e.printStackTrace();
}
for (int i = 0; i < size; i++) {
try {
//Adding the content to the document
Bitmap bmp = bitmaCache.get(String.valueOf(i));
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bmp.compress(Bitmap.CompressFormat.PNG, 100, stream);
Image image = Image.getInstance(stream.toByteArray());
float scaler = ((document.getPageSize().getWidth() - document.leftMargin()
- document.rightMargin() - 0) / image.getWidth()) * 100; // 0 means you have no indentation. If you have any, change it.
image.scalePercent(scaler);
image.setAlignment(com.itextpdf.text.Image.ALIGN_CENTER | com.itextpdf.text.Image.ALIGN_TOP);
if (!document.isOpen()) {
document.open();
}
document.add(image);
} catch (Exception ex) {
Log.e("TAG-ORDER PRINT ERROR", ex.getMessage());
}
}
if (document.isOpen()) {
document.close();
}
if (isShareTrue) {
Intent intentShareFile = new Intent(Intent.ACTION_SEND);
if (file.exists()) {
Uri pdfUri;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
pdfUri = FileProvider.getUriForFile(context, context.getPackageName() + ".provider", file);
} else {
pdfUri = Uri.fromFile(file);
}
intentShareFile.setType("application/pdf");
intentShareFile.putExtra(Intent.EXTRA_STREAM, pdfUri);
intentShareFile.putExtra(Intent.EXTRA_SUBJECT, "Sharing File...");
intentShareFile.putExtra(Intent.EXTRA_TEXT, "Sharing File...");
context.startActivity(Intent.createChooser(intentShareFile, "Share File"));
}
} else {
Toast.makeText(context, "PDF Generated successfully", Toast.LENGTH_LONG).show();
}
}
}
Now I have replaced recycler view with ExpandableListView and my print and share functionality is not working.
I want to create PDF with ExpandableListView content.
I'm using such code for creating pdf from webview
PrintManager printManager = (PrintManager) this
.getSystemService(Context.PRINT_SERVICE);
PrintDocumentAdapter printAdapter = webView.createPrintDocumentAdapter("PDF");
printManager.print("PDF", printAdapter,
new PrintAttributes.Builder().build());
what should I do, to add to this pdf creation some TextView because I need to add additional fields to my fragment?
Know about itextg, but I need something free.
Choose an option to implement fields as html in webview
You can get a bitmap out of the webview and then draw the textview on the bitmap, using the bitmap canvas.
From there, you can convert the bitmap into a pdf and share the pdf.
Here is the code for converting a webview into a bitmap, and also converting a bitmap into a pdf and then sharing it, asking the user to select its printer app:
public static void sharePdfFile(WebView webView, Context context)
{
Bitmap bitmap = webviewToBitmap( webView );
PrintedPdfDocument pdf = bitmapToPdf( bitmap, context );
File file = pdfToFile( pdf, context );
shareFile( file,"application/pdf", context );
}
private static void shareFile(File file, String contentType, Context context)
{
Uri uri = FileProvider.getUriForFile(
context,
context.getPackageName() + ".fileprovider",
file);
Intent shareIntent = new Intent(android.content.Intent.ACTION_SEND);
shareIntent.setType(contentType);
shareIntent.putExtra(Intent.EXTRA_STREAM, uri);
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Toast.makeText(
context,
"Choose your printer app",
Toast.LENGTH_LONG
).show();
context.startActivity( shareIntent );
}
private static File pdfToFile(PrintedPdfDocument printedPdfDocument, Context context)
{
File file = new File(context.getFilesDir(), "share.pdf");
try {
FileOutputStream outputStream = new FileOutputStream(file);
printedPdfDocument.writeTo(outputStream);
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
printedPdfDocument.close();
return file;
}
private static PrintedPdfDocument bitmapToPdf(Bitmap bitmap, Context context)
{
PrintAttributes printAttributes = new PrintAttributes.Builder()
.setColorMode(PrintAttributes.COLOR_MODE_COLOR)
.setMediaSize(PrintAttributes.MediaSize.ISO_A4)
.setMinMargins(PrintAttributes.Margins.NO_MARGINS)
.setResolution(new PrintAttributes.Resolution("1", "label", 300, 300))
.build();
PrintedPdfDocument printedPdfDocument = new PrintedPdfDocument(context, printAttributes);
PdfDocument.Page pdfDocumentPage = printedPdfDocument.startPage(1);
Canvas pdfCanvas = pdfDocumentPage.getCanvas();
bitmap = scaleBitmapToHeight(bitmap, pdfCanvas.getHeight());
pdfCanvas.drawBitmap(bitmap, 0f, 0f, null);
printedPdfDocument.finishPage(pdfDocumentPage);
return printedPdfDocument;
}
private static Bitmap webviewToBitmap(WebView webView) {
webView.measure(
View.MeasureSpec.makeMeasureSpec(
0,
View.MeasureSpec.UNSPECIFIED
),
View.MeasureSpec.makeMeasureSpec(
0,
View.MeasureSpec.UNSPECIFIED
)
);
int webViewWidth = webView.getMeasuredWidth();
int webViewHeight = webView.getMeasuredHeight();
webView.layout(0,0, webViewWidth, webViewHeight );
Bitmap bitmap = Bitmap.createBitmap(webViewWidth, webViewHeight, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.drawBitmap(bitmap, 0, bitmap.getHeight(), new Paint());
webView.draw(canvas);
return bitmap;
}
private static Bitmap scaleBitmapToHeight(Bitmap bitmap, int maxHeight) {
int height = bitmap.getHeight();
if(height > maxHeight) {
int width = bitmap.getWidth();
float scalePercentage = ((float)maxHeight) / height;
return Bitmap.createScaledBitmap(bitmap, (int) (width * scalePercentage), maxHeight, false);
}
return bitmap;
}
I have created the bitmap and have created the pdf file for the bitmap.
but I need to generate pdf for the whole listview which is scrollable.
Given below is is my code, please give me any suggestion, thanks in advance!!
I could not find the pdf creating application which could copy the entire UI or say in my case the entire listview into the pdf. If anybody could suggest what could be done in this case I would be grateful.
public class MainActivity extends AppCompatActivity {
private Button btn;
private LinearLayout llScroll;
private Bitmap bitmap;
private ListView listView;
ArrayList<String> myList;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn = findViewById(R.id.btn);
llScroll = findViewById(R.id.llScroll);
listView = (ListView)findViewById(R.id.listView);
String[] names= new String[]{"One","Two","Three","Four","Five","Six","Seven","One","Two","Three","Four","Five","Six","Seven"};
ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,android.R.id.text1,names);
listView.setAdapter(arrayAdapter);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d("size"," "+llScroll.getWidth() +" "+llScroll.getWidth());
bitmap = loadBitmapFromView(llScroll, llScroll.getWidth(), llScroll.getHeight());
createPdf();
}
});
}
public static Bitmap loadBitmapFromView(View v, int width, int height) {
Bitmap b = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
v.draw(c);
return b;
}
private void createPdf(){
DisplayMetrics displaymetrics = new DisplayMetrics();
this.getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
float hight = displaymetrics.heightPixels ;
float width = displaymetrics.widthPixels ;
int convertHighet = (int) hight, convertWidth = (int) width;
PdfDocument document = new PdfDocument();
PdfDocument.PageInfo pageInfo = new PdfDocument.PageInfo.Builder(convertWidth, convertHighet, 1).create();
PdfDocument.Page page = document.startPage(pageInfo);
Canvas canvas = page.getCanvas();
Paint paint = new Paint();
canvas.drawPaint(paint);
bitmap = Bitmap.createScaledBitmap(bitmap, convertWidth, convertHighet, true);
paint.setColor(Color.BLUE);
canvas.drawBitmap(bitmap, 0, 0 , null);
document.finishPage(page);
// write the document content
String targetPdf = "/sdcard/pdffromScroll.pdf";
File filePath;
filePath = new File(targetPdf);
try {
document.writeTo(new FileOutputStream(filePath));
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(this, "Something wrong: " + e.toString(), Toast.LENGTH_LONG).show();
}
// close the document
document.close();
Toast.makeText(this, "PDF of Scroll is created!!!", Toast.LENGTH_SHORT).show();
openGeneratedPDF();
}
private void openGeneratedPDF(){
File file = new File("/sdcard/pdffromScroll.pdf");
if (file.exists())
{
Intent intent=new Intent(Intent.ACTION_VIEW);
Uri uri = Uri.fromFile(file);
intent.setDataAndType(uri, "application/pdf");
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
try
{
startActivity(intent);
}
catch(ActivityNotFoundException e)
{
Toast.makeText(MainActivity.this, "No Application available to view pdf", Toast.LENGTH_LONG).show();
}
}
}}
ARCore camera doesn't seem to support takePicture.
https://developers.google.com/ar/reference/java/com/google/ar/core/Camera
Anyone know how I can take pictures with ARCore?
I am assuming you mean a picture of what the camera is seeing and the AR objects. At a high level you need to get permission to write to external storage to save the picture, copy the frame from OpenGL and then save it as a png (for example). Here are the specifics:
Add the WRITE_EXTERNAL_STORAGE permission to the AndroidManifest.xml
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Then change CameraPermissionHelper to iterate over both the CAMERA and WRITE_EXTERNAL_STORAGE permissions to make sure they are granted
private static final String REQUIRED_PERMISSIONS[] = {
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.CAMERA
};
/**
* Check to see we have the necessary permissions for this app.
*/
public static boolean hasCameraPermission(Activity activity) {
for (String p : REQUIRED_PERMISSIONS) {
if (ContextCompat.checkSelfPermission(activity, p) !=
PackageManager.PERMISSION_GRANTED) {
return false;
}
}
return true;
}
/**
* Check to see we have the necessary permissions for this app,
* and ask for them if we don't.
*/
public static void requestCameraPermission(Activity activity) {
ActivityCompat.requestPermissions(activity, REQUIRED_PERMISSIONS,
CAMERA_PERMISSION_CODE);
}
/**
* Check to see if we need to show the rationale for this permission.
*/
public static boolean shouldShowRequestPermissionRationale(Activity activity) {
for (String p : REQUIRED_PERMISSIONS) {
if (ActivityCompat.shouldShowRequestPermissionRationale(activity, p)) {
return true;
}
}
return false;
}
Next, add a couple fields to HelloARActivity to keep track of the dimensions of the frame and boolean to indicate when to save the picture.
private int mWidth;
private int mHeight;
private boolean capturePicture = false;
Set the width and height in onSurfaceChanged()
public void onSurfaceChanged(GL10 gl, int width, int height) {
mDisplayRotationHelper.onSurfaceChanged(width, height);
GLES20.glViewport(0, 0, width, height);
mWidth = width;
mHeight = height;
}
At the bottom of onDrawFrame(), add a check for the capture flag. This should be done after all the other drawing happens.
if (capturePicture) {
capturePicture = false;
SavePicture();
}
Then add the onClick method for a button to take the picture, and the actual code to save the image:
public void onSavePicture(View view) {
// Here just a set a flag so we can copy
// the image from the onDrawFrame() method.
// This is required for OpenGL so we are on the rendering thread.
this.capturePicture = true;
}
/**
* Call from the GLThread to save a picture of the current frame.
*/
public void SavePicture() throws IOException {
int pixelData[] = new int[mWidth * mHeight];
// Read the pixels from the current GL frame.
IntBuffer buf = IntBuffer.wrap(pixelData);
buf.position(0);
GLES20.glReadPixels(0, 0, mWidth, mHeight,
GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, buf);
// Create a file in the Pictures/HelloAR album.
final File out = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES) + "/HelloAR", "Img" +
Long.toHexString(System.currentTimeMillis()) + ".png");
// Make sure the directory exists
if (!out.getParentFile().exists()) {
out.getParentFile().mkdirs();
}
// Convert the pixel data from RGBA to what Android wants, ARGB.
int bitmapData[] = new int[pixelData.length];
for (int i = 0; i < mHeight; i++) {
for (int j = 0; j < mWidth; j++) {
int p = pixelData[i * mWidth + j];
int b = (p & 0x00ff0000) >> 16;
int r = (p & 0x000000ff) << 16;
int ga = p & 0xff00ff00;
bitmapData[(mHeight - i - 1) * mWidth + j] = ga | r | b;
}
}
// Create a bitmap.
Bitmap bmp = Bitmap.createBitmap(bitmapData,
mWidth, mHeight, Bitmap.Config.ARGB_8888);
// Write it to disk.
FileOutputStream fos = new FileOutputStream(out);
bmp.compress(Bitmap.CompressFormat.PNG, 100, fos);
fos.flush();
fos.close();
runOnUiThread(new Runnable() {
#Override
public void run() {
showSnackbarMessage("Wrote " + out.getName(), false);
}
});
}
Last step is to add the button to the end of activity_main.xml layout
<Button
android:id="#+id/fboRecord_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignStart="#+id/surfaceview"
android:layout_alignTop="#+id/surfaceview"
android:onClick="onSavePicture"
android:text="Snap"
tools:ignore="OnClick"/>
Acquiring the image buffer
In the latest ARCore SDK, we get access to the image buffer via public class Frame. Below is the sample code which gives us access to the image buffer.
private void onSceneUpdate(FrameTime frameTime) {
try {
Frame currentFrame = sceneView.getArFrame();
Image currentImage = currentFrame.acquireCameraImage();
int imageFormat = currentImage.getFormat();
if (imageFormat == ImageFormat.YUV_420_888) {
Log.d("ImageFormat", "Image format is YUV_420_888");
}
}
onSceneUpdate() will be called for every update if you register it to setOnUpdateListener() callback. Image will be in YUV_420_888 format, but it will have full Field of view of native high resolution camera.
Also do not forget to close resources of received image by calling currentImage.close(). Otherwise you will receive a ResourceExhaustedException on the next run of onSceneUpdate.
Writing the acquired image buffer to a file
Following implementation converts YUV buffer to compressed JPEG byte array
private static byte[] NV21toJPEG(byte[] nv21, int width, int height) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
YuvImage yuv = new YuvImage(nv21, ImageFormat.NV21, width, height, null);
yuv.compressToJpeg(new Rect(0, 0, width, height), 100, out);
return out.toByteArray();
}
public static void WriteImageInformation(Image image, String path) {
byte[] data = null;
data = NV21toJPEG(YUV_420_888toNV21(image),
image.getWidth(), image.getHeight());
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(path));
bos.write(data);
bos.flush();
bos.close();
}
private static byte[] YUV_420_888toNV21(Image image) {
byte[] nv21;
ByteBuffer yBuffer = image.getPlanes()[0].getBuffer();
ByteBuffer uBuffer = image.getPlanes()[1].getBuffer();
ByteBuffer vBuffer = image.getPlanes()[2].getBuffer();
int ySize = yBuffer.remaining();
int uSize = uBuffer.remaining();
int vSize = vBuffer.remaining();
nv21 = new byte[ySize + uSize + vSize];
//U and V are swapped
yBuffer.get(nv21, 0, ySize);
vBuffer.get(nv21, ySize, vSize);
uBuffer.get(nv21, ySize + vSize, uSize);
return nv21;
}
Sorry for answering late.You can use code to click picture in ARCore:
private String generateFilename() {
String date =
new SimpleDateFormat("yyyyMMddHHmmss", java.util.Locale.getDefault()).format(new Date());
return Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES) + File.separator + "Sceneform/" + date + "_screenshot.jpg";
}
private void saveBitmapToDisk(Bitmap bitmap, String filename) throws IOException {
File out = new File(filename);
if (!out.getParentFile().exists()) {
out.getParentFile().mkdirs();
}
try (FileOutputStream outputStream = new FileOutputStream(filename);
ByteArrayOutputStream outputData = new ByteArrayOutputStream()) {
bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputData);
outputData.writeTo(outputStream);
outputStream.flush();
outputStream.close();
} catch (IOException ex) {
throw new IOException("Failed to save bitmap to disk", ex);
}
}
private void takePhoto() {
final String filename = generateFilename();
/*ArSceneView view = fragment.getArSceneView();*/
mSurfaceView = findViewById(R.id.surfaceview);
// Create a bitmap the size of the scene view.
final Bitmap bitmap = Bitmap.createBitmap(mSurfaceView.getWidth(), mSurfaceView.getHeight(),
Bitmap.Config.ARGB_8888);
// Create a handler thread to offload the processing of the image.
final HandlerThread handlerThread = new HandlerThread("PixelCopier");
handlerThread.start();
// Make the request to copy.
PixelCopy.request(mSurfaceView, bitmap, (copyResult) -> {
if (copyResult == PixelCopy.SUCCESS) {
try {
saveBitmapToDisk(bitmap, filename);
} catch (IOException e) {
Toast toast = Toast.makeText(DrawAR.this, e.toString(),
Toast.LENGTH_LONG);
toast.show();
return;
}
Snackbar snackbar = Snackbar.make(findViewById(android.R.id.content),
"Photo saved", Snackbar.LENGTH_LONG);
snackbar.setAction("Open in Photos", v -> {
File photoFile = new File(filename);
Uri photoURI = FileProvider.getUriForFile(DrawAR.this,
DrawAR.this.getPackageName() + ".ar.codelab.name.provider",
photoFile);
Intent intent = new Intent(Intent.ACTION_VIEW, photoURI);
intent.setDataAndType(photoURI, "image/*");
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(intent);
});
snackbar.show();
} else {
Log.d("DrawAR", "Failed to copyPixels: " + copyResult);
Toast toast = Toast.makeText(DrawAR.this,
"Failed to copyPixels: " + copyResult, Toast.LENGTH_LONG);
toast.show();
}
handlerThread.quitSafely();
}, new Handler(handlerThread.getLooper()));
}
I want to design an app that generates a QR code and gives the user the possibility to save the generated image to their internal storage only. I successfully generate the bitmap and save it as .PNG image, but when I try to open it from the gallery it appears broken or corrupt.
Below is the code to generate the bitmap and display it on an ImageView(qrCode):
bitmap = encodeAsBitmap(value);
qrCode.setImageBitmap(bitmap);
Bitmap encodeAsBitmap(String str) throws WriterException {
BitMatrix result;
try {
result = new MultiFormatWriter().encode(str,
BarcodeFormat.QR_CODE, WIDTH, WIDTH, null);
} catch (IllegalArgumentException iae) {
// Unsupported format
return null;
}
int w = result.getWidth();
int h = result.getHeight();
int[] pixels = new int[w * h];
for (int y = 0; y < h; y++) {
int offset = y * w;
for (int x = 0; x < w; x++) {
pixels[offset + x] = result.get(x, y) ? getResources().getColor(R.color.colorBlack) :
getResources().getColor(R.color.colorWhite);
}
}
Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
bitmap.setPixels(pixels, 0, 500, 0, 0, w, h);
return bitmap;
}
It works perfectly up to this level. The user can then click a button in order to save this image to their device's internal storage, thanks to the below method:
public void onClickSaveCode(View view) {
String title = getResources().getString(R.string.saved_image_title_prepend) + stringDate;
String format = getResources().getString(R.string.saved_image_format);
String directory = getResources().getString(R.string.saved_image_directory);
// Method call to save image
saveImageToInternalStorage(bitmap, directory, title, format);
}
public boolean saveImageToInternalStorage(Bitmap bitmap, String directory, String title, String format) {
ContextWrapper contextWrapper = new ContextWrapper(getApplicationContext());
File imageDirectory = contextWrapper.getDir(directory, Context.MODE_WORLD_READABLE);
File path = new File(imageDirectory, title + format);
try {
FileOutputStream fos = new FileOutputStream(path);
// Use the compress method on the Bitmap object to write image to the OutputStream
bitmap.compress(Bitmap.CompressFormat.PNG, QUALITY, fos);
fos.close();
new SingleMediaScanner(this, path);
Toast.makeText(this, getString(R.string.save_success), Toast.LENGTH_LONG).show();
return true;
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(this, getString(R.string.save_failure), Toast.LENGTH_LONG).show();
return false;
}
}
And finally below is the MediaScannerConnection class to scan for all images saved to the device and display them in the gallery:
public class SingleMediaScanner implements MediaScannerConnectionClient {
private MediaScannerConnection mSC;
private File file;
public SingleMediaScanner(Context context, File f) {
file = f;
mSC = new MediaScannerConnection(context, this);
mSC.connect();
}
#Override
public void onMediaScannerConnected() {
mSC.scanFile(file.getAbsolutePath(), null);
}
#Override
public void onScanCompleted(String path, Uri uri) {
mSC.disconnect();
}
}
The images are saved, yet they appear in the gallery as broken files.
Any help will be greatly appreciated.
string path = Android.OS.Environment.ExternalStorageDirectory.AbsolutePath;
string filePath = System.IO.Path.Combine(path, "compressed.png");
//Bitmap bmp = ((BitmapDrawable)imgV.Drawable).Bitmap;
Bitmap b = newBitmap;
FileStream ms = new FileStream(filePath, FileMode.Create);
//FileOutputStream fos = new FileOutputStream(filePath,true);
await b.CompressAsync(Bitmap.CompressFormat.Png, 100, ms);
ms.Close();
//ByteArrayOutputStream opstream = new ByteArrayOutputStream();
//b.Compress(Bitmap.CompressFormat.Png, 100, opstream);
//byte[] bytArray = opstream.ToByteArray();
Toast.MakeText(Application.Context, "Compressed : " , ToastLength.Short).Show();
imgCompress.SetImageBitmap(b);