編輯:關於Android編程
一、需求:launcher上的圖標統一改成矩形,如下圖所示;
二、實現方案
主要采用openCV來實現圖片的一些識別和判斷,本人在做這個需求之前從來沒有接觸過Z喎?/kf/ware/vc/" target="_blank" class="keylink">vcGVuQ1ajrNK7x9C2vMrHz9bRp8/W08OjrLbUzbzP8bSmwO21xNK70Km8vMr1us3L47eo0rLBy73itcSyu7bgo6y/xL/EsO2w7dfcy+PX9rP2wLS1xNCnufu/ydLUv7S/tKGj19TWqrT6wuvQtLXEuty1zby2o6y1q8rHttTNvM/xtKbA7dXit73D5rXEtqvO97u5ysfNptPQ0MvIpLXEoaPPo837tsHV38W8yLu/tLW9v8nS1L7NzsTW0LXE0rvQqbK71+PWrrSm1ri149K7tv6jrLK7ssXU2rTLz8jQu7n9wcujoTwvcD4NCjxwPsTasr/TptPDus1NSUXTptPDo6zS1Lyw1tC5+sf4ytCzocnPtcR0b3AxMDC1xNOm08O1xM28serTyVVFzOG5qdSk1sPU2mxhdW5jaGVy1tDM5ru7oaM8L3A+DQo8cD7G5Mv7zrTUpNbGzbyx6rXE06bTw828seqjrLC01dXG5M28seq1xMzY1fejrNPJtPrC67340NC0psDto6y0psDtt73KvbfWyOfPwsj91tajujwvcD4NCjxwPjIuMSDUrc28seq089ChzqrV/be90M7H0rv5sb6907381f2zo828seq089ChtcSjrLLpv7TQws28serKx7fxzqrW0NDEvdjUsrKivNOw18mrsbOw5aGj0Ke5+8jnz8LNvMv5yr46PGJyIC8+DQo8aW1nIGFsdD0="這裡寫圖片描述" src="/uploadfile/Collfiles/20160518/20160518091340377.png" title="\" />
原圖1
截圓加白背板圖1
原本這類圖標會再細分為兩類分別做處理。
一類為背板顏色較單一的,如google, BBC News,因為把圖標放在矩形區域中時,可能會露出空白的部分,比如如果原圖標圓角弧度較大的,所以當時有兩種方案,一種是摳圖,即摳出圖片中心的特征點,比如google圖標中心的”g”, BBC News中間的“BBC NEWS“字樣,並畫出一個矩形圓角形狀,取出背板的顏色作為矩形的填充色,兩者組合在一起形成新的圖標。另一種技術方案是將背板顏色做延伸,填充矩形區域去截取原圖標後可能露出的空白處。摳圖的方案可以由openCV的Imgproc.grabCut(mat, mask, rect, bgdModel, fgdModel, 1, Imgproc.GC_INIT_WITH_RECT)方法來實現,但是准確度欠缺,不知道是否我用的不對。背板顏色延伸的方案有難度,後來項目就進度考慮未深度研究下去。總之這類圖標的處理沒有實現。
另一類圖標是背板顏色五顏六色,也可以說沒有主要的圖標特征。比如Angry Birds, European War。因為不管摳圖還是背板顏色延伸的方案都不可能,所以這類圖標截取中心圓加白色白板。最終UE提供的圖片是中心透明的,所以在處理上只需要將原圖標按圖標可見區域的實際大小縮小至一定比例然後再畫上背板圖片即可。
2.2 原圖標大小為不規則形狀(不是正方形,或者大小比正常圖標大小要小(小的程度在代碼中自定義了一個阈值,這個阈值不應該是關注的重點),應該加上取原圖標的主色調做背板顏色並加漸變色效果的一個背板。如下圖所示:
原圖2
截圓加白背板圖2
2.3 原圖標為矩形,且長寬比和要求的圖標長寬比相近,應該只對圖標進行適當縮放並加圓角處理。該效果基本保持和原圖一致,除大小稍做調整並且明顯的直角會稍做圓角處理。效果如下圖所示:
原圖3
截圓加白背板圖3
三、技術要點
1. 判斷是否有預制圖標並替換。
在原調用Utilities.createIconBitmap的地方,先做預置圖標的判斷,如IconChache的
CacheLocked((ComponentName componentName,....)方法:
if (!getEntryFromDB(componentName, user, entry, useLowResIcon)) {
if (info != null) {
// entry.icon = Utilities.createIconBitmap(info.getBadgedIcon(mIconDpi), mContext);
if(CustomUtil.sWhetherUseRectangleIcon) {
// {@ icon replace start@}
Drawable icon = Utilities.findPrePlacedIconResource(componentName, mContext);
if (icon != null) {
entry.icon = Utilities.createIconBitmap(icon, mContext);
} else {
if(Utilities.sRectangleIconDEBUG){
Log.d(Utilities.sRectangleIcon,"packageName: "+info.getLabel() + " START<<<<<<<<<<<<<<<<<<<<<");
}
entry.icon = Utilities.createRectangleIconBitmap(info.getBadgedIcon(mIconDpi), mContext);
if(Utilities.sRectangleIconDEBUG){
Log.d(Utilities.sRectangleIcon,"packageName: "+info.getLabel() + " END>>>>>>>>>>>>>>>>>>>>>>>");
}
}
// {@ icon replace end@}
} else {
entry.icon = Utilities.createIconBitmap(info.getBadgedIcon(mIconDpi), mContext);
}
} else {
public static Drawable findPrePlacedIconResource(ComponentName componentName, Context context){
Drawable icon = null;
if (componentName != null && !TextUtils.isEmpty(componentName.getPackageName())
&& !TextUtils.isEmpty(componentName.getClassName())) {
String filename = componentName.toString().replace("ComponentInfo{", "");
filename = filename.replace("}", "");
filename = filename.replace("/", "_");
return findPrePlacedIconResource(filename, context);
}
return icon;
}
// public static Drawable findPrePlacedIconResource(String packageName, Context context){
public static Drawable findPrePlacedIconResource(String fileName, Context context) {
Drawable icon = null;
if (!TextUtils.isEmpty(fileName)) {
InputStream is = null;
try {
// String path = "icons";
// String unit = ".png";
// is = getIconsInputStream(is, fileName, path, unit, context);
StringBuilder sb=new StringBuilder();
is = context.getAssets().open(sb.append(REPLACE_ICON_PATH).append(fileName).append(REPLACE_ICON_FORMAT).toString());
if (is != null) {
icon = Drawable.createFromStream(is, null);
TLog.d(TAG,"replace icon by launcher default for APP "+fileName);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
return icon;
}
判斷圖標是否為矩形且長寬比是否和要求的長寬比
//找到圖標的最外層輪廓
public static MatOfPoint findFirstContour(Bitmap b){
Mat RGBMat = new Mat();
Mat oriMatCompare = new Mat();
Utils.bitmapToMat(b.copy(Bitmap.Config.ARGB_8888, false), oriMatCompare);
Imgproc.cvtColor(oriMatCompare, RGBMat, Imgproc.COLOR_RGBA2RGB);
Mat grayMatForCompare = new Mat();
Mat mHierarchy = new Mat();
Imgproc.cvtColor(RGBMat, grayMatForCompare, Imgproc.COLOR_RGBA2GRAY);
List contours = new ArrayList();
Imgproc.findContours(grayMatForCompare, contours, mHierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_NONE);
Iterator it = contours.iterator();
MatOfPoint contour = (MatOfPoint) it.next();
org.opencv.core.Point[] contourArray = contour.toArray();
return contour;
}
![圖標的最外層輪廓,其中百度地圖為預置圖標](http://img.blog.csdn.net/20160517165017209)
public static boolean isBitmapNeedtoChange(MatOfPoint contour, MatOfPoint compareContour){
MatOfPoint2f approxContour = new MatOfPoint2f();
MatOfPoint2f mMOP2f1=new MatOfPoint2f();
contour.convertTo(mMOP2f1, CvType.CV_32FC2);
//獲取圖標的近似輪廓
Imgproc.approxPolyDP(mMOP2f1, approxContour, Imgproc.CV_POLY_APPROX_DP, true);
MatOfPoint mMOP2f2 = new MatOfPoint();
//獲取圖標最外層輪廓的最小外界矩形
org.opencv.core.Rect boundingRect = Imgproc.boundingRect(mMOP2f2);
//獲取對比圖標的最外層輪廓的最小外界矩形
//此對比圖標為符合要求的矩形圖標,如圖所示:
org.opencv.core.Rect boundingRectOfCompare = Imgproc.boundingRect(compareContour);
DecimalFormat df = new DecimalFormat("######0.00");
double areaD = (boundingRect.area() - Imgproc.contourArea(approxContour)) / boundingRect.area();
double rate1 = (double)boundingRect.width/(double)boundingRect.height;
double rate2 = (double)boundingRectOfCompare.width/(double)boundingRectOfCompare.height;
if(sRectangleIconDEBUG) {
Log.d(sRectangleIcon, "areaD: " + areaD + ",bound rate:" + rate1 + "== " + df.format(rate1) + ",conpare bounding rate:" + rate2 + "==" + df.format(rate2)+", rate rio:"+Math.abs(rate1 - rate2)/rate2);
}
//比較輪廓的最小外接矩形面積和輪廓內的面積的差值比是否在一定阈值內
//且圖標和其對比圖標的最小外接矩形的寬高比的差值比是否在一定阈值內
//兩個阈值的設定都是通過安裝大量的apk根據視覺效果來定出
if (areaD < 0.1 && Math.abs(rate1 - rate2) / rate2 < 0.05) {
return true;
}
return false;
}
對比圖標
判斷圖標是否應該需要加主色調背板–原圖標為不規則形狀,或者大小比正常大小圖標要小。
public static boolean shouldBitmapAddMainColorBg(Bitmap b, MatOfPoint contour, Context context){
org.opencv.core.Point[] contourArray = contour.toArray();
Mat mat = new Mat();
Utils.bitmapToMat(b.copy(Bitmap.Config.ARGB_8888, false), mat);
int point2Didsance = mat.rows()/4;
org.opencv.core.Point tempPtXMiddle = new org.opencv.core.Point((double) (mat.rows() / 2), (double) 0);
org.opencv.core.Point tempPtYMiddle = new org.opencv.core.Point((double) 0, (double) (mat.cols() / 2));
org.opencv.core.Point tempPtX2 = new org.opencv.core.Point((double) (mat.rows() / 2 + point2Didsance), (double) 0);
org.opencv.core.Point tempPtY2 = new org.opencv.core.Point((double) 0, (double) (mat.cols() / 2 + point2Didsance));
double positionCheckXMiddle = Imgproc.pointPolygonTest(new MatOfPoint2f(contourArray), tempPtXMiddle, true);
double positionCheckYMiddle = Imgproc.pointPolygonTest(new MatOfPoint2f(contourArray), tempPtYMiddle, true);
double positionCheckX2 = Imgproc.pointPolygonTest(new MatOfPoint2f(contourArray), tempPtX2, true);
double positionCheckY2 = Imgproc.pointPolygonTest(new MatOfPoint2f(contourArray), tempPtY2, true);
double distance = context.getResources().getDimensionPixelSize(R.dimen.visible_contour_distance);
if(sRectangleIconDEBUG){
Log.d(sRectangleIcon, "distance:" + distance + ", positionCheckXMiddle:" + positionCheckXMiddle + ",positionCheckYMiddle:" + positionCheckYMiddle + ",positionCheckX5:" + positionCheckX2 + ",positionCheckY5:" + positionCheckY2);
}
//check if the contour is a line
if(((Math.abs(positionCheckX2) != Math.abs(positionCheckXMiddle)) || Math.abs(positionCheckY2) != Math.abs(positionCheckYMiddle)) ? true:
(Math.abs(positionCheckXMiddle) > distance || Math.abs(positionCheckYMiddle) > distance)) {
return true;
}
else
return false;
}
如果滿足條件2,圖標進行適當縮放,並對可見矩形部分做圓角處理。
public static Bitmap bitmapAddRoundCorner(Context context, Bitmap bitmap, MatOfPoint contour, MatOfPoint compareContour, int iconSize){
org.opencv.core.Rect rect = getBitmapBoundingRect(contour);
org.opencv.core.Rect compareRect = Imgproc.boundingRect(compareContour);
float resizeRate = Math.abs((float) rect.height / (float) compareRect.height);
float bitmatZoomedSize = resizeRate * iconSize;
int resizeRectW = (int)(Math.abs(rect.width) * resizeRate);
int resizeRectH = Math.abs(compareRect.height) ;
Bitmap resizeBitmap = zoomBitmap(bitmap, bitmatZoomedSize, bitmatZoomedSize);
// return resizeBitmap;
//Log.d(sRectangleIcon, "bitmatZoomedSize:"+bitmatZoomedSize+",compareRect:"+compareRect+",rect:"+rect);
Bitmap bg = Bitmap.createBitmap(iconSize, iconSize, Bitmap.Config.ARGB_8888);
Canvas canvas1 = new Canvas(bg);
int srcLeft = ((int) bitmatZoomedSize - resizeRectW) / 2;
int srcTop = ((int) bitmatZoomedSize - resizeRectH) / 2;
int dstLeft = (iconSize - resizeRectW) / 2;
int dstTop = (iconSize - resizeRectH) / 2;
Rect src = new Rect(srcLeft, srcTop, resizeRectW + srcLeft, resizeRectH + srcTop);
Rect dst = new Rect(srcLeft, srcTop, resizeRectW + srcLeft, resizeRectH + srcTop);
RectF rectf = new RectF(dst);
Paint photoPaint = new Paint();
photoPaint.setAntiAlias(true);
photoPaint.setDither(true);
//photoPaint.setARGB(100, 255, 0, 0);
int roundPx = context.getResources().getDimensionPixelSize(R.dimen.round_size);
canvas1.drawRoundRect(rectf, roundPx, roundPx, photoPaint);
photoPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas1.drawBitmap(resizeBitmap, src, dst, photoPaint);
canvas1.setBitmap(null);
return bg;
}
如果滿足條件3,則取圖標的主色調作為背板顏色並加漸變色,加圓角矩形背板,並縮小原圖標至一定尺寸組合再一起作為新圖標。
static Bitmap bitmapAddBgUseMainColor(Context context, Bitmap b) {
final float FLAT_ASPECT_RATIO = 0.792f; //According to GD
int iconSize = getIconBitmapSize();
int height = (int) (iconSize * FLAT_ASPECT_RATIO);
//取圖標的六種調色板的顏色
Bitmap bg = FallbackAlgorithm.getProcessedIcon(context, b, new Point(iconSize, height));
//draw blank bg
Drawable bg2 = context.getResources().getDrawable(R.drawable.carving);
Bitmap blankbg = Bitmap.createBitmap(iconSize, iconSize, Bitmap.Config.ARGB_8888);
Canvas canvas2 = new Canvas(blankbg);
bg2.setBounds(0, 0, iconSize, iconSize);
bg2.draw(canvas2);
Paint p2 = new Paint();
p2.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OVER));
canvas2.drawBitmap(bg, 0, (iconSize - bg.getHeight()) / 2, null);
canvas2.setBitmap(null);
return blankbg;
}
其中取背板顏色的類如下:
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.support.v7.graphics.Palette;
import android.util.Log;
import com.tct.launcher.R;
public class FallbackAlgorithm {
private static class RGB {
float r, g, b; // Red, Green and Blue in [0, 1]
RGB() { }
RGB(float r, float g, float b){
this.r = r;
this.g = g;
this.b = b;
}
int getColor(){
return Color.rgb((int) (r * 255), (int) (g * 255), (int) (b * 255));
}
@Override
public String toString(){
return "{ r: " + r + ", g: " + g + ", b: " + b + " }";
}
}
private static class HSL {
float h, s, l; // Hue in [0, 360], Saturation and Lightness in [0, 1]
//HSL() { }
HSL(float h, float s, float l){
this.h = h;
this.s = s;
this.l = l;
}
HSL(float[] hsl){
this.h = hsl[0];
this.s = hsl[1];
this.l = hsl[2];
}
@Override
public String toString(){
return "{ h: " + h + ", s: " + s + ", l: " + l + " }";
}
}
private static float hue2rgb(float p, float q, float t){
if (t < 0f) t += 1f;
if (t > 1f) t -= 1f;
if (t < 1f/6f) return p + (q - p) * 6f * t;
if (t < 1f/2f) return q;
if (t < 2f/3f) return p + (q - p) * (2f/3f - t) * 6f;
return p;
}
private static void hsl2rgb(HSL hsl, RGB rgb){
if (hsl.s == 0){
rgb.r = rgb.g = rgb.b = hsl.l; // achromatic
}
else {
float q = hsl.l < 0.5f ? hsl.l * (1f + hsl.s) : hsl.l + hsl.s - hsl.l * hsl.s;
float p = 2 * hsl.l - q;
rgb.r = hue2rgb(p, q, hsl.h / 360f + 1f / 3f);
rgb.g = hue2rgb(p, q, hsl.h / 360f);
rgb.b = hue2rgb(p, q, hsl.h / 360f - 1f / 3f);
}
}
private static RGB hsl2rgb(HSL hsl){
RGB rgb = new RGB();
hsl2rgb(hsl, rgb);
return rgb;
}
private static float softlight(float in, float softlightCoef){
return ((float) Math.pow(in, Math.pow(2f, 2f * (0.5f - softlightCoef))));
}
private static RGB softlight(RGB rgbIn, float softlightCoef){
return new RGB(softlight(rgbIn.r, softlightCoef),
softlight(rgbIn.g, softlightCoef),
softlight(rgbIn.b, softlightCoef));
}
private static class ChosenSwatch {
Palette.Swatch mSwatch;
int mPopulation;
final int POPULATION_STEP_COEF = 10; // Empirical value
void updateChoice(Palette.Swatch swatch){
mPopulation *= POPULATION_STEP_COEF;
if (swatch == null) return;
if (mSwatch == null || mPopulation < swatch.getPopulation()){
mSwatch = swatch;
mPopulation = mSwatch.getPopulation();
}
}
}
public static Bitmap getProcessedIcon(Context context, Bitmap originalIcon, Point targetResolution){
Bitmap finalIcon = Bitmap.createBitmap(targetResolution.x, targetResolution.y, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(finalIcon);
canvas.drawColor(Color.TRANSPARENT);
try {
Palette palette = Palette.from(originalIcon).generate();
ChosenSwatch chosenSwatch = new ChosenSwatch();
chosenSwatch.updateChoice(palette.getVibrantSwatch());
chosenSwatch.updateChoice(palette.getDarkVibrantSwatch());
chosenSwatch.updateChoice(palette.getDarkMutedSwatch());
chosenSwatch.updateChoice(palette.getMutedSwatch());
chosenSwatch.updateChoice(palette.getLightMutedSwatch());
chosenSwatch.updateChoice(palette.getLightVibrantSwatch());
Palette.Swatch swatch = chosenSwatch.mSwatch;
RGB rgb;
if (swatch == null){
rgb = hsl2rgb(new HSL(50, 0.2f, 0.8f));
}
else {
HSL hsl = new HSL(swatch.getHsl());
if (hsl.h >= 35 && hsl.h < 70){
hsl.s = 0.2f;
hsl.l = 0.8f;
}
else {
hsl.l = Math.min(0.30f, 0.75f * hsl.l);
}
rgb = hsl2rgb(hsl);
}
RGB gradientLight = softlight(rgb, 0.75f);
RGB gradientDark = softlight(rgb, 0.25f);
// FIXME: Scale-down and blur coefs shall depend on display density !!!
final int SHADOW_SCALE_DOWN = 4;
Bitmap smallerOriginal = Bitmap.createScaledBitmap(originalIcon, originalIcon.getWidth() / SHADOW_SCALE_DOWN, originalIcon.getHeight() / SHADOW_SCALE_DOWN, true);
BlurMaskFilter blurMaskFilter = new BlurMaskFilter(5, BlurMaskFilter.Blur.NORMAL);
Paint blurPaint = new Paint();
blurPaint.setMaskFilter(blurMaskFilter);
blurPaint.setColor(Color.BLACK);
int[] offsetXY = new int[2];
Bitmap shadow = smallerOriginal.extractAlpha(blurPaint, offsetXY);
Shader shader = new LinearGradient(0, 0, 0, finalIcon.getHeight(), gradientLight.getColor(), gradientDark.getColor(), Shader.TileMode.CLAMP);
Paint paint = new Paint();
paint.setShader(shader);
//canvas.drawRect(new RectF(0, 0, finalIcon.getWidth(), finalIcon.getHeight()), paint);
int roundPx = context.getResources().getDimensionPixelSize(R.dimen.round_size);
canvas.drawRoundRect(new RectF(0, 0, finalIcon.getWidth(), finalIcon.getHeight()), roundPx, roundPx, paint);
final float BORDER_MARGIN = 1.25f; //Empirical value
float maxWidthRatio = 1f * finalIcon.getWidth() / BORDER_MARGIN / originalIcon.getWidth();
float maxHeightRatio = 1f * finalIcon.getHeight() / BORDER_MARGIN / originalIcon.getHeight();
float maxRatio = Math.min(1f, Math.min(maxWidthRatio, maxHeightRatio));
//Log.i(_.TAG, "maxWidthRatio: " + maxWidthRatio + ", maxHeightRatio: " + maxHeightRatio + " => maxRatio: " + maxRatio);
final float MIN_CONTENT_SIZE = 1.618f; // Empirical value
float minWidthRatio = 1f * finalIcon.getWidth() / MIN_CONTENT_SIZE / originalIcon.getWidth();
float minHeightRatio = 1f * finalIcon.getHeight() / MIN_CONTENT_SIZE / originalIcon.getHeight();
float minRatio = Math.max(minWidthRatio, minHeightRatio);
//Log.i(_.TAG, "minWidthRatio: " + minWidthRatio + ", minHeightRatio: " + minHeightRatio + " => minRatio: " + minRatio);
float ratio = Math.max(maxRatio, minRatio);
//Log.i(_.TAG, "ratio: " + ratio);
final float SHADOW_RATIO = 0.9f; // Empirical value. Make sure it's not too big...
float finalShadowWidth = SHADOW_RATIO * ratio * (originalIcon.getWidth() - 2 * SHADOW_SCALE_DOWN * offsetXY[0]);
float finalShadowHeight = SHADOW_RATIO * ratio * (originalIcon.getHeight() - 2 * SHADOW_SCALE_DOWN * offsetXY[1]);
float finalShadowLeft = (finalIcon.getWidth() - finalShadowWidth) / 2;
float finalShadowTop = (finalIcon.getHeight() - finalShadowHeight) / 2 - SHADOW_RATIO * SHADOW_SCALE_DOWN * offsetXY[1];
RectF shadowDstRect = new RectF(finalShadowLeft,
finalShadowTop,
finalShadowLeft + finalShadowWidth,
finalShadowTop + finalShadowHeight);
Paint shadowPaint = new Paint();
shadowPaint.setAlpha(0x40); // Empirical value
shadowPaint.setFilterBitmap(true);
canvas.drawBitmap(shadow, null, shadowDstRect, shadowPaint);
float finalWidth = ratio * originalIcon.getWidth();
float finalHeight = ratio * originalIcon.getHeight();
float finalLeft = (finalIcon.getWidth() - finalWidth) / 2;
float finalTop = (finalIcon.getHeight() - finalHeight) / 2;
RectF dstRect = new RectF(finalLeft, finalTop, finalLeft + finalWidth, finalTop + finalHeight);
Paint iconPaint = new Paint();
iconPaint.setFilterBitmap(true);
canvas.drawBitmap(originalIcon, null, dstRect, iconPaint);
//_.saveBitmap(sApplicationContext, finalIcon, "finalIcon-" + Math.random());
}
catch (Exception e){
e.printStackTrace();
}
return finalIcon;
}
public static Bitmap getDrawableBitmap(Drawable drawable) {
Bitmap originalIcon;
if (BitmapDrawable.class.isInstance(drawable)){
BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
originalIcon = bitmapDrawable.getBitmap();
}
else {
int width = drawable.getIntrinsicWidth();
int height = drawable.getIntrinsicHeight();
if (width != 0 || height != 0){
if (width != 0 && height == 0){
height = width;
}
else if (height != 0 && width == 0){
width = height;
}
}
originalIcon = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(originalIcon);
canvas.drawColor(Color.TRANSPARENT);
drawable.setBounds(0, 0, width, height);
drawable.draw(canvas);
}
return originalIcon;
}
}
調節2,3篩選後的圖標都做中心截圓加白背板處理。
public static Bitmap bitmapAddWhiteBg(Context context, int iconSize, Bitmap b, MatOfPoint contour){
//find the visible area, ajust the resize ratio according visible area
org.opencv.core.Point[] contourArray = contour.toArray();
Mat mat = new Mat();
Utils.bitmapToMat(b.copy(Bitmap.Config.ARGB_8888, false), mat);
org.opencv.core.Point tempPtXMiddle = new org.opencv.core.Point((double) (mat.cols() / 2), (double) 0);
org.opencv.core.Point tempPtYMiddle = new org.opencv.core.Point((double) 0, (double) (mat.rows() / 2));
org.opencv.core.Point tempPtX2 = new org.opencv.core.Point((double) (mat.cols() / 2 ), (double) mat.rows());
org.opencv.core.Point tempPtY2 = new org.opencv.core.Point((double) mat.cols(), (double) (mat.rows() / 2 ));
double positionCheckXMiddle = Math.abs(Imgproc.pointPolygonTest(new MatOfPoint2f(contourArray), tempPtXMiddle, true));
double positionCheckYMiddle = Math.abs(Imgproc.pointPolygonTest(new MatOfPoint2f(contourArray), tempPtYMiddle, true));
double positionCheckX2 = Math.abs(Imgproc.pointPolygonTest(new MatOfPoint2f(contourArray), tempPtX2, true));
double positionCheckY2 = Math.abs(Imgproc.pointPolygonTest(new MatOfPoint2f(contourArray), tempPtY2, true));
Drawable iconbgDrawable = context.getResources().getDrawable(R.drawable.baseboard);
Bitmap addbg = Bitmap.createBitmap(iconSize, iconSize,
iconbgDrawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565);
Canvas canvasBg = new Canvas(addbg);
iconbgDrawable.setBounds(0, 0, iconSize, iconSize);
iconbgDrawable.draw(canvasBg);
Paint p2 = new Paint();
p2.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OVER));
//zoom bitmap according the visible area
double resizeIconsizeX ;
double resizeIconsizeY ;
//取原圖標外輪廓的內接垂直和水平的中心線的長度的最小值(Math.min(visibleW, visibleH))和白背板圖標的中心圓的直徑做比,乘以項目所對應的要求的正方形圖標的大小(其實所有的圖標都是正方形的),即為縮小後的圖標大小。如果縮小後的圖標可見區域的較大值(Math.max(visibleW, visibleH)*resizeRate)比標准圖標的可見高度要大,則以大的那個值和中心圓的直徑做對比求出縮小的比例。
double visibleH = iconSize - positionCheckXMiddle - positionCheckX2;
double visibleW = iconSize - positionCheckYMiddle - positionCheckY2;
float innerCirleDiameter = context.getResources().getDimension(R.dimen.visible_inner_circle_d);
float visibleWhiteBgH = context.getResources().getDimension(R.dimen.visible_whitle_bg_h);
double resizeRate = innerCirleDiameter / Math.min(visibleW, visibleH);
resizeIconsizeX = resizeIconsizeY = resizeRate * iconSize;
double cutRateH = 1;
if(visibleH * resizeRate > visibleWhiteBgH){
// resizeIconsize = innerCirleDiameter / Math.max(visibleW, visibleH) * iconSize;
cutRateH = visibleWhiteBgH/visibleH;
b = Bitmap.createBitmap(b, 0, Math.max(0,(int)((b.getHeight()-b.getHeight()* cutRateH)/2)), b.getWidth(), Math.min((int)(b.getHeight()* cutRateH),b.getHeight()), new Matrix(), true);
}
if (sRectangleIconDEBUG) {
Log.d(sRectangleIcon, "resizeIconsizeX: " + resizeIconsizeX + "resizeIconsizY: " + resizeIconsizeY + ",visibleW:" + ",visibleH:" + visibleH + ",positionCheckXMiddle:" + positionCheckXMiddle + ",positionCheckX2:" +
positionCheckX2 + ",positionCheckYMiddle:" + positionCheckYMiddle + ",positionCheckY2:" + positionCheckY2);
}
Bitmap resizeCircleBitmap = zoomBitmap(b, (float)resizeIconsizeX, (float)resizeIconsizeY*(float)cutRateH);
double adX = (iconSize - resizeIconsizeX)/2;
double adY = (iconSize - resizeIconsizeY*cutRateH)/2;
canvasBg.drawBitmap(resizeCircleBitmap, (float)adX ,(float) adY , p2);
canvasBg.setBitmap(null);
return addbg;
}
最後附上效果圖:
Android手機內存管理與性能優化視頻教程課程講師:xiao_q課程分類:Android適合人群:中級課時數量:34小節用到技術:Dalvik,DDMS,File Ex
在android 中,邊緣模糊的效果是通過BlurMaskFilter實現的 , 它定義了一個邊緣模糊半徑和模糊效果 (Blur)。Blur 有四種模糊效果, inner
上篇博文和大家分享了下拉刷新,這是一個用戶體驗非常好的操作方式。新浪微薄就是使用這種方式的典型。 還有個問題,當用戶從網絡上讀取微薄的時候,如果一下子全部加載用戶未讀
listview是開發中必見的功能應用,各種需求也不盡相同,今天給大家一個帶來一個簡單方便的自定義listview,希望對大家有幫助,閒話不說,先上幾張效果圖1、功能示例