JPEG gets corrupt when saving image with exif metadata - android

I am developing an Android app that saves bitmaps as jpeg images to the external storage. It occasionally happens that the JPEGs get corrupt (see image below). I have realized that corruption (eventually) only occurs when saveExif() is called. If I comment out saveExif(), the corruption never happened. This means that it is caused by something related to EXIF and not the compression process.
I have analyzed the jpeg with software (Bad Peggy) that detected the image as corrupt due to a premature end of data segment.
Any idea how to fix it?
This is how I save the image initially:
lateinit var uri: Uri
val imageOutStream: OutputStream
val contentResolver = context.contentResolver
val mimeType = "image/jpeg"
val mediaContentUri = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
val values = ContentValues().apply {
put(MediaStore.Images.Media.DISPLAY_NAME, fileName)
put(MediaStore.Images.Media.MIME_TYPE, mimeType)
put(MediaStore.Images.Media.RELATIVE_PATH, directory)
}
contentResolver.run {
uri = context.contentResolver.insert(mediaContentUri, values)
?: return
imageOutStream = openOutputStream(uri) ?: return
}
try {
imageOutStream.use { bitmap.compress(Bitmap.CompressFormat.JPEG, photoCompression, it) }
} catch (e: java.lang.Exception) {
e.printStackTrace()
} finally {
imageOutStream.close()
}
try {
context.contentResolver.openInputStream(uri).use {
val exif = ExifInterface(context.contentResolver.openFileDescriptor(uri, "rw")!!.fileDescriptor)
saveExif(exif, context) //method ads exif metadata to image
}
}catch (e: java.lang.Exception){
}
This is how I add Exif metadata after the JPEG has been stored:
private fun saveExif(exif: ExifInterface, context: Context){
if (referenceWithCaptionExif != "" && notesExif != "") {
exif.setAttribute(ExifInterface.TAG_USER_COMMENT, "$referenceWithCaptionExif | $notesExif")
} else {
exif.setAttribute(ExifInterface.TAG_USER_COMMENT, "$referenceWithCaptionExif$notesExif")
}
if (companyExif != "") {
exif.setAttribute(ExifInterface.TAG_CAMERA_OWNER_NAME, companyExif)
val yearForExif = SimpleDateFormat("yyyy",
Locale.getDefault()).format(Date())
exif.setAttribute(ExifInterface.TAG_COPYRIGHT, "Copyright (c) $companyExif $yearForExif")
}
if (projectExif != "") {
exif.setAttribute(ExifInterface.TAG_IMAGE_DESCRIPTION, projectExif)
}
exif.setAttribute(ExifInterface.TAG_MAKER_NOTE, "Project[$projectExif] Company[$companyExif] " +
"Notes[$notesExif] Reference[$referenceExif] ReferenceType[$referenceTypeExif] Coordinates[$coordinatesExif] " +
"CoordinateSystem[$coordinateSystemExif] Accuracy[$accuracyExif] Altitude[$altitudeExif] " +
"Date[$dateTimeExif] Address[$addressExif]")
exif.setAttribute(ExifInterface.TAG_ARTIST, "${android.os.Build.MANUFACTURER} ${android.os.Build.MODEL}")
exif.setAttribute(ExifInterface.TAG_SOFTWARE, context.resources.getString(R.string.app_name))
exif.setAttribute(ExifInterface.TAG_MAKE, (android.os.Build.MANUFACTURER).toString())
exif.setAttribute(ExifInterface.TAG_MODEL, (android.os.Build.MODEL).toString())
exif.setAttribute(ExifInterface.TAG_COMPRESSION, 7.toString())
exif.setAttribute(ExifInterface.TAG_IMAGE_WIDTH, "${bitmapToProcess.width} px")
exif.setAttribute(ExifInterface.TAG_IMAGE_LENGTH, "${bitmapToProcess.height} px")
exif.setAttribute(ExifInterface.TAG_PIXEL_X_DIMENSION, "${bitmapToProcess.width} px")
exif.setAttribute(ExifInterface.TAG_PIXEL_Y_DIMENSION, "${bitmapToProcess.height} px")
exif.setAttribute(ExifInterface.TAG_GPS_ALTITUDE, altitudeExif)
exif.setAttribute(ExifInterface.TAG_GPS_ALTITUDE_REF, 0.toString())
exif.setAltitude(altitudeMetricExif)
exif.setLatLong(latitudeWGS84Exif, longitudeWGS84Exif)
exif.setAttribute(ExifInterface.TAG_GPS_TIMESTAMP, timeGPSExif)
exif.setAttribute(ExifInterface.TAG_GPS_DATESTAMP, dateGPSExif)
exif.setAttribute(ExifInterface.TAG_GPS_PROCESSING_METHOD, "GPS")
exif.setAttribute(ExifInterface.TAG_DATETIME, dateTimeOriginalExif)
exif.setAttribute(ExifInterface.TAG_DATETIME_ORIGINAL, dateTimeOriginalExif)
exif.setAttribute(ExifInterface.TAG_DATETIME_DIGITIZED, dateTimeOriginalExif)
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
exif.setAttribute(ExifInterface.TAG_OFFSET_TIME_DIGITIZED, SimpleDateFormat("XXX", Locale.getDefault()).format(Date()))
exif.setAttribute(ExifInterface.TAG_OFFSET_TIME_ORIGINAL, SimpleDateFormat("XXX", Locale.getDefault()).format(Date()))
exif.setAttribute(ExifInterface.TAG_OFFSET_TIME, SimpleDateFormat("XXX", Locale.getDefault()).format(Date()))
}
exif.saveAttributes()
}

