SwiftUI图片缩放、拼图等处理教程

SwiftUI是一种使用Swift语言在苹果设备上构建用户界面的创新且简单的方式,下面这篇文章主要给大家介绍了关于SwiftUI图片缩放、拼图等处理的相关资料,需要的朋友可以参考下

前言

采用SwiftUI Core Graphics技术,与C#的GDI+绘图类似,具体概念不多说,毕竟我也是新手,本文主要展示效果图及代码,本文示例代码需要请拉到文末自取。

1、图片缩放

  • 完全填充,变形压缩
  • 将图像居中缩放截取
  • 等比缩放

上面三个效果,放一起比较好对比,如下

原图 - 完全填充,变形压缩 - 居中缩放截取 - 等比缩放

  • 第1张为原图
  • 第2张为完全填充,变形压缩
  • 第3张为图像居中缩放截取
  • 第4张为等比缩放

示例中缩放前后的图片可导出

2、图片拼图

顾名思义,将多张图片组合成一张图,以下为多张美图原图:

多张美图原图

选择后,界面中预览:

界面中预览

导出拼图查看效果:

导出拼图

3、图片操作方法

最后上图片缩放、拼图代码:

 import SwiftUI struct ImageHelper { static let shared = ImageHelper() private init() {} // NSView 转 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];  // 只是打开图片时的初始大小,对图片本省没有影响 // 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-600, properties:[:])! } do { // 写文件 保存到本地需要关闭沙盒  ---- 保存的文件路径一定要是绝对路径,相对路径不行 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 // 需要读取的源图像的高度或宽度 let readHeight: CGFloat = targetHeight / scaleFactor let readWidth: CGFloat = targetWidth / scaleFactor let readPoint: CGPoint = CGPoint(x: widthFactor > heightFactor ? 0 : (width - readWidth) * 0.5, y: widthFactor  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  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("数据最终大小:\(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  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 转 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转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、示例代码

界面布局及效果展示代码

 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("导出", 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("导出", 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("导出", 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("导出", 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("导出", 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: "选择图片存储路径", 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、结尾

所有代码已贴,并且代码已上传Github,见下面备注。

本文示例代码:https://github.com/dotnet9/MacTest/blob/main/src/macos_test/macos_test/TestImageDemo.swift

参考文章标题:《MAC图像NSIMAGE缩放、组合、压缩及CIIMAGEREF和NSIMAGE转换处理》

参考文章链接:https://www.freesion.com/article/774352759/

以上就是SwiftUI图片缩放、拼图等处理教程的详细内容,更多请关注0133技术站其它相关文章!

赞(0) 打赏
未经允许不得转载:0133技术站首页 » 其他教程