生成自适应背景图片

前言

有些时候,我们需要批量替换产品运营图片,比如添加logo,水印,或者改变图片尺寸,与其他背景图片合并等。

效果

效果图

实现

在图片上下文里面,我们需要合并背景图外,还需要添加从左到右的渐变,添加随机圆形,画一条曲线。
为了不太突兀,在原图里面获取像素点的色值来作为渐变色、圆形填充色以及贝塞尔曲线的填充色。

获取图片色值

先解压图片获取原始像素点数值,需要注意的是,它的坐标系和view的坐标系统不一样,左下为坐标零点。

- (NSArray<UIColor*> *)randomPixelColorWithImage:(UIImage *)image
                            colorCount:(NSInteger)colorCount{
    CGImageRef imageRef = CGImageCreateCopy([image CGImage]);
    size_t imageWidth = CGImageGetWidth(imageRef);
    size_t imageHeight = CGImageGetHeight(imageRef);
    size_t bytesPerRow = imageWidth * 4;
    uint32_t* rgbImageBuf = (uint32_t*)malloc(bytesPerRow * imageHeight);
    CGContextRef context = CGBitmapContextCreate(rgbImageBuf, imageWidth, imageHeight, 8, bytesPerRow, CGColorSpaceCreateDeviceRGB(),kCGImageAlphaPremultipliedFirst);
    CGContextDrawImage(context, CGRectMake(0, 0, imageWidth, imageHeight), imageRef);
    size_t pixelNum = imageWidth * imageHeight;
    
    NSMutableArray *colors = [NSMutableArray array];
    
    uint32_t* pCurPtr = rgbImageBuf;
    uint8_t *ptr = (uint8_t *)pCurPtr;
    float red = ptr[1]; float green = ptr[2]; float blue = ptr[3];
    [colors addObject:[UIColor colorWithRed:red/255 green:green/255 blue:blue/255 alpha:1.0]];
    
    ptr = (uint8_t *)pCurPtr+4*pixelNum-20;
    float endRed = ptr[1];float endGreen = ptr[2]; float endBlue = ptr[3];
    [colors addObject:[UIColor colorWithRed:endRed/255 green:endGreen/255 blue:endBlue/255 alpha:1.0]];
    
     float middleRed = (red+endRed)/2;float middleGreen = (endGreen+green)/2; float middleBlue = (endBlue+blue)/2;
    [colors addObject:[UIColor colorWithRed:middleRed/255 green:middleGreen/255 blue:middleBlue/255 alpha:1.0]];
    
    for (int i = 0; i < colorCount - 1; i++) {
        int wave = 40;
        int random = arc4random()%2;
        int redWave = ( random == 0)?arc4random()%wave:-arc4random()%wave;
        int greenWave = (random == 0)?arc4random()%wave:-arc4random()%wave;
        int blueWave = (random == 0)?arc4random()%wave:-arc4random()%wave;
        [colors addObject:[UIColor colorWithRed:MIN(245, MAX(10, redWave+middleRed))/255 green:MIN(245, MAX(10, greenWave+middleGreen))/255 blue:MIN(245, MAX(10, blueWave+middleBlue))/255 alpha:1.0]];//第一个和中间像素点中间值为基准
    }
    
    CGContextRelease(context);
    free(rgbImageBuf);
    CGImageRelease(imageRef);
    return colors;
}
绘制各个元素

绘制各种元素在同一个上下文中执行,除了添加以下元素,也可添加其他形状或者图片,最后合成一张图片。
CGImageRef并不是自动释放的,需要手动释放声明的变量。

