step 19 : hapus loading, tambahkan grayscale upload foto, show foto kalau sudah di foto
This commit is contained in:
@@ -6,7 +6,7 @@
|
|||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:label="scanktpflutter"
|
android:label="Ocr Ktp"
|
||||||
android:name="${applicationName}"
|
android:name="${applicationName}"
|
||||||
android:icon="@mipmap/ic_launcher">
|
android:icon="@mipmap/ic_launcher">
|
||||||
<activity
|
<activity
|
||||||
|
|||||||
@@ -5,7 +5,8 @@
|
|||||||
<key>CFBundleDevelopmentRegion</key>
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||||
<key>CFBundleDisplayName</key>
|
<key>CFBundleDisplayName</key>
|
||||||
<string>Scanktpflutter</string>
|
<!-- <string>Scanktpflutter</string> -->
|
||||||
|
<string>Ocr Ktp</string>
|
||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
<string>$(EXECUTABLE_NAME)</string>
|
<string>$(EXECUTABLE_NAME)</string>
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import '../../model/sex_model.dart';
|
import '../../model/sex_model.dart';
|
||||||
|
|
||||||
import '../model/person_ktp_model.dart';
|
import '../model/person_ktp_model.dart';
|
||||||
import '../model/edit_person_model.dart';
|
|
||||||
import 'base_repository.dart';
|
import 'base_repository.dart';
|
||||||
|
|
||||||
class ScanRepository extends BaseRepository {
|
class ScanRepository extends BaseRepository {
|
||||||
|
|||||||
77
lib/screen/scan/fungsiold.txt
Normal file
77
lib/screen/scan/fungsiold.txt
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
Future<File> rotateAndCropImage(File imageFile) async {
|
||||||
|
Uint8List imageBytes = await imageFile.readAsBytes();
|
||||||
|
img.Image? original = img.decodeImage(imageBytes);
|
||||||
|
if (original == null) return imageFile;
|
||||||
|
|
||||||
|
img.Image rotated = img.bakeOrientation(original);
|
||||||
|
|
||||||
|
int width = rotated.width;
|
||||||
|
int height = rotated.height;
|
||||||
|
bool isPortrait = height > width;
|
||||||
|
|
||||||
|
int cropWidth, cropHeight;
|
||||||
|
|
||||||
|
if (isPortrait) {
|
||||||
|
cropHeight = (height * 0.7).toInt();
|
||||||
|
cropWidth = (cropHeight ~/ 1.59).toInt();
|
||||||
|
} else {
|
||||||
|
cropWidth = (width * 0.7).toInt();
|
||||||
|
cropHeight = (cropWidth ~/ 1.59).toInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
int left = ((width - cropWidth) ~/ 2).toInt();
|
||||||
|
int top = ((height - cropHeight) ~/ 2).toInt();
|
||||||
|
|
||||||
|
img.Image cropped = img.copyCrop(rotated,
|
||||||
|
x: left, y: top, width: cropWidth, height: cropHeight);
|
||||||
|
|
||||||
|
File croppedFile = File('${imageFile.path}_cropped.jpg');
|
||||||
|
await croppedFile.writeAsBytes(img.encodeJpg(cropped));
|
||||||
|
|
||||||
|
return croppedFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<File> rotateImage(File imageFile) async {
|
||||||
|
Uint8List bytes = await imageFile.readAsBytes();
|
||||||
|
img.Image? image = img.decodeImage(bytes);
|
||||||
|
|
||||||
|
if (image == null) return imageFile;
|
||||||
|
|
||||||
|
img.Image rotated = img.copyRotate(image, angle: -90);
|
||||||
|
|
||||||
|
File rotatedFile = File('${imageFile.path}_rotated.jpg');
|
||||||
|
await rotatedFile.writeAsBytes(img.encodeJpg(rotated));
|
||||||
|
|
||||||
|
return rotatedFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> captureAndCropImage() async {
|
||||||
|
try {
|
||||||
|
isLoading.value = true;
|
||||||
|
await initializeControllerFuture.value;
|
||||||
|
|
||||||
|
// Ambil gambar dari kamera
|
||||||
|
final image = await cameraController.value!.takePicture();
|
||||||
|
File cropped = await rotateAndCropImage(File(image.path));
|
||||||
|
|
||||||
|
// Rotate gambar setelah cropping
|
||||||
|
File rotatedImage = await rotateImage(cropped);
|
||||||
|
|
||||||
|
// Simpan hasil yang sudah di-crop dan di-rotate
|
||||||
|
capturedImage.value = image;
|
||||||
|
croppedImage.value = rotatedImage;
|
||||||
|
|
||||||
|
// post ke BE
|
||||||
|
Uint8List bytes = await croppedImage.value!.readAsBytes();
|
||||||
|
String base64String = base64Encode(bytes);
|
||||||
|
ref.read(uploadScanProvider.notifier).uploadScan(
|
||||||
|
host: host,
|
||||||
|
base64File: base64String,
|
||||||
|
userId: userId,
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
print("Error capturing image: $e");
|
||||||
|
} finally {
|
||||||
|
isLoading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -122,13 +122,21 @@ class ScanScreen extends HookConsumerWidget {
|
|||||||
// Rotate gambar setelah cropping
|
// Rotate gambar setelah cropping
|
||||||
File rotatedImage = await rotateImage(cropped);
|
File rotatedImage = await rotateImage(cropped);
|
||||||
|
|
||||||
|
// Convert to grayscale
|
||||||
|
Uint8List bytes = await rotatedImage.readAsBytes();
|
||||||
|
img.Image? coloredImage = img.decodeImage(bytes);
|
||||||
|
if (coloredImage != null) {
|
||||||
|
img.Image grayscaleImage = img.grayscale(coloredImage);
|
||||||
|
rotatedImage.writeAsBytesSync(img.encodeJpg(grayscaleImage));
|
||||||
|
}
|
||||||
|
|
||||||
// Simpan hasil yang sudah di-crop dan di-rotate
|
// Simpan hasil yang sudah di-crop dan di-rotate
|
||||||
capturedImage.value = image;
|
capturedImage.value = image;
|
||||||
croppedImage.value = rotatedImage;
|
croppedImage.value = rotatedImage;
|
||||||
|
|
||||||
// post ke BE
|
// post ke BE
|
||||||
Uint8List bytes = await croppedImage.value!.readAsBytes();
|
Uint8List finalBytes = await croppedImage.value!.readAsBytes();
|
||||||
String base64String = base64Encode(bytes);
|
String base64String = base64Encode(finalBytes);
|
||||||
ref.read(uploadScanProvider.notifier).uploadScan(
|
ref.read(uploadScanProvider.notifier).uploadScan(
|
||||||
host: host,
|
host: host,
|
||||||
base64File: base64String,
|
base64File: base64String,
|
||||||
@@ -184,22 +192,6 @@ class ScanScreen extends HookConsumerWidget {
|
|||||||
return () {};
|
return () {};
|
||||||
}, [isLoadingUpload.value]);
|
}, [isLoadingUpload.value]);
|
||||||
|
|
||||||
// loading proses image useEffect
|
|
||||||
useEffect(() {
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
||||||
if (isLoading.value == true) {
|
|
||||||
snackbarWidget(
|
|
||||||
context,
|
|
||||||
'Sedang Proses Gambar...',
|
|
||||||
snackbarType.warning,
|
|
||||||
// Duration(seconds: 5),
|
|
||||||
Duration(days: 1),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return () {};
|
|
||||||
}, [isLoading.value]);
|
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(
|
title: Text(
|
||||||
@@ -229,7 +221,7 @@ class ScanScreen extends HookConsumerWidget {
|
|||||||
backgroundColor: Colors.black.withOpacity(0.5),
|
backgroundColor: Colors.black.withOpacity(0.5),
|
||||||
body: Stack(
|
body: Stack(
|
||||||
children: [
|
children: [
|
||||||
if (cameraController.value != null)
|
if (cameraController.value != null && croppedImage.value == null)
|
||||||
FutureBuilder<void>(
|
FutureBuilder<void>(
|
||||||
future: initializeControllerFuture.value,
|
future: initializeControllerFuture.value,
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
@@ -240,19 +232,39 @@ class ScanScreen extends HookConsumerWidget {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
// bingkai foto
|
// jika sudah ada foto
|
||||||
Positioned.fill(
|
if (croppedImage.value != null) ...[
|
||||||
child: CustomPaint(
|
Container(
|
||||||
painter: OverlayPainter(),
|
width: double.infinity,
|
||||||
|
height: 300,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
),
|
||||||
|
child: ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
child: Image.file(
|
||||||
|
croppedImage.value!,
|
||||||
|
fit: BoxFit.contain,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
] else ...[
|
||||||
|
// bingkai foto
|
||||||
|
Positioned.fill(
|
||||||
|
child: CustomPaint(
|
||||||
|
painter: OverlayPainter(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
// loading
|
// loading
|
||||||
if (isLoading.value)
|
if (isLoading.value)
|
||||||
Positioned.fill(
|
Positioned.fill(
|
||||||
child: Container(
|
child: Container(
|
||||||
color: Colors.black.withOpacity(0.5),
|
color: Colors.black.withOpacity(0.5),
|
||||||
child: const Center(
|
child: const Center(
|
||||||
child: CircularProgressIndicator(color: Colors.white),
|
child: CircularProgressIndicator(
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
Reference in New Issue
Block a user