메인 콘텐츠로 건너뛰기

Capacitor 앱에서 사진 찍고 편집하는 방법

사진을 찍고 편집하는 방법은 Capgo 앱에서 카메라 8 API 기능을 사용하여 Capacitor 앱에서 사진을 찍고, 앨범에서 사진을 선택하고, 앱 내에서 사진을 편집하고, 실시간 미리보기, 압축, EXIF 정보, 업로드를 지원합니다.

기사 저자

마틴 도나디유

작가

발레리아

리뷰어

조던

편집자

Capacitor 앱에서 사진을 찍고 편집하는 방법

Capacitor 앱에서 사진을 찍고 편집하려면 @capacitor/camera 8.1 이상: Camera.takePhoto() 카메라를 열어 editable: 'in-app' 촬영 및 편집을 위한 카파시토르 앱에서 사진을 찍고 편집하는 방법 chooseFromGallery() 사진을 찍고 편집하는 방법 @capgo/camera-preview이 안내서에서는 촬영, 편집, 권한, 압축, 메타데이터, 저장, 업로드에 대해 설명합니다. code에 대해 Capacitor 8.

어떤 도구를 선택해야 하나요

필요한 플러그인 왜
시스템 카메라 UI를 사용하여 사진을 찍어보세요 @capacitor/camera takePhoto 유지 관리가 필요없는 커스텀 UI가 없으며 모든 장치에서 작동합니다.
사용자가 사진을 잘라거나 회전할 수 있도록 해보세요 @capacitor/camera editable, editPhoto, editURIPhoto iOS와 Android에서 내장된 편집기
사진 또는 비디오 중 하나 이상을 선택하세요 @capacitor/camera chooseFromGallery Android 사진 선택기와 PHPicker를 사용하여 광범위한 권한 없이
커스텀 카메라 화면 (Overlay, ID 카드 프레임, 얼굴 안내) @capgo/camera-preview HTML과 JS에서 제어하는 네이티브 미리보기
자신의 그리드 내에서 전체 사진 라이브러리를 탐색 @capgo/capacitor-photo-library 썸네일과 함께 페이지네이션된 라이브러리 접근
HEIC를 축소, 리사이즈 또는 변환 @capgo/capacitor-file-compressor 네이티브 인코더, EXIF를 제거
대형 사진을 신뢰할 수 있는 업로드 @capgo/capacitor-uploader 네이티브 배경 업로드와 진행률

카메라 플러그인을 설치하고 구성

bun add @capacitor/camera
bunx cap sync

버전 8.1 이상이 있어야 합니다. 이 안내서에 설명된 메소드 (takePhoto, chooseFromGallery, editPhoto, editURIPhoto)는 8.1에서 추가되었으며 CameraErrorCode 8.2 에서. 더 오래된 getPhoto 그리고 pickImages deprecated

iOS

이 키를 추가하세요 ios/App/App/Info.plist. 애플은 모호한 문자열이 있는 빌드에 반대하므로 실제 이유를 설명하세요:

<key>NSCameraUsageDescription</key>
<string>Take a photo for your profile or attach it to a report.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Choose existing photos to attach.</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>Save photos you take to your library.</string>

Android

촬영 및 앨범 선택에는 권한이 필요하지 않습니다. 플러그인은 시스템 카메라 활동을 시작하고 Android 11 이상의 기기에 있는 Android Photo Picker를 사용합니다. 지원하는 기기에서는 이에 fallback합니다. 더 오래된 기기에 Google Play 서비스를 사용하여 백포트된 픽커를 얻으려면 이 안에 추가하세요 ACTION_OPEN_DOCUMENT 8.2 에서 <application> in AndroidManifest.xmlnamespace를 사용하므로 tools 또한 추가하세요 xmlns:tools="http://schemas.android.com/tools" __CAPGO_KEEP_0__ <manifest> element이 아직 존재하지 않으면 (새로운 Capacitor 프로젝트는) xmlns:android):

<service android:name="com.google.android.gms.metadata.ModuleDependencies"
    android:enabled="false"
    android:exported="false"
    tools:ignore="MissingClass">
    <intent-filter>
        <action android:name="com.google.android.gms.metadata.MODULE_DEPENDENCIES" />
    </intent-filter>
    <meta-data android:name="photopicker_activity:0:required" android:value="" />
