Android绘制点引发的思考

背景

在Canvas上绘制一个点,比如(1.0f,1.0f),原本以为绘制的范围应该是[1.0f,1.0f]-[2.0f,2.0f]这么一个矩形区域,但是实际结果却是[0.5f,0.5f]-[1.5f,1.5f]这么一个矩形区域。于是联想到如果通过绘制点的方式来绘制一张图片会是什么效果呢?

绘制一个点

下面代码是绘制一个点的简单例子:

/**
 * 绘制一个点
 */

public class PointView extends View {
    //View的宽度
    private int mWidth;
    //View的高度
    private int mHeight;
    //画线的画笔
    private Paint mLinePaint = new Paint();
    //画点的画笔
    private Paint mPointPaint = new Paint();
    //Canvas缩放的比例
    private float mScale = 100.0f;


    public PointView(Context context) {
        this(context, null);
    }

    public PointView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public PointView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mLinePaint.setColor(Color.BLUE);
        mLinePaint.setStyle(Paint.Style.STROKE);


        mPointPaint.setColor(Color.RED);
        mPointPaint.setStyle(Paint.Style.FILL);
        //设置画笔大小
        mPointPaint.setStrokeWidth(1.0f);
        mPointPaint.setAntiAlias(true);
        mPointPaint.setDither(true);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        if (changed) {
            mWidth = right - left;
            mHeight = bottom - top;
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawColor(Color.WHITE);
        canvas.save();
        Matrix matrix = new Matrix();
        matrix.setScale(mScale, mScale, 0.0f, 0.0f);
        //让画布扩大倍
        canvas.setMatrix(matrix);
        //绘制网格
        for (int i = 0; i <= mWidth; i++) {
            float[] points = new float[]{i, 0, i, mHeight};
            canvas.drawLines(points, mLinePaint);
        }
        for (int i = 0; i <= mHeight; i++) {
            float[] points = new float[]{0, i, mWidth, i};
            canvas.drawLines(points, mLinePaint);
        }
        //绘制点
        canvas.drawPoint(1.0f, 1.0f, mPointPaint);
        canvas.restore();
    }
}

下面图片中红色的方块区域是绘制点(1.0f,1.0f)的结果,把画布放大了一定倍数,便于观察绘。

为什么绘制的区域是[0.5f,0.5f]-[1.5f,1.5f]这个矩形区域,而不是主观意识中[1.0f,1.0f]-[2.0f,2.0f]。Android关于绘制点的API其中一个有下面介绍:

    /**
     * Draw a series of points. Each point is centered at the coordinate specified by pts[], and its
     * diameter is specified by the paint's stroke width (as transformed by the canvas' CTM), with
     * special treatment for a stroke width of 0, which always draws exactly 1 pixel (or at most 4
     * if antialiasing is enabled). The shape of the point is controlled by the paint's Cap type.
     * The shape is a square, unless the cap type is Round, in which case the shape is a circle.
     *
     * @param pts Array of points to draw [x0 y0 x1 y1 x2 y2 ...]
     * @param offset Number of values to skip before starting to draw.
     * @param count The number of values to process, after skipping offset of them. Since one point
     *            uses two values, the number of "points" that are drawn is really (count >> 1).
     * @param paint The paint used to draw the points
     */
    public void drawPoints(@Size(multiple = 2) float[] pts, int offset, int count,
            @NonNull Paint paint) {
        super.drawPoints(pts, offset, count, paint);
    }

上面这段注释说明绘制一个点是以这个点为中心,画笔的大小为直径绘制的一个方形。所以最后在画布上显示的矩形区域就是[0.5f,0.5f]-[1.5f,1.5f]

绘制一张图片

如果通过很多个点来绘制一张图片,会是什么效果呢?具体代码如下:

/**
 * 利用像素绘制一个点,绘制出整张图片
 */

public class PixelsView extends View {
    //View的宽度
    private int mWidth;
    //View的高度
    private int mHeight;
    //画线的画笔
    private Paint mLinePaint = new Paint();
    //画点的画笔
    private Paint mPointPaint = new Paint();
    //存储图片的像素
    private int[] mPixels;
    //图片对象
    private Bitmap mBitmap;
    //图片宽度
    private int mBmpWidth;
    //图片高度
    private int mBmpHeight;
    //Canvas缩放的比例
    private float mScale = 15.0f;

    public PixelsView(Context context) {
        this(context, null);
    }

    public PixelsView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public PixelsView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mLinePaint.setColor(Color.BLUE);
        mLinePaint.setStyle(Paint.Style.STROKE);


        mPointPaint.setColor(Color.BLACK);
        mPointPaint.setStyle(Paint.Style.FILL);
        mPointPaint.setStrokeWidth(1.0f);
        mPointPaint.setAntiAlias(true);
        mPointPaint.setDither(true);

        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.test);

        int bmpWidth = mBmpWidth = bitmap.getWidth();
        int bmpHeight = mBmpHeight = bitmap.getHeight();

        int[] pixels = new int[bmpWidth * bmpHeight];
        bitmap.getPixels(pixels, 0, bmpWidth, 0, 0, bmpWidth, bmpHeight);
        mPixels = pixels;
        mBitmap = bitmap;
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        if (changed) {
            mWidth = right - left;
            mHeight = bottom - top;
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawColor(Color.WHITE);
        canvas.save();
        Matrix matrix = new Matrix();
        matrix.setScale(mScale, mScale, 0.0f, 0.0f);
        canvas.setMatrix(matrix);
        for (int i = 0; i <= mWidth; i++) {
            float[] points = new float[]{i, 0, i, mHeight};
            canvas.drawLines(points, mLinePaint);
        }
        for (int i = 0; i <= mHeight; i++) {
            float[] points = new float[]{0, i, mWidth, i};
            canvas.drawLines(points, mLinePaint);
        }
        for (int i = 0; i < mBmpHeight; i++) {
            for (int j = 0; j < mBmpWidth; j++) {
                int argbs = mPixels[i * mBmpWidth + j];
                mPointPaint.setColor(argbs);
                canvas.drawPoint(j, i, mPointPaint);
                //点的位置移动0.5单位个大小
                //canvas.drawPoint(((float)j+0.5f),(float)i+0.5f,mPointPaint);
            }
        }
        canvas.drawBitmap(mBitmap, 0f, mBmpHeight + 1, null);
        canvas.restore();
    }
}

这段代码通过把图片的像素绘制到对应的点上来绘制图片对象,同时还绘制了一个Bitmap对象来作为对比。程序运行结果如下:

(通过点绘制像素形成的图片由于把画布放大了就变得模糊了)对比通过点绘制的图像,以及直接通过Bitmap绘制图像的方式,发现通过点绘制的图像在宽与高出都少了半个格子(0.5个单位)。

于是把通过点绘制图像的方式中所有的点都加上0.5个单位,这样两种绘制的方式就是一样的了。程序运行结果如下:

疑问

直接通过Bitmap对象来绘制一张图片时,传入的顶点坐标并没有偏移0.5个单位而绘制出了正确位置的图像,比如前面程序中的(0,mBmpHeight + 1)。难道是系统内部实现的时候自动调整了0.5个单位吗?
希望有了解过的人告诉下,或者是自己一开始就理解错了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值