你好,歡迎進入江蘇優(yōu)軟數(shù)字科技有限公司官網(wǎng)!
發(fā)布時間:2023-05-24
瀏覽次數(shù):0
戰(zhàn)斗社區(qū)
Java實戰(zhàn)社區(qū)
長按識別下方二維碼,按需添加
掃碼關注并添加客服
走進社區(qū)▲
掃碼關注并添加客服
進入Java社區(qū)▲
作者| 小豬
來源 | 小豬的博客
介紹
矢量圖形是指通過一系列物理描述,可以無損地改變和縮放的圖像。 與標量圖像(如JPEG等標量圖像壓縮格式)相比,它在素描時可以任意縮放而不模糊,甚至可以實現(xiàn)動態(tài)著色、動畫等一系列交互。
在聯(lián)通設備規(guī)格越來越復雜,各種操作系統(tǒng)級別的夜間主題(或)越來越被提倡的場景下,如果我們仍然使用標量圖形,我們需要針對不同的屏幕尺寸(比如2x , 3x ), 以及相應的主題場景(Light/Dark), 提供了NxM階的標量圖,對于App的大小來說是非常昂貴的。 因此,使用矢量圖形是一種非常有效的解決方案。 本系列文章主要著重講解iOS端的矢量圖解決方案。
第一章是關于SVG及其對應衍生的解決方案,之后還會有其他PDF章節(jié)涉及到矢量圖等sketch導出svg圖標,它們各自有不同的詳細場景判斷和優(yōu)缺點。
SVG是目前Web上最流行的矢量格式,在iOS端的支持可以說是一言難盡。 在這里,我從各個方向(公開的方案,企業(yè)內部的實現(xiàn)無從知曉)總結目前已有的實現(xiàn)方式,對比選擇最適合自己場景的方案。
圖像
Image是Apple在和iOS13上提供的矢量圖形分析解決方案。
之所以命名為Image,來源于該技術方案的實現(xiàn)細節(jié)。 它最先誕生于SVG字體規(guī)范:-SVG。 該規(guī)范由 Adob??e 提出,但得到了很多公司的支持,包括 . 蘋果自己的字體框架,雖然早在iOS11時代內部就支持了SVG類型的。
制作圖像
Image整體的API設計,雖然不像是圖片,更像是一種字體(類似)。
對于同一個Image,可以看成是的集合。 上面說了,Image是基于-SVG字體的。 對于字體,我們都知道字體粗細的概念,它用來決定渲染時腰線的粗細。
因此,Image也有9個權重:, Thin, Light,,,, Bold, Heavy, Black。 同時,Image 支持每個詞權重有 3 種尺寸,即 Small 和 Large。 也就是說一個Image最多可以有27種大小和粗細的樣式。
一般來說,從頭開始創(chuàng)建圖像非常復雜。 Apple推薦的形式是使用SFApp導入一個SVG模板,然后用它來編輯。
從原始SVG數(shù)據(jù)來看,每個Image包含的所有樣式都是一個Path節(jié)點,對應圖標的輪廓。 如果要新建一個Image,需要完全刪除Path節(jié)點,重新繪制矢量路徑。
導出圖像
導出圖片的方法非常簡單。 你只需要將準備好的圖片拖到Xcode的Asset窗口中就可以集成了。 Xcode可以顯示相應的預覽效果。
另外,實際形成的文件夾后綴是.,區(qū)別于普通的(后綴.),也就是說可以同時引入一個同名的Image和一個普通的Image。
使用圖像
對于iOS13系統(tǒng)提供的內置Image,UIKit提供了init(:)方法來獲取。 對于App本身提供的Image,我們使用了init(named:)技術。
請注意,您可以同時包含一個圖像和一個普通的 ,共享一個名稱。 這樣設計的好處,在WWDC上介紹過,就是可以兼容iOS12等低系統(tǒng)版本。 在 iOS13 上,Image 的優(yōu)先級總是低于普通的 ,在 iOS12 上則為手動。
let imageView = UIImageView()
let symbolImage = UIImage(named: "my.symbol.image")
// 默認配置下,這個symbol image是template的,意味著他不會含有顏色,顏色由UIView級別tintColor決定
imageView.image = symbolImage
// 如果確定要獲取系統(tǒng)Symbol Image
let systemSymbolImage = UIImage(systemName: "wifi.exclamationmark")
// 如果要指定顏色
let redSymbolImage = symbolImage.withTintColor(.red, renderingMode: .alwaysOrigin)
imageView.image = redSymbolImage
對于Image,我們可以指定運行時需要的字體粗細
let regularSymbolImage = UIImage(named: "my.symbol.image")
// 指定你想要的字號,字重,這里是18號,Bold 字重,Large 大小
let symbolConfiguration = UImage.SymbolConfiguration(pointSize: 18, weight: .large, scale: .large)
let boldSymbolImage = regularSymbolImage.applyingSymbolConfiguration(symbolConfiguration)
imageView.image = boldSymbolImage
另外,我們也可以配合使用,只要傳入對應的Image即可。
let textView = UITextView()
// 可以微調Symbol Image與文字的對齊
let baselineSymbolImage = symbolImage.withBaselineOffset(fromBottom: 1.0)
let imageAttachment = NSTextAttachment(image: baselineSymbolImage)
let imageString = NSAttributedString(attachment: imageAttachment)
textView.attributedText = imageString
共同點和不同點
優(yōu)勢:
? iOS原生支持,工具鏈建立
? 原生支持,迄今為止Image唯一可以使用的矢量方案(排除)
? 支持和無縫混合,類似于
缺點:
?僅限iOS13+
? 通過字體屬性控制大小,視UI場景而定,Pixel級別的拉伸會出問題
?需要單獨做一個Image,跨平臺,Web使用痛點
它是iOS13支持Image的底層SVG渲染引擎,用C++編寫。
目前為止,還是屬于的,社區(qū)也有很多人向蘋果反饋,建議開放。 也許以后我們會在 得到更多的消息。
注意! 以下方法均為使用的API,可能會隨著操作系統(tǒng)的變化而變化,存在初審風險。 如需在線使用,請自行進行代碼混淆等解決方案。
將 SVG 與資產(chǎn)一起使用
目前Xcode不支持直接拖拽SVG文件集成到中,因為拖拽SVG默認會被當做Image處理。
但是,我們可以通過一種巧妙的方法來實現(xiàn)它。 Xcode支持PDF矢量圖(從iOS11和開始支持,PDF章節(jié)會說明)。 因此,我們可以把SVG后綴改成PDF,然后拖到Xcode中,最后再改回SVG后綴,只是同步./.json上面的文件名即可,如下:
添加完SVG圖片后,就可以通過Name導入和使用PDF矢量圖一樣的方式使用了,如下
UIImageView *imageView = [UIImageView new];
UIImage *svgImage = [UIImage imageNamed:@"my_svg"];
imageView.image = svgImage;
// 然后我們可以自由縮放ImageView的大小,會自動觸發(fā)矢量繪制
imageView.frame = CGRectMake(0, 0, 1000, 1000);
從運行時的角度來看,添加到Asset中的SVG矢量圖形不僅有豐富的對應對象,而且還包含標量圖像的縮略圖,可以通過縮略圖或其他系統(tǒng)API調用。 并且Xcode上會有顯眼的SVG標記(類似于PDF)
加載任意 SVG 數(shù)據(jù)(網(wǎng)絡)
不僅可以通過Asset添加SVG圖片,還可以在運行時分析從網(wǎng)絡數(shù)據(jù)下載的SVG數(shù)據(jù),提供更廣泛的應用場景。
UIImageView *imageView = [UIImageView new];
NSData *data;
CGSVGDocumentRef document = CGSVGDocumentCreateFromData((__bridge CFDataRef)data, NULL);
UIImage *svgImage = [UIImage _imageWithCGSVGDocument:document];
imageView.image = svgImage;
將 SVG 矢量圖形渲染為標量圖形
一些UIKit視圖,或者一些圖像處理,沒有考慮矢量圖的支持,或者我們在做性能優(yōu)化的時候,需要對矢量圖進行光柵化得到對應的標量圖形。 提供類似PDF的界面,讓你繪制相應的標量圖。
CGSVGDocumentRef document; // 原始SVG Document
CGSize targetSize; // 指定標量圖大小
BOOL preserveAspectRatio; // 是否保持寬高比
// 獲取SVG的canvas大小,本質上是按照SVG規(guī)范,將viewPort和viewBox計算得出的
CGSize size = CGSVGDocumentGetCanvasSize(document);
// 計算Transform
CGFloat xRatio = targetSize.width / size.width;
CGFloat yRatio = targetSize.height / size.height;
CGFloat xScale = preserveAspectRatio ? MIN(xRatio, yRatio) : xRatio;
CGFloat yScale = preserveAspectRatio ? MIN(xRatio, yRatio) : yRatio;
CGAffineTransform scaleTransform = CGAffineTransformMakeScale(xScale, yScale);
CGSize scaledSize = CGSizeApplyAffineTransform(size, scaleTransform);
CGAffineTransform translationTransform = CGAffineTransformMakeTranslation(targetSize.width / 2 - scaledSize.width / 2, targetSize.height / 2 - scaledSize.height / 2);
// 開始CGContext繪制
UIGraphicsBeginImageContextWithOptions(targetSize, NO, 0);
CGContextRef context = UIGraphicsGetCurrentContext();
// UIKit坐標系和CG坐標系轉換
CGContextTranslateCTM(context, 0, targetSize.height);
CGContextScaleCTM(context, 1, -1);
// 應用Transform
CGContextConcatCTM(context, translationTransform);
CGContextConcatCTM(context, scaleTransform);
// 繪制SVG Document
CGContextDrawSVGDocument(context, document);
// 獲取標量圖
image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
SVG導入
目前沒有類似PDF的換元素接口,只能直接導入。 事實上,未來隨著框架的開放,會有類似現(xiàn)在PDF編輯的中間界面。
// 獲取SVG Document
UIImage *svgImage;
CGSVGDocumentRef document = [svgImage _CGSVGDocument];
NSURL *url = [NSURL fileURLWithPath:@"/tmp/output.svg"];
NSMutableData *data = [NSMutableData data];
// 導出到Data
CGSVGDocumentWriteToData(document, (__bridge CFMutableDataRef)data, NULL);
// 或者文件
CGSVGDocumentWriteToURL(document, (__bridge CFURLRef)url, NULL);
共同點和不同點
優(yōu)勢
? 支持目前可用的大量SVG,并在Web端復用
? 蘋果原生支持,穩(wěn)定性有保障,會隨著系統(tǒng)升級不斷優(yōu)化
? 高性能,借助系統(tǒng)庫和內部SPI進行矢量圖繪制,目前性能最好
缺點
?目前為私有,初審和使用存在風險
? 部分SVG元素可能存在兼容性問題,需要不斷探索
? 不支持,需要使用
三方SVG庫
它是 iOS 上最早的開源 SVG 渲染方案,已經(jīng)有 8 年的歷史了。 內部支持兩種渲染方式,一種是通過CPU渲染(重繪),一種是通過GPU渲染(樹組合)。 有不同的兼容性和性能。
例子
// CPU渲染
SVGKImageView *imageView = [SVGKFastImageView new];
// GPU渲染
imageView = [SVGKLayeredImageView new];
SVGKImage *svgImage = [[SVGKImage alloc] initWithData:data];
imageView.image = svgImage;
優(yōu)勢
? 支持純C
? 如果支持圖像,則性能相對較高(一秒可渲染1000級Path)
缺點
? 社區(qū)不再維護,大量Issue無人跟進解決
? 不尊重語義版本控制,用分支發(fā)布更新,下游不依賴
? 部分SVG特性確實支持sketch導出svg圖標,但存在缺少單測等問題
? 不支持 SVG 動畫
金剛鸚鵡
Macaw是一個矢量繪圖框架,它提供了一個非常簡單的DSL句型來描述矢量路徑繪制的場景。它本身并沒有與SVG強綁定,并且提供了對SVG格式的兼容和支持
例子
let node = try! SVGParser.parse(path: "/path/to/svg")
let imageView = SVGView()
imageView.node = node
優(yōu)勢
?目前最活躍最成熟的iOS端SVG開源框架(上)
? 支持DSL直接生成矢量圖,改變節(jié)點等,非常強大
?支持SVG動畫(部分功能)
缺點
如有侵權請聯(lián)系刪除!
Copyright ? 2023 江蘇優(yōu)軟數(shù)字科技有限公司 All Rights Reserved.正版sublime text、Codejock、IntelliJ IDEA、sketch、Mestrenova、DNAstar服務提供商
13262879759
微信二維碼