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.4
visual 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),
),
);