UIImage *pic = [UIImage imageNamed:@"tape1a_000004_title"];
self.orignalImageView.image = pic;
CGImageRef bgImageRef = [UIImage imageNamed:@"bg"].CGImage;
NSArray *randomColors = [self randomPixelColorWithImage:pic colorCount:6];//第一个像素点颜色
UIImage *combineImage = [self createImageWithClassImage:pic bgImageRef:bgImageRef bgColor:randomColors.firstObject randomColors:randomColors];
self.combineImageView.image = combineImage;
- (UIImage *)createImageWithClassImage:(UIImage *)image
                            bgImageRef:(CGImageRef)bgImageRef
                                bgColor:(UIColor *)bgColor
                           randomColors:(NSArray<UIColor*>*)randomColor{
    CGImageRef imageRef = CGImageCreateCopy([image CGImage]);
    size_t bgWidth = CGImageGetWidth(bgImageRef);
    size_t bgHeight = CGImageGetHeight(bgImageRef);
    CGContextRef context = CGBitmapContextCreate(NULL, bgWidth, bgHeight, 8, 0, CGColorSpaceCreateDeviceRGB(), kCGImageAlphaPremultipliedFirst);
    if (!context) return NULL;
    
    CGContextSetFillColorWithColor(context, bgColor.CGColor);
    //填充背景色
//    CGContextFillRect(context,CGRectMake(0, 0, bgWidth, bgHeight));
    //填充渐变背景色
    CGFloat gradientLocations[] = { 1.0, 0.0 };
    NSArray *gradientColors = @[(__bridge id) [randomColor[1] colorWithAlphaComponent:0.9].CGColor, (__bridge id) [randomColor[0] colorWithAlphaComponent:0.5].CGColor];
    CGGradientRef gradient = CGGradientCreateWithColors(CGColorSpaceCreateDeviceRGB(), (__bridge CFArrayRef) gradientColors, gradientLocations);
    CGContextDrawLinearGradient(context, gradient, CGPointZero, CGPointMake(bgWidth, bgHeight), kCGGradientDrawsBeforeStartLocation);
    
    [self drawArcWithFillColor:randomColor[3] context:context];//画圆
    [self drawArcWithFillColor:randomColor[4] context:context];
    [self drawArcWithFillColor:randomColor[5] context:context];
    [self drawArcWithFillColor:randomColor[6] context:context];
    
    [self drawTopBezierLineFillColor:randomColor[2] context:context];
    
    CGContextDrawImage(context, CGRectMake(0, 0, bgWidth, bgHeight), bgImageRef); // decodeif (!context) return NULL;
    CGContextDrawImage(context, CGRectMake(180*4-9, (bgHeight-137*4)/2, 96*4, 137*4), imageRef); // decodeif (!context) return NULL;
    CGImageRef newImageRef = CGBitmapContextCreateImage(context);
    UIImage *combineImage = [UIImage imageWithCGImage:newImageRef];
    CFRelease(context);
    CGImageRelease(imageRef);
    CGImageRelease(newImageRef);
    return combineImage;
}
//画圆
- (void)drawArcWithFillColor:(UIColor *)fillColor
                     context:(CGContextRef)context {
    CGContextSetFillColorWithColor(context, fillColor?[fillColor colorWithAlphaComponent:0.6].CGColor:[UIColor colorWithRed:1.0 green:0 blue:0 alpha:0.2].CGColor);
    CGContextAddArc(context, arc4random()%1280, arc4random()%720, arc4random()%70+30, 0, M_PI*2, 0);
    CGContextFillPath(context);
}
//上边边画贝塞尔曲线
- (void)drawBottomBezierLineFillColor:(UIColor *)fillColor
                            context:(CGContextRef)context{
    UIBezierPath *bezierPath = [UIBezierPath bezierPath];
    NSMutableArray *points = [NSMutableArray array];
    CGPoint auxiliaryStartPoint = CGPointMake(-130, -100); //作为曲线的辅助点
    [points addObject:[NSValue valueWithCGPoint:auxiliaryStartPoint]];
    CGPoint startPoint = CGPointMake(0, -50);
    [points addObject:[NSValue valueWithCGPoint:startPoint]];
    
    CGFloat startx = 0;
    for (int i = 0; i < 6; i++) {
        startx = startx + 200+arc4random()%100;
        CGFloat valueY = arc4random()%70+80;
        if(i%2 == 1) {
            valueY = arc4random()%50;
        }
        [points addObject:[NSValue valueWithCGPoint:CGPointMake(startx, valueY)]];
    }
    [points addObject:[NSValue valueWithCGPoint:CGPointMake(startx+130, -50)]];//曲线辅助点
    
    for (NSInteger i = 0; i < points.count-3; i++) {
        CGPoint p1 = [[points objectAtIndex:i] CGPointValue];
        CGPoint p2 = [[points objectAtIndex:i+1] CGPointValue];
        CGPoint p3 = [[points objectAtIndex:i+2] CGPointValue];
        CGPoint p4 = [[points objectAtIndex:i+3] CGPointValue];
        if (i == 0) {
            [bezierPath moveToPoint:p2];
        }
        [self getControlPointx0:p1.x andy0:p1.y x1:p2.x andy1:p2.y x2:p3.x andy2:p3.y x3:p4.x andy3:p4.y path:bezierPath];
    }
    [bezierPath addLineToPoint:[[points objectAtIndex:points.count-1] CGPointValue]];//加上最后的曲线辅助点
    [bezierPath addLineToPoint:startPoint];//合闭曲线
    
    CGContextSetFillColorWithColor(context, fillColor?[fillColor colorWithAlphaComponent:0.4].CGColor:[UIColor colorWithRed:1.0 green:0 blue:0 alpha:0.2].CGColor);
    CGContextAddPath(context, bezierPath.CGPath);
    CGContextFillPath(context);
    
}
/*
 * 计算平滑点
 */
