From c4ce6a51941def3816df6ff6bae1cdb34c13d19d Mon Sep 17 00:00:00 2001 From: Sartaj Roshan Date: Thu, 16 Apr 2020 16:19:28 +0530 Subject: [PATCH 1/3] Changed Exif library to Androidx Found that android.media.Exifinterface has some bugs and recommended with androidx support library. Most stable version of Exif library is used. --- .idea/codeStyles/Project.xml | 134 ++++++++++++++---- app/build.gradle | 12 +- .../compressor/ExampleInstrumentedTest.kt | 4 +- .../java/com/qkopy/compressor/FileUtil.java | 106 -------------- .../java/com/qkopy/compressor/FileUtil.kt | 101 +++++++++++++ .../java/com/qkopy/compressor/MainActivity.kt | 5 +- build.gradle | 2 +- gradle.properties | 2 + gradle/wrapper/gradle-wrapper.properties | 4 +- imagecompressor/build.gradle | 11 +- .../ExampleInstrumentedTest.java | 4 +- .../com/qkopy/imagecompressor/Compressor.kt | 3 +- .../com/qkopy/imagecompressor/ImageUtil.kt | 2 +- 13 files changed, 238 insertions(+), 152 deletions(-) delete mode 100644 app/src/main/java/com/qkopy/compressor/FileUtil.java create mode 100644 app/src/main/java/com/qkopy/compressor/FileUtil.kt diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index 34dc27c..ce889bd 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -3,31 +3,115 @@ - - - - - - - - - - + + + +
+ + + + xmlns:android + + ^$ + + + +
+
+ + + + xmlns:.* + + ^$ + + + BY_NAME + +
+
+ + + + .*:id + + http://schemas.android.com/apk/res/android + + + +
+
+ + + + .*:name + + http://schemas.android.com/apk/res/android + + + +
+
+ + + + name + + ^$ + + + +
+
+ + + + style + + ^$ + + + +
+
+ + + + .* + + ^$ + + + BY_NAME + +
+
+ + + + .* + + http://schemas.android.com/apk/res/android + + + ANDROID_ATTRIBUTE_ORDER + +
+
+ + + + .* + + .* + + + BY_NAME + +
+
+
+
diff --git a/app/build.gradle b/app/build.gradle index 2f76242..207ef74 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -12,7 +12,7 @@ android { targetSdkVersion 28 versionCode 1 versionName "1.0" - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { release { @@ -25,12 +25,12 @@ android { dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation 'com.android.support:appcompat-v7:28.0.0' - implementation 'com.android.support.constraint:constraint-layout:1.1.3' + implementation 'androidx.appcompat:appcompat:1.1.0' + implementation 'androidx.constraintlayout:constraintlayout:1.1.3' testImplementation 'junit:junit:4.12' - androidTestImplementation 'com.android.support.test:runner:1.0.2' - androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' + androidTestImplementation 'androidx.test.ext:junit:1.1.1' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' implementation project(path: ':imagecompressor') - implementation 'io.reactivex.rxjava2:rxandroid:2.1.0' + implementation 'io.reactivex.rxjava2:rxandroid:2.1.1' implementation "org.jetbrains.anko:anko:0.10.8" } diff --git a/app/src/androidTest/java/com/qkopy/compressor/ExampleInstrumentedTest.kt b/app/src/androidTest/java/com/qkopy/compressor/ExampleInstrumentedTest.kt index 874df5a..9638041 100644 --- a/app/src/androidTest/java/com/qkopy/compressor/ExampleInstrumentedTest.kt +++ b/app/src/androidTest/java/com/qkopy/compressor/ExampleInstrumentedTest.kt @@ -1,7 +1,7 @@ package com.qkopy.compressor -import android.support.test.InstrumentationRegistry -import android.support.test.runner.AndroidJUnit4 +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 import org.junit.Assert.assertEquals import org.junit.Test import org.junit.runner.RunWith diff --git a/app/src/main/java/com/qkopy/compressor/FileUtil.java b/app/src/main/java/com/qkopy/compressor/FileUtil.java deleted file mode 100644 index c7b908e..0000000 --- a/app/src/main/java/com/qkopy/compressor/FileUtil.java +++ /dev/null @@ -1,106 +0,0 @@ -package com.qkopy.compressor; - -import android.content.Context; -import android.database.Cursor; -import android.net.Uri; -import android.provider.OpenableColumns; -import android.util.Log; - -import java.io.*; - -class FileUtil { - private static final int EOF = -1; - private static final int DEFAULT_BUFFER_SIZE = 1024 * 4; - - private FileUtil() { - - } - - public static File from(Context context, Uri uri) throws IOException { - InputStream inputStream = context.getContentResolver().openInputStream(uri); - String fileName = getFileName(context, uri); - String[] splitName = splitFileName(fileName); - File tempFile = File.createTempFile(splitName[0], splitName[1]); - tempFile = rename(tempFile, fileName); - tempFile.deleteOnExit(); - FileOutputStream out = null; - try { - out = new FileOutputStream(tempFile); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } - if (inputStream != null) { - copy(inputStream, out); - inputStream.close(); - } - - if (out != null) { - out.close(); - } - return tempFile; - } - - private static String[] splitFileName(String fileName) { - String name = fileName; - String extension = ""; - int i = fileName.lastIndexOf("."); - if (i != -1) { - name = fileName.substring(0, i); - extension = fileName.substring(i); - } - - return new String[]{name, extension}; - } - - private static String getFileName(Context context, Uri uri) { - String result = null; - if (uri.getScheme().equals("content")) { - Cursor cursor = context.getContentResolver().query(uri, null, null, null, null); - try { - if (cursor != null && cursor.moveToFirst()) { - result = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)); - } - } catch (Exception e) { - e.printStackTrace(); - } finally { - if (cursor != null) { - cursor.close(); - } - } - } - if (result == null) { - result = uri.getPath(); - assert result != null; - int cut = result.lastIndexOf(File.separator); - if (cut != -1) { - result = result.substring(cut + 1); - } - } - return result; - } - - private static File rename(File file, String newName) { - File newFile = new File(file.getParent(), newName); - if (!newFile.equals(file)) { - if (newFile.exists() && newFile.delete()) { - Log.d("FileUtil", "Delete old " + newName + " file"); - } - if (file.renameTo(newFile)) { - Log.d("FileUtil", "Rename file to " + newName); - } - } - return newFile; - } - - private static long copy(InputStream input, OutputStream output) throws IOException { - long count = 0; - int n; - byte[] buffer = new byte[DEFAULT_BUFFER_SIZE]; - while (EOF != (n = input.read(buffer))) { - output.write(buffer, 0, n); - count += n; - } - return count; - } -} - diff --git a/app/src/main/java/com/qkopy/compressor/FileUtil.kt b/app/src/main/java/com/qkopy/compressor/FileUtil.kt new file mode 100644 index 0000000..282da09 --- /dev/null +++ b/app/src/main/java/com/qkopy/compressor/FileUtil.kt @@ -0,0 +1,101 @@ +package com.qkopy.compressor + +import android.content.Context +import android.net.Uri +import android.provider.OpenableColumns +import android.util.Log +import java.io.* + +internal object FileUtil { + private const val EOF = -1 + private const val DEFAULT_BUFFER_SIZE = 1024 * 4 + + @Throws(IOException::class) + fun from(context: Context, uri: Uri): File { + val inputStream = context.contentResolver.openInputStream(uri) + val fileName = getFileName(context, uri) + val splitName = + splitFileName(fileName) + var tempFile = File.createTempFile(splitName[0], splitName[1]) + tempFile = rename(tempFile, fileName) + tempFile.deleteOnExit() + var out: FileOutputStream? = null + try { + out = FileOutputStream(tempFile) + } catch (e: FileNotFoundException) { + e.printStackTrace() + } + if (inputStream != null) { + copy(inputStream, out) + inputStream.close() + } + out?.close() + return tempFile + } + + private fun splitFileName(fileName: String?): Array { + var name = fileName + var extension: String? = "" + val i = fileName!!.lastIndexOf(".") + if (i != -1) { + name = fileName.substring(0, i) + extension = fileName.substring(i) + } + return arrayOf(name, extension) + } + + private fun getFileName( + context: Context, + uri: Uri + ): String? { + var result: String? = null + if (uri.scheme == "content") { + val cursor = + context.contentResolver.query(uri, null, null, null, null) + try { + if (cursor != null && cursor.moveToFirst()) { + result = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)) + } + } catch (e: Exception) { + e.printStackTrace() + } finally { + cursor?.close() + } + } + if (result == null) { + result = uri.path + assert(result != null) + val cut = result.lastIndexOf(File.separator) + if (cut != -1) { + result = result.substring(cut + 1) + } + } + return result + } + + private fun rename(file: File, newName: String?): File { + val newFile = File(file.parent, newName) + if (newFile != file) { + if (newFile.exists() && newFile.delete()) { + Log.d("FileUtil", "Delete old $newName file") + } + if (file.renameTo(newFile)) { + Log.d("FileUtil", "Rename file to $newName") + } + } + return newFile + } + + @Throws(IOException::class) + private fun copy(input: InputStream, output: OutputStream?): Long { + var count: Long = 0 + var n: Int + val buffer = + ByteArray(DEFAULT_BUFFER_SIZE) + while (EOF != input.read(buffer).also { n = it }) { + output!!.write(buffer, 0, n) + count += n.toLong() + } + return count + } +} \ No newline at end of file diff --git a/app/src/main/java/com/qkopy/compressor/MainActivity.kt b/app/src/main/java/com/qkopy/compressor/MainActivity.kt index 124a2df..753565a 100644 --- a/app/src/main/java/com/qkopy/compressor/MainActivity.kt +++ b/app/src/main/java/com/qkopy/compressor/MainActivity.kt @@ -1,10 +1,11 @@ package com.qkopy.compressor +import android.annotation.SuppressLint import android.app.Activity import android.content.Intent import android.graphics.BitmapFactory import android.os.Bundle -import android.support.v7.app.AppCompatActivity +import androidx.appcompat.app.AppCompatActivity import android.util.Log import android.view.View import com.qkopy.imagecompressor.Compressor @@ -29,6 +30,7 @@ class MainActivity : AppCompatActivity() { setContentView(R.layout.activity_main) clearImage() + } fun chooseImage(view: View) { @@ -37,6 +39,7 @@ class MainActivity : AppCompatActivity() { startActivityForResult(intent, PICK_IMAGE_REQUEST) } + @SuppressLint("CheckResult") fun compressImage(view: View) { if (actualImage == null) { toast("Please choose an image!") diff --git a/build.gradle b/build.gradle index f955cc3..96e8f1c 100644 --- a/build.gradle +++ b/build.gradle @@ -8,7 +8,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:3.3.1' + classpath 'com.android.tools.build:gradle:3.6.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files diff --git a/gradle.properties b/gradle.properties index 85be9ea..3d8ce0c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,3 +13,5 @@ org.gradle.jvmargs=-Xmx1536m # org.gradle.parallel=true # Kotlin code style for this project: "official" or "obsolete": kotlin.code.style=official +android.useAndroidX=true +android.enableJetifier=true diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 0d53024..8130cf0 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Wed Feb 20 19:08:52 IST 2019 +#Thu Apr 16 12:52:09 IST 2020 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip diff --git a/imagecompressor/build.gradle b/imagecompressor/build.gradle index 8904043..b1721c5 100644 --- a/imagecompressor/build.gradle +++ b/imagecompressor/build.gradle @@ -13,7 +13,7 @@ android { versionCode 1 versionName "1.0" - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } @@ -29,12 +29,13 @@ android { dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'com.android.support:appcompat-v7:28.0.0' +// implementation 'com.android.support:appcompat-v7:28.0.0' testImplementation 'junit:junit:4.12' - androidTestImplementation 'com.android.support.test:runner:1.0.2' - androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' + androidTestImplementation 'androidx.test.ext:junit:1.1.1' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation "io.reactivex.rxjava2:rxjava:2.2.3" + implementation "io.reactivex.rxjava2:rxjava:2.2.6" + implementation 'androidx.exifinterface:exifinterface:1.2.0' } repositories { mavenCentral() diff --git a/imagecompressor/src/androidTest/java/com/qkopy/imagecompressor/ExampleInstrumentedTest.java b/imagecompressor/src/androidTest/java/com/qkopy/imagecompressor/ExampleInstrumentedTest.java index e70ff1b..28f16b5 100644 --- a/imagecompressor/src/androidTest/java/com/qkopy/imagecompressor/ExampleInstrumentedTest.java +++ b/imagecompressor/src/androidTest/java/com/qkopy/imagecompressor/ExampleInstrumentedTest.java @@ -1,8 +1,8 @@ package com.qkopy.imagecompressor; import android.content.Context; -import android.support.test.InstrumentationRegistry; -import android.support.test.runner.AndroidJUnit4; +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/imagecompressor/src/main/java/com/qkopy/imagecompressor/Compressor.kt b/imagecompressor/src/main/java/com/qkopy/imagecompressor/Compressor.kt index 7b7e57b..06f9c13 100644 --- a/imagecompressor/src/main/java/com/qkopy/imagecompressor/Compressor.kt +++ b/imagecompressor/src/main/java/com/qkopy/imagecompressor/Compressor.kt @@ -62,7 +62,8 @@ class Compressor(context: Context) { private fun compressToFile(imageFileList: ArrayList):ArrayList{ val compressArrayList = ArrayList() for (imageFile in imageFileList) { - val compressed = ImageUtil.compressImage(imageFile, maxWidth, maxHeight, compressFormat, quality, destinationDirectoryPath + File.separator + imageFile.name) + val compressed = ImageUtil.compressImage(imageFile, maxWidth, maxHeight, compressFormat, quality, + destinationDirectoryPath + File.separator + imageFile.name) compressArrayList.add(compressed) } return compressArrayList diff --git a/imagecompressor/src/main/java/com/qkopy/imagecompressor/ImageUtil.kt b/imagecompressor/src/main/java/com/qkopy/imagecompressor/ImageUtil.kt index ff95b81..56ecebb 100644 --- a/imagecompressor/src/main/java/com/qkopy/imagecompressor/ImageUtil.kt +++ b/imagecompressor/src/main/java/com/qkopy/imagecompressor/ImageUtil.kt @@ -1,7 +1,7 @@ package com.qkopy.imagecompressor import android.graphics.* -import android.media.ExifInterface +import androidx.exifinterface.media.ExifInterface import java.io.File import java.io.FileOutputStream import java.io.IOException From 915c36b6b78c6a5547690b57b256c6b24986bc31 Mon Sep 17 00:00:00 2001 From: Sartaj Roshan Date: Sat, 9 May 2020 15:52:34 +0530 Subject: [PATCH 2/3] Changed Exif library to Androidx Found that android.media.Exifinterface has some bugs and recommended with androidx support library. Most stable version of Exif library is used. --- .../compressor/ExampleInstrumentedTest.kt | 22 ------------ app/src/main/AndroidManifest.xml | 4 +-- .../java/com/qkopy/compressor/FileUtil.kt | 1 + .../java/com/qkopy/compressor/MainActivity.kt | 34 ++++++++++++++++++- app/src/main/res/layout/activity_main.xml | 31 +++++++++++++++++ .../com/qkopy/compressor/ExampleUnitTest.kt | 16 --------- imagecompressor/build.gradle | 4 +-- .../com/qkopy/imagecompressor/ImageUtil.kt | 6 +++- 8 files changed, 74 insertions(+), 44 deletions(-) delete mode 100644 app/src/androidTest/java/com/qkopy/compressor/ExampleInstrumentedTest.kt delete mode 100644 app/src/test/java/com/qkopy/compressor/ExampleUnitTest.kt diff --git a/app/src/androidTest/java/com/qkopy/compressor/ExampleInstrumentedTest.kt b/app/src/androidTest/java/com/qkopy/compressor/ExampleInstrumentedTest.kt deleted file mode 100644 index 9638041..0000000 --- a/app/src/androidTest/java/com/qkopy/compressor/ExampleInstrumentedTest.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.qkopy.compressor - -import androidx.test.platform.app.InstrumentationRegistry -import androidx.test.ext.junit.runners.AndroidJUnit4 -import org.junit.Assert.assertEquals -import org.junit.Test -import org.junit.runner.RunWith - -/** - * Instrumented test, which will execute on an Android device. - * - * See [testing documentation](http://d.android.com/tools/testing). - */ -@RunWith(AndroidJUnit4::class) -class ExampleInstrumentedTest { - @Test - fun useAppContext() { - // Context of the app under test. - val appContext = InstrumentationRegistry.getTargetContext() - assertEquals("com.qkopy.compressor", appContext.packageName) - } -} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e284842..9fcdc53 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,10 +1,10 @@ + xmlns:tools="http://schemas.android.com/tools" package="com.qkopy.compressor" + > - = Build.VERSION_CODES.KITKAT) { + Intent(Intent.ACTION_OPEN_DOCUMENT) + } else { + Intent(Intent.ACTION_GET_CONTENT) + } + intent.addCategory(Intent.CATEGORY_OPENABLE) intent.type = "image/*" startActivityForResult(intent, PICK_IMAGE_REQUEST) + } @SuppressLint("CheckResult") @@ -54,12 +65,18 @@ class MainActivity : AppCompatActivity() { // Compress image using RxJava in background thread Compressor(this@MainActivity) + + //.setDestinationDirectoryPath(obbDir.path+File.separator+"image") + //.compressToBitmapAsFlowable(actualImage!!) .compressToFileAsFlowable(actualImage!!) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe({ file -> + compressedImage = file setCompressedImage() +// compressedBitmap = file +// setCompressedImageBitmap() }, { throwable -> throwable.printStackTrace() toast("$throwable.message") @@ -80,10 +97,20 @@ class MainActivity : AppCompatActivity() { private fun setCompressedImage() { compressed_image.setImageBitmap(BitmapFactory.decodeFile(compressedImage?.absolutePath)) compressed_size.text = String.format("Size : %s", getReadableFileSize(compressedImage?.length())) + val exif = ExifInterface(compressedImage?.absolutePath) + compressed_meta.text = "${exif.getAttribute(ExifInterface.TAG_DATETIME)}\n${exif.getAttribute(ExifInterface.TAG_SOFTWARE)}\n" + + "${exif.getAttribute(ExifInterface.TAG_Y_RESOLUTION)}" //Toast.makeText(this, "Compressed image save in " + compressedImage?.path, Toast.LENGTH_LONG).show() Log.d("Compressor", "Compressed image save in " + compressedImage?.path) } + private fun setCompressedImageBitmap() { + compressed_image.setImageBitmap(compressedBitmap) + compressed_size.text = String.format("Size : %s", getReadableFileSize(compressedBitmap?.byteCount?.toLong())) + //Toast.makeText(this, "Compressed image save in " + compressedImage?.path, Toast.LENGTH_LONG).show() + Log.d("Compressor", "Compressed image save in " + compressedBitmap?.config?.name) + } + private fun clearImage() { compressed_image.setImageDrawable(null) compressed_size.text = getString(R.string.size) @@ -101,6 +128,11 @@ class MainActivity : AppCompatActivity() { if (actualImage!!.absolutePath != null) { actual_image.setImageBitmap(BitmapFactory.decodeFile(actualImage!!.absolutePath)) actual_size.text = String.format("Size : %s", getReadableFileSize(actualImage!!.length())) + val exif = ExifInterface(actualImage?.absolutePath) + actual_meta.text = "${exif.getAttribute(ExifInterface.TAG_DATETIME)}\n${exif.getAttribute(ExifInterface.TAG_SOFTWARE)}\n" + + "${exif.getAttribute(ExifInterface.TAG_Y_RESOLUTION)}" + exif.toString() + clearImage() } diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index d6c7e04..d244e99 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -40,6 +40,7 @@ android:layout_weight="1" android:adjustViewBounds="true"/> + + + + + + + + +