如何缩放图像而不模糊?

发布于 2024-10-29 22:11:27 字数 920 浏览 0 评论 0原文

我正在尝试将一个小图像(例如 20x40 像素)缩放为任意大的图像。我通过设置 ImageView.scaleType 属性来进行缩放,但是当它确实缩放图像时,它会从一种原始像素颜色淡入下一种颜色,从而创建一个大的模糊版本的图像。

这是这个问题的一些背景。我正在尝试为 Android 创建一款老式 16 位风格游戏。我想将精灵/等存储为小文件,然后根据用户的屏幕尺寸将它们放大。这样,我就不必为每个精灵创建大量不同尺寸的不同图像。现在我正在研究概念验证,因此我正在尝试将一个微小的 20x40 图像文件缩放到整个屏幕的大小。

*编辑:我想出了如何使用 Reflog 推荐的方法。然而,它仍然会产生一些衰落,只是远小于默认算法。

*编辑2:明白了!我必须关闭抗锯齿功能

*edit3:这对我来说神秘地停止了工作,我发现了另一个需要禁用抖动/自动缩放的地方。添加了选项行。

@Override
protected void onDraw(Canvas canvas) {
    Paint paint = new Paint();
    paint.setDither(false);
    paint.setAntiAlias(false);

    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inDither = false;
    options.inScaled = false;

    Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.tinyimg, options);
    canvas.drawBitmap(bitmap, null, new RectF(getLeft(), getTop(), getRight()/2, getBottom()/2), paint);
}

I'm trying to scale a tiny image (something like 20x40 pixels) to an arbitrarily large image. I'm doing the scaling by setting the ImageView.scaleType property, but while it does scale the image, it fades from one original pixel color to the next, creating a large blurry version of the image.

Here's some context for the question. I'm trying to create an old school 16-bit style game for Android. I want to store the sprites/etc as tiny files, and then scale them larger depending on the user's screen size. That way, I don't have to create a ton of different images at different sizes for each sprite. Right now I'm just working on a proof of concept, so I'm trying to scale a tiny 20x40 image file to the size of the entire screen.

*edit: I figured out how to use the method Reflog recommended. However, it still does some fading, just far less than the default algorithm.

*edit2: Got it! I had to turn anti-aliasing off

*edit3: This mysteriously stopped working for me, and I found another place where dithering/auto scaling needed to be disabled. Added the options lines.

@Override
protected void onDraw(Canvas canvas) {
    Paint paint = new Paint();
    paint.setDither(false);
    paint.setAntiAlias(false);

    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inDither = false;
    options.inScaled = false;

    Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.tinyimg, options);
    canvas.drawBitmap(bitmap, null, new RectF(getLeft(), getTop(), getRight()/2, getBottom()/2), paint);
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

星星的軌跡 2024-11-05 22:11:27

使用:

paint.setDither(false);
g.drawBitmap(img, src, dst, paint);

使用NN缩放,这会减少模糊,但也会降低缩放的质量。

Use:

paint.setDither(false);
g.drawBitmap(img, src, dst, paint);

to use NN scaling, this will reduce blurring, but also will reduce the quality of the scaling.

海风掠过北极光 2024-11-05 22:11:27

也许这段代码可以帮助您:

/**
 * @param bitmap Bitmap original
 * @param finWid width of the new Bitmap (width of the cut)
 * @param finHei height of the new Bitmap (height of the cut)
 * @param angulo angle of rotation in degrees
 * @param sx scale X
 * @param sy scale Y
 * @param tx Translate X
 * @param ty Translate Y
 * @param config {@link Config} of the new Bitmap
 * @return {@link Bitmap} transformed
 */
public Bitmap createTransPixBitmap(Bitmap bitmap, int finWid, int finHei, float  angulo, float sx, float sy, float tx, float ty, Config config){

    return Bitmap.createBitmap(createTransPixArray(bitmap, bitmap.getWidth(), bitmap.getHeight(), finWid, finHei, angulo, sx, sy, tx, ty), finWid, finHei, config);

}

public int[] createTransPixArray(Bitmap bitmap, int width, int height, int finWid, int finHei, float angulo, float sx, float sy, float tx, float ty){

    float scaWid = width*sx;
    float scaHei = height*sy;

    int[] ori = new int[width*height];
    bitmap.getPixels(ori, 0, width, 0, 0, width, height);

    bitmap.recycle();
    bitmap = null;
    System.gc();

    return transformPix(ori, width, height, scaWid, scaHei, finWid, finHei, angulo, tx, ty);
}

/**
 * Core function for apply scale, translate and rotation (cut the image if you want too)
 * @param ori original color array
 * @param wid original width
 * @param hei original height
 * @param scaWid scaled original width
 * @param scaHei scaled original height
 * @param finWid width of the new Bitmap
 * @param finHei height of the new Bitmap
 * @param angulo rotation in degrees
 * @param tx Translate X
 * @param ty Translate Y
 * @return int[] of colors
 */
