7

I have made a Watch Face for Android Wear.
But the problem is image scaling. Images for background, markers and gadgets are of reduced quality when I resize them.

For example, I put 480x480 background image in drawable-nodpi folder (I have tried other dpi as well), and I rescale it like this:

BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = true;
Bitmap bgImage = BitmapFactory.decodeResource(context.getResources(), R.drawable.ticks_1, options);
bgImage = Bitmap.createScaledBitmap(bgImage , width, height, false);

Here are the images:

background enter image description here

and this is what I get on the watch:

screenshot

Am I doing something wrong with resizing or what?

filipst
  • 1,547
  • 1
  • 30
  • 55

4 Answers4

10

I have found a solution here and it works great.
Here is the part of the code for scaling the image:

public Bitmap getResizedBitmap(Bitmap bitmap, int newWidth, int newHeight) {
        Bitmap resizedBitmap = Bitmap.createBitmap(newWidth, newHeight, Bitmap.Config.ARGB_8888);

        float scaleX = newWidth / (float) bitmap.getWidth();
        float scaleY = newHeight / (float) bitmap.getHeight();
        float pivotX = 0;
        float pivotY = 0;

        Matrix scaleMatrix = new Matrix();
        scaleMatrix.setScale(scaleX, scaleY, pivotX, pivotY);

        Canvas canvas = new Canvas(resizedBitmap);
        canvas.setMatrix(scaleMatrix);
        canvas.drawBitmap(bitmap, 0, 0, new Paint(Paint.FILTER_BITMAP_FLAG));

        return resizedBitmap;
    }
filipst
  • 1,547
  • 1
  • 30
  • 55
2

A few comments on the below code. The options section of your decoding doesn't do anything, as no sample size is set. So it can be removed.

// BitmapFactory.Options options = new BitmapFactory.Options();
// options.inScaled = true;
// Bitmap bgImage = BitmapFactory.decodeResource(context.getResources(), R.drawable.ticks_1, options);
Bitmap bgImage = BitmapFactory.decodeResource(context.getResources(), R.drawable.ticks_1);
bgImage = Bitmap.createScaledBitmap(bgImage , width, height, false);

I think the issue with your image distortion, is in-fact the image itself. When you resize is down to 75%. It is just unable to resize it while keeping the image looking exactly the same. the bands are so thin that any slight off is causing to appear different.

I suggest trying it with thicker rings. And see if the image is distorted or not. Even just as a quick test, or permanent solution.

update:

To expand on keeping images crisp clear at all resolutions, look into VECTOR images. These are pixel perfect at all resolutions, and would present fantastic graphics on all watches. Especially, since you are using basic shapes, it should be easy to achieve.

If you are resizing bitmaps, you can expect blur as the image is redrawn. If it must be a bitmap, include multiple resolutions in the different dpi folders so that android selects accordingly, the best match for resizing.

IAmGroot
  • 13,760
  • 18
  • 84
  • 154
  • I had an image with just one black circle on it, and again I got bad quality. I don't get it how are other people making the faces with lots of graphics in them. – filipst Aug 30 '16 at 14:25
  • @filipst See edit. If you are wanting to have good quality you should be using vector images for basic shape geometric. I thought your question had been aimed at how the image had distorted from lack of quality, rather than sharpness. [Some Info here](https://developer.android.com/training/material/drawables.html) – IAmGroot Aug 30 '16 at 14:48
  • I will try that. But do you think watch like this for example is drawn programmatically? https://play.google.com/store/apps/details?id=com.denite.watchface.blackmetal – filipst Aug 30 '16 at 14:53
  • @filipst it looks more like 9 patch and drawables. Plus correct DPI images. I would not refer to vector images as programmatically. Although coordinates are specified for how its drawn, it is much more versatile. – IAmGroot Aug 30 '16 at 15:51
1

Change

bgImage = Bitmap.createScaledBitmap(bgImage , width, height, false);

to

bgImage = Bitmap.createScaledBitmap(bgImage , width, height, true);

This will apply simple bilinear interpolation. Result will be a bit blurry image as circles are so thin, but there will be more information used to create scaled image. Resulted image will also have some moire-pattern, but will be less distorted than in your example picture. If you downscale image in Photoshop using Bicubic filtering, you will get the best results, but even then using vector graphics will outperform any bitmap-based efforts like Doomsknight suggested.

Virne
  • 1,205
  • 11
  • 11
-1

Above Accepted cuts the bitmap try my answer

  public Bitmap getResizedBitmap(Bitmap bitmap, int newWidth, int newHeight) {
             Bitmap scaledBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), bitmap.getConfig());

    float scaleX = newWidth / (float) bitmap.getWidth();
    float scaleY = newHeight / (float) bitmap.getHeight();
    float pivotX = 0;
    float pivotY = 0;

    Matrix scaleMatrix = new Matrix();
    scaleMatrix.setScale(scaleX, scaleY, pivotX, pivotY);

    Canvas canvas = new Canvas(resizedBitmap);
    canvas.setMatrix(scaleMatrix);
    canvas.drawBitmap(bitmap, 0, 0, new Paint(Paint.FILTER_BITMAP_FLAG));

    return resizedBitmap;
}
Vinesh Chauhan
  • 1,288
  • 11
  • 27