You could comment out each piece of metadata, one at a time and see if there’s a specific one that is causing the corruption. There’s a lot of programming happening for some of them so I wonder if it has to do with an incorrect string type or something.

Related

Image my Android app saves doesn't show in the gallery

I save a png image to external storage using this block of code for sdk<=28
/**
* save image with this method if the sdk is 28 or lower
*/
private fun saveImageSdk28(fileName: String){
//declar the output stream variable outside of try/catch so that it can always be closed
var imageOutputStream: FileOutputStream? = null
var outputImageFile = getFile(fileName)
if (!outputImageFile.exists()) {
outputImageFile.createNewFile()
}
try {
imageOutputStream = FileOutputStream(outputImageFile)
encryptedBitmap.compress(Bitmap.CompressFormat.PNG, 100, imageOutputStream)
} catch (e: IOException) {
e.printStackTrace()
Timber.i(e.toString())
} finally {
if (imageOutputStream != null) {
imageOutputStream.flush()
imageOutputStream.close()
}
}
}
/**
* returns file from fileName
*/
fun getFile(fileName: String): File{
//open, or create the directory where the image will be stored
var directory = File(
Environment.getExternalStorageDirectory().toString() + "/AppNameOutput/"
)
if (!directory.exists()) {
directory.mkdir()
}
//create the file
var file: File = File(directory.absolutePath, fileName)
return file
}
and this code for when the sdk>28
/**
* save image with this method if the sdk is 29 or higher
*/
#RequiresApi(Build.VERSION_CODES.Q)
private fun saveImageSdk29(fileName: String){
val imageCollection = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
val contentValues = ContentValues().apply {
put(MediaStore.Images.Media.DISPLAY_NAME, "$fileName")
put(MediaStore.Images.Media.MIME_TYPE, "image/png")
put(MediaStore.Images.Media.WIDTH, encryptedBitmap.width)
put(MediaStore.Images.Media.HEIGHT, encryptedBitmap.height)
}
try{
val contentResolver = getApplication<Application>().contentResolver
contentResolver.insert(imageCollection, contentValues)?.also {uri->
contentResolver.openOutputStream(uri).use {outputStream ->
encryptedBitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream)
}
}
}catch (e: IOException){
e.printStackTrace()
}
}
The image sucsessfully saves on the users device and can be accesed through files, however, the user can't access these images through the gallery, or Images tab.
I solved it. Turns out you just need to wait a while and reboot the phone for the gallery to show your images.

I am trying to read an image from Gallery On app Starting Up that is pre set by the user Android Studio Kotlin

