android L Palette 實現原理,androidpalette
有時候,看到一些介面上的色彩,心情可能會很舒暢,有時候,看到一些其他色彩,就覺得很討厭,不爽,看到android L Palette 從圖片中提取篩選出來的顏色,覺得都挺好看的,就去瞭解了下Palette調色盤。
看了代碼,根據我的理解,大概說說主要的步驟:
第一步,將圖片縮小,再整個過程中,可以降低計算量和減少記憶體的使用,跟不縮小也能達到一樣的效果
/** * Scale the bitmap down so that it's smallest dimension is * {@value #CALCULATE_BITMAP_MIN_DIMENSION}px. If {@code bitmap} is smaller than this, than it * is returned. */ private static Bitmap scaleBitmapDown(Bitmap bitmap) { final int minDimension = Math.min(bitmap.getWidth(), bitmap.getHeight()); if (minDimension <= CALCULATE_BITMAP_MIN_DIMENSION) { // If the bitmap is small enough already, just return it return bitmap; } final float scaleRatio = CALCULATE_BITMAP_MIN_DIMENSION / (float) minDimension; return Bitmap.createScaledBitmap(bitmap, Math.round(bitmap.getWidth() * scaleRatio), Math.round(bitmap.getHeight() * scaleRatio), false); }
第二步,將縮小後的圖片資料,放在一個int 數組裡
/** * Factory-method to generate a {@link ColorCutQuantizer} from a {@link Bitmap} object. * * @param bitmap Bitmap to extract the pixel data from * @param maxColors The maximum number of colors that should be in the result palette. */ static ColorCutQuantizer fromBitmap(Bitmap bitmap, int maxColors) { final int width = bitmap.getWidth(); final int height = bitmap.getHeight(); final int[] pixels = new int[width * height]; bitmap.getPixels(pixels, 0, width, 0, 0, width, height); return new ColorCutQuantizer(new ColorHistogram(pixels), maxColors); }
第三步,將這個int 數組由小到大排序,就相當於,將一張圖片一樣的顏色堆在一起,然後計算共有多少種顏色,每種顏色它是多大,這些是在一個叫ColorHistogram(顏色長條圖)類裡面計算的,用顏色長條圖來說,就是共有多少柱顏色,每柱顏色有多高
/** * Class which provides a histogram for RGB values. */final class ColorHistogram { private final int[] mColors; private final int[] mColorCounts; private final int mNumberColors; /** * A new {@link ColorHistogram} instance. * * @param pixels array of image contents */ ColorHistogram(final int[] pixels) { // Sort the pixels to enable counting below Arrays.sort(pixels); // Count number of distinct colors mNumberColors = countDistinctColors(pixels); // Create arrays mColors = new int[mNumberColors]; mColorCounts = new int[mNumberColors]; // Finally count the frequency of each color countFrequencies(pixels); } /** * @return 擷取共用多少柱不同顏色 number of distinct colors in the image. */ int getNumberOfColors() { return mNumberColors; } /** * @return 擷取排好序後的不同顏色的數組 an array containing all of the distinct colors in the image. */ int[] getColors() { return mColors; } /** * @return 擷取儲存每一柱有多高的數組 an array containing the frequency of a distinct colors within the image. */ int[] getColorCounts() { return mColorCounts; } //計算共用多少柱不同顏色 private static int countDistinctColors(final int[] pixels) { if (pixels.length < 2) { // If we have less than 2 pixels we can stop here return pixels.length; } // If we have at least 2 pixels, we have a minimum of 1 color... int colorCount = 1; int currentColor = pixels[0]; // Now iterate from the second pixel to the end, counting distinct colors for (int i = 1; i < pixels.length; i++) { // If we encounter a new color, increase the population if (pixels[i] != currentColor) { currentColor = pixels[i]; colorCount++; } } return colorCount; } //計算每一柱有多高 private void countFrequencies(final int[] pixels) { if (pixels.length == 0) { return; } int currentColorIndex = 0; int currentColor = pixels[0]; mColors[currentColorIndex] = currentColor; mColorCounts[currentColorIndex] = 1; Log.i("pixels.length",""+ pixels.length); if (pixels.length == 1) { // If we only have one pixel, we can stop here return; } // Now iterate from the second pixel to the end, population distinct colors for (int i = 1; i < pixels.length; i++) { if (pixels[i] == currentColor) { // We've hit the same color as before, increase population mColorCounts[currentColorIndex]++; } else { // We've hit a new color, increase index currentColor = pixels[i]; currentColorIndex++; mColors[currentColorIndex] = currentColor; mColorCounts[currentColorIndex] = 1; } } }}
第四步,將各種顏色,根據RGB轉HSL演算法,得出對應的HSL(H: Hue 色相,S:Saturation 飽和度L Lightness 明度),根據特定的條件,比如是明度L是否接近白色,黑色,還有一個判斷叫isNearRedILine,解釋是@return true if the color lies close to the red side of the I line(接近紅色私密地區附近?).,然後根據這三個條件,過濾掉這些顏色,什麼是HSL和RGB轉HSL演算法可以查看下百科,比較有詳細說明
/** * Private constructor. * * @param colorHistogram histogram representing an image's pixel data * @param maxColors The maximum number of colors that should be in the result palette. */ private ColorCutQuantizer(ColorHistogram colorHistogram, int maxColors) { final int rawColorCount = colorHistogram.getNumberOfColors(); final int[] rawColors = colorHistogram.getColors();//顏色數組 final int[] rawColorCounts = colorHistogram.getColorCounts();//對應rawColors每一個顏色數組的大小 // First, lets pack the populations into a SparseIntArray so that they can be easily // retrieved without knowing a color's index mColorPopulations = new SparseIntArray(rawColorCount); for (int i = 0; i < rawColors.length; i++) { mColorPopulations.append(rawColors[i], rawColorCounts[i]); } // Now go through all of the colors and keep those which we do not want to ignore mColors = new int[rawColorCount]; int validColorCount = 0; for (int color : rawColors) { if (!shouldIgnoreColor(color)) { mColors[validColorCount++] = color; } } Log.d("mColors length", ""+mColors.length); if (validColorCount <= maxColors) { // The image has fewer colors than the maximum requested, so just return the colors mQuantizedColors = new ArrayList<Swatch>(); for (final int color : mColors) { mQuantizedColors.add(new Swatch(color, mColorPopulations.get(color))); } } else { // We need use quantization to reduce the number of colors mQuantizedColors = quantizePixels(validColorCount - 1, maxColors); } }
<span style="font-weight: bold;"></span>
<span style="font-weight: bold;">這裡截了張圖看看</span>
<img src="http://img.blog.csdn.net/20150129001750011" alt="" style="font-weight: bold;" />
第五步,根據是各種亮度,飽和度的取值範圍,比如有活力的暗色,有活力的亮色,柔和的顏色,柔和的暗色,柔和的亮色,找到對應的顏色
private Swatch findColor(float targetLuma, float minLuma, float maxLuma, float targetSaturation, float minSaturation, float maxSaturation) { Swatch max = null; float maxValue = 0f; for (Swatch swatch : mSwatches) { final float sat = swatch.getHsl()[1]; final float luma = swatch.getHsl()[2]; if (sat >= minSaturation && sat <= maxSaturation && luma >= minLuma && luma <= maxLuma && !isAlreadySelected(swatch)) { float thisValue = createComparisonValue(sat, targetSaturation, luma, targetLuma, swatch.getPopulation(), mHighestPopulation); if (max == null || thisValue > maxValue) { max = swatch; maxValue = thisValue; } } } return max; }
看下
完整代碼下載(相容低版本,外送用viewpager實現“無限迴圈”和ImageView的複用年終礼包)
歡迎轉載,但請說明出處http://blog.csdn.net/yebo0505/article/details/43234113