iOS Gif 图片的编辑-旋转,镜像,设置背景色
前言:最近一个项目是要对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