I am Saving the Path to an Image that is set by the user, when the app starts up from cold the image path is read from file and is(should be displayed) but it doesn't want to show. is there a simpler method to reading a set image from gallery?
This is my read File, within this Internal file I am saving a String Path to the Image
fun readDataLocally(context: Context, FileName: String): String {
var str = ""
try {
val inputStream = context.openFileInput(FileName)
if (inputStream != null) {
val inputStreamReader = InputStreamReader(inputStream)
val bufferedReader = BufferedReader(inputStreamReader)
val partialStr = StringBuilder()
var done = false
while (!done) {
val line = bufferedReader.readLine()
done = (line == null)
if (line != null) partialStr.append(line)
}
inputStream.close()
str = partialStr.toString()
}
} catch (e: FileNotFoundException) {
Log.e("Error: ", "file not found: " + e.toString())
} catch (e: IOException) {
Log.e("Error: ", "cannot read file: " + e.toString())
}
Log.d("FileRead",str)
return str
}
This reads the Image path and sets the bit map, any time I call this method it causes the Exception E.
fun readImageFromPath(context: Context, path : String) : Bitmap? {
var bitmap : Bitmap? = null
val uri = Uri.parse(path)
Log.d("path",path)
if (uri != null) {
try {
val parcelFileDescriptor = context.contentResolver.openFileDescriptor(uri, "r")
val fileDescriptor = parcelFileDescriptor?.fileDescriptor
bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor)
parcelFileDescriptor?.close()
} catch (e: Exception) {
Toast.makeText(context,"Image Read is unavailable please reload",Toast.LENGTH_SHORT).show()
}
}
Log.d("Rip", bitmap.toString())
return bitmap
}
Methods used too call Image to show on Activity Start Up
ImageView.setImageBitmap(readImageFromPath(this,readDataLocally(this, "HomeImage")))
and I tried
val bitmap = readDataLocally(this, "HomeImage")
ManagerScreen_Image.setImageBitmap(readImageFromPath(this, bitmap))
I have the Correct Manifest Permissions.

Download images from a URL, save them to App Internal Storage without blocking calls (multiple files in parallel). Using Kotlin Coroutines on Android

Basically, I am trying to download three different images(bitmaps) from a URL and save them to Apps Internal storage, and then use the URI's from the saved file to save a new Entity to my database. I am having a lot of issues with running this in parallel and getting it to work properly. As ideally all three images would be downloaded, saved and URI's returned simultaneously. Most of my issues come from blocking calls that I cannot seem to avoid.
Here's all of the relevant code
private val okHttpClient: OkHttpClient = OkHttpClient()
suspend fun saveImageToDB(networkImageModel: CBImageNetworkModel): Result<Long> {
return withContext(Dispatchers.IO) {
try {
//Upload all three images to local storage
val edgesUri = this.async {
val req = Request.Builder().url(networkImageModel.edgesImageUrl).build()
val response = okHttpClient.newCall(req).execute() // BLOCKING
val btEdges = BitmapFactory.decodeStream(response.body?.byteStream())
return#async saveBitmapToAppStorage(btEdges, ImageType.EDGES)
}
val finalUri = this.async {
val urlFinal = URL(networkImageModel.finalImageUrl) // BLOCKING
val btFinal = BitmapFactory.decodeStream(urlFinal.openStream())
return#async saveBitmapToAppStorage(btFinal, ImageType.FINAL)
}
val labelUri = this.async {
val urlLabels = URL(networkImageModel.labelsImageUrl)
val btLabel = BitmapFactory.decodeStream(urlLabels.openStream())
return#async saveBitmapToAppStorage(btLabel, ImageType.LABELS)
}
awaitAll(edgesUri, finalUri, labelUri)
if(edgesUri.getCompleted() == null || finalUri.getCompleted() == null || labelUri.getCompleted() == null) {
return#withContext Result.failure(Exception("An image couldn't be saved"))
}
} catch (e: Exception) {
Result.failure<Long>(e)
}
try {
// Result.success( db.imageDao().insertImage(image))
Result.success(123) // A placeholder untill I actually get the URI's to create my Db Entity
} catch (e: Exception) {
Timber.e(e)
Result.failure(e)
}
}
}
//Save the bitmap and return Uri or null if failed
private fun saveBitmapToAppStorage(bitmap: Bitmap, imageType: ImageType): Uri? {
val type = when (imageType) {
ImageType.EDGES -> "edges"
ImageType.LABELS -> "labels"
ImageType.FINAL -> "final"
}
val filename = "img_" + System.currentTimeMillis().toString() + "_" + type
val file = File(context.filesDir, filename)
try {
val fos = file.outputStream()
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
fos.close();
} catch (e: Exception) {
Timber.e(e)
return null
}
return file.toUri()
}
Here I am calling this function
viewModelScope.launch {
val imageID = appRepository.saveImageToDB(imageNetworkModel)
withContext(Dispatchers.Main) {
val uri = Uri.parse("$PAINT_DEEPLINK/$imageID")
navManager.navigate(uri)
}
}
Another issue I am facing is returning the URI in the first place and handling errors. As if one of these parts fails, I'd like to cancel the whole thing and return Result.failure(), but I am unsure on how to achieve that. As returning null just seems meh, I'd much prefer to have an error message or something along those lines.

