I implemented share image to other apps using intent, I followed the recommended approach by saving the image first then getting its LocalBitmapUri. but when i run the app and share image i get the Toast message [The file format is not supported]. and i cant seem to figure out what I did wrong.. thanks.
fun shareItem(url: String?,context: Context,scope: CoroutineScope) {
scope.launch {
withContext(Dispatchers.IO){
val i = Intent(Intent.ACTION_SEND)
i.type = "image/*"
i.putExtra(Intent.EXTRA_STREAM,
getBitmap("d",context,"https://cdn2.thecatapi.com/images/3o8.jpg")?.let {
getLocalBitmapUri(
it,
context
)
})
startActivity(context,Intent.createChooser( i, "Share Image"),null)
}
}
}
fun getLocalBitmapUri(bmp: Bitmap,context: Context): Uri? {
val builder = VmPolicy.Builder()
StrictMode.setVmPolicy(builder.build())
var bmpUri: Uri? = null
try {
val file = File(
context.getExternalFilesDir(Environment.DIRECTORY_PICTURES),
"share_image_jj" + System.currentTimeMillis() + ".png"
)
val out = FileOutputStream(file)
bmp.compress(Bitmap.CompressFormat.PNG, 90, out)
out.close()
bmpUri = Uri.fromFile(file)
} catch (e: IOException) {
e.printStackTrace()
}
return bmpUri
}
private suspend fun getBitmap(tag: String, context: Context, imageUrl: String): Bitmap? {
var bitmap: Bitmap? = null
val imageRequest = ImageRequest.Builder(context)
.data(imageUrl)
.target(
...//,
onSuccess = { result ->
Log.e(tag, "Coil loader success.")
bitmap = result.toBitmap()
}
)
.build()
context.imageLoader.execute(imageRequest)
return bitmap
}
Related
I am trying to take a screenshot of the displayed activity.
In this case, the activity contains a webview (wvMainView).
The problem is, the main content of the screen (usually a chart), does not appear in the screenshot. The only time I get the full screenshot is when I have a table inside the webpage.
Here is the code for the screenshot:
var lMainActivityLayout: ConstraintLayout? = findViewById(R.id.lMainActivityLayout)
val bitmap = getScreenShotFromView(lMainActivityLayout!!)
// val bitmap = getScreenShotFromView(wvMainView!!)
if (bitmap != null){ saveMediaToStorage(bitmap) }
private fun getScreenShotFromView(v: View): Bitmap?
{
Log.i("-","MainActivity > getScreenShotFromView")
var screenshot: Bitmap? = null
try
{
screenshot = Bitmap.createBitmap(v.measuredWidth, v.measuredHeight, Bitmap.Config.ARGB_8888)
val canvas = Canvas(screenshot)
v.draw(canvas)
}
catch (e: Exception)
{
Log.e("GFG", "Failed to capture screenshot because:" + e.message)
}
return screenshot
}
private fun saveMediaToStorage(bitmap: Bitmap)
{
Log.i("-","MainActivity > saveMediaToStorage")
val filename = "${System.currentTimeMillis()}.jpg"
var fos: OutputStream? = null
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
{
this.contentResolver?.also { resolver ->
val contentValues = ContentValues().apply
{
put(MediaStore.MediaColumns.DISPLAY_NAME, filename)
put(MediaStore.MediaColumns.MIME_TYPE, "image/jpg")
put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES)
}
val imageUri: Uri? = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
fos = imageUri?.let { resolver.openOutputStream(it) }
}
}
else
{
val imagesDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
val image = File(imagesDir, filename)
fos = FileOutputStream(image)
}
fos?.use
{
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, it)
Toast.makeText(this , "Image saved to Gallery!" , Toast.LENGTH_SHORT).show()
}
}
As for the screenshot, take a look at the example below. When I run the app and take the screenshot, inside the gray area there is a bar chart that simple won't show up in the screenshot.
I tried taking a screenshot of the main layout as well as of the web view but with the same result.
The iOS version of the app works fine.
Any idea on what causes this strange behavior?
Maybe I should take the screenshot of the entire screen and not of a certain view (is this possible)?
And another small issue - the screenshot does no always appear in the Gallery app although I can find it using the Files app.
I ended up using ScreenShotty for this - https://github.com/bolteu/screenshotty
Add this to build.graddle:
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
Here's the code, maybe it helps someone:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?)
{
Log.i("","MainActivity > onActivityResult")
super.onActivityResult(requestCode, resultCode, data)
screenshotManager!!.onActivityResult(requestCode, resultCode, data)
}
fun getFullScreenshot()
{
Log.i("","MainActivity > getFullScreenshot")
val screenshotResult = screenshotManager!!.makeScreenshot()
val subscription = screenshotResult.observe(
onSuccess =
{
// Add a delay to prefent lag / crash on Android 5.0/5.1.
// Not sure if this is the correct way but it works for me
Handler(Looper.getMainLooper()).postDelayed({ editScreenshot(it) }, 1000)
},
onError =
{
Log.i("", "Screenshot failed!")
}
)
}
fun editScreenshot(screenshot: Screenshot)
{
Log.i("","MainActivity > editScreenshot")
val width: Int = Resources.getSystem().getDisplayMetrics().widthPixels
val height: Int = Resources.getSystem().getDisplayMetrics().heightPixels
val bitmap = when (screenshot)
{
is ScreenshotBitmap -> screenshot.bitmap
}
// Multiple resolutions cases go here
bitmap?.apply {
cropRectangle(
xOffset = 50,
yOffset = 250,
newWidth = width - 100,
newHeight = height - 450
)?.let { saveMediaToStorage(it) }
}
}
fun saveMediaToStorage(bitmap: Bitmap)
{
Log.i("","MainActivity > saveMediaToStorage")
val screenshotFileName = "${System.currentTimeMillis()}.jpg"
var fos: OutputStream? = null
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
{
this.contentResolver?.also { resolver ->
val contentValues = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, screenshotFileName)
put(MediaStore.MediaColumns.MIME_TYPE, "image/jpg")
put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES)
}
val imageUri: Uri? = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
fos = imageUri?.let { resolver.openOutputStream(it) }
}
}
else
{
val imagesDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
val image = File(imagesDir, screenshotFileName)
fos = FileOutputStream(image)
}
fos?.use {
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, it)
Toast.makeText(this , "Captured View and saved to Gallery" , Toast.LENGTH_SHORT).show()
}
}
I have created a function to upload images to drive in kotlin. It is as follow.
DriveServiceHelper class
class DriveServiceHelper(private val mDriveService: Drive) {
private val mExecutor: Executor =
Executors.newSingleThreadExecutor()
private val TAG = "DRIVE_TAG"
fun uploadFile(
localFile: java.io.File,
mimeType: String?, folderId: String?
): Any? {
return Tasks.call(mExecutor, Callable<Any> { // Retrieve the metadata as a File object.
val root: List<String>
root = folderId?.let { listOf(it) } ?: listOf("root")
val metadata =
File()
.setParents(root)
.setMimeType(mimeType)
.setName(localFile.name)
val fileContent = FileContent(mimeType, localFile)
val fileMeta =
mDriveService.files().create(
metadata,
fileContent
).execute()
val googleDriveFileHolder = GoogleDriveFileHolder()
googleDriveFileHolder.id=(fileMeta.id)
googleDriveFileHolder.name=(fileMeta.name)
googleDriveFileHolder
})
}
In my activity i call it as follows.
var mDriveServiceHelper: DriveServiceHelper? = null
private fun driveSetUp() {
val mAccount =
GoogleSignIn.getLastSignedInAccount(this)
val credential = GoogleAccountCredential.usingOAuth2(
applicationContext, setOf(Scopes.DRIVE_FILE)
)
credential.selectedAccount = mAccount!!.account
googleDriveService = Drive.Builder(
AndroidHttp.newCompatibleTransport(),
GsonFactory(),
credential
)
.setApplicationName("GoogleDriveIntegration 3")
.build()
mDriveServiceHelper = DriveServiceHelper(googleDriveService)
}
private fun uploadImageIntoDrive() {
driveSetUp()
val TAG = "image upload"
val bitmap = MediaStore.Images.Media.getBitmap(this.contentResolver, arrayList[0].uri)
try {
if (bitmap == null) {
Log.i(TAG, "Bitmap is null")
return
}
val file =
File(applicationContext.filesDir, "FirstFile")
val bos = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.PNG, 0 /*ignored for PNG*/, bos)
val bitmapdata = bos.toByteArray()
//write the bytes in file
val fos = FileOutputStream(file)
fos.write(bitmapdata)
fos.flush()
fos.close()
mDriveServiceHelper!!.uploadFile(file, "image/jpeg", null)
.addOnSuccessListener(OnSuccessListener<GoogleDriveFileHolder> { googleDriveFileHolder ->
Log.i(
TAG,
"Successfully Uploaded. File Id :" + googleDriveFileHolder.id)
})
.addOnFailureListener(OnFailureListener { e ->
Log.i(
TAG,
"Failed to Upload. File Id :" + e.message
)
})
} catch (e: Exception) {
Log.i(TAG, "Exception : " + e.message)
}
}
But the problem is in the uploadImageTodrive() function addOnSuccessListener is displayed in red color and says Unresolved Reference: addOnSuccessListener.
Please help
Your helper class returns type Any?:
fun uploadFile(
localFile: java.io.File,
mimeType: String?, folderId: String?
): Any? { ... // Look at the return type
But it actually should return Task<GoogleDriveFileHolder>:
fun uploadFile(
localFile: java.io.File,
mimeType: String?, folderId: String?
): Task<GoogleDriveFileHolder> { ... // Non-optional Task<GoogleDriveFileHolder>
I tried saving video to gallery like i found on example:
private fun saveVideoToInternalStorage3(filePath: String) {
val newfile: File
try {
val currentFile = File(filePath)
val fileName = currentFile.name
val cw = ContextWrapper(applicationContext)
val directory = cw.getDir("videoDir", Context.MODE_PRIVATE)
newfile = File(directory.absolutePath, fileName)
if(currentFile.exists()) {
val `in`: InputStream = FileInputStream(currentFile)
val out: OutputStream = FileOutputStream(newfile)
// Copy the bits from instream to outstream
val buf = ByteArray(1024)
var len: Int
while(`in`.read(buf).also {len = it} > 0) {
out.write(buf, 0, len)
}
scanner(filePath)
`in`.close()
out.close()
Log.d("", "Video file saved successfully.")
Toast.makeText(this, "Push Video Saved TO Gallery", Toast.LENGTH_SHORT).show()
} else {
Log.d("", "Video saving failed. Source file missing.")
}
} catch(e: java.lang.Exception) {
Log.d("", "EXS " + e.message)
e.printStackTrace()
}
And it works fine it shows message "Video file saved successfully." But there is no video in my gallery.
After searching for problem i found post that says you need a scanner and i tried:
private fun scanner(path: String) {
MediaScannerConnection.scanFile(this, arrayOf(path), null, object: OnScanCompletedListener {
override fun onScanCompleted(path: String, uri: Uri?) {
Log.i("", "Finished scanning $path")
}
})
But still no luck. Does any1 know what is going on? Saving images in gallery works fine btw.
I try to compress images with a large size >3MB to 200BK with my code. But It does not work. Although I put any quality, the output always with the same result. I don't know where I was wrong.
Please show me my mistake.
I want to convert PNG only.
MAX_SIZE_UPLOAD = 200KB. Ex:
input: 4900000, quality: 90 output = 32000000
input: 4900000, quality: 80 output = 32000000
override fun compress(file: File): Single<File> {
val result: SingleSubject<File> = SingleSubject.create()
val options = RequestOptions()
val optionsBitmap = BitmapFactory.Options()
val originSize = file.length()
optionsBitmap.inJustDecodeBounds = true
BitmapFactory.decodeFile(file.absolutePath, optionsBitmap)
Glide.with(context)
.asBitmap().load(file)
.into(object : SimpleTarget<Bitmap>() {
override fun onLoadFailed(errorDrawable: Drawable?) {
super.onLoadFailed(errorDrawable)
}
override fun onResourceReady(
resource: Bitmap,
transition: com.bumptech.glide.request.transition.Transition<in Bitmap>?
) {
thread {
try {
val stream = ByteArrayOutputStream()
val quality = ((100 * MAX_SIZE_UPLOAD) / file.length())
resource.compress(Bitmap.CompressFormat.PNG, quality.toInt(), stream)
saveFileToCacheDir(stream.toByteArray())
.observeOnUiThread()
.subscribe({
result.onSuccess(it)
}, {
result.onError(Throwable())
})
} catch (e: Exception) {
result.onError(Throwable())
}
}
}
})
return result
}
override fun saveFileToCacheDir(data: ByteArray): Single<File> {
val result: SingleSubject<File> = SingleSubject.create()
try {
val file = File(context.cacheDir, "$FILE_NAME${System.currentTimeMillis()}")
file.createNewFile()
val fos = FileOutputStream(file)
fos.write(data)
fos.flush()
fos.close()
result.onSuccess(file)
} catch (e: IOException) {
result.onError(e)
}
return result
}
Here is the solution to compress image bitmap to file.
fun bitmapToFile(bitmap: Bitmap, context: Context): String {
// Get the context wrapper
val wrapper = ContextWrapper(context)
// Initialize a new file instance to save bitmap object
var file = wrapper.getDir("Images", Context.MODE_PRIVATE)
file = File(file, "${UUID.randomUUID()}.jpg")
try {
val stream: OutputStream = FileOutputStream(file)
bitmap.compress(Bitmap.CompressFormat.JPEG,15,stream)
stream.flush()
stream.close()
} catch (e: IOException) {
e.printStackTrace()
}
// Return the saved bitmap uri
return file.absolutePath
}
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())
}
}