iOSQuart2D繪圖之UIImage簡單使用

代碼地址以下:
http://www.demodashi.com/demo/11609.htmlhtml

人生得意須盡歡,莫使金樽空對月。
   天生我材必有用,千金散盡還復來。面試

前記

說到UIImage你們都不會感到陌生,最近在研究UIImage,就順便把以前工做中用到的一些category總結了一下,記錄記錄。數組

在這以前先看一下一些簡答的效果圖緩存

一、簡單處理

12.png

二、GIF圖片加載

12.gif

三、圖片添加文字、圖片及圖片截屏、擦除

添加文字.png

添加圖片.png

截圖.png

wipe.gif

代碼分析
一、圖片圓角處理

關於圖片的圓角處理,這個可能用的比較多點,固然你也能夠用給UIIImageView設置圓角來達到目的,可是在性能上特別是用在tableview上的時候,就沒那麼好了。服務器

在這以前,咱們先來看看CGContextRef,這個怎麼解釋呢?個人理解就是畫布,就至關於咱們在畫畫的時候的畫板,咱們須要畫圖片、文字、線條都須要在這上面進行。
在瞭解這個以後,咱們就開始看代碼ide

帶圓圈的圓圖函數

+ (UIImage*)gl_circleImage:(UIImage*)image withBorder:(CGFloat)border color:(UIColor *)color
{
    //經過本身建立一個context來繪製,一般用於對圖片的處理
    //在retian屏幕上要使用這個函數,才能保證不失真
    //該函數會自動建立一個context,並把它push到上下文棧頂,座標系也經處理和UIKit的座標系相同
    UIGraphicsBeginImageContextWithOptions(CGSizeMake(image.size.width, image.size.height), NO, [UIScreen mainScreen].scale);
    //獲取上下文
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGRect rect = CGRectMake(0, 0, image.size.width, image.size.height);
    //設置寬度
    CGContextSetLineWidth(context, 4*border);
    //設置邊框顏色
    CGContextSetStrokeColorWithColor(context, color.CGColor);

    //畫橢圓 當寬和高同樣的時候 爲圓 此處設置可視範圍
    CGContextAddEllipseInRect(context, rect);
    //剪切可視範圍
    CGContextClip(context);

    //繪製圖片
    [image drawInRect:rect];

    CGContextAddEllipseInRect(context, rect);
    // 繪製當前的路徑 只描繪邊框
    CGContextStrokePath(context);

    
    UIImage *newimg = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return newimg;
}

本想講點什麼,可是代碼中已經有註釋,就不說什麼了,這裏須要注意的是UIGraphicsBeginImageContextWithOptions這個函數,最後一個參數--縮放因子,和咱們平時用的倍圖相關,好比@x,@2x,@3x,在4s上爲1,後面的機型中,plus3,其他爲2,在這裏能夠設置爲0,這樣會自動匹配。性能

不帶圓圈的圓圖動畫

/**
 建立圓形圖片

 @param image 原始圖片
 @return 返回
 */
+ (UIImage *)gl_circleImage:(UIImage *)image;

因爲和帶圓圈的原圖代碼幾乎一致,只是少了邊框這部分代碼,這裏就不在貼出來了,後面會給出demothis

二、根據顏色建立圖片

這個比較簡單,最主要的是靠下面兩個函數來進行實現

//設置填充顏色
    CGContextSetFillColorWithColor(context, color.CGColor);
    //直接按rect的範圍覆蓋
    CGContextFillRect(context, CGRectMake(0, 0, size.width, size.height));

在這裏有兩個函數,CGContextSetFillColorWithColorCGContextSetStrokeColorWithColor,是相對的兩個函數,一個是設置覆蓋區域的顏色,一個是設置邊框的顏色,在使用的時候應該和其餘函數對應一塊兒使用。
下面仍是列出代碼

+ (UIImage *)gl_imageWithColor:(UIColor *)color size:(CGSize)size{
    CGSize imageSize = size;
    //經過本身建立一個context來繪製,一般用於對圖片的處理
    UIGraphicsBeginImageContextWithOptions(imageSize, NO, [UIScreen mainScreen].scale);
    //獲取上下文
    CGContextRef context = UIGraphicsGetCurrentContext();
    //設置填充顏色
    CGContextSetFillColorWithColor(context, color.CGColor);
    //直接按rect的範圍覆蓋
    CGContextFillRect(context, CGRectMake(0, 0, size.width, size.height));
    UIImage *newimg = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return newimg;
}