Wrong image name and type when saving bitmap Android 8

I have a fun that saves bitmap as PNG or JPG (both not working), but seems like using content values not working as expected.
File name is incorrect.
File type is incorrect.
What am I missing ?
Works on Android 10, but not working on Android 8
fun Bitmap.save(context: Context) {
val contentResolver = context.contentResolver
val contentValues = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, "test.png")
put(MediaStore.MediaColumns.TITLE, "test")
put(MediaStore.MediaColumns.MIME_TYPE, "image/png")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES)
put(MediaStore.MediaColumns.IS_PENDING, 1)
}
}
val contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
val uri = contentResolver.insert(contentUri, contentValues)
if (uri != null) {
try {
contentResolver.openFileDescriptor(uri, "w", null)?.use {
if (it.fileDescriptor != null) {
with(FileOutputStream(it.fileDescriptor)) {
compress(
Bitmap.CompressFormat.PNG,
DEFAULT_IMAGE_QUALITY,
this
)
flush()
close()
}
}
}
} catch (e: Exception) {
e.printStackTrace()
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
contentValues.clear()
contentValues.put(MediaStore.MediaColumns.IS_PENDING, 0)
contentResolver.update(uri, contentValues, null, null)
}
MediaScannerConnection.scanFile(context, arrayOf(uri.toString()), null, null)
}
recycle()
}
Actual file name is 1592205828045 (some timestamp)
Actual file type is jpg with 0B - as it was not saved properly ?
You will have to maintain 2 different ways of saving images to shared storage. This post covers it quite well. Using Media Store API in older phones results in the problem you have described. Some code sample for you (tested in Android 8, 10, and 11).
Add these to your manifest
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!-- File save functions handles this -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28"
tools:ignore="ScopedStorage" />
Add a permission check to your app (code not provided)
When you are ready with your bitmap call either of these functions (depending on the SDK version of the phone that the app is currently running on)
//TODO - bitmap needs null check
val bitmap = BitmapFactory.decodeFile(bitmapFile.canonicalPath)
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q)
{
saveBitmapPreQ(bitmap)
} else {
saveBitmapPostQ(bitmap)
}
Finally these are the implementations of saveBitmapPreQ and saveBitmapPostQ
#Suppress("DEPRECATION") // Check is preformed on function call
private fun saveBitmapPreQ(thisBitmap: Bitmap){
Log.d("HOME_4", "in pre Q")
val pictureDirectory =
File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
"MyFolder")
if (!pictureDirectory.exists()){
pictureDirectory.mkdir()
}
val dateTimeStamp = SimpleDateFormat("yyyyMMddHHmmss").format(Date())
val name = "Image_$dateTimeStamp"
val bitmapFile = File(pictureDirectory, "$name.png")
try {
val fileOutputStream = bitmapFile.outputStream()
thisBitmap.compress(Bitmap.CompressFormat.PNG, 100, fileOutputStream)
fileOutputStream.flush()
fileOutputStream.close()
} catch (e: Exception) {
Log.d("HOME_5", "Pre Q error $e")
}
}
private fun saveBitmapPostQ(thisBitmap: Bitmap){
Log.d("HOME_6", "in post Q")
val dateTimeStamp = SimpleDateFormat("yyyyMMddHHmmss").format(Date())
val name = "Image_$dateTimeStamp"
val relativePath = Environment.DIRECTORY_PICTURES + File.separator + "MyFolder"
val contentValues = ContentValues().apply {
put(MediaStore.Images.ImageColumns.DISPLAY_NAME, name)
put(MediaStore.MediaColumns.MIME_TYPE, "image/png")
put(MediaStore.MediaColumns.TITLE, name)
put(MediaStore.Images.ImageColumns.RELATIVE_PATH, relativePath)
}
val contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
var outputStream: OutputStream? = null
var uri: Uri? = null
try {
uri = contentResolver.insert(contentUri, contentValues)
if (uri == null){
throw IOException("Failed to create new MediaStore record.")
}
outputStream = contentResolver.openOutputStream(uri)
if (outputStream == null){
throw IOException("Failed to get output stream.")
}
if (!thisBitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream)){
throw IOException("Failed to save bitmap.")
}
} catch (e: IOException){
if (uri != null)
{
contentResolver.delete(uri, null, null)
}
throw IOException(e)
}
finally {
outputStream?.close()
}
}
I have left log messages in there to help you understand the flow. In the saveBitmapPostQ funtions I have taken a few shortcuts. Please read this post under the headding Creating a New File on how you can improve that function further.
You are creating the file, but you still need to write your Bitmap to it:
fun Bitmap.save(context: Context) {
...
val bitmap = this
val maxImageQuality = 100
val uri = contentResolver.insert(contentUri, contentValues)
if (uri != null) {
try {
contentResolver.openFileDescriptor(uri, "w", null)?.use {
if (it.fileDescriptor != null) {
with(FileOutputStream(it.fileDescriptor)) {
bitmap.compress(
Bitmap.CompressFormat.PNG,
maxImageQuality, this
)
flush()
close()
}
}
}
} catch (e: Exception) {
e.printStackTrace()
}
// release pending status of the file
contentValues.clear()
contentValues.put(MediaStore.Images.Media.IS_PENDING, 0)
contentResolver.update(uri, contentValues, null, null)
// notify media scanner there's a new picture
MediaScannerConnection.scanFile(context, arrayOf(uri.toString()), null, null)
}
// don't forget to recycle the bitmap when you don't need it any longer
bitmap.recycle()
}