private int[] transformPix(int[] ori, int wid, int hei, float scaWid, float scaHei, int finWid, int finHei, float angulo, float tx, float ty){

    int[] fin = new int[finWid*finHei];

    double sin = Math.sin(Math.toRadians(angulo));
    double cos = Math.cos(Math.toRadians(angulo));

    int dx = (int)((scaWid-finWid)/2);
    int dy = (int)((scaHei-finHei)/2);

    /* No se como explicar esto, solo puedo decir que el proceso de escalado es en sentido inverso
     * escala, rota, translada y corta, todo al mismo tiempo :D
     */
    for(int y = 0; y < finHei; y++){
        for(int x = 0; x < finWid; x++){
            int tempX = (int)Math.floor(((x+dx-((float)scaWid/2))*((float)wid/scaWid))+0.5f-tx);
            int tempY = (int)Math.floor(((y+dy-((float)scaHei/2))*((float)hei/scaHei))+0.5f-ty);

            int tempRX = (int)Math.floor(((cos*(float)tempX)+(sin*(float)tempY))+0.5f+((float)wid/2));
            int tempRY = (int)Math.floor(((cos*(float)tempY)-(sin*(float)tempX))+0.5f+((float)hei/2));

            if((tempRX >= 0 && tempRX < wid) && (tempRY >= 0 && tempRY < hei))
                fin[x+(y*finWid)] = ori[tempRX+(tempRY*wid)];   
        }
    }

    ori = null;
    return fin;
}

此函数只是缩放颜色数组(如果您不需要额外的功能):

private int[] scale(int[] ori, int wid, int hei, int finWid, int finHei){

    int[] fin = new int[finWid*finHei];

    for(int y = 0; y < finHei; y++){
        for(int x = 0; x < finWid; x++){
            int temp = (int)(x*(wid/finWid))+((int)(y*(hei/finHei))*wid);
            fin[x+(y*finWid)] = ori[temp];
        }
    }

    return fin;
}

我希望这很有用,并且我很乐意感谢一些改进此代码的建议。

Maybe this code can help you:

/**
 * @param bitmap Bitmap original
 * @param finWid width of the new Bitmap (width of the cut)
 * @param finHei height of the new Bitmap (height of the cut)
 * @param angulo angle of rotation in degrees
 * @param sx scale X
 * @param sy scale Y
 * @param tx Translate X
 * @param ty Translate Y
 * @param config {@link Config} of the new Bitmap
 * @return {@link Bitmap} transformed
 */
public Bitmap createTransPixBitmap(Bitmap bitmap, int finWid, int finHei, float  angulo, float sx, float sy, float tx, float ty, Config config){

    return Bitmap.createBitmap(createTransPixArray(bitmap, bitmap.getWidth(), bitmap.getHeight(), finWid, finHei, angulo, sx, sy, tx, ty), finWid, finHei, config);

}

public int[] createTransPixArray(Bitmap bitmap, int width, int height, int finWid, int finHei, float angulo, float sx, float sy, float tx, float ty){

    float scaWid = width*sx;
    float scaHei = height*sy;

    int[] ori = new int[width*height];
    bitmap.getPixels(ori, 0, width, 0, 0, width, height);

    bitmap.recycle();
    bitmap = null;
    System.gc();

    return transformPix(ori, width, height, scaWid, scaHei, finWid, finHei, angulo, tx, ty);
}

/**
 * Core function for apply scale, translate and rotation (cut the image if you want too)
 * @param ori original color array
 * @param wid original width
 * @param hei original height
 * @param scaWid scaled original width
 * @param scaHei scaled original height
 * @param finWid width of the new Bitmap
 * @param finHei height of the new Bitmap
 * @param angulo rotation in degrees
 * @param tx Translate X
 * @param ty Translate Y
 * @return int[] of colors
 */
private int[] transformPix(int[] ori, int wid, int hei, float scaWid, float scaHei, int finWid, int finHei, float angulo, float tx, float ty){

    int[] fin = new int[finWid*finHei];

    double sin = Math.sin(Math.toRadians(angulo));
    double cos = Math.cos(Math.toRadians(angulo));

    int dx = (int)((scaWid-finWid)/2);
    int dy = (int)((scaHei-finHei)/2);

    /* No se como explicar esto, solo puedo decir que el proceso de escalado es en sentido inverso
     * escala, rota, translada y corta, todo al mismo tiempo :D
     */
    for(int y = 0; y < finHei; y++){
        for(int x = 0; x < finWid; x++){
            int tempX = (int)Math.floor(((x+dx-((float)scaWid/2))*((float)wid/scaWid))+0.5f-tx);
            int tempY = (int)Math.floor(((y+dy-((float)scaHei/2))*((float)hei/scaHei))+0.5f-ty);

            int tempRX = (int)Math.floor(((cos*(float)tempX)+(sin*(float)tempY))+0.5f+((float)wid/2));
            int tempRY = (int)Math.floor(((cos*(float)tempY)-(sin*(float)tempX))+0.5f+((float)hei/2));

            if((tempRX >= 0 && tempRX < wid) && (tempRY >= 0 && tempRY < hei))
                fin[x+(y*finWid)] = ori[tempRX+(tempRY*wid)];   
        }
    }

    ori = null;
    return fin;
}

This function just scale the color array (if you don't want the extra features):

private int[] scale(int[] ori, int wid, int hei, int finWid, int finHei){

    int[] fin = new int[finWid*finHei];

    for(int y = 0; y < finHei; y++){
        for(int x = 0; x < finWid; x++){
            int temp = (int)(x*(wid/finWid))+((int)(y*(hei/finHei))*wid);
            fin[x+(y*finWid)] = ori[temp];
        }
    }

    return fin;
}

I hope this is useful, and I gladly would appreciate some advice for improving this code.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文