以矩形裁剪位图图像

Posted

技术标签:

【中文标题】以矩形裁剪位图图像【英文标题】:Crop bitmap image in rectangular 【发布时间】:2019-07-15 09:09:48 【问题描述】:

我想在不使用任何库的情况下裁剪图像。

我正在参考https://***.com/a/6909144 并尝试更改值但无法找出解决方案

Bitmap bitmap = BitmapUtil.getBitmap(path);

                    Log.d(TAG,"bitmap  width : "+bitmap.getWidth()+"  height:  "+bitmap.getHeight());

                    if (bitmap.getWidth() >= bitmap.getHeight())
                        Toast.makeText(this,"Height Greater",Toast.LENGTH_SHORT).show();
                        Log.d(TAG,"Greater : Height");
                        textView.setText("Height Greater");
                        bitmap = Bitmap.createBitmap(
                                bitmap,
                                bitmap.getWidth()/2 - bitmap.getHeight()/2,
                                0,
                                bitmap.getHeight(),
                                bitmap.getHeight()
                        );

                    else
                        Toast.makeText(this,"Width Greater",Toast.LENGTH_SHORT).show();
                        Log.d(TAG,"Greater : Width");
                        textView.setText("Width Greater");
                        bitmap = Bitmap.createBitmap(
                                bitmap,
                                0,
                                bitmap.getHeight()/2 - bitmap.getWidth()/2,
                                bitmap.getWidth(),
                                bitmap.getWidth()
                        );
                    

我想要一个矩形内的裁剪位图图像。

【问题讨论】:

【参考方案1】:

为了有效地创建位图,试试这个

import android.graphics.Bitmap
import android.graphics.BitmapFactory
import java.io.ByteArrayOutputStream

    /**
     * 
     * ImageScalingUtils responsible for compressing the bitmap efficiently
     */
    object ImageScalingUtils 

        /**
         * Utility function for decoding an image resource. The decoded bitmap will
         * be optimized for further scaling to the requested destination dimensions
         * and scaling logic.
         *
         * @param dstWidth Width of destination area
         * @param dstHeight Height of destination area
         * @param scalingLogic Logic to use to avoid image stretching
         * @return Decoded bitmap
         */


        fun decodeBitmap(bm: Bitmap, dstWidth: Int, dstHeight: Int,
                         scalingLogic: ScalingLogic): Bitmap 
            val stream = ByteArrayOutputStream()
            bm.compress(Bitmap.CompressFormat.PNG, 100, stream)
            val byteArray = stream.toByteArray()
            val options = BitmapFactory.Options()
            options.inJustDecodeBounds = true
            BitmapFactory.decodeByteArray(byteArray, 0, byteArray.size, options)
            options.inJustDecodeBounds = false
            options.inSampleSize = calculateSampleSize(options.outWidth, options.outHeight, dstWidth,
                    dstHeight, scalingLogic)
            return BitmapFactory.decodeByteArray(byteArray, 0, byteArray.size, options)
        

        /**
         * ScalingLogic defines how scaling should be carried out if source and
         * destination image has different aspect ratio.
         *
         * CROP: Scales the image the minimum amount while making sure that at least
         * one of the two dimensions fit inside the requested destination area.
         * Parts of the source image will be cropped to realize this.
         *
         * FIT: Scales the image the minimum amount while making sure both
         * dimensions fit inside the requested destination area. The resulting
         * destination dimensions might be adjusted to a smaller size than
         * requested.
         */
        enum class ScalingLogic 
            CROP, FIT
        

        /**
         * Calculate optimal down-sampling factor given the dimensions of a source
         * image, the dimensions of a destination area and a scaling logic.
         *
         * @param srcWidth Width of source image
         * @param srcHeight Height of source image
         * @param dstWidth Width of destination area
         * @param dstHeight Height of destination area
         * @param scalingLogic Logic to use to avoid image stretching
         * @return Optimal down scaling sample size for decoding
         */
        private fun calculateSampleSize(srcWidth: Int, srcHeight: Int, dstWidth: Int, dstHeight: Int,
                                        scalingLogic: ScalingLogic): Int 
            if (scalingLogic == ScalingLogic.FIT) 
                val srcAspect = srcWidth.toFloat() / srcHeight.toFloat()
                val dstAspect = dstWidth.toFloat() / dstHeight.toFloat()

                return if (srcAspect > dstAspect) 
                    srcWidth / dstWidth
                 else 
                    srcHeight / dstHeight
                
             else 
                val srcAspect = srcWidth.toFloat() / srcHeight.toFloat()
                val dstAspect = dstWidth.toFloat() / dstHeight.toFloat()

                return if (srcAspect > dstAspect) 
                    srcHeight / dstHeight
                 else 
                    srcWidth / dstWidth
                
            
        


    

