美文网首页iOS日常笔记
iOS Gif 图片的编辑-旋转,镜像,设置背景色

iOS Gif 图片的编辑-旋转,镜像,设置背景色

作者: Mr_Zhou | 来源:发表于2023-11-06 15:16 被阅读0次

    前言:最近一个项目是要对Gif图片进行修改,然后保存到手机相册中,编辑涉及的比较少,更换背景颜色,添加文字,旋转角度,水平和垂直镜像这几种,一开始脑子里想着苹果gif图片保存不了,保存下来都是png的格式,结果想错了,还真可以保存,转为Data的形式可以直接保存到相册中。

    先看下对图片的处理,核心思路就是将Gif图片分解成数组,然后对每一张图片进行编辑,然后进行重新整合

    
    #pragma mark -- 分解Gif并重新整合
    
    /// 分解Gif并重新整合
    /// @param type 1-垂直 2-水平 3-旋转 4-改变背景色 5-合并文字
    /// @param rote  旋转角度
    -(void)decomposeGif:(NSString *)type rote:(CGFloat)rote color:(UIColor *)color
    {
        dispatch_async(dispatch_get_main_queue(), ^{
            
            NSMutableArray *newImageArr = [NSMutableArray array];
            
            NSArray *imageArray;
            
            if (self.imageArrayPng.count > 0)
            {
                imageArray = self.imageArrayPng;
            }
            else
            {
                // 第一次获取Gif数组
                imageArray = [self processingGIFPictures:self.imageName];
            }
                    
            
            for (UIImage *image in imageArray) {
                
                UIImage *newImage;
    
                if ([type isEqualToString:@"1"])
                {
                    newImage = [image flipVertical];
                }
                else if ([type isEqualToString:@"2"])
                {
                    newImage = [image flipHorizontal];
                }
                else if ([type isEqualToString:@"3"])
                {
                    if (rote != 0)
                    {
                        newImage = [image imageRotatedByDegrees:rote];
                    }
                    else
                    {
                        newImage = image;
                    }
                }
                else if ([type isEqualToString:@"4"])
                {
                    if(self.changeColor)
                    {
                        newImage = [self addImage:image toImage:self.backImageVIew.image];
                    }
                    else
                    {
                        newImage = image;
                    }
                    
                }
                else if ([type isEqualToString:@"5"])
                {
                    if (self.textL.text > 0)
                    {
                        newImage = [self addLabelToImage:image];
                    }
                    else
                    {
                        newImage = image;
                    }
                }
                
                [newImageArr addObject:newImage];
                
            }
            
            self.imageArrayPng = newImageArr;
        });
    }
    

    保存的方法

    #pragma mark -- 保存 Gif 图片到本地相册
    
    -(void)saveGifPhoto
    {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{//异步加载耗时操作
            // 获取相册的路径地址
            NSString *filePath = [self exportGifImages:self.imageArrayPng loopCount:0];
    
    // 转为data形式进行保存
            NSData *data = [NSData dataWithContentsOfFile:filePath];
               
            if(data!=nil) {
                
                [[PHPhotoLibrary sharedPhotoLibrary]performChanges:^{
                    
                    [[PHAssetCreationRequest creationRequestForAsset] addResourceWithType:PHAssetResourceTypePhoto data:data options:nil];
                    
                }completionHandler:^(BOOL success,NSError*_Nullable error) {
                    
                    dispatch_async(dispatch_get_main_queue(), ^{//进入主线程修改
                                            
                        if(success && !error){
                            
                            [EmoticonPackLoadShow showSuccessWithMessage:@"Successfully saved image"];
                            
                        }else{
                            
                            [EmoticonPackLoadShow showFailureWithMessage:@"Failed to save image"];
                        }});
                }];
            }
        });
    }
    
    
    #pragma mark -- 返回 gif 图片保存路径
    
    -(NSString *)exportGifImages:(NSArray*)images loopCount:(NSUInteger)loopCount
    {
        NSString *fileName = [NSString stringWithFormat: @"show.gif"];
    
        NSString *filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:fileName];
        
        CGImageDestinationRef destination = CGImageDestinationCreateWithURL((__bridge CFURLRef)[NSURL     fileURLWithPath:filePath],kUTTypeGIF, images.count, NULL);
        
        if(!loopCount){
        
        
            loopCount = 0;
        
        }
        
        NSDictionary *gifProperties = @{ (__bridge id)kCGImagePropertyGIFDictionary: @{
        
        
            (__bridge id)kCGImagePropertyGIFLoopCount: @(loopCount), // 0 means loop forever
        
       
        }};
        
        float delay = 0.1; //默认每一帧间隔0.1秒
        
        for(int i= 0 ; i <images.count ;i ++){
        
       
            UIImage *itemImage = images[i];
        
    // 这里是每一帧的时间间隔,我默认都是0.1秒。如果你们有特定的要求可以传这个值
    //        if(delays && i<delays.count){
    //            
    //            
    //            delay = [delays[i] floatValue];
    //            
    //            
    //        }
        
        //每一帧对应的延迟时间
        
        
            NSDictionary *frameProperties = @{(__bridge id)kCGImagePropertyGIFDictionary: @{
        
        
                (__bridge id)kCGImagePropertyGIFDelayTime: @(delay), // a float (not double!) in seconds, rounded to centiseconds in     the GIF data
        
            }};
        
      
            CGImageDestinationAddImage(destination,itemImage.CGImage, (__bridge CFDictionaryRef)frameProperties);
        
        }
        
        CGImageDestinationSetProperties(destination, (__bridge CFDictionaryRef)gifProperties);
        
        if (!CGImageDestinationFinalize(destination)) {
        
       
            EmotionLog(@"failed to finalize image destination");
        
        }
        
        CFRelease(destination);
        
        return filePath;
    
    }
    

    一 、现在说一下怎样编辑Gif 图片呢,将大概的思路给你们说一下,我的做法是,将Gif 图片分解成帧数组(UIImage),然后对每一张图片进行相同的处理,再将每一张图片组合起来,即为新的Gif 图片。至于显示,我用的是YYImage加载的gif图片,因为SDWebImage有点耗内存。

    接下来逐一讲解怎么去改变角度,背景颜色,镜像,文字。在讲解这个的时候先说下两个类 UIImage+Rotate(旋转以及镜像) 和 HImageUtility(图片合成)

    UIImage+Rotate.h

    #import <UIKit/UIKit.h>
    
    @interface UIImage (Rotate)
    
    
    /** 纠正图片的方向 */
    - (UIImage *)fixOrientation;
    
    /** 按给定的方向旋转图片 */
    - (UIImage*)rotate:(UIImageOrientation)orient;
    +(UIImage *)createImage:(UIImage *)originImg degrees:(float)degrees;
    
    /** 垂直翻转 */
    - (UIImage *)flipVertical;
    
    /** 水平翻转 */
    - (UIImage *)flipHorizontal;
    
    - (UIImage *)rotateImageWithDegrees:(CGFloat)degrees;
    /** 将图片旋转degrees角度 */
    - (UIImage *)imageRotatedByDegrees:(CGFloat)degrees;
    
    /** 将图片旋转radians弧度 */
    - (UIImage *)imageRotatedByRadians:(CGFloat)radians;
    /**
     根据指定尺寸获取缩略图尺寸
    
     @param size 缩略图尺寸
     @return 缩略图尺寸
     */
    - (CGSize )thumbWithSize:(CGSize)size;
    @end
    
    

    UIImage+Rotate.m

    
    #import "UIImage+Rotate.h"
    
    //由角度转换弧度
    #define kDegreesToRadian(x)      (M_PI * (x) / 180.0)
    //由弧度转换角度
    #define kRadianToDegrees(radian) (radian * 180.0) / (M_PI)
    
    @implementation UIImage (Rotate)
    
    /** 纠正图片的方向 */
    - (UIImage *)fixOrientation
    {
        if (self.imageOrientation == UIImageOrientationUp) return self;
        
        // We need to calculate the proper transformation to make the image upright.
        // We do it in 2 steps: Rotate if Left/Right/Down, and then flip if Mirrored.
        CGAffineTransform transform = CGAffineTransformIdentity;
        
        switch (self.imageOrientation)
        {
            case UIImageOrientationDown:
            case UIImageOrientationDownMirrored:
                transform = CGAffineTransformTranslate(transform, self.size.width, self.size.height);
                transform = CGAffineTransformRotate(transform, M_PI);
                break;
                
            case UIImageOrientationLeft:
            case UIImageOrientationLeftMirrored:
                transform = CGAffineTransformTranslate(transform, self.size.width, 0);
                transform = CGAffineTransformRotate(transform, M_PI_2);
                break;
                
            case UIImageOrientationRight:
            case UIImageOrientationRightMirrored:
                transform = CGAffineTransformTranslate(transform, 0, self.size.height);
                transform = CGAffineTransformRotate(transform, -M_PI_2);
                break;
            case UIImageOrientationUp:
            case UIImageOrientationUpMirrored:
                break;
        }
        
        switch (self.imageOrientation)
        {
            case UIImageOrientationUpMirrored:
            case UIImageOrientationDownMirrored:
                transform = CGAffineTransformTranslate(transform, self.size.width, 0);
                transform = CGAffineTransformScale(transform, -1, 1);
                break;
                
            case UIImageOrientationLeftMirrored:
            case UIImageOrientationRightMirrored:
                transform = CGAffineTransformTranslate(transform, self.size.height, 0);
                transform = CGAffineTransformScale(transform, -1, 1);
                break;
            case UIImageOrientationUp:
            case UIImageOrientationDown:
            case UIImageOrientationLeft:
            case UIImageOrientationRight:
                break;
        }
        
        // Now we draw the underlying CGImage into a new context, applying the transform
        // calculated above.
        CGContextRef ctx = CGBitmapContextCreate(NULL, self.size.width, self.size.height,
                                                 CGImageGetBitsPerComponent(self.CGImage), 0,
                                                 CGImageGetColorSpace(self.CGImage),
                                                 CGImageGetBitmapInfo(self.CGImage));
        CGContextConcatCTM(ctx, transform);
        
        switch (self.imageOrientation)
        {
            case UIImageOrientationLeft:
            case UIImageOrientationLeftMirrored:
            case UIImageOrientationRight:
            case UIImageOrientationRightMirrored:
                CGContextDrawImage(ctx, CGRectMake(0,0,self.size.height,self.size.width), self.CGImage);
                break;
                
            default:
                CGContextDrawImage(ctx, CGRectMake(0,0,self.size.width,self.size.height), self.CGImage);
                break;
        }
        
        CGImageRef cgimg = CGBitmapContextCreateImage(ctx);
        UIImage *img = [UIImage imageWithCGImage:cgimg];
        CGContextRelease(ctx);
        CGImageRelease(cgimg);
        
        return img;
    }
    
    /** 按给定的方向旋转图片 */
    - (UIImage*)rotate:(UIImageOrientation)orient
    {
        CGRect bnds = CGRectZero;
        UIImage* copy = nil;
        CGContextRef ctxt = nil;
        CGImageRef imag = self.CGImage;
        CGRect rect = CGRectZero;
        CGAffineTransform tran = CGAffineTransformIdentity;
        
        rect.size.width = CGImageGetWidth(imag);
        rect.size.height = CGImageGetHeight(imag);
        
        bnds = rect;
        
        switch (orient)
        {
            case UIImageOrientationUp:
                return self;
                
            case UIImageOrientationUpMirrored:
                tran = CGAffineTransformMakeTranslation(rect.size.width, 0.0);
                tran = CGAffineTransformScale(tran, -1.0, 1.0);
                break;
                
            case UIImageOrientationDown:
                tran = CGAffineTransformMakeTranslation(rect.size.width,
                                                        rect.size.height);
                tran = CGAffineTransformRotate(tran, M_PI);
                break;
                
            case UIImageOrientationDownMirrored:
                tran = CGAffineTransformMakeTranslation(0.0, rect.size.height);
                tran = CGAffineTransformScale(tran, 1.0, -1.0);
                break;
                
            case UIImageOrientationLeft:
                bnds = swapWidthAndHeight(bnds);
                tran = CGAffineTransformMakeTranslation(0.0, rect.size.width);
                tran = CGAffineTransformRotate(tran, 3.0 * M_PI / 2.0);
                break;
                
            case UIImageOrientationLeftMirrored:
                bnds = swapWidthAndHeight(bnds);
                tran = CGAffineTransformMakeTranslation(rect.size.height,
                                                        rect.size.width);
                tran = CGAffineTransformScale(tran, -1.0, 1.0);
                tran = CGAffineTransformRotate(tran, 3.0 * M_PI / 2.0);
                break;
                
            case UIImageOrientationRight:
                bnds = swapWidthAndHeight(bnds);
                tran = CGAffineTransformMakeTranslation(rect.size.height, 0.0);
                tran = CGAffineTransformRotate(tran, M_PI / 2.0);
                break;
                
            case UIImageOrientationRightMirrored:
                bnds = swapWidthAndHeight(bnds);
                tran = CGAffineTransformMakeScale(-1.0, 1.0);
                tran = CGAffineTransformRotate(tran, M_PI / 2.0);
                break;
                
            default:
                return self;
        }
        
        UIGraphicsBeginImageContext(bnds.size);
        ctxt = UIGraphicsGetCurrentContext();
        
        switch (orient)
        {
            case UIImageOrientationLeft:
            case UIImageOrientationLeftMirrored:
            case UIImageOrientationRight:
            case UIImageOrientationRightMirrored:
                CGContextScaleCTM(ctxt, -1.0, 1.0);
                CGContextTranslateCTM(ctxt, -rect.size.height, 0.0);
                break;
                
            default:
                CGContextScaleCTM(ctxt, 1.0, -1.0);
                CGContextTranslateCTM(ctxt, 0.0, -rect.size.height);
                break;
        }
        
        CGContextConcatCTM(ctxt, tran);
        CGContextDrawImage(UIGraphicsGetCurrentContext(), rect, imag);
        
        copy = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        
        return copy;
    }
    
    + (UIImage *)createImage:(UIImage *)originImg degrees:(float)degrees
    {
        if (originImg == nil || degrees == 0.0f) {
            return originImg;
        }
        CGImageRef oriImgRef = originImg.CGImage;
        CGImageRef rotatedImgRef = [self createRotatedImage:oriImgRef degrees:degrees];
        
        UIImage *rotatedImage =  [[UIImage alloc] initWithCGImage:rotatedImgRef];
        return rotatedImage;
    }
    
    // 图片旋转
    + (CGImageRef )createRotatedImage:(CGImageRef)original degrees:(float)degrees {
        if (degrees == 0.0f) {
            CGImageRetain(original);
            return original;
        } else {
            double radians = degrees * M_PI / 180;
            
    #if TARGET_OS_EMBEDDED || TARGET_IPHONE_SIMULATOR
            radians = -1*radians;
    #endif
            
            size_t _width = CGImageGetWidth(original);
            size_t _height = CGImageGetHeight(original);
            
            CGRect imgRect = CGRectMake(0, 0, _width, _height);
            CGAffineTransform __transform = CGAffineTransformMakeRotation(radians);
            CGRect rotatedRect = CGRectApplyAffineTransform(imgRect, __transform);
            
            CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
            CGContextRef context = CGBitmapContextCreate(NULL,
                                                         rotatedRect.size.width,
                                                         rotatedRect.size.height,
                                                         CGImageGetBitsPerComponent(original),
                                                         0,
                                                         colorSpace,
                                                         kCGBitmapAlphaInfoMask & kCGImageAlphaPremultipliedFirst);
          
            CGContextSetAllowsAntialiasing(context, FALSE);
            CGContextSetInterpolationQuality(context, kCGInterpolationNone);
            CGColorSpaceRelease(colorSpace);
            
            CGContextTranslateCTM(context,
                                  +(rotatedRect.size.width/2),
                                  +(rotatedRect.size.height/2));
            CGContextRotateCTM(context, radians);
            
            CGContextDrawImage(context, CGRectMake(-imgRect.size.width/2,
                                                   -imgRect.size.height/2,
                                                   imgRect.size.width,
                                                   imgRect.size.height),
                               original);
            
            CGImageRef rotatedImage = CGBitmapContextCreateImage(context);
            if (!context) {
                
            }else
            {
                CFRelease(context);
            }
            return rotatedImage;
        }
    }
    
    /** 垂直翻转 */
    - (UIImage *)flipVertical
    {
        return [self rotate:UIImageOrientationDownMirrored];
    }
    
    /** 水平翻转 */
    - (UIImage *)flipHorizontal
    {
        return [self rotate:UIImageOrientationUpMirrored];
    }
    
    - (UIImage *)rotateImageWithDegrees:(CGFloat)degrees {
        // Convert the degrees to radians
        CGFloat radians = degrees * M_PI / 180;
    
        // Create a rotation transform
        CGAffineTransform transform = CGAffineTransformMakeRotation(radians);
    
        // Apply the transform by drawing the image into a new context
        UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale);
        CGContextRef context = UIGraphicsGetCurrentContext();
        CGContextConcatCTM(context, transform);
        [self drawInRect:CGRectMake(-self.size.width / 2, -self.size.height / 2, self.size.width, self.size.height)];
        UIImage *rotatedImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        return rotatedImage;
    }
    
    
    /** 将图片旋转弧度radians */
    - (UIImage *)imageRotatedByRadians:(CGFloat)radians
    {
        // calculate the size of the rotated view's containing box for our drawing space
        UIView *rotatedViewBox = [[UIView alloc] initWithFrame:CGRectMake(0,0,self.size.width, self.size.height)];
        CGAffineTransform t = CGAffineTransformMakeRotation(radians);
        rotatedViewBox.transform = t;
        CGSize rotatedSize = rotatedViewBox.frame.size;
        
        // Create the bitmap context
        UIGraphicsBeginImageContext(rotatedSize);
        CGContextRef bitmap = UIGraphicsGetCurrentContext();
        
        // Move the origin to the middle of the image so we will rotate and scale around the center.
        CGContextTranslateCTM(bitmap, rotatedSize.width/2, rotatedSize.height/2);
        
        //   // Rotate the image context
        CGContextRotateCTM(bitmap, radians);
        
        // Now, draw the rotated/scaled image into the context
        CGContextScaleCTM(bitmap, 1.0, -1.0);
        CGContextDrawImage(bitmap, CGRectMake(-self.size.width / 2, -self.size.height / 2, self.size.width, self.size.height), [self CGImage]);
    //    CGContextDrawImage(bitmap, CGRectMake(-(self.size.width - rotatedSize.width) / 2, -(self.size.height - rotatedSize.height) / 2, self.size.width, self.size.height), [self CGImage]);
    
        UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        
        return newImage;
    }
    
    /** 将图片旋转角度degrees */
    - (UIImage *)imageRotatedByDegrees:(CGFloat)degrees
    {
        return [self imageRotatedByRadians:kDegreesToRadian(degrees)];
    }
    
    /** 交换宽和高 */
    static CGRect swapWidthAndHeight(CGRect rect)
    {
        CGFloat swap = rect.size.width;
        
        rect.size.width = rect.size.height;
        rect.size.height = swap;
        
        return rect;
    }
    
    /**
     根据指定尺寸获取缩略图尺寸
    
     @param size 缩略图尺寸
     @return 缩略图尺寸
     */
    - (CGSize )thumbWithSize:(CGSize)size {
        CGFloat scale;
        CGSize newsize = self.size;
    
        CGFloat srcWidth = size.width;
        CGFloat srcHeight = size.height;
        
        
        if (newsize.height && (newsize.height > srcWidth))//如果新图的高度不为0,且大于原图高度
       {
            scale = srcHeight / newsize.height;//比例为 原高/新高
            newsize.width *= scale;//新图的宽度等于 =
            newsize.height *= scale;
        }
    
       if (newsize.width && (newsize.width >= srcHeight))
       {
            scale = srcWidth / newsize.width;
            newsize.width *= scale;
            newsize.height *= scale;
        }
        return CGSizeMake(newsize.width*0.8, newsize.height*0.8);
    }
    
    
    
     + (CGSize) fitSize: (CGSize)thisSize inSize: (CGSize) aSize
     {
         CGFloat scale;
         CGSize newsize = thisSize;
    
    
         if (newsize.height && (newsize.height > aSize.height))//如果新图的高度不为0,且大于原图高度
        {
             scale = aSize.height / newsize.height;//比例为 原高/新高
             newsize.width *= scale;//新图的宽度等于 =
            newsize.height *= scale;
         }
    
        if (newsize.width && (newsize.width >= aSize.width))
        {
             scale = aSize.width / newsize.width;
            newsize.width *= scale;
             newsize.height *= scale;
         }
    
         return newsize;
     }
    
    @end
    
    

    HImageUtility.h

    
    #import <UIKit/UIKit.h>
    @interface HImageUtility : NSObject
    
    
    
    //////////////////////////////////////灰色处理//////////////////////////////////////////////
    /**
     *  return 灰色图片
     *  @param imageName        图片名称
     */
    + (UIImage *)imageToGraryWithImageName:(NSString *)imageName;
    + (UIImage *)imageToGraryWithImage:(UIImage *)image;
    
    
    
    //////////////////////////////////////图片合成处理//////////////////////////////////////////////
    /**
     *  return 合成后的图片 (以坐标为参考点,不准确)
     *  @param imageArray        图片数组  第一张图片位画布,所以最大
     *  @param frameArray        坐标数组  
     */
    + (UIImage *)composeImageWithArray:(NSArray<UIImage *> *)imageArray
                            frameArray:(NSArray *)frameArray;
    
    /**
     *  return 合成后的图片 (以坐标为参考点,准确)
     *  @param mainImage        第一张图片位画布                          (必传,不可空)
     *  @param viewFrame        第一张图片所在View的frame(获取压缩比用)    (必传,不可空)
     *  @param imgArray         子图片数组                               (必传,不可空)
     *  @param frameArray       子图片坐标数组                            (必传,不可空)
     */
    + (UIImage *)composeImageOnMainImage:(UIImage *)mainImage
                      mainImageViewFrame:(CGRect)viewFrame
                          subImageArray:(NSArray *)imgArray
                     subImageFrameArray:(NSArray *)frameArray;
    
    
    
    //////////////////////////////////////imageView旋转后的图片处理//////////////////////////////////////////////
    /**
     *  return 旋转后的图片
     *  @param image              原始图片    (必传,不可空)
     *  @param orientation        旋转方向    (必传,不可空)
     */
    + (UIImage *)image:(UIImage *)image
              rotation:(UIImageOrientation)orientation ;
    
    
    
    //////////////////////////////////////图片合成文字//////////////////////////////////////////////
    
    /**
     图片合成文字
     @param text            文字
     @param fontSize        字体大小
     @param textColor       字体颜色
     @param textFrame       字体位置
     @param image           原始图片
     @param viewFrame       图片所在View的位置
     @return UIImage *
     */
    + (UIImage *)imageWithText:(NSString *)text
                      textFont:(NSInteger)fontSize
                     textColor:(UIColor *)textColor
                     textFrame:(CGRect)textFrame
                   originImage:(UIImage *)image
        imageLocationViewFrame:(CGRect)viewFrame;
    
    
    @end
    

    HImageUtility.m

    
    #import "HImageUtility.h"
    #import "NSString+StringSize.h"
    
    @implementation HImageUtility
    
    
    
    /////////////////////////////////////灰色头像//////////////////////////////////////////////////////////
    
    + (UIImage *)imageToGraryWithImageName:(NSString *)imageName {
        return [HImageUtility imageToGraryWithImage:[UIImage imageNamed:imageName]];
    }
    
    
    + (UIImage *)imageToGraryWithImage:(UIImage *)image {
        // 1.拿到图片,获取宽高
        CGImageRef imageRef = image.CGImage;
        NSInteger width = CGImageGetWidth(imageRef);
        NSInteger height = CGImageGetHeight(imageRef);
        
        // 2:创建颜色空间(灰色空间
        CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceGray();
        
        CGContextRef contextRef = CGBitmapContextCreate(nil,
                                                        width,
                                                        height,
                                                        8, // 固定写法  8位
                                                        width * 4, // 每一行的字节  宽度 乘以32位 = 4字节
                                                        colorSpaceRef,
                                                        kCGImageAlphaNone); // 无透明度
        if (!contextRef) {
            return image;
        }
        
        CGContextDrawImage(contextRef, CGRectMake(0, 0, width, height), imageRef);
        
        CGImageRef grayImageRef = CGBitmapContextCreateImage(contextRef);
        UIImage * graryImage = [UIImage imageWithCGImage:grayImageRef];
        //释放内存
        CGColorSpaceRelease(colorSpaceRef);
        CGContextRelease(contextRef);
        CGImageRelease(grayImageRef);
        return graryImage;
    }
    
    /////////////////////////////////////图片合成//////////////////////////////////////////////////////////
    + (UIImage *)composeImageWithArray:(NSArray<UIImage *> *)imageArray frameArray:(NSArray *)frameArray {
        if (imageArray.count == 0) {  return nil;  }
        if (imageArray.count == 1) {  return imageArray.firstObject;  }
        if (imageArray.count != frameArray.count) {  return nil;  }
        
        __block UIImage *image0;
        [imageArray enumerateObjectsUsingBlock:^(UIImage * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            if (obj.size.width == 0) {
                *stop = YES;
                image0 = idx == 0 ? obj : [imageArray objectAtIndex:idx - 1];
            }
        }];
        if (image0) {
            return image0;
        }
        
        NSMutableArray *arrayImages = imageArray.mutableCopy;
        NSMutableArray *arrayFrames = frameArray.mutableCopy;
        
        NSString *string = arrayFrames.firstObject;
        CGRect fristRect = CGRectFromString(string);
        UIImage *img0 = arrayImages.firstObject;
        CGFloat w0 = fristRect.size.width;
        CGFloat h0 = fristRect.size.height;
        // 以第一张的图大小为画布创建上下文
        UIGraphicsBeginImageContext(CGSizeMake(w0, h0));
        [img0 drawInRect:CGRectMake(0, 0, w0, h0)];// 先把第一张图片 画到上下文中
        
        
        for (int i = 1; i < arrayImages.count; i ++) {
            NSString *string2 = [arrayFrames objectAtIndex:i];
            CGRect secondRect = CGRectFromString(string2);
            UIImage *img1 = [arrayImages objectAtIndex:1];
            [img1 drawInRect:secondRect];// 再把小图放在上下文中
        }
        
        UIImage *resultImg = UIGraphicsGetImageFromCurrentImageContext();// 从当前上下文中获得最终图片
        UIGraphicsEndImageContext();// 关闭上下文
        return resultImg;
    }
    
    + (UIImage *)composeImageOnMainImage:(UIImage *)mainImage
                      mainImageViewFrame:(CGRect)viewFrame
                           subImageArray:(NSArray *)imgArray
                      subImageFrameArray:(NSArray *)frameArray {
        if (!mainImage) {   return nil; }
        if (viewFrame.size.width == 0 || viewFrame.size.height == 0) {   return nil; }
        if (imgArray.count == 0) {  return nil;  }
        if (imgArray.count == 1) {  return imgArray.firstObject;  }
        if (imgArray.count != frameArray.count) {  return nil;  }
        
        // 此处拿到缩放比例
        CGFloat widthScale = mainImage.size.width / viewFrame.size.width;
        CGFloat heightScale = mainImage.size.height / viewFrame.size.height;
    
        UIGraphicsBeginImageContext(CGSizeMake(mainImage.size.width, mainImage.size.height));
        [mainImage drawInRect:CGRectMake(0, 0, mainImage.size.width, mainImage.size.height)];
        int i = 0;
        for (UIImage *img in imgArray) {
            NSString *string = [frameArray objectAtIndex:i];
            CGRect fristRect = CGRectFromString(string);
            [img drawInRect:CGRectMake(fristRect.origin.x * widthScale, fristRect.origin.y * heightScale, fristRect.size.width, fristRect.size.height)];
            i+=1;
        }
        
        UIImage *resultImg = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        
            return resultImg == nil ? mainImage : resultImg;
    }
    
    
    
    /////////////////////////////////////图片旋转//////////////////////////////////////////////////////////
    + (UIImage *)image:(UIImage *)image rotation:(UIImageOrientation)orientation
    {
        long double rotate = 0.0;
        CGRect rect;
        float translateX = 0;
        float translateY = 0;
        float scaleX = 1.0;
        float scaleY = 1.0;
        
        switch (orientation) {
            case UIImageOrientationLeft:
                rotate = M_PI_2;
                rect = CGRectMake(0, 0, image.size.height, image.size.width);
                translateX = 0;
                translateY = -rect.size.width;
                scaleY = rect.size.width/rect.size.height;
                scaleX = rect.size.height/rect.size.width;
                break;
            case UIImageOrientationRight:
                rotate = 33 * M_PI_2;
                rect = CGRectMake(0, 0, image.size.height, image.size.width);
                translateX = -rect.size.height;
                translateY = 0;
                scaleY = rect.size.width/rect.size.height;
                scaleX = rect.size.height/rect.size.width;
                break;
            case UIImageOrientationDown:
                rotate = M_PI;
                rect = CGRectMake(0, 0, image.size.width, image.size.height);
                translateX = -rect.size.width;
                translateY = -rect.size.height;
                break;
            default:
                rotate = 0.0;
                rect = CGRectMake(0, 0, image.size.width, image.size.height);
                translateX = 0;
                translateY = 0;
                break;
        }
        
        UIGraphicsBeginImageContext(rect.size);
        CGContextRef context = UIGraphicsGetCurrentContext();
        //做CTM变换
        CGContextTranslateCTM(context, 0.0, rect.size.height);
        CGContextScaleCTM(context, 1.0, -1.0);
        CGContextRotateCTM(context, rotate);
        CGContextTranslateCTM(context, translateX, translateY);
        
        CGContextScaleCTM(context, scaleX, scaleY);
        //绘制图片
        CGContextDrawImage(context, CGRectMake(0, 0, rect.size.width, rect.size.height), image.CGImage);
        
        UIImage *newPic = UIGraphicsGetImageFromCurrentImageContext();
        
        return newPic;
    }
    
    
    
    //////////////////////////////////////图片合成文字//////////////////////////////////////////////
    
    
    + (UIImage *)imageWithText:(NSString *)text
                      textFont:(NSInteger)fontSize
                     textColor:(UIColor *)textColor
                     textFrame:(CGRect)textFrame
                   originImage:(UIImage *)image
        imageLocationViewFrame:(CGRect)viewFrame {
        
        if (!text)      {  return image;   }
        if (!fontSize)  {  fontSize = 17;   }
        if (!textColor) {  textColor = [UIColor blackColor];   }
        if (!image)     {  return nil;  }
        if (viewFrame.size.height==0 || viewFrame.size.width==0 || textFrame.size.width==0 || textFrame.size.height==0 ){return nil;}
    
        NSString *mark = text;
        CGFloat height = [mark sizeWithPreferWidth:textFrame.size.width font:[UIFont systemFontOfSize:fontSize]].height; // 此分类方法要导入头文件
        if ((height + textFrame.origin.y) > viewFrame.size.height) { // 文字高度超出父视图的宽度
            height = viewFrame.size.height - textFrame.origin.y;
        }
        
    //    CGFloat w = image.size.width;
    //    CGFloat h = image.size.height;
        UIGraphicsBeginImageContext(viewFrame.size);
        [image drawInRect:CGRectMake(0, 0, viewFrame.size.width, viewFrame.size.height)];
        NSDictionary *attr = @{NSFontAttributeName: [UIFont systemFontOfSize:fontSize], NSForegroundColorAttributeName : textColor };
        //位置显示
        [mark drawInRect:CGRectMake(textFrame.origin.x, textFrame.origin.y, textFrame.size.width, height) withAttributes:attr];
        
        UIImage *aimg = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        return aimg;
    }
    
    @end
    

    知道上面两个类后进行讲解

    1、改变背景颜色

    我的做法是在后面用了一个ImageView,改变颜色只是改变后面的背景色,相当于只是预览,在点击确认保存的时候才将原始图片进行改变,思路就是将两张照片合成为一张

    (1)首先用选择的颜色创建一个Image图片

    #pragma mark -- 根据颜色生成一张纯色图片
    
    UIKIT_EXTERN UIImage * __nullable UIColorAsImage(UIColor * __nonnull color, CGSize size) {
        
        CGRect rect = CGRectMake(0, 0, size.width, size.height);
        
        UIGraphicsBeginImageContextWithOptions(rect.size, NO, [UIScreen mainScreen].scale);
        
        CGContextRef context = UIGraphicsGetCurrentContext();
        CGContextSetFillColorWithColor(context,color.CGColor);
        CGContextFillRect(context, rect);
        
        UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        
        return image;
    }
    

    (2)先将底色画在画布上,再将Gif图的每一帧画在画布上

    #pragma mark -- 将需要合并的两张照片传入
    // image2为颜色生成的图片,image1为gif图(分解为每一帧,for循环处理)
    - (UIImage*)addImage:(UIImage*)image1 toImage:(UIImage*)image2
    {
        CGFloat imageW = image1.size.width;
        CGFloat imageH = image1.size.height;
    
        if (imageW > 200)
        {
            imageW = 200;
        }
        
        if (imageH > 200)
        {
            imageH = 200;
        }
          
        //将底部的一张的大小作为所截取的合成图的尺寸
        UIGraphicsBeginImageContext(CGSizeMake(image2.size.width, image2.size.height));
        // 将image2画在画布上面
        [image2 drawInRect:CGRectMake(0, 0, image2.size.width, image2.size.height)];
        //将image1叠加image2的画布上面
        [image1 drawInRect:CGRectMake((image2.size.width - imageW)/2,(image2.size.height - imageH)/2, imageW, imageH)];
            
        //生成合成图片
        UIImage *resultingImage = UIGraphicsGetImageFromCurrentImageContext();
        //结束图片合成
        UIGraphicsEndImageContext();
        
        return resultingImage;
    }
    

    (3)转为Data形式进行保存(看开头)

    2、文字合并

    文字具有拖拽功能,所以可以使用这个UIView+Draggable分类

    UIView+Draggable.h

    
    #import <UIKit/UIKit.h>
    
    /**
     拖拽方式
     - DraggingTypeDisabled :不能拖拽
     - DraggingTypeNormal: 正常拖拽
     - DraggingTypeRevert: 释放后还原
     - DraggingTypePullOver: 自动靠边,只会靠左右两边
     - DraggingTypeAdsorb: 靠边时自动吸附边缘,可吸附四周
     */
    typedef NS_ENUM(NSUInteger, DraggingType) {
        DraggingTypeDisabled,
        DraggingTypeNormal,
        DraggingTypeRevert,
        DraggingTypePullOver,
        DraggingTypeAdsorb,
    };
    
    @protocol DraggingDelegate <NSObject>
    
    -(void)draggingDidBegan:(UIView *)view;
    -(void)draggingDidChanged:(UIView *)view;
    -(void)draggingDidEnded:(UIView *)view;
    
    @end
    
    @interface UIView (Draggable)<UIGestureRecognizerDelegate>
    
    /**
     拖拽事件委托,可监听拖拽的开始、变化以及结束事件。
     */
    @property (weak, nonatomic) id<DraggingDelegate> delegate;
    
    /**
     拖拽方式,默认是DraggingTypeDisabled。
     */
    @property(nonatomic)DraggingType draggingType;
    /**
     是否可只能在subView的范围内,默认是NO。
     
     @warning 如果NO,超出subView范围的部分无法响应拖拽。剪裁超出部分可直接使用superView.clipsToBounds=YES
     */
    @property(nonatomic)BOOL draggingInBounds;
    
    /**
     主动靠边并吸附
     */
    -(void)adsorbingAnimated:(BOOL)animated;
    
    /**
     主动靠边
     */
    -(void)pullOverAnimated:(BOOL)animated;
    
    /**
     主动还原位置
     */
    -(void)revertAnimated:(BOOL)animated;
    

    UIView+Draggable.m

    
    #import "UIView+Draggable.h"
    #import <objc/runtime.h>
    
    static const void *kPanKey           = @"panGestureKey";
    static const void *kDelegateKey      = @"delegateKey";
    static const void *kTypeKey          = @"draggingTypeKey";
    static const void *kInBoundsKey      = @"inBoundsKey";
    static const void *kRevertPointKey   = @"revertPointKey";
    static const NSInteger kAdsorbingTag = 10000;
    static const CGFloat kAdsorbScope    = 2.f;
    static const CGFloat kAdsorbDuration = 0.5f;
    
    @implementation UIView (Draggable)
    
    #pragma mark - synthesize
    -(UIPanGestureRecognizer *)panGesture {
        return objc_getAssociatedObject(self, kPanKey);
    }
    
    -(void)setPanGesture:(UIPanGestureRecognizer *)panGesture {
        objc_setAssociatedObject(self, kPanKey, panGesture, OBJC_ASSOCIATION_ASSIGN);
    }
    
    -(id<DraggingDelegate>)delegate {
        return objc_getAssociatedObject(self, kDelegateKey);
    }
    
    -(void)setDelegate:(id<DraggingDelegate>)delegate {
        objc_setAssociatedObject(self, kDelegateKey, delegate, OBJC_ASSOCIATION_ASSIGN);
    }
    
    - (DraggingType)draggingType {
        return [objc_getAssociatedObject(self, kTypeKey) integerValue];
    }
    
    - (void)setDraggingType:(DraggingType)draggingType {
        if ([self draggingType]==DraggingTypeAdsorb) {
            [self bringViewBack];
        }
        objc_setAssociatedObject(self, kTypeKey, [NSNumber numberWithInteger:draggingType], OBJC_ASSOCIATION_ASSIGN);
        [self makeDraggable:!(draggingType==DraggingTypeDisabled)];
        switch (draggingType) {
            case DraggingTypePullOver:
                [self pullOverAnimated:YES];
                break;
            case DraggingTypeAdsorb:
                [self adsorb];
                break;
            default:
                break;
        }
    }
    
    -(BOOL)draggingInBounds {
        return [objc_getAssociatedObject(self, kInBoundsKey) boolValue];
    }
    
    -(void)setDraggingInBounds:(BOOL)draggingInBounds {
        objc_setAssociatedObject(self, kInBoundsKey, [NSNumber numberWithBool:draggingInBounds], OBJC_ASSOCIATION_ASSIGN);
    }
    
    -(CGPoint)revertPoint {
        NSString *pointString = objc_getAssociatedObject(self, kRevertPointKey);
        CGPoint point = CGPointFromString(pointString);
        return point;
    }
    
    -(void)setRevertPoint:(CGPoint)revertPoint {
        NSString *point = NSStringFromCGPoint(revertPoint);
        objc_setAssociatedObject(self, kRevertPointKey, point, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    
    #pragma mark - Draggable
    -(void)makeDraggable:(BOOL)draggable {
        [self setUserInteractionEnabled:YES];
        [self removeConstraints:self.constraints];
        for (NSLayoutConstraint *constraint in self.superview.constraints) {
            if ([constraint.firstItem isEqual:self]) {
                [self.superview removeConstraint:constraint];
            }
        }
        [self setTranslatesAutoresizingMaskIntoConstraints:YES];
        UIPanGestureRecognizer *panGesture = [self panGesture];
        if (draggable) {
            if (!panGesture) {
                panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];
                panGesture.delegate = self;
                [self addGestureRecognizer:panGesture];
                [self setPanGesture:panGesture];
            }
        }else{
            if (panGesture) {
                [self setPanGesture:nil];
                [self removeGestureRecognizer:panGesture];
            }
        }
    }
    
    - (void)pan:(UIPanGestureRecognizer *)panGestureRecognizer {
        switch (panGestureRecognizer.state) {
            case UIGestureRecognizerStateBegan: {
                [self bringViewBack];
                [self setRevertPoint:self.center];
                [self dragging:panGestureRecognizer];
                [self.delegate draggingDidBegan:self];
            }
                break;
            case UIGestureRecognizerStateChanged: {
                [self dragging:panGestureRecognizer];
                [self.delegate draggingDidChanged:self];
            }
                break;
            case UIGestureRecognizerStateEnded: {
                switch ([self draggingType]) {
                    case DraggingTypeRevert: {
                        [self revertAnimated:YES];
                    }
                        break;
                    case DraggingTypePullOver: {
                        [self pullOverAnimated:YES];
                    }
                        break;
                    case DraggingTypeAdsorb :{
                        [self adsorb];
                    }
                        break;
                    default:
                        break;
                }
                [self.delegate draggingDidEnded:self];
            }
                break;
            default:
                break;
        }
    }
    
    -(void)dragging:(UIPanGestureRecognizer *)panGestureRecognizer {
        UIView *view = panGestureRecognizer.view;
        CGPoint translation = [panGestureRecognizer translationInView:view.superview];
        CGPoint center = CGPointMake(view.center.x + translation.x, view.center.y + translation.y);
        if ([self draggingInBounds]) {
            CGSize size = view.frame.size;
            CGSize superSize = view.superview.frame.size;
            CGFloat width = size.width;
            CGFloat height = size.height;
            CGFloat superWidth = superSize.width;
            CGFloat superHeight = superSize.height;
            center.x = (center.x<width/2)?width/2:center.x;
            center.x = (center.x+width/2>superWidth)?superWidth-width/2:center.x;
            center.y = (center.y<height/2)?height/2:center.y;
            center.y = (center.y+height/2>superHeight)?superHeight-height/2:center.y;
        }
        [view setCenter:center];
        [panGestureRecognizer setTranslation:CGPointZero inView:view.superview];
    }
    
    #pragma mark - pull over
    -(void)pullOverAnimated:(BOOL)animated {
        [self bringViewBack];
        CGPoint center = [self centerByPullOver];
        [UIView animateWithDuration:animated?kAdsorbDuration:0 animations: ^{
            [self setCenter:center];
        } completion:nil];
    }
    
    -(CGPoint)centerByPullOver {
        CGPoint center = [self center];
        CGSize size = self.frame.size;
        CGSize superSize = [self superview].frame.size;
        if (center.x<superSize.width/2) {
            center.x = size.width/2;
        }else{
            center.x = superSize.width-size.width/2;
        }
        if (center.y<size.height/2) {
            center.y = size.height/2;
        }else if (center.y>superSize.height-size.height/2){
            center.y = superSize.height-size.height/2;
        }
        return center;
    }
    
    #pragma mark - revert
    -(void)revertAnimated:(BOOL)animated {
        [self bringViewBack];
        CGPoint center = [self revertPoint];
        [UIView animateWithDuration:animated?kAdsorbDuration:0 animations: ^{
            [self setCenter:center];
        } completion:nil];
    }
    
    #pragma mark - adsorb
    -(void)adsorbingAnimated:(BOOL)animated {
        if (self.superview.tag == kAdsorbingTag) {
            return;
        }
        CGPoint center = [self centerByPullOver];
        [UIView animateWithDuration:animated?kAdsorbDuration:0 animations: ^{
            [self setCenter:center];
        } completion: ^(BOOL finish){
            [self adsorbAnimated:animated];
        }];
    }
    
    -(void)adsorb {
        if (self.superview.tag == kAdsorbingTag) {
            return;
        }
        CGPoint origin = self.frame.origin;
        CGSize size = self.frame.size;
        CGSize superSize = self.superview.frame.size;
        BOOL adsorbing = NO;
        if (origin.x<kAdsorbScope) {
            origin.x = 0;
            adsorbing = YES;
        }else if (origin.x>superSize.width-size.width-kAdsorbScope){
            origin.x = superSize.width-size.width;
            adsorbing = YES;
        }
        if (origin.y<kAdsorbScope) {
            origin.y = 0;
            adsorbing = YES;
        }else if (origin.y>superSize.height-size.height-kAdsorbScope){
            origin.y = superSize.height-size.height;
            adsorbing = YES;
        }
        if (adsorbing) {
            [self setFrame:CGRectMake(origin.x, origin.y, size.width, size.height)];
            [self adsorbAnimated:YES];
        }
    }
    
    -(void)adsorbAnimated:(BOOL)animated {
        NSAssert([self superview], @"必须先将View添加到superView上");
        CGRect frame = self.frame;
        UIView *adsorbingView = [[UIView alloc]initWithFrame:frame];
        adsorbingView.tag = kAdsorbingTag;
        [adsorbingView setBackgroundColor:[UIColor clearColor]];
        adsorbingView.clipsToBounds = YES;
        [self.superview addSubview:adsorbingView];
        
        CGSize superSize = adsorbingView.superview.frame.size;
        CGPoint center = CGPointZero;
        CGRect newFrame = frame;
        if (frame.origin.x==0) {
            center.x = 0;
            newFrame.size.width = frame.size.width/2;
        }else if (frame.origin.x==superSize.width-frame.size.width) {
            newFrame.size.width = frame.size.width/2;
            newFrame.origin.x = frame.origin.x+frame.size.width/2;
            center.x = newFrame.size.width;
        }else{
            center.x = frame.size.width/2;
        }
        if (frame.origin.y==0) {
            center.y = 0;
            newFrame.size.height = frame.size.height/2;
        }else if (frame.origin.y==superSize.height-frame.size.height) {
            newFrame.size.height = frame.size.height/2;
            newFrame.origin.y = frame.origin.y+frame.size.height/2;
            center.y = newFrame
            .size.height;
        }else{
            center.y = frame.size.height/2;
        }
        [self sendToView:adsorbingView];
        [UIView animateWithDuration:animated?kAdsorbDuration:0 animations: ^{
            [adsorbingView setFrame:newFrame];
            [self setCenter:center];
        } completion: nil];
    }
    
    -(void)sendToView:(UIView *)view {
        CGRect convertRect = [self.superview convertRect:self.frame toView:view];
        [view addSubview:self];
        [self setFrame:convertRect];
    }
    
    -(void)bringViewBack {
        UIView *adsorbingView = self.superview;
        if (adsorbingView.tag == kAdsorbingTag) {
            [self sendToView:adsorbingView.superview];
            [adsorbingView removeFromSuperview];
        }
    }
    
    @end
    

    使用方法如下

        self.textL.draggingType = DraggingTypeNormal;
        self.textL.draggingInBounds = YES;
    

    文字的合成我用的是上面提供的HImageUtility类,返回的是UIImage,将UIImage合并后就是Gif图了,使用方法如下

    - (UIImage*)addLabelToImage:(UIImage*)image
    {
        UIImage * resultingImage = [HImageUtility imageWithText:self.textL.text textFont:16 textColor:[UIColor blackColor] textFrame:CGRectMake(self.textL.x, self.textL.y, self.textL.width, self.textL.height) originImage:image imageLocationViewFrame:CGRectMake(0, 0, image.size.width, image.size.height)];
        
        
        return resultingImage;
    }
    

    3、镜像-水平和垂直使用的是UIImage+Rotate类,使用方法如下

    // 都返回的是UIImage,我们都需要将它进行重新组合
                    newImage = [image flipVertical]; // 垂直
                    newImage = [image flipHorizontal]; // 水平
    

    4、调节旋转角度,这个方法在保存的时候并不能将图片进行旋转,而要在保存的时候调用另外一个方法

    // 预览的时候调用
            imageView.transform = CGAffineTransformMakeRotation(value * ( M_PI / 180));
    
    // 点击保存的时候调用,传入角度信息,返回新的image                 
        newImage = [image imageRotatedByDegrees:rote];
    
    

    下面我将编辑界面的源码奉上,供你们分析

    EditEmioyViewController.h

    
    #import <UIKit/UIKit.h>
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface EditEmioyViewController : EmoticonPackBaseVC
    // 传进来的gif图片名称(我们的都是在本地放着)
    @property (copy,nonatomic) NSString *imageName;
    
    @end
    
    NS_ASSUME_NONNULL_END
    

    UIView+Draggable.h

    #import "EditEmioyViewController.h"
    #import "UIImage+Rotate.h"
    #import "UIView+Draggable.h"
    #import "EnabelFuncationView.h"
    #import "HImageUtility.h"
    #import <YYImage/YYImage.h>
    #import <MobileCoreServices/UTCoreTypes.h>
    #import <Photos/Photos.h>
    #import <CoreImage/CoreImage.h>
    
    @interface EditEmioyViewController ()<OperationResultDelegate>
    
    // scrollerview
    @property (weak, nonatomic) IBOutlet UIScrollView *scrollerView;
    // 改变 imageVIew 的背景色
    @property (weak, nonatomic) IBOutlet YYAnimatedImageView *imageEm;
    // 底部编辑的界面
    @property (weak, nonatomic) IBOutlet UIView *editorView;
    // 分解后的 png 数组
    @property (strong,nonatomic) NSArray *imageArrayPng;
    // 添加文字
    @property (weak, nonatomic) IBOutlet UILabel *textL;
    // 底部改变颜色的 ImageView
    @property (weak, nonatomic) IBOutlet YYAnimatedImageView *backImageVIew;
    // YYimage
    @property (strong,nonatomic)  YYImage *yyImage;
    // Gif的时长
    @property (assign,nonatomic) NSTimeInterval gifTimeValue;
    // gif 每帧的间隔
    @property (strong,nonatomic) NSArray *delaysArray;
    // 底部功能 view
    @property (strong,nonatomic) EnabelFuncationView *enabelView;
    // 旋转角度
    @property (assign,nonatomic) CGFloat roteFloat;
    // 改变的颜色
    @property (strong,nonatomic) UIColor *changeColor;
    // 保存的按钮
    @property (strong,nonatomic) UIButton *dowmLoadBtn;
    // 获取当前图片的宽和高
    @property (assign,nonatomic) CGFloat widthImage;
    @property (assign,nonatomic) CGFloat heightImage;
    // Xib 中的图片宽和高
    @property (weak, nonatomic) IBOutlet NSLayoutConstraint *widthCon;
    @property (weak, nonatomic) IBOutlet NSLayoutConstraint *heightCon;
    // 防止快速点击
    @property (strong,nonatomic) UIButton *buttonH;
    @property (strong,nonatomic) UIButton *buttonV;
    
    @end
    
    @implementation EditEmioyViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        self.navigationItem.title = @"Preview";
        // 设置保存按钮
        [self setItemBar];
        // 处理传进来的图片
        [self handleGifImage];
        // 创建功能操作 view
        self.enabelView = [EnabelFuncationView loadViewFromXib];
        
        self.enabelView.frame = CGRectMake(0, 0, self.editorView.width, self.editorView.height);
        
        self.enabelView.delegate = self;
        
        [self.editorView addSubview:self.enabelView];
    
        // 先显示 view
        self.yyImage = [YYImage imageNamed:self.imageName];
        self.imageEm.image = self.yyImage;
        
        // 获取当前图的宽高
        self.widthImage = self.yyImage.size.width;
        self.heightImage = self.yyImage.size.height;
        
        if (self.widthImage > 200)
        {
            self.widthImage = 200;
        }
        
        if (self.heightImage > 200)
        {
            self.heightImage = 200;
        }
        
        self.widthCon.constant = self.widthImage;
        self.heightCon.constant = self.heightImage;
    
        // 设置拖拽的label
        self.textL.draggingType = DraggingTypeNormal;
        self.textL.draggingInBounds = YES;
        self.textL.hidden = YES;
        
        // 监听键盘的弹起和收回
        [EmotionNSNotifi addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
    
        [EmotionNSNotifi addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
    
    }
    
    -(void)setItemBar
    {
        self.dowmLoadBtn = [UIButton buttonWithType:UIButtonTypeCustom];
        
        self.dowmLoadBtn.frame = CGRectMake(0, 0, 50, 40);
    
        [self.dowmLoadBtn setImage:[UIImage imageNamed:@"nav_icon_download"] forState:UIControlStateNormal];
        
        [self.dowmLoadBtn addTarget:self action:@selector(downAction:) forControlEvents:UIControlEventTouchUpInside];
              
        self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc]initWithCustomView:self.dowmLoadBtn];
    
    }
    
    #pragma mark -- 获取GIF图像的相关信息
    
    -(void)handleGifImage
    {
        // 将 Gif 转为 png 数组
        self.imageArrayPng = [self processingGIFPictures:self.imageName];
        // 获取 Gif 的保存路径
        NSString *filePath = [[NSBundle bundleWithPath:[[NSBundle mainBundle] bundlePath]] pathForResource:self.imageName ofType:nil];
        // Gif 转为 data
        NSData *data = [NSData dataWithContentsOfFile:filePath];
        // 获取 Gif 图片的时长
        self.gifTimeValue = [self durationForGifData:data];
        // 设置动画执行的时长
        if(self.gifTimeValue > 4)
        {
            self.gifTimeValue = 4;
        }
        else if (self.gifTimeValue < 1)
        {
            self.gifTimeValue = 0.5;
        }
    }
    
    #pragma mark -- 分解Gif并重新整合
    
    /// 分解Gif并重新整合
    /// @param type 1-垂直 2-水平 3-旋转 4-改变背景色 5-合并文字
    /// @param rote  旋转角度
    -(void)decomposeGif:(NSString *)type rote:(CGFloat)rote color:(UIColor *)color
    {
        dispatch_async(dispatch_get_main_queue(), ^{
            
            NSMutableArray *newImageArr = [NSMutableArray array];
            
            NSArray *imageArray;
            
            if (self.imageArrayPng.count > 0)
            {
                imageArray = self.imageArrayPng;
            }
            else
            {
                imageArray = [self processingGIFPictures:self.imageName];
            }
                    
            
            for (UIImage *image in imageArray) {
                
                UIImage *newImage;
    
                if ([type isEqualToString:@"1"])
                {
                    newImage = [image flipVertical];
                }
                else if ([type isEqualToString:@"2"])
                {
                    newImage = [image flipHorizontal];
                }
                else if ([type isEqualToString:@"3"])
                {
                    if (rote != 0)
                    {
                        newImage = [image imageRotatedByDegrees:rote];
                    }
                    else
                    {
                        newImage = image;
                    }
                }
                else if ([type isEqualToString:@"4"])
                {
                    if(self.changeColor)
                    {
                        newImage = [self addImage:image toImage:self.backImageVIew.image];
                    }
                    else
                    {
                        newImage = image;
                    }
                    
                }
                else if ([type isEqualToString:@"5"])
                {
                    if (self.textL.text > 0)
                    {
                        newImage = [self addLabelToImage:image];
                    }
                    else
                    {
                        newImage = image;
                    }
                }
                
                [newImageArr addObject:newImage];
                
            }
            
            self.imageArrayPng = newImageArr;
        });
    }
    
    #pragma mark --- 获取 gif 图片数组
    
    - (NSArray *)processingGIFPictures:(NSString *)name
    {
        if ([name rangeOfString:@".gif"].location != NSNotFound)
        {
            NSRange range = [name rangeOfString:@".gif"];
            
            name = [name substringToIndex:range.location];//从字符串开头截取到索引3
        }
        
        //获取Gif文件
        NSURL *gifImageUrl = [[NSBundle mainBundle] URLForResource:name withExtension:@"gif"];
        
        //获取Gif图的原数据
        CGImageSourceRef gifSource = CGImageSourceCreateWithURL((CFURLRef)gifImageUrl, NULL);
        
        //获取Gif图有多少帧
        size_t gifcount = CGImageSourceGetCount(gifSource);
        
        
        NSMutableArray *images = [[NSMutableArray alloc] init];
        
        
        for (NSInteger i = 0; i < gifcount; i++) {
            
            //由数据源gifSource生成一张CGImageRef类型的图片
            
            CGImageRef imageRef = CGImageSourceCreateImageAtIndex(gifSource, i, NULL);
            
            UIImage *image = [UIImage imageWithCGImage:imageRef];
            
            [images addObject:image];
            CGImageRelease(imageRef);
            
        }
        
        //得到图片数组
        return images;
    }
    
    
    
    
    #pragma mark -- 返回 gif 图片保存路径
    
    -(NSString *)exportGifImages:(NSArray*)images loopCount:(NSUInteger)loopCount
    {
        NSString *fileName = [NSString stringWithFormat: @"show.gif"];
    
        NSString *filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:fileName];
        
        CGImageDestinationRef destination = CGImageDestinationCreateWithURL((__bridge CFURLRef)[NSURL     fileURLWithPath:filePath],kUTTypeGIF, images.count, NULL);
        
        if(!loopCount){
        
        
            loopCount = 0;
        
        }
        
        NSDictionary *gifProperties = @{ (__bridge id)kCGImagePropertyGIFDictionary: @{
        
        
            (__bridge id)kCGImagePropertyGIFLoopCount: @(loopCount), // 0 means loop forever
        
       
        }};
        
        float delay = 0.1; //默认每一帧间隔0.1秒
        
        for(int i= 0 ; i <images.count ;i ++){
        
       
            UIImage *itemImage = images[i];
        
    
    //        if(delays && i<delays.count){
    //            
    //            
    //            delay = [delays[i] floatValue];
    //            
    //            
    //        }
        
        //每一帧对应的延迟时间
        
        
            NSDictionary *frameProperties = @{(__bridge id)kCGImagePropertyGIFDictionary: @{
        
        
                (__bridge id)kCGImagePropertyGIFDelayTime: @(delay), // a float (not double!) in seconds, rounded to centiseconds in     the GIF data
        
            }};
        
      
            CGImageDestinationAddImage(destination,itemImage.CGImage, (__bridge CFDictionaryRef)frameProperties);
        
        }
        
        CGImageDestinationSetProperties(destination, (__bridge CFDictionaryRef)gifProperties);
        
        if (!CGImageDestinationFinalize(destination)) {
        
       
            EmotionLog(@"failed to finalize image destination");
        
        }
        
        CFRelease(destination);
        
        return filePath;
    
    }
    
    
    #pragma mark -- 保存 Gif 图片到本地相册
    
    -(void)saveGifPhoto
    {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{//异步加载耗时操作
                    
            NSString *filePath = [self exportGifImages:self.imageArrayPng loopCount:0];
    
            NSData *data = [NSData dataWithContentsOfFile:filePath];
               
            if(data!=nil) {
                
                [[PHPhotoLibrary sharedPhotoLibrary]performChanges:^{
                    
                    [[PHAssetCreationRequest creationRequestForAsset] addResourceWithType:PHAssetResourceTypePhoto data:data options:nil];
                    
                }completionHandler:^(BOOL success,NSError*_Nullable error) {
                    
                    dispatch_async(dispatch_get_main_queue(), ^{//进入主线程修改
                                            
                        if(success && !error){
                            
                            [EmoticonPackLoadShow showSuccessWithMessage:@"Successfully saved image"];
                            
                        }else{
                            
                            [EmoticonPackLoadShow showFailureWithMessage:@"Failed to save image"];
                        }});
                }];
            }
        });
    }
    
    
    #pragma mark -- 获取gif图片的总时长
    
    - (NSTimeInterval)durationForGifData:(NSData *)data{
        //将GIF图片转换成对应的图片源
        CGImageSourceRef gifSource = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
        //获取其中图片源个数,即由多少帧图片组成
        size_t frameCout = CGImageSourceGetCount(gifSource);
        //定义数组存储拆分出来的图片
        NSMutableArray* frames = [[NSMutableArray alloc] init];
        NSTimeInterval totalDuration = 0;
        for (size_t i=0; i<frameCout; i++) {
            //从GIF图片中取出源图片
            CGImageRef imageRef = CGImageSourceCreateImageAtIndex(gifSource, i, NULL);
            //将图片源转换成UIimageView能使用的图片源
            UIImage* imageName = [UIImage imageWithCGImage:imageRef];
            //将图片加入数组中
            [frames addObject:imageName];
            NSTimeInterval duration = [self gifImageDeleyTime:gifSource index:i];
            totalDuration += duration;
            CGImageRelease(imageRef);
        }
    
        CFRelease(gifSource);
        return totalDuration;
    }
    
    
    //获取GIF图片每帧的时长
    - (NSTimeInterval)gifImageDeleyTime:(CGImageSourceRef)imageSource index:(NSInteger)index {
       NSTimeInterval duration = 0;
       CFDictionaryRef imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource, index, NULL);
       if (imageProperties) {
           CFDictionaryRef gifProperties;
           BOOL result = CFDictionaryGetValueIfPresent(imageProperties, kCGImagePropertyGIFDictionary, (const void **)&gifProperties);
           if (result) {
               const void *durationValue;
               if (CFDictionaryGetValueIfPresent(gifProperties, kCGImagePropertyGIFUnclampedDelayTime, &durationValue)) {
                   duration = [(__bridge NSNumber *)durationValue doubleValue];
                   if (duration < 0) {
                       if (CFDictionaryGetValueIfPresent(gifProperties, kCGImagePropertyGIFDelayTime, &durationValue)) {
                           duration = [(__bridge NSNumber *)durationValue doubleValue];
                       }
                   }
               }
           }
       }
       
       return duration;
    }
    
    
    #pragma mark --- 底部功能区代理
    
    //type: 1-水平 2-竖直 3-旋转角度 4-颜色 5-内容
    -(void)clickActionWithType:(nonnull NSString *)type color:(nullable UIColor *)color text:(nullable NSString *)text value:(CGFloat)value buttonV:(UIButton *)buttonV buttonH:(UIButton *)buttonH
    {
        self.buttonH = buttonH;
        self.buttonV = buttonV;
    
        if([type isEqualToString:@"1"])
        {
            self.buttonH.enabled = NO;
            self.buttonV.enabled = NO;
            
            [self decomposeGif:@"2" rote:0 color:color];
            [self startAnimal];
        }
        else if ([type isEqualToString:@"2"])
        {
            self.buttonH.enabled = NO;
            self.buttonV.enabled = NO;
            
            [self decomposeGif:@"1" rote:0 color:color];
            [self startAnimal];
        }
        else if ([type isEqualToString:@"3"])
        {
            self.roteFloat = value;
            // 最后确定保存的时候才调用
            
            self.imageEm.transform = CGAffineTransformMakeRotation(value * ( M_PI / 180));
        }
        else if ([type isEqualToString:@"4"])
        {
            self.changeColor = color;
            self.backImageVIew.image = UIColorAsImage(color, CGSizeMake(220, 220));
            self.backImageVIew.backgroundColor = color;
        }
        else if ([type isEqualToString:@"5"])
        {
            self.textL.hidden = NO;
            
            CGFloat widthText =  [self textWidthWithString:text];
            
            self.textL.width = widthText;
            
            if (widthText > 180)
            {
                self.textL.width = 180;
            }
            
            self.textL.text = text;
    
        }
    }
    
    -(void)startAnimal
    {
        EmotionSelf(self);
        
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    
            weakself.imageEm.animationImages = self.imageArrayPng;
            weakself.imageEm.animationDuration = self.gifTimeValue;
            weakself.imageEm.animationRepeatCount = 0;
            [weakself.imageEm startAnimating];
            
            weakself.buttonH.enabled = YES;
            weakself.buttonV.enabled = YES;
        });
    }
    
    
    
    #pragma mark -- 将需要合并的两张照片传入
    
    - (UIImage*)addImage:(UIImage*)image1 toImage:(UIImage*)image2
    {
        CGFloat imageW = image1.size.width;
        CGFloat imageH = image1.size.height;
    
        if (imageW > 200)
        {
            imageW = 200;
        }
        
        if (imageH > 200)
        {
            imageH = 200;
        }
        
        EmotionLog(@"%.f,%.f,%.f,%.f",imageW, imageH,image2.size.width, image2.size.height);
        
        //将底部的一张的大小作为所截取的合成图的尺寸
        UIGraphicsBeginImageContext(CGSizeMake(image2.size.width, image2.size.height));
        // 将image2画在画布上面
        [image2 drawInRect:CGRectMake(0, 0, image2.size.width, image2.size.height)];
        //将image1叠加image2的画布上面
        [image1 drawInRect:CGRectMake((image2.size.width - imageW)/2,(image2.size.height - imageH)/2, imageW, imageH)];
            
        //生成合成图片
        UIImage *resultingImage = UIGraphicsGetImageFromCurrentImageContext();
        //结束图片合成
        UIGraphicsEndImageContext();
        
        return resultingImage;
    }
    
    #pragma mark -- 将文字合并到照片上
    
    - (UIImage*)addLabelToImage:(UIImage*)image
    {
        UIImage * resultingImage = [HImageUtility imageWithText:self.textL.text textFont:16 textColor:[UIColor blackColor] textFrame:CGRectMake(self.textL.x, self.textL.y, self.textL.width, self.textL.height) originImage:image imageLocationViewFrame:CGRectMake(0, 0, image.size.width, image.size.height)];
        
        
        return resultingImage;
    }
    
    
    
    #pragma mark -- 根据颜色生成一张纯色图片
    
    UIKIT_EXTERN UIImage * __nullable UIColorAsImage(UIColor * __nonnull color, CGSize size) {
        
        CGRect rect = CGRectMake(0, 0, size.width, size.height);
        
        UIGraphicsBeginImageContextWithOptions(rect.size, NO, [UIScreen mainScreen].scale);
        
        CGContextRef context = UIGraphicsGetCurrentContext();
        CGContextSetFillColorWithColor(context,color.CGColor);
        CGContextFillRect(context, rect);
        
        UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        
        return image;
    }
    
    #pragma mark -- 计算文字的宽度
    
    
    /**
     计算字符串宽度
     */
    - (CGFloat)textWidthWithString:(NSString *)str
    {
        UIFont *font = [UIFont systemFontOfSize:16.0];
        NSDictionary *attributes = @{NSFontAttributeName: font};
        CGSize size = [str sizeWithAttributes:attributes];
        CGFloat width = size.width;
    
        return width;
    }
    
    
    
    
    #pragma mark -- 分享和保存本底
    
    -(void)downAction:(UIButton *)sender
    {
    
        EmotionSelf(self);
            
        [EmoticonPackLoadShow show];
           
        self.dowmLoadBtn.enabled = NO;
        
        // 确定保存之前有三件事
        // 旋转角度、颜色改变、文字
      
        //下面按顺序去执行操作
        
        // 1.创建队列组,串行加通知
        dispatch_group_t group = dispatch_group_create();
    
        // 2. 串行队列
        dispatch_queue_t concurrencyQueue = dispatch_queue_create("myqueue",DISPATCH_QUEUE_SERIAL);
    
        //3.开辟一个子线程,异步操作
               
        dispatch_group_async(group, concurrencyQueue, ^{
               
            [weakself decomposeGif:@"3" rote:self.roteFloat color:self.changeColor];
            
            EmotionLog(@"角度执行完毕");
    
        });
        
        
        
    
        dispatch_group_async(group, concurrencyQueue, ^{
                
            [weakself decomposeGif:@"4" rote:0 color:self.changeColor];
            
            EmotionLog(@"颜色执行完毕");
    
        });
        
        
        dispatch_group_async(group, concurrencyQueue, ^{
    
            //添加文字
            [weakself decomposeGif:@"5" rote:0 color:self.changeColor];
            
            EmotionLog(@"文字执行完毕");
    
        });
        
    
        //4.都完成后会自动通知
        dispatch_group_notify(group, dispatch_get_main_queue(), ^{
            
            //主线程刷新数据
            EmotionLog(@"所有的都执行完毕");
            [weakself saveGifPhoto];
            // 按钮打开
            weakself.dowmLoadBtn.enabled = YES;
            // 重置数据
            weakself.yyImage = [YYImage imageNamed:weakself.imageName];
            weakself.imageEm.image = weakself.yyImage;
            weakself.imageArrayPng = nil;
            
        });
    }
    
    
    -(BOOL)isOpenCamera{
        
        // 获取当前App的相册授权状态
        PHAuthorizationStatus authorizationStatus = [PHPhotoLibrary authorizationStatus];
        // 判断授权状态
        if (authorizationStatus == PHAuthorizationStatusAuthorized)
        {
            return YES;
        }
        else if (authorizationStatus == PHAuthorizationStatusNotDetermined)
        {
            return NO;
        }
        else
        {
            return NO;
        }
    }
    
    // 键盘将要弹起
    - (void)keyboardWillShow:(NSNotification *)notificationP{
       
        //获取键盘弹出的高度
    //    NSDictionary *dict = [notificationP userInfo];
    //    NSValue *value = [dict objectForKey:UIKeyboardFrameEndUserInfoKey];
    //    CGRect keyH = [value CGRectValue];
    //    CGFloat keyBoardH = keyH.size.height;
        
        CGFloat currentOffset = self.scrollerView.contentOffset.y;
    
        CGFloat newOffset;
    
        newOffset = currentOffset + 120;
    
        [UIScrollView animateWithDuration:0.3 animations:^(void) {
    
            [self.scrollerView setContentOffset:CGPointMake(0.0,newOffset)];
    
        }completion:^(BOOL finished) {
    
    
        }];
    
    }
    
    // 键盘将要隐藏
    - (void)keyboardWillHide:(NSNotification *)notificationP{
     
        [self.scrollerView setContentOffset:CGPointMake(0.0,0)];
    
    }
    
    
    -(void)dealloc
    {
        [EmotionNSNotifi removeObserver:self];
    }
    
    @end
    
    

    相关文章

      网友评论

        本文标题:iOS Gif 图片的编辑-旋转,镜像,设置背景色

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