因爲根據顏色來繪製圓形圖片代碼和上面幾乎一致,只是將其中的
CGContextFillRect換成了CGContextAddEllipseInRectCGContextFillPath,這裏就不在詳細講解

三、給圖片設置圓角

這個可能用的比較多點,好比當美工不給我切圖的時候,咱們又須要使圖片其中的幾個角有圓角,那麼這時候這個方法就派上用場了。

在這裏,主要是經過方法CGContextAddPathUIBezierPath一塊兒來實現,詳細看到這裏,你們都知道怎麼用的了,下面咱們就來看源碼

+ (UIImage*)gl_cornerImage:(UIImage*)image corner:(CGFloat)corner rectCorner:(UIRectCorner)rectCorner
{
    CGSize imageSize = image.size;
    UIGraphicsBeginImageContextWithOptions(imageSize, NO, [UIScreen mainScreen].scale);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGRect rect = CGRectMake(0,
                             0,
                             imageSize.width,
                             imageSize.height);
    UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:rect
                                               byRoundingCorners:rectCorner
                                                     cornerRadii:CGSizeMake(corner,
                                                                            corner)];
    //添加路徑
    CGContextAddPath(context, [path CGPath]);
    //剪切可視範圍
    CGContextClip(context);
    [image drawInRect:rect];
    
    UIImage *newimg = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return newimg;
}
四、壓縮圖片

說到壓縮圖片,這個應該是用的最多的了,好比有一天忽然項目經理給你說,咱們上傳的這個圖片啊,太大了,不只浪費流量還特別慢,並且服務器壓力還不小....大家客戶端處理下把,最好在250kb左右,可是又不能裁剪圖片,這個時候,這個方法就能大展身手了。
其主要思路是經過一個while循環,不停的去縮小咱們所要的圖片,固然計算圖片的大小,咱們用的是UIImageJPEGRepresentation,雖然這個和真實圖片的大小仍是有那麼點偏差,可是通常狀況下仍是沒什麼問題的,下面咱們來看源碼

+ (UIImage*)gl_compressImage:(UIImage *)image maxSize:(CGFloat)maxSize maxSizeWithKB:(CGFloat)maxSizeKB
{    
    if (maxSize <= 0) {
        return nil;
    }
    
    if (maxSizeKB <= 0) {
        return nil;
    }

    CGSize compressSize = image.size;
    //獲取縮放比 進行比較 
    CGFloat widthScale = compressSize.width*1.0 / maxSize;
    CGFloat heightScale = compressSize.height*1.0 / maxSize;
    
    if (widthScale > 1 && widthScale > heightScale) {
        compressSize = CGSizeMake(image.size.width/widthScale, image.size.height/widthScale);
    }
    else if (heightScale > 1 && heightScale > widthScale){
        compressSize = CGSizeMake(image.size.width/heightScale, image.size.height/heightScale);
    }
    
    //建立圖片上下文 並獲取剪切尺寸後的圖片
    UIGraphicsBeginImageContextWithOptions(compressSize, NO, 1);
    CGRect rect = {CGPointZero,compressSize};
    [image drawInRect:rect];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    
    //循環縮小圖片大小
    NSData *imageData = UIImageJPEGRepresentation(newImage, 1.0);
    //獲取當前圖片的大小
    CGFloat currentImageSizeOfKB = imageData.length/1024.0;
    
    //壓縮比例
    CGFloat compress = 0.9;
    
    while (currentImageSizeOfKB > maxSizeKB && compress > 0.1) {
        imageData = UIImageJPEGRepresentation(newImage, compress);
        currentImageSizeOfKB = imageData.length/1024.0;
        compress -= 0.1;
    }
    return [UIImage imageWithData:imageData];
}
五、加載GIF圖片

說到加載動態圖片,需求量雖然不大,但仍是偶爾會用到,這裏咱們有一個很關鍵的API---+ (nullable UIImage *)animatedImageWithImages:(NSArray<UIImage *> *)images duration:(NSTimeInterval)duration,經過這個函數,咱們能夠簡單的來播放動態圖片。下面咱們要作的就是怎麼獲得GIF圖片的圖片資源和其播放時間duration

