iOS Gif 圖片的編輯-旋轉,鏡像,設置背景色

前言:最近一個項目是要對Gif圖片進行修改,然后保存到手機相冊中,編輯涉及的比較少,更換背景顏色,添加文字,旋轉角度,水平和垂直鏡像這幾種,一開始腦子里想著蘋果gif圖片保存不了,保存下來都是png的格式,結果想錯了,還真可以保存,轉為Data的形式可以直接保存到相冊中。

先看下對圖片的處理,核心思路就是將Gif圖片分解成數(shù)組,然后對每一張圖片進行編輯,然后進行重新整合


#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數(shù)組
            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;

}

一 、現(xiàn)在說一下怎樣編輯Gif 圖片呢,將大概的思路給你們說一下,我的做法是,將Gif 圖片分解成幀數(shù)組(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;
/**
 根據(jù)指定尺寸獲取縮略圖尺寸

 @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;
}

/**
 根據(jù)指定尺寸獲取縮略圖尺寸

 @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        圖片數(shù)組  第一張圖片位畫布,所以最大
 *  @param frameArray        坐標數(shù)組  
 */
+ (UIImage *)composeImageWithArray:(NSArray<UIImage *> *)imageArray
                        frameArray:(NSArray *)frameArray;

/**
 *  return 合成后的圖片 (以坐標為參考點,準確)
 *  @param mainImage        第一張圖片位畫布                          (必傳,不可空)
 *  @param viewFrame        第一張圖片所在View的frame(獲取壓縮比用)    (必傳,不可空)
 *  @param imgArray         子圖片數(shù)組                               (必傳,不可空)
 *  @param frameArray       子圖片坐標數(shù)組                            (必傳,不可空)
 */
+ (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:創(chuàng)建顏色空間(灰色空間
    CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceGray();
    
    CGContextRef contextRef = CGBitmapContextCreate(nil,
                                                    width,
                                                    height,
                                                    8, // 固定寫法  8位
                                                    width * 4, // 每一行的字節(jié)  寬度 乘以32位 = 4字節(jié)
                                                    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;
    // 以第一張的圖大小為畫布創(chuàng)建上下文
    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)首先用選擇的顏色創(chuàng)建一個Image圖片

#pragma mark -- 根據(jù)顏色生成一張純色圖片

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循環(huán)處理)
- (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>

/**
 拖拽事件委托,可監(jiān)聽拖拽的開始、變化以及結束事件。
 */
@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、調節(jié)旋轉角度,這個方法在保存的時候并不能將圖片進行旋轉,而要在保存的時候調用另外一個方法

// 預覽的時候調用
        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 數(shù)組
@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];
    // 創(chuàng)建功能操作 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;
    
    // 監(jiān)聽鍵盤的彈起和收回
    [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 數(shù)組
    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];
    // 設置動畫執(zhí)行的時長
    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 圖片數(shù)組

- (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圖的原數(shù)據(jù)
    CGImageSourceRef gifSource = CGImageSourceCreateWithURL((CFURLRef)gifImageUrl, NULL);
    
    //獲取Gif圖有多少幀
    size_t gifcount = CGImageSourceGetCount(gifSource);
    
    
    NSMutableArray *images = [[NSMutableArray alloc] init];
    
    
    for (NSInteger i = 0; i < gifcount; i++) {
        
        //由數(shù)據(jù)源gifSource生成一張CGImageRef類型的圖片
        
        CGImageRef imageRef = CGImageSourceCreateImageAtIndex(gifSource, i, NULL);
        
        UIImage *image = [UIImage imageWithCGImage:imageRef];
        
        [images addObject:image];
        CGImageRelease(imageRef);
        
    }
    
    //得到圖片數(shù)組
    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);
    //獲取其中圖片源個數(shù),即由多少幀圖片組成
    size_t frameCout = CGImageSourceGetCount(gifSource);
    //定義數(shù)組存儲拆分出來的圖片
    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];
        //將圖片加入數(shù)組中
        [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 --- 底部功能區(qū)代理

//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 -- 根據(jù)顏色生成一張純色圖片

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;
    
    // 確定保存之前有三件事
    // 旋轉角度、顏色改變、文字
  
    //下面按順序去執(zhí)行操作
    
    // 1.創(chuàng)建隊列組,串行加通知
    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(@"角度執(zhí)行完畢");

    });
    
    
    

    dispatch_group_async(group, concurrencyQueue, ^{
            
        [weakself decomposeGif:@"4" rote:0 color:self.changeColor];
        
        EmotionLog(@"顏色執(zhí)行完畢");

    });
    
    
    dispatch_group_async(group, concurrencyQueue, ^{

        //添加文字
        [weakself decomposeGif:@"5" rote:0 color:self.changeColor];
        
        EmotionLog(@"文字執(zhí)行完畢");

    });
    

    //4.都完成后會自動通知
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        
        //主線程刷新數(shù)據(jù)
        EmotionLog(@"所有的都執(zhí)行完畢");
        [weakself saveGifPhoto];
        // 按鈕打開
        weakself.dowmLoadBtn.enabled = YES;
        // 重置數(shù)據(jù)
        weakself.yyImage = [YYImage imageNamed:weakself.imageName];
        weakself.imageEm.image = weakself.yyImage;
        weakself.imageArrayPng = nil;
        
    });
}


-(BOOL)isOpenCamera{
    
    // 獲取當前App的相冊授權狀態(tài)
    PHAuthorizationStatus authorizationStatus = [PHPhotoLibrary authorizationStatus];
    // 判斷授權狀態(tài)
    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

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容