</service>

Only saveToGallery: true Only

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="29" />

저장소 권한이 필요하고, 오래된 안드로이드 버전에서만: READ_MEDIA_IMAGES 추가하지 마세요

앱의 핵심 목적이 갤러리나 편집기라면 제외합니다. 구글 플레이의 사진 및 비디오 권한 정책은 간헐적으로 사진이 필요한 앱이 픽커를 사용해야 하며, 권한을 선언하지 않고 이유를 설명하지 않은 빌드가 거부됩니다.

import { Camera, CameraDirection, CameraErrorCode, EncodingType } from '@capacitor/camera';

export async function takePicture() {
  try {
    const photo = await Camera.takePhoto({
      quality: 85,
      targetWidth: 2048,
      targetHeight: 2048,
      correctOrientation: true,
      encodingType: EncodingType.JPEG,
      cameraDirection: CameraDirection.Rear, // iOS and web
      includeMetadata: true,
    });

    // webPath works directly in <img src>
    document.querySelector<HTMLImageElement>('#preview')!.src = photo.webPath!;
    return photo;
  } catch (e: any) {
    if (e.code === CameraErrorCode.TakePhotoCancelled) return null;
    if (e.code === CameraErrorCode.CameraPermissionDenied) {
      // show a screen that explains how to enable the camera in Settings
      return null;
    }
    throw e;
  }
}

사진 찍기 MediaResult:

  • uri사진 찍기를 완료하면 editURIPhoto.
  • webPath: 원본 사진의 native file URI (웹에서는 사용할 수 없음). Filesystem, 업로더, 또는
  • thumbnail: WebView가 로드할 수 있는 URL. 미리보기 대신 base64를 사용하지 마세요.
  • metadata: native에서 base64로 thumbnail, 웹에서 원본 사진을 로드합니다. includeMetadata true.
  • savedwhether saveToGallery succeeded.

targetWidth and targetHeight 업로드를 피하기 위해 2048 pixel 이미지를 필요로 할 때 12 MP 사진을 업로드하지 않도록 가장 저렴한 방법입니다.

사진 편집: 자르기 및 회전

촬영 직후 편집

설정 editable promise가 해결되기 전에 사용자가 편집기에서 도착합니다:

const photo = await Camera.takePhoto({
  quality: 85,
  editable: 'in-app', // 'in-app' | 'external' | 'no'
});

'external' Android에서는 Google Photos와 같은 다른 편집기를 설치하여 이미지에 접근하고, iOS에서는 내장 편집기를 사용합니다. 'in-app'.

기존 사진 편집

선택한 사진이나 이전에 저장한 사진을 편집하려면 URI를 전달하세요.

const edited = await Camera.editURIPhoto({
  uri: photo.uri!,
  saveToGallery: false,
  includeMetadata: false,
});

만약에 canvas 또는 서버 응답에서만 base64 (예를 들어)만 가지고 있다면 사용하세요. editPhoto입력은 raw base64일 때만 사용하세요. data: prefix가 없습니다:

const { outputImage } = await Camera.editPhoto({ inputImage: base64 });
img.src = `data:image/jpeg;base64,${outputImage}`;

웹에서 이 두 가지 방법은 사용할 수 없습니다. 필터, 스티커, 텍스트 또는 자유 형식의 드로잉이 필요하다면 내장 편집기는 충분하지 않습니다. 이미지를 렌더링하고 편집을 적용하려면 canvas를 사용하거나 Cropper.js와 같은 자바스크립트 크로퍼를 사용하세요. fixed aspect ratios (예를 들어, 아바타)에서. <canvas> canvas export ( )는 Blob을 반환하여 직접 업로드할 수 있습니다.canvas.toBlob(cb, 'image/jpeg', 0.85)갤러리에서 사진을 선택하세요.

import { Camera, MediaTypeSelection } from '@capacitor/camera';

const { results } = await Camera.chooseFromGallery({
  mediaType: MediaTypeSelection.Photo,
  allowMultipleSelection: true,
  limit: 5,            // Android 13+ and iOS
  quality: 85,
  targetWidth: 2048,
  targetHeight: 2048,
});

const urls = results.map((r) => r.webPath);

