【问题标题】:Android Crop Center of BitmapAndroid 位图裁剪中心
【发布时间】:2011-10-18 00:38:08
【问题描述】:

我有正方形或矩形的位图。我走最短的一边,做这样的事情:

int value = 0;
if (bitmap.getHeight() <= bitmap.getWidth()) {
    value = bitmap.getHeight();
} else {
    value = bitmap.getWidth();
}

Bitmap finalBitmap = null;
finalBitmap = Bitmap.createBitmap(bitmap, 0, 0, value, value);

然后我使用以下方法将其缩放为 144 x 144 位图:

Bitmap lastBitmap = null;
lastBitmap = Bitmap.createScaledBitmap(finalBitmap, 144, 144, true);

问题是它裁剪了原始位图的左上角,谁有裁剪位图中心的代码?

【问题讨论】:

    标签: android bitmap crop


    【解决方案1】:
    public Bitmap getResizedBitmap(Bitmap bm) {
        int width = bm.getWidth();
        int height = bm.getHeight();
    
        int narrowSize = Math.min(width, height);
        int differ = (int)Math.abs((bm.getHeight() - bm.getWidth())/2.0f);
        width  = (width  == narrowSize) ? 0 : differ;
        height = (width == 0) ? differ : 0;
    
        Bitmap resizedBitmap = Bitmap.createBitmap(bm, width, height, narrowSize, narrowSize);
        bm.recycle();
        return resizedBitmap;
    }
    

    【讨论】:

      【解决方案2】:
      public static Bitmap resizeAndCropCenter(Bitmap bitmap, int size, boolean recycle) {
          int w = bitmap.getWidth();
          int h = bitmap.getHeight();
          if (w == size && h == size) return bitmap;
          // scale the image so that the shorter side equals to the target;
          // the longer side will be center-cropped.
          float scale = (float) size / Math.min(w,  h);
          Bitmap target = Bitmap.createBitmap(size, size, getConfig(bitmap));
          int width = Math.round(scale * bitmap.getWidth());
          int height = Math.round(scale * bitmap.getHeight());
          Canvas canvas = new Canvas(target);
          canvas.translate((size - width) / 2f, (size - height) / 2f);
          canvas.scale(scale, scale);
          Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG);
          canvas.drawBitmap(bitmap, 0, 0, paint);
          if (recycle) bitmap.recycle();
          return target;
      }
      
      private static Bitmap.Config getConfig(Bitmap bitmap) {
          Bitmap.Config config = bitmap.getConfig();
          if (config == null) {
              config = Bitmap.Config.ARGB_8888;
          }
          return config;
      }
      

      【讨论】:

        【解决方案3】:

        虽然上面的大多数答案都提供了一种方法来做到这一点,但已经有一种内置的方法可以做到这一点,它是 1 行代码 (ThumbnailUtils.extractThumbnail())

        int dimension = getSquareCropDimensionForBitmap(bitmap);
        bitmap = ThumbnailUtils.extractThumbnail(bitmap, dimension, dimension);
        
        ...
        
        //I added this method because people keep asking how 
        //to calculate the dimensions of the bitmap...see comments below
        public int getSquareCropDimensionForBitmap(Bitmap bitmap)
        {
            //use the smallest dimension of the image to crop to
            return Math.min(bitmap.getWidth(), bitmap.getHeight());
        }
        

        如果您希望位图对象被回收,您可以传递使其如此的选项:

        bitmap = ThumbnailUtils.extractThumbnail(bitmap, dimension, dimension, ThumbnailUtils.OPTIONS_RECYCLE_INPUT);
        

        发件人:ThumbnailUtils Documentation

        public static Bitmap extractThumbnail (Bitmap source, int width, int 高度)

        在 API 级别 8 中添加 创建所需大小的居中位图。

        参数 source original bitmap source width 目标宽度 height 目标高度

        我有时在使用已接受的答案时出现内存不足错误,而使用 ThumbnailUtils 为我解决了这些问题。另外,这更清洁,更可重复使用。

        【讨论】:

        • +1 我认为您必须改进此代码,而不是使用 400px,传递最短的 bmp 大小,以便为上面的原始帖子提供替代方案。但是感谢您提请我们注意,这似乎是一个非常有用的功能。可惜没见过……
        • 对,我只是硬编码 400 来给出一个具体的例子......细节取决于实现者:)
        • @DiscDev - 这确实是整个网站上最有用的答案之一。严重地。 Android 问题很奇怪——你通常可以搜索两个小时才能找到简单明显的答案。不知道该怎么感谢你。赏金途中!
        • 你甚至可以使用一些不同的函数,来回收旧的位图:= ThumbnailUtils.extractThumbnail(bitmap, width,height, ThumbnailUtils.OPTIONS_RECYCLE_INPUT)
        • 这是迄今为止我看到的关于 android 问题的最有力的答案。我已经看到了 20 种不同的解决方案,如何在 Android 上缩放/裁剪/缩小/调整大小等位图。所有的答案都不一样。而这个只需要 1 行并且完全按预期工作。谢谢。
        【解决方案4】:

        可能是迄今为止最简单的解决方案:

        public static Bitmap cropCenter(Bitmap bmp) {
            int dimension = Math.min(bmp.getWidth(), bmp.getHeight());
            return ThumbnailUtils.extractThumbnail(bmp, dimension, dimension);
        }
        

        进口:

        import android.media.ThumbnailUtils;
        import java.lang.Math;
        import android.graphics.Bitmap;
        

        【讨论】:

          【解决方案5】:

          这可以通过以下方式实现:Bitmap.createBitmap(source, x, y, width, height)

          if (srcBmp.getWidth() >= srcBmp.getHeight()){
          
            dstBmp = Bitmap.createBitmap(
               srcBmp, 
               srcBmp.getWidth()/2 - srcBmp.getHeight()/2,
               0,
               srcBmp.getHeight(), 
               srcBmp.getHeight()
               );
          
          }else{
          
            dstBmp = Bitmap.createBitmap(
               srcBmp,
               0, 
               srcBmp.getHeight()/2 - srcBmp.getWidth()/2,
               srcBmp.getWidth(),
               srcBmp.getWidth() 
               );
          }
          

          【讨论】:

          • 编辑了答案,使实际的目标位图是一个正方形。
          • @Lumis:你为什么回滚修订版 3?这似乎是一个有效的正确。您当前的版本创建了正确的起点,但随后包含了太长边的其余部分。例如,给定一个100x1000 图像,你会得到一个100x550 图像。
          • 谢谢,你说得对,格式是Bitmap.createBitmap(source, x, y, width, height)
          • 查看我关于使用内置 ThumbnailUtils.extractThumbnail() 方法的答案。为什么要重新发明轮子??? stackoverflow.com/a/17733530/1103584
          • 这个解决方案比创建一个画布然后绘制一个drawable要短。它的处理量也比 ThumbnailUtils 解决方案少(它计算样本大小以确定如何缩放)。
          【解决方案6】:

          这里是一个更完整的 sn-p,它裁剪出任意尺寸的 [位图] 的中心,并将结果缩放到您想要的 [IMAGE_SIZE]。所以你总是会得到一个 [croppedBitmap] 固定大小的图像中心的缩放正方形。非常适合缩略图等。

          它是其他解决方案的更完整组合。

          final int IMAGE_SIZE = 255;
          boolean landscape = bitmap.getWidth() > bitmap.getHeight();
          
          float scale_factor;
          if (landscape) scale_factor = (float)IMAGE_SIZE / bitmap.getHeight();
          else scale_factor = (float)IMAGE_SIZE / bitmap.getWidth();
          Matrix matrix = new Matrix();
          matrix.postScale(scale_factor, scale_factor);
          
          Bitmap croppedBitmap;
          if (landscape){
              int start = (tempBitmap.getWidth() - tempBitmap.getHeight()) / 2;
              croppedBitmap = Bitmap.createBitmap(tempBitmap, start, 0, tempBitmap.getHeight(), tempBitmap.getHeight(), matrix, true);
          } else {
              int start = (tempBitmap.getHeight() - tempBitmap.getWidth()) / 2;
              croppedBitmap = Bitmap.createBitmap(tempBitmap, 0, start, tempBitmap.getWidth(), tempBitmap.getWidth(), matrix, true);
          }
          

          【讨论】:

            【解决方案7】:

            纠正@willsteel 解决方案:

            if (landscape){
                            int start = (tempBitmap.getWidth() - tempBitmap.getHeight()) / 2;
                            croppedBitmap = Bitmap.createBitmap(tempBitmap, start, 0, tempBitmap.getHeight(), tempBitmap.getHeight(), matrix, true);
                        } else {
                            int start = (tempBitmap.getHeight() - tempBitmap.getWidth()) / 2;
                            croppedBitmap = Bitmap.createBitmap(tempBitmap, 0, start, tempBitmap.getWidth(), tempBitmap.getWidth(), matrix, true);
                        }
            

            【讨论】:

            • 这是对 WillSteel 解决方案的修复。在这种情况下,tempBitmap 只是原始(未更改)位图或其自身的副本。
            【解决方案8】:

            您可以使用以下代码来解决您的问题。

            Matrix matrix = new Matrix();
            matrix.postScale(0.5f, 0.5f);
            Bitmap croppedBitmap = Bitmap.createBitmap(bitmapOriginal, 100, 100,100, 100, matrix, true);
            

            上述方法在裁剪前对图像进行postScalling,这样您可以在裁剪图像时获得最佳效果而不会出现OOM错误。

            更多详情可以参考this blog

            【讨论】:

            • E/AndroidRuntime(30010): Caused by: java.lang.IllegalArgumentException: x + width must be
            【解决方案9】:

            您是否考虑过从layout.xml 执行此操作?您可以将ImageViewScaleType 设置为android:scaleType="centerCrop",并在layout.xml 内的ImageView 中设置图像的尺寸。

            【讨论】:

            • 我用以下 OpenGLRenderer 错误尝试了这个想法:“位图太大,无法上传到纹理中(2432x4320,max=4096x4096)”所以,我猜无法处理 4320 高度.
            • 当然这是一个正确的答案,并且完美地回答了这个问题!优化大图像的图像质量/尺寸......嗯,这是一个不同的问题!
            • @ichalos 也许你找到了你要找的东西,但这并不能回答最初的问题。最初的问题是关于在画布上手动渲染。实际上,我不确定任何人第一次尝试裁剪照片会如何在画布上手动渲染,但是嘿,你在这里找到了解决方案很好:)
            • @milosmns 也许你是对的。也许这正是用户试图解决手动裁剪到中心问题的方式。这一切都取决于原始用户的确切需求。
            猜你喜欢
            • 1970-01-01
            • 2015-12-11
            • 2012-11-08
            • 2012-12-02
            • 1970-01-01
            • 2019-05-10
            • 1970-01-01
            • 2015-02-02
            • 2014-05-26
            相关资源
            最近更新 更多