网站如何做301,中国建筑网官网查询证书,推广app的单子都在哪里接的,html网站标题怎么做背景 某日产品拿来了一个由30多页高清长图生成的pdf#xff0c;在应用中运行出现了崩溃。
排查 经过调试发现加载长图生成的pdf时#xff0c;运行内存会出现缓慢增长#xff0c;直至崩溃。经过代码定位发现时pdf转成image对象的过程中由于是长图生成的pdf#xff0c;这一页…背景 某日产品拿来了一个由30多页高清长图生成的pdf在应用中运行出现了崩溃。
排查 经过调试发现加载长图生成的pdf时运行内存会出现缓慢增长直至崩溃。经过代码定位发现时pdf转成image对象的过程中由于是长图生成的pdf这一页的pdf的size相当于正常pdfsize的30多页转换的过程中context的fill的size也是正常pdf的30多倍。经过调研尝试发现对于同一页的pdf可以通过调整context的fill的size来只把pdf中的部分内容转换成image对象内存正常也不大。
方案 原来的方案是每页pdf生成一个image对象通过一个collectonViewCell来显示。调整后的方案为根据屏幕大小来决定一个pdf页面生成多少个image对象有多少个image对象一个section里就有多少个cell。方案如下
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) - CGSize {if pdfSize.height/pdfSize.width 3.0 { //长图生成的pdf 备注pdfSize 即一页pdf的大小let visible_width pdfSize.widthlet visible_height visible_width * Board_height/Board_widthlet visibleSize CGSize(width: visible_width, height: visible_height)let count:Int Int(ceil(pdfSize.height/visible_height))// 计算需要分割的次数let index:Intlet itemSize:CGSizeif indexPath.item count {index indexPath.item} else {index count - 1}if CGFloat(index) * visibleSize.height visibleSize.height pdfSize.height {itemSize visibleSize} else {let tailHeight pdfSize.height - CGFloat(index) * visibleSize.heightitemSize CGSize(width: visibleSize.width, height: tailHeight)}return itemSize}return pdfSize}在讲pdf转成image对象的过程中方案调整核心代码如下
//index就是pdf中的从上往下被分割后的image的索引值private func subImageFromLongPDF(ori_page:PDFPage, pdfSize:CGSize, index:Int) - UIImage {guard let page ori_page.pageRef else {return UIImage()}var dic [PDFAnnotation:CGRect]()let originalPageRect ori_page.originalPageRectlet elaborate: CGFloat 1.0let scale_W pdfSize.width / originalPageRect.size.width * elaboratelet scale_H pdfSize.height / originalPageRect.size.height * elaboratelet width originalPageRect.size.width * scale_Wlet height width * Board_height/Board_width // Board_height屏幕高度Board_width屏幕宽度let visibleSize CGSize(width: width, height: height)let rotation ori_page.rotationori_page.rotation 0let scaledOrigin CGPoint(x: originalPageRect.origin.x * scale_W, y: originalPageRect.origin.y * scale_H)let scaledPageSize CGSize(width: originalPageRect.size.width * scale_W, height: originalPageRect.size.height * scale_H)let scaledPageRect:CGRectvar tailHeight 0.0if CGFloat(index) * visibleSize.height height scaledPageSize.height {scaledPageRect CGRect(origin: CGPoint(x: 0, y: CGFloat(index) * visibleSize.height), size: visibleSize)} else {tailHeight scaledPageSize.height - CGFloat(index) * visibleSize.heightscaledPageRect CGRect(origin: CGPoint(x: 0, y: CGFloat(index) * visibleSize.height), size: CGSize(width: visibleSize.width, height: tailHeight))}var img:UIImage?autoreleasepool {let renderer UIGraphicsImageRenderer(size: scaledPageRect.size)var tmpImg:UIImage? renderer.image {ctx inUIColor.white.set()//这个核心代码scaledPageRect就是计算好的rectctx.fill(scaledPageRect)let rotationAngle: CGFloatswitch page.rotationAngle {//保持和安卓一致强制为0了case 90:rotationAngle 270//平移 以用户空间为单位指定上下文的坐标空间 x 轴的位移量。ctx.cgContext.translateBy(x: -scaledPageRect.origin.x, y: 0)case 180:rotationAngle 180//平移ctx.cgContext.translateBy(x: scaledPageRect.width,y: 0)case 270:rotationAngle 90//平移ctx.cgContext.translateBy(x: scaledPageRect.origin.x, y: scaledPageRect.size.height - scaledPageRect.origin.y)default:rotationAngle 0//平移 以用户空间为单位指定上下文的坐标空间 x 轴的位移量。//指定上下文的坐标空间 y 轴的位移量以用户空间为单位。if rotation 180 {if tailHeight 0 {//尾部不足一屏的特殊处理逻辑ctx.cgContext.translateBy(x: 0 - scaledOrigin.x, y: 0 scaledOrigin.y CGFloat(index1) * visibleSize.height - (visibleSize.height - tailHeight))//翻转180度正常} else {ctx.cgContext.translateBy(x: 0 - scaledOrigin.x, y: 0 scaledOrigin.y CGFloat(index1) * visibleSize.height)//翻转180度正常}} else {ctx.cgContext.translateBy(x: 0 - scaledOrigin.x, y: scaledPageSize.height scaledOrigin.y - scaledPageRect.origin.y)}}//Rotate是以原点为圆心旋转,Quartz创建的图形上下文旋转圆心为左下角角度值正数为逆时针旋转负数为顺时针旋转//UIKit创建的图像上下文旋转圆心为左上角,角度值正数为顺时针旋转负数为逆时针旋转。// Flip the context vertically because the Core Graphics coordinate system starts from the bottom.ctx.cgContext.scaleBy(x:1.0, y: -1.0)//垂直翻转上下文因为核心图形坐标系从底部开始//旋转 正值逆时针旋转负值顺时针旋转ctx.cgContext.rotate(by: rotationAngle.degreesToRadians)ctx.cgContext.scaleBy(x: scale_W, y: scale_H)//缩放// Draw the PDF page.// 此处仍然是正常的绘制pdf因为前面设置了context的fillSize因此pdf绘制的时候只在前面指定的rect才会生效。ctx.cgContext.drawPDFPage(page)for annotation in ori_page.annotations {let origin annotation.bounds.origindic[annotation] annotation.boundslet annotation_fill_bounds CGRect(x: origin.x originalPageRect.origin.x, y: origin.y originalPageRect.origin.y, width: annotation.bounds.size.width, height: annotation.bounds.size.height)annotation.bounds annotation_fill_boundsannotation.draw(with: .cropBox, in: ctx.cgContext)}}if rotation%360 ! 0 {let scale:Float Float(rotation) / Float(180)tmpImg tmpImg?.rotate(radians: Float.pi * scale) ?? UIImage.init()}img tmpImgtmpImg nil}//将对pdfpage的修改进行还原ori_page.rotation rotationfor (annotation,bounds) in dic {annotation.bounds bounds}return img ?? UIImage()}extension PDFPage {var originalPageRect: CGRect {switch rotation {case 90, 270:let originalRect bounds(for: PDFDisplayBox.cropBox)let rotatedSize CGSize(width: originalRect.height, height: originalRect.width)return CGRect(origin: originalRect.origin, size: rotatedSize)default:return bounds(for: PDFDisplayBox.cropBox)}}
}extension UIImage {func rotate(radians: Float) - UIImage? {var newSize CGRect(origin: CGPoint.zero, size: self.size).applying(CGAffineTransform(rotationAngle: CGFloat(radians))).size// Trim off the extremely small float value to prevent core graphics from rounding it upnewSize.width floor(newSize.width)newSize.height floor(newSize.height)UIGraphicsBeginImageContextWithOptions(newSize, false, self.scale)guard let context UIGraphicsGetCurrentContext() else {return nil}// Move origin to middlecontext.translateBy(x: newSize.width/2, y: newSize.height/2)// Rotate around middlecontext.rotate(by: CGFloat(radians))// Draw the image at its centerself.draw(in: CGRect(x: -self.size.width/2, y: -self.size.height/2, width: self.size.width, height: self.size.height))let newImage UIGraphicsGetImageFromCurrentImageContext()UIGraphicsEndImageContext()return newImage}
}extension FloatingPoint {var degreesToRadians: Self { return self * .pi / 180 }var radiansToDegrees: Self { return self * 180 / .pi }
}备注这段代码结合了自己的项目实际业务大家作为参考。多看下核心代码和注释