본문 바로가기
Front-End/Flutter

[Flutter] 09. 카메라

by 삼준 2024. 3. 16.
반응형

카메라는 camera 패키지를 임포트해야 함.

 

추가로,

 

OS별로 다음과 같은 추가 작업을 해주어야 사용이 가능함.

2024.03.16 기준

 

예시 코드는 다음과 같음.

import 'dart:io';
import 'dart:math' as math;
import 'dart:typed_data';

import 'package:camera/camera.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
import 'package:http/http.dart' as http;

import '../main.dart';

late List<CameraDescription> _cameras;

// 카메라 촬영 화면
class SelfCam extends StatefulWidget {

  const SelfCam({super.key});

  @override
  State<SelfCam> createState() => _SelfCamState();
}

class _SelfCamState extends State<SelfCam> {
  late CameraController controller;
  bool cameraInitialized = false;
  bool isPictureCapturing = false;
  double x = 0;
  double y = 0;

  @override
  void initState() {
    super.initState();
    prepareCam();
  }

  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }

  void prepareCam() async {
    _cameras = await availableCameras();
    CameraDescription frontCam = _cameras[0];
    for( var cam in _cameras ) // 전면카메라 찾기
        {
      if( cam.lensDirection == CameraLensDirection.front )
      {
        frontCam = cam;
        break;
      }
    }

    controller = CameraController(frontCam, ResolutionPreset.veryHigh);
    controller.initialize().then((_) {
      if (!mounted) {
        return;
      }
      controller.setFlashMode(FlashMode.off);
      setState(() {
        cameraInitialized = true;
      });
    }).catchError((Object e) {
      if (e is CameraException) {
        switch (e.code) {
          case 'CameraAccessDenied':
            break;
          default:
            break;
        }
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: !cameraInitialized ?
        Center(
          child: Container(
            width: MediaQuery.of(context).size.width,
            decoration: const BoxDecoration(
                image: DecorationImage(
                  image: AssetImage('assets/background_image.png'),
                  fit: BoxFit.cover,
                )
            ),
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Image.asset(
                  'assets/loading_new.gif', // 로딩 이미지 파일 경로
                  width: 200, // 이미지의 너비 설정
                  height: 200,
                ),
                Text(
                  'Loading...',
                  style:  myTextStyle(25.0, fontWeight: FontWeight.w500),),
              ],
            ),
          ),
        ):
        Container(
          decoration: const BoxDecoration(
              image: DecorationImage(
                image: AssetImage('assets/background_image.png'),
                fit: BoxFit.cover,
              )
          ),
          child: Center(
            child:Column(
              children: [
                Padding(
                  padding: const EdgeInsets.only(top: 40),
                  child: Text("※알림※",textAlign: TextAlign.center,style: myTextStyle(24)),
                ),
                Padding(
                  padding: const EdgeInsets.only(bottom: 20),
                  child: Text("캐릭터에 적용될 얼굴 사진을 촬영합니다!",
                      textAlign: TextAlign.center,style: myTextStyle(20, fontWeight: FontWeight.w500)
                  ),
                ),
                Container(
                  height: MediaQuery.of(context).size.height*0.7,
                  margin: const EdgeInsets.fromLTRB(20, 0, 20, 0),
                  // 그림자
                  decoration: BoxDecoration(
                      color: const Color(0xFFFFFDF9),
                      borderRadius: BorderRadius.circular(20),
                      boxShadow: [
                        BoxShadow(
                          color: Colors.black.withOpacity(0.3),
                          spreadRadius: 2,
                          blurRadius: 3,
                          offset: const Offset(0, 1), // 위치 조정
                        )
                      ]
                  ),
                  child: ClipRRect(
                    borderRadius: BorderRadius.circular(20),
                    child: Stack(
                      alignment: Alignment.center,
                      children: [
                        CameraPreview(
                          controller,
                          child: GestureDetector(onTapDown: (TapDownDetails details) {
                            x = details.localPosition.dx;
                            y = details.localPosition.dy;

                            double fullWidth = MediaQuery.of(context).size.width;
                            double cameraHeight = fullWidth * controller.value.aspectRatio;

                            double xp = x / fullWidth;
                            double yp = y / cameraHeight;

                            Offset point = Offset(xp,yp);
                            controller.setFocusPoint(point);
                          },),
                        ),
                        Image.asset("assets/face_frame.png",width: MediaQuery.of(context).size.width*0.8,),
                        const Positioned(
                            bottom: 40,
                            child: Text("틀에 얼굴을 맞춰 찍어주세요!",
                              style: TextStyle(
                                fontSize: 25,
                                color: Colors.black,
                                fontFamily: 'Dovemayo_gothic',
                                fontWeight: FontWeight.w700,
                              ),
                            )
                        ),
                        const Positioned(
                          bottom: 40,
                            child: Text("틀에 얼굴을 맞춰 찍어주세요!",
                              style: TextStyle(
                                fontSize: 25,
                                color: Colors.white,
                                fontFamily: 'Dovemayo_gothic',
                                fontWeight: FontWeight.w500,
                              ),

                            )
                        ),
                      ],
                    ),
                  ),
                ),
                Expanded(
                    flex: 1,
                    child: IconButton(
                        onPressed: !isPictureCapturing ? () async {
                          isPictureCapturing = true;
                          // 경로 생성
                          final path = join(
                              ( await getTemporaryDirectory() ).path,
                              '${DateTime.now()}.png'
                          );
                          // 사진 촬영
                          // 포커스 모드 고정 안하면 STATE_WAITING_FOCUS 뜨면서 엄청 오래걸림
                          controller.setFocusMode(FocusMode.locked);
                          XFile picture = await controller.takePicture();
                          controller.setFocusMode(FocusMode.auto);
                          // 사진 저장
                          picture.saveTo(path);
                          if (!mounted) return;
                          isPictureCapturing = false;
                          // 검사 화면으로 전환
                          Navigator.push(context,
                              MaterialPageRoute(
                                  builder: ( context ) => ChkAndSend( imagePath: path )
                              ),
                          );
                        } : null,
                        icon: Image.asset("assets/photo_capture.png")
                    )
                )
              ],
            ),
          ),
        )
    );
  }
}

참고로 위 코드는 필자가 직접 작성한 코드의 일부로,

 

카메라 부분 외에는 삭제되어있으므로 그대로 복붙할시 절대 작동 안함.

 

공식 문서 : https://pub.dev/packages/camera

 

camera | Flutter package

A Flutter plugin for controlling the camera. Supports previewing the camera feed, capturing images and video, and streaming image buffers to Dart.

pub.dev

 

반응형

'Front-End > Flutter' 카테고리의 다른 글

[Flutter] 11. 드롭다운 메뉴  (0) 2024.03.21
[Flutter] 10. 토스트, 스낵바  (1) 2024.03.16
[Flutter] 08. 시간  (0) 2024.03.16
[Flutter] 07. Row, Column, GridView  (0) 2024.03.16
[Flutter] 06. 버튼, 잉크웰  (0) 2024.03.16

댓글