In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-02-14 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)05/31 Report--
This article mainly introduces the "Android performance optimization of picture size, size compression method", in the daily operation, I believe that many people in the Android performance optimization of picture size, size compression methods have doubts, Xiaobian consulted all kinds of data, sorted out a simple and easy-to-use method of operation, hope to answer the "Android performance optimization of picture size, size compression method" of doubt! Next, please follow the editor to study!
Preface
In Android, we often encounter scenes of image compression, such as uploading pictures to the server, including user avatars of personal information, sometimes face recognition also needs to capture pictures, and so on. In this case, we all need to do some processing to the picture, such as size, size and so on.
Common image compression methods
Mass compression
Size compression
Libjpeg
Mass compression
First we want to introduce an api--Bitmap.compress ()
@ WorkerThreadpublic boolean compress (CompressFormat format, int quality, OutputStream stream) {checkRecycled ("Can't compress a recycled bitmap"); / / do explicit check before calling the native method if (stream = = null) {throw new NullPointerException ();} if (quality
< 0 || quality >) {throw new IllegalArgumentException ("quality must be 0.100");} StrictMode.noteSlowCall ("Compression of a bitmap is slow"); Trace.traceBegin (Trace.TRACE_TAG_RESOURCES, "Bitmap.compress"); boolean result = nativeCompress (mNativePtr, format.nativeInt, quality, stream, new byte [writing _ COMPRESS_STORAGE]); Trace.traceEnd (Trace.TRACE_TAG_RESOURCES); return result;}
Compress () is the API of the system, and it is also a common method of mass and size compression.
Public boolean compress (Bitmap.CompressFormat format, int quality, OutputStream stream); this method takes three parameters:
Compression format of Bitmap.CompressFormat format Image
Int quality image compression ratio, Omur100. 0 compression 100% focus 100 means no compression
OutputStream stream writes the output stream of compressed data
Return value: if the compressed data is successfully written to the output stream, true is returned.
Pseudo code
Val baos= ByteArrayoutputstream () try {var quality = 50 do {quality-= 10 baos.reset () bitmap.compress (Bitmap.CompressFormat.JPEG, quality Baos)} while (baos.toByteArray (). Size / 1024 > 100) fos.write (baos.toByteArray (o))} catch (ex: Throwable) {ex.printStackTrace ()} finally {fos.apply I this: FileOutputStream flush () close ()} size compression
Let's first take a look at an attribute, Options.
Property inJustDecodeBounds, if the value is true, the actual bitmap will not be returned and no memory space will be allocated to it, thus avoiding memory overflows.
Allows us to query the image information, including image size information, options.outHeight (original height of the picture) and option.outWidth (original width of the picture).
Decode twice and pass in different options configurations:
Partial pseudo code
Val reqWidth = 500val reqHeight = 300val bitmap = decodeSampledBitmapFromFile (imageFile, reqWidth, reqHeight) val fos = Fileoutputstream (File (applicationContext.filesDir, child: "${system.currentTimeMillis ()} _ scale.jpg")) try {val quality = 50 bitmap.compress (Bitmap.CompressFormat.JPEG, quality) Fos) catch (ex: Throwable) {ex.printstackTrace () finally {fos.apply {flush () close ()} private fun decodeSampledBitmapFromFile (imageFile: File ReqWidth: Int,reqHeight: Int): Bitmap {return BitmapFactory.Options (). Run {inJustDecodeBounds = true / / gets the width and height of the original image first, does not load Bitmap into memory, and returns null BitmapFactory.decodeFile (imageFile.absolutePath, opts: this) inSamplesize = calculateInSampleSize (options: this, reqWidth,reqHeight) inJustDecodeBounds-false BitmapFactory.decodeFile (imageFile.absolutePath) Opts: this)}} private fun calculateInSampleSize (context: BitmapFactory, reqWidth: Int, reqHeight: Int): Int {/ / deconstruct syntax to get the width and height of the original image val (height: Int, width: Int) = options.run {outHeight to outwidth} / / calculate the maximum inSampleSize value, which is the power of 2, while keeping the height and width of these two values greater than the requested height and width. / / the width and height of the original image should be greater than the required width and height var inSampleSize = 1 if (height > reqHeight | | width > reqWidth) {val halfHeight: Int = height / 2 val halfwidth: Int = width / 2 while (halfHeight / inSampleSize > = reqHeight & & halfwidth / inSampleSize > = reqWidth) {inSampleSize * = 2}} return inSampleSize}
InSampleSize is a multiple of 2.
BitmapFactory provides us with a parameter class BitmapFactory.Options that parses the size of the image, and sets the inJustDecodeBounds parameter of the object of this class to true. Although the parsed Bitmap is a null, you can get the width and height of the picture and the type of the picture in options. After getting the actual width and height of the picture, we can set up the compression, mainly to calculate the sampling rate of the picture.
The first sampling is over, and we have successfully calculated the size of the sampleSize
In the second sampling, I need to load the picture and display it, not just the frame of the picture, so the inJustDecodeBounds property should be set to false.
Libjpeg
Libjpeg is a library written entirely in C language, including the widely used implementation of JPEG decoding, JPEG encoding and other JPEG functions.
Libjpeg-turbo image codec, which uses the SIMD instruction to speed up JPEG compression and decompression on x86, x86-64, ARM, and PowerPC systems. Libjpeg-turbo is usually 2-6 times faster than libjpeg.
You can use Huffman
The approach adopted by Wechat
Image compression process
In fact, the most important thing is to convert ARGB to RBG, that is, 4 bytes per pixel, to 3 bytes per pixel.
You can write C code jpeg.so and jpeg-turbo.so by importing the corresponding so library file.
Writing this part of the code requires the environment of NDK and the foundation of C language.
Pseudo code
Int generateCompressJPEG (BYTE * data, int w, int h, int quality, const char * outfileName, jboolean optimize) {/ / structure is equivalent to java class struct jpeg_compress_struct jcs; / / callback struct my_error_mgr jem; jcs.err = jpeg_std_error (& jem.pub); jem.pub.error_exit = my_error_exit when you finish reading the whole file / / setjmp is a system-level function that is a callback if (setjmp (jem.setjmp_buffer)) {return 0;} / initializes the jsc structure jpeg_create_compress (& jcs); / / opens the output file wb writable rb readable FILE * f = fopen (outfileName, "wb"); if (f = NULL) {return 0 } / / set the file path of the structure, and the width and height jpeg_stdio_dest (& jcs, f); jcs.image_width = w; jcs.image_height = h; / / TRUE=arithmetic coding, FALSE=Huffman jcs.arith_code = false; int nComponent = 3; / / the composition of the color rgb, three of color components in input image jcs.input_components = nComponent / / set the color space to rgb jcs.in_color_space = JCS_RGB; jpeg_set_defaults (& jcs); / / whether to use Huffman jcs.optimize_coding = optimize; / / set the quality jpeg_set_quality (& jcs, quality, true); / / start compressing 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]; jpeg_write_scanlines(&jcs, row_pointer, 1); } // 压缩结束 jpeg_finish_compress(&jcs); // 销毁回收内存 jpeg_destroy_compress(&jcs); //关闭文件 fclose(f); return 1;}for (int i = 0; i < bitmapInfo.height; ++i) { for (int j= 0; j < bitmapInfo.width; ++j){ if (bitmapInfo.format == ANDROID_BITMAP_FORMAT_RGBA_8888){ //0x2312faff ->588446463 color = * (int *) (pixelsColor); / / read the value of RGBA from the color value / / ABGR b = (color > > 16) & 0xFE; g = (color > > 8) & OxFF; r = (color > > 0) & OxFF; * data = r; * (data + 1) = g; * (data + 2) = b Data + = 3; / / move step size 4 bytes pixelsColor +-4;} else {return-2;} / / whether to use Huffman jcs.optimize_coding = optimize
At this point, the three image compression methods have been introduced.
Summary
After the practice of image compression, the quality compression is the same as the size of the last picture in libjpeg, and the effect is similar to the original image.
In fact, after looking through the original code, I found that the new version of Bitmap.compress () will call
Boolean result = nativeCompress (mNativePtr, format.nativeInt, quality, stream, new byte [writing _ COMPRESS_STORAGE]); private static native boolean nativeCompress (long nativeBitmap, int format, int quality, OutputStream stream, byte [] tempStorage)
In fact, the compression of nativeCompress will be called in the end, and Huffman algorithm will be used to improve the compression efficiency.
In that case, why introduce libjpeg's approach here?
Compatible with lower versions, the early compress does not use Huffman algorithm.
Cross-platform algorithm of Dachang
At this point, on the "Android performance optimization of picture size, size compression method" study is over, I hope to be able to solve your doubts. The collocation of theory and practice can better help you learn, go and try it! If you want to continue to learn more related knowledge, please continue to follow the website, the editor will continue to work hard to bring you more practical articles!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.