【问题标题】:Rendering Bitmap based on Views position in parent基于父视图中的位置渲染位图
【发布时间】:2018-07-17 09:42:09
【问题描述】:

我正在尝试制作一个简单的图像编辑器。一开始我认为将视图状态简单地保存为位图是个好主意,但事实证明,屏幕分辨率范围很广,这会导致巨大的质量(和内存使用)波动。

现在我正在尝试制作一个将视图状态转换为所需分辨率的模块。

在下面的代码中,我试图在画布中重新创建视图的当前状态:

    Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.id.test_1_1);
    bitmap = Bitmap.createScaledBitmap(bitmap, parentView.getMeasuredWidth(), parentView.getMeasuredHeight(), true);

    Canvas canvas = new Canvas(bitmap);
    Paint paint = new Paint();
    for (View rootView : addedViews) {
        ImageView imageView = rootView.findViewById(R.id.sticker);

        float[] viewPosition = new float[2];
        transformToAncestor(viewPosition, parentView, imageView);

        Bitmap originalBitmap = ((BitmapDrawable) imageView.getDrawable()).getBitmap();
        Matrix adjustMatrix = new Matrix();
        adjustMatrix.postTranslate(viewPosition[0], viewPosition[1]);
        adjustMatrix.postScale(
                rootView.getScaleX(),
                rootView.getScaleY(),
                rootView.getWidth() / 2,
                rootView.getHeight() / 2);
        adjustMatrix.postRotate(rootView.getRotation(),
                rootView.getWidth() / 2,
                rootView.getHeight() / 2);

        canvas.drawBitmap(originalBitmap, adjustMatrix, paint);
    }

transformToAncestor 函数来自here

public static void transformToAncestor(float[] point, final View ancestor, final View descendant) {
    final float scrollX = descendant.getScrollX();
    final float scrollY = descendant.getScrollY();
    final float left = descendant.getLeft();
    final float top = descendant.getTop();
    final float px = descendant.getPivotX();
    final float py = descendant.getPivotY();
    final float tx = descendant.getTranslationX();
    final float ty = descendant.getTranslationY();
    final float sx = descendant.getScaleX();
    final float sy = descendant.getScaleY();

    point[0] = left + px + (point[0] - px) * sx + tx - scrollX;
    point[1] = top + py + (point[1] - py) * sy + ty - scrollY;

    ViewParent parent = descendant.getParent();
    if (descendant != ancestor && parent != ancestor && parent instanceof View) {
        transformToAncestor(point, ancestor, (View) parent);
    }
}

(作者写了一个说明,他的函数不支持旋转,但在我的示例中没有太多旋转,所以我认为现在不重要)。

我的问题是:

第一张图片是通过保存父视图状态生成的。第二个是通过将视图位置、旋转和缩放转换到画布上生成的。 如您所见,在画布上,未缩放的贴纸位置正确,但缩放后的位置不正确。

如何正确定位这些缩放视图?

【问题讨论】:

  • 你需要什么transformToAncestor方法?您的目标是创建某种图层(在您的情况下用白星绘制) - 每个图层都缩放、平移和可能旋转?
  • 我正在使用这种方法来转换每个星星的位置,然后我正在缩放和旋转它。有一个更好的方法吗?我的目标是根据视图位置渲染图像,不需要图层。
  • 我不明白:您同时使用ImageViews 和Canvas#drawBitmap,这是为了什么?只需使用自定义视图和Canvas#drawBitmap,您就可以控制一切,几乎不需要额外的逻辑
  • 就我个人而言,我会分叉该库并删除它使用的任何 ImageViews 并替换为原始的低级别 Bitmaps - 如果您想同时使用它们,您将永远无法获得像素完美的解决方案

标签: android scale android-canvas android-view android-bitmap


【解决方案1】:

我自己设法解决了这个问题。 结果证明我的解决方案几乎没问题,但我没有考虑到我对矩阵的操作确实改变了原始点的排列,所以我的

rootView.getWidth() / 2,
rootView.getHeight() / 2

在调用Matrix.postScaleMatrix.postRotation 后不再适用于作为视图的中心。

我想:

  • 应用比例,枢轴位于左上角,
  • 应用旋转,以视图中心为轴。

鉴于假设,这里是工作代码:

    // setup variables for sizing and transformation
    float position[] = new float[2];
    transformToAncestor(position, rootView, imageView);
    float desiredRotation = imageView.getRotation();
    float sizeDeltaX = imageView.getMeasuredWidth() / (float) imageBitmap.getWidth();
    float sizeDeltaY = imageView.getMeasuredHeight() / (float) imageBitmap.getHeight();
    float desiredScaleX = imageView.getScaleX() * sizeDeltaX * scaleX;
    float desiredScaleY = imageView.getScaleY() * sizeDeltaY * scaleY;
    float imageViewWidth = imageView.getMeasuredWidth() * imageView.getScaleX();
    float imageViewHeight = imageView.getMeasuredHeight() * imageView.getScaleY();

    float rootViewWidth = rootView.getMeasuredWidth();
    float rootViewHeight = rootView.getMeasuredHeight();
    float percentXPos = position[0] / rootViewWidth;
    float percentYPos = position[1] / rootViewHeight;
    float percentXCenterPos = (position[0] + imageViewWidth/2)
            / rootViewWidth;
    float percentYCenterPos = (position[1] + imageViewHeight/2)
            / rootViewHeight;

    float desiredPositionX = background.getWidth() * percentXPos;
    float desiredPositionY = background.getHeight() * percentYPos;
    float desiredCenterX = background.getWidth() * percentXCenterPos;
    float desiredCenterY = background.getHeight() * percentYCenterPos;

    // apply above variables to matrix
    Matrix matrix = new Matrix();
    float[] points = new float[2];
    matrix.postTranslate(
            desiredPositionX,
            desiredPositionY);

    matrix.mapPoints(points);
    matrix.postScale(
            desiredScaleX,
            desiredScaleY,
            points[0],
            points[1]);

    matrix.postRotate(
            desiredRotation,
            desiredCenterX,
            desiredCenterY);

    // apply matrix to bitmap, then draw it on canvas
    canvas.drawBitmap(imageBitmap, matrix, paint);

如您所见,mapPoints 方法是我问题的答案 - 它只是在 转换之后返回点。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-07
    • 1970-01-01
    • 1970-01-01
    • 2013-07-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多