Image I/O

RSS for tag

Read and write most image file formats, manage color, access image metadata using Image I/O.

Posts under Image I/O tag

62 Posts
Sort by:

Post

Replies

Boosts

Views

Activity

Screenshot with ScreenCaptureKit much larger than with Command-Shift-3
I am capturing a screenshot with SCScreenshotManager's captureImageWithFilter. The resulting PNG has the same resolution as the PNG taken from Command-Shift-3 (4112x2658) but is 10x larger (14.4MB vs 1.35MB). My SCStreamConfiguration uses the SCDisplay's width and height and sets the color space to kCGColorSpaceSRGB. I currently save to file by initializing a NSBitmapImageRep using initWithCGImage, then representing as PNG with representationUsingType NSBitmapImageFileTypePNG, then writeToFile:atomically. Is there some configuration or compression I can use to bring down the PNG size to be more closely in-line with a Command-Shift-3 screenshot. Thanks!
1
0
212
1w
MacOS Finder Preview/Thumbnail Generation Limited to 20-21 Alpha Channels?
I am using the following shell script to return an image preview for use in FileMaker: qlmanage -t [sourcePath] -s 512 -o [outputPath] This usually works well, but it hangs if the RGB image (.tif, .psb, or .psd) has too many Alpha Channels ( >20 if on transparent background; >21 if flattened). This issue can be also be seen when looking at the image thumbnail or preview in the Finder. It appears MacOS won't create a thumbnail when the image has over 21 Alpha Channels... it just shows the default tif/psb/psd thumbnail, even if the image is very small. Environment MacOS Sonoma 14.4.1 Adobe Photoshop 2024 (25.6.0) Maximize PSD and PSB File Compatibility is enabled when saved from Photoshop Since I'm only able to upload a screenshot to this post, the original test files can be found in the Adobe Forum with the Title: "MacOS Finder Preview Limited to 20-21 Alpha Channels?"
0
0
110
1w
Lossy option has no effect when exporting PNG to HEIF
Under Sonoma 14.4 the compression option doesn't work with PNG images. It works for JPG/HEIF. Preview can export PNG file to HEIC with compression option. What am I missing? Previously this has worked. I am trying with 0.01 and 0.9 as compression quality and the file size is the same for PNG. Is Preview using some trick to convert the image using ciContext.createCGImage? PS: Compression option of 1.0 was broken under 14.4 RC and Preview created empty file. func heifImageDataUsingDestination(at url: URL, compressionQuality : CGFloat) -> Data? { guard let imageSource = CGImageSourceCreateWithURL(url as CFURL, nil) else { return nil } guard let cgImage = CGImageSourceCreateImageAtIndex(imageSource, 0, nil) else { return nil } var mutableData = NSMutableData() guard let imageDestination = CGImageDestinationCreateWithData(mutableData, "public.heic" as CFString, 1, nil) else { return nil } let options = [ kCGImageDestinationLossyCompressionQuality: compressionQuality ] as CFDictionary CGImageDestinationAddImage(imageDestination, cgImage, options) let success = CGImageDestinationFinalize(imageDestination) if success { return mutableData as Data } return nil } func heifImageDataUsingCIContext(at url: URL, compressionQuality : CGFloat) -> Data? { guard let ciImage = CIImage(contentsOf: url) else { return nil } let context = CIContext() let colorspace = ciImage.colorSpace ?? CGColorSpaceCreateDeviceRGB() let options = [CIImageRepresentationOption(rawValue: kCGImageDestinationLossyCompressionQuality as String) : compressionQuality] return context.heifRepresentation(of: ciImage, format: .RGBA8, colorSpace: colorspace, options: options) }
4
0
445
2w
iOS 17 UIImageReader has memory leaks
In my SwiftUI view, I try to load the image from data. var body: some View { Group{ if let data = model.detailImageData, let uiimage = UIImage(data: data) {// no memory issue Image(uiImage: uiimage) .resizable() .scaledToFit() } } } But I want to get the HDR style of my image, so I use if let data = model.detailImageData, let uiimage = UIImageReader.default.image(data:data){ //memory leaks!!! When I change the data, the memory of the previous image is never freeed. finally caused my app to crash. You can see it from the Instrument screenshot.
0
0
283
Apr ’24
Memory Leak in ImageIO?
I use this code to show the Image in HDR in SwiftUI struct HDRImageView: UIViewRepresentable { // Set up a common reader for all UIImage read requests. static let reader: UIImageReader = { var config = UIImageReader.Configuration() config.prefersHighDynamicRange = true return UIImageReader(configuration: config) }() let data:Data? let enableHDR:Bool func makeUIView(context: Context) -> UIImageView { let view = UIImageView() view.preferredImageDynamicRange = enableHDR ? .high : .standard update(view) // Set this view to fit itself to the parent view. view.setContentCompressionResistancePriority(.defaultLow, for: .horizontal) view.setContentCompressionResistancePriority(.defaultLow, for: .vertical) view.setContentHuggingPriority(.required, for: .horizontal) view.setContentHuggingPriority(.required, for: .vertical) return view } func updateUIView(_ view: UIImageView, context: Context) { update(view) } func update(_ view: UIImageView) { autoreleasepool{//not working if let data = data { view.image = nil//set to nil first is not working view.image = HDRImageView.reader.image(data: data) } else { view.image = nil } view.preferredImageDynamicRange = enableHDR ? .high : .standard } } } But when I update the input data, seems that the old image data can not be freeed. After several changes, the app takes too much memory and crash. I found it's the VM:ImageIO_Surface_Data and the VM_Image_IO take up the memory. If I change the HDRImageView into a normal Image(uiimage:UIImage(data:)) It no longer have this issue. Is it a memory leak? and how to solve this. Update: I then tried using Image(_:cgImage), and it appear to be the same result.
0
0
265
Apr ’24
Render a SwiftUI view into an image on Dark mode not work
This is my test code. import SwiftUI extension View { @MainActor func render(scale: CGFloat) -> UIImage? { let renderer = ImageRenderer(content: self) renderer.scale = scale return renderer.uiImage } } struct ContentView: View { @Environment(\.colorScheme) private var colorScheme @State private var snapImg: UIImage = UIImage() var snap: some View { Text("I'm now is \(colorScheme == .dark ? "DARK" : "LIGHT") Mode!") .foregroundStyle(colorScheme == .dark ? .red : .green) } @ViewBuilder func snapEx() -> some View { VStack { Text("@ViewBuilder I'm now is \(colorScheme == .dark ? "DARK" : "LIGHT") Mode!") .foregroundStyle(colorScheme == .dark ? .red : .green) Text("@ViewBuilder I'm now is \(colorScheme == .dark ? "DARK" : "LIGHT") Mode!") .background(.pink) Text("@ViewBuilder I'm now is \(colorScheme == .dark ? "DARK" : "LIGHT") Mode!") .background(.purple) Text("@ViewBuilder I'm now is \(colorScheme == .dark ? "DARK" : "LIGHT") Mode!") .foregroundStyle(colorScheme == .dark ? .red : .green) Text("@ViewBuilder I'm now is \(colorScheme == .dark ? "DARK" : "LIGHT") Mode!") .foregroundStyle(colorScheme == .dark ? .red : .green) } } @ViewBuilder func snapView() -> some View { VStack { Text("Text") Text("Test2") .background(.green) snap snapEx() } } var body: some View { let snapView = snapView() VStack { snapView Image(uiImage: snapImg) Button("Snap") { snapImg = snapView.render(scale: UIScreen.main.scale) ?? UIImage() } } } } When using ImageRenderer, there are some problems with converting View to images. For example, Text cannot automatically modify the foreground color of Dark Mode. This is just a simple test code, not just Text. How should I solve it?
3
1
731
Apr ’24
Does CVE-2024-1580 affect my app?
I have an image viewing app with support for avif (and avis) images. I'm trying to figure out if the recent bug in CoreMedia (dav1d) affects my app. The apple security update: https://support.apple.com/en-gb/HT214097 The vulnerable code path in dav1d is only reached when c->n_fc > 1 (https://code.videolan.org/videolan/dav1d/-/blob/2b475307dc11be9a1c3cc4358102c76a7f386a51/src/decode.c#L2845), where c is the dav1d context. With some reverse engineering, the way I see CMPhoto calling into VideoToolBox (which internally calls into AV1SW.videodecoder, which is a wrapper around dav1d), the max frame delay is hardcoded to 1 in the dav1d settings which intern means that c->n_fc in dav1d is always 1. The vulnerable code path in dav1d is only reached when c->n_fc > 1 (https://code.videolan.org/videolan/dav1d/-/blob/2b475307dc11be9a1c3cc4358102c76a7f386a51/src/decode.c#L2845). From my understand, this should mean that my app isn't affected. The apple security update however clearly mentions that "Processing an image may lead to arbitrary code execution". Surely I'm missing something?
0
0
286
Apr ’24
iOS ImageRenderer Unable to localize text correctly Bug
A simple view has misaligned localized content after being converted to an image using ImageRenderer. This is still problematic on real phone and TestFlight I'm not sure what the problem is, I'm assuming it's an ImageRenderer bug. I tried to use UIGraphicsImageRenderer, but the UIGraphicsImageRenderer captures the image in an inaccurate position, and it will be offset resulting in a white border. And I don't know why in some cases it encounters circular references that result in blank images. "(1) days" is also not converted to "1 day" properly.
2
0
230
Apr ’24
Capturing the coordinates of an image and locating a second image to those coordinates
if balloon == yellow1_balloon { soundFile = "Sounds/newblop.wav" playSound() balloon.isHidden = true poppedImages.isHidden = false poppedImages.animationImages = ["popyellow-1","popyellow-2","popyellow-3","popyellow-4","popyellow-5","popyellow-6","popyellow-7"] .compactMap({ name in UIImage(named: name) }) let x:CGFloat = yellow1_balloon.frame.origin.x let y:CGFloat = yellow1_balloon.frame.origin.y poppedImages.frame.origin.x = x poppedImages.frame.origin.y = y poppedImages.animationDuration = 1.0 poppedImages.animationRepeatCount = 1 poppedImages.startAnimating() score = score + 10 scoreLbl.text = String(score) return } x,y cordinates are always the same a when yellow1_balloon is first created and not where it ends up after being touched.
0
0
257
Mar ’24
Save ARDepthData as .tiff
I would like to save the depth map from ARDepthData as .tiff, but notice my output tiff distances are incorrect. Objects that are close are reported to be slightly farther away, and walls that are around 4 meters away from me have a recorded value of 2 meters. I am using this code to write the tiff: import UIKit # Save method extension CVPixelBuffer { func saveDepthMapToTIFF(to path: URL) { let ciImage = CIImage(cvPixelBuffer: self) let context = CIContext() do { try context.writeTIFFRepresentation( of: ciImage, to: path, format: .Lf, colorSpace: CGColorSpaceCreateDeviceGray() ) } catch { print("Failed to write TIFF: \(error)") } } } # Calling the save arFrame.sceneDepth?.depthMap.saveDepthMapToTIFF(to: depthMapPath) I am reading the file like this in Python import tifffile depth_map = tifffile.imread("test.tiff") plt.imshow(depth_map) plt.colorbar() which creates this image: The farthest parts of the room should be around 4 meters, not 2. The dark blue spot on the lower right is closer than half a meter away. Notably the depth map contains distances from the camera plane to each region, not the distance from the camera sensor to the region. Even correcting for this though, the depth map remains about the same. Is there an issue with how I am saving the depth image? Is there a scale factor or format error?
1
1
350
Mar ’24
Is it possible to compile images into an APNG using Swift?
Hello, I'm wondering if there is a way to programmatically write a series of UIImages into an APNG, similar to what the code below does for GIFs (credit: https://github.com/AFathi/ARVideoKit/tree/swift_5). I've tried implementing a similar solution but it doesn't seem to work. My code is included below I've also done a lot of searching and have found lots of code for displaying APNGs, but have had no luck with code for writing them. Any hints or pointers would be appreciated. func generate(gif images: [UIImage], with delay: Float, loop count: Int = 0, _ finished: ((_ status: Bool, _ path: URL?) -> Void)? = nil) { currentGIFPath = newGIFPath gifQueue.async { let gifSettings = [kCGImagePropertyGIFDictionary as String : [kCGImagePropertyGIFLoopCount as String : count]] let imageSettings = [kCGImagePropertyGIFDictionary as String : [kCGImagePropertyGIFDelayTime as String : delay]] guard let path = self.currentGIFPath else { return } guard let destination = CGImageDestinationCreateWithURL(path as CFURL, __UTTypeGIF as! CFString, images.count, nil) else { finished?(false, nil); return } //logAR.message("\(destination)") CGImageDestinationSetProperties(destination, gifSettings as CFDictionary) for image in images { if let imageRef = image.cgImage { CGImageDestinationAddImage(destination, imageRef, imageSettings as CFDictionary) } } if !CGImageDestinationFinalize(destination) { finished?(false, nil); return } else { finished?(true, path) } } } My adaptation of the above code for APNGs (doesn't work; outputs empty file): func generateAPNG(images: [UIImage], delay: Float, count: Int = 0) { let apngSettings = [kCGImagePropertyPNGDictionary as String : [kCGImagePropertyAPNGLoopCount as String : count]] let imageSettings = [kCGImagePropertyPNGDictionary as String : [kCGImagePropertyAPNGDelayTime as String : delay]] guard let destination = CGImageDestinationCreateWithURL(outputURL as CFURL, UTType.png.identifier as CFString, images.count, nil) else { fatalError("Failed") } CGImageDestinationSetProperties(destination, apngSettings as CFDictionary) for image in images { if let imageRef = image.cgImage { CGImageDestinationAddImage(destination, imageRef, imageSettings as CFDictionary) } } }
3
0
770
Mar ’24
ICDeviceBrowser detects camera devices
I am developing an app using a data cable to link a camera. When I enter the page for the first time, I can detect the camera device, and then when I exit the page and enter again, I cannot detect the linked camera. - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. self.view.backgroundColor = [UIColor whiteColor]; [self addImageCaptureCore]; } - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [self checkCameraConnection]; }); } - (void)checkCameraConnection { if (@available(iOS 13.0, *)) { NSArray<ICDevice *> *connectedDevices = self.browser.devices; if (connectedDevices.count > 0) { NSLog(@"Camera is connected"); } else { NSLog(@"Camera is not connected"); } } else { // Fallback on earlier versions } } - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; if (@available(iOS 13.0, *)) { if (self.cameraDevice) { if (self.cameraDevice.hasOpenSession) { [self.cameraDevice requestCloseSession]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [self.browser stop]; self.browser.delegate = nil; self.browser = nil; }); } else { dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [self.browser stop]; self.browser.delegate = nil; self.browser = nil; }); } } } else { // Fallback on earlier versions } } - (void)addImageCaptureCore { if (@available(iOS 13.0, *)) { ICDeviceBrowser *browser = [[ICDeviceBrowser alloc] init]; browser.delegate = self; [browser start]; self.browser = browser; } else { } } #pragma mark - ICDeviceBrowserDelegate - (void)deviceBrowser:(ICDeviceBrowser*)browser didAddDevice:(ICDevice*)device moreComing:(BOOL) moreComing API_AVAILABLE(ios(13.0)){ NSLog(@"Device name = %@",device.name); if ([device isKindOfClass:[ICCameraDevice class]]) { if ([device.capabilities containsObject:ICCameraDeviceCanAcceptPTPCommands]) { ICCameraDevice *cameraDevice = (ICCameraDevice *)device; cameraDevice.delegate = self; [cameraDevice requestOpenSession]; self.cameraDevice = cameraDevice; } } } - (void)deviceBrowser:(ICDeviceBrowser*)browser didRemoveDevice:(ICDevice*)device moreGoing:(BOOL) moreGoing API_AVAILABLE(ios(13.0)){ if (self.cameraDevice) { if (self.cameraDevice.hasOpenSession) { [self.cameraDevice requestCloseSession]; self.cameraDevice.delegate = nil; self.cameraDevice = nil; } else { self.cameraDevice.delegate = nil; self.cameraDevice = nil; } } } #pragma mark - ICCameraDeviceDelegate - (void)cameraDevice:(ICCameraDevice*)camera didAddItems:(NSArray<ICCameraItem*>*) items API_AVAILABLE(ios(13.0)){ if (items.count > 0) { ICCameraItem *latestItem = items.lastObject; NSLog(@"name = %@",latestItem.name); } } #pragma mark - ICDeviceDelegate - (void)device:(ICDevice*)device didOpenSessionWithError:(NSError* _Nullable) error API_AVAILABLE(ios(13.0)){ if (error) { NSLog(@"Failed to open session %@",error.localizedDescription); } else { NSLog(@"open session success"); } } - (void)device:(ICDevice*)device didCloseSessionWithError:(NSError* _Nullable)error API_AVAILABLE(ios(13.0)){ if (error) { NSLog(@"close session error = %@",error.localizedDescription); } else { NSLog(@"didCloseSession"); } } - (void)didRemoveDevice:(ICDevice*)device { }
0
0
270
Mar ’24
CoreML Image Classification Model - What Preprocessing Is Required For Static Images
I have trained a model to classify some symbols using Create ML. In my app I am using VNImageRequestHandler and VNCoreMLRequest to classify image data. If I use a CVPixelBuffer obtained from an AVCaptureSession then the classifier runs as I would expect. If I point it at the symbols it will work fairly accurately, so I know the model is trained fairly correctly and works in my app. If I try to use a cgImage that is obtained by cropping a section out of a larger image (from the gallery), then the classifier does not work. It always seems to return the same result (although the confidence is not a 1.0 and varies for each image, it will be to within several decimal points of it, eg 9.9999). If I pause the app when I have the cropped image and use the debugger to obtain the cropped image (via the little eye icon and then open in preview), then drop the image into the Preview section of the MLModel file or in Create ML, the model correctly classifies the image. If I scale the cropped image to be the same size as I get from my camera, and convert the cgImage to a CVPixelBuffer with same size and colour space to be the same as the camera (1504, 1128, kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange) then I get some difference in ouput, it's not accurate, but it returns different results if I specify the 'centerCrop' or 'scaleFit' options. So I know that 'something' is happening, but it's not the correct thing. I was under the impression that passing a cgImage to the VNImageRequestHandler would perform the necessary conversions, but experimentation shows this is not the case. However, when using the preview tool on the model or in Create ML this conversion is obviously being done behind the scenes because the cropped part is being detected. What am I doing wrong. tl;dr my model works, as backed up by using video input directly and also dropping cropped images into preview sections passing the cropped images directly to the VNImageRequestHandler does not work modifying the cropped images can produce different results, but I cannot see what I should be doing to get reliable results. I'd like my app to behave the same way the preview part behaves, I give it a cropped part of an image, it does some processing, it goes to the classifier, it returns a result same as in Create ML.
2
0
628
Mar ’24
How to visualize 16bit raw image data
I'm working on a very simple App where I need to visualize an image on the screen of an iPhone. However, the image has some special properties. It's a 16bit, yuv422_yuy2 encoded image. I already have all the raw bytes saved in a Data object. After googling for a long time, I still did not figure out the correct way. My current understanding is first create a CVPixelBuffer to properly represent the encoding information. Then conver the CVPixelBuffer to an UIImage. The following is my current implementation. public func YUV422YUY2ToUIImage(data: Data, height: Int, width: Int, bytesPerRow: Int) -> UIImage { return rosImage.data.withUnsafeMutableBytes { rawPointer in let baseAddress = rawPointer.baseAddress! let tempBufferPointer = UnsafeMutablePointer<CVPixelBuffer?>.allocate(capacity: 1) CVPixelBufferCreateWithBytes( kCFAllocatorDefault, width, height, kCVPixelFormatType_422YpCbCr16, baseAddress, bytesPerRow, nil, nil, nil, tempBufferPointer) let ciImage = CIImage(cvPixelBuffer: tempBufferPointer.pointee!) return UIImage(ciImage: ciImage) } } However, when I execute the code, I have the followin error -[CIImage initWithCVPixelBuffer:options:] failed because its pixel format v216 is not supported. So it seems CIImage is unhappy. I think I need to convert the encoding from yuv422_yuy2 to something like plain ARGB. But after a long tim googling, I didn't find a way to do that. The closest function I cand find is https://developer.apple.com/documentation/accelerate/1533015-vimageconvert_422cbypcryp16toarg But the function is too complex for me to understand how to use it. Any help is appreciated. Thank you!
2
0
517
Mar ’24
Image processing
How to extract an object from a picture or remove the background of an object just like you can create stickers in Photos app. Is there any other official model or library other than using some website's API? (DeepLabV3.mlmodel cannot infer what I need)
0
0
325
Feb ’24
[macOS Sonoma] screencapture CLI no longer includes DPI information
Using the screencapture CLI on macOS Sonoma 14.0 (23A344) results in a 72dpi image file, no matter if it was captured on a retina display or not. For example, using screencapture -i ~/Desktop/test.png in Terminal lets me create a selective screenshot, but the resulting file does not contain any DPI metadata (checked using mdls ~/Desktop/test.png), nor does the image itself have the correct DPI information (should be 144, but it's always 72; checked using Preview.app). I noticed a (new?) flag option, -r, for which the documentation states: -r Do not add screen dpi meta data to captured file. Is that flag somehow automatically set? Setting it myself makes no difference and obviously results in a no-dpi-in-metadata and wrong-dpi-in-image file. The only two ways I got the correct DPI information in a resulting image file was using the default options (forced by -p): screencapture -i -p, and by making the capture go to the clipboard screencapture -i -c. Sadly, I can't use those in my case. Feedback filed: FB13208235 I'd appreciate any pointers, Matthias
4
2
1.1k
Feb ’24