1

My app writes huge images (billions of pixels).

The image is too large to read as a UIImage or as Data.

Typically, when I share images with an activity controller, I do this:

var data: Data
data = ...
activityViewController = UIActivityViewController(activityItems: [data], applicationActivities: [purchaseCanvasPrintActivity])

Is it possible to pass a URL or something that points to the stored file than having to be allocated in a Data object or accomplish this with a custom UIActivity?

Jeshua Lacock
  • 5,730
  • 1
  • 28
  • 58

1 Answers1

0

From the docs (emphasis mine):

init(activityItems:applicationActivities:)

...

activityItems

The array of data objects on which to perform the activity. The type of objects in the array is variable and dependent on the data your application manages. For example, the data might consist of one or more string or image objects representing the currently selected content.

Instead of actual data objects, the objects in this array can be objects that adopt the UIActivityItemSource protocol, such as UIActivityItemProvider objects. Source and provider objects act as proxies for the corresponding data in situations where you do not want to provide that data until it is needed. Note that you should not reuse an activity view controller object that includes a UIActivityItemProvider object in its activityItems array.

Try implementing your own subclass of UIActivityItemProvider to provide the data on-demand.

Alexander
  • 59,041
  • 12
  • 98
  • 151
  • Thanks sounds promising. If you know of any example code it would be appreciated. But reading full documentation at the moment. – Jeshua Lacock Jul 27 '22 at 23:52
  • Found UIActivityItemProvider example on SO. Reading. – Jeshua Lacock Jul 27 '22 at 23:54
  • Hmm based on the example, it is returning a NSData object that is instantiated by a URL so I don't think that will work: https://stackoverflow.com/questions/20581389/how-do-i-use-uiactivityitemprovider-to-send-an-email-with-attachment-with-uiacti – Jeshua Lacock Jul 27 '22 at 23:56
  • I need the user to be able to copy the file somehow (like AirDrop). Shame I have to return a NSData object since the whole file isn't needed to be loaded to RAM to simply copy the blocks. – Jeshua Lacock Jul 28 '22 at 00:02
  • @JeshuaLacock I believe you can also return an `NSImage`, which will at least (typically) be a compressed image, unlike a raw bitmap stored as `Data`. A billion pixels is only a gigabyte, and probably compresses down to several 10s of MB. Might be plausible. – Alexander Jul 28 '22 at 00:50
  • From reading the docs, I couldn't actually get a good sense of what kind of result types are exceptable. Certainly `NSURL`s, `NSString`s, `NSData` and `NSImage` objects, but IDK about what others might be possible. – Alexander Jul 28 '22 at 00:51
  • oops, I meant `UIImage`* in both cases – Alexander Jul 28 '22 at 00:51
  • The images aren't limited to a single gigapixel though. Multi-gigapixels. The image is already compressed. – Jeshua Lacock Jul 28 '22 at 00:56
  • It sounds like you are suggesting that a UIActivityItemProvider can provide URLs, and are not required to return NSData? – Jeshua Lacock Jul 28 '22 at 01:01
  • P.S. 1 gigapixel image weighs in around 1GB compressed. – Jeshua Lacock Jul 28 '22 at 01:14
  • "he image is already compressed." Oh RIP, that's pretty rough. I was thinking the NSData you were talking about was an uncompressed bitmap (which are bafflingly large, JPEG and the discrete cosine transform more generally, is a miracle technology lol) – Alexander Jul 28 '22 at 01:19
  • "It sounds like you are suggesting that a UIActivityItemProvider can provide URLs, and are not required to return NSData?" I think so, but IDK if that could point to an item on disk. I was basing this off a quick/dirty skim of how people were using this API in public repos on GitHub: https://cs.github.com/?scopeName=All+repos&scope=&q=%22var+item%22+path%3A%2F**%2F*rovider.swift – Alexander Jul 28 '22 at 01:21
  • So I'm trying to pass 1GB data read from the image to the Activity Controller, the menu shows up, but if I attempt to use AirDrop it does nothing, no errors (well other than the usual warnings). Besides passing Data do I need to give it a MIME type or something? – Jeshua Lacock Jul 28 '22 at 01:42
  • The git link you provided seems to be obfuscated. – Jeshua Lacock Jul 28 '22 at 01:45
  • @JeshuaLacock Oh the special chars got parsed badly. How is this [link](https://cs.github.com/?scopeName=All+repos&scope=&q=%22var+item%22+path%3A%2F**%2F*rovider.swift)? – Alexander Jul 28 '22 at 01:55
  • I'm afraid that doesn't work either. I searched for "Arovider.swift github" but can't find it. – Jeshua Lacock Jul 28 '22 at 02:09
  • @JeshuaLacock You need to be logged in and enable the GitHub search preview (https://github.blog/2021-12-08-improving-github-code-search/). If you don't have access, you can approximate it with [the non-beta search UI](https://github.com/search?q=%22var+item%3A+Any%22+extension%3Aswift++filename%3A*provider.swift&type=Code) – Alexander Jul 28 '22 at 02:39
  • So, I can use a NSFileCoordinator to get it to copy the file with the AirDrop, but, only if the URL has the extension "zip" instead of "jpg". Then the Mac thinks its a zip file, which of course it isn't. Ugh. – Jeshua Lacock Jul 28 '22 at 02:43
  • 1
    First time learning about `NSFileCoordinator`. I'm afraid we've hit the limit of my current knowledge. I hope I started you off in the right direction, though! – Alexander Jul 28 '22 at 02:45
  • Mmm not really (not subclassing a `UIActivityItemProvider`), but I appreciate you trying to help. – Jeshua Lacock Jul 28 '22 at 02:49