summaryrefslogtreecommitdiff
path: root/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/BitmapUtils.java
blob: 3570aa2c0b94f94221d6f6064c9346725c62f0b2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
package com.mapbox.mapboxsdk.utils;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.PorterDuff;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.support.annotation.ColorInt;
import android.support.annotation.DrawableRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
import android.view.View;

import java.io.ByteArrayOutputStream;
import java.nio.ByteBuffer;
import java.util.Arrays;

/**
 * Utility class for creating bitmaps
 */
public class BitmapUtils {

  /**
   * Convert a view to a bitmap.
   *
   * @param view the view to convert
   * @return the converted bitmap
   */
  public static Bitmap createBitmapFromView(@NonNull View view) {
    view.setDrawingCacheEnabled(true);
    view.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_LOW);
    view.buildDrawingCache();

    if (view.getDrawingCache() == null) {
      return null;
    }

    Bitmap snapshot = Bitmap.createBitmap(view.getDrawingCache());
    view.setDrawingCacheEnabled(false);
    view.destroyDrawingCache();
    return snapshot;
  }

  /**
   * Create a bitmap from a background and a foreground bitmap
   *
   * @param background The bitmap placed in the background
   * @param foreground The bitmap placed in the foreground
   * @return the merged bitmap
   */
  public static Bitmap mergeBitmap(@NonNull Bitmap background, @NonNull Bitmap foreground) {
    Bitmap result = Bitmap.createBitmap(background.getWidth(), background.getHeight(), background.getConfig());
    Canvas canvas = new Canvas(result);
    canvas.drawBitmap(background, 0f, 0f, null);
    canvas.drawBitmap(foreground, 10, 10, null);
    return result;
  }

  /**
   * Extract an underlying bitmap from a drawable
   *
   * @param sourceDrawable The source drawable
   * @return The underlying bitmap
   */
  @Nullable
  public static Bitmap getBitmapFromDrawable(@Nullable Drawable sourceDrawable) {
    if (sourceDrawable == null) {
      return null;
    }

    if (sourceDrawable instanceof BitmapDrawable) {
      return ((BitmapDrawable) sourceDrawable).getBitmap();
    } else {
      //copying drawable object to not manipulate on the same reference
      Drawable.ConstantState constantState = sourceDrawable.getConstantState();
      if (constantState == null) {
        return null;
      }
      Drawable drawable = constantState.newDrawable().mutate();

      Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(),
        Bitmap.Config.ARGB_8888);
      Canvas canvas = new Canvas(bitmap);
      drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
      drawable.draw(canvas);
      return bitmap;
    }
  }

  /**
   * Create a byte array out of drawable
   *
   * @param drawable The source drawable
   * @return The byte array of source drawable
   */
  @Nullable
  public static byte[] getByteArrayFromDrawable(@Nullable Drawable drawable) {
    if (drawable == null) {
      return null;
    }

    Bitmap bitmap = getBitmapFromDrawable(drawable);
    if (bitmap == null) {
      return null;
    }
    ByteArrayOutputStream stream = new ByteArrayOutputStream();
    bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
    return stream.toByteArray();
  }

  /**
   * Decode byte array to drawable object
   *
   * @param context Context to obtain {@link android.content.res.Resources}
   * @param array   The source byte array
   * @return The drawable created from source byte array
   */
  @Nullable
  public static Drawable getDrawableFromByteArray(@NonNull Context context, @Nullable byte[] array) {
    if (array == null) {
      return null;
    }
    Bitmap compass = BitmapFactory.decodeByteArray(array, 0, array.length);
    return new BitmapDrawable(context.getResources(), compass);
  }

  /**
   * Get a drawable from a resource.
   *
   * @param context     Context to obtain {@link android.content.res.Resources}
   * @param drawableRes Drawable resource
   * @return The drawable created from the resource
   */
  @Nullable
  public static Drawable getDrawableFromRes(@NonNull Context context, @DrawableRes int drawableRes) {
    return getDrawableFromRes(context, drawableRes, null);
  }

  /**
   * Get a tinted drawable from a resource.
   *
   * @param context     Context to obtain {@link android.content.res.Resources}
   * @param drawableRes Drawable resource
   * @param tintColor   Tint color
   * @return The drawable created from the resource
   */
  @Nullable
  public static Drawable getDrawableFromRes(@NonNull Context context, @DrawableRes int drawableRes,
                                            @Nullable @ColorInt Integer tintColor) {
    Drawable drawable = context.getResources().getDrawable(drawableRes);
    if (drawable == null) {
      return null;
    }

    if (tintColor == null) {
      return drawable;
    }

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
      drawable.setTint(tintColor);
    } else {
      drawable.mutate().setColorFilter(tintColor, PorterDuff.Mode.SRC_IN);
    }
    return drawable;
  }

  /**
   * Validates if the bytes of a bitmap matches another
   *
   * @param bitmap the bitmap to be compared against
   * @param other  the bitmap to compare with
   * @return true if equal
   */
  @VisibleForTesting
  public static boolean equals(Bitmap bitmap, Bitmap other) {
    ByteBuffer buffer = ByteBuffer.allocate(bitmap.getHeight() * bitmap.getRowBytes());
    bitmap.copyPixelsToBuffer(buffer);

    ByteBuffer bufferOther = ByteBuffer.allocate(other.getHeight() * other.getRowBytes());
    other.copyPixelsToBuffer(bufferOther);

    return Arrays.equals(buffer.array(), bufferOther.array());
  }

}