缩放图片类来缩放你的图片

 import android.content.ContentResolver
    import android.graphics.Bitmap
    import android.graphics.BitmapFactory
    import android.graphics.Matrix
    import android.graphics.RectF
    import android.net.Uri
    import androidx.exifinterface.media.ExifInterface
    import java.io.FileNotFoundException
    import java.io.IOException
    import java.io.InvalidObjectException

    /**
     *
     * ScaledPicture responsible for compressing the bitmap efficiently
     */
    class ScaledPicture(private var uri: Uri?, private var resolver: ContentResolver) 
        private var path: String? = null
        private var orientation: Matrix? = null
        private var storedHeight: Int = 0
        private var storedWidth: Int = 0

        @Throws(IOException::class)
        private fun getInformation(): Boolean 
            /*if (getInformationFromMediaDatabase())
                return true;*/
            return getInformationFromFileSystem()
        

        /* Support for file managers and dropbox */
        @Throws(IOException::class)
        private fun getInformationFromFileSystem(): Boolean 
            path = uri?.path
            if (path == null)
                return false
            val exif = ExifInterface(path.toString())
            val orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION,
                    ExifInterface.ORIENTATION_NORMAL)
            this.orientation = Matrix()
            when (orientation) 
                ExifInterface.ORIENTATION_NORMAL -> 
                
                ExifInterface.ORIENTATION_FLIP_HORIZONTAL -> this.orientation?.setScale(-1f, 1f)
                ExifInterface.ORIENTATION_ROTATE_180 -> this.orientation?.setRotate(180f)
                ExifInterface.ORIENTATION_FLIP_VERTICAL -> this.orientation?.setScale(1f, -1f)
                ExifInterface.ORIENTATION_TRANSPOSE -> 
                    this.orientation?.setRotate(90f)
                    this.orientation?.postScale(-1f, 1f)
                
                ExifInterface.ORIENTATION_ROTATE_90 -> this.orientation?.setRotate(90f)
                ExifInterface.ORIENTATION_TRANSVERSE -> 
                    this.orientation?.setRotate(-90f)
                    this.orientation?.postScale(-1f, 1f)
                
                ExifInterface.ORIENTATION_ROTATE_270 -> this.orientation?.setRotate(-90f)
            /* Identity matrix */
            return true
        

        @Throws(IOException::class)
        private fun getStoredDimensions(): Boolean 
            val input = resolver.openInputStream(uri)
            val options = BitmapFactory.Options()
            options.inJustDecodeBounds = true
            BitmapFactory.decodeStream(resolver.openInputStream(uri), null, options)
            /* The input stream could be reset instead of closed and reopened if it were possible
               to reliably wrap the input stream on a buffered stream, but it's not possible because
               decodeStream() places an upper read limit of 1024 bytes for a reset to be made (it calls
               mark(1024) on the stream). */

            input?.close()
            if (options.outHeight <= 0 || options.outWidth <= 0)
                return false
            storedHeight = options.outHeight
            storedWidth = options.outWidth
            return true
        

        @Throws(IOException::class)
        fun getBitmap(reqWidth: Int, reqHeight: Int): Bitmap 
            val heightWidth = 1000
            if (!getInformation())
                throw FileNotFoundException()
            if (!getStoredDimensions())
                throw InvalidObjectException(null)
            val rect = RectF(0f, 0f, storedWidth.toFloat(), storedHeight.toFloat())
            orientation?.mapRect(rect)
            var width = rect.width().toInt()
            var height = rect.height().toInt()
            var subSample = 1
            while (width > heightWidth || height > heightWidth) 
                width /= 2
                height /= 2
                subSample *= 2
            
            if (width == 0 || height == 0)
                throw InvalidObjectException(null)
            val options = BitmapFactory.Options()
            options.inSampleSize = subSample
            val subSampled = BitmapFactory.decodeStream(resolver.openInputStream(uri), null, options)
            val picture: Bitmap
            if (orientation?.isIdentity == false) 
                picture = Bitmap.createBitmap(subSampled, 0, 0, options.outWidth, options.outHeight,
                        orientation, false)
                subSampled.recycle()
             else

                picture = subSampled

            return ImageScalingUtils.decodeBitmap(picture, reqWidth, reqHeight, ImageScalingUtils.ScalingLogic.CROP)
        

    

将上面的类复制到你的项目中,像这样使用

var bitmap = ScaledPicture(mSelectedUri, contentResolver).getBitmap(800, 800)

传递你想要的高度和宽度

【讨论】:

感谢您的回复,我尝试了您的解决方案,但没有成功,图片没有被裁剪。 你遇到了什么问题 实际上我的 xml 框架宽度 = 260 和高度 =400 和图像边宽度 = 1080 高度 = 1920 您提供的解决方案按原样返回位图 Scaled() 图片类返回给您的位是否与具有原始大小的实际图像一致?

以上是关于以矩形裁剪位图图像的主要内容,如果未能解决你的问题,请参考以下文章

Android 位图平移/缩放/裁剪

如何从顶部和底部裁剪位图图像?

将位图图像裁剪为自定义正方形

在ImageView中设置圆角图像

如何裁剪位图并获得图像的下 50%

在 Android 中基于叠加层裁剪位图 - Camera API 2