Good morning, everyone. Today I recommend Hensen’s original article, which will introduce you several schemes of compressing pictures on Android platform. This is to correct the error of yesterday’s tweet title, the original tweet New Year’s Eve book giving activity award readers should be in the winter solstice, big night editing manuscript, want to see the New Year’s Eve day to go, the result did not pay attention to the regular push of the article, here thank you pointed out several students, and to say sorry to everyone. Yesterday, I also received messages from award-winning readers one after another. At present, there are two students, Jiaying and Joyce, who did not leave me the recipient’s name + delivery address + desired book + mobile phone number + wechat account. Please leave a message to me on the background after you see it, thank you. All right, let’s get straight to the text.
Original: http://blog.csdn.net/qq_30379689/article/details/78884167
Results demonstrate
Directly first to give you a comparison of several picture compression effect
The quality of compressed
Quality compression: according to the quality of the transfer into the size, using the system’s own compression algorithm, compress the picture into JPEG format
/** * public static void compressQuality(bitmap, bitmap, bitmap, bitmap) int quality, File file) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.JPEG, quality, baos); try { FileOutputStream fos = new FileOutputStream(file); fos.write(baos.toByteArray()); fos.flush(); fos.close(); } catch (Exception e) { e.printStackTrace(); }}
Copy the code
Size of the compression
Size compression: reduce the size of the picture by equal proportions according to the zoom ratio, so as to achieve the effect of compression
Public static void compressSize(bitmap, file file) {int ratio = 8; Bitmap result = bitmap.createbitmap (bitmap.getwidth ()/ratio, bitmap.getheight ()/ratio, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(result); Rect rect = new Rect(0, 0, bitmap.getWidth() / ratio, bitmap.getHeight() / ratio); canvas.drawBitmap(bitmap, null, rect, null); compressQuality(result, 100, file); }
Copy the code
Sampling rate compression
Sampling rate compression: Compress according to the sample rate size of the picture
@param filePath @param filePath public static void compressSample(String filePath, String filePath) File file) { int inSampleSize = 8; Bitmapfactory.options Options = new bitmapFactory.options (); options.inJustDecodeBounds = false; options.inSampleSize = inSampleSize; Bitmap bitmap = BitmapFactory.decodeFile(filePath, options); compressQuality(bitmap, 100, file); }
Copy the code
LibJpeg compression
LibJpeg compression: Using Ndk to call LibJpeg library for compression, retain the original pixel, high resolution
Compile LibJpeg
1, is already written compilation script can be downloaded from the making of project: https://github.com/Zelex/libjpeg-turbo-android, and upload it to a directory of Linux server
2. Grant permissions to the entire directory
chmod 777 -R libjpeg-turbo-android-master
Copy the code
3. Go to the libjpeg directory and use the following instructions to compile, assuming your server has built the ndK-build and configured the environment variables
ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=./Android.mk APP_ABI=armeabi-v7a obj/local/armeabi-v7a/libjpeg.a LOCAL_ARM_MODE=arm LOCAL_ARM_NEON=true ARCH_ARM_HAVE_NEON=true
Copy the code
Libjpeg.a will be generated in the obj/local directory
Create a project
1, create a new project, check include C++, check C++11 and C++ dependent libraries
2. Import the generated libjpeg.a and header file into our project
3. Configure Gradle
Android {compileSdkVersion 25 buildToolsVersion "25.0.3 defaultConfig {applicationId" com. Handsome. Bitmapcompress" 25 versionCode minSdkVersion 16 targetSdkVersion 1 versionName testInstrumentationRunner "1.0" "android.support.test.runner.AndroidJUnitRunner" externalNativeBuild { cmake { cppFlags "-std=c++11 -frtti -fexceptions" // The supported CPU type abiFilters "armeabi", "armeabi-v7a" } } } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'}} // Modify Libs library path sourcesets. main {jnilibs.srcdirs = [' Libs '] jni.srcdirs = []} externalNativeBuild { cmake { path "CMakeLists.txt" } } }
Copy the code
4. Configure CMake
Cmake_minimum_required (VERSION 3.4.1 track) include_directories (. / libs/jpeg) link_directories (. / libs / ${ANDROID_ABI}) find_library(log-lib log) find_library(android-lib android) find_library(bitmap-lib jnigraphics) add_library( # Sets the name of the library. native-lib # Sets the library as a shared library. SHARED # Provides a relative path to your source file(s). src/main/cpp/native-lib.cpp ) target_link_libraries( native-lib ${log-lib} ${android-lib} ${bitmap-lib} jpeg )
Copy the code
5. Declare permissions
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Copy the code
Use LibJpeg
Launch the Intent for the selected file
/** * selectFile */public void selectFile() {if (build.version.sdk_int < build.version_codes.kitkat) { startActivityForResult(new Intent(Intent.ACTION_GET_CONTENT).setType("image/*"), REQUEST_PICK_IMAGE); } else { Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); intent.addCategory(Intent.CATEGORY_OPENABLE); intent.setType("image/*"); startActivityForResult(intent, REQUEST_KITKAT_PICK_IMAGE); }}
Copy the code
2. Compress the returned results
Return result ** @param requestCode * @param resultCode * @param data */ @overridePublic void onActivityResult(int) requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK) { switch (requestCode) { case REQUEST_PICK_IMAGE: if (data ! = null) { Uri uri = data.getData(); compressImage(uri); } break; case REQUEST_KITKAT_PICK_IMAGE: if (data ! = null) { Uri uri = ensureUriPermission(this, data); compressImage(uri); } break; }}}/** * * * @param uri */public void compressImage(uri uri) {try {File saveFile = new File(getExternalCacheDir), "The NDK compression. JPG"); Bitmap bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), uri); int code = CompressUtils.compressBitmap(bitmap, 20, saveFile.getAbsolutePath().getBytes(), true); File saveFile1 = new File(getExternalCacheDir(), "quality compression.jpg"); CompressUtils.compressQuality(bitmap, 20, saveFile1); File saveFile2 = new File(getExternalCacheDir(), "size compressed.jpg "); CompressUtils.compressSize(bitmap, saveFile2); File saveFile3 = new File(getExternalCacheDir(), "sample rate compressed.jpg"); File LocalFile = new File("/storage/emulated/0/DCIM/Camera/IMG_20171216_171956.jpg"); if (LocalFile.exists()) { CompressUtils.compressSample(LocalFile.getAbsolutePath(), saveFile3); } } catch (IOException e) { e.printStackTrace(); }}
Copy the code
Load the local library and declare the LibJpeg compression method
public class CompressUtils { static {
System.loadLibrary("native-lib");
} public static native int compressBitmap(Bitmap bitmap, int quality, byte[] fileNameBytes, boolean optimize);
}
Copy the code
4. Write LibJpeg local files
-
Extract the ARGB flux of the picture and the RGB flux
-
The LibJpeg API is used for compression
-
Write data to a file
#include <jni.h>#include <string>#include <android/bitmap.h>#include <android/log.h>#include <setjmp.h>extern "C" { #include "jpeglib.h" #include "cdjpeg.h"}#define LOG_TAG "jni"#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)typedef uint8_t BYTE; typedef struct my_error_mgr *my_error_ptr; struct my_error_mgr { struct jpeg_error_mgr pub; jmp_buf setjmp_buffer; }; METHODDEF(void) my_error_exit(j_common_ptr cinfo) { my_error_ptr myerr = (my_error_ptr) cinfo->err; (*cinfo->err->output_message)(cinfo); LOGE("jpeg_message_table[%d]:%s", myerr->pub.msg_code, myerr->pub.jpeg_message_table[myerr->pub.msg_code]); longjmp(myerr->setjmp_buffer, 1); } /** * Libjpeg * @param data * @param w * @param H * @param quality * @param outfilename * @param optimize * @return */int generateJPEG(BYTE *data, int w, int h, int quality, const char *outfilename, Jboolean optimize) {// struct jpeg_compress_struct JCS; Struct my_error_mgr jem; my_error_exit struct my_error_mgr jem; jcs.err = jpeg_std_error(&jem.pub); jem.pub.error_exit = my_error_exit; if (setjmp(jem.setjmp_buffer)) { return 0; } // Initialize the JSC structure jpeg_create_compress(& JCS); // open the output FILE FILE* f = fopen(outfilename, "wb"); if (f == NULL) { return 0; } // Set the structure's file path jpeg_stdio_dest(&jcs, f); jcs.image_width = w; // Set the width and height to jcs.image_height = h; // Arithmetic coding, TRUE=arithmetic coding, FALSE=Huffman if (optimize) {jcs.arith_code = FALSE; } else { jcs.arith_code = true; } // Color channel count int nComponent = 3; jcs.input_components = nComponent; // Set the structure's color space to RGB jcs.in_color_space = JCS_RGB; // Set all the default arguments jpeg_set_defaults(& JCS); JCS. Optimize_coding = optimize; // Set the quality jpeG_set_quality (& JCS, quality, true); // Start compression, (whether to write all pixels) jpeg_start_compress(& JCS, TRUE); JSAMPROW row_pointer[1]; int row_stride; Row_stride = jcs.image_width * nComponent; While (jcs.next_scanline < jcs.image_height) {row_pointer[0] = &data[jcs.next_scanline * row_stride]; // This method increments JCS. Next_scanline by 1 jpeG_write_scanlines (& JCS, row_pointer, 1); } jpeg_finish_compress(&jcs); //row_pointer is the start address of a row, 1: the number of rows to write. jpeg_destroy_compress(&jcs); fclose(f); return 1; }/** * char *jstrinTostring(JNIEnv *env, jbyteArray barr) {char * RTN = NULL; jsize alen = env->GetArrayLength(barr); jbyte *ba = env->GetByteArrayElements(barr, 0); if (alen > 0) { rtn = (char *) malloc(alen + 1); memcpy(rtn, ba, alen); rtn[alen] = 0; } env->ReleaseByteArrayElements(barr, ba, 0); return rtn; } extern "C"JNIEXPORT jint JNICALL Java_com_handsome_bitmapcompress_CompressUtils_compressBitmap(JNIEnv *env, jclass type, jobject bitmap, jint quality, jbyteArray fileNameBytes_, Jboolean optimize) {AndroidBitmapInfo android_bitmap_info; AndroidBitmap_getInfo(env, bitmap, &android_bitmap_info); // Format int w = android_bitmap_info.width; // Format int w = android_bitmap_info.width; int h = android_bitmap_info.height; int format = android_bitmap_info.format; if (format ! = ANDROID_BITMAP_FORMAT_RGBA_8888) { return -1; } // Store all ARGB pixels BYTE *pixelsColor; AndroidBitmap_lockPixels(env, Bitmap, (void **) &pixelsColor); Int I = 0, j = 0; BYTE a, r, g, b; // Store all RGB pixels BYTE *data; data = (BYTE *) malloc(w * h * 3); BYTE *tempData = data; int color; for (i = 0; i < h; ++i) { for (j = 0; j < w; ++j) {color = *((int *) pixelsColor); // Value a = ((color & 0xFF000000) >> 24); r = ((color & 0x00FF0000) >> 16); g = ((color & 0x0000FF00) >> 8); b = ((color & 0x000000FF)); // Assign *data = b; *(data + 1) = g; *(data + 2) = r; // data += 3; pixelsColor += 4; AndroidBitmap_unlockPixels(env, bitmap); char *fileName = jstrinTostring(env, fileNameBytes_); Int resultCode = generateJPEG(tempData, w, h, quality, fileName, optimize); if (resultCode == 0) { return 0; } return 1; }
Copy the code
Need to run more than several programs source code, you can visit: https://github.com/AndroidHensen/BitmapCompress.
Past wonderful
-
Some thoughts on Android APP performance optimization
-
Gift book welfare, happy winter solstice!
-
Understand Java memory leaks once and for all
If you like this article, you can support the original author with likes, retweets and tips.
The author’s appreciation code