iOS日常笔记

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

2023-11-06  本文已影响0人  Mr_Zhou

前言:最近一个项目是要对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

上一篇下一篇

猜你喜欢

热点阅读