swiftui图片缩放、拼图等处理教程-kb88凯时官网登录

来自:网络
时间:2023-07-25
阅读:
目录

前言

采用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, properties:[:])!
        }
        
        do {
            // 写文件 保存到本地需要关闭沙盒  ---- 保存的文件路径一定要是绝对路径,相对路径不行
            try imagedata.write(to: , 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 < 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("数据最终大小:\(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转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 转 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: , 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: )
            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: , 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: )!)
                }
            }
            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: ,
                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([])
    }
}
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/

返回顶部
顶部
网站地图