仿射變換(二)- UIView的平移,旋轉,放縮


1、回顧

? ? ? ?上一節中,我們實現一個UIImageView的移動,放縮,旋轉,并把這些數據存儲在Transform屬性里面,但我們知道,這些數據只是用于當前低畫質的圖片,而我們需要的是處理原圖(高品質的圖片)。因此,這一節,我們將實現如何把Tranform屬性應用在原圖上面。

2、畫圖

? ? ? ?很容易,我們便相當了畫圖的功能,自然而然想到了CoreGraphics,然后我查了查API,很高興,CoreGraphics 也有矩陣應用API,如:

  • CGContextTranslateCTM
  • CGContextConcatCTM
  • ……

? ? ? ?那直接開干,創建一個類 UIImage+Extensions

- (UIImage *)handleOriginImage:(CGAffineTransform)transform{
    UIGraphicsBeginImageContext(self.size);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextConcatCTM(context, transform);

    //self 即當前的UIImage
    [self drawInRect:CGRectMake(0, 0, self.size.width, self.size.height)];
    UIImage *copy = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return copy;
}

? ? ? ?感覺對的啊。沒有問題,但運行結果和期望的大相徑庭,不知道什么原因??!通過慢慢排查,你會發現是 定點 在搞鬼。

? ? ? ?我們都知道的在 UIImageView 進行旋轉放縮的時候,我們默認設置的是 UIImageView 的中心點為定點 anchor Point,而你在作圖的時候,你會驚奇的發現,畫圖的定點一直是左上角,所以旋轉和放縮之后,得到的結果相差很大。

? ? ? ?那自然而然,想到,該如何改變畫布的定點,可惜我找了大半天也沒找到。??赡苁俏姨酰坑邪l現的大神請告訴我?。?!那難道,我只能把 UIImageView 操作的時候的定點,設置到左上角?那樣體驗也太不好了吧。。。

? ? ? ?后來想到,記得上一節,在圖片移動的時候,我們用過三角函數,進行變換,那當然我們這兒也可以。坐標系東西都可以用數學知識進行改變的。

3、解決方案

圖示:

圖1.png

? ? ? ?我可以先把圖片移動到特定的位置,讓其按左上角旋轉之后的結果,和在原始位置按中心點旋轉的結果一樣。(為什么不在圖片旋轉之后再移動位置呢?如上節說過,圖片矩陣旋轉,會改變坐標系,那時候的移動得相對于那時的坐標系,操作起來更加繁瑣!因此,我們在最初進行坐標移動矯正,然后應用矩陣)

- (UIImage *)handleOriginImage:(CGAffineTransform)transform scale:(CGFloat)scale{
    UIGraphicsBeginImageContext(self.size);
    CGContextRef context = UIGraphicsGetCurrentContext();

    //先計算出操作圖的旋轉角度和放縮比例
    CGFloat editDegree = atan2(transform.b, transform.a);
    CGFloat editScale = sqrt(pow(transform.a, 2) + pow(transform.c, 2));

    //通過計算,在操作之前,修正左上角的位置
    CGFloat diameter = sqrt(pow(self.size.width, 2)+pow(self.size.height, 2));
    CGFloat originDegree = asin(self.size.height / diameter);
    CGFloat currentDegree = originDegree + editDegree;

    CGFloat newX = self.size.width / 2 - cos(currentDegree) * diameter * editScale / 2;
    CGFloat newY = self.size.height / 2 - sin(currentDegree) * diameter * editScale/ 2;

    //水平的操作,在原圖上進行修正,tx,ty分別代表 X,Y軸移動的距離
    transform.tx = transform.tx * scale;
    transform.ty = transform.ty * scale;

    //先修正左上角的位置
    CGContextTranslateCTM(context, newX, newY);

    //對3*3矩陣進行渲染
    CGContextConcatCTM(context, transform);

    [self drawInRect:CGRectMake(0, 0, self.size.width, self.size.height)];
    UIImage *copy = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return copy;
}

? ? ? ?代碼很清楚,一點需要解釋: //水平的操作,在原圖上進行修正 這部分的代碼,因為在UIImageView上面做的操作,比如當時圖片是 100 * 100, 原圖是1000 * 1000,所以當時的移動距離,在原圖上面應該放大10倍,所以這里主要做這個處理。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 1、需求來源: 現在需要實現一個圖片編輯功能,能夠對一個圖片進行平移,旋轉,放縮。因為考慮到圖片操作的流暢度...
    iven_zf閱讀 2,329評論 0 5
  • Core Animation其實是一個令人誤解的命名。你可能認為它只是用來做動畫的,但實際上它是從一個叫做Laye...
    小貓仔閱讀 3,803評論 1 4
  • 第一部分:CocoaPods 的使用 需求 在 iOS 開發過程中,當你需要使用必要的三方庫時,是否被各種庫搞得筋...
    小白進城閱讀 2,454評論 0 2
  • 發現 關注 消息 iOS 第三方庫、插件、知名博客總結 作者大灰狼的小綿羊哥哥關注 2017.06.26 09:4...
    肇東周閱讀 12,257評論 4 61
  • 2017.07.05 星期三 陰轉雨 農歷六月十二 這兩天女兒休息寶寶帶回去的,老媽也去農家樂玩了,家里就留我一個...
    小幸福vs茹萍閱讀 250評論 0 0