iOS 图片处理学习: 实现点九切图

1,014 阅读1分钟

先来一个例子: 一张图片,保留中间, 拉伸两边

看效果
  • 原始图片

easy

easy.png

  • 处理后

截屏2022-01-19 上午3.42.36.png

调用代码
        view.backgroundColor = UIColor.white

        let imgViewWidth: CGFloat = 300

        let imgView = UIImageView(frame: CGRect(origin: CGPoint(x: 50, y: 250), size: CGSize(width: imgViewWidth, height: 100)))

        imgView.contentMode = .scaleAspectFit

        view.addSubview(imgView)

        if let image = UIImage(named: "easy"), let img = stretchImageSides(image: image, newWidth: imgViewWidth){

            imgView.image = img

        }
        
实现代码

逻辑比较简单,

  • 先拉左边

拉升最左边 3 pt 的图片

保留其他部分不变

  • 再拉右边

拉升最右边 3 pt 的图片

保留其他部分不变

这两步的区别是,

画布拉大

func stretchImageSides(image: UIImage, newWidth: CGFloat) -> UIImage? {
        guard image.size.width < newWidth else {
            return image
        }

        let originalWidth = image.size.width
        let tiledAreaWidth = ceil(newWidth - originalWidth) / 2.0

        UIGraphicsBeginImageContextWithOptions(CGSize(width: originalWidth + tiledAreaWidth, height: image.size.height),
                                               false, image.scale)

        let firstResizable = image.resizableImage(withCapInsets: UIEdgeInsets(top: 0,
                                                                              left: 0,
                                                                              bottom: 0,
                                                                              right: originalWidth - 3),
                                                  resizingMode: .stretch)
        
        
        // 先拉左边
        firstResizable.draw(in: CGRect(x: 0, y: 0, width: originalWidth + tiledAreaWidth, height: image.size.height))

        let leftPart = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        UIGraphicsBeginImageContextWithOptions(CGSize(width: newWidth, height: image.size.height),
                                               false, image.scale)

        let secondResizable = leftPart?.resizableImage(withCapInsets: UIEdgeInsets(top: 0,
                                                                                  left: tiledAreaWidth + originalWidth - 3,
                                                                                  bottom: 0,
                                                                                  right: 0),
                                                  resizingMode: .stretch)
        
        // 再拉右边
        secondResizable?.draw(in: CGRect(x: 0, y: 0, width: newWidth, height: image.size.height))

        let fullImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        return fullImage
    }

分步演示: 配合理解

只拉左边

完成一半


    func stretchImageSides(image: UIImage, newWidth: CGFloat) -> UIImage? {
        guard image.size.width < newWidth else {
            return image
        }

        let originalWidth = image.size.width
        let tiledAreaWidth = ceil(newWidth - originalWidth) / 2.0

        UIGraphicsBeginImageContextWithOptions(CGSize(width: originalWidth + tiledAreaWidth, height: image.size.height),
                                               false, image.scale)

        let firstResizable = image.resizableImage(withCapInsets: UIEdgeInsets(top: 0,
                                                                              left: 0,
                                                                              bottom: 0,
                                                                              right: originalWidth - 3),
                                                  resizingMode: .stretch)
        
        
        // 先拉左边
        firstResizable.draw(in: CGRect(x: 0, y: 0, width: originalWidth + tiledAreaWidth, height: image.size.height))

        let leftPart = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        return leftPart
    }


  • 效果图:

截屏2022-01-19 上午3.55.25.png

实现,点九切图

例子:

  • 原始图:

gift.9

gift.9.png

  • 处理后

截屏2022-01-19 上午3.57.49.png

这里的效果,是左右的拉伸
调用代码
        // 其他,同上例
        
        if let image = UIImage(named: "gift.9"), let img = stretch(image: image, newWidth: imgViewWidth){
             imgView.image = img
         }

点九图的实现

这里多了一步,先做图片切割,再做图片的左右拉伸

图片切割部分:
     func crop(img: UIImage, with rect: CGRect) -> UIImage? {
            guard let cgImg = img.cgImage else { return nil }
            if let imageRef: CGImage = cgImg.cropping(to: rect){
                let image: UIImage = UIImage(cgImage: imageRef, scale: img.scale, orientation: img.imageOrientation)
                return image
            }
            else{
                return nil
            }
        }

图片拉伸部分:


// 拆分拉伸
    func stretch(image: UIImage, newWidth: CGFloat) -> UIImage? {
        guard image.size.width < newWidth else {
            return image
        }

        let originalWidth = image.size.width
        let offset: CGFloat = 1
        // 先切左边
        let left = crop(img: image, with: CGRect(x: 0, y: 0, width: originalWidth/2, height: image.size.height))
        // 再切右边
        let right = crop(img: image, with: CGRect(x: originalWidth/2, y: 0, width: originalWidth/2, height: image.size.height))

        UIGraphicsBeginImageContextWithOptions(CGSize(width: newWidth, height: image.size.height),
                                               false, image.scale)

        let lhsResizable = left?.resizableImage(withCapInsets: UIEdgeInsets(top: 0,
                                                                                  left: originalWidth/2 - offset,
                                                                                  bottom: 0,
                                                                                  right: 0),
                                                  resizingMode: .stretch)
        // 绘制左边部分的拉伸图
        lhsResizable?.draw(in: CGRect(x: 0, y: 0, width: newWidth/2, height: image.size.height))
        
        let rhsResizable = right?.resizableImage(withCapInsets: UIEdgeInsets(top: 0,
                                                                                  left: 0,
                                                                                  bottom: 0,
                                                                                  right: originalWidth/2 - offset),
                                                  resizingMode: .stretch)
         // 绘制右边部分的拉伸图
        rhsResizable?.draw(in: CGRect(x: newWidth/2, y: 0, width: newWidth/2, height: image.size.height))

        let fullImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        return fullImage
    }