В этой статье мы хотели бы предложить вниманию читателей пошаговый алгоритм создания простого фоторедактора, который может оказаться полезными для приложений, предполагающих взаимодействие пользователя с изображениями. Он будет включать в себя самые базовые функции, давая возможность вносить небольшие корректировки: затереть определенную область (например, ник), выделить важный текст (телефон, адрес или просто цитату), обвести какую либо область на карте или «нарисовать слово». С технической точки зрения, тема довольно избитая, но мы нашли способ модифицировать процесс, сделав его быстрее и проще — возможно, кто-то возьмет на заметку.
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
NSSet *allTouches = [event allTouches];
if (allTouches.count != 1){
return;
}
UITouch *touch = [[allTouches allObjects] objectAtIndex:0];
pointTo = [touch locationInView:self];
}
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[super touchesMoved:touches withEvent:event];
NSSet *allTouches = [event allTouches];
if (allTouches.count != 1){
[linePaint removeAllObjects];
[self setNeedsDisplay];
return;
}
UITouch *touch = [[allTouches allObjects] objectAtIndex:0];
pointFrom = pointTo;
pointTo = [touch locationInView:self];
if (pointTo.y < self.bounds.size.height && pointFrom.y < self.bounds.size.height) {
[self addLineFrom:pointFrom to:pointTo];
}
}
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[super touchesEnded:touches withEvent:event];
NSSet *allTouches = [event allTouches];
if (allTouches.count != 1){
[linePaint removeAllObjects];
[self setNeedsDisplay];
return;
}
UITouch *touch = [[allTouches allObjects] objectAtIndex:0];
pointFrom = pointTo;
pointTo = [touch locationInView:self];
if (pointTo.y < self.bounds.size.height && pointFrom.y < self.bounds.size.height) {
[self addLineFrom:pointFrom to:pointTo];
}
imgForPaint = [self getImage:imgForPaint];
dispatch_async(dispatch_get_main_queue(), ^{
if (_imageAfterEndPaint) {
_imageAfterEndPaint(imgForPaint);
}
});
}
- (UIBezierPath*)getBezuerPathWith:(float)zoom {
UIBezierPath *bezierPath = [[UIBezierPath alloc] init];
float width = zoom * _lineWidth / 2.;
for (PaintLine *line in linePaint) {
CGPoint point1 = CGPointApplyAffineTransform(line.point1, CGAffineTransformMakeScale(zoom, zoom));
CGPoint point2 = CGPointApplyAffineTransform(line.point2, CGAffineTransformMakeScale(zoom, zoom));
[bezierPath moveToPoint:point1];
float alf = atan2(point2.y - point1.y, point2.x - point1.x);
[bezierPath addArcWithCenter:point1 radius:width startAngle:alf + M_PI_2 endAngle:alf - M_PI_2 clockwise:YES];
float alf0 = alf - M_PI_2;
CGPoint point = CGPointMake(cos(alf0) * width + point2.x, sin(alf0) * width + point2.y);
[bezierPath addLineToPoint:point];
[bezierPath addArcWithCenter:point2 radius:width startAngle:alf - M_PI_2 endAngle:alf + M_PI_2 clockwise:YES];
alf0 = alf + M_PI_2;
point = CGPointMake(cos(alf0) * width + point1.x, sin(alf0) * width + point1.y);
[bezierPath addLineToPoint:point];
}
return bezierPath;
}
[colorQueue addObject:[NSValue valueWithCGPoint:newStartPoint]];
int offset = 4*((w*round(newStartPoint.y))+round(newStartPoint.x)) + 1;
memcpy(colorFroUpdate, &data[offset], 3);
float limit = 10;
isCanPaint = !(abs(newColorArray[0] - data[offset]) < limit && abs(newColorArray[1] - data[offset + 1]) < limit && abs(newColorArray[2] - data[offset + 2]) < limit);
NSInteger countPixelICurrentIterrations = 1;
int iterrationIndex = 1;
while (isCanPaint && colorQueue.count > 0) {
CGPoint point = [[colorQueue objectAtIndex:0] CGPointValue];
[colorQueue removeObjectAtIndex:0];
countPixelICurrentIterrations--;
offset = 4*((w*round(point.y))+round(point.x)) + 1;
memcpy(&data[offset], newColorArray, 3);
CGPoint newPoint;
int x0 = point.x - 1;
int x1 = point.x + 1;
int y0 = point.y - 1;
int y1 = point.y + 1;
for (int x = x0; x <= x1; x++) {
for (int y = y0; y <= y1; y++) {
float s = sqrtf((x - newStartPoint.x) * (x - newStartPoint.x) + (y - newStartPoint.y) * (y - newStartPoint.y));
if (s < iterrationIndex + 1) {
newPoint = CGPointMake(x, y);
if (newPoint.x >= 0 && newPoint.x < w && newPoint.y >= 0 && newPoint.y < h) {
offset = 4*((w*round(newPoint.y))+round(newPoint.x)) + 1;
if (abs(colorFroUpdate[0] - data[offset]) < limit && abs(colorFroUpdate[1] - data[offset + 1]) < limit && abs(colorFroUpdate[2] - data[offset + 2]) < limit) {
memcpy(&data[offset], newColorArray, 3);
[colorQueue addObject:[NSValue valueWithCGPoint:newPoint]];
}
}
}
}
}
if (countPixelICurrentIterrations <= 0 && self.updateImageOn) {
if (iterrationIndex % 5 == 0)
@autoreleasepool {
CGImageRef cgImage = CGBitmapContextCreateImage(cgctx);
UIImage *resultUIImage = [UIImage imageWithCGImage:cgImage];
self.updateImageOn(resultUIImage);
CGImageRelease(cgImage);
}
countPixelICurrentIterrations = [colorQueue count];
iterrationIndex++;
}
}
}
К сожалению, не доступен сервер mySQL