Function effect

The demo sample

Functional analysis

  • Function: Render an incoming image -> Select edit area manually -> Use slider to edit area to increase or decrease

  • OpenGL principle:

    • Because OpenGL can only draw triangles, so when processing images or graphics, we need to divide the object to be processed by triangular lines into objects composed of triangles and vertices.

    • So in OpenGL the coordinates are starting from the lower left corner positive X up, positive Y to the right

Function implementation

  • Split image:

    • Split method 1: it can be seen from the graph that it is a rectangle, and the rectangle can be divided into two triangles and four vertices, through which the image can be rendered with GL.


      Split triangle


      So after break up can be normal rendering, but the problem is my four vertices are dead, that is the four vertices must be canvas four vertices, after change the coordinates of vertices can only lead to changes in the whole piece of canvas, instead of a certain area, the change of the whole picture if it’s a stretch of stretching, so want to realize local processing this segmentation approach is not feasible.

    • Splitting method 2: Split the whole picture into three rectangles first, and then split each rectangle into two triangles to obtain six triangles and eight vertices, as shown below:


      Break up 2


      So that can ensure that the height of the rectangle in the middle of the can arbitrarily change and the height of the fluctuation two parts the same only change position, that is to say we are doing the DEMO any drawing operations are to the operation of the intermediate rectangle, in other words is to change the top of the rectangular on the bottom of the rectangle and the distance between the to achieve the purpose of the middle area of tensile and compression. We create an array with the coordinates of the vertices according to the split method

// Vertex array GLfloatAre [] = {1.2, 1.2, / / lower left 1.2, 1.2, / / right - 1.2, 0.4, / / small rectangular bottom left 1.2, 0.4, / / small rectangular right - 1.2, 0.4, / / small rectangular upper left 1.2, 0.4, // Top right rectangle -1.2, 1.2, // top left 1.2, 1.2, // top right}; // Fill the texture array GLfloatTexCoords [] = {0, 0, // lower left // subscript 0 1 1, 0, // lower right // subscript 2 30 0, 1.0/3.0, // lower left // subscript 4 5 1, 1.0/3.0, // lower right // subscript 6 7 0, 2.0/3.0, // top left corner of small rectangle // subscript 8 9 1, 2.0/3.0, // top left corner of small rectangle // subscript 10 11 0, 1, // top left // subscript 12 13 1, 1, // top right // subscript 14 15};Copy the code
  • Manual selection: Drag to modify the selection by adding a UIView with custom gestures.
* * * * * * * * * * * * * * * * * CustomPanView code * * * * * * * * * * * * * * * * * *#import <UIKit/UIKit.h>@protocol CustomPanViewDelegate <NSObject> /** * Start dragging ** @param customPanView itself * @Param centerY its y coordinate */ - (void)beginDragWithCoustomPanView:(UIView *)customPanView centerY:(CGFloat)centerY; @end @interface CustomPanView : UIView @property (nonatomic, assign) id<CustomPanViewDelegate> delegate; @endCopy the code
* * * * * * * * * * * * * * * * * CustomPanViewDelegate code * * * * * * * * * * * * * * * * * *#pragma mark -
Pragma mark drags the View's proxy method- (void) beginDragWithCoustomPanView: (UIView *) customPanView centerY: (CGFloat) centerY {/ / limits: cutting area cannot be greater than the picture areaif (customPanView.center.y >= imageBottom) {
        customPanView.center = CGPointMake(customPanView.center.x, imageBottom);
    }
    if(customPanView.center.y <= imageTop) { customPanView.center = CGPointMake(customPanView.center.x, imageTop); } // Get the coordinates of the two lines CGFloat topY = _topview.center.y; CGFloat bottomY = _bottomView.center.y; // Refresh the clipping area UI [_cutLabel according to the coordinates of the two linessetFrame:CGRectMake(0, topY < bottomY ? topY : bottomY, SCREEN_WIDTH, fabs(bottomY - topY))]; CGFloat fromPoint = topY < bottomY? (imageBottom - bottomY) / imageHeight : (imageBottom - topY) / imageHeight; CGFloat toPoint = topY < bottomY ? (imageBottom - topY) / imageHeight : (imageBottom - bottomY) / imageHeight; // Associate the vertex coordinates of the middle rectangle with the coordinate associated clipping area. [self sendFromePoint:fromPoint endPoint:toPoint];if(_cutLabel. Frame. The size, height < 30) {/ / hide text _cutLabel. Text = @"";
    } else {
        _cutLabel.text = @"Edit area";
    }

    [self.slider setValue: 0.0 animated: YES]; TmpHeight = 0.0 f; }Copy the code