關於圖片源,在ImageIo中有這麼一個類CGImageSource,其中的CGImageSourceRef也就是咱們所說的圖片源,查看API,咱們能夠獲得三種方式:

一、CGImageSourceCreateWithURL
基於一個URL連接來讀取圖片信息。這個方法也是蘋果推薦的方法,由於有些時候咱們想獲取照片的信息,但不須要將照片加載到內存中(由於這是不必的),因此只須要給出照片的URL地址。
二、CGImageSourceCreateWithData
這個方法是基於一個NSData對象來獲取照片信息。因此若是想使用此方法,必需將一個UIImage對象轉換成NSData對象,例如:

NSString *filePath = [[NSBundle mainBundle]pathForResource:@"24" ofType:@"jpg"];
    NSData *data = [NSData dataWithContentsOfFile:filePath];
    CGImageSourceRef imageSource = CGImageSourceCreateWithData((__bridge CFDataRef)data, nil);

三、CGImageSourceCreateWithDataProvider
這種方法主要是須要將一個CGImageRef生成一個CGDataProvider。而參數"options"選項是一個字典,用於建立圖片源時提供的附加屬性,例如是否對圖片進行緩存等。

在有了獲得圖片源的方法後,咱們就能夠經過圖片源來獲得其中的相關信息,最主要的是動畫時間,具體代碼以下

static CGFloat frameDuration(NSInteger index,CGImageSourceRef source)
{
    //獲取每一幀的信息
    CFDictionaryRef frameProperties = CGImageSourceCopyPropertiesAtIndex(source,index, nil);
    //轉換爲dic
    NSDictionary *framePropertiesDic = (__bridge NSDictionary *)frameProperties;
    //獲取每幀中關於GIF的信息
    NSDictionary *gifProperties = framePropertiesDic[(__bridge NSString *)kCGImagePropertyGIFDictionary];
    /*
     蘋果官方文檔中的說明
     kCGImagePropertyGIFDelayTime
     The amount of time, in seconds, to wait before displaying the next image in an animated sequence
     
     kCGImagePropertyGIFUnclampedDelayTime
     The amount of time, in seconds, to wait before displaying the next image in an animated sequence. This value may be 0 milliseconds or higher. Unlike the kCGImagePropertyGIFDelayTime property, this value is not clamped at the low end of the range.
     
     看了翻譯瞬間蒙了 感受同樣 可是kCGImagePropertyGIFDelayTime 可能爲0  因此我以爲能夠先判斷kCGImagePropertyGIFDelayTime
     */
    CGFloat duration = 0.1;
    
    NSNumber *unclampedPropdelayTime = gifProperties[(__bridge NSString *)kCGImagePropertyGIFUnclampedDelayTime];
    NSNumber *delayTime = gifProperties[(__bridge NSString *)kCGImagePropertyGIFDelayTime];
    
    if (unclampedPropdelayTime) {
        duration = unclampedPropdelayTime.floatValue;
    }else{
        if (delayTime) {
            duration = delayTime.floatValue;
        }
    }
    
    CFRelease(frameProperties);
    
    return duration;
}

在有了動態圖片時間後,咱們來看看後續動態圖片的實現

//動態圖片處理
static UIImage *animatedImageWithAnimateImageSource(CGImageSourceRef imageSource)
{
    if (imageSource) {
        //獲得圖片資源的數量
        size_t imageCount = CGImageSourceGetCount(imageSource);
        
        //最終圖片資源
        UIImage *resultImage = nil;
        
        //動態圖片時間
        NSTimeInterval duration = 0.0;
        //取圖片資源
        NSMutableArray *images = [NSMutableArray arrayWithCapacity:imageCount];
        
        for (size_t i = 0; i < imageCount; i ++) {
            //此處用到了create  後面記得釋放
            CGImageRef cgImage = CGImageSourceCreateImageAtIndex(imageSource, i, NULL);
            
            if (cgImage) {
                //將圖片加入到數組中
                [images addObject:[UIImage imageWithCGImage:cgImage scale:[UIScreen mainScreen].scale orientation:UIImageOrientationUp]];
            }
            
            duration += frameDuration(i, imageSource);
            
            //釋放掉 否則會內存泄漏
            CGImageRelease(cgImage);
        }
        
        if (duration == 0.0) {
            duration = 0.1 * imageCount;
        }
        
        
        resultImage = [UIImage animatedImageWithImages:images duration:duration];
        
        CFRelease(imageSource);
        
        return resultImage;
    }
    return nil;
}

