Fix vector icons drawing

This commit is contained in:
max-klaus 2020-05-03 15:31:06 +03:00
parent 731376a572
commit 7fee1d08ca
7 changed files with 119 additions and 112 deletions

View file

@ -162,11 +162,10 @@ public class OsmandRenderer {
return dashEffect.get(dashes);
}
public Shader getShader(String resId){
if(shaders.get(resId) == null){
public Shader getShader(String resId) {
if (shaders.get(resId) == null) {
Bitmap bmp = RenderingIcons.getIcon(context, resId, true);
if(bmp != null){
if (bmp != null) {
Shader sh = new BitmapShader(bmp, TileMode.REPEAT, TileMode.REPEAT);
shaders.put(resId, sh);
} else {
@ -329,14 +328,14 @@ public class OsmandRenderer {
for (IconDrawInfo icon : rc.iconsToDraw) {
if (icon.resId != null) {
Bitmap ico = RenderingIcons.getIcon(context, icon.resId, true);
Drawable ico = RenderingIcons.getDrawableIcon(context, icon.resId, true);
if (ico != null) {
if (icon.y >= 0 && icon.y < rc.height && icon.x >= 0 && icon.x < rc.width) {
int visbleWidth = icon.iconSize >= 0 ? (int) icon.iconSize : ico.getWidth();
int visbleHeight = icon.iconSize >= 0 ? (int) icon.iconSize : ico.getHeight();
int visbleWidth = icon.iconSize >= 0 ? (int) icon.iconSize : ico.getIntrinsicWidth();
int visbleHeight = icon.iconSize >= 0 ? (int) icon.iconSize : ico.getIntrinsicHeight();
boolean intersects = false;
float coeff = rc.getDensityValue(rc.screenDensityRatio * rc.textScale);
RectF rf = calculateRect(rc, icon, ico.getWidth(), ico.getHeight());
RectF rf = calculateRect(rc, icon, ico.getIntrinsicWidth(), ico.getIntrinsicHeight());
RectF visibleRect = null;
if (visbleHeight > 0 && visbleWidth > 0) {
visibleRect = calculateRect(rc, icon, visbleWidth, visbleHeight);
@ -350,37 +349,29 @@ public class OsmandRenderer {
}
if (!intersects) {
Bitmap shield = icon.shieldId == null ? null : RenderingIcons.getIcon(context, icon.shieldId, true);
if(shield != null) {
RectF shieldRf = calculateRect(rc, icon, shield.getWidth(), shield.getHeight());
if (coeff != 1f) {
Rect src = new Rect(0, 0, shield.getWidth(), shield.getHeight());
drawBitmap(cv, shield, shieldRf, src);
} else {
drawBitmap(cv, shield, shieldRf);
Drawable shield = icon.shieldId == null ? null : RenderingIcons.getDrawableIcon(context, icon.shieldId, true);
boolean fillRect = coeff != 1f;
if (shield != null) {
cv.save();
RectF shieldRf = calculateRect(rc, icon, shield.getIntrinsicWidth(), shield.getIntrinsicHeight());
cv.translate(shieldRf.left, shieldRf.top);
draw(cv, shield, shieldRf, fillRect);
cv.restore();
}
}
if (coeff != 1f) {
Rect src = new Rect(0, 0, ico.getWidth(), ico.getHeight());
drawBitmap(cv, RenderingIcons.getIcon(context, icon.resId_1, true), rf, src);
drawBitmap(cv, ico, rf, src);
drawBitmap(cv, RenderingIcons.getIcon(context, icon.resId2, true), rf, src);
drawBitmap(cv, RenderingIcons.getIcon(context, icon.resId3, true), rf, src);
drawBitmap(cv, RenderingIcons.getIcon(context, icon.resId4, true), rf, src);
drawBitmap(cv, RenderingIcons.getIcon(context, icon.resId5, true), rf, src);
} else {
drawBitmap(cv, RenderingIcons.getIcon(context, icon.resId_1, true), rf);
drawBitmap(cv, ico, rf);
drawBitmap(cv, RenderingIcons.getIcon(context, icon.resId2, true), rf);
drawBitmap(cv, RenderingIcons.getIcon(context, icon.resId3, true), rf);
drawBitmap(cv, RenderingIcons.getIcon(context, icon.resId4, true), rf);
drawBitmap(cv, RenderingIcons.getIcon(context, icon.resId5, true), rf);
}
if(visibleRect != null) {
cv.save();
cv.translate(rf.left, rf.top);
draw(cv, RenderingIcons.getDrawableIcon(context, icon.resId_1, true), rf, fillRect);
draw(cv, ico, rf, fillRect);
draw(cv, RenderingIcons.getDrawableIcon(context, icon.resId2, true), rf, fillRect);
draw(cv, RenderingIcons.getDrawableIcon(context, icon.resId3, true), rf, fillRect);
draw(cv, RenderingIcons.getDrawableIcon(context, icon.resId4, true), rf, fillRect);
draw(cv, RenderingIcons.getDrawableIcon(context, icon.resId5, true), rf, fillRect);
if (visibleRect != null) {
visibleRect.inset(-visibleRect.width() / 4, -visibleRect.height() / 4);
boundIntersections.insert(visibleRect,
new QuadRect(visibleRect.left, visibleRect.top, visibleRect.right, visibleRect.bottom));
}
cv.restore();
}
}
}
@ -391,23 +382,16 @@ public class OsmandRenderer {
}
}
public Drawable getShieldDrawable(String shieldId){
Bitmap shield = RenderingIcons.getIcon(context, shieldId, true);
return new BitmapDrawable(context.getResources(),shield);
}
protected void drawBitmap(Canvas cv, Bitmap ico, RectF rf) {
if(ico == null) {
protected void draw(Canvas cv, Drawable ico, RectF rf, boolean fillRect) {
if (ico == null) {
return;
}
cv.drawBitmap(ico, rf.left, rf.top, paintIcon);
if (fillRect) {
ico.setBounds(0, 0, (int) rf.width(), (int) rf.height());
} else {
ico.setBounds(0, 0, ico.getIntrinsicWidth(), ico.getIntrinsicHeight());
}
protected void drawBitmap(Canvas cv, Bitmap ico, RectF rf, Rect src) {
if(ico == null) {
return;
}
cv.drawBitmap(ico, src, rf, paintIcon);
ico.draw(cv);
}
private RectF calculateRect(RenderingContext rc, IconDrawInfo icon, int visbleWidth, int visbleHeight) {

View file

@ -1,17 +1,5 @@
package net.osmand.plus.render;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.LinkedHashMap;
import java.util.Map;
import net.osmand.PlatformUtil;
import net.osmand.plus.R;
import net.osmand.plus.R.drawable;
import org.apache.commons.logging.Log;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
@ -23,6 +11,18 @@ import android.os.Build;
import androidx.core.content.ContextCompat;
import androidx.core.graphics.drawable.DrawableCompat;
import net.osmand.PlatformUtil;
import net.osmand.plus.R;
import net.osmand.plus.R.drawable;
import org.apache.commons.logging.Log;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.LinkedHashMap;
import java.util.Map;
public class RenderingIcons {
private static final Log log = PlatformUtil.getLog(RenderingIcons.class);
@ -43,9 +43,11 @@ public class RenderingIcons {
return bigIcons.containsKey(s);
}
public static synchronized byte[] getBitmapFromVectorDrawable(Context context, int drawableId) {
public static synchronized Bitmap getBitmapFromVectorDrawable(Context context, int drawableId) {
Drawable drawable = ContextCompat.getDrawable(context, drawableId);
if (drawable == null) {
return null;
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
drawable = (DrawableCompat.wrap(drawable)).mutate();
}
@ -58,20 +60,27 @@ public class RenderingIcons {
Canvas canvas = new Canvas(cacheBmp);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return cacheBmp;
}
private static synchronized byte[] getPngFromVectorDrawable(Context context, int drawableId) {
Bitmap bmp = getBitmapFromVectorDrawable(context, drawableId);
if (bmp == null) {
return null;
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
cacheBmp.compress(Bitmap.CompressFormat.PNG, 100, baos);
bmp.compress(Bitmap.CompressFormat.PNG, 100, baos);
return baos.toByteArray();
}
public static byte[] getIconRawData(Context ctx, String s) {
Integer resId = shaderIcons.get(s);
if(resId == null) {
if (resId == null) {
resId = smallIcons.get(s);
}
if(resId == null)
if (resId == null) {
return null;
}
try {
final InputStream inputStream = ctx.getResources().openRawResource(resId.intValue());
final ByteArrayOutputStream proxyOutputStream = new ByteArrayOutputStream(1024);
@ -83,7 +92,7 @@ public class RenderingIcons {
inputStream.close();
final byte[] bitmapData = proxyOutputStream.toByteArray();
if (isVectorData(bitmapData)) {
return getBitmapFromVectorDrawable(ctx, resId.intValue());
return getPngFromVectorDrawable(ctx, resId.intValue());
}
// log.info("Icon data length is " + bitmapData.length); //$NON-NLS-1$
// Bitmap dm = android.graphics.BitmapFactory.decodeByteArray(bitmapData, 0, bitmapData.length) ;
@ -130,6 +139,12 @@ public class RenderingIcons {
return null;
}
/**
* Return vector icon as bitmap. Used for java rendering only.
*
* @deprecated Use getDrawableIcon instead.
*/
@Deprecated
public static Bitmap getIcon(Context ctx, String s, boolean includeShader) {
if(s == null) {
return null;
@ -140,7 +155,7 @@ public class RenderingIcons {
if (!iconsBmp.containsKey(s)) {
Integer resId = s.startsWith("h_") ? shaderIcons.get(s.substring(2)) : smallIcons.get(s);
if (resId != null) {
Bitmap bmp = BitmapFactory.decodeResource(ctx.getResources(), resId, null);
Bitmap bmp = getBitmapFromVectorDrawable(ctx, resId);
iconsBmp.put(s, bmp);
} else {
iconsBmp.put(s, null);

View file

@ -31,6 +31,8 @@ import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import org.apache.commons.logging.Log;
public class TextRenderer {
@ -315,19 +317,20 @@ public class TextRenderer {
public void drawShieldIcon(RenderingContext rc, Canvas cv, TextDrawInfo text, String sr) {
if (sr != null) {
float coef = rc.getDensityValue(rc.screenDensityRatio * rc.textScale);
Bitmap ico = RenderingIcons.getIcon(context, sr, true);
Drawable ico = RenderingIcons.getDrawableIcon(context, sr, true);
if (ico != null) {
float left = text.centerX - ico.getWidth() / 2 * coef - 0.5f;
float top = text.centerY - ico.getHeight() / 2 * coef - paintText.descent() * 1.5f;
if(rc.screenDensityRatio != 1f){
RectF rf = new RectF(left, top, left + ico.getWidth() * coef,
top + ico.getHeight() * coef);
Rect src = new Rect(0, 0, ico.getWidth(), ico
.getHeight());
cv.drawBitmap(ico, src, rf, paintIcon);
float left = text.centerX - ico.getIntrinsicWidth() / 2f * coef - 0.5f;
float top = text.centerY - ico.getIntrinsicHeight() / 2f * coef - paintText.descent() * 1.5f;
cv.save();
cv.translate(left, top);
if (rc.screenDensityRatio != 1f) {
ico.setBounds(0, 0, (int) (ico.getIntrinsicWidth() * coef), (int) (ico.getIntrinsicHeight() * coef));
ico.draw(cv);
} else {
cv.drawBitmap(ico, left, top, paintIcon);
ico.setBounds(0, 0, ico.getIntrinsicWidth(), ico.getIntrinsicHeight());
ico.draw(cv);
}
cv.restore();
}
}
}

View file

@ -14,8 +14,8 @@ import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffColorFilter;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.util.Pair;
import android.view.MotionEvent;
@ -170,7 +170,7 @@ public abstract class OsmandMapLayer {
private Bitmap arrowBitmap;
private Bitmap walkArrowBitmap;
private Bitmap anchorBitmap;
private Map<Pair<Integer, Bitmap>, Bitmap> stopBitmapsCache = new HashMap<>();
private Map<Pair<Integer, Drawable>, Bitmap> stopBitmapsCache = new HashMap<>();
private Map<Integer, Bitmap> stopSmallBitmapsCache = new HashMap<>();
public GeometryWayContext(Context ctx, float density) {
@ -317,8 +317,8 @@ public abstract class OsmandMapLayer {
return anchorBitmap;
}
public Bitmap getStopShieldBitmap(int color, Bitmap stopBitmap) {
Bitmap bmp = stopBitmapsCache.get(new Pair<>(color, stopBitmap));
public Bitmap getStopShieldBitmap(int color, Drawable stopDrawable) {
Bitmap bmp = stopBitmapsCache.get(new Pair<>(color, stopDrawable));
if (bmp == null) {
int fillColor = UiUtilities.getContrastColor(getApp(), color, true);
int strokeColor = getStrokeColor(color);
@ -344,15 +344,15 @@ public abstract class OsmandMapLayer {
paint.setStyle(Paint.Style.STROKE);
canvas.drawRoundRect(rect, routeShieldCornerRadius, routeShieldCornerRadius, paint);
if (stopBitmap != null) {
paint.setFilterBitmap(true);
paint.setColorFilter(new PorterDuffColorFilter(strokeColor, Mode.SRC_IN));
Rect src = new Rect(0, 0, stopBitmap.getWidth(), stopBitmap.getHeight());
if (stopDrawable != null) {
stopDrawable.setColorFilter(new PorterDuffColorFilter(strokeColor, Mode.SRC_IN));
float marginBitmap = 1f * density;
rect.inset(marginBitmap, marginBitmap);
canvas.drawBitmap(stopBitmap, src, rect, paint);
stopDrawable.setBounds(0, 0, (int) rect.width(), (int) rect.height());
canvas.translate(rect.left, rect.top);
stopDrawable.draw(canvas);
}
stopBitmapsCache.put(new Pair<>(color, stopBitmap), bmp);
stopBitmapsCache.put(new Pair<>(color, stopDrawable), bmp);
}
return bmp;
}

View file

@ -11,6 +11,7 @@ import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffColorFilter;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.util.Pair;
@ -559,7 +560,7 @@ public class RouteLayer extends OsmandMapLayer implements ContextMenuLayer.ICont
private static class GeometryTransportWayStyle extends GeometryWayStyle {
private TransportRouteResultSegment segment;
private Bitmap stopBitmap;
private Drawable stopDrawable;
protected Integer pointColor;
GeometryTransportWayStyle(GeometryWayContext context, TransportRouteResultSegment segment) {
@ -579,7 +580,7 @@ public class RouteLayer extends OsmandMapLayer implements ContextMenuLayer.ICont
type = TransportStopType.findType("bus");
}
if (type != null) {
stopBitmap = RenderingIcons.getIcon(getCtx(), type.getResName(), false);
stopDrawable = RenderingIcons.getDrawableIcon(getCtx(), type.getResName(), false);
}
}
@ -607,7 +608,7 @@ public class RouteLayer extends OsmandMapLayer implements ContextMenuLayer.ICont
}
public Bitmap getStopBitmap() {
return getContext().getStopShieldBitmap(color, stopBitmap);
return getContext().getStopShieldBitmap(color, stopDrawable);
}
public Bitmap getStopSmallBitmap() {

View file

@ -4,11 +4,13 @@ import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.drawable.Drawable;
import android.util.DisplayMetrics;
import android.view.WindowManager;
@ -48,8 +50,8 @@ public class TransportStopsLayer extends OsmandMapLayer implements ContextMenuLa
private OsmandMapTileView view;
private Paint paintIcon;
private Paint paintLightIcon;
private Paint paintDarkIcon;
private ColorFilter paintLightIconFilter;
private ColorFilter paintDarkIconFilter;
private Bitmap backgroundIcon;
private Bitmap stopBus;
private Bitmap stopSmall;
@ -81,10 +83,8 @@ public class TransportStopsLayer extends OsmandMapLayer implements ContextMenuLa
WindowManager wmgr = (WindowManager) view.getContext().getSystemService(Context.WINDOW_SERVICE);
wmgr.getDefaultDisplay().getMetrics(dm);
paintIcon = new Paint();
paintLightIcon = new Paint();
paintLightIcon.setColorFilter(new PorterDuffColorFilter(ContextCompat.getColor(mapActivity, R.color.active_buttons_and_links_text_light), PorterDuff.Mode.SRC_IN));
paintDarkIcon = new Paint();
paintDarkIcon.setColorFilter(new PorterDuffColorFilter(ContextCompat.getColor(mapActivity, R.color.active_buttons_and_links_text_dark), PorterDuff.Mode.SRC_IN));
paintLightIconFilter = new PorterDuffColorFilter(ContextCompat.getColor(mapActivity, R.color.active_buttons_and_links_text_light), PorterDuff.Mode.SRC_IN);
paintDarkIconFilter = new PorterDuffColorFilter(ContextCompat.getColor(mapActivity, R.color.active_buttons_and_links_text_dark), PorterDuff.Mode.SRC_IN);
path = new Path();
stopBus = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_transport_stop_bus);
stopSmall = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_transport_stop_small);
@ -253,9 +253,14 @@ public class TransportStopsLayer extends OsmandMapLayer implements ContextMenuLa
if (stopRoute != null) {
TransportStopType type = TransportStopType.findType(stopRoute.route.getType());
if (type != null) {
Bitmap foregroundIcon = RenderingIcons.getIcon(mapActivity, type.getResName(), false);
Drawable foregroundIcon = RenderingIcons.getDrawableIcon(mapActivity, type.getResName(), false);
canvas.drawBitmap(backgroundIcon, x - backgroundIconHalfWidth, y - backgroundIconHalfHeight, paintIcon);
canvas.drawBitmap(foregroundIcon, x - foregroundIcon.getWidth() / 2f, y - foregroundIcon.getHeight() / 2f, nightMode ? paintDarkIcon : paintLightIcon);
canvas.save();
canvas.translate(x - foregroundIcon.getIntrinsicWidth() / 2f, y - foregroundIcon.getIntrinsicHeight() / 2f);
foregroundIcon.setBounds(0, 0, foregroundIcon.getIntrinsicWidth(), foregroundIcon.getIntrinsicHeight());
foregroundIcon.setColorFilter(nightMode ? paintDarkIconFilter : paintLightIconFilter);
foregroundIcon.draw(canvas);
canvas.restore();
}
} else {
Bitmap b = stopBus;

View file

@ -59,6 +59,7 @@ import net.osmand.plus.helpers.WaypointDialogHelper;
import net.osmand.plus.helpers.WaypointHelper;
import net.osmand.plus.helpers.WaypointHelper.LocationPointWrapper;
import net.osmand.plus.render.OsmandRenderer;
import net.osmand.plus.render.RenderingIcons;
import net.osmand.plus.render.TextRenderer;
import net.osmand.plus.routepreparationmenu.MapRouteInfoMenu;
import net.osmand.plus.routepreparationmenu.ShowAlongTheRouteBottomSheet;
@ -1130,7 +1131,6 @@ public class MapInfoWidgetsFactory {
}
private boolean setRoadShield(ImageView view, RouteDataObject object) {
String nameTag = null;
String name = null;
StringBuilder additional = new StringBuilder();
@ -1144,7 +1144,6 @@ public class MapInfoWidgetsFactory {
additional.append(key).append("=").append(val).append(";");
}
}
// LOG.debug("Additionals (names): " + additional.toString() );
Context context = topBar.getContext();
int[] tps = object.getTypes();
@ -1197,13 +1196,13 @@ public class MapInfoWidgetsFactory {
}
if (shieldRes != -1) {
float xSize;
float ySize;
Bitmap shield;
shield = BitmapFactory.decodeResource(app.getResources(), shieldRes);
ySize = shield.getHeight();
xSize = shield.getWidth();
float xyRatio = xSize/ySize;
Drawable shield = ContextCompat.getDrawable(view.getContext(), shieldRes);
if (shield == null) {
return false;
}
float xSize = shield.getIntrinsicWidth();
float ySize = shield.getIntrinsicHeight();
float xyRatio = xSize / ySize;
//setting view propotions (height is fixed by toolbar size - 48dp);
int viewHeightPx = AndroidUtils.dpToPx(context, 48);
int viewWidthPx = (int) (viewHeightPx * xyRatio);
@ -1215,9 +1214,9 @@ public class MapInfoWidgetsFactory {
//creating bitmap according to size of resource
Bitmap bitmap = Bitmap.createBitmap((int) xSize, (int) ySize, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
text.fillProperties(rc, rreq, xSize/2, ySize/2 - p.getFontMetrics().ascent/2f);
text.fillProperties(rc, rreq, xSize / 2f, ySize / 2f - p.getFontMetrics().ascent / 2f);
textRenderer.drawShieldIcon(rc, canvas, text, text.getShieldResIcon());
textRenderer.drawWrappedText(canvas, text, 20);
textRenderer.drawWrappedText(canvas, text, 20f);
view.setImageBitmap(bitmap);
return true;