Skip to content

chooseFromGallery returns the original library asset (HEIC on iOS) where pickImages re-encoded to JPEG #69

Description

@mhuggins

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

iOSIONCameraLib'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.

Androidioncamera-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

  1. On an iPhone with Settings → Camera → Formats → High Efficiency, take a photo.
  2. Call chooseFromGallery({ mediaType: MediaTypeSelection.Photo, includeMetadata: true }) and pick it.
  3. 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:

  1. Give ChooseFromGalleryOptions an encodingType like TakePhotoOptions has, and re-encode to it.
  2. Re-encode gallery picks to JPEG by default, matching the deprecated methods' behaviour.
  3. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions