Post

Replies

Boosts

Views

Activity

Reply to PDF Widget Annotations appear Pixelated/Rasterized
We hit the same regression and traced it. Filed as FB24882188, with a small repro project. What is happening: on iOS/iPadOS/macOS 27, PDFKit draws annotations into a private layer, PDFPageLayerAnnotationEffect, and configures it with contentsScale 1.0 and magnificationFilter "nearest". The PDFPageLayerTile layers that draw the page right beside it get the real on-screen scale (3.86 in our repro) and "linear". So annotations are rasterized at 1 pixel per point and then stretched with nearest-neighbour sampling, which is the pixelation. On iOS 26.5 the same layer gets the tile scale and "linear", which is why the same build is crisp there. It is not caused by custom draw(with:in:) code: standard ink and free-text annotations show it too, and widgets as well (the OP's FB24843022, same defect). Setting those two values on the live layer fixes it immediately, and PDFKit's next draw then uses the new scale. PDFKit resets the layer on every redraw, though, so the correction has to run right before each one. We do that by replacing -display on that one class (never on CALayer itself): import UIKit // iOS/iPadOS/macOS 27 workaround for pixelated PDFKit annotations (FB24882188, FB24843022). // Call once at launch, before any PDFView draws. No-op if the private class is absent. func installAnnotationLayerFix() { guard #available(iOS 27.0, *), let cls = NSClassFromString("PDFPageLayerAnnotationEffect"), let method = class_getInstanceMethod(cls, #selector(CALayer.display)) else { return } typealias Display = @convention(c) (CALayer, Selector) -> Void let original = unsafeBitCast(method_getImplementation(method), to: Display.self) let block: @convention(block) (CALayer) -> Void = { layer in if Thread.isMainThread { MainActor.assumeIsolated { correctScale(of: layer) } } original(layer, #selector(CALayer.display)) } // Adds an override on the subclass only; CALayer itself is untouched. class_replaceMethod(cls, #selector(CALayer.display), imp_implementationWithBlock(block), method_getTypeEncoding(method)) } /// Gives the layer its real on-screen density (screen scale x its magnification in the window) /// and linear filtering, which is what PDFKit gives the page tiles beside it. @MainActor private func correctScale(of layer: CALayer) { guard let window = hostView(of: layer)?.window else { return } let bounds = layer.bounds guard bounds.width > 0, bounds.height > 0 else { return } let inWindow = layer.convert(bounds, to: window.layer) let magnification = sqrt((inWindow.width * inWindow.height) / (bounds.width * bounds.height)) let scale = magnification * window.traitCollection.displayScale guard scale.isFinite, scale > 0 else { return } layer.contentsScale = scale layer.magnificationFilter = .linear } @MainActor private func hostView(of layer: CALayer) -> UIView? { var current = layer.superlayer while let l = current { if let view = l.delegate as? UIView { return view } current = l.superlayer } return nil } It depends on a private class name, so treat it as a stopgap until Apple fixes the regression; if the class is renamed or removed, it silently does nothing. In our app it fixed everything on iPadOS 27 and Mac Catalyst (macOS 27): new annotations, annotations loaded from saved files, zooming, page changes, rotation. It compiles under both Swift 5 and Swift 6 language modes. If you're affected, please file your own report and mention FB24882188 and FB24843022 in it, so they get linked on Apple's side.
Topic: App & System Services SubTopic: General Tags:
2d
Reply to PDFAnnotation not rendered properly on iOS27
We hit the same regression and traced it. Filed as FB24882188, with a small repro project. What is happening: on iOS/iPadOS/macOS 27, PDFKit draws annotations into a private layer, PDFPageLayerAnnotationEffect, and configures it with contentsScale 1.0 and magnificationFilter "nearest". The PDFPageLayerTile layers that draw the page right beside it get the real on-screen scale (3.86 in our repro) and "linear". So annotations are rasterized at 1 pixel per point and then stretched with nearest-neighbour sampling, which is the pixelation. On iOS 26.5 the same layer gets the tile scale and "linear", which is why the same build is crisp there. It is not caused by custom draw(with:in:) code: standard ink and free-text annotations show it too, and widgets as well (FB24843022, same defect). Setting those two values on the live layer fixes it immediately, and PDFKit's next draw then uses the new scale. PDFKit resets the layer on every redraw, though, so the correction has to run right before each one. We do that by replacing -display on that one class (never on CALayer itself): import UIKit // iOS/iPadOS/macOS 27 workaround for pixelated PDFKit annotations (FB24882188, FB24843022). // Call once at launch, before any PDFView draws. No-op if the private class is absent. func installAnnotationLayerFix() { guard #available(iOS 27.0, *), let cls = NSClassFromString("PDFPageLayerAnnotationEffect"), let method = class_getInstanceMethod(cls, #selector(CALayer.display)) else { return } typealias Display = @convention(c) (CALayer, Selector) -> Void let original = unsafeBitCast(method_getImplementation(method), to: Display.self) let block: @convention(block) (CALayer) -> Void = { layer in if Thread.isMainThread { MainActor.assumeIsolated { correctScale(of: layer) } } original(layer, #selector(CALayer.display)) } // Adds an override on the subclass only; CALayer itself is untouched. class_replaceMethod(cls, #selector(CALayer.display), imp_implementationWithBlock(block), method_getTypeEncoding(method)) } /// Gives the layer its real on-screen density (screen scale x its magnification in the window) /// and linear filtering, which is what PDFKit gives the page tiles beside it. @MainActor private func correctScale(of layer: CALayer) { guard let window = hostView(of: layer)?.window else { return } let bounds = layer.bounds guard bounds.width > 0, bounds.height > 0 else { return } let inWindow = layer.convert(bounds, to: window.layer) let magnification = sqrt((inWindow.width * inWindow.height) / (bounds.width * bounds.height)) let scale = magnification * window.traitCollection.displayScale guard scale.isFinite, scale > 0 else { return } layer.contentsScale = scale layer.magnificationFilter = .linear } @MainActor private func hostView(of layer: CALayer) -> UIView? { var current = layer.superlayer while let l = current { if let view = l.delegate as? UIView { return view } current = l.superlayer } return nil } It depends on a private class name, so treat it as a stopgap until Apple fixes the regression; if the class is renamed or removed, it silently does nothing. In our app it fixed everything on iPadOS 27 and Mac Catalyst (macOS 27): new annotations, annotations loaded from saved files, zooming, page changes, rotation. It compiles under both Swift 5 and Swift 6 language modes. If you're affected, please file your own report and mention FB24882188 and FB24843022 in it, so they get linked on Apple's side.
Topic: App & System Services SubTopic: General Tags:
2d
Reply to Crash in PDFView / PDFPageAnalyzerV2
We have been chasing the same class from a different angle – not a crash inside it, but an unbounded leak. On iPadOS 26.6, every PDFDocument whose pages get rendered starts a VNRecognizeDocumentsRequest pipeline that is never released: roughly 2.7 OS threads and 20 MB per document, permanently. Our process reached 153 threads and 1.5 GB in under seven minutes of repeated document loads. It is not released by replacing PDFView.document, by deallocating the PDFView, or by time – with the app fully idle the thread count keeps rising. One thing that may save you time: usePageViewController(true, withViewOptions: nil) does not help with this. It reduces visiblePagesChanged: frequency, and in our measurements page changes on a stable document leak nothing at all – around 1000 of them left the footprint declining. The variable is newly rendered documents, not new pages. PDFView does carry -setDocumentAnalysisEnabled: / -isDocumentAnalysisEnabled, none of it public. With analysis off, our leak goes to exactly zero over 28 document loads. If you are facing the same issue, it would help if you also file feedback and suggest that these properties are made public. An analysis that never starts cannot crash – and in many cases the analysis is not relevant to the app.
Topic: UI Frameworks SubTopic: General Tags:
Aug ’26
Reply to PDF Widget Annotations appear Pixelated/Rasterized
We hit the same regression and traced it. Filed as FB24882188, with a small repro project. What is happening: on iOS/iPadOS/macOS 27, PDFKit draws annotations into a private layer, PDFPageLayerAnnotationEffect, and configures it with contentsScale 1.0 and magnificationFilter "nearest". The PDFPageLayerTile layers that draw the page right beside it get the real on-screen scale (3.86 in our repro) and "linear". So annotations are rasterized at 1 pixel per point and then stretched with nearest-neighbour sampling, which is the pixelation. On iOS 26.5 the same layer gets the tile scale and "linear", which is why the same build is crisp there. It is not caused by custom draw(with:in:) code: standard ink and free-text annotations show it too, and widgets as well (the OP's FB24843022, same defect). Setting those two values on the live layer fixes it immediately, and PDFKit's next draw then uses the new scale. PDFKit resets the layer on every redraw, though, so the correction has to run right before each one. We do that by replacing -display on that one class (never on CALayer itself): import UIKit // iOS/iPadOS/macOS 27 workaround for pixelated PDFKit annotations (FB24882188, FB24843022). // Call once at launch, before any PDFView draws. No-op if the private class is absent. func installAnnotationLayerFix() { guard #available(iOS 27.0, *), let cls = NSClassFromString("PDFPageLayerAnnotationEffect"), let method = class_getInstanceMethod(cls, #selector(CALayer.display)) else { return } typealias Display = @convention(c) (CALayer, Selector) -> Void let original = unsafeBitCast(method_getImplementation(method), to: Display.self) let block: @convention(block) (CALayer) -> Void = { layer in if Thread.isMainThread { MainActor.assumeIsolated { correctScale(of: layer) } } original(layer, #selector(CALayer.display)) } // Adds an override on the subclass only; CALayer itself is untouched. class_replaceMethod(cls, #selector(CALayer.display), imp_implementationWithBlock(block), method_getTypeEncoding(method)) } /// Gives the layer its real on-screen density (screen scale x its magnification in the window) /// and linear filtering, which is what PDFKit gives the page tiles beside it. @MainActor private func correctScale(of layer: CALayer) { guard let window = hostView(of: layer)?.window else { return } let bounds = layer.bounds guard bounds.width > 0, bounds.height > 0 else { return } let inWindow = layer.convert(bounds, to: window.layer) let magnification = sqrt((inWindow.width * inWindow.height) / (bounds.width * bounds.height)) let scale = magnification * window.traitCollection.displayScale guard scale.isFinite, scale > 0 else { return } layer.contentsScale = scale layer.magnificationFilter = .linear } @MainActor private func hostView(of layer: CALayer) -> UIView? { var current = layer.superlayer while let l = current { if let view = l.delegate as? UIView { return view } current = l.superlayer } return nil } It depends on a private class name, so treat it as a stopgap until Apple fixes the regression; if the class is renamed or removed, it silently does nothing. In our app it fixed everything on iPadOS 27 and Mac Catalyst (macOS 27): new annotations, annotations loaded from saved files, zooming, page changes, rotation. It compiles under both Swift 5 and Swift 6 language modes. If you're affected, please file your own report and mention FB24882188 and FB24843022 in it, so they get linked on Apple's side.
Topic: App & System Services SubTopic: General Tags:
Replies
Boosts
Views
Activity
2d
Reply to PDFAnnotation not rendered properly on iOS27
We hit the same regression and traced it. Filed as FB24882188, with a small repro project. What is happening: on iOS/iPadOS/macOS 27, PDFKit draws annotations into a private layer, PDFPageLayerAnnotationEffect, and configures it with contentsScale 1.0 and magnificationFilter "nearest". The PDFPageLayerTile layers that draw the page right beside it get the real on-screen scale (3.86 in our repro) and "linear". So annotations are rasterized at 1 pixel per point and then stretched with nearest-neighbour sampling, which is the pixelation. On iOS 26.5 the same layer gets the tile scale and "linear", which is why the same build is crisp there. It is not caused by custom draw(with:in:) code: standard ink and free-text annotations show it too, and widgets as well (FB24843022, same defect). Setting those two values on the live layer fixes it immediately, and PDFKit's next draw then uses the new scale. PDFKit resets the layer on every redraw, though, so the correction has to run right before each one. We do that by replacing -display on that one class (never on CALayer itself): import UIKit // iOS/iPadOS/macOS 27 workaround for pixelated PDFKit annotations (FB24882188, FB24843022). // Call once at launch, before any PDFView draws. No-op if the private class is absent. func installAnnotationLayerFix() { guard #available(iOS 27.0, *), let cls = NSClassFromString("PDFPageLayerAnnotationEffect"), let method = class_getInstanceMethod(cls, #selector(CALayer.display)) else { return } typealias Display = @convention(c) (CALayer, Selector) -> Void let original = unsafeBitCast(method_getImplementation(method), to: Display.self) let block: @convention(block) (CALayer) -> Void = { layer in if Thread.isMainThread { MainActor.assumeIsolated { correctScale(of: layer) } } original(layer, #selector(CALayer.display)) } // Adds an override on the subclass only; CALayer itself is untouched. class_replaceMethod(cls, #selector(CALayer.display), imp_implementationWithBlock(block), method_getTypeEncoding(method)) } /// Gives the layer its real on-screen density (screen scale x its magnification in the window) /// and linear filtering, which is what PDFKit gives the page tiles beside it. @MainActor private func correctScale(of layer: CALayer) { guard let window = hostView(of: layer)?.window else { return } let bounds = layer.bounds guard bounds.width > 0, bounds.height > 0 else { return } let inWindow = layer.convert(bounds, to: window.layer) let magnification = sqrt((inWindow.width * inWindow.height) / (bounds.width * bounds.height)) let scale = magnification * window.traitCollection.displayScale guard scale.isFinite, scale > 0 else { return } layer.contentsScale = scale layer.magnificationFilter = .linear } @MainActor private func hostView(of layer: CALayer) -> UIView? { var current = layer.superlayer while let l = current { if let view = l.delegate as? UIView { return view } current = l.superlayer } return nil } It depends on a private class name, so treat it as a stopgap until Apple fixes the regression; if the class is renamed or removed, it silently does nothing. In our app it fixed everything on iPadOS 27 and Mac Catalyst (macOS 27): new annotations, annotations loaded from saved files, zooming, page changes, rotation. It compiles under both Swift 5 and Swift 6 language modes. If you're affected, please file your own report and mention FB24882188 and FB24843022 in it, so they get linked on Apple's side.
Topic: App & System Services SubTopic: General Tags:
Replies
Boosts
Views
Activity
2d
Reply to Crash in PDFView / PDFPageAnalyzerV2
We have been chasing the same class from a different angle – not a crash inside it, but an unbounded leak. On iPadOS 26.6, every PDFDocument whose pages get rendered starts a VNRecognizeDocumentsRequest pipeline that is never released: roughly 2.7 OS threads and 20 MB per document, permanently. Our process reached 153 threads and 1.5 GB in under seven minutes of repeated document loads. It is not released by replacing PDFView.document, by deallocating the PDFView, or by time – with the app fully idle the thread count keeps rising. One thing that may save you time: usePageViewController(true, withViewOptions: nil) does not help with this. It reduces visiblePagesChanged: frequency, and in our measurements page changes on a stable document leak nothing at all – around 1000 of them left the footprint declining. The variable is newly rendered documents, not new pages. PDFView does carry -setDocumentAnalysisEnabled: / -isDocumentAnalysisEnabled, none of it public. With analysis off, our leak goes to exactly zero over 28 document loads. If you are facing the same issue, it would help if you also file feedback and suggest that these properties are made public. An analysis that never starts cannot crash – and in many cases the analysis is not relevant to the app.
Topic: UI Frameworks SubTopic: General Tags:
Replies
Boosts
Views
Activity
Aug ’26