plus를 사용하면 한 번에 선택-잘라내기 기능을 제공합니다. allowMultipleSelection: false plus editable: 'in-app' iOS에서 사용자는 제한된 접근 권한을 부여할 수 있습니다. mediaType: MediaTypeSelection.All __CAPGO_KEEP_0__

__CAPGO_KEEP_0__ pickLimitedLibraryPhotos() 앱에서 사진을 찍고 편집하는 방법 getLimitedLibraryPhotos() 선택을 변경하고 변경할 수 있는 것을 반환합니다. 시스템 픽커를 사용하면 거의 필요하지 않습니다. 선택한 항목은 항상 읽을 수 있습니다.

사용자의 라이브러리를 자신의 UI 내에 표시하는 앱 (사진 인쇄 앱, 백업 앱)에서 사용하세요. @capgo/capacitor-photo-library:

import { PhotoLibrary } from '@capgo/capacitor-photo-library';

const { state } = await PhotoLibrary.requestAuthorization();
if (state === 'authorized' || state === 'limited') {
  const { assets, hasMore } = await PhotoLibrary.getLibrary({
    limit: 60,
    offset: 0,
    thumbnailWidth: 256,
    thumbnailHeight: 256,
  });
  // assets[i].thumbnail?.webPath for the grid, getPhotoUrl({ id }) for full size
}

같은 플러그인의 pickMedia() 시스템 픽커를 열고 선택을 캐시에 복사합니다. 두 가지 흐름에 하나의 플러그인을 사용하려면 캐시를 원한다면. Android에서 전체 라이브러리 접근을 요청하기 전에 Google Play 정책을 기억하세요.

커스텀 카메라 화면 만들기

시스템 카메라 UI는 ID 카드 프레임, 문서 윤곽, 브랜드를 표시할 수 없습니다. @capgo/camera-preview 자연 카메라 피드를 렌더링하고 HTML에서 UI를 그립니다:

bun add @capgo/camera-preview
bunx cap sync
import { CameraPreview } from '@capgo/camera-preview';

await CameraPreview.start({
  position: 'rear',
  toBack: true,          // preview behind the WebView
  aspectRatio: '4:3',
  storeToFile: true,     // capture() returns a file path instead of base64
  disableAudio: true,
});

await CameraPreview.setFlashMode({ flashMode: 'auto' });
await CameraPreview.setZoom({ level: 2 });

const { value: filePath, exif } = await CameraPreview.capture({ quality: 85 });

await CameraPreview.stop();

그것과 함께 toBack: true, 미리보기는 WebView 뒤에 있으므로 페이지와 모든 부모 요소는 카메라가 활성화된 동안 투명한 배경을 가지고 있어야 합니다. 일반적인 패턴은 camera-active 클래스 body 이것을 설정합니다. background: transparent 을 호출합니다. NSCameraUsageDescription 카메라 권한을 요청하기 위해 CAMERA 을 호출합니다. requestPermissions()스크린이 닫히면 카메라를 해제하기 위해 stop() 을 호출합니다.

이미지를 표시, 압축 및 변환합니다.