這樣的話,咱們就能夠加載咱們所須要的動態圖片了。在上述代碼中,須要注意的幾個地方
一、使用了create和copy這樣的函數,咱們須要手動對其內存進行管理
二、在封裝方法的時候,我只封裝了用圖片url和圖片二進制文件以及圖片資源地址的方法,須要注意的是,在使用圖片二進制文件的時候,須要特別注意二進制文件的轉化,不能使用UIImageJPEGRepresentation,親測不對,不知道gif用此方法爲何不行,建議經過路徑的方式來獲取data,如NSData *data = [NSData dataWithContentsOfFile:imagePath],上面是核心代碼,其餘部分,能夠參考後面的demo

六、圖片添加文字或者圖片

這個比較簡單,最主要的方法就是經過drawInRect來將文字或者圖片畫到當前的畫布上,這裏就只列一個添加文字的代碼出來,添加圖片的後面能夠參考demo

+ (UIImage *)gl_addTitleAboveImage:(UIImage *)image addTitleText:(NSString *)text
                   attributeDic:(NSDictionary *)attributeDic point:(CGPoint)point
{
    UIGraphicsBeginImageContextWithOptions(image.size, NO, [UIScreen mainScreen].scale);
    
    CGRect imageRect = CGRectMake(0, 0, image.size.width, image.size.height);
    
    [image drawInRect:imageRect];
    
    [text drawAtPoint:point withAttributes:attributeDic];
    
    //獲取上下文中的新圖片
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    
    UIGraphicsEndImageContext();
    
    return newImage;
}

須要注意的是函數UIGraphicsBeginImageContextWithOptions中的最後一個參數,須要根據當前屏幕來,不然添加的文字和圖片可能會出現模糊,如在5S上面,將其設爲1

七、圖片截屏或者擦除

在這兩個功能中,最主要用到的函數是renderInContextCGContextClearRect,第一個主要是用來截屏用的,渲染當前圖片,與之接近的還有一個函數drawInContext,固然,咱們不能用這個函數,由於這個函數不能渲染圖片,只針對layer。然後面的一個函數主要是用來清除該區域的。經過上面兩個函數,咱們就可以輕鬆的實現擦除功能,就如橡皮擦功能。
代碼以下

+ (UIImage *)gl_wipeImageWithView:(UIView *)view movePoint:(CGPoint)point brushSize:(CGSize)size
{
    //開啓上下文
    UIGraphicsBeginImageContext(view.bounds.size);
    
    CGContextRef context = UIGraphicsGetCurrentContext();
    //此方法不能渲染圖片 只針對layer
    //[view.layer drawInContext:context];
    
    //以point爲中心,而後size的一半向兩邊延伸  坐畫筆  橡皮擦
    CGRect clearRect = CGRectMake(point.x - size.width/2.0, point.y - size.width/2.0, size.width, size.height);
    
    //渲染圖片
    [view.layer renderInContext:context];
    //清除該區域
    CGContextClearRect(context, clearRect);
    //獲得新圖片
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    
    UIGraphicsEndImageContext();
    //避免內存泄漏
    view.layer.contents = nil;
    
    return newImage;
}

移動路徑的代碼就不在這裏貼了,demo中有的,截屏的核心代碼也就不貼了,很簡單的,能夠查看demo

項目文件截圖:

寫在最後

其實上面的這些都是比較簡單的,主要是經過CGContextRef及其中的一些方法進行實習的,真正讓人東西的,仍是圖形的處理,如添加馬賽克、圖片濾鏡等,今天面試就問道了濾鏡,當場就蒙了,後面我會努力研究下,但願到時候也能有好的東西分享給你們。iOSQuart2D繪圖之UIImage簡單使用

代碼地址以下:
http://www.demodashi.com/demo/11609.html

注:本文著做權歸做者,由demo大師代發,拒絕轉載,轉載須要做者受權

相關文章
相關標籤/搜索