Core Graphics

RSS for tag

Harness the power of Quartz technology to perform lightweight 2D rendering with high-fidelity output using Core Graphics.

Posts under Core Graphics tag

51 Posts

Post

Replies

Boosts

Views

Activity

iOS version 26.0, get pixel alpha value invalid if subviews contains WKWebView
using renderInContext fetch pixel faild if subviews contains WKWebView, the code is as follows: self.contentView = [SimpleClearContentView alloc] initWithFrame:CGRectMake(0, 100, 100, 100)]; contentView.backgroundColor = [UIColor clearColor]; self.contentView.webView = [[WKWebView alloc] init]; self.contentView.webView.frame = CGRectMake(0, 0, 50, 100); // make web view clear bg color self.contentView.webView.backgroundColor = [UIColor clearColor]; self.contentView.webView.scrollView.backgroundColor = [UIColor clearColor]; // webView load clear background webpage [self.contentView.webView loadRequest:***]; [self.view addSubView:contentView]; // this method still return 0.0f anywhere -(CGFloat)getPixelAlphaAtPoint:(CGPoint)point { unsigned char pixel[4] = {0}; CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); CGContextRef context = CGBitmapContextCreate(pixel, 1, 1, 8, 4, colorSpace, kCGBitmapAlphaInfoMask & kCGImageAlphaPremultipliedLast); CGContextTranslateCTM(context, -point.x, -point.y); WKWebView *webView = self.contentView.webView; [webView.layer renderInContext:context]; CGContextRelease(context); CGColorSpaceRelease(colorSpace); CGFloat alpha = pixel[3]/255.0; return alpha; }
1
0
24
5d
WindowServer crash when moving window near left edge of external display
Steps to Reproduce: Connect a MacBook Pro (lid closed) to a large external monitor. Run the SDL3 testwm test application. git clone https://github.com/libsdl-org/SDL.git cmake -S . -B build -DBUILD_SHARED_LIBS=OFF -DSDL_TESTS=ON cmake --build build The testwm binary will be located in the build/test directory. Move the application window around the left edge of the external display. Observed Result: WindowServer crashes. System Configuration: MacBook Pro M3 Max, macOS Sequoia 15.6.1 LG GX9, 5120x2160 resolution, running at 165 Hz refresh rate Lid closed, single external display Panic Log: panic(cpu 7 caller 0xfffffe0027f61d5c): "mismatched swapID's 6386399 vs 6386400\n" @UnifiedPipeline.cpp:14570 Debugger message: panic Memory ID: 0xff OS release type: User OS version: 24G90 Kernel version: Darwin Kernel Version 24.6.0: Mon Jul 14 11:30:55 PDT 2025; root:xnu-11417.140.69~1/RELEASE_ARM64_T6031 Fileset Kernelcache UUID: 8AA69CD2038CD2BAE2ED364428F4DBEA Kernel UUID: 75A21406-D046-3232-AA3F-085335D5C848 Boot session UUID: B949E839-683B-4DAF-BE42-4562758F976E iBoot version: iBoot-11881.140.96 iBoot Stage 2 version: iBoot-11881.140.96 secure boot?: YES roots installed: 0 Paniclog version: 14 KernelCache slide: 0x000000001e0ec000 KernelCache base: 0xfffffe00250f0000 Kernel slide: 0x000000001e0f4000 Kernel text base: 0xfffffe00250f8000 Kernel text exec slide: 0x000000001f870000 Kernel text exec base: 0xfffffe0026874000 mach_absolute_time: 0x64e7db3e6a9 Epoch Time: sec usec Boot : 0x68b207f0 0x00082ee7 Sleep : 0x68c1a51c 0x00048c6c Wake : 0x68c1a760 0x00039aa4 Calendar: 0x68c1b78d 0x0001776a Zone info: Zone map: 0xfffffe1018000000 - 0xfffffe3618000000 . VM : 0xfffffe1018000000 - 0xfffffe15e4000000 . RO : 0xfffffe15e4000000 - 0xfffffe187e000000 . GEN0 : 0xfffffe187e000000 - 0xfffffe1e4a000000 . GEN1 : 0xfffffe1e4a000000 - 0xfffffe2416000000 . GEN2 : 0xfffffe2416000000 - 0xfffffe29e2000000 . GEN3 : 0xfffffe29e2000000 - 0xfffffe2fae000000 . DATA : 0xfffffe2fae000000 - 0xfffffe3618000000 Metadata: 0xfffffe393c010000 - 0xfffffe3945810000 Bitmaps : 0xfffffe3945810000 - 0xfffffe394c104000 Extra : 0 - 0 CORE 0 recently retired instr at 0xfffffe0026a407a0 CORE 1 recently retired instr at 0xfffffe0026a40798 CORE 2 recently retired instr at 0xfffffe0026a407a0 CORE 3 recently retired instr at 0xfffffe0026a407a0 CORE 4 recently retired instr at 0xfffffe0026a407a0 CORE 5 recently retired instr at 0xfffffe0026a407a0 CORE 6 recently retired instr at 0xfffffe0026a407a0 CORE 7 recently retired instr at 0xfffffe0026a3eefc CORE 8 recently retired instr at 0xfffffe0026a407a0 CORE 9 recently retired instr at 0xfffffe0026a407a0 CORE 10 recently retired instr at 0xfffffe0026a407a0 CORE 11 recently retired instr at 0xfffffe0026a407a0 CORE 12 recently retired instr at 0xfffffe0026a407a0 CORE 13 recently retired instr at 0xfffffe0026a407a0 TPIDRx_ELy = {1: 0xfffffe29e4ef5ee0 0: 0x0000000000001007 0ro: 0x000000016c59b0e0 } CORE 0 PVH locks held: None CORE 1 PVH locks held: None CORE 2 PVH locks held: None CORE 3 PVH locks held: None CORE 4 PVH locks held: None CORE 5 PVH locks held: None CORE 6 PVH locks held: None CORE 7 PVH locks held: None CORE 8 PVH locks held: None CORE 9 PVH locks held: None CORE 10 PVH locks held: None CORE 11 PVH locks held: None CORE 12 PVH locks held: None CORE 13 PVH locks held: None CORE 0: PC=0xfffffe0026abfa40, LR=0xfffffe0026ae4fc8, FP=0xfffffe65b8703980 CORE 1: PC=0x0000000193ae2730, LR=0x000000019389d108, FP=0x000000016f43e590 CORE 2: PC=0xfffffe0026911e84, LR=0xfffffe0026911e84, FP=0xfffffe65b850bed0 CORE 3: PC=0xfffffe0026911e84, LR=0xfffffe0026911e84, FP=0xfffffe65b8ee7ed0 CORE 4: PC=0xfffffe0026911e84, LR=0xfffffe0026911e84, FP=0xfffffe65b7eebed0 CORE 5: PC=0xfffffe0026a3ac1c, LR=0xfffffe0026a3ac18, FP=0xfffffe65b8c63e40 CORE 6: PC=0xfffffe0026911e84, LR=0xfffffe0026911e84, FP=0xfffffe65b7033ed0 CORE 7 is the one that panicked. Check the full backtrace for details. CORE 8: PC=0xfffffe0026a3ac1c, LR=0xfffffe0026a3ac18, FP=0xfffffe65b737be40 CORE 9: PC=0xfffffe0026911e84, LR=0xfffffe0026911e84, FP=0xfffffe65b8f1fed0 CORE 10: PC=0xfffffe0026911e84, LR=0xfffffe0026911e84, FP=0xfffffe65b7fe7ed0 CORE 11: PC=0xfffffe0026a3ac1c, LR=0xfffffe0026a3ac18, FP=0xfffffe65b870fe40 CORE 12: PC=0xfffffe0026911e84, LR=0xfffffe0026911e84, FP=0xfffffe65b80a7ed0 CORE 13: PC=0xfffffe0026a3ac1c, LR=0xfffffe0026a3ac18, FP=0xfffffe65b685fe40 Compressor Info: 6% of compressed pages limit (OK) and 16% of segments limit (OK) with 0 swapfiles and OK swap space Panicked task 0xfffffe23153cb940: 10375 pages, 28 threads: pid 406: WindowServer Panicked thread: 0xfffffe29e4ef5ee0, backtrace: 0xfffffe65b6f07210, tid: 5146 lr: 0xfffffe00268d53d4 fp: 0xfffffe65b6f072a0 lr: 0xfffffe0026a36da0 fp: 0xfffffe65b6f07310 lr: 0xfffffe0026a35114 fp: 0xfffffe65b6f073d0 lr: 0xfffffe002687f8b0 fp: 0xfffffe65b6f073e0 lr: 0xfffffe00268d5710 fp: 0xfffffe65b6f077b0 lr: 0xfffffe0027169290 fp: 0xfffffe65b6f077d0 lr: 0xfffffe0027f61d5c fp: 0xfffffe65b6f07850 lr: 0xfffffe0029186878 fp: 0xfffffe65b6f07880 lr: 0xfffffe00270bd2a0 fp: 0xfffffe65b6f078b0 lr: 0xfffffe00270bd5b0 fp: 0xfffffe65b6f07a40 lr: 0xfffffe0026a00194 fp: 0xfffffe65b6f07b60 lr: 0xfffffe00268dcd48 fp: 0xfffffe65b6f07c00 lr: 0xfffffe00268b2ed4 fp: 0xfffffe65b6f07c60 lr: 0xfffffe00268c6868 fp: 0xfffffe65b6f07cb0 lr: 0xfffffe00268c6c80 fp: 0xfffffe65b6f07da0 lr: 0xfffffe0026a29bbc fp: 0xfffffe65b6f07e50 lr: 0xfffffe0026a355a4 fp: 0xfffffe65b6f07f10 lr: 0xfffffe002687f8b0 fp: 0xfffffe65b6f07f20 lr: 0x000000018dc89c34 fp: 0x0000000000000000 Kernel Extensions in backtrace: com.apple.iokit.IOMobileGraphicsFamily(343.0)[6C8CFA29-99CD-39D4-81BC-2B0F147BE64F]@0xfffffe002917d860->0xfffffe00291a024f
1
0
61
1w
perspectiveTransform causing large memory spike / app being killed
I have a PDF which contains geocoordinates. I'm extracting out that image with the following code (this is for an iOS application): guard let cgDocument = CGPDFDocument(overlay.pdfUrl as CFURL) else { return } guard let cgPage = cgDocument.page(at: 1) else { return } var boundingRect = self.rect(for: overlay.boundingMapRect) let pdfPageRect = cgPage.getBoxRect(.mediaBox) let renderer = UIGraphicsImageRenderer(size: pdfPageRect.size) var img = renderer.image { ctx in UIColor.white.set() ctx.fill(pdfPageRect) ctx.cgContext.translateBy(x: 0.0, y: pdfPageRect.size.height) ctx.cgContext.scaleBy(x: 1.0, y: -1.0) ctx.cgContext.drawPDFPage(cgPage) } Once I have that image, I then need to adjust it to fit the specific coordinate corners. For that, I'm doing the following using a perspectiveTransform: let ciImg = CIImage(image: img)! let perspectiveTransformFilter = CIFilter.perspectiveTransform() perspectiveTransformFilter.inputImage = ciImg perspectiveTransformFilter.topRight = cartesianForPoint(point: ur, extent: boundingRect) perspectiveTransformFilter.topLeft = cartesianForPoint(point: ul, extent: boundingRect) perspectiveTransformFilter.bottomRight = cartesianForPoint(point: lr, extent: boundingRect) perspectiveTransformFilter.bottomLeft = cartesianForPoint(point: ll, extent: boundingRect) let txImg = perspectiveTransformFilter.outputImage! img = UIImage(ciImage: txImg) The original image is 792 x 612 (a landscape PDF) but the boundingRect covering the coordinates is 25625 x 20030. Obviously when I try to draw the image into that bounding box the app runs out of memory (25625 x 20030 x 4 is around 2GB of memory). What I'm struggling with is - how do I correctly scale this image to fit into the bounding box even though the bounding box is, oh, 10x the resolution of the actual device? There's some key CoreGraphics thing I'm sure I'm missing here.
6
0
151
2w
Where's the replacement for Quartz Debug?
Hi, This can't be right. Is there really no replacement for Quartz Debug?!? As the sole developer on a project who has an Intel Mac and Quartz Debug, I am basically a god now. Everyone else has Apple Silicon and... I think they're randomly guessing at this point. Because I have entire teams sending me Intel Mac builds of stuff just so I can test it in QD. This is THE TOOL we used at NewTek to find performance issues, and THE TOOL I used for a dozen companies after that, to help them with similar issues. If there's no replacement, is there a reason there's no replacement? This feels like a massive step backwards, having to guess at problems like this. -Chilton
1
0
110
Aug ’25
Images with unusual color spaces not correctly loaded by Core Image
Some users reported that their images are not loading correctly in our app. After a lot of debugging we identified the following: This only happens when the app is build for Mac Catalyst. Not on iOS, iPadOS, or “real” macOS (AppKit). The images in question have unusual color spaces. We observed the issue for uRGB and eciRGB v2. Those images are rendered correctly in Photos and Preview on all platforms. When displaying the image inside of a UIImageView or in a SwiftUI Image, they render correctly. The issue only occurs when loading the image via Core Image. When comparing the different Core Image render graphs between AppKit (working) and Catalyst (faulty) builds, they look identical—except for the result. Mac (AppKit): Catalyst: Something seems to be off when Core Image tries to load an image with foreign color space in Catalyst. We identified a workaround: By using a CGImageDestination to transcode the image using the kCGImageDestinationOptimizeColorForSharing option, Image I/O will convert the image to sRGB (or similar) and Core Image is able to load the image correctly. However, one potentially loses fidelity this way. Or might there be a better workaround?
2
3
85
Aug ’25
vImageConverter_CreateWithCGImageFormat Fails with kvImageInvalidImageFormat When Trying to Convert CMYK to RGB
So I get JPEG data in my app. Previously I was using the higher level NSBitmapImageRep API and just feeding the JPEG data to it. But now I've noticed on Sonoma If I get a JPEG in the CMYK color space the NSBitmapImageRep renders mostly black and is corrupted. So I'm trying to drop down to the lower level APIs. Specifically I grab a CGImageRef and and trying to use the Accelerate API to convert it to another format (to hopefully workaround the issue... CGImageRef sourceCGImage = `CGImageCreateWithJPEGDataProvider(jpegDataProvider,` NULL, shouldInterpolate, kCGRenderingIntentDefault); Now I use vImageConverter_CreateWithCGImageFormat... with the following values for source and destination formats: Source format: (derived from sourceCGImage) bitsPerComponent = 8 bitsPerPixel = 32 colorSpace = (kCGColorSpaceICCBased; kCGColorSpaceModelCMYK; Generic CMYK Profile) bitmapInfo = kCGBitmapByteOrderDefault version = 0 decode = 0x000060000147f780 renderingIntent = kCGRenderingIntentDefault Destination format: bitsPerComponent = 8 bitsPerPixel = 24 colorSpace = (DeviceRBG) bitmapInfo = 8197 version = 0 decode = 0x0000000000000000 renderingIntent = kCGRenderingIntentDefault But vImageConverter_CreateWithCGImageFormat fails with kvImageInvalidImageFormat. Now if I change the destination format to use 32 bitsPerpixel and use alpha in the bitmap info the vImageConverter_CreateWithCGImageFormat does not return an error but I get a black image just like NSBitmapImageRep
14
0
1.3k
Aug ’25
CGSetDisplayTransferByTable no longer working on macOS Tahoe
For an app of mine I use CGSetDisplayTransferByTable to adjust the gamma table of the device. Since macOS Tahoe, these modifications are silently ignored. The display's actual gamma curve remains unchanged despite the API reporting successful completion. I've filed a FB for it a few weeks ago, and would love to figure out what could be causing this. FB18559786
3
1
264
Aug ’25
CoreGraphics reports two displays connections during system wakeup
Hello, The application I'm working on must report new hardware connections. To retrieve connected displays information and monitor new connections, I'm using the "Core Graphics" framework (see recommendation https://developer.apple.com/forums/thread/779945). The monitoring logic relies on a callback function which invokes when the local display configuration changes(kCGDisplayAddFlag/kCGDisplayRemoveFlag). #import <Cocoa/Cocoa.h> static void displayChanged(CGDirectDisplayID displayID, CGDisplayChangeSummaryFlags flags, void *userInfo) { uint32_t vendor = CGDisplayVendorNumber(displayID); if (flags & kCGDisplayAddFlag) { if (vendor == kDisplayVendorIDUnknown) { NSLog(@"I/O Kit cannot identify the monitor. kDisplayVendorIDUnknown. displayId = %u", displayID); return; } NSLog(@"%u connected. vendor(%u)", displayID, vendor); } if (flags & kCGDisplayRemoveFlag) { NSLog(@"%u disconnected", displayID); } } int main(int argc, const char * argv[]) { @autoreleasepool { CGDisplayRegisterReconfigurationCallback(displayChanged, NULL); NSApplicationLoad(); CFRunLoopRun(); } return 0; } The test environment is a Mac mini with an external display connected via HDMI. Everything works correctly until the system enters sleep mode. Upon wakeup, the app reports two displays: the first with vendor ID kDisplayVendorIDUnknown and the second with the expected vendor ID. Why does Core Graphics report two connections during wakeup? Is there any way to avoid this? Thank you in advance.
2
0
95
Jul ’25
Fullscreen Detection
Hi, I want to detect if there is a fullscreen window on each screen. _AXUIElementGetWindow and kAXFullscreenAttribute methods work, but I have to be in a non-sandbox environment to use them. Is there any other way that also works? I don't think it's enough to judge if it's fullscreen by comparing the window size to the screen size, since it doesn't work on MacBook with notch, or the menu bar is set to 'auto-hide'. Thanks.
14
1
1.5k
Jul ’25
Programmatic motion on the mouse cursor triggers "shake to locate"
I use the following code to keep the mouse cursor within the bounds of my application window. This causes the mouse cursor to become magnified while hugging the window's edges. Is there a way to prevent this? My clients are building a game, board style with a large map viewed from a top camera. They want the map to pan automatically when the mouse reaches the edge of the window. And they want the mouse cursor to stay confined to the game window. Thank you. CGDisplayMoveCursorToPoint(CGMainDisplayID(), location); // Removes a delay introduced by CGWarpMouseCursorPosition to keep mouse cursor motion fluid while hugging the screen edges CGEventSourceRef eventSourceRef = CGEventSourceCreate(kCGEventSourceStateCombinedSessionState); CGEventSourceSetLocalEventsSuppressionInterval(eventSourceRef, 0);
0
0
46
Jul ’25
WWDC25 combining metal and ML
WWDC25: Combine Metal 4 machine learning and graphics Demonstrated a way to combine neural network in the graphics pipeline directly through the shaders, using an example of Texture Compression. However there is no mention of using which ML technique texture is compressed. Can anyone point me to some well known model/s for this particular use case shown in WWDC25.
2
0
338
Jul ’25
EXC_BREAKPOINT, QuartzCore , Crash CA::Render::Image::new_image
We are seeing crashes in Xcode organizer. So far we are not able to reproduce them locally. They affect multiple app releases (some older, built with Xcode 15.x and newer built with Xcode 16.0). They only affect iOS 18.5. Is there anything that changed in latest iOS? It's hard to tell what exactly is causing this crash because setting symbolic breakpoint on CA::Render::Image::new_image(unsigned int, unsigned int, unsigned int, unsigned int, CGColorSpace*, void const*, unsigned long const*, void (*)(void const*, void*), void*) triggers this breakpoint all the time, but not necessarily with exactly the previous stack frames matching the crash report. Is it a known issue? crash.crash Thank you.
0
5
239
Jul ’25
`UIGraphicsImageRenderer` + `drawHierarchy` gives very flat colors
My setup: a UILabel with text in it and then let aBugRenderer = UIGraphicsImageRenderer(size: aBugLabel.bounds.size) let aBugImage = aBugRenderer.image { context in aBugLabel.drawHierarchy(in: aBugLabel.bounds, afterScreenUpdates: true) } The layout and everything is correct, the image is correct, but I used my colors in the displayP3 color space to configure the source UILabel.textColor And unfortunately, the resulted image ends up being sRGB IEC61966-2.1 color space and the color appears way bleaker than when it's drawn natively. Question: how can I set up the renderer so that it draws the same color.
0
0
46
Jun ’25
` UIBezierPath(roundedRect:cornerRadius:)` renders Inconsistently at Specific Size-to-Radius Ratios
Hello everyone, I've encountered a fascinating and perplexing rendering anomaly when using UIBezierPath(roundedRect:cornerRadius:) to create a CGPath. Summary of the Issue: When the shortest side of the rectangle (min(width, height)) is just under a certain multiple of the cornerRadius (empirically, around 3x), the algorithm for generating the path seems to change entirely. This results in a path with visually different (and larger) corners than when the side is slightly longer, even with the same cornerRadius parameter. How to Reproduce: The issue is most clearly observed with a fixed cornerRadius while slightly adjusting the rectangle's height or width across a specific threshold. Create a UIView (contentView) and another UIView (shadowView) behind it. Set the shadowView.layer.shadowPath using UIBezierPath(roundedRect: contentView.bounds, cornerRadius: 16).cgPath. Adjust the height of the contentView. Observe the shadowPath at height 48 vs. height 49 Minimal Reproducible Example: Here is a simple UIViewController to demonstrate the issue. You can drop this into a project. Tapping the "Toggle Height" button will switch between the two states and print the resulting CGPath to the console. import UIKit class PathTestViewController: UIViewController { private let contentView = UIView() private let shadowView = UIView() private var heightConstraint: NSLayoutConstraint! private let cornerRadius: CGFloat = 16.0 private let normalHeight: CGFloat = 49 private let anomalyHeight: CGFloat = 48 override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .systemGray5 setupViews() setupButton() } override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() updateShadowPath() } private func updateShadowPath() { let newPath = UIBezierPath(roundedRect: contentView.bounds, cornerRadius: cornerRadius).cgPath shadowView.layer.shadowPath = newPath } private func setupViews() { // ContentView (the visible rect) contentView.backgroundColor = .systemBlue contentView.translatesAutoresizingMaskIntoConstraints = false contentView.isHidden = true // ShadowView (to render the path) shadowView.layer.shadowColor = UIColor.black.cgColor shadowView.layer.shadowOpacity = 1 shadowView.layer.shadowRadius = 2 shadowView.layer.shadowOffset = .zero shadowView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(shadowView) view.addSubview(contentView) heightConstraint = contentView.heightAnchor.constraint(equalToConstant: normalHeight) NSLayoutConstraint.activate([ contentView.centerXAnchor.constraint(equalTo: view.centerXAnchor), contentView.centerYAnchor.constraint(equalTo: view.centerYAnchor), contentView.widthAnchor.constraint(equalToConstant: 300), heightConstraint, shadowView.topAnchor.constraint(equalTo: contentView.topAnchor), shadowView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), shadowView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor), shadowView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor), ]) } private func setupButton() { let button = UIButton(type: .system, primaryAction: UIAction(title: "Toggle Height", handler: { [unowned self] _ in let newHeight = self.heightConstraint.constant == self.normalHeight ? self.anomalyHeight : self.normalHeight self.heightConstraint.constant = newHeight UIView.animate(withDuration: 0.3) { self.view.layoutIfNeeded() } })) button.translatesAutoresizingMaskIntoConstraints = false view.addSubview(button) NSLayoutConstraint.activate([ button.centerXAnchor.constraint(equalTo: view.centerXAnchor), button.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -20) ]) } } Evidence: CGPath Analysis Note: The CGPath data below is from my initial observation. At that time, height 48.7 produced a path with straight edges. Now, this "correct" path is only produced at height 49.0 or greater. The inconsistency now occurs at 48.7.* The key difference lies in the raw CGPath data. Path for Height = 48.7 (Expected Behavior) The path is constructed with lineto commands for the straight edges between the curved corners. // Path for Height 48.7 Path 0x60000300a0a0: moveto (24.4586, 0) lineto (24.5414, 0) // <-- Straight line on top edge curveto (31.5841, 0) (35.1055, 0) (38.8961, 1.19858) ... Path for Height = 48.6 (Anomalous Behavior) The lineto commands for the short edges disappear. The path is composed of continuous curveto commands, as if the two corners have merged into a single, larger curve. This creates the visual discrepancy. // Path for Height 48.6 Path 0x600003028630: moveto (24.1667, 0) lineto (24.1667, 0) // <-- Zero-length line curveto (24.1667, 0) (24.1667, 0) (24.1667, 0) lineto (25.375, 1.44329e-15) curveto (34.8362, -2.77556e-16) (43.2871, 5.9174) (46.523, 14.808) // <-- First curve curveto (48.3333, 20.5334) (48.3333, 25.8521) (48.3333, 36.4896) // <-- Second curve, no straight line in between ... min.length == 48 min.length == 49 My Questions: Is this change in the path-generation algorithm at this specific size/radius threshold an intended behavior, or is it a bug? Is this behavior documented anywhere? The threshold doesn't seem to be a clean side/radius == 2.0, so it's hard to predict. Is there a recommended workaround to ensure consistent corner rendering across these small size thresholds? Any insight would be greatly appreciated. Thank you! Environment: Xcode: 16.4 iOS: 16.5.1(iPad), 18.4(iphone simulator)
2
0
91
Jun ’25
CGContext PDF/A intents
let dic : [AnyHashable:Any] = [ kCGPDFXRegistryName: "http://www.color.org" as CFString, kCGPDFXOutputConditionIdentifier: "FOGRA43" as CFString, kCGPDFContextOutputIntent: "GTS_PDFX" as CFString, kCGPDFXOutputIntentSubtype: "GTS_PDFX" as CFString, kCGPDFContextCreateLinearizedPDF: "" as CFString, kCGPDFContextCreatePDFA: "" as CFString, kCGPDFContextAuthor: "Placeholder" as CFString, kCGPDFContextCreator: "Placeholder" as CFString ] Hello, Now I would like to export my PDF's as PDF/A. In my opinion, there is also the right option for this under Core Graphics. Unfortunately, the documentation does not show what is 'kCGPDFContextCreatePDFA' or 'kCGPDFContextLinearizedPDF' for a stringvalue is required. What I have already tried: GTS_PDFA1 , PDF/A-1, true as CFString. (Above my CFDictionary. ...Author e.g are working perfectly.) In the Finder you can see these two options, which I would also like to implement in my app. Thank you in advance!
1
0
114
Jun ’25
CATiledLayer flashes and re-draws entirely when re-drawing a single tile
I have filed a bug report for this (FB17734946), but I'm posting it here verbatim in case others have the same issue and in hopes of getting attention from an Apple engineer sooner. When calling setNeedsDisplayInRect on a CATiledLayer - or a UIView whose backing layer is CATiledLayer - one would expect to re-draw only a region identified by the rect passed to the method. This is even written in the documentation for the class: "Regions of the layer may be invalidated using the setNeedsDisplayInRect: method however the update will be asynchronous. While the next display update will most likely not contain the updated content, a future update will." However, upon calling this method, CATiledLayer redraws whole contents instead of just the tile at the specified rect, and it flashes when doing so. It behaves exactly the same as if one had called setNeedsDisplay without passing any rect; all contents are cleared and re-drawn again. I'm 100% sure I've passed in the correct rect of the exact tile that I need to redraw. I have even tried passing much smaller rects, but still the same. (And yes, the rect I've passed accounts for the current level of detail.) I have found this GitHub repo https://github.com/frankus/NetPhotoScroller, which based on discussion from here https://forums.macrumors.com/threads/catiledlayer-blanks-out-tiles-when-redrawing.1333948/ aims at solving these issues by using two private methods on CATiledLayer class: (void)setNeedsDisplayInRect:(CGRect)r levelOfDetail:(int)level; (BOOL)canDrawRect:(CGRect)rect levelOfDetail:(int)level; I have explored the repo in detail, however I wasn't able to test exactly this code from the GitHub repo. I have tried using those two private methods myself (through an Objective-C class that defines the methods in the header file and then a swift class which inherits it), but I couldn't solve the issue; the flashing and the full re-draw is still there. After doing a lot of research, the conclusion seems to be that one cannot use CATiledLayer with contents that are downloaded remotely, on demand, as tiles are being requested. I have, however, found one interesting thing which seems to work so far: before calling setNeedsDisplayInRect (or just setNeedsDisplay, as they behave the same for CATiledLayer in my testing), cache the current layer's contents, and after calling setNeedsDisplay (or setNeedsDisplayInRect), restore the contents back to the layer. This prevents flashing and preserves any tiles that were drawn at the time of the re-draw. let c = tiledLayer.contents tiledLayer.setNeedsDisplay(tileRect) tiledLayer.contents = c However! Docs clearly state the warning: Do not attempt to directly modify the contents property of a CATiledLayer object. Doing so disables the ability of a tiled layer to asynchronously provide tiled content, effectively turning the layer into a regular CALayer object. I believe this message implies modifying the contents property with some raw content, like image data, and that it may be safe to re-apply the existing contents (which are in my testing of type CAImageProvider) -- but I can't rely on an implementation detail in my production app. I have tested this and confirmed that the bug appears on: iPhone 14 Pro, iOS 18.5 iPhone 13 Pro, iOS 17.5.1 iPhone 5s, iOS 15.8.3 iPad Pro 1st gen, iPadOS 18.4.1 a couple simulator versions I can also confirm that the fix (to re-apply contents property) is also working properly on all these versions. Is this expected behavior, that tiled layer redraws itself entirely instead of redrawing specific tiles? Is it safe to modify contents of a CATiledLayer by re-applying the existing contents? If not, is there an alternative to avoid flashing?
3
0
107
May ’25