Use webPath (or Capacitor.convertFileSrc(path) 이미지를 업로드하기 전에 이미지를 축소하세요: <img> that sets

and hides the rest of the app.

import { FileCompressor } from '@capgo/capacitor-file-compressor';

const { path } = await FileCompressor.compressImage({
  path: photo.uri!,
  width: 1600,          // keeps aspect ratio
  quality: 0.75,
  mimeType: 'image/jpeg',
});

HEIC 형식의 사진을 iPhone에서 받아 HEIC를 JPEG로 변환하는 것을 지원합니다. 이 변환은 백엔드가 HEIC를 읽을 수 없는 경우에만 수행됩니다. 변환 결과는 임시 디렉토리에 저장되므로, 필요할 경우 이 디렉토리에서 사진을 이동해야 합니다. @capacitor/filesystem 이 사진을 유지하려면 이동하세요.

EXIF 메타데이터 및 위치隐私

With includeMetadata: true, metadata.exif 카메라 롤에서 가져온 사진은 GPS 좌표를 포함할 수 있습니다. 두 가지 규칙을 통해 문제를 피할 수 있습니다:

  1. 공개되는 사진(프로필 사진, 시장 목록)을 업로드하기 전에 위치 정보를 제거하세요. @capgo/capacitor-file-compressor 압축 과정에서 모든 플랫폼에서 EXIF를 제거합니다.
  2. 필요한 경우 위치 정보(现场 보고서, 검사)를 읽어 압축하기 전에 EXIF에서 읽어 분리된 field로 전송하세요. 그런 다음 App Store의 개인 정보 레이블 및 Play 데이터 안전성 양식에 위치 정보를 공개하세요. iOS 쪽에 대한 개인 정보 매니페스트 가이드를 참조하세요. 앱 스토어의 개인 정보 레이블 및 Play 데이터 안전성 양식에 위치 정보를 공개하세요. 사진을 갤러리나 앱 저장소에 저장하세요.

saveToGallery: true 디렉토리 takePhoto 또는 editURIPhoto Live Update saved Cloudflare

import { Filesystem, Directory } from '@capacitor/filesystem';

await Filesystem.copy({
  from: photo.uri!,
  to: `photos/${Date.now()}.jpg`,
  toDirectory: Directory.Data,
});

Capacitor

GitHub

Capgo fetch code FormData API

const blob = await fetch(photo.webPath!).then((r) => r.blob());
const form = new FormData();
form.append('file', blob, 'photo.jpg');
await fetch('https://api.example.com/photos', { method: 'POST', body: form });

SDK

import { Uploader } from '@capgo/capacitor-uploader';

const { id } = await Uploader.startUpload({
  filePath: path,
  serverUrl: 'https://api.example.com/photos',
  method: 'POST',
  mimeType: 'image/jpeg',
});

await Uploader.addListener('events', (event) => {
  console.log(event.name, event.payload);
});

CLI

  1. npm
  2. bun takePhoto 또는 chooseFromGallery 과 editable: 'in-app', targetWidth: 1024, targetHeight: 1024.
  3. 1:1 비율을 보장하기 위해 캔버스에서 사각형으로 잘라야 합니다.
  4. 압축하기 quality: 0.8 및 EXIF를 제거합니다.
  5. 업로드하고, 서버 URL을 보여주고, 로컬 파일을 보여주지 않아야 하므로 아바타가 다시 설치될 때 살아남습니다.

문제 해결

iOS에서 카메라가 열릴 때 앱이 충돌합니다.: 사용 설명 키가 누락되어 있습니다. Info.plist.

Android에서 사진이 회전합니다.: correctOrientation: true (기본값)이며 EXIF 회전을 적용하지 않고 raw 픽셀을 읽지 않도록 하십시오.

Android 기기에서 메모리가 부족한 경우 앱이 사진을 찍은 후 재시작됩니다.: 카메라가 열려 있는 동안 액티비티가 종료될 수 있습니다. appRestoredResult from @capacitor/app 을 사용하여 재시작 후 결과를 복원하세요.

webPath 이미지 로드가 실패합니다.: 사진을 저장한 webPath 을 재사용하세요. uri 을 저장하고 다시 로드하세요. Capacitor.convertFileSrc.

또는 을 저장하고 다시 로드하세요. start() 카메라 프리뷰 화면이 검은색 화면으로 표시됩니다.

: WebView 위에 있는 요소가 배경 색상을 가지고 있거나, : 제거 READ_MEDIA_IMAGES 그리고 READ_MEDIA_VIDEO trừ야, 당신이 당신의 앱이 광범위한 접근이 필요하다고 선언한 경우

스토어 릴리즈 없이 고쳐진 것을 배포

이미지 크기, 압축 수준, 자르기 비율 및 업로드 엔드포인트는 모두 당신의 웹 code 에서 관리됩니다. Capgo Live Update __CAPGO_KEEP_0__ Live Update를 사용하면 사용자별로 변경할 수 있습니다. 하지만 네이티브 변경 사항은 새로운 플러그인과 같은 경우 정기적인 빌드 과정을 거칩니다. iOS 빌드를 맥 없이도 필요하다면 Capgo 빌드 __CAPGO_KEEP_0__ Build

Live updates for Capacitor apps

웹-layer 버그가 활성화된 상태에서 앱 스토어 승인까지 며칠 기다리지 않고 Capgo를 통해 패치를 배포하세요. 사용자는 배경에서 업데이트를 받으며 네이티브 변경 사항은 일반적인 검토 경로에 남게 됩니다.

최신 블로그

Capgo은 전문적인 모바일 앱을 만들기 위해 필요한 최고의 통찰력을 제공합니다.