Android Save Bitmap to Gallery – Download and Save Image from URL
Things are changing very fast in tech world. And if you want to be an Android Developer, then be ready to keep upgrading yourself. Actually this learning curve is the best thing that I like about this industry (My personal opinion). So, here is a new about about “Android Save Bitmap to Gallery”.
Saving file to internal storage, is required many times in our projects. We have done this thing many times before, but the method for saving file to internal storage has been changed completely for devices running with OS >= android10.
Basically your old way of saving files will not work with new versions of android, starting with android10. You can still go the old way, but it is a temporary solution. In this post we are going to talk about all these things.
File Storage in Android
Now, we have two kinds of storage to store files.
- App-specific storage: The files for your application only. Files store here cannot be accessed outside your application. And you do not need any permission to access this storage.
- Shared Storage: The files that can be shared with other apps as well. For example Media Files (Images, Videos, Audios), Documents and other files.
To know more details about File Storage in Android, you can go through this official guide.
In this post we will be saving a Bitmap to Shared Storage as an Image File.
To demonstrate saving file to internal storage in android10, I will be creating an app that will fetch an Image from the Given URL and then it will save it to external storage.
Android Save Bitmap to Gallery
Let’s first start with the main function, that we need to save a Bitmap instance to gallery as an Image File.
Let’s understand the above function.
- We have the bitmap instance that we want to save to our gallery in the function parameter.
- Then I’ve generated a file name using System . currentTimeMillis () , you apply your own logic here if you want a different file name. I used it just to generate a unique name quickly.
- Now we have created an OutputStream instance.
- The main thing here is we need to write two logics, because method of android 10 and above won’t work for lower versions; and that is why I have written a check here to identify if the device is > = VERSION_CODES . Q .
- Inside the if block, first I’ve got the ContentResolver from the Context .
- Inside ContentResolver , we have created ContentValues and inside ContentValues we have added the Image File informations.
- Now we have got the Uri after inserting the content values using the insert () function.
- After getting the Uri , we have opened output stream using openOutputStream () function.
- I am not explaining the else part, as it is the old way, that we already know.
- Finally using the output stream we are writing the Bitmap to stream using compress () function. And that’s it.
Now let’s build a complete application that will save image from an URL to the external storage.
Creating an Image Downloader Application
Again we will start by creating a new Android Studio project. I have created a project named ImageDownloader. And now we will start by adding all the required dependencies first.
Adding Permissions
For this app we require Internet and Storage permission. So define these permision in your AndroidManifest . xml file.
Источник
Практический опыт работы с Bitmap средствами Android
Не так давно по долгу службы я столкнулся с одной задачей: нужно было придумать и реализовать дизайн медиа-плеера для Android. И если продумать и организовать более или менее сносное размещение элементов управления и информации оказалось делом не хитрым, то чтобы привнести в дизайн какую-то изюминку, пришлось хорошенько подумать. К счастью, в запасе у меня был такой элемент, как картинка с обложкой альбома проигрываемой мелодии. Именно он должен был добавить красок всей картинке.
Однако, будучи просто выведенной среди кнопок и надписей, обложка выглядела бумажным стикером, наклеенным на экран. Я понял, что без обработки изображения здесь не обойтись.
Некоторые раздумья насчёт того, что можно было бы тут придумать увенчались решением сделать для изображения обложки эффект отражения и тени. Сразу оговорюсь, что практическая реализация отражения не является моей оригинальной идеей. Её я подсмотрел в найденной англоязычной статье. В настоящем посте я лишь хочу привести некоторое осмысление производимых над изображением манипуляций, свои дополнения к процессу обработки и отметить некоторые нюансы работы с Bitmap в Android.
Итак, на входе я имел Bitmap с картинкой. Для начала я создал пустой Bitmap размером с оригинальную картинку, который позже должен был стать той же обложкой, но с нанесённой на неё тенью.
Этот метод создаёт изменяемый (что важно) Bitmap.
Здесь обязательно нужно отметить, что при работе с Bitmap’ами необходимо внимательно следить за памятью. Придётся ловить исключения. И ещё один момент: изучение профайлером показало, что перед вызовом метода createBitmap() работает сборщик мусора. Учтите это, если в вашем приложении скорость работы критична.
Далее я создал холст и нанёс на него исходное изображение.
В этом месте отмечу, что всегда, как только Bitmap становится не нужен, его нужно уничтожать методом recycle(). Дело в том, что объект этого типа представляет собой всего лишь ссылку на память с самим изображением и выглядит для сборщика мусора очень маленьким (хотя на самом деле памяти занято много). Это может привести к тому, что память закончится в самый неподходящий момент.
После всей подготовки я нанёс на холст краску с тенью.
RadialGradient в моём случае представляет тень, падающую по полукругу из правого верхнего угла изображения в центр нижней грани. Ему нужно установить центр (может выходить за пределы картинки), радиус, последовательность цветов и расстояния от центра по радиусу для каждого цвета. Для тени использовалось изменение альфы в цветах на радиусе.
LinearGradient использовался для фэйда краёв картинки. Его применение очень похоже на RadialGradient. Нужно задать начало и конец линии, вдоль которой пойдёт градиент, цвета и их позиции на этой линии.
Наконец, я приступил к рисованию отражения. К этому моменту у меня уже был Bitmap с нанесёнными тенями gradBitmap. Опять надо было создавать холст, создавать пустое изображение (на этот раз на треть длиннее оригинального), помещать его на холст и наносить на верх него Bitmap с тенями.
После недолгих приготовлений начиналось самое интересное. Я создал матрицу, переворачивающую изображение снизу вверх. С её помощью создал Bitmap из трети исходного и нанёс его на холст под оригинальным изображением.
Кстати, краткое замечание: в классе Bitmap существует несколько методов createBitmap, и лишь один из них создаёт изменяемые Bitmap’ы, на которых можно рисовать. Остальные для рисования НА них не годятся.
И наконец, нанесение прозрачного градиента для придания эффекта отражения.
Краска наносится на ту часть рисунка, которая является отражением.
Всё. Я получил refCover — Bitmap, на котором изображена обложка альбома с тенью, сглаженными краями и отражением.
P.S. В данной статье для меня был важен не сам факт достижения визуальных эффектов, а способы их получения и нюансы, с ними связанные. Если для кого-то вещи, описанные здесь, очевидны — прекрасно. Всем остальным, я надеюсь, статья поможет в написании своих приложений под Android.
UPD: картинки ДО и ПОСЛЕ
Источник
mgochoa / AndroidManifest.xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
xml version = » 1.0 » encoding = » utf-8 » ?> |
LinearLayout xmlns : android = » http://schemas.android.com/apk/res/android « |
xmlns : tools = » http://schemas.android.com/tools « |
android : layout_width = » match_parent « |
android : layout_height = » match_parent « |
android : paddingBottom = » @dimen/activity_vertical_margin « |
android : paddingLeft = » @dimen/activity_horizontal_margin « |
android : paddingRight = » @dimen/activity_horizontal_margin « |
android : paddingTop = » @dimen/activity_vertical_margin « |
android : orientation = » vertical « |
tools : context = » com.example.loadphoto.MainActivity » > |
ImageView |
android : id = » @+id/imageview « |
android : layout_width = » 300dp « |
android : layout_height = » wrap_content « |
android : padding = » 8dp « |
android : layout_gravity = » center »/> |
Button |
android : id = » @+id/button « |
android : layout_width = » wrap_content « |
android : layout_height = » wrap_content « |
android : layout_gravity = » center « |
android : text = » Cargar Imagen « |
android : textSize = » 30sp « |
android : onClick = » loadImage »/> |
LinearLayout > |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
xml version = » 1.0 » encoding = » utf-8 » ?> |
manifest xmlns : android = » http://schemas.android.com/apk/res/android « |
package = » com.example.loadphoto » > |
uses-permission android : name = » android.permission.READ_EXTERNAL_STORAGE »/> |
uses-permission android : name = » android.permission.WRITE_EXTERNAL_STORAGE »/> |
application |
android : allowBackup = » true « |
android : icon = » @mipmap/ic_launcher « |
android : label = » @string/app_name « |
android : supportsRtl = » true « |
android : theme = » @style/AppTheme » > |
activity android : name = » .MainActivity » > |
intent-filter > |
action android : name = » android.intent.action.MAIN »/> |
category android : name = » android.intent.category.LAUNCHER »/> |
intent-filter > |
activity > |
application > |
manifest > |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
package com.example.loadphoto ; |
import android.graphics.Bitmap ; |
import android.graphics.BitmapFactory ; |
import java.io.ByteArrayOutputStream ; |
/** |
* Created by mguillermo.ochoa on 6/09/16. |
*/ |
public class BitmapHelper < |
// convert from bitmap to byte array |
public static byte [] getBytes ( Bitmap bitmap ) < |
ByteArrayOutputStream stream = new ByteArrayOutputStream (); |
bitmap . compress( Bitmap . CompressFormat . PNG , 0 , stream); |
return stream . toByteArray(); |
> |
// convert from byte array to bitmap |
public static Bitmap getImage ( byte [] image ) < |
return BitmapFactory . decodeByteArray(image, 0 , image . length); |
> |
> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
package com.example.loadphoto ; |
import android.content.Intent ; |
import android.database.Cursor ; |
import android.graphics.Bitmap ; |
import android.graphics.BitmapFactory ; |
import android.net.Uri ; |
import android.provider.MediaStore ; |
import android.support.v7.app.AppCompatActivity ; |
import android.os.Bundle ; |
import android.view.View ; |
import android.widget.Button ; |
import android.widget.ImageView ; |
public class MainActivity extends AppCompatActivity < |
private final int SELECT_PHOTO = 0 ; |
Button btnLoad; |
ImageView imageView; |
Bitmap yourSelectedImage; |
@Override |
protected void onCreate ( Bundle savedInstanceState ) < |
super . onCreate(savedInstanceState); |
setContentView( R . layout . activity_main); |
btnLoad = ( Button )findViewById( R . id . button); |
imageView = ( ImageView )findViewById( R . id . imageview); |
> |
public void loadImage ( View v ) < |
Intent photoPickerIntent = new Intent ( Intent . ACTION_PICK ); |
photoPickerIntent . setType( » image/* » ); |
startActivityForResult(photoPickerIntent, SELECT_PHOTO ); |
> |
protected void onActivityResult ( int requestCode , int resultCode , |
Intent imageReturnedIntent ) < |
super . onActivityResult(requestCode, resultCode, imageReturnedIntent); |
switch (requestCode) < |
case SELECT_PHOTO : |
if (resultCode == RESULT_OK ) < |
Uri selectedImage = imageReturnedIntent . getData(); |
String [] filePathColumn = < MediaStore . Images . Media . DATA >; |
Cursor cursor = getContentResolver() . query( |
selectedImage, filePathColumn, null , null , null ); |
cursor . moveToFirst(); |
int columnIndex = cursor . getColumnIndex(filePathColumn[ 0 ]); |
String filePath = cursor . getString(columnIndex); |
cursor . close(); |
yourSelectedImage = BitmapFactory . decodeFile(filePath); |
// Just testing the bitmap process was the same forwards and backwards |
imageView . setImageBitmap( BitmapHelper . getImage( BitmapHelper . getBytes(yourSelectedImage))); |
> |
> |
> |
> |
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Источник