- (void)getControlPointx0:(CGFloat)x0 andy0:(CGFloat)y0
                       x1:(CGFloat)x1 andy1:(CGFloat)y1
                       x2:(CGFloat)x2 andy2:(CGFloat)y2
                       x3:(CGFloat)x3 andy3:(CGFloat)y3
                     path:(UIBezierPath*) path{
    CGFloat smooth_value =0.6;//平滑度,大多数是0.6 效果相对更好
    CGFloat ctrl1_x;
    CGFloat ctrl1_y;
    CGFloat ctrl2_x;
    CGFloat ctrl2_y;
    CGFloat xc1 = (x0 + x1) /2.0;
    CGFloat yc1 = (y0 + y1) /2.0;
    CGFloat xc2 = (x1 + x2) /2.0;
    CGFloat yc2 = (y1 + y2) /2.0;
    CGFloat xc3 = (x2 + x3) /2.0;
    CGFloat yc3 = (y2 + y3) /2.0;
    CGFloat len1 = sqrt((x1-x0) * (x1-x0) + (y1-y0) * (y1-y0));
    CGFloat len2 = sqrt((x2-x1) * (x2-x1) + (y2-y1) * (y2-y1));
    CGFloat len3 = sqrt((x3-x2) * (x3-x2) + (y3-y2) * (y3-y2));
    CGFloat k1 = len1 / (len1 + len2);
    CGFloat k2 = len2 / (len2 + len3);
    CGFloat xm1 = xc1 + (xc2 - xc1) * k1;
    CGFloat ym1 = yc1 + (yc2 - yc1) * k1;
    CGFloat xm2 = xc2 + (xc3 - xc2) * k2;
    CGFloat ym2 = yc2 + (yc3 - yc2) * k2;
    ctrl1_x = xm1 + (xc2 - xm1) * smooth_value + x1 - xm1;
    ctrl1_y = ym1 + (yc2 - ym1) * smooth_value + y1 - ym1;
    ctrl2_x = xm2 + (xc2 - xm2) * smooth_value + x2 - xm2;
    ctrl2_y = ym2 + (yc2 - ym2) * smooth_value + y2 - ym2;
    [path addCurveToPoint:CGPointMake(x2, y2) controlPoint1:CGPointMake(ctrl1_x, ctrl1_y) controlPoint2:CGPointMake(ctrl2_x, ctrl2_y)];
}

计算平滑点,可阅读画贝塞尔曲线 连续曲线 平滑曲线 曲线图表

批量绘制

到这基本算是完成了,对于图片比较多的情况,需要在自动释放池中执行提前释放,避免内存暴涨。

- (IBAction)combineAction:(UIBarButtonItem *)sender {
    CGImageRef bgImageRef = [UIImage imageNamed:@"bg"].CGImage;
    for (NSInteger i = 0; i < _imageNameList.count; i++) {
        @autoreleasepool {
            NSString *imageName = self.imageNameList[i];
            NSString *imagePath = [NSString stringWithFormat:@"%@/%@",self.bundlePath,imageName];
            UIImage *pic = [UIImage imageWithContentsOfFile:imagePath];
            NSArray *randomColors = [self randomPixelColorWithImage:pic colorCount:6];//像素点颜色
            UIImage *combineImage = [self createImageWithClassImage:pic bgImageRef:bgImageRef bgColor:randomColors.firstObject randomColors:randomColors];
            [self savePicToHomeDirectoryWithName:imageName image:combineImage];//保存图片到沙盒
        }
    }
    CGImageRelease(bgImageRef);
}
总结
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,377评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,390评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,967评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,344评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,441评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,492评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,497评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,274评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,732评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,008评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,184评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,837评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,520评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,156评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,407评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,056评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,074评论 2 352

推荐阅读更多精彩内容