Summary
chooseFromGallery returns the original photo-library asset without re-encoding it, so on iOS a normally-shot iPhone photo comes back as HEIC. The deprecated pickImages/getPhoto it replaces always re-encoded to JPEG, so migrating off them is a behaviour change for any app that assumed a browser-renderable format.
This isn't obvious from the docs: ChooseFromGalleryOptions carries a quality field documented as "Only applicable for MediaType.Photo and JPEG format", which reads as though photos come back as JPEG.
Where it happens
iOS — IONCameraLib's IONCAMRPhotoLibraryService.fetchImage(from:) builds its result from fetchImageURL(for: asset), which is asset.requestContentEditingInput { … editingInput?.fullSizeImageURL }. That URL is the original asset in the library; nothing decodes or re-encodes it.
Worth noting this applies to both selection modes, not just allowMultipleSelection: true. didFinishPicking branches on thumbnailAsData rather than on the selection mode:
if self.thumbnailAsData {
let results = await self.fetchMultipleResult(assetArray) // original asset URL
…
} else {
let item = await self.fetchSingleResult(assetArray.first) // UIImage → toData()
…
}
IONCAMRGalleryOptions decodes thumbnailAsData with a default of true, and ChooseFromGalleryOptions in the plugin's TypeScript has no field that maps to it — so a chooseFromGallery call can only ever take the first branch.
Android — ioncamera-android's onChooseFromGalleryResult resolves the picked URI to a file path and passes it to createImageMediaResult, whose bitmap decode/compress feeds only the base64 thumbnail; the result's uri still names the original file. Less visible in practice because Android cameras usually write JPEG, but the same pass-through.
takePhoto is unaffected — UIImage.toData(with:) honours encodingType, which defaults to JPEG.
Why it matters
HEIC uploads fine and then fails to render for most viewers: Chrome and Firefox decode none of it, and server-side sharp's prebuilt libvips ships no HEVC decoder, so thumbnailing fails too. An app that offers "choose from library" and accepts what it gets will store images that a majority of its users see as broken — and the failure lands after upload, where the only remedy is rejecting a photo the user already chose.
Versions: @capacitor/camera 8.2.2, IONCameraLib 1.0.5, ioncamera-android 1.0.2.
Steps to reproduce
- On an iPhone with Settings → Camera → Formats → High Efficiency, take a photo.
- Call
chooseFromGallery({ mediaType: MediaTypeSelection.Photo, includeMetadata: true }) and pick it.
results[0].metadata.format is heic, and uri points at a .HEIC file.
Expected (and what pickImages did): a JPEG.
Possible resolutions
Any one of these would be enough, in rough order of preference:
- Give
ChooseFromGalleryOptions an encodingType like TakePhotoOptions has, and re-encode to it.
- Re-encode gallery picks to JPEG by default, matching the deprecated methods' behaviour.
- If pass-through is the intended design, say so in the
chooseFromGallery docs and in the deprecation notes on getPhoto/pickImages — the format change is the migration's sharpest edge and currently isn't mentioned.
Summary
chooseFromGalleryreturns the original photo-library asset without re-encoding it, so on iOS a normally-shot iPhone photo comes back as HEIC. The deprecatedpickImages/getPhotoit replaces always re-encoded to JPEG, so migrating off them is a behaviour change for any app that assumed a browser-renderable format.This isn't obvious from the docs:
ChooseFromGalleryOptionscarries aqualityfield documented as "Only applicable forMediaType.Photoand JPEG format", which reads as though photos come back as JPEG.Where it happens
iOS —
IONCameraLib'sIONCAMRPhotoLibraryService.fetchImage(from:)builds its result fromfetchImageURL(for: asset), which isasset.requestContentEditingInput { … editingInput?.fullSizeImageURL }. That URL is the original asset in the library; nothing decodes or re-encodes it.Worth noting this applies to both selection modes, not just
allowMultipleSelection: true.didFinishPickingbranches onthumbnailAsDatarather than on the selection mode:IONCAMRGalleryOptionsdecodesthumbnailAsDatawith a default oftrue, andChooseFromGalleryOptionsin the plugin's TypeScript has no field that maps to it — so achooseFromGallerycall can only ever take the first branch.Android —
ioncamera-android'sonChooseFromGalleryResultresolves the picked URI to a file path and passes it tocreateImageMediaResult, whose bitmap decode/compressfeeds only the base64 thumbnail; the result'suristill names the original file. Less visible in practice because Android cameras usually write JPEG, but the same pass-through.takePhotois unaffected —UIImage.toData(with:)honoursencodingType, which defaults to JPEG.Why it matters
HEIC uploads fine and then fails to render for most viewers: Chrome and Firefox decode none of it, and server-side
sharp's prebuilt libvips ships no HEVC decoder, so thumbnailing fails too. An app that offers "choose from library" and accepts what it gets will store images that a majority of its users see as broken — and the failure lands after upload, where the only remedy is rejecting a photo the user already chose.Versions:
@capacitor/camera8.2.2,IONCameraLib1.0.5,ioncamera-android1.0.2.Steps to reproduce
chooseFromGallery({ mediaType: MediaTypeSelection.Photo, includeMetadata: true })and pick it.results[0].metadata.formatisheic, anduripoints at a.HEICfile.Expected (and what
pickImagesdid): a JPEG.Possible resolutions
Any one of these would be enough, in rough order of preference:
ChooseFromGalleryOptionsanencodingTypelikeTakePhotoOptionshas, and re-encode to it.chooseFromGallerydocs and in the deprecation notes ongetPhoto/pickImages— the format change is the migration's sharpest edge and currently isn't mentioned.