Android: Read a file without external storage permission

I don't want my app to require any permissions, but I want the user to be able to select a file for reading. My app doesn't need arbitrary access to the filesystem. However, all openfiledialog implementations I have researched so far seem to assume permission to access external storage.
One workaround I can think of is to configure my app to be among the list of apps to open a certain type of file. I haven't tried this, but I hope this would work without permission to access external storage. However, user guidance would be less then ideal in this case. I would prefer a solution with a dialog and have the user pick the file.
I think this requirement does not undermine security, because the user has full control over the file my app can read. Is this possible somehow?
However, all openfiledialog implementations I have researched so far seem to assume permission to access external storage.
Set your minSdkVersion to 19, then use ACTION_OPEN_DOCUMENT, part of the Storage Access Framework.
Or, if you need your minSdKVersion to be below 19, use ACTION_GET_CONTENT on the older devices.
You will get a Uri back via onActivityResult(). Use a ContentResolver and methods like openInputStream() to consume the content identified by that Uri.
I haven't tried this, but I hope this would work without permission to access external storage
Only if you exclude file: Uri values. For example, an <intent-filter> that supports only content: Uri values would work.
Android 11 Resolve file access issue without use of MANAGE_EXTERNAL_STORAGE.
I have added code for get doc file and Upload to server.
AndroidManifest
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application
android:preserveLegacyExternalStorage="true"
android:requestLegacyExternalStorage="true"
</application>
Now, Add this lib in your project
https://github.com/FivesoftCode/FilePicker
Add below code to Activity/Fragment
FilePicker.from(activity)
.setFileTypes(FilePicker.IMAGE, FilePicker.VIDEO) //Set file types you want to pick.
.setAllowMultipleFiles(true) //Allow user to select multiple files
.setListener { files -> //Wait for results
if (files != null && files.size > 0) {
//Do something with uris.
for (items in files) {
val extension: String = getMimeType(activity!!,items)!!
if (extension == "pdf") {
val cacheDir: String = context!!.cacheDir.toString()
val getCopyFilePath = copyFileToInternalStorage(context!!,items,cacheDir)
Log.e("TAG", "getPathToUploadDoc: " + getCopyFilePath )
}
}
} else {
//Add msg here...
}
}
.setTitle("Pick a file from My Files")
.pick() //Open file picker
Add below method for get Mime Type
fun getMimeType(context: Context, uri: Uri): String? {
val extension: String?
//Check uri format to avoid null
extension = if (uri.scheme == ContentResolver.SCHEME_CONTENT) {
//If scheme is a content
val mime = MimeTypeMap.getSingleton()
mime.getExtensionFromMimeType(context.contentResolver.getType(uri))
} else {
//If scheme is a File
//This will replace white spaces with %20 and also other special characters. This will avoid returning null values on file name with spaces and special characters.
MimeTypeMap.getFileExtensionFromUrl(Uri.fromFile(File(uri.path)).toString())
}
return extension
}
fun getFiledetails(uri: Uri,context: Context,getCopyFilePath:String): NormalFile? {
// var result: String? = null
if (uri.scheme == "content") {
val cursor: Cursor = context.contentResolver.query(uri,
FileLoader.FILE_PROJECTION, null, null, null)!!
try {
if (cursor != null && cursor.moveToFirst()) {
// result = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME))
val path: String = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA))
if (path != null && path != "") {
//Create a File instance
cursor.getLong(cursor.getColumnIndexOrThrow(BaseColumns._ID))
// cursor.getLong(cursor.getColumnIndexOrThrow(BaseColumns._ID)).toInt()
cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.TITLE))
// cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA))
cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.SIZE))
cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATE_ADDED))
cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.MIME_TYPE))
}
}
} finally {
cursor.close()
}
}
/*if (result == null) {
result = uri.path
val cut = result!!.lastIndexOf('/')
if (cut != -1) {
result = result.substring(cut + 1)
}
}*/
return file
}
fun copyFileToInternalStorage(context: Context?,uri: Uri, newDirName: String): String? {
val returnCursor = context!!.contentResolver.query(
uri, arrayOf(
OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE
), null, null, null
)
/*
* Get the column indexes of the data in the Cursor,
* * move to the first row in the Cursor, get the data,
* * and display it.
* */
val nameIndex = returnCursor!!.getColumnIndex(OpenableColumns.DISPLAY_NAME)
val sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE)
returnCursor.moveToFirst()
val name = returnCursor.getString(nameIndex)
val size = java.lang.Long.toString(returnCursor.getLong(sizeIndex))
val output: File
output = if (newDirName != "") {
val dir = File(/*context!!.filesDir.toString() + "/" +*/ newDirName)
if (!dir.exists()) {
dir.mkdir()
}
File(/*context!!.filesDir.toString() + "/" +*/ newDirName + "/" + name)
} else {
File(context!!.filesDir.toString() + "/" + name)
}
try {
val inputStream: InputStream? = context!!.contentResolver.openInputStream(uri)
val outputStream = FileOutputStream(output)
var read = 0
val bufferSize = 1024
val buffers = ByteArray(bufferSize)
while (inputStream?.read(buffers).also { read = it!! } != -1) {
outputStream.write(buffers, 0, read)
}
inputStream?.close()
outputStream.close()
} catch (e: Exception) {
Log.e("Exception", e.message!!)
}
return output.path
}
For upload Doc
implementation 'net.gotev:uploadservice:2.1'
var uploadId = UUID.randomUUID().toString()
val url = ServerConfig.MAIN_URL
uploadReceiver.setDelegate(this)
uploadReceiver.setUploadID(uploadId)
val data = MultipartUploadRequest(mContext, uploadId, url)
.addFileToUpload(path, "attachment")
.addHeader("Authentication", getMD5EncryptedString())
.addParameter(USER_ID,1)
.setMaxRetries(5)
.startUpload()
fun getMD5EncryptedString(): String {
val encTarget = ServerConfig.AUTHENTICATE_VALUE //Any pwd
var mdEnc: MessageDigest? = null
try {
mdEnc = MessageDigest.getInstance("MD5")
} catch (e: NoSuchAlgorithmException) {
println("Exception while encrypting to md5")
e.printStackTrace()
}
mdEnc!!.update(encTarget.toByteArray(), 0, encTarget.length)
var md5 = BigInteger(1, mdEnc.digest()).toString(16)
while (md5.length < 32) {
md5 = "0$md5"
}
return md5
}

Categories

Resources