Use a Delegate to return the dragged y-coordinate, because we only care about the y-coordinate because we’re moving vertically.

  • Change the size: change the vertex coordinates by associating the ValueChange of UISliderBar with the vertex coordinates, and then call the display method of GLKView to refresh the UI and show the change process.
- (void)action (UISlider *)sender {isRightDirection = sender.value >= judgeDirection? YES : NO; ChangeHeight = sender. Value - tmpHeight; // go through the number groupfor(int i = 0; i < 16; // Filter out the Y coordinatesif(i % 2 ! = 0) {// Lower half of the rectangleifVerticesCopy [I] -changeheight; verticesCopy[I] -changeheight; verticesCopy[I] -changeheight; // top half of rectangle}else ifVerticesCopy [I] + changeHeight; verticesCopy[I] = verticesCopy[I] + changeHeight; }}} // If the edit area has become a line during zooming, it cannot be zoomed outif(vertices[11] > vertices[7]) { [self.glView display]; }}Copy the code
  • To read pixel data from memory via glReadPixels, GLubyte -> CGImageRef -> UIimage and most relevant save or other operations.
#pragma mark -
#pragma Mark gets the processed image
- (UIImage *) createImage {

    int imageY = 0;

    int imgHeight = 0;

    ifImageY = fabs(imageTop - Fabs (changeHeight * perOpengleseCoordinate)) * screenScale; imgHeight = fabs(imageHeight + 2 * fabs(changeHeight * perOpengleseCoordinate)) * screenScale; }else{ imageY = fabs(imageTop + fabs(changeHeight * perOpengleseCoordinate)) * screenScale; imgHeight = fabs(imageHeight - 2 * fabs(changeHeight * perOpengleseCoordinate)) * screenScale; } int imageWidth = SCREEN_WIDTH * screenScale; int dataLength = imageWidth * imgHeight * 4; GLubyte *data = (GLubyte*)malloc(dataLength * sizeof(GLubyte)); glPixelStorei(GL_PACK_ALIGNMENT, 4); glReadPixels(0, imageY, imageWidth, imgHeight, GL_RGBA, GL_UNSIGNED_BYTE, data); / / read from the memory pixel CGDataProviderRef ref = CGDataProviderCreateWithData (NULL, data, dataLength, NULL); CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB(); CGImageRef iref = CGImageCreate(imageWidth, imgHeight, 8, 32, imageWidth * 4, colorspace, kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast,ref, NULL,true, kCGRenderingIntentDefault);

    UIGraphicsBeginImageContext(CGSizeMake(imageWidth, imgHeight));
    CGContextRef cgcontext = UIGraphicsGetCurrentContext();
    CGContextSetBlendMode(cgcontext, kCGBlendModeCopy);
    CGContextDrawImage(cgcontext, CGRectMake(0, 0, imageWidth, imgHeight), iref);

    CGImageRef imageMasked = CGBitmapContextCreateImage(cgcontext);
    UIImage * image = [UIImage imageWithCGImage:imageMasked scale:screenScale orientation:UIImageOrientationUp];
    UIGraphicsEndImageContext();

    free(data);
    CFRelease(ref);
    CFRelease(colorspace);
    CGImageRelease(iref);

    return image;

}Copy the code

I Jane books of synchronous updating oh www.jianshu.com/u/fd21f41fb…