使用GLSurfaceView Android实现旋转和捏合缩放的图像效果

7

我正在开发一个应用程序,为图像应用效果/旋转/缩放功能。我已经从https://github.com/Grishu/ImageEffects下载了演示应用程序。

它运行良好,现在我的问题/疑问如下:

  1. Apply multiple effects on images with progress change value (e.g. First apply brightness effect and result of this apply another effect say "contrast".)

    - problem: in code effect always apply on original image. So change in code to apply effect on final image like,

    if(isApplyEffectOnOriginalImage){//call first time only         
        mEffect.apply(mTextures[0], mImageWidth, mImageHeight, mTextures[1]);
    }else{
        mEffect.apply(mTextures[1], mImageWidth, mImageHeight, mTextures[1]);
    }
    

    Now, if apply brightness effect on progress change first time it works fine. But if I apply the same or other(contrast) effect, now I think on progress change effect apply on mTextures[1] and result set in mTextures[1], so is it possible to create temporary mTextures[2] to store mTextures[1] initially and when user change the progress value apply effect on mTextures[2] and set result on mTextures[1] like happen in if condition.

  2. How to apply pinch to zoom on images

  3. Rotation issue: I was rotating image at 90 angle clockwise, just by setting values(90,180,270, etc.), but the problem is when rotating image from 90 to 180, image rendering is not properly. see

A) 0度角图像

0度角图像

B) 90度角图像

90度角图像

C) 180度角图像

180度角图像

1个回答

5
我修改了Grishu的演示项目:这里是屏幕录制,然后进行一些解释:

(图像旋转,并应用三种效果 - 水平翻转,交叉处理,鱼眼)

1) 对于在结果上应用效果,您的建议很好。我不太明白您所说的“进度更改效果”。您是否想调整效果的参数?

2) 要使用手势,您需要扩展GLSurfaceView并实现GestureDetector.OnGestureListener和/或ScaleGestureDetector.OnScaleGestureListener,具体取决于您的需求。请参见此处的TouchGLView:源代码或下面的代码片段:

private class TouchGLView extends GLSurfaceView
        implements GestureDetector.OnGestureListener,
        ScaleGestureDetector.OnScaleGestureListener {
    private TextureRenderer mRenderer;
    private GestureDetector mTapDetector;
    private ScaleGestureDetector mScaleDetector;
    private float mLastSpan = 0;

    TouchGLView(Context c) {
        super(c);
        // Use Android's built-in gesture detectors to detect
        // which touch event the user is doing.
        mTapDetector = new GestureDetector(c, this);
        mTapDetector.setIsLongpressEnabled(false);
        mScaleDetector = new ScaleGestureDetector(c, this);

        // Create an OpenGL ES 2.0 context.
        setEGLContextClientVersion(2);
        mRenderer = new TextureRenderer(c);
        setRenderer(mRenderer);
    }
    @Override
    public boolean onTouchEvent(final MotionEvent e) {
        // Forward touch events to the gesture detectors.
        mScaleDetector.onTouchEvent(e);
        mTapDetector.onTouchEvent(e);
        return true;
    }
    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2,
                            final float dx, final float dy) {
        // Forward the drag event to the renderer.
        queueEvent(new Runnable() {
            public void run() {
                mRenderer.drag(dx, dy);
            }});
        return true;
    }
    @Override
    public boolean onScale(ScaleGestureDetector detector) {
        // Forward the scale event to the renderer.
        final float amount = detector.getCurrentSpan() - mLastSpan;
        queueEvent(new Runnable() {
            public void run() {
                mRenderer.zoom(amount);
            }});
        mLastSpan = detector.getCurrentSpan();
        return true;
    }
    ...
}

3) 通过修改顶点坐标并考虑视口,您可以旋转图像。此外,您可以应用不同的旋转。您可以旋转(和缩放)视图(顶点坐标)本身(这不会影响原始纹理缓冲区),或者您可以在纹理缓冲区中旋转像素(对于90°、180°等很容易实现),然后更新顶点坐标以匹配新的图像宽度/高度。

以下是操作顶点坐标的示例:

private void computeOutputVertices() {
    if (mPosVertices != null) {
        float imgAspectRatio = mTexWidth / (float)mTexHeight;
        float viewAspectRatio = mViewWidth / (float)mViewHeight;
        float x0, y0, x1, y1;
        // Set initial vertex coords based in texture aspect
        if (imgAspectRatio > 1.0f) {
            x0 = -1.0f ;
            y0 = -1.0f / imgAspectRatio;
            x1 = 1.0f ;
            y1 = 1.0f / imgAspectRatio;
        } else {
            x0 = -1.0f *imgAspectRatio;
            y0 = -1.0f;
            x1 = 1.0f *imgAspectRatio;
            y1 = 1.0f;
        }
        float[] coords = new float[] { x0, y0, x1, y0, x0, y1, x1, y1 };
        // Scale coordinates with mZoom
        for (int i = 0; i < 8; i++) {
            coords[i] *= mZoom;
        }
        // Rotate coordinates with mRot
        float cosa = (float)Math.cos(mRot);
        float sina = (float)Math.sin(mRot);
        float x,y;
        for (int i = 0; i < 8; i+=2) {
            x = coords[i]; y = coords[i+1];
            coords[i]   = cosa*x-sina*y;
            coords[i+1] = sina*x+cosa*y;
        }
        // Finally scale again to match screen aspect
        if (viewAspectRatio > 1.0f) {
            for (int i = 0; i < 8; i+=2) {
                coords[i] = coords[i]/viewAspectRatio;
            }
        } else {
            for (int i = 1; i < 8; i+=2) {
                coords[i] = coords[i]*viewAspectRatio;
            }
        }
        mPosVertices.put(coords).position(0);
    }
}

我建议您深入了解OpenGL矩阵,并使用它们进行所有这些变换。

我已修改TextureRenderer类以实现GLSurfaceView.Renderer,并将renderMode更改为RENDERMODE_CONTINUOUSLY

最后,修改后的演示源代码在此处


1
首先感谢您的回复。 1)是否可以在SeekBar进度更改时应用效果?当我从“mTextures [0]”到“mTextures [1]”应用效果并渲染textureId“mTextures [1]”时,它第一次工作。第一次应用效果后,如果在SeekBar进度更改时应用第二个效果,例如“CONTRAST”,则效果将从“mTextures [1]”应用到“mTextures [1]”,并且渲染textureId“mTextures [1]”。您会注意到图像将变黑。 - Hiren Dabhi
1
  1. 我认为如果我将“mTextures [1]”作为新纹理重复使用,就可以解决我的问题,但是不知道如何重新使用它。
  2. 捏合缩放:效果很好,但滚动图像时会出现问题。有什么想法吗?
  3. 旋转:效果很好。是否可以使用内置的顺时针旋转效果(90、180、270...)来应用旋转?
- Hiren Dabhi
旋转和缩放效果良好,但拖拽无法使用...该如何解决。 - Bhavin Patel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接