前言
采用swiftui core graphics技術(shù),與c#的gdi+繪圖類(lèi)似,具體概念不多說(shuō),畢竟我也是新手,本文主要展示效果圖及代碼,本文示例代碼需要請(qǐng)拉到文末自取。
1、圖片縮放
- 完全填充,變形壓縮
- 將圖像居中縮放截取
- 等比縮放
上面三個(gè)效果,放一起比較好對(duì)比,如下
原圖 - 完全填充,變形壓縮 - 居中縮放截取 - 等比縮放
- 第1張為原圖
- 第2張為完全填充,變形壓縮
- 第3張為圖像居中縮放截取
- 第4張為等比縮放
示例中縮放前后的圖片可導(dǎo)出
2、圖片拼圖
顧名思義,將多張圖片組合成一張圖,以下為多張美圖原圖:
多張美圖原圖
選擇后,界面中預(yù)覽:
界面中預(yù)覽
導(dǎo)出拼圖查看效果:
導(dǎo)出拼圖
3、圖片操作方法
最后上圖片縮放、拼圖代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
|
import swiftui struct imagehelper { static let shared = imagehelper() private init() {} // nsview 轉(zhuǎn) nsimage func imagefromview(cview: nsview) -> nsimage? { // 從view、data、cgimage獲取bitmapimagerep // nsbitmapimagerep *bitmap = [nsbitmapimagerep imagerepwithdata:data]; // nsbitmapimagerep *bitmap = [[[nsbitmapimagerep alloc] initwithcgimage:cgimage]; guard let bitmap: nsbitmapimagerep = cview.bitmapimagerepforcachingdisplay(in: cview.visiblerect) else { return nil } cview.cachedisplay(in: cview.visiblerect, to: bitmap) let image: nsimage = nsimage(size: cview.frame.size) image.addrepresentation(bitmap) return image; } // 保存圖片到本地 func saveimage(image: nsimage, filename: string) -> bool { guard var imagedata = image.tiffrepresentation, let imagerep = nsbitmapimagerep(data: imagedata) else { return false } // [imagerep setsize:size]; // 只是打開(kāi)圖片時(shí)的初始大小,對(duì)圖片本省沒(méi)有影響 // jpg if (filename.hassuffix( "jpg" )) { let quality:nsnumber = 0.85 // 壓縮率 imagedata = imagerep.representation(using: .jpeg, properties:[.compressionfactor:quality])! } else { // png imagedata = imagerep.representation(using: .png, properties:[:])! } do { // 寫(xiě)文件 保存到本地需要關(guān)閉沙盒 ---- 保存的文件路徑一定要是絕對(duì)路徑,相對(duì)路徑不行 try imagedata.write(to: url(fileurlwithpath: filename), options: .atomic) return true } catch { return false } } // 將圖片按照比例壓縮 // rate 壓縮比0.1~1.0之間 func compressedimagedatawithimg(image: nsimage, rate: cgfloat) -> nsdata? { guard let imagedata = image.tiffrepresentation, let imagerep = nsbitmapimagerep(data: imagedata) else { return nil } guard let data: data = imagerep.representation(using: .jpeg, properties:[.compressionfactor:rate]) else { return nil } return data as nsdata; } // 完全填充,變形壓縮 func resizeimage(sourceimage: nsimage, forsize size: nssize) -> nsimage { let targetframe: nsrect = nsmakerect( 0 , 0 , size.width, size.height); let sourceimagerep: nsimagerep = sourceimage.bestrepresentation( for : targetframe, context: nil, hints: nil)! let targetimage: nsimage = nsimage(size: size) targetimage.lockfocus() sourceimagerep.draw(in: targetframe) targetimage.unlockfocus() return targetimage; } // 將圖像居中縮放截取targetsize func resizeimage1(sourceimage: nsimage, forsize targetsize: cgsize) -> nsimage { let imagesize: cgsize = sourceimage.size let width: cgfloat = imagesize.width let height: cgfloat = imagesize.height let targetwidth: cgfloat = targetsize.width let targetheight: cgfloat = targetsize.height var scalefactor: cgfloat = 0.0 let widthfactor: cgfloat = targetwidth / width let heightfactor: cgfloat = targetheight / height scalefactor = (widthfactor > heightfactor) ? widthfactor : heightfactor // 需要讀取的源圖像的高度或?qū)挾?/code> let readheight: cgfloat = targetheight / scalefactor let readwidth: cgfloat = targetwidth / scalefactor let readpoint: cgpoint = cgpoint(x: widthfactor > heightfactor ? 0 : (width - readwidth) * 0.5 , y: widthfactor < heightfactor ? 0 : (height - readheight) * 0.5 ) let newimage: nsimage = nsimage(size: targetsize) let thumbnailrect: cgrect = cgrect(x: 0 , y: 0 , width: targetsize.width, height: targetsize.height) let imagerect: nsrect = nsrect(x: readpoint.x, y: readpoint.y, width: readwidth, height: readheight) newimage.lockfocus() sourceimage.draw(in: thumbnailrect, from: imagerect, operation: .copy, fraction: 1.0 ) newimage.unlockfocus() return newimage; } // 等比縮放 func resizeimage2(sourceimage: nsimage, forsize targetsize: cgsize) -> nsimage { let imagesize: cgsize = sourceimage.size let width: cgfloat = imagesize.width let height: cgfloat = imagesize.height let targetwidth: cgfloat = targetsize.width let targetheight: cgfloat = targetsize.height var scalefactor: cgfloat = 0.0 var scaledwidth: cgfloat = targetwidth var scaledheight: cgfloat = targetheight var thumbnailpoint: cgpoint = cgpoint(x: 0.0 , y: 0.0 ) if __cgsizeequaltosize(imagesize, targetsize) == false { let widthfactor: cgfloat = targetwidth / width let heightfactor: cgfloat = targetheight / height // scale to fit the longer scalefactor = (widthfactor > heightfactor) ? widthfactor : heightfactor scaledwidth = ceil(width * scalefactor) scaledheight = ceil(height * scalefactor) // center the image if (widthfactor > heightfactor) { thumbnailpoint.y = (targetheight - scaledheight) * 0.5 } else if (widthfactor < heightfactor) { thumbnailpoint.x = (targetwidth - scaledwidth) * 0.5 } } let newimage: nsimage = nsimage(size: nssize(width: scaledwidth, height: scaledheight)) let thumbnailrect: cgrect = cgrect(x: thumbnailpoint.x, y: thumbnailpoint.y, width: scaledwidth, height: scaledheight) let imagerect: nsrect = nsrect(x: 0.0 , y: 0.0 , width: width, height: height) newimage.lockfocus() sourceimage.draw(in: thumbnailrect, from: imagerect, operation: .copy, fraction: 1.0 ) newimage.unlockfocus() return newimage; } // 將圖片壓縮到指定大小(kb) func compressimgdata(imgdata: nsdata, toaimkb aimkb: nsinteger) -> nsdata? { let aimrate: cgfloat = cgfloat(aimkb * 1000 ) / cgfloat(imgdata.length) let imagerep: nsbitmapimagerep = nsbitmapimagerep(data: imgdata as data)! guard let data: data = imagerep.representation(using: .jpeg, properties:[.compressionfactor:aimrate]) else { return nil } print( "數(shù)據(jù)最終大小:\(cgfloat(data.count) / 1000), 壓縮比率:\(cgfloat(data.count) / cgfloat(imgdata.length))" ) return data as nsdata } // 組合圖片 func jointedimagewithimages(imgarray: [nsimage]) -> nsimage { var imgw: cgfloat = 0 var imgh: cgfloat = 0 for img in imgarray { imgw += img.size.width; if (imgh < img.size.height) { imgh = img.size.height; } } print( "size : \(nsstringfromsize(nssize(width: imgw, height: imgh)))" ) let togetherimg: nsimage = nsimage(size: nssize(width: imgw, height: imgh)) togetherimg.lockfocus() let imgcontext: cgcontext? = nsgraphicscontext.current?.cgcontext var imgx: cgfloat = 0 for imgitem in imgarray { if let img = imgitem as? nsimage { let imageref: cgimage = self.getcgimagereffromnsimage(image: img)! imgcontext?.draw(imageref, in: nsrect(x: imgx, y: 0 , width: img.size.width, height: img.size.height)) imgx += img.size.width; } } togetherimg.unlockfocus() return togetherimg; } // nsimage轉(zhuǎn)cgimageref func getcgimagereffromnsimage(image: nsimage) -> cgimage? { let imagedata: nsdata? = image.tiffrepresentation as nsdata? var imageref: cgimage? = nil if (imagedata != nil) { let imagesource: cgimagesource = cgimagesourcecreatewithdata(imagedata! as cfdata, nil)! imageref = cgimagesourcecreateimageatindex(imagesource, 0 , nil) } return imageref; } // cgimage 轉(zhuǎn) nsimage func getnsimagewithcgimageref(imageref: cgimage) -> nsimage? { return nsimage(cgimage: imageref, size: nssize(width: imageref.width, height: imageref.height)) // var imagerect: nsrect = nsrect(x: 0, y: 0, width: 0, height: 0) // // var imagecontext: cgcontext? = nil // var newimage: nsimage? = nil // // imagerect.size.height = cgfloat(imageref.height) // imagerect.size.width = cgfloat(imageref.width) // // // create a new image to receive the quartz image data. // newimage = nsimage(size: imagerect.size) // // newimage?.lockfocus() // // get the quartz context and draw. // imagecontext = nsgraphicscontext.current?.cgcontext // imagecontext?.draw(imageref, in: imagerect) // newimage?.unlockfocus() // // return newimage; } // nsimage轉(zhuǎn)ciimage func getciimagewithnsimage(image: nsimage) -> ciimage?{ // convert nsimage to bitmap guard let imagedata = image.tiffrepresentation, let imagerep = nsbitmapimagerep(data: imagedata) else { return nil } // create ciimage from imagerep let ciimage: ciimage = ciimage(bitmapimagerep: imagerep)! // create affine transform to flip ciimage let affinetransform: nsaffinetransform = nsaffinetransform() affinetransform.translatex(by: 0 , yby: 128 ) affinetransform.scalex(by: 1 , yby: - 1 ) // create cifilter with embedded affine transform let transform:cifilter = cifilter(name: "ciaffinetransform" )! transform.setvalue(ciimage, forkey: "inputimage" ) transform.setvalue(affinetransform, forkey: "inputtransform" ) // get the new ciimage, flipped and ready to serve let result: ciimage? = transform.value(forkey: "outputimage" ) as? ciimage return result; } } |
4、示例代碼
界面布局及效果展示代碼
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
|
import swiftui struct testimagedemo: view { @state private var sourceimagepath: string? @state private var sourceimage: nsimage? @state private var sourceimagewidth: cgfloat = 0 @state private var sourceimageheight: cgfloat = 0 @state private var resizeimage: nsimage? @state private var resizeimagewidth: string = "250" @state private var resizeimageheight: string = "250" @state private var resize1image: nsimage? @state private var resize1imagewidth: string = "250" @state private var resize1imageheight: string = "250" @state private var resize2image: nsimage? @state private var resize2imagewidth: string = "250" @state private var resize2imageheight: string = "250" @state private var joinimage: nsimage? var body: some view { geometryreader { reader in vstack { hstack { button( "選擇展示圖片縮放" , action: self.choiceresizeimage) button( "選擇展示圖片拼圖" , action: self.choicejoinimage) spacer() } hstack { vstack { if let simage = sourceimage { section(header: text( "原圖" )) { image(nsimage: simage) .resizable().aspectratio(contentmode: .fit) .frame(width: reader.size.width / 2 ) text( "\(self.sourceimagewidth)*\(self.sourceimageheight)" ) button( "導(dǎo)出" , action: { self.saveimage(image: simage) }) } } if let simage = self.joinimage { section(header: text( "拼圖" )) { image(nsimage: simage) .resizable().aspectratio(contentmode: .fit) .frame(width: reader.size.width) button( "導(dǎo)出" , action: { self.saveimage(image: simage) }) } } } vstack { section(header: text( "完全填充,變形壓縮" )) { vstack { section(header: text( "width:" )) { textfield( "width" , text: self.$resizeimagewidth) } section(header: text( "height:" )) { textfield( "height" , text: self.$resizeimageheight) } if let simage = resizeimage { image(nsimage: simage) text( "\(self.resizeimagewidth)*\(self.resizeimageheight)" ) button( "導(dǎo)出" , action: { self.saveimage(image: simage) }) } } } } vstack { section(header: text( "將圖像居中縮放截取" )) { vstack { section(header: text( "width:" )) { textfield( "width" , text: self.$resize1imagewidth) } section(header: text( "height:" )) { textfield( "height" , text: self.$resize1imageheight) } if let simage = resize1image { image(nsimage: simage) text( "\(self.resize1imagewidth)*\(self.resize1imageheight)" ) button( "導(dǎo)出" , action: { self.saveimage(image: simage) }) } } } } vstack { section(header: text( "等比縮放" )) { vstack { section(header: text( "width:" )) { textfield( "width" , text: self.$resize2imagewidth) } section(header: text( "height:" )) { textfield( "height" , text: self.$resize2imageheight) } if let simage = resize2image { image(nsimage: simage) text( "\(self.resize2imagewidth)*\(self.resize2imageheight)" ) button( "導(dǎo)出" , action: { self.saveimage(image: simage) }) } } } } spacer() } spacer() } } } private func choiceresizeimage() { let result: (fail: bool, url: [url?]?) = dialogprovider.shared.showopenfiledialog(title: "" , prompt: "" , message: "選擇圖片" , directoryurl: url(fileurlwithpath: "" ), allowedfiletypes: [ "png" , "jpg" , "jpeg" ]) if result.fail { return } if let urls = result.url, let url = urls[ 0 ] { self.sourceimagepath = url.path self.sourceimage = nsimage(contentsof: url(fileurlwithpath: self.sourceimagepath!)) self.sourceimagewidth = (self.sourceimage?.size.width)! self.sourceimageheight = (self.sourceimage?.size.height)! if let resizewidth = int (self.resizeimagewidth), let resizeheight = int (self.resizeimageheight) { self.resizeimage = imagehelper.shared.resizeimage(sourceimage: self.sourceimage!, forsize: cgsize(width: resizewidth, height: resizeheight)) } if let resize1width = int (self.resize1imagewidth), let resize1height = int (self.resize1imageheight) { self.resize1image = imagehelper.shared.resizeimage1(sourceimage: self.sourceimage!, forsize: cgsize(width: resize1width, height: resize1height)) } if let resize2width = int (self.resize2imagewidth), let resize2height = int (self.resize2imageheight) { self.resize2image = imagehelper.shared.resizeimage1(sourceimage: self.sourceimage!, forsize: cgsize(width: resize2width, height: resize2height)) } } } private func choicejoinimage() { let result: (fail: bool, url: [url?]?) = dialogprovider.shared.showopenfiledialog(title: "" , prompt: "" , message: "選擇圖片" , directoryurl: url(fileurlwithpath: "" ), allowedfiletypes: [ "png" , "jpg" , "jpeg" ], allowsmultipleselection: true ) if result.fail { return } if let urls = result.url { var imgs: [nsimage] = [] for url in urls { if let filepath = url?.path { imgs.append(nsimage(contentsof: url(fileurlwithpath: filepath))!) } } if imgs.count > 0 { self.joinimage = imagehelper.shared.jointedimagewithimages(imgarray: imgs) } } } private func saveimage(image: nsimage) { let result: (isopenfail: bool, url: url?) = dialogprovider.shared.showsavedialog( title: "選擇圖片存儲(chǔ)路徑" , directoryurl: url(fileurlwithpath: "" ), prompt: "" , message: "" , allowedfiletypes: [ "png" ] ) if result.isopenfail || result.url == nil || result.url!.path.isempty { return } let exportimagepath = result.url!.path _ = imagehelper.shared.saveimage(image: image, filename: exportimagepath) nsworkspace.shared.activatefileviewerselecting([url(fileurlwithpath: exportimagepath)]) } } struct testimagedemo_previews: previewprovider { static var previews: some view { testimagedemo() } } |
5、結(jié)尾
所有代碼已貼,并且代碼已上傳github,見(jiàn)下面?zhèn)渥ⅰ?/p>
本文示例代碼:https://github.com/dotnet9/mactest/blob/main/src/macos_test/macos_test/testimagedemo.swift
參考文章標(biāo)題:《mac圖像nsimage縮放、組合、壓縮及ciimageref和nsimage轉(zhuǎn)換處理》
參考文章鏈接:https://www.freesion.com/article/774352759/
到此這篇關(guān)于swiftui圖片縮放、拼圖等處理的文章就介紹到這了,更多相關(guān)swiftui圖片縮放、拼圖內(nèi)容請(qǐng)搜索服務(wù)器之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持服務(wù)器之家!
原文鏈接:https://www.cnblogs.com/Dotnet9-com/p/15171001.html