【问题标题】:Resizing a bitmap to a fixed value but without changing the aspect ratio将位图大小调整为固定值但不更改纵横比
【发布时间】:2023-03-04 08:17:07
【问题描述】:

我正在寻找以下问题的解决方案:如何将Bitmap 的大小更改为固定大小(例如 512x128)。必须保留位图内容的纵横比。

我觉得应该是这样的:

  • 创建一个空的 512x128 位图

  • 缩小原始位图以适应 512x128 像素,同时保持纵横比

  • 将缩放后的位图复制到空位图(居中)

实现这一目标的最简单方法是什么?

所有这一切的原因是,当图像的纵横比与另一个图像的纵横比不同时,GridView 会使布局混乱。这是一个屏幕截图(除了最后一张,所有图片的宽高比都是 4:1):

screenshot

【问题讨论】:

    标签: android view bitmap scaling


    【解决方案1】:

    试试这个,计算比率,然后重新缩放。

    private Bitmap scaleBitmap(Bitmap bm) {
        int width = bm.getWidth();
        int height = bm.getHeight();
    
        Log.v("Pictures", "Width and height are " + width + "--" + height);
    
        if (width > height) {
            // landscape
            float ratio = (float) width / maxWidth;
            width = maxWidth;
            height = (int)(height / ratio);
        } else if (height > width) {
            // portrait
            float ratio = (float) height / maxHeight;
            height = maxHeight;
            width = (int)(width / ratio);
        } else {
            // square
            height = maxHeight;
            width = maxWidth;
        }
    
        Log.v("Pictures", "after scaling Width and height are " + width + "--" + height);
    
        bm = Bitmap.createScaledBitmap(bm, width, height, true);
        return bm;
    }
    

    【讨论】:

    • 加上一个简单的解决方案。但我会将 int 比率更改为 float/double 比率,因为 int/int 在尝试除以 0 时可能会产生异常。
    • 很棒的简单解决方案!使用浮点数而不是整数是必须的。结果在大多数情况下可能是错误的,否则(例如,比率应为 1.4 时变为 1)。
    • @Hikaru 你是对的,想这样做,但从来没有做到。感谢您的编辑和提醒 -)
    • 第三条似乎没有纵横比。不要使用高度 = maxHeight;宽度 = 最大宽度;删除最后一个子句并将 else if (height > width) { 更改为 else{
    【解决方案2】:

    Coen Damen 的回答并不总是尊重最大高度和最大宽度。 这是一个答案:

     private static Bitmap resize(Bitmap image, int maxWidth, int maxHeight) {
        if (maxHeight > 0 && maxWidth > 0) {
            int width = image.getWidth();
            int height = image.getHeight();
            float ratioBitmap = (float) width / (float) height;
            float ratioMax = (float) maxWidth / (float) maxHeight;
    
            int finalWidth = maxWidth;
            int finalHeight = maxHeight;
            if (ratioMax > 1) {
                finalWidth = (int) ((float)maxHeight * ratioBitmap);
            } else {
                finalHeight = (int) ((float)maxWidth / ratioBitmap);
            }
            image = Bitmap.createScaledBitmap(image, finalWidth, finalHeight, true);
            return image;
        } else {
            return image;
        }
    }
    

    【讨论】:

    • 窃取我的答案很好。当然 maxWidth 和 maxHeight 是类变量而不是方法参数。
    【解决方案3】:

    我在我的项目中多次偶然发现同样的问题,每次由于时间不足(和懒惰),我都会对不太理想的解决方案感到满意。但最近我找到了一些时间来解决这个特殊问题。这是我的解决方案,我希望它可以帮助某人。

    Bitmap scaleDownLargeImageWithAspectRatio(Bitmap image)
                {
                    int imageVerticalAspectRatio,imageHorizontalAspectRatio;
                    float bestFitScalingFactor=0;
                    float percesionValue=(float) 0.2;
        
                    //getAspect Ratio of Image
                    int imageHeight=(int) (Math.ceil((double) image.getHeight()/100)*100);
                    int imageWidth=(int) (Math.ceil((double) image.getWidth()/100)*100);
                    int GCD=BigInteger.valueOf(imageHeight).gcd(BigInteger.valueOf(imageWidth)).intValue();
                    imageVerticalAspectRatio=imageHeight/GCD;
                    imageHorizontalAspectRatio=imageWidth/GCD;
                    Log.i("scaleDownLargeImageWIthAspectRatio","Image Dimensions(W:H): "+imageWidth+":"+imageHeight);
                    Log.i("scaleDownLargeImageWIthAspectRatio","Image AspectRatio(W:H): "+imageHorizontalAspectRatio+":"+imageVerticalAspectRatio);
        
                    //getContainer Dimensions
                    int displayWidth = getWindowManager().getDefaultDisplay().getWidth();
                    int displayHeight = getWindowManager().getDefaultDisplay().getHeight();
                   //I wanted to show the image to fit the entire device, as a best case. So my ccontainer dimensions were displayWidth & displayHeight. For your case, you will need to fetch container dimensions at run time or you can pass static values to these two parameters 
        
                    int leftMargin = 0;
                    int rightMargin = 0;
                    int topMargin = 0;
                    int bottomMargin = 0;
                    int containerWidth = displayWidth - (leftMargin + rightMargin);
                    int containerHeight = displayHeight - (topMargin + bottomMargin);
                    Log.i("scaleDownLargeImageWIthAspectRatio","Container dimensions(W:H): "+containerWidth+":"+containerHeight);
        
                    //iterate to get bestFitScaleFactor per constraints
                    while((imageHorizontalAspectRatio*bestFitScalingFactor <= containerWidth) && 
                            (imageVerticalAspectRatio*bestFitScalingFactor<= containerHeight))
                    {
                        bestFitScalingFactor+=percesionValue;
                    }
        
                    //return bestFit bitmap
                    int bestFitHeight=(int) (imageVerticalAspectRatio*bestFitScalingFactor);
                    int bestFitWidth=(int) (imageHorizontalAspectRatio*bestFitScalingFactor);
                    Log.i("scaleDownLargeImageWIthAspectRatio","bestFitScalingFactor: "+bestFitScalingFactor);
                    Log.i("scaleDownLargeImageWIthAspectRatio","bestFitOutPutDimesions(W:H): "+bestFitWidth+":"+bestFitHeight);
                    image=Bitmap.createScaledBitmap(image, bestFitWidth,bestFitHeight, true);
        
                    //Position the bitmap centre of the container
                    int leftPadding=(containerWidth-image.getWidth())/2;
                    int topPadding=(containerHeight-image.getHeight())/2;
                    Bitmap backDrop=Bitmap.createBitmap(containerWidth, containerHeight, Bitmap.Config.RGB_565);
                    Canvas can = new Canvas(backDrop);
                    can.drawBitmap(image, leftPadding, topPadding, null);
        
                    return backDrop;
                }
    

    【讨论】:

      【解决方案4】:

      https://developer.android.com/reference/android/graphics/Bitmap.html#createScaledBitmap(android.graphics.Bitmap, int, int, boolean)

      并确保dstWidthdstHeight 都是从src.getWidth()*scalesrc.getHeight()*scale 获得的,其中scale 是您需要确定的值,以确保缩放位图适合512x128。

      【讨论】:

      • createScaledBitmap 不能解决我的问题。这就是我已经使用的。在示例中,最后一张图像已按这种方式缩放。
      • 如果您已经有一个按比例缩小的位图(在您的示例中宽度小于 512 或高度小于 128),只需将 GridView 项目的 ImageView 中的这些属性设置为 android:layout_width="512dp"和 android:layout_height="128dp" 和 android:scaleType="center" 或 android:scaleType="centerInside"
      • 根据我的解释,示例中的最后一张图片已经按比例缩小了,所以它已经是最大的了。 128 像素高。尽管如此,图像视图显示它比其他图像更大。另外我不想要一个 512x128dp 网格的图像视图。
      • 在您的屏幕截图中,对于 3 张图像的最后/底行:最后一张更大(更高)。您是想让前两个更高(与最后一个匹配)还是让最后一个不那么高(与前两个匹配)?
      • 如果您希望所有 GridView 项目具有相同的高度,请将 ImageView 的 layout_height 设置为 128dp(或任何其他固定值),并将 layout_width 设置为 wrap_content。将 scaleType 设置为 fitEnd、fitStart、fitXY 或 fitCenter。
      【解决方案5】:

      我认为@Coen 的答案不是这个问题的正确解决方案。我也需要这样的方法,但我想对图像进行平方。

      这是我的方形图像解决方案;

      public static Bitmap resizeBitmapImageForFitSquare(Bitmap image, int maxResolution) {
      
          if (maxResolution <= 0)
              return image;
      
          int width = image.getWidth();
          int height = image.getHeight();
          float ratio = (width >= height) ? (float)maxResolution/width :(float)maxResolution/height;
      
          int finalWidth = (int) ((float)width * ratio);
          int finalHeight = (int) ((float)height * ratio);
      
          image = Bitmap.createScaledBitmap(image, finalWidth, finalHeight, true);
      
          if (image.getWidth() == image.getHeight())
              return image;
          else {
              //fit height and width
              int left = 0;
              int top = 0;
      
              if(image.getWidth() != maxResolution)
                  left = (maxResolution - image.getWidth()) / 2;
      
              if(image.getHeight() != maxResolution)
                  top = (maxResolution - image.getHeight()) / 2;
      
              Bitmap bitmap = Bitmap.createBitmap(maxResolution, maxResolution, Bitmap.Config.ARGB_8888);
              Canvas canvas = new Canvas(bitmap);
              canvas.drawBitmap(image, left, top, null);
              canvas.save();
              canvas.restore();
      
              return  bitmap;
          }
      }
      

      【讨论】:

      • 最大分辨率是多少?
      猜你喜欢
      • 1970-01-01
      • 2014-06-15
      • 2013-05-07
      • 2012-01-03
      • 2017-08-10
      • 2019-05-14
      • 2014-09-17
      • 2013-06-26
      相关资源
      最近更新 更多