I have this function in my MainActivity.kt file which I want to produce a screenshot of the google map being rendered, then display it in an image view and save it. This is related to what I am trying to do but I don't have enough experience with Kotlin, Java and android studio to understand what isn't working.
My main issue is that I can't figure out how to get / access a variable containing the Bitmap
This is being added to the code from This Google Tutorial
private fun takePicture(googleMap: GoogleMap) {
var bitmapfrommap: Bitmap? = null
val snapshotReadyCallback : GoogleMap.SnapshotReadyCallback = GoogleMap.SnapshotReadyCallback {
fun onSnapshotReady(snapshot: Bitmap) {
bitmapfrommap = snapshot
imageView.setImageBitmap(bitmapfrommap)
var filename = "export.png"
var path = getExternalFilesDir(null)
var fileOut = File(path, filename)
if (bitmapfrommap != null) {
fileOut.writeBitmap(bitmapfrommap!!, Bitmap.CompressFormat.PNG, 85)
}
}
}
val onMapLoadedCallback : GoogleMap.OnMapLoadedCallback = GoogleMap.OnMapLoadedCallback {
googleMap.snapshot(snapshotReadyCallback, bitmapfrommap)
}
googleMap.setOnMapLoadedCallback(onMapLoadedCallback)
}
binding.takeMapScreenshot.setOnClickListener {
myMap?.snapshot { bitmap -> //here you do whatever you want with the resulting bitmap }
}
Related
GoogleMap composes support maker icons but does not help get from Url, I hope some coding helps customer properties Icons image easy more. But If you have a solution good more, please comment here
Code in GoogleMap compose
val bitmapState = remember {
mutableStateOf<BitmapDescriptor?>(null)
}
LaunchedEffect(key1 = locationFocus.value.imageUrl) {
getBitmapFromURL(locationFocus.value.imageUrl)?.let { bm ->
getResizedBitmap(bm, 150, 150)?.let {
getRoundedCornerBitmap(it)?.let {
bitmapState.value =
BitmapDescriptorFactory.fromBitmap(it)
}
}
}
}
Marker(
state = MarkerState(position = cameraPositionState.position.target),
title = locationFocus.value.name,
snippet = locationFocus.value.address,
icon = bitmapState.value,
)
}
//Get Bitmap from Url
suspend fun getBitmapFromURL(imgUrl: String?): Bitmap? =
withContext(Dispatchers.IO) {
try {
val url = URL(imgUrl)
val connection: HttpURLConnection =
url.openConnection() as HttpURLConnection
connection.doInput = true
connection.connect()
val input: InputStream = connection.inputStream
BitmapFactory.decodeStream(input)
} catch (e: IOException) {
// Log exception
null
}
}
//Resize Image Bitmap
fun getResizedBitmap(bm: Bitmap, newWidth: Int, newHeight: Int): Bitmap? {
...
bm.recycle()
return resizedBitmap
}
//Border Bitmap
fun getRoundedCornerBitmap(bitmap: Bitmap): Bitmap? {
...
return output
}
If you have another code simple please comment. Good job
Image result marker icon google map compose.
I am using below code to save image data into local directory from Uris obtained through pick intent.
private fun sendImages(uriString: String, messageBody: String, uriList: ArrayList<Uri>) {
val pathList = mutableListOf<String>()
val fileNameList = mutableListOf<String>()
var fieSize = 0
var multiSize = 0
if(uriList.isEmpty() && uriString.isNotEmpty())
uriList.add(Uri.parse(uriString))
val localId: String = "localId"
for(i in 0 until uriList.size) {
val uri = uriList[i]
val path = FileUtils.getPath(application, uri)!!
val fullName = path.substring(path.lastIndexOf("/") + 1)
val name = "some function call that returns unique name for file"
val file = File(requireActivity().applicationContext.filesDir, localId + name)
file.createNewFile()
var bitmapdata: ByteArray? = null
var inputStream: InputStream? = null
try {
val ei = ExifInterface(path)
val orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED)
var bitmap: Bitmap? = null
bitmap = if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
ImageDecoder.decodeBitmap(ImageDecoder.createSource(requireActivity().applicationContext.contentResolver, uri))
}
else MediaStore.Images.Media.getBitmap(requireActivity().applicationContext.contentResolver, uri)
val newBitmap = FunctionUtil.rotateImage(bitmap, orientation)
bitmapdata = FileUtils.getCompressedBitmapForUpload(newBitmap!!)
FunctionUtil.recycleBitmap(newBitmap)
} catch (e: Exception) {
return
}
}
requireActivity().applicationContext.openFileOutput(file.name, Context.MODE_PRIVATE).use {
it.write(bitmapdata)
}
val localPath = FunctionUtil.getMediaStorePath(requireActivity().application)
val completePath = requireActivity().application.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)!!
var outFile =File(localPath+"/"+file.name)
org.apache.commons.io.FileUtils.copyFile(file,outFile)
Logger.log("PATH ${ outFile.absolutePath} ${ outFile.path}")
pathList.add(outFile.absolutePath)
fileNameList.add(file.name)
//... Do something with this data
}
}
In the same code, if single file is copied to local directory, it is getting saved & i am able to send it . But whenever i try to save multiple files, the files are becoming empty when i try to send them.
I am not able to find what issue is there. Please help
Some Android phones will encounter such a problem :
the file does exist, but the 'fd' returned by the 'c++ open()' method is -1, and the 'strerror' showing 'No such file or directory".
The phones I have come across are as follows:
vivo
V2055A V2073A V2241A
huawei
GIA-AN00 JLH-AN00 CMA-AN00 HPB-AN00 NTN-AN20 CMA-AN40
oppo
LE2110
In the source code of the Android System, a similar phenomenon can also be found :
The above is a comment added in 2017, and only the common 'bmp' and 'ico' formats are written.
In face, this problem also occurs with pictures in 'heif/heic' format.
Finally,
Using 'FileInputStream' will be ok.
In fragment A, I trying to get image object from server and store them into totalListImage. This steps works fine.
var totalListImage: MutableList<Image> = mutableListOf()
fun getWorkRequestImage() {
GlobalScope.launch(Dispatchers.Main) {
val request = WebApi.getImages(activity, obj?.id!!)
request?.images?.let {
for (i in it!!.iterator()) {
totalListImage?.add(i)
}
}
mImageListAdapter.notifyDataSetChanged()
}
}
In same fragment, I allow user to take image and store the captured image into totalListImage.
Here onActivityResult
var path = data?.getExtras()?.getString("bitmap")
if (path != null) {
Log.d(TAG,path)
val images = Image()
images.image?.url = path
totalListImage.add(images)
display()
}
Finally in display method, I want to display all the url. But I get null pointer on the last captured image.
fun display() {
for (i in totalListImage) {
Log.d(TAG, i.image?.url)
}
}
If I remove the captured image, I get this
D/AFragment: https://xxx/image/633/1562424667277.png
D/AFragment: https://xxx/image/637/1562426838223.png
The path of the captured image confirm not null, as I display it I saw this
D/AFragment: /data/user/0/xxxk/cache/images/1562437144046.png
Why I can't save the last image's path into images.image?.url ?
Images
class Images : Serializable {
#PrimaryKey
var id = ""
#Ignore
var image : Image?=null
}
Image
#Parcelize
class Image(
#ColumnInfo(name = "image")
var url: String ? =null
) : Serializable,Parcelable
Referring to this code:
val images = Image()
images.image?.url = path
totalListImage.add(images)
and assuming that you meant val images = Images() (otherwise this snippet won't even compile),
then the issue is that images.image is null.
That's because of the definition of the Images class, where you have var image : Image?=null.
To solve you either:
change the class definition to have a not-null default value, like:
var image : Image? = Image()
or manually initialize it in the snippet above, like:
val images = Images()
images.image = Image()
images.image?.url = path
totalListImage.add(images)
I am new to Android Studio and especially to Kotlin. I need to load image from internet and then save it to phone. I tried to load image with Glide as Bitmap and then save it. But it doesn't work. This code is best thing i found but it doesn't work.
try {
var bitmap = Glide.with(this)
.asBitmap()
.load("https://s3.amazonaws.com/appsdeveloperblog/Micky.jpg")
.apply(RequestOptions().override(100).downsample(DownsampleStrategy.CENTER_INSIDE).skipMemoryCache(true).diskCacheStrategy(DiskCacheStrategy.NONE))
.submit().get()
val wrapper = ContextWrapper(applicationContext)
var file = wrapper.getDir("Images", Context.MODE_PRIVATE)
file = File(file, "img.jpg")
val out = FileOutputStream(file)
bitmap.compress(Bitmap.CompressFormat.JPEG, 85, out)
out.flush()
out.close()
}
catch (e: Exception) {
println(e)
}
How I understood problem is in this ".submit().get()" part of Glide. But if I take it away then compress doesn't work.
submit(): Returns a future that can be used to do a blocking get on a background thread.
get(): Waits if necessary for the computation to complete, and then retrieves its result.
In your case to download an image from a url and save it to internal storage, you should use a background thread to do that. If you calling on main thread, your app might be throws ANR dialog.
Here I will demo how to download and save the image by using AsyncTask API
First write a class to download and save the image.
class DownloadAndSaveImageTask(context: Context) : AsyncTask<String, Unit, Unit>() {
private var mContext: WeakReference<Context> = WeakReference(context)
override fun doInBackground(vararg params: String?) {
val url = params[0]
val requestOptions = RequestOptions().override(100)
.downsample(DownsampleStrategy.CENTER_INSIDE)
.skipMemoryCache(true)
.diskCacheStrategy(DiskCacheStrategy.NONE)
mContext.get()?.let {
val bitmap = Glide.with(it)
.asBitmap()
.load(url)
.apply(requestOptions)
.submit()
.get()
try {
var file = it.getDir("Images", Context.MODE_PRIVATE)
file = File(file, "img.jpg")
val out = FileOutputStream(file)
bitmap.compress(Bitmap.CompressFormat.JPEG, 85, out)
out.flush()
out.close()
Log.i("Seiggailion", "Image saved.")
} catch (e: Exception) {
Log.i("Seiggailion", "Failed to save image.")
}
}
}
}
Then in activity just call
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
DownloadAndSaveImageTask(this).execute("https://s3.amazonaws.com/appsdeveloperblog/Micky.jpg")
}
}
If you want to save to internal storage
var file = File(it.filesDir, "Images")
if (!file.exists()) {
file.mkdir()
}
file = File(file, "img.jpg")
It will save the image in path data/data/yourapppackagename/files/Images/img.jpg
Just use this method
fun DownloadImageFromPath(path: String?) {
var `in`: InputStream? = null
var bmp: Bitmap? = null
val iv = findViewById<View>(R.id.imagFullImage) as ImageView
var responseCode = -1
try {
val url = URL(path) //"http://192.xx.xx.xx/mypath/img1.jpg
val con: HttpURLConnection = url.openConnection() as HttpURLConnection
con.setDoInput(true)
con.connect()
responseCode = con.getResponseCode()
if (responseCode == HttpURLConnection.HTTP_OK) {
//download
`in` = con.getInputStream()
bmp = BitmapFactory.decodeStream(`in`)
`in`.close()
iv.setImageBitmap(bmp)
}
} catch (ex: Exception) {
Log.e("Exception", ex.toString())
}
}
I have a recyclerview that displays a list of images in the GIF format using Fresco, a library for Android.
When the user clicks on an image in the recyclerview, I need to be able to fetch the .gif file and store it as somename.gif
I tried this code:
val contentRequest = ImageRequest.fromUri(items[position])
val cacheKey = DefaultCacheKeyFactory.getInstance().getEncodedCacheKey(contentRequest, null)
val imageResource = ImagePipelineFactory.getInstance().mainFileCache.getResource(cacheKey)
val file = (imageResource as FileBinaryResource).file
Log.d("VED-APP", file.name)
But the result ends up being: Lw0g1Jq7J0jUxSCCEZe3UwRa6-0.cnt, which is different from "somename.gif".
So, I tried this code instead:
val contentRequest = ImageRequest.fromUri(items[position])
val imagePipeline = Fresco.getImagePipeline()
val dataSource : DataSource<CloseableReference<CloseableImage>> =
imagePipeline.fetchDecodedImage(contentRequest, null)
But, the problem is, I need to write the object dataSource to a file.
I found this code sample that could help me write dataSource to a file, but I don't know how to convert it into Kotlin. Could someone help me out in converting this?
Or, if anyone knows of a better way to fetch files from Fresco, could they suggest an alternative method?
DataSource<CloseableReference<T>> dataSource = ...;
DataSubscriber<CloseableReference<T>> dataSubscriber =
new BaseDataSubscriber<CloseableReference<T>>() {
#Override
protected void onNewResultImpl(
DataSource<CloseableReference<T>> dataSource) {
if (!dataSource.isFinished()) {
// if we are not interested in the intermediate images,
// we can just return here.
return;
}
CloseableReference<T> ref = dataSource.getResult();
if (ref != null) {
try {
// do something with the result
T result = ref.get();
...
} finally {
CloseableReference.closeSafely(ref);
}
}
}
#Override
protected void onFailureImpl(DataSource<CloseableReference<T>> dataSource) {
Throwable t = dataSource.getFailureCause();
// handle failure
}
};
dataSource.subscribe(dataSubscriber, executor);
Important Update One -
I figured out how to convert most of the above code to Kotlin. The only problem is that I don't know how to use the appropriate executor to subscribe to the dataSubscriber, see the code below for clarification.
According to the documentation, I should be using a background thread executor, but I'm not sure how to do that in Kotlin.
val dataSubscriber : DataSubscriber<CloseableReference<CloseableImage>> =
object : BaseDataSubscriber<CloseableReference<CloseableImage>>() {
override fun onNewResultImpl(dataSource: DataSource<CloseableReference<CloseableImage>>?) {
if(!dataSource!!.isFinished) {
return
}
val ref : CloseableReference<CloseableImage>? = dataSource.result
if(ref != null) {
try {
val result = ref.get()
} finally {
CloseableReference.closeSafely(ref)
}
}
}
override fun onFailureImpl(dataSource: DataSource<CloseableReference<CloseableImage>>?) {
Log.d("VED-APP","Fresco Failed to Fetch?")
}
}
val contentRequest = ImageRequest.fromUri(items[position])
val imagePipeline = Fresco.getImagePipeline()
val dataSource : DataSource<CloseableReference<CloseableImage>> =
imagePipeline.fetchDecodedImage(contentRequest, null)
dataSource.subscribe(dataSubscriber,/*I don't know what to put here */)