Camera App - GlobalMediaBridge/cosmetic-server GitHub Wiki
์นด๋ฉ๋ผ ์ฑ์ ๋ง๋ค๊ธฐ ์ํด์ flutter๊ฐ ์ ๊ณตํ๋ ์ฌ๋ฌ ํ๋ฌ๊ทธ์ธ์ ์ฌ์ฉํด์ผํ๋ค.
- ์นด๋ฉ๋ผ ์ฅ์น๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํ camera
- ์ด๋ฏธ์ง๋ฅผ ์ ์ฅํ ๊ฒฝ๋ก๋ฅผ ์ฐพ๊ธฐ์ํ path_provider
- ์ด๋ ํ๋ซํผ์์๋ ์ฌ๋ฐ๋ฅผ ๊ฒฝ๋ก๋ฅผ ์ฐพ๊ธฐ์ํ path
๊ฐ ํ๋ฌ๊ทธ์ธ ์ค์น ํ์ด์ง์์ ์๋ง์ ๋ฒ์ ์ pubspec.yamlํ์ผ์ ์์ฑํด์ค๋ค. (2020-02-21 ๊ธฐ์ค)
dependencies:
camera: ^0.5.7+3
path_provider: ^1.6.1
path: ^1.6.4visual studio code์์ ์์ฑ์ค์ด๋ผ๋ฉด ์ ์ฅ์ ๋ฐ๋ก ํ๋ฌ๊ทธ์ธ์ด ์ค์น๋ ๊ฒ์ด๋ค.
์ด ํ ์นด๋ฉ๋ผ๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด์ ๋ช๊ฐ์ง ์ค์ ์ ๋ ํด์ฃผ์ด์ผ ํ๋ค.
ios/Runner/Info.plist ํ์ผ์ <dict> ์์ชฝ์ ์๋ ๋ด์ฉ์ ์ถ๊ฐํด์ค๋ค.
<dict>
<key>NSCameraUsageDescription</key>
<string>Can I use the camera please?</string>
<key>NSMicrophoneUsageDescription</key>
<string>Can I use the mic please?</string>
</dict>android/app/build.gradle ํ์ผ์์ minSdkVersion์ 21๋ก ์์ ํด์ค๋ค.
android {
defaultConfig {
minSdkVersion 21
}
}MaterialApp์ ์ด์ฉํ๊ณ ์ฌ์ง์ดฌ์์ ์ํ TakePictureScreen์ ์ํ๋ฅผ ๊ฐ๋ ์์ ฏ์ผ๋ก ์์ฑํ๋ค. ์นด๋ฉ๋ผ๋ฅผ ์กฐ์ํ ์ ์๋ ์ปจํธ๋กค๋ฌ๊ฐ ํ์ํ๊ธฐ ๋๋ฌธ์ ์ํ ๋ณ๊ฒฝ์ด ๊ฐ๋ฅํ ์์ ฏ์ด ํ์ํ๋ค. visual studio code์์๋ stf๋ฅผ ์
๋ ฅํ๋ฉด ์ํ ๋ณ๊ฒฝ ๊ฐ๋ฅํ ์์ ฏ์ ์ฝ๊ฒ ์์ฑํ ์ ์๋ค.
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
theme: ThemeData.dark(),
home: TakePictureScreen(),
),
);
}
class TakePictureScreen extends StatefulWidget {
@override
_TakePictureScreenState createState() => _TakePictureScreenState();
}
class _TakePictureScreenState extends State<TakePictureScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Take a picture')),
body: Center(child:Text('camera'))
);
}
}
์นด๋ฉ๋ผ๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด์๋ ์ฌ์ฉ๊ฐ๋ฅํ ์นด๋ฉ๋ผ ๋ชฉ๋ก์ ๋ถ๋ฌ์์ผํ๋ค. runApp()ํจ์๋ฅผ ์คํํ๊ธฐ ์ ์ ๋ถ๋ฌ์ค๋ ๊ฒ์ด ์๋ค๋ฉด WidgetsFlutterBinding.ensureInitialized() ํจ์๋ฅผ ์คํํด์ฃผ์ด์ผํ๋ค. ์นด๋ฉ๋ผ ๋ชฉ๋ก์ ๋ถ๋ฌ์ค๋ ํจ์๋ ์๊ฐ์ด ์ค๋๊ฑธ๋ฆฐ๋ค. ์๊ฐ์ด ์ค๋๊ฑธ๋ฆฌ๋ ์์
์ Future ๋ผ๋ ๊ฒ์ผ๋ก ๊ฐ์ธ์ฃผ์ด์ผํ๊ณ ์ด๋ฅผ ๊ธฐ๋ค๋ฆฌ๊ธฐ ์ํด์๋ ํด๋น ํจ์๊ฐ ์คํ๋๋ ํจ์์ async๋ฅผ ์ฐ๊ณ ํด๋น ํจ์ ์์ await์ ์จ์ฃผ๋ฉด ๋๋ค. availableCameras()ํจ์๋ฅผ ํตํด ์ฌ์ฉ๊ฐ๋ฅํ ์นด๋ฉ๋ผ ๋ชฉ๋ก์ ๋ฐ์์ ๊ทธ์ค ์ฒซ๋ฒ์งธ ์นด๋ฉ๋ผ๋ฅผ TakePictureScreen์ ์ ๋ฌํด ์ฃผ๊ฒ ๋ค.
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
final cameras = await availableCameras();
final firstCamera = cameras.first;
runApp(
MaterialApp(
theme: ThemeData.dark(),
home: TakePictureScreen(
camera: firstCamera,
),
),
);
}๊ธฐ์กด์ mainํจ์๋ฅผ ์์ ๊ฐ์ด ๋ณ๊ฒฝํด์ฃผ๋ฉด ๋๋ค. Future๋ฅผ ์ฌ์ฉํ๊ฑฐ๋ ์นด๋ฉ๋ผ๋ฅผ ์ฐ๊ธฐ์ํด์ ํ๋ฌ๊ทธ์ธ๋ค์ ๋ถ๋ฌ์์ผํ๋๋ฐ ์์
์์ ์ฐ์ผ ํ๋ฌ๊ทธ์ธ๋ค์ ๋ฏธ๋ฆฌ ๋ถ๋ฌ์์ฃผ๋๋ก ํ๋ค.
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:camera/camera.dart';
import 'package:path/path.dart' show join;
import 'package:path_provider/path_provider.dart';์นด๋ฉ๋ผ๊ฐ TakePictureScreen๋ก ์ ๋ฌ๋์๊ธฐ ๋๋ฌธ์ ๊ทธ๊ฑธ ๋ฐ์์ค๋ ์ฝ๋๊ฐ ํ์ํ๋ค. TakePictureScreen ํด๋์ค ์์ ์์ฑํด์ค๋ค.
final CameraDescription camera;
const TakePictureScreen({
Key key,
@required this.camera,
}) : super(key: key);์ด์ ์ํ๋ฅผ ๊ฐ์ง ์ ์๋_TakePictureScreenState ํด๋์ค์์ ์นด๋ฉ๋ผ ์ปจํธ๋กค๋ฌ๋ฅผ ์์ฑํด์ ์ค์ ํด์ฃผ๋ฉด ๋๋ค. initState์์ ์นด๋ฉ๋ผ ์ปจํธ๋กค๋ฌ๋ฅผ ๋ง๋ค์ด์ฃผ๋๋ฐ ์๊น ๋ฐ์์จ ์นด๋ฉ๋ผ๋ฅผ widget.camera๋ก ์ ๋ฌํด์ฃผ๋ฉด๋๋ค. ์ถ๊ฐ์ ์ผ๋ก ํด์๋๋ฅผ medium์ผ๋ก ์ค์ ํด์ฃผ์๋ค. ๊ทธ๋ฆฌ๊ณ ์ปจํธ๋กค๋ฌ๋ฅผ ์์ํด์ Future์์ ๋ด์๋์๋ค. ์ด ์ญ์ ์๊ฐ์ด ์ค๋๊ฑธ๋ฆฌ๊ธฐ ๋๋ฌธ์ ์ผ๋จ _initializeControllerFutre์์ ๋ด์๋๊ฒ ๋ค. async, awaitํค์๋๋ฅผ ์ฌ์ฉํ์ง ์์๊ธฐ ๋๋ฌธ์ ์์ง ๊ธฐ๋ค๋ฆฌ์ง ์๋๋ค. ๊ทธ๋ฆฌ๊ณ ํ๋ฉด์ด ์ฌ๋ผ์ง๋ ๊ฒฝ์ฐ ์ปจํธ๋กค๋ฌ๋ฅผ ์ง์์ฃผ๊ธฐ ์ํด dispose๋ ์์ฑํด์ค๋ค.
CameraController _controller;
Future<void> _initializeControllerFuture;
@override
void initState() {
super.initState();
_controller = CameraController(
widget.camera,
ResolutionPreset.medium,
);
_initializeControllerFuture = _controller.initialize();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}ํ๋ฉด์ ๋ํ๋ด์ฃผ๋ build์์ ์ปจํธ๋กค๋ฌ์ ์์์ ๊ธฐ๋ค๋ฆฐ ํ ์์ ฏ์ ์์ฑํ๊ธฐ์ํด์ FutureBuilder๋ฅผ ์ฌ์ฉํ๋ค. ๊ธฐ๋ค๋ฆด ๊ฒ์ future๋ก ์ ๋ฌํ๊ณ ๊ธฐ๋ค๋ฆผ์ด ๋๋ ๋ค ๋ง๋ค ์์ ฏ์ builder๋ก ์ ๋ฌํด์ฃผ๋ฉด๋๋ค.
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Take a picture')),
body: FutureBuilder<void>(
future: _initializeControllerFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return CameraPreview(_controller);
} else {
return Center(child: CircularProgressIndicator());
}
},
)
);
}์ ์ฝ๋๋ ๋ค์๊ณผ ๊ฐ๋ค.
-
_initializeControllerFuture๋ฅผ ๊ธฐ๋ค๋ ค์ ์๋ฃ๊ฐ ๋๋ฉด ๊ทธ ๊ฐ์builder์snapshot์ผ๋ก ์ ๋ฌํ๋ค. -
snapshot์ ์ฐ๊ฒฐ์ํ๊ฐ done์ธ๊ฒฝ์ฐCameraPreview๋ฅผ ๋ณด์ฌ์ค๋ค. - ์ฐ๊ฒฐ์ํ๊ฐ done์ด ์๋๋ฉด ์ค์ฌ์
CircularProgressIndicator๋ฅผ ๋ณด์ฌ์ค๋ค.CameraPreview๋ ์นด๋ฉ๋ผ๋ฅผ ์ฐ๊ณ ์์ ๋ ์นด๋ฉ๋ผ๊ฐ ๋ณด๊ณ ์๋ ํ๋ฉด์ ์ฌ์ฉ์์๊ฒ ๋ฏธ๋ฆฌ ๋ณด์ฌ์ฃผ๊ธฐ ์ํ ์์ ฏ์ด๋ค. ํด๋น ์์ ฏ์๋ ์นด๋ฉ๋ผ ์ปจํธ๋กค๋ฌ๊ฐ ํ์ํ๋ค.
์ด๋ฏธ์ง ์ดฌ์์ ์ํด ์ฐ์ ์ดฌ์๋ฒํผ์ ๋ง๋ค์ด์ค๋ค. MaterialApp์ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ ๊ฐ๋จํ๊ฒ FloatingActionButton์ ์ด์ฉํ๋๋ก ํ๋ค. Scaffold์์ ๋ง๋ค์ด์ฃผ๋๋กํ๋ค.
Scaffold(
floatingActionButton: FloatingActionButton(
child: Icon(Icons.camera_alt),
onPressed: () { },
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
);MaterialApp์์ ์ ๊ณตํ๋ ์นด๋ฉ๋ผ ์์ด์ฝ์ ์ฌ์ฉํ๊ณ ๋ฒํผ์ ์์น๋ฅผ ์ค์์ผ๋ก ์ฎ๊ฒจ์ฃผ์๋ค. ๋ฒํผ์ ๋๋ ์ ๋ ์คํ๋ onPressed ๋ถ๋ถ์์ ์ด๋ฏธ์ง๋ฅผ ์์๋ก ์ ์ฅํ๋๋ก ํ๋ค. ์ฌ์ง์ ์ฐ๊ณ ์ ์ฅํ๋ ์ผ์ ์ค๋๊ฑธ๋ฆฌ๋ ์ผ์ด๊ธฐ ๋๋ฌธ์ async์ await์ ์ด์ฉํด ๊ธฐ๋ค๋ ค์ฃผ๋๋ก ํ๋ค. ๋ํ ์ค๋ฅ๊ฐ ์ฝ๊ฒ ๋ฐ์ํ ์ ์๊ธฐ ๋๋ฌธ์ try์์์ ์์ฑํ๊ณ ์ค๋ฅ๊ฐ ์๊ธฐ๋ฉด catchํ๋๋ก ํ๋ค.
onPressed: () {
try {
await _initializeControllerFuture;
final path = join(
(await getTemporaryDirectory()).path,
'${DateTime.now()}.png',
);
await _controller.takePicture(path);
} catch (e) {
// If an error occurs, log the error to the console.
print(e);
}
},์ ์ฝ๋๋ ๋ค์๊ณผ ๊ฐ๋ค.
- ์นด๋ฉ๋ผ ์ปจํธ๋กค๋ฌ๋ฅผ ์คํํด์ค๋ค.
- ์์๋ก ์ ์ฅํ ๊ณต๊ฐ์ ์ป์ด์ ํ์ฌ ์๊ฐ์ ์ ๋ชฉ์ผ๋ก png ํ์ผ์ ๋ง๋ค์ด์ path์ ๊ธฐ์ต์ํจ๋ค.
- ์ปจํธ๋กค๋ฌ๋ก
takePictureํจ์๋ฅผ ์คํ์์ผ ์ดฌ์ํ๊ณ ์ป์ ์ด๋ฏธ์ง๋ฅผ path์ ์์น์ ์ ์ฅํ๋ค. - ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ฉด ์ถ๋ ฅํ๋ค.
path์์น์ ์ ์ฅ๋ ์ด๋ฏธ์ง๋ฅผ ๋ณด์ฌ์ฃผ๊ธฐ ์ํด ์๋ก์ด ํ์ด์ง๋ฅผ ๋ง๋ ๋ค. ๋จ์ํ ๋ณด์ฌ์ฃผ๊ธฐ๋ง ํ๋ฉด ๋๊ธฐ ๋๋ฌธ์ ์ํ๊ฐ ์๋ ์์ ฏ์ผ๋ก ๋ง๋ค์ด์ค๋ค. visual studio code๋ฅผ ์ฌ์ฉํ๋ค๋ฉด stl ํค์๋๋ก ์ฝ๊ฒ ์์ฑํ ์ ์๋ค.
class DisplayPictureScreen extends StatelessWidget {
final String imagePath;
const DisplayPictureScreen({Key key, this.imagePath}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Display the Picture')),
body: Image.file(File(imagePath)),
);
}
}imagePath๋ผ๋ ๊ณณ์ผ๋ก ํ์ผ ์์น๋ฅผ ๋๊ฒจ๋ฐ์์ ๋ณด์ฌ์ฃผ๋ ํ๋ฉด์ด๋ค. ์ด์ ์ดฌ์ํด์ ์ด๋ฏธ์ง ์ ์ฅ์ด ๋๋๋ฉด ์๋ก์ด ํ์ด์ง๋ฅผ ๋ณด์ฌ์ฃผ๊ธฐ ์ํด onPressed์ takePictureํจ์ ์๋์ ์ฝ๋๋ฅผ ์์ฑํด์ค๋ค.
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DisplayPictureScreen(imagePath: path),
),
);
