step 19 : hapus loading, tambahkan grayscale upload foto, show foto kalau sudah di foto

This commit is contained in:
sindhu
2025-02-19 01:42:18 +07:00
parent d9a8bf5de4
commit 952934ed67
5 changed files with 117 additions and 28 deletions

View File

@@ -6,7 +6,7 @@
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application
android:label="scanktpflutter"
android:label="Ocr Ktp"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<activity

View File

@@ -5,7 +5,8 @@
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Scanktpflutter</string>
<!-- <string>Scanktpflutter</string> -->
<string>Ocr Ktp</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>

View File

@@ -1,7 +1,6 @@
import '../../model/sex_model.dart';
import '../model/person_ktp_model.dart';
import '../model/edit_person_model.dart';
import 'base_repository.dart';
class ScanRepository extends BaseRepository {

View 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;
}
}

View File

@@ -122,13 +122,21 @@ class ScanScreen extends HookConsumerWidget {
// Rotate gambar setelah cropping
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
capturedImage.value = image;
croppedImage.value = rotatedImage;
// post ke BE
Uint8List bytes = await croppedImage.value!.readAsBytes();
String base64String = base64Encode(bytes);
Uint8List finalBytes = await croppedImage.value!.readAsBytes();
String base64String = base64Encode(finalBytes);
ref.read(uploadScanProvider.notifier).uploadScan(
host: host,
base64File: base64String,
@@ -184,22 +192,6 @@ class ScanScreen extends HookConsumerWidget {
return () {};
}, [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(
appBar: AppBar(
title: Text(
@@ -229,7 +221,7 @@ class ScanScreen extends HookConsumerWidget {
backgroundColor: Colors.black.withOpacity(0.5),
body: Stack(
children: [
if (cameraController.value != null)
if (cameraController.value != null && croppedImage.value == null)
FutureBuilder<void>(
future: initializeControllerFuture.value,
builder: (context, snapshot) {
@@ -240,19 +232,39 @@ class ScanScreen extends HookConsumerWidget {
}
},
),
// bingkai foto
Positioned.fill(
child: CustomPaint(
painter: OverlayPainter(),
// jika sudah ada foto
if (croppedImage.value != null) ...[
Container(
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
if (isLoading.value)
Positioned.fill(
child: Container(
color: Colors.black.withOpacity(0.5),
child: const Center(
child: CircularProgressIndicator(color: Colors.white),
child: CircularProgressIndicator(
color: Colors.white,
),
),
),
),