Android中的万花筒效果

时间:2016-12-08 05:31:43

标签: java android matrix

我正在尝试在Android中使用ImageView创建一个Kaleidoscope。我正在努力让每个'段'的旋转和镜像正确。我是图像处理的新手,我正在尝试使用here的代码示例来修改android。

我有以下代码:

private void drawKaleidoscope() {

    Bitmap bm               = BitmapFactory.decodeResource(getResources(), R.drawable.cropped_landscape);
    Bitmap imageview_bitmap = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(), Bitmap.Config.ARGB_8888);  
    Bitmap matrix_bitmap;
    BitmapShader fillShader;

    Path triangle_mask    = new Path();
    RectF r               = new RectF(0, 0, bm.getWidth(), bm.getHeight()); // create new rectangle to match the dimensions of our image
    this.radius           = (int)r.height() / 2;

    Canvas c = new Canvas(imageview_bitmap);
    c.drawColor(Color.BLACK);


    float start_angle = 0;


    for (int i = 0; i < this.segments; i++) {

        // Create pie-slice shape mask
        triangle_mask.reset();
        triangle_mask.moveTo(r.centerX(), r.centerY());
        triangle_mask.arcTo(r, start_angle, angle);
        triangle_mask.close();


        // Use odd even check to decide when to mirror the image or not
        if (i % 2 == 0) {

            Matrix mat = new Matrix();
            mat.preTranslate(-radius, -radius);
            mat.postRotate(i * angle);
            mat.postTranslate(radius, radius);

            matrix_bitmap = Bitmap.createBitmap(bm, 0, 0, (int)r.width(), (int)r.height(), mat, true);
        }
        else {

            Matrix mat = new Matrix();

            // mirror on x axis
            mat.postScale(-1, 1);

            mat.postTranslate(-radius, radius);
            mat.postRotate((float)-Math.PI);
            mat.postRotate(i * angle);
            mat.postTranslate(radius, -radius);


            matrix_bitmap = Bitmap.createBitmap(bm, 0, 0, (int)r.width(), (int)r.height(), mat, true);
        }

        fillShader = new BitmapShader(matrix_bitmap, Shader.TileMode.MIRROR, Shader.TileMode.MIRROR);


        // Fill the triangle masked area with our image now
        Paint fill = new Paint();
        fill.setColor(0xFFFFFFFF);
        fill.setStyle(Paint.Style.FILL);
        fill.setShader(fillShader);

        c.drawPath(triangle_mask, fill);
        start_angle += angle;
    }


    kal.setImageBitmap(imageview_bitmap);
}

上述函数的输出如下:

enter image description here

如果有人能够提供一些有关如何正确执行图像旋转/镜像的信息,那将非常感激。

1 个答案:

答案 0 :(得分:1)

好的,我最终以不同的方式进行了这项工作。而不是旋转源图像我只是将图像蒙版绘制到画布上的相同点,然后旋转画布本身。假设我有12个图像'切片'。我绘制了6个交替的段,通过canvas.scale(-1,1)翻转画布,然后在空格所在的位置绘制另外6个段。这是我最终得到的代码:

private Bitmap generateKaleidoscopeBitmap(float start_angle) {

    Canvas canvas = new Canvas(imageview_bitmap);
    canvas.drawColor(Color.BLACK);
    BitmapShader fillShader;

    Path triangle_mask    = new Path();
    RectF r               = new RectF(0, 0, imageview_bitmap.getWidth(), imageview_bitmap.getHeight()); // create new rectangle to match the dimensions of our image

    int centerX = imageview_bitmap.getWidth() / 2;
    int centerY = imageview_bitmap.getHeight() / 2;

    // how much to rotate the canvas by after the image is flipped
    float offset = calculateCanvasSymmetryOffset(start_angle);


    // Create a pie-slice shaped clipping mask
    triangle_mask.moveTo(r.centerX(), r.centerY());
    triangle_mask.arcTo(r, start_angle, angle);
    triangle_mask.close();


    // Fill the triangle masked area with our shader now
    Paint fill = new Paint();
    fill.setColor(0xFFFFFFFF);
    fill.setStyle(Paint.Style.FILL);
    fillShader = new BitmapShader(source_image, Shader.TileMode.MIRROR, Shader.TileMode.MIRROR);
    fill.setShader(fillShader);


    // Rotate the canvas and draw the clipping mask to the canvas
    for (int i = 0; i < this.segments / 2; i++) {

        canvas.drawPath(triangle_mask, fill);
        canvas.rotate(angle * 2, centerX, centerY);
    }


    // mirror the canvas and rotate it once to counter the symmetrical offset
    canvas.scale(-1, 1, centerX, centerY);
    canvas.rotate(offset, centerX, centerY);


    // Rotate the now mirrored canvas and draw the clipping mask to it
    // This is a cheap and easy way of creating mirrored segments
    for (int i = 0; i < this.segments / 2; i++) {

        canvas.drawPath(triangle_mask, fill);
        canvas.rotate(angle * 2, centerX, centerY);
    }

    return imageview_bitmap;
}