美文网首页
iOS 下利用 CGContextRef 简单实现多图拼接功能

iOS 下利用 CGContextRef 简单实现多图拼接功能

作者: 大菠萝_DABLO | 来源:发表于2022-01-25 12:14 被阅读0次

    废话开篇:简单实现多张小图拼接为一张长整图的功能。

    一、需要实现的功能

    将这三张 拼接成下面的一张整图

    图片

    最终要保存的图

    图片 图片

    二、合并功能操作代码

    在控制器里进行多图的拼接操作,

    UIImage * image1 = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"fd1" ofType:@"jpeg"]];
    
        UIImage * image2 = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"fd2" ofType:@"jpeg"]];
    
        UIImage * image3 = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"fd3" ofType:@"jpeg"]];
    
        self.scrollView = [[UIScrollView alloc] initWithFrame:self.view.bounds];
    
        [self.view addSubview:self.scrollView];
    
        //合并小图
        [WSLImageCombineOperation combineImages:@[image1,image2,image3] callBack:^(UIImage * _Nonnull resultImage) {
    
            UIImageView * imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, self.scrollView.frame.size.height *  resultImage.size.width / resultImage.size.height,self.scrollView.frame.size.height)];
    
            imageView.image = resultImage;
    
            imageView.contentMode = UIViewContentModeScaleAspectFit;
    
            [self.scrollView addSubview:imageView];
    
            self.scrollView.contentSize = CGSizeMake(imageView.frame.size.width, imageView.frame.size.height);
            //保存到沙盒
            [WSLImageCombineOperation saveImageToCache:resultImage];
    
        }];
    

    三、WSLImageCombineOperation 类,实现图合并功能

    其实这里主要的是利用 CGContextRef 上下文进行的绘制。在开辟上下文后,在上下文里面进行多图的绘制,最后将上下文内容转为 image 进行展示与保存。

    在开辟上下文的之前,需要做几件事:

    1、创建 CGContextRef 上下文。

    创建上下文之前,需要计算多张图上下依次拼接的最大高度图组中最宽的一张图片宽度

    保证上下文满足两个条件:

    (1)足够的高度。

    (2)以最大图片为准,居中排列。

    //同时获取图片组最大宽度及拼接高度
    + (void)getAllImagesMaxWidthAndTotleHeight:(NSArray *)images callBack:(void(^)(NSUInteger maxWith,NSUInteger totleHeight))callBack
    {
        CGFloat maxWidth = 0;
        CGFloat allImageHeight = 0;
        for (UIImage * image in images) {
            CGFloat currentImageWidth = [self imageWidth:image];
            maxWidth = maxWidth < currentImageWidth ? currentImageWidth : maxWidth;
            allImageHeight += [self imageHeight:image];
        }
        callBack(maxWidth,allImageHeight);
    }
    
    //获取图片宽度
    + (CGFloat)imageWidth:(UIImage *)image
    {
        return image.size.width;
    }
    
    //获取图片高度
    + (CGFloat)imageHeight:(UIImage *)image
    {
        return image.size.height;
    }
    

    2、绘制内容到 CGContextRef 上下文中

    在绘制前,可以先设置上下的填充颜色。

    //设置大图上下文背景填充颜色(这里是黑色)
      CGContextSetFillColorWithColor(contextRef, [UIColor blackColor].CGColor);
      //设置大图上下文背景填充区域(全部区域)
      CGContextFillRect(contextRef, CGRectMake(0, 0, imageWidth, imageHeight));
    

    其次,进行循环绘制,直接放完整代码

    + (void)combineImages:(NSArray *)images callBack:(void(^)(UIImage * resultImage))callBack
    {
        //获取拼接后图片的高度及最大宽度
        [self getAllImagesMaxWidthAndTotleHeight:images callBack:^(NSUInteger imageWidth, NSUInteger imageHeight) {
            //创建颜色空间
            CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
            //开辟像素区域
            UInt32 *imagePiexl = (UInt32 *)calloc(imageWidth*imageHeight, sizeof(UInt32));
            //创建上下文
            CGContextRef contextRef = CGBitmapContextCreate(imagePiexl,
                                                            imageWidth,
                                                            imageHeight,
                                                            8,
                                                            4*imageWidth,
                                                            colorSpaceRef,
                                                            kCGImageAlphaNoneSkipLast);
    
            //设置大图上下文背景填充颜色(这里是黑色)
            CGContextSetFillColorWithColor(contextRef, [UIColor blackColor].CGColor);
            //设置大图上下文背景填充区域(全部区域)
            CGContextFillRect(contextRef, CGRectMake(0, 0, imageWidth, imageHeight));
            //拼接图片 X 值
            NSUInteger imageX = 0;
            //拼接图片 Y 值
            NSUInteger imageY = 0
            //循环遍历进行绘制
            for (UIImage * image in images) {
    
                //循环绘制
                CGImageRef imageRef = image.CGImage;
                NSUInteger width = CGImageGetWidth(imageRef);
                NSUInteger height = CGImageGetHeight(imageRef);//谢谢[可爱亲宝宝]的纠正
                imageX = (imageWidth - width) / 2.0;
                CGContextDrawImage(contextRef, CGRectMake(imageX, imageY, width, height), imageRef);
                //重新计算 Y 值
                imageY += height;
            }
    
            //生成图片,供外部 UIImageView 渲染
            CGImageRef resultRef = CGBitmapContextCreateImage(contextRef);
            UIImage * resultImage = [UIImage imageWithCGImage:resultRef scale:[UIScreen mainScreen].scale orientation:UIImageOrientationUp];
            callBack(resultImage);
    
            //释放用过的内存
            CGContextRelease(contextRef);
            CGColorSpaceRelease(colorSpaceRef);
            free(imagePiexl);
            CGImageRelease(resultRef);
        }];
    
     }
    

    3、保存图片到沙盒

    实现图片保存到沙盒的功能

    //保存到沙盒
    + (BOOL)saveImageToCache:(UIImage *)image
    {
        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);
        NSString *filePath = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"酆都大帝.jpg"];
        NSLog(@"filePath = %@",filePath);
        BOOL result = [UIImagePNGRepresentation(image) writeToFile: filePath atomically:YES];
        return result;
    }
    

    这里打印 filePath 缓存路径,复制出来,直接在 MAC电脑 “前往文件夹”下输入此路径就能找到模拟器下的对应沙盒文件。

    四、总结与思考

    上述实现原理比较简单。除此之外,如果是要某张小图的某一部分或者对图片整体像素处理,那么,就需要对图片进行像素操作了。个人理解,通过 image.CGImage 可以获得图片的很多信息数据,图片格式、图片宽高、三色素值等具体的信息,只要最后修改的文件符合图片格式,那么,其他的操作就都是二进制数据的修改与拼接。

    相关文章

      网友评论

          本文标题:iOS 下利用 CGContextRef 简单实现多图拼接功能

          本文链接:https://www.haomeiwen.com/subject/gdrbhrtx.html