diff --git a/config.properties b/config.properties index 1726c90..c4abeaa 100644 --- a/config.properties +++ b/config.properties @@ -1,22 +1,26 @@ -#Thu Jan 30 14:56:00 WIB 2025 +#Thu Feb 13 11:48:36 WIB 2025 AudioPhase1=C\:\\Users\\rdkar\\OneDrive\\Documents\\IntelliJ Project\\ErhaCam\\audio\\phase1.mp3 AudioPhase2=C\:\\Users\\rdkar\\OneDrive\\Documents\\IntelliJ Project\\ErhaCam\\audio\\phase2.mp3 AudioPhase3=C\:\\Users\\rdkar\\OneDrive\\Documents\\IntelliJ Project\\ErhaCam\\audio\\phase3.mp3 AudioPhase4=C\:\\Users\\rdkar\\OneDrive\\Documents\\IntelliJ Project\\ErhaCam\\audio\\phase4.mp3 AudioPhase5=C\:\\Users\\rdkar\\OneDrive\\Documents\\IntelliJ Project\\ErhaCam\\audio\\phase5.mp3 -CameraCenter=OBSBOT Meet 2 StreamCamera -CameraConfigCenter={"Brightness"\:0.0,"Contrast"\:32.0,"Saturation"\:64.0,"Hue"\:0.0,"Gain"\:1.0,"Exposure"\:157.0,"Sharpness"\:3.0,"Gamma"\:100.0,"AutoExposure"\:true,"AutoFocus"\:true,"AutoWhiteBalance"\:true} -CameraConfigLeft45={"Brightness"\:37.58730158730158,"Contrast"\:32.0,"Saturation"\:64.0,"Hue"\:0.0,"Gain"\:1.0,"Exposure"\:157.0,"Sharpness"\:3.0,"Gamma"\:100.0,"AutoExposure"\:true,"AutoFocus"\:true,"AutoWhiteBalance"\:true} -CameraConfigLeft90={"Brightness"\:0.0,"Contrast"\:32.0,"Saturation"\:64.0,"Hue"\:0.0,"Gain"\:1.0,"Exposure"\:157.0,"Sharpness"\:3.0,"Gamma"\:100.0,"AutoExposure"\:true,"AutoFocus"\:true,"AutoWhiteBalance"\:true} -CameraConfigRight45={"Brightness"\:0.0,"Contrast"\:32.0,"Saturation"\:64.0,"Hue"\:0.0,"Gain"\:1.0,"Exposure"\:157.0,"Sharpness"\:3.0,"Gamma"\:100.0,"AutoExposure"\:true,"AutoFocus"\:true,"AutoWhiteBalance"\:true} -CameraConfigRight90={"Brightness"\:0.0,"Contrast"\:32.0,"Saturation"\:64.0,"Hue"\:0.0,"Gain"\:1.0,"Exposure"\:157.0,"Sharpness"\:3.0,"Gamma"\:100.0,"AutoExposure"\:true,"AutoFocus"\:true,"AutoWhiteBalance"\:true} -CameraLeft45=OBSBOT Meet 2 StreamCamera -CameraLeft90=OBSBOT Meet 2 StreamCamera -CameraRight45=OBSBOT Meet 2 StreamCamera -CameraRight90=OBSBOT Meet 2 StreamCamera +CameraCenter= +CameraConfigCenter={"Brightness"\:0.0,"Contrast"\:0.0,"Saturation"\:0.0,"Hue"\:0.0,"Gain"\:1.0,"Exposure"\:1.0,"Sharpness"\:0.0,"Gamma"\:0.0,"AutoExposure"\:true,"AutoFocus"\:true,"AutoWhiteBalance"\:true} +CameraConfigLeft45={"Brightness"\:0.0,"Contrast"\:0.0,"Saturation"\:0.0,"Hue"\:0.0,"Gain"\:1.0,"Exposure"\:1.0,"Sharpness"\:0.0,"Gamma"\:0.0,"AutoExposure"\:true,"AutoFocus"\:true,"AutoWhiteBalance"\:true} +CameraConfigLeft90={"Brightness"\:0.0,"Contrast"\:0.0,"Saturation"\:0.0,"Hue"\:0.0,"Gain"\:1.0,"Exposure"\:1.0,"Sharpness"\:0.0,"Gamma"\:0.0,"AutoExposure"\:true,"AutoFocus"\:true,"AutoWhiteBalance"\:true} +CameraConfigRight45={"Brightness"\:0.0,"Contrast"\:0.0,"Saturation"\:0.0,"Hue"\:0.0,"Gain"\:1.0,"Exposure"\:1.0,"Sharpness"\:0.0,"Gamma"\:0.0,"AutoExposure"\:true,"AutoFocus"\:true,"AutoWhiteBalance"\:true} +CameraConfigRight90={"Brightness"\:0.0,"Contrast"\:0.0,"Saturation"\:0.0,"Hue"\:0.0,"Gain"\:1.0,"Exposure"\:1.0,"Sharpness"\:0.0,"Gamma"\:0.0,"AutoExposure"\:true,"AutoFocus"\:true,"AutoWhiteBalance"\:true} +CameraLeft45= +CameraLeft90= +CameraRight45= +CameraRight90= FTPHost=192.168.10.2 FTPPass=password FTPPath=/ FTPPort=21 FTPUser=user -PhotoDirectory=C\:\\Users\\rdkar\\OneDrive\\Desktop\\photoresult +PhotoDirectory=C\:\\Users\\rdkar\\OneDrive\\Documents\\IntelliJ Project\\ErhaCam +cascadeMaxSize=500 +cascadeMinNeighbors=3 +cascadeMinSize=250 +cascadeScaleFactor=1.1 diff --git a/countdown321.wav b/countdown321.wav new file mode 100644 index 0000000..2e0f9a3 Binary files /dev/null and b/countdown321.wav differ diff --git a/libs/win32-x86-64/SecureDongleJ.dll b/libs/win32-x86-64/SecureDongleJ.dll new file mode 100644 index 0000000..5f85967 Binary files /dev/null and b/libs/win32-x86-64/SecureDongleJ.dll differ diff --git a/libs/win32-x86/SecureDongleJ.dll b/libs/win32-x86/SecureDongleJ.dll new file mode 100644 index 0000000..70871f6 Binary files /dev/null and b/libs/win32-x86/SecureDongleJ.dll differ diff --git a/out/artifacts/ErhaCam_jar/ErhaCam.jar b/out/artifacts/ErhaCam_jar/ErhaCam.jar index 77b1997..9de235f 100644 Binary files a/out/artifacts/ErhaCam_jar/ErhaCam.jar and b/out/artifacts/ErhaCam_jar/ErhaCam.jar differ diff --git a/pengambilan_berhasil.wav b/pengambilan_berhasil.wav new file mode 100644 index 0000000..c56c170 Binary files /dev/null and b/pengambilan_berhasil.wav differ diff --git a/pengambilan_gagal.wav b/pengambilan_gagal.wav new file mode 100644 index 0000000..4afa67b Binary files /dev/null and b/pengambilan_gagal.wav differ diff --git a/posisikan_wajah.wav b/posisikan_wajah.wav new file mode 100644 index 0000000..18ab44d Binary files /dev/null and b/posisikan_wajah.wav differ diff --git a/scan_barcode.wav b/scan_barcode.wav new file mode 100644 index 0000000..0d9c7f3 Binary files /dev/null and b/scan_barcode.wav differ diff --git a/src/main/java/BASS/AudioPlayer.java b/src/main/java/BASS/AudioPlayer.java index 58909af..c41dc3a 100644 --- a/src/main/java/BASS/AudioPlayer.java +++ b/src/main/java/BASS/AudioPlayer.java @@ -105,7 +105,7 @@ public class AudioPlayer { * @return true if success, false if failed */ public boolean PlayFile(final String filename, final PlaybackStatus playbackstatus){ - if (inited){ + if (inited && filename!=null && !filename.isEmpty()){ int filehandle = bass.BASS_StreamCreateFile(false, filename, 0, 0, 0); if (filehandle!=0){ if (bass.BASS_ChannelStart(filehandle)){ diff --git a/src/main/java/Config/SomeCodes.java b/src/main/java/Config/SomeCodes.java index b9876bf..5d2bd88 100644 --- a/src/main/java/Config/SomeCodes.java +++ b/src/main/java/Config/SomeCodes.java @@ -4,6 +4,7 @@ package Config; import com.google.gson.Gson; import com.google.zxing.MultiFormatReader; import javafx.embed.swing.SwingFXUtils; +import javafx.scene.control.Alert; import javafx.scene.image.Image; import org.bytedeco.javacv.Java2DFrameConverter; import org.bytedeco.javacv.OpenCVFrameConverter; @@ -129,13 +130,9 @@ public class SomeCodes { } } - public static Rect ScaleRect(Rect original, double scaleX, double scaleY){ - if (original!=null){ - return new Rect((int)(original.x()*scaleX), (int)(original.y()*scaleY), - (int)(original.width()*scaleX), (int)(original.height()*scaleY)); - } - return null; - } + + + /** * Make thumbfile from source jpg file @@ -175,6 +172,11 @@ public class SomeCodes { return x.format(dtf); } + /** + * Extract resource file to current directory + * @param filename resource file name + * @return extracted file path if success, or null if failed + */ public static String ExtractResource(String filename){ try{ File destination = new File(currentDirectory, filename); @@ -193,6 +195,11 @@ public class SomeCodes { return null; } + /** + * Check if path is valid directory + * @param path directory path + * @return true if valid directory, false if not valid directory + */ public static boolean ValidDirectory(String path){ if (ValidString(path)){ File ff = new File(path); @@ -201,10 +208,20 @@ public class SomeCodes { return false; } + /** + * Check if port number is valid + * @param port port number + * @return true if valid port number, false if not valid port number + */ public static boolean ValidPortNumber(int port){ return port>0 && port<65536; } + /** + * Convert string to integer + * @param x string + * @return integer value if success, or 0 if failed + */ public static int toInt(String x){ try { return Integer.parseInt(x); @@ -213,6 +230,11 @@ public class SomeCodes { } } + /** + * Check if string is valid IPV4 address + * @param ipaddress IPV4 address + * @return true if valid IPV4 address, false if not valid IPV4 address + */ public static boolean ValidIPV4(String ipaddress){ if (ValidString(ipaddress)){ try{ @@ -228,6 +250,11 @@ public class SomeCodes { return false; } + /** + * Check if string is valid IPV6 address + * @param ipaddress IPV6 address + * @return true if valid IPV6 address, false if not valid IPV6 address + */ public static boolean ValidIPV6(String ipaddress){ if (ValidString(ipaddress)){ try{ @@ -243,6 +270,11 @@ public class SomeCodes { return false; } + /** + * Get file name from file path + * @param filepath file path + * @return file name if success, or empty string if failed + */ public static String GetFileName(String filepath){ if (ValidString(filepath)){ File ff = new File(filepath); @@ -253,6 +285,11 @@ public class SomeCodes { return ""; } + /** + * Check if string is valid file + * @param filename file name + * @return true if valid file, false if not valid file + */ public static boolean ValidFile(String filename){ if (ValidString(filename)){ File ff = new File(filename); @@ -261,6 +298,102 @@ public class SomeCodes { return false; } + /** + * Read file as byte array + * @param filename file name + * @return byte array if success, or null if failed + */ + public static byte[] ReadFile(String filename){ + if (ValidFile(filename)){ + try{ + return Files.readAllBytes(Path.of(filename)); + } catch (Exception e){ + Logger.error("Error reading file: "+filename+", Msg : "+e.getMessage()); + } + } + return null; + } + + + + /** + * Resize Rect + * @param original original Rect + * @param scaleX scale factor + * @param scaleY scale factor + * @param Xoffset X offset, positive value to increase width, negative value to decrease width + * @param Yoffset Y offset, positive value to increase height, negative value to decrease height + * @return resized Rect if success, or null if failed + */ + public static Rect ResizeRect(Rect original, double scaleX, double scaleY, int Xoffset, int Yoffset){ + if (original!=null){ + int newX = (int)(original.x()*scaleX); + newX -= Xoffset; + if (newX<0) newX = 0; + int newY = (int)(original.y()*scaleY); + newY -= Yoffset; + if (newY<0) newY = 0; + int newWidth = (int)(original.width()*scaleX); + newWidth += Xoffset*2; + int newHeight = (int)(original.height()*scaleX); + newHeight += Yoffset*2; + return new Rect(newX, newY, newWidth, newHeight); + } + return null; + } + + public static UMat CropUMat(UMat source, Rect ROI){ + if (source!=null && !source.empty() && ValidROI(ROI)){ + int x = ROI.x(); + int y = ROI.y(); + int width = ROI.width(); + int height = ROI.height(); + + if (x>=0 && y>=0 && width>0 && height>0){ + if (x+width>source.cols()) width = source.cols()-x; + if (y+height>source.rows()) height = source.rows()-y; + if (width>0 && height>0){ + Rect crop = new Rect(x, y, width, height); + return new UMat(source, crop); + } + } + } + return null; + } + + /** + * Concatenate byte arrays + * @param args byte arrays + * @return concatenated byte array if success, or null if failed + */ + public static byte[] Concat(byte[]... args){ + if (args!=null && args.length>0){ + int total = 0; + for(byte[] x : args){ + if (x!=null && x.length>0){ + total += x.length; + } + } + if (total>0){ + byte[] result = new byte[total]; + int offset = 0; + for(byte[] x : args){ + if (x!=null && x.length>0){ + System.arraycopy(x, 0, result, offset, x.length); + offset += x.length; + } + } + return result; + } + } + return null; + } + + /** + * Check if string is valid + * @param x string + * @return true if valid, false if not valid + */ public static boolean ValidString(String x){ if (x!=null){ return !x.isEmpty(); @@ -268,6 +401,10 @@ public class SomeCodes { return false; } + /** + * Open picture in default viewer + * @param filename picture file name + */ public static void OpenPictureInDefaultViewer(String filename){ try{ File ff = new File(filename); @@ -299,6 +436,11 @@ public class SomeCodes { } + /** + * Make array from string arguments + * @param args string arguments + * @return array of strings if success, or empty array if failed + */ public static String[] MakeArray(String... args){ if (args!=null && args.length>0){ List ll = new ArrayList<>(); @@ -310,14 +452,28 @@ public class SomeCodes { return new String[0]; } + public static boolean ValidBarCode(String value){ + if (value!=null && value.length()==10){ + boolean valid = true; + for(int i=0; i0){ - if (ROI.height()>0){ - return true; + if (ROI.x()>=0){ + if (ROI.y()>=0){ + if (ROI.width()>0){ + if (ROI.height()>0){ + return true; + } + } } } } return false; } + /** + * Check if Region of Interest is inside UMat + * @param ROI Region of Interest + * @param mat UMat + * @return true if inside, false if not inside + */ public static boolean ROIInsideUMat(Rect ROI, UMat mat){ if (ValidROI(ROI)){ if (mat!=null){ @@ -351,6 +522,12 @@ public class SomeCodes { return false; } + /** + * Check if Region of Interest 1 is same with Region of Interest 2 + * @param ROI1 Region of Interest 1 + * @param ROI2 Region of Interest 2 + * @return true if same, false if not same + */ public static boolean IsSameROI(Rect ROI1, Rect ROI2){ if (ValidROI(ROI1) && ValidROI(ROI2)){ return ROI1.x()==ROI2.x() && ROI1.y()==ROI2.y() && @@ -359,6 +536,12 @@ public class SomeCodes { return false; } + /** + * Check if Rect 1 is inside Rect 2 + * @param smaller Rect 1 + * @param bigger Rect 2 + * @return true if inside, false if not inside + */ public static boolean IsInsideRect(Rect smaller, Rect bigger){ if (smaller!=null && bigger!=null){ return smaller.x()>=bigger.x() && smaller.y()>=bigger.y() && @@ -378,12 +561,30 @@ public class SomeCodes { if (!ff.isDirectory()){ try{ Files.createDirectories(ff.toPath()); - System.out.println("Directory created: "+path); + Logger.info("Directory created: "+path); } catch (Exception e){ - System.out.println("Error creating directory: "+path+", Msg : "+e.getMessage()); + Logger.info("Error creating directory: "+path+", Msg : "+e.getMessage()); } - } else System.out.println("Directory exists: "+path); + } else Logger.info("Directory exists: "+path); + } + + + } + + public static short ToShort(String x){ + try{ + return Short.parseShort(x); + } catch (Exception e){ + return 0; } } + public static void ShowAlert(Alert.AlertType type, String title, String header, String content){ + Alert alert = new Alert(type); + alert.setTitle(title); + alert.setHeaderText(header); + alert.setContentText(content); + alert.showAndWait(); + } + } diff --git a/src/main/java/Database/PhotoReviewClass.java b/src/main/java/Database/PhotoReviewClass.java index 17ef3a1..0f610fe 100644 --- a/src/main/java/Database/PhotoReviewClass.java +++ b/src/main/java/Database/PhotoReviewClass.java @@ -10,10 +10,25 @@ public class PhotoReviewClass { private String DateTime; private String Prefix; private String FileLeft90; + private String CompressedLeft90; + private String CroppedLeft90; + private String CompressedCropLeft90; private String FileLeft45; + private String CompressedLeft45; + private String CroppedLeft45; + private String CompressedCropLeft45; private String FileCenter; + private String CompressedCenter; + private String CroppedCenter; + private String CompressedCropCenter; private String FileRight45; + private String CompressedRight45; + private String CroppedRight45; + private String CompressedCropRight45; private String FileRight90; + private String CompressedRight90; + private String CroppedRight90; + private String CompressedCropRight90; private String ThumbLeft90; private String ThumbLeft45; private String ThumbCenter; @@ -53,15 +68,43 @@ public class PhotoReviewClass { } /** - * Get all files that are not null + * Get all Full Resolution files that are not null * @return array of files */ - public String[] files(){ + public String[] fullres(){ return MakeArray(FileLeft90, FileLeft45, FileCenter, FileRight45, FileRight90); } + /** + * Get all Thumbnail files that are not null + * @return array of files + */ public String[] thumbnails(){ return MakeArray(ThumbLeft90, ThumbLeft45, ThumbCenter, ThumbRight45, ThumbRight90); } + /** + * Get all Compressed files that are not null + * @return array of files + */ + public String[] compressed(){ + return MakeArray(CompressedLeft90, CompressedLeft45, CompressedCenter, CompressedRight45, CompressedRight90); + } + + /** + * Get all Cropped full resolution files that are not null + * @return array of files + */ + public String[] cropped(){ + return MakeArray(CroppedLeft90, CroppedLeft45, CroppedCenter, CroppedRight45, CroppedRight90); + } + + /** + * Get all Cropped compressed files that are not null + * @return array of files + */ + public String[] compressedcrop(){ + return MakeArray(CompressedCropLeft90, CompressedCropLeft45, CompressedCropCenter, CompressedCropRight45, CompressedCropRight90); + } + } diff --git a/src/main/java/ErhaAPI/BarcodeResullt.java b/src/main/java/ErhaAPI/BarcodeResullt.java new file mode 100644 index 0000000..6380e2a --- /dev/null +++ b/src/main/java/ErhaAPI/BarcodeResullt.java @@ -0,0 +1,29 @@ +package ErhaAPI; + + +public class BarcodeResullt { + public int currentPage; + public int limit; + public int totalPages; + public int totalRecords; + public String message; + public boolean error; + public String errorId; + public String errorMessage; + public String errorCode; + public PatientRecord[] data; + + @Override + public String toString(){ + StringBuilder sb = new StringBuilder(); + sb.append("currentPage : ").append(currentPage).append(", limit : ").append(limit).append(", totalPages : ").append(totalPages).append(", totalRecords : ").append(totalRecords).append(", message : ").append(message).append(", error : ").append(error); + if (data != null){ + sb.append(", data : ["); + for (PatientRecord pr : data){ + sb.append(pr.toString()).append(", "); + } + sb.append("]"); + } + return sb.toString(); + } +} diff --git a/src/main/java/ErhaAPI/ErhaAPI.java b/src/main/java/ErhaAPI/ErhaAPI.java new file mode 100644 index 0000000..9c73acf --- /dev/null +++ b/src/main/java/ErhaAPI/ErhaAPI.java @@ -0,0 +1,195 @@ +package ErhaAPI; + +import Config.SomeCodes; +import com.google.gson.Gson; +import lombok.Getter; + + +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.file.Files; +import java.util.Base64; +import java.util.UUID; + +import static Config.SomeCodes.*; + + +public class ErhaAPI { + private @Getter String API_USERNAME = "erha-pb-001"; + private @Getter String API_PASSWORD = "bM0tH!s"; + + + + private String auth; + private final String API_URL; + + private final Gson gson = new Gson(); + + public ErhaAPI(boolean isProduction){ + final String API_URL_PROD = "https://connect-api.aryanoble.co.id/api"; + final String API_URL_STAGING = "https://connect-api-staging.aryanoble.web.id/api"; + API_URL = isProduction ? API_URL_PROD : API_URL_STAGING; + update_auth(); + } + /** + * Set API Username + * @param API_USERNAME API Username + */ + public void setAPI_USERNAME(String API_USERNAME){ + if (ValidString(API_USERNAME)){ + if (!API_USERNAME.equals(this.API_USERNAME)){ + this.API_USERNAME = API_USERNAME; + update_auth(); + } + } + } + + /** + * Set API Password + * @param API_PASSWORD API Password + */ + public void setAPI_PASSWORD(String API_PASSWORD){ + if (ValidString(API_PASSWORD)){ + if (!API_PASSWORD.equals(this.API_PASSWORD)){ + this.API_PASSWORD = API_PASSWORD; + update_auth(); + } + } + } + + /** + * Validate Barcode data + * @param Barcode Barcode to verify + * @return BarcodeResullt object if success, or null if failed + */ + public BarcodeResullt Validate_Barcode(String Barcode){ + if (ValidBarCode(Barcode)){ + + try (HttpClient client = HttpClient.newHttpClient()) { + int medical_record_detail_id = toInt(Barcode); + HttpRequest request = HttpRequest.newBuilder() + .uri(java.net.URI.create(API_URL+"/photobooth/photobooth/" + medical_record_detail_id)) + .header("Authorization", "Basic " + auth) + .GET() + .build(); + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); + if (response.statusCode()==200){ + String body = response.body(); + return gson.fromJson(body, BarcodeResullt.class); + } else System.out.println("Validate Barcode status code : " + response.statusCode()); + + } catch (IOException e) { + System.out.println("Validate_Barcode IO Exception, Msg : " + e.getMessage()); + } catch (InterruptedException e) { + System.out.println("Validate_Barcode Interrupted Exception, Msg : " + e.getMessage()); + } + + } + return null; + } + +// public String Upload_File_OKHttp(String patientID, String filename){ +// if (ValidMedicalRecordId(patientID)){ +// int medical_record_detail_id = toInt(patientID); +// if (ValidFile(filename)){ +// try { +// okhttp3.OkHttpClient client = new okhttp3.OkHttpClient(); +// okhttp3.RequestBody requestBody = new okhttp3.MultipartBody.Builder() +// .setType(okhttp3.MultipartBody.FORM) +// .addFormDataPart("medical_record_detail_id", String.valueOf(medical_record_detail_id)) +// .addFormDataPart("file", filename, okhttp3.RequestBody.create(okhttp3.MediaType.parse("application/octet-stream"), new java.io.File(filename))) +// .build(); +// +// okhttp3.Request request = new okhttp3.Request.Builder() +// .url(API_URL + "/photobooth/photobooth") +// .header("Authorization", "Basic " + auth) +// .post(requestBody) +// .build(); +// +// okhttp3.Response response = client.newCall(request).execute(); +// if (response.isSuccessful()){ +// return response.body().string(); +// } else System.out.println("Upload_File_OKHttp status code : " + response.code()); +// } catch (Exception e){ +// System.out.println("Upload_File_OKHttp Exception, Msg : " + e.getMessage()); +// } +// } else return "Invalid File"; +// } else return "Invalid Patient ID"; +// return null; +// } + + + /** + * Upload File + * @param patientID Patient ID + * @param filename File to upload + * @return null if failed, or response body if success + */ + public UploadResult Upload_File(String patientID, String filename) { + if (ValidMedicalRecordId(patientID)){ + int medical_record_detail_id = toInt(patientID); + if (ValidFile(filename)){ + File ff = new File(filename); + try (HttpClient client = HttpClient.newHttpClient()){ + byte[] fileBytes = Files.readAllBytes(new java.io.File(filename).toPath()); + String fn = ff.getName(); + // Unique boundary for multipart data + String boundary = "----JavaHttpClientBoundary" + UUID.randomUUID(); + String CRLF = "\r\n"; + + // Form Data (Text Field) + String formData1 = "--" + boundary + CRLF + + "Content-Disposition: form-data; name=\"medical_record_detail_id\"" + CRLF + CRLF + + medical_record_detail_id + CRLF; + + // Form Data (File) + String formData2 = "--" + boundary + CRLF + + "Content-Disposition: form-data; name=\"file\"; filename=\"" + fn + "\"" + CRLF + + "Content-Type: image/jpeg" + CRLF + CRLF; // Change Content-Type accordingly + + // End Boundary + String endBoundary = CRLF + "--" + boundary + "--" + CRLF; + + // Combine all parts into a single byte array + byte[] multipartData = SomeCodes.Concat( + formData1.getBytes(), + formData2.getBytes(), + fileBytes, + endBoundary.getBytes() + ); + + + HttpRequest request = HttpRequest.newBuilder() + .uri(new URI(API_URL + "/photobooth/photobooth")) + .header("Authorization", "Basic " + auth) + .header("Content-Type", "multipart/form-data; boundary=" + boundary) + .POST(HttpRequest.BodyPublishers.ofByteArray(multipartData)) + .build(); + + // Send request + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); + + if (response.statusCode()==200){ + return gson.fromJson(response.body(), UploadResult.class); + + } else System.out.println("Upload_File status code : " + response.statusCode()); + + + } catch (Exception e){ + System.out.println("Upload_File Exception, Msg : " + e.getMessage()); + } + } + } + return null; + } + + + private void update_auth(){ + auth = Base64.getEncoder().encodeToString((API_USERNAME + ":" + API_PASSWORD).getBytes()); + } + +} diff --git a/src/main/java/ErhaAPI/PatientRecord.java b/src/main/java/ErhaAPI/PatientRecord.java new file mode 100644 index 0000000..93d447d --- /dev/null +++ b/src/main/java/ErhaAPI/PatientRecord.java @@ -0,0 +1,23 @@ +package ErhaAPI; + +public class PatientRecord { + public String medical_record_detail_id; + public String medical_staff_id; + public String medical_staff_name; + public String branch_id; + public String branch_code; + public String branch_name; + public String registration_id; + public String registration_date; + public String patient_id; + public String mrnl; + public String name; + public String phone; + public String birthdate; + public String service; + + @Override + public String toString(){ + return "medical_record_detail_id : " + medical_record_detail_id + ", medical_staff_id : " + medical_staff_id + ", medical_staff_name : " + medical_staff_name + ", branch_id : " + branch_id + ", branch_code : " + branch_code + ", branch_name : " + branch_name + ", registration_id : " + registration_id + ", registration_date : " + registration_date + ", patient_id : " + patient_id + ", mrnl : " + mrnl + ", name : " + name + ", phone : " + phone + ", birthdate : " + birthdate + ", service : " + service; + } +} diff --git a/src/main/java/ErhaAPI/PhotoResult.java b/src/main/java/ErhaAPI/PhotoResult.java new file mode 100644 index 0000000..c9ed0ea --- /dev/null +++ b/src/main/java/ErhaAPI/PhotoResult.java @@ -0,0 +1,30 @@ +package ErhaAPI; + +import lombok.Getter; +import lombok.Setter; + +@Getter @Setter +public class PhotoResult { + private final String cameraname; + private String fullres; + private String compressedfile; + private String fullcrop; + private String compressedcrop; + private String thumbnail; + public PhotoResult(String cameraname){ + this.cameraname = cameraname; + this.fullres = ""; + this.compressedfile = ""; + this.fullcrop = ""; + this.compressedcrop = ""; + this.thumbnail = ""; + } + public PhotoResult(String cameraname,String fullres, String compressedfile, String fullcrop, String compressedcrop, String thumbnail){ + this.cameraname = cameraname; + this.fullres = fullres; + this.compressedfile = compressedfile; + this.fullcrop = fullcrop; + this.compressedcrop = compressedcrop; + this.thumbnail = thumbnail; + } +} diff --git a/src/main/java/ErhaAPI/UploadResult.java b/src/main/java/ErhaAPI/UploadResult.java new file mode 100644 index 0000000..79d56ac --- /dev/null +++ b/src/main/java/ErhaAPI/UploadResult.java @@ -0,0 +1,18 @@ +package ErhaAPI; + +public class UploadResult { + public int currentPage; + public int limit; + public int totalPages; + public int totalRecords; + public boolean error; + public String errorId; + public String errorMessage; + public String errorCode; + public String message; + + @Override + public String toString(){ + return "message : " + message + ", error : " + error + ", errorId : " + errorId + ", errorMessage : " + errorMessage + ", errorCode : " + errorCode ; + } +} diff --git a/src/main/java/SecureDongle/LibSecureDongle.java b/src/main/java/SecureDongle/LibSecureDongle.java new file mode 100644 index 0000000..1f64c87 --- /dev/null +++ b/src/main/java/SecureDongle/LibSecureDongle.java @@ -0,0 +1,107 @@ +package SecureDongle; + +import com.sun.jna.Library; +import com.sun.jna.Native; + +public interface LibSecureDongle extends Library { + LibSecureDongle Instance = (LibSecureDongle) Native.load("SecureDongleJ", LibSecureDongle.class); + short SD_FIND=1; + short SD_FIND_NEXT=2; + short SD_OPEN=3; + short SD_CLOSE=4; + short SD_READ=5; + short SD_WRITE=6; + short SD_RANDOM=7; + short SD_SEED=8; + short SD_WRITE_USERID=9; + short SD_READ_USERID=10; + short SD_SET_MODULE=11; + short SD_CHECK_MODULE=12; + short SD_WRITE_ARITHMETIC=13; + short SD_CALCULATE1=14; + short SD_CALCULATE2=15; + short SD_CALCULATE3=16; + short SD_DECREASE=17; + + short SD_SET_RSAKEY_N=29; + short SD_SET_RSAKEY_D=30; + + short SD_SET_DES_KEY=41; + short SD_DES_ENC=42; + short SD_DES_DEC=43; + short SD_RSA_ENC=44; + short SD_RSA_DEC=45; + + short SD_READ_EX=46; + short SD_WRITE_EX=47; + + short SD_SET_COUNTER_EX=160; + short SD_GET_COUNTER_EX=161; + short SD_SET_TIMER_EX=162; + short SD_GET_TIMER_EX=163; + short SD_ADJUST_TIMER_EX=164; + short SD_UPDATE_GEN_HEADER_EX=165; + short SD_UPDATE_GEN_EX=166; + short SD_UPDATE_CHECK_EX=167; + short SD_UPDATE_EX=168; + short SD_SET_UPDATE_KEY=169; + short SD_ADD_UPDATE_HEADER=170; + short SD_ADD_UPDATE_CONTENT=171; + short SD_GET_TIME_DWORD=172; + + short SD_VERSION=100; + + short DES_SINGLE_MODE=0; + short DES_TRIPLE_MODE=1; + short RSA_PRIVATE_KEY=0; + short RSA_PUBLIC_KEY=1; + short RSA_SECUREDONGLE_PADDING=0; + short RSA_USER_PADDING=1; + + //error code + short ERR_SUCCESS=0; + short ERR_NO_ROCKEY=3; + short ERR_INVALID_PASSWORD=4; + short ERR_INVALID_PASSWORD_OR_ID=5; + short ERR_SETID=6; + short ERR_INVALID_ADDR_OR_SIZE=7; + short ERR_UNKNOWN_COMMAND=8; + short ERR_NOTBELEVEL3=9; + short ERR_READ=10; + short ERR_WRITE=11; + short ERR_RANDOM=12; + short ERR_SEED=13; + short ERR_CALCULATE=14; + short ERR_NO_OPEN=15; + short ERR_OPEN_OVERFLOW=16; + short ERR_NOMORE=17; + short ERR_NEED_FIND=18; + short ERR_DECREASE=19; + short ERR_AR_BADCOMMAND=20; + short ERR_AR_UNKNOWN_OPCODE=21; + short ERR_AR_WRONGBEGIN=22; + short ERR_AR_WRONG_END=23; + short ERR_AR_VALUEOVERFLOW=24; + + short ERR_TOOMUCHTHREAD=25; + short ERR_INVALID_SD=30; + short ERR_INVALID_PARAMETER=31; + short ERR_INVALID_TIMEVALUE=32; + + short ERR_SET_DES_KEY=40; + short ERR_DES_ENCRYPT=41; + short ERR_DES_DECRYPT=42; + short ERR_SET_RSAKEY_N=43; + short ERR_SET_RSAKEY_D=44; + short ERR_RSA_ENCRYPT=45; + short ERR_RSA_DECRYPT=46; + short ERR_INVALID_LENGTH=47; + + short ERR_UNKNOWN=-1; + short ERR_RECEIVE_NULL=256; + short ERR_INVALID_BUFFER=257; + short ERR_UNKNOWN_SYSTEM=258; + short ERR_UNINIT_TIME_UNIT=259; + + short SecureDongle(short command, short[] handle, int[] lp1, int[] lp2, short[] p1, short[] p2, short[] p3, short[] p4, byte[] buffer); +} diff --git a/src/main/java/SecureDongle/SecureDongle.java b/src/main/java/SecureDongle/SecureDongle.java new file mode 100644 index 0000000..9b5255f --- /dev/null +++ b/src/main/java/SecureDongle/SecureDongle.java @@ -0,0 +1,273 @@ +package SecureDongle; + +import lombok.Getter; +import lombok.Setter; +import org.tinylog.Logger; + +import java.util.function.Consumer; + +import static Config.SomeCodes.ToShort; + +public class SecureDongle { + + private final int[] lp1 = new int[1]; + private final int[] lp2 = new int[1]; + // for Open/Close Handle + private final short[] handle = new short[1]; + // P1 + private final short[] p1 = new short[1]; + // P2 + private final short[] p2 = new short[1]; + // P3 + private final short[] p3 = new short[1]; + // P4 + private final short[] p4 = new short[1]; + + private final byte[] buffer = new byte[1024]; + + LibSecureDongle SD; + + private @Getter boolean Opened = false; + private @Getter short Handle; + private @Getter int HardwareID = 0; + private @Getter int UserID = 0; + + private @Setter SecureDongleEvent event; + + /** + * Create SecureDongle with P1, P2, P3, P4 + * @param P1 Password 1 + * @param P2 Password 2 + * @param P3 Password 3 + * @param P4 Password 4 + */ + public SecureDongle(Short P1, Short P2, Short P3, Short P4){ + this.p1[0] = P1; + this.p2[0] = P2; + this.p3[0] = P3; + this.p4[0] = P4; + SD = LibSecureDongle.Instance; + } + + /** + * Create SecureDongle with P1, P2, P3, P4 + * @param P1 Password 1 + * @param P2 Password 2 + * @param P3 Password 3 + * @param P4 Password 4 + */ + public SecureDongle(String P1, String P2, String P3, String P4){ + this.p1[0] = ToShort(P1); + this.p2[0] = ToShort(P2); + this.p3[0] = ToShort(P3); + this.p4[0] = ToShort(P4); + SD = LibSecureDongle.Instance; + } + + + + + /** + * Find SecureDongle + * This must be executed first time + * @return true if found + */ + public boolean Find(){ + HardwareID = 0; + short result = SD.SecureDongle(LibSecureDongle.SD_FIND, handle, lp1, lp2, p1, p2, p3, p4, buffer); + + if (result== LibSecureDongle.ERR_SUCCESS){ + HardwareID = lp1[0]; + //System.out.println("SecureDongle found with HardwareID="+HardwareID); + return true; + } else { + if (event!=null) event.onDongleError("Find", result); + } + return false; + } + + /** + * Open SecureDongle + * @return true if success + */ + public boolean Open(){ + Handle=0; + if (HardwareID!=0){ + lp1[0] = HardwareID; + short result = SD.SecureDongle(LibSecureDongle.SD_OPEN, handle, lp1, lp2, p1, p2, p3, p4, buffer); + if (result== LibSecureDongle.ERR_SUCCESS){ + Handle = handle[0]; + Opened = true; + return true; + } else if (event!=null) event.onDongleError("Open", result); + } //else System.out.println("HardwareID not found, Find SecureDongle first"); + return false; + } + + /** + * Close SecureDongle + * @return true if success + */ + public boolean Close(){ + handle[0] = Handle; + short result = SD.SecureDongle(LibSecureDongle.SD_CLOSE, handle, lp1, lp2, p1, p2, p3, p4, buffer); + if (result== LibSecureDongle.ERR_SUCCESS){ + return true; + } else if (event!=null) event.onDongleError("Close", result); + Opened = false; + return false; + } + + /** + * Read from User Data Zone (UDZ) + * @param StartAddress Start Address, zero based + * @param Length Length of data to read, max 1000 bytes + * @return byte array of data, length=0 if failed + */ + public byte[] Read(short StartAddress, short Length){ + if (Opened){ + handle[0] = Handle; + p1[0] = StartAddress>=0 ? StartAddress : 0; + if (Length<1) Length=1; + if (Length>1000) Length=1000; + p2[0] = Length; + short result = SD.SecureDongle(LibSecureDongle.SD_READ, handle, lp1, lp2, p1, p2, p3, p4, buffer); + if (result== LibSecureDongle.ERR_SUCCESS){ + //System.out.println("SecureDongle HardwareID="+HardwareID+" read success "); + byte[] data = new byte[Length]; + System.arraycopy(buffer, 0, data, 0, Length); + return data; + } else if (event!=null) event.onDongleError("Read", result); + } //else System.out.println("SecureDongle not opened"); + + return new byte[0]; + } + + /** + * Write to User Data Zone (UDZ) + * @param StartAddress start address of UDZ, zero based + * @param length length of data to write, max 1000 bytes + * @param data data to write + * @return true if success + */ + public boolean Write(short StartAddress, short length, byte[] data){ + if (Opened){ + handle[0] = Handle; + p1[0] = StartAddress>=0 ? StartAddress : 0; + if (length<1) length=1; + if (length>1000) length=1000; + p2[0] = length; + System.arraycopy(data, 0, buffer, 0, length); + short result = SD.SecureDongle(LibSecureDongle.SD_WRITE, handle, lp1, lp2, p1, p2, p3, p4, buffer); + if (result== LibSecureDongle.ERR_SUCCESS){ + //System.out.println("SecureDongle HardwareID="+HardwareID+" write success "); + return true; + } else if (event!=null) event.onDongleError("Write", result); + } //else System.out.println("SecureDongle not opened"); + + return false; + } + + /** + * Generate Random Number + * @return short array of random number + */ + public short[] GenerateRandomNumber(){ + short[] random = new short[4]; + if (Opened){ + handle[0] = Handle; + short result = SD.SecureDongle(LibSecureDongle.SD_RANDOM, handle, lp1, lp2, p1, p2, p3, p4, buffer); + if (result== LibSecureDongle.ERR_SUCCESS){ + //System.out.println("SecureDongle HardwareID="+HardwareID+" generate random success "); + random[0] = p1[0]; + random[1] = p2[0]; + random[2] = p3[0]; + random[3] = p4[0]; + return random; + } else if (event!=null) event.onDongleError("GenerateRandomNumber", result); + } //else System.out.println("SecureDongle not opened"); + + return random; + } + + /** + * Write UserID to SecureDongle + * @param UserID UserID to write + * @return true if success + */ + public boolean WriteUserID(int UserID){ + if (Opened){ + handle[0] = Handle; + lp1[0] = UserID; + short result = SD.SecureDongle(LibSecureDongle.SD_WRITE_USERID, handle, lp1, lp2, p1, p2, p3, p4, buffer); + if (result== LibSecureDongle.ERR_SUCCESS){ + //System.out.println("SecureDongle HardwareID="+HardwareID+" set UserID success "); + this.UserID = UserID; + return true; + } else if (event!=null) event.onDongleError("WriteUserID", result); + } //else System.out.println("SecureDongle not opened"); + + return false; + } + + /** + * Read UserID from SecureDongle + * @return UserID, 0 if failed + */ + public int ReadUserID(){ + if (Opened){ + handle[0] = Handle; + short result = SD.SecureDongle(LibSecureDongle.SD_READ_USERID, handle, lp1, lp2, p1, p2, p3, p4, buffer); + if (result== LibSecureDongle.ERR_SUCCESS){ + this.UserID = lp1[0]; + //System.out.println("SecureDongle HardwareID="+HardwareID+" read UserID success, value = "+UserID); + return UserID; + } else if (event!=null) event.onDongleError("ReadUserID", result); + } //else System.out.println("SecureDongle not opened"); + + return 0; + } + + boolean ismonitoring = false; + + /** + * Stop Monitoring SecureDongle + */ + public void StopMonitor(){ + ismonitoring = false; + } + + /** + * Start Monitoring SecureDongle + * if dongle missing, will raise event onDongleMissing + */ + public void StartMonitor(){ + new Thread(()->{ + if (HardwareID==0) Find(); + Open(); + int firstUserID = ReadUserID(); + Close(); + if (firstUserID!=0){ + ismonitoring = true; + Logger.info("Start Monitoring UserID="+Integer.toHexString(firstUserID)); + while (ismonitoring){ + try { + Thread.sleep(5000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + Open(); + int newUserID = ReadUserID(); + Close(); + if (newUserID!=firstUserID){ + if (event!=null) event.onDongleMissing(); + } + + } + System.out.println("Stop Monitoring"); + } else System.out.println("Canceled Monitoring, UserID not found"); + + }).start(); + } + +} diff --git a/src/main/java/SecureDongle/SecureDongleEvent.java b/src/main/java/SecureDongle/SecureDongleEvent.java new file mode 100644 index 0000000..53b197a --- /dev/null +++ b/src/main/java/SecureDongle/SecureDongleEvent.java @@ -0,0 +1,6 @@ +package SecureDongle; + +public interface SecureDongleEvent { + void onDongleMissing(); + void onDongleError(String function,int errorCode); +} diff --git a/src/main/java/id/co/gtc/erhacam/Cameradetail.java b/src/main/java/id/co/gtc/erhacam/Cameradetail.java index 6dc0622..6d548ab 100644 --- a/src/main/java/id/co/gtc/erhacam/Cameradetail.java +++ b/src/main/java/id/co/gtc/erhacam/Cameradetail.java @@ -5,6 +5,7 @@ import Camera.LiveCamEvent; import Camera.ObsbotMeet2Preset; import Config.CameraConfigEnum; import Config.SomeCodes; +import ErhaAPI.PhotoResult; import com.google.zxing.BinaryBitmap; import com.google.zxing.NotFoundException; import com.google.zxing.Result; @@ -109,9 +110,14 @@ public class Cameradetail { private @Getter Rect ReducedMatROI; private @Getter Rect LiveMatROI; - private Size LiveSize = new Size(640, 360); - private Size ReducedSize = new Size(1280, 720); - private Size BestSize = new Size(1920, 1080); +// private Size LiveSize = new Size(640, 360); +// private Size ReducedSize = new Size(1280, 720); +// private Size BestSize = new Size(1920, 1080); + + // putar portrait + private Size LiveSize = new Size(360, 640); + private Size ReducedSize = new Size(720, 1280); + private Size BestSize = new Size(2160, 3840); //TODO ini angka dari Erha, cek apakah masih cocok atau tidak private @Getter @Setter Size FullCropSize = new Size(1036,1036); @@ -345,15 +351,28 @@ public class Cameradetail { * @param photoheight Height used on photo capture * @param reducedwidth Width used on reduced resolution * @param reducedheight Height used on reduced resolution + * @param isPotrait if true, set to portrait mode, otherwise landscape */ - public void SetGrabber(OpenCVFrameGrabber grabber, int livewidth, int liveheight, int photowidth, int photoheight, int reducedwidth, int reducedheight){ + public void SetGrabber(OpenCVFrameGrabber grabber, int livewidth, int liveheight, int photowidth, int photoheight, int reducedwidth, int reducedheight, boolean isPotrait){ if (mGrabber!=null) { StopLiveView(); } - LiveSize = new Size(livewidth, liveheight); - BestSize = new Size(photowidth, photoheight); - ReducedSize = new Size(reducedwidth, reducedheight); + + if (isPotrait){ + // putar portrait + LiveSize = new Size(liveheight, livewidth); + BestSize = new Size(photoheight, photowidth); + ReducedSize = new Size(reducedheight, reducedwidth); + } else { + LiveSize = new Size(livewidth, liveheight); + BestSize = new Size(photowidth, photoheight); + ReducedSize = new Size(reducedwidth, reducedheight); + } + + + mGrabber = grabber; + } //Exposure and Focus Tricks : @@ -545,9 +564,8 @@ public class Cameradetail { * @param ROI_Compressed Region of Interest for Compressed Photo. If Null, will not save cropped photo * @return filename path of the saved photo, or null if failed */ - @SuppressWarnings("BusyWait") - public String TakePhoto(String directory, String prefix, Rect ROI_Full, Rect ROI_Compressed) throws InterruptedException { - String result = null; + public PhotoResult TakePhoto(String directory, String prefix, Rect ROI_Full, Rect ROI_Compressed) throws InterruptedException { + PhotoResult result = new PhotoResult(cameratitle.getText()); if (!ValidDirectory(directory)) directory = currentDirectory; if (mGrabber!=null){ @@ -577,33 +595,31 @@ public class Cameradetail { // save BestMat at quality 9 PNG String filename = Path.of(directory, "FullQuality", makeFileName(prefix,".png")).toString(); if (imwrite(filename, BestMat, parampng)){ - result = filename; + result.setFullres(filename); } else System.out.println("TakePhoto failed, Unable to Save FullQUality Photo for camera "+cameratitle.getText()); - if (ROIInsideUMat(ROI_Full, BestMat)){ - // save ROI_Full at 100% JPEG + UMat FullCrop = CropUMat(BestMat, ROI_Full); + if (FullCrop!=null){ String roifilename = Path.of(directory, "FullQualityCrop", makeFileName(prefix,".png")).toString(); - UMat ROI = new UMat(BestMat, ROI_Full); - if (!imwrite(roifilename, ROI, paramjpeg)){ + if (!imwrite(roifilename, FullCrop, parampng)){ System.out.println("TakePhoto failed, Unable to Save FullQUalityCrop for camera "+cameratitle.getText()); - } - } else System.out.println("ROI_Full is outside of BestMat for camera "+cameratitle.getText()); + } else result.setFullcrop(roifilename); + } // save ReducedMat at 100% JPEG String reducedfilename = Path.of(directory, "Compressed", makeReducedFileName(prefix,".jpg")).toString(); opencv_imgproc.resize(BestMat, ReducedMat, ReducedSize); if (!imwrite(reducedfilename, ReducedMat, paramjpeg)){ System.out.println("TakePhoto failed, Unable to Save Reduced Photo for camera "+cameratitle.getText()); - } + } else result.setCompressedfile(reducedfilename); - if (ROIInsideUMat(ROI_Compressed, ReducedMat)){ - // save ROI_Compressed at 100% JPEG + UMat CompressedCrop = CropUMat(ReducedMat, ROI_Compressed); + if (CompressedCrop!=null){ String roifilename = Path.of(directory, "CompressedCrop", makeReducedFileName(prefix,".jpg")).toString(); - UMat ROI = new UMat(ReducedMat, ROI_Compressed); - if (!imwrite(roifilename, ROI, paramjpeg)){ + if (!imwrite(roifilename, CompressedCrop, paramjpeg)){ System.out.println("TakePhoto failed, Unable to Save CompressedCrop for camera "+cameratitle.getText()); - } - } else System.out.println("ROI_Compressed is outside of ReducedMat for camera "+cameratitle.getText()); + } else result.setCompressedcrop(roifilename); + } } else raise_log("TakePhoto failed, Live View is Empty"); @@ -699,7 +715,8 @@ public class Cameradetail { int _face_height; boolean have_palm = false; boolean have_fist = false; - long no_face_counter = 0; + int no_face_counter = 0; + int face_counter = 0; while (Capturing.get()) { try { @@ -710,23 +727,30 @@ public class Cameradetail { if (!Capturing.get()) return null; IsGrabbingLiveView.set(true); - Frame frame = mGrabber.grab(); // grab frame + Frame frame=null; + try{ + frame = mGrabber.grab(); // grab frame + } catch (Exception e){ + System.out.println("Exception on grab frame from camera "+cameratitle+", Message : "+e.getMessage()); + } + if (frame==null) continue; Mat mat = matconverter.convert(frame); // convert to Mat fps.incrementAndGet(); - mat.copyTo(BestMat); // copy to BestMat for using OpenCL + UMat originalmat = new UMat(); + mat.copyTo(originalmat); // copy to BestMat for using OpenCL + opencv_core.rotate(originalmat, BestMat, opencv_core.ROTATE_90_COUNTERCLOCKWISE); IsGrabbingLiveView.set(false); - if (frame != null) { + if (!BestMat.empty()) { opencv_imgproc.resize(BestMat, LiveMat, LiveSize); // resize to LiveSize UMat graymat = new UMat(); // use OpenCL for grayscale opencv_imgproc.cvtColor(LiveMat,graymat, COLOR_BGR2GRAY); // convert to grayscale if (use_qr){ String qr = DetectQRFromMat(graymat); - if (ValidPatientID(qr)){ + if (ValidBarCode(qr)){ if (!qr.equals(qrtext)){ qrtext = qr; - raise_log("QR Detected: " + qrtext); if (event!=null) event.onDetectedQRCode(qrtext); } } @@ -771,6 +795,12 @@ public class Cameradetail { if (have_frontal_face){ + if (face_counter<5){ + face_counter++; + //System.out.println("Frontal Face Counter = "+face_counter+ " from camera "+cameratitle+" eye count = "+theface.getEyesCount()); + continue; + } + no_face_counter = 0; if (event!=null) event.onFrontalFaceDetector(true, _face_width, _face_height); LiveMatROI = theface.getFace(); @@ -805,20 +835,25 @@ public class Cameradetail { } + + } else if (have_left_45_face ){ no_face_counter = 0; LiveMatROI = theface.getFace(); if (event!=null) event.onProfileFaceDetector(true, _face_width, _face_height); - } else { - // no face detected, but lets not cancel the previous state immediately - if (no_face_counter>30){ + + } else { + // no face detected, but let's not cancel the previous state immediately + + if (no_face_counter>60){ // kalau tidak ada face selama 30 frame, reset state - // 30 frame approximately 2 second + // 60 frame approximately 2 second eye_state = -1; last_blink = 0; waiting_for_second_blink = false; + face_counter = 0; if (event!=null) { event.onFrontalFaceDetector(false, _face_width, _face_height); event.onProfileFaceDetector(false, _face_width, _face_height); @@ -880,16 +915,26 @@ public class Cameradetail { return false; } - public void RemapROI(){ + /** + * Remap LiveMatROI to BestMatROI and ReducedMatROI Resolution + * @param scale scale factor, 1.0 for 100%, 0.5 for 50%, etc + */ + public void RemapROI(double scale){ if (ValidROI(LiveMatROI)){ if (ROIInsideUMat(LiveMatROI, LiveMat)){ System.out.println("LiveMatROI camera "+cameratitle.getText()+" = "+RectToString(LiveMatROI)); - double scaleXBest = 1.0*BestSize.width()/LiveSize.width(); - double scaleYBest = 1.0*BestSize.height()/LiveSize.height(); - double scaleXReduced = 1.0*ReducedSize.width()/LiveSize.width(); - double scaleYReduced = 1.0*ReducedSize.height()/LiveSize.height(); - BestMatROI = ScaleRect(LiveMatROI, scaleXBest, scaleYBest); - ReducedMatROI = ScaleRect(LiveMatROI, scaleXReduced, scaleYReduced); + + double scaleXBest = scale*BestSize.width()/LiveSize.width(); + double scaleYBest = scale*BestSize.height()/LiveSize.height(); + System.out.println("scaleXBest = "+scaleXBest+" scaleYBest = "+scaleYBest); + double scaleXReduced = scale*ReducedSize.width()/LiveSize.width(); + double scaleYReduced = scale*ReducedSize.height()/LiveSize.height(); + System.out.println("scaleXReduced = "+scaleXReduced+" scaleYReduced = "+scaleYReduced); + + BestMatROI = ResizeRect(LiveMatROI, scaleXBest, scaleYBest, 50,250); + System.out.println("BestMatROI camera "+cameratitle.getText()+" = "+RectToString(BestMatROI)); + ReducedMatROI = ResizeRect(LiveMatROI, scaleXReduced, scaleYReduced, 50,250); + System.out.println("ReducedMatROI camera "+cameratitle.getText()+" = "+RectToString(ReducedMatROI)); } else { System.out.println("LiveMatROI is Outside LiveMat for camera "+cameratitle.getText()); diff --git a/src/main/java/id/co/gtc/erhacam/CaptureView.java b/src/main/java/id/co/gtc/erhacam/CaptureView.java index 3a291e8..c34c1c9 100644 --- a/src/main/java/id/co/gtc/erhacam/CaptureView.java +++ b/src/main/java/id/co/gtc/erhacam/CaptureView.java @@ -4,9 +4,13 @@ import BASS.AudioPlayer; import BASS.PlaybackStatus; import Camera.*; import Config.CameraConfigEnum; -import Config.SomeCodes; import Database.PhotoReviewClass; import Database.Sqlite; +import ErhaAPI.ErhaAPI; +import ErhaAPI.BarcodeResullt; +import ErhaAPI.PhotoResult; +import ErhaAPI.PatientRecord; +import ErhaAPI.UploadResult; import FTP.FTPUpload; import FTP.FTPUploadEvent; import FTP.FtpMonitorData; @@ -33,6 +37,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import javafx.scene.control.Alert.AlertType; import org.bytedeco.javacv.OpenCVFrameGrabber; import org.bytedeco.javacv.VideoInputFrameGrabber; +import org.bytedeco.opencv.opencv_core.Rect; import org.bytedeco.opencv.opencv_core.Size; import org.tinylog.Logger; @@ -44,13 +49,30 @@ public class CaptureView { private AnchorPane CaptureViewAnchor; @FXML - private AnchorPane cam1, cam2, cam3, cam4, cam5, controlpane; + private AnchorPane cam1; + @FXML + private AnchorPane cam2; + @FXML + private AnchorPane cam3; + @FXML + private AnchorPane cam4; + @FXML + private AnchorPane cam5; + @FXML + private AnchorPane controlpane; private Cameradetail image1, image2, image3, image4, image5; @FXML - private TextArea directorypath, prefixfile; + private TextArea directorypath; + @FXML + private TextArea barcodeData; + @FXML + private TextArea medicalRecordID; + @FXML + private TextArea PatientName; + @FXML private Button btnTakePhoto; @FXML @@ -80,6 +102,8 @@ public class CaptureView { private final AtomicBoolean[] have_right_eye = new AtomicBoolean[5]; private final AtomicBoolean isTakingPhoto = new AtomicBoolean(false); + private final ErhaAPI erhaAPI = new ErhaAPI(false); + @FXML private void ChangeDirectory(){ DirectoryChooser dc = new DirectoryChooser(); @@ -95,11 +119,11 @@ public class CaptureView { if (image!=null){ if (image.isCapturing()){ image.setAutoFocus(false); - Thread.sleep(2); - image.setFocus(0.9); - Thread.sleep(2); + Thread.sleep(5); + image.setFocus(0.7); + Thread.sleep(5); image.setAutoFocus(true); - Thread.sleep(2); + Thread.sleep(5); } } } @@ -119,16 +143,27 @@ public class CaptureView { private void TakePhotos(){ boolean has_face = Arrays.stream(have_face).anyMatch(AtomicBoolean::get); if (has_face){ - if (audioPlayer.isPlaying()) audioPlayer.StopCurrentPlayback(); - audioPlayer.PlayFile(audio_countdown, ps); + if (audioPlayer!=null && audioPlayer.isInited()){ + if (!audioPlayer.getCurrentFile().equals(audio_countdown)) { + audioPlayer.StopCurrentPlayback(); + Wait(200); + } + audioPlayer.PlayFile(audio_countdown, ps); + } - btnAutoFocus.fire(); + + try{ + AutoFocus(); + Thread.sleep(2000); + } catch (InterruptedException e){ + Logger.error("Error AutoFocus: "+e.getMessage()); + } Size thumbsize = new Size(160,120); String directory = directorypath.getText(); - String prefix = RemoveSpaces(prefixfile.getText()) ; + String prefix = RemoveSpaces(medicalRecordID.getText()) ; if (ValidDirectory(directory)){ - if (ValidPatientID(prefix)){ + if (ValidMedicalRecordId(prefix)){ PhotoReviewClass prc = new PhotoReviewClass(); prc.setPrefix(prefix); @@ -137,75 +172,181 @@ public class CaptureView { ExecutorService executor = Executors.newFixedThreadPool(5); + // face detection Rect ROI to head detection Rect ROI + // head is bigger than face, so we need to scale it + final double face_to_head_scale = 1.2; + Rect bestsize = new Rect(0,0,0,0); + Rect reducedsize = new Rect(0,0,0,0); + + if (image1!=null) { + image1.RemapROI(face_to_head_scale); + if (image1.getBestMatROI()!=null && image1.getBestMatROI().width()>bestsize.width()) { + bestsize = image1.getBestMatROI(); + System.out.println("BestSize: "+bestsize.width()+"x"+bestsize.height()); + } + + if (image1.getReducedMatROI()!=null && image1.getReducedMatROI().width()>reducedsize.width()) { + reducedsize = image1.getReducedMatROI(); + System.out.println("ReducedSize: "+reducedsize.width()+"x"+reducedsize.height()); + } + } + if (image2!=null) { + image2.RemapROI(face_to_head_scale); + if (image2.getBestMatROI()!=null && image2.getBestMatROI().width()>bestsize.width()) { + bestsize = image2.getBestMatROI(); + System.out.println("BestSize: "+bestsize.width()+"x"+bestsize.height()); + } + if (image2.getReducedMatROI()!=null && image2.getReducedMatROI().width()>reducedsize.width()) { + reducedsize = image2.getReducedMatROI(); + System.out.println("ReducedSize: "+reducedsize.width()+"x"+reducedsize.height()); + } + } + if (image3!=null) { + image3.RemapROI(face_to_head_scale); + if (image3.getBestMatROI()!=null && image3.getBestMatROI().width()>bestsize.width()) { + bestsize = image3.getBestMatROI(); + System.out.println("BestSize: "+bestsize.width()+"x"+bestsize.height()); + } + if (image3.getReducedMatROI()!=null && image3.getReducedMatROI().width()>reducedsize.width()) { + reducedsize = image3.getReducedMatROI(); + System.out.println("ReducedSize: "+reducedsize.width()+"x"+reducedsize.height()); + } + } + if (image4!=null) { + image4.RemapROI(face_to_head_scale); + if (image4.getBestMatROI()!=null && image4.getBestMatROI().width()>bestsize.width()) { + bestsize = image4.getBestMatROI(); + System.out.println("BestSize: "+bestsize.width()+"x"+bestsize.height()); + } + if (image4.getReducedMatROI()!=null && image4.getReducedMatROI().width()>reducedsize.width()) { + reducedsize = image4.getReducedMatROI(); + System.out.println("ReducedSize: "+reducedsize.width()+"x"+reducedsize.height()); + } + } + if (image5!=null) { + image5.RemapROI(face_to_head_scale); + if (image5.getBestMatROI()!=null && image5.getBestMatROI().width()>bestsize.width()) { + bestsize = image5.getBestMatROI(); + System.out.println("BestSize: "+bestsize.width()+"x"+bestsize.height()); + } + if (image5.getReducedMatROI()!=null && image5.getReducedMatROI().width()>reducedsize.width()) { + reducedsize = image5.getReducedMatROI(); + System.out.println("ReducedSize: "+reducedsize.width()+"x"+reducedsize.height()); + } + } + + // find biggest BestROI and ReducedROI + final Rect finalbestsize = bestsize; + final Rect finalreducedsize = reducedsize; + + Callable task1 = ()->{ if (image1!=null) { - image1.RemapROI(); - String p1 = image1.TakePhoto(directory,prefix, image1.getBestMatROI(), image1.getReducedMatROI()); - if (ValidFile(p1)) { - Platform.runLater(()->image1.setCameraStatus("Photo: "+ SomeCodes.GetFileName(p1))); - - prc.setFileLeft90(p1); - String thumb1 = MakeThumbfile(p1, thumbsize); + image1.RemapROI(face_to_head_scale); + PhotoResult p1 = image1.TakePhoto(directory,prefix, finalbestsize, finalreducedsize); + if (ValidFile(p1.getFullres())) { + prc.setFileLeft90(p1.getFullres()); + String thumb1 = MakeThumbfile(p1.getFullres(), thumbsize); if (ValidFile(thumb1)) { prc.setThumbLeft90(thumb1); } } else System.out.println("Image1 ValidFile is false"); + if (ValidFile(p1.getCompressedfile())){ + prc.setCompressedLeft90(p1.getCompressedfile()); + } + if (ValidFile(p1.getFullcrop())){ + prc.setCroppedLeft90(p1.getFullcrop()); + } + if (ValidFile(p1.getCompressedcrop())){ + prc.setCompressedCropLeft90(p1.getCompressedcrop()); + } } else System.out.println("Image1 is null"); return "Task 1 Done"; }; Callable task2 = ()->{ if (image2!=null) { - image2.RemapROI(); - String p2 = image2.TakePhoto(directory,prefix, image2.getBestMatROI(), image2.getReducedMatROI()); - if (ValidFile(p2)) { - Platform.runLater(()->image2.setCameraStatus("Photo: "+ SomeCodes.GetFileName(p2))); - - prc.setFileLeft45(p2); - String thumb2 = MakeThumbfile(p2, thumbsize); + image2.RemapROI(face_to_head_scale); + PhotoResult p2 = image2.TakePhoto(directory,prefix, finalbestsize, finalreducedsize); + if (ValidFile(p2.getFullres())) { + prc.setFileLeft45(p2.getFullres()); + String thumb2 = MakeThumbfile(p2.getFullres(), thumbsize); if (ValidFile(thumb2)) prc.setThumbLeft45(thumb2); } else System.out.println("Image2 ValidFile is false"); + if (ValidFile(p2.getCompressedfile())){ + prc.setCompressedLeft45(p2.getCompressedfile()); + } + if (ValidFile(p2.getFullcrop())){ + prc.setCroppedLeft45(p2.getFullcrop()); + } + if (ValidFile(p2.getCompressedcrop())){ + prc.setCompressedCropLeft45(p2.getCompressedcrop()); + } } else System.out.println("Image2 is null"); return "Task 2 Done"; }; Callable task3 = ()->{ if (image3!=null) { - image3.RemapROI(); - String p3 = image3.TakePhoto(directory,prefix, image3.getBestMatROI(), image3.getReducedMatROI()); - if (ValidFile(p3)) { - Platform.runLater(()->image3.setCameraStatus("Photo: "+ SomeCodes.GetFileName(p3))); - prc.setFileCenter(p3); - String thumb3 = MakeThumbfile(p3, thumbsize); + image3.RemapROI(face_to_head_scale); + PhotoResult p3 = image3.TakePhoto(directory,prefix, finalbestsize, finalreducedsize); + if (ValidFile(p3.getFullres())) { + prc.setFileCenter(p3.getFullres()); + String thumb3 = MakeThumbfile(p3.getFullres(), thumbsize); if (ValidFile(thumb3)) prc.setThumbCenter(thumb3); } else System.out.println("Image3 ValidFile is false"); + if (ValidFile(p3.getCompressedfile())){ + prc.setCompressedCenter(p3.getCompressedfile()); + } + if (ValidFile(p3.getFullcrop())){ + prc.setCroppedCenter(p3.getFullcrop()); + } + if (ValidFile(p3.getCompressedcrop())){ + prc.setCompressedCropCenter(p3.getCompressedcrop()); + } } else System.out.println("Image3 is null"); return "Task 3 Done"; }; Callable task4 = ()->{ if (image4!=null) { - image4.RemapROI(); - String p4 = image4.TakePhoto(directory,prefix, image4.getBestMatROI(), image4.getReducedMatROI()); - if (ValidFile(p4)) { - Platform.runLater(()->image4.setCameraStatus("Photo: "+ SomeCodes.GetFileName(p4))); - prc.setFileRight45(p4); - String thumb4 = MakeThumbfile(p4, thumbsize); + image4.RemapROI(face_to_head_scale); + PhotoResult p4 = image4.TakePhoto(directory,prefix, finalbestsize, finalreducedsize); + if (ValidFile(p4.getFullres())) { + prc.setFileRight45(p4.getFullres()); + String thumb4 = MakeThumbfile(p4.getFullres(), thumbsize); if (ValidFile(thumb4)) prc.setThumbRight45(thumb4); } else System.out.println("Image4 ValidFile is false"); + if (ValidFile(p4.getCompressedfile())){ + prc.setCompressedRight45(p4.getCompressedfile()); + } + if (ValidFile(p4.getFullcrop())){ + prc.setCroppedRight45(p4.getFullcrop()); + } + if (ValidFile(p4.getCompressedcrop())){ + prc.setCompressedCropRight45(p4.getCompressedcrop()); + } } else System.out.println("Image4 is null"); return "Task 4 Done"; }; Callable task5 = ()->{ if (image5!=null) { - image5.RemapROI(); - String p5 = image5.TakePhoto(directory,prefix, image5.getBestMatROI(), image5.getReducedMatROI()); - if (ValidFile(p5)) { - Platform.runLater(()->image5.setCameraStatus("Photo: "+ SomeCodes.GetFileName(p5))); - prc.setFileRight90(p5); - String thumb5 = MakeThumbfile(p5, thumbsize); + image5.RemapROI(face_to_head_scale); + PhotoResult p5 = image5.TakePhoto(directory,prefix, finalbestsize, finalreducedsize); + if (ValidFile(p5.getFullres())) { + prc.setFileRight90(p5.getFullres()); + String thumb5 = MakeThumbfile(p5.getFullres(), thumbsize); if (ValidFile(thumb5)) prc.setThumbRight90(thumb5); } else System.out.println("Image5 ValidFile is false"); + if (ValidFile(p5.getCompressedfile())){ + prc.setCompressedRight90(p5.getCompressedfile()); + } + if (ValidFile(p5.getFullcrop())){ + prc.setCroppedRight90(p5.getFullcrop()); + } + if (ValidFile(p5.getCompressedcrop())){ + prc.setCompressedCropRight90(p5.getCompressedcrop()); + } } else System.out.println("Image5 is null"); return "Task 5 Done"; }; @@ -231,21 +372,81 @@ public class CaptureView { long duration = (System.nanoTime() - nanostart) / 1000000; // in milliseconds System.out.println("TakePhotos duration: "+duration+" ms"); - - if (audioPlayer.isPlaying()) { - if (!audio_pengambilan_berhasil.equals((audioPlayer.getCurrentFile()))){ + if (audioPlayer!=null && audioPlayer.isInited()){ + if (!audioPlayer.getCurrentFile().equals(audio_pengambilan_berhasil)) { audioPlayer.StopCurrentPlayback(); + Wait(200); } + audioPlayer.PlayFile(audio_pengambilan_berhasil, ps); } - audioPlayer.PlayFile(audio_pengambilan_berhasil, ps); - String[] files = prc.files(); - if (files!=null && files.length>0){ + + String[] files = prc.compressed(); + + if (files.length>0){ InsertSQL(prc); - progressanchor.getChildren().clear(); - prefixfile.setText(""); + Task uploadtask = new Task<>() { + @Override + protected Void call() { + int totalfiles = files.length; + int counter = 0; + for (String ff : files) { + UploadResult ur = erhaAPI.Upload_File(prefix, ff); + if (ur != null) { + if (ur.message.startsWith("Record has been created")) { + counter++; + updateMessage("Upload success for " + ff); + } else updateMessage("Upload failed for " + ff+", Message : "+ur.message); + } else updateMessage("Upload failed for " + ff+" because UploadResult is null"); + + } + if (counter == totalfiles) { + super.succeeded(); + } else super.failed(); + return null; + } + }; + + + + uploadtask.messageProperty().addListener((obs, oldval, newval)-> { + System.out.println("UploadTask message: "+newval); + Logger.info(newval); + }); + + + uploadtask.setOnSucceeded(e-> { + if (audioPlayer!=null && audioPlayer.isInited()){ + if (!audioPlayer.getCurrentFile().equals(audio_upload_berhasil)) { + audioPlayer.StopCurrentPlayback(); + Wait(200); + } + audioPlayer.PlayFile(audio_upload_berhasil, ps); + audioPlayer.WaitUntilFinished(); + } + + }); + + uploadtask.setOnFailed(e-> { + if (audioPlayer!=null && audioPlayer.isInited()){ + if (!audioPlayer.getCurrentFile().equals(audio_upload_gagal)) { + audioPlayer.StopCurrentPlayback(); + Wait(200); + } + audioPlayer.PlayFile(audio_upload_gagal, ps); + audioPlayer.WaitUntilFinished(); + } + + }); + + new Thread(uploadtask).start(); + + + progressanchor.getChildren().clear(); + barcodeData.setText(""); + medicalRecordID.setText(""); + PatientName.setText(""); - //TODO ganti ke API upload // new Thread(()-> { // try{ @@ -294,19 +495,21 @@ public class CaptureView { } } else { - if (audioPlayer.isPlaying()) { - if (!audio_posisikan_muka.equals((audioPlayer.getCurrentFile()))){ + if (audioPlayer!=null && audioPlayer.isInited()){ + if (!audioPlayer.getCurrentFile().equals(audio_posisikan_muka)) { audioPlayer.StopCurrentPlayback(); + Wait(200); } + audioPlayer.PlayFile(audio_posisikan_muka, ps); } - audioPlayer.PlayFile(audio_posisikan_muka, ps); + } isTakingPhoto.set(false); } private void UpdateBtnTakePhoto(){ - boolean valid = ValidDirectory(directorypath.getText()) && ValidString(prefixfile.getText()); + boolean valid = ValidDirectory(directorypath.getText()) && ValidString(barcodeData.getText()) && ValidString(medicalRecordID.getText()) && ValidString(PatientName.getText()); btnTakePhoto.setDisable(!valid); } @@ -326,8 +529,9 @@ public class CaptureView { btnTakePhoto.setDisable(true); directorypath.textProperty().addListener((obs, oldval, newval)-> UpdateBtnTakePhoto()); - prefixfile.textProperty().addListener((obs, oldval, newval)-> UpdateBtnTakePhoto()); - + barcodeData.textProperty().addListener((obs, oldval, newval)-> UpdateBtnTakePhoto()); + medicalRecordID.textProperty().addListener((obs, oldval, newval)-> UpdateBtnTakePhoto()); + PatientName.textProperty().addListener((obs, oldval, newval)-> UpdateBtnTakePhoto()); cams = null; try{ String[] xxx = VideoInputFrameGrabber.getDeviceDescriptions(); @@ -600,27 +804,69 @@ public class CaptureView { reducewidth = ObsbotMeet2.Mode3.getWidth(); reduceheight = ObsbotMeet2.Mode3.getHeight(); } - image.SetGrabber(grabber, livewidth,liveheight,photowidth,photoheight,reducewidth,reduceheight); + image.SetGrabber(grabber, livewidth,liveheight,photowidth,photoheight,reducewidth,reduceheight, true); boolean use_face_detector = true; boolean use_qr_detector = true; LiveCamEvent lce = new LiveCamEvent() { @Override - public void onDetectedQRCode(String qrCode) { - qrCode = RemoveSpaces(qrCode); - if (ValidPatientID(qrCode)){ - String prefix = prefixfile.getText(); - if (!qrCode.equals(prefix)){ - String finalQrCode = qrCode; - System.out.println("PatientID detected: "+finalQrCode); - Platform.runLater(()->prefixfile.setText(finalQrCode)); - if (audioPlayer.isPlaying()) { - if (!audio_posisikan_muka.equals((audioPlayer.getCurrentFile()))){ - audioPlayer.StopCurrentPlayback(); + public void onDetectedQRCode(String barCode) { + barCode = RemoveSpaces(barCode); + if (ValidBarCode(barCode)){ + String prefix = barcodeData.getText(); + if (!barCode.equals(prefix)){ + String finalbarCode = barCode; + Platform.runLater(()-> barcodeData.setText(finalbarCode)); + Task checkpatientID = new Task<>() { + @Override + protected PatientRecord call() { + BarcodeResullt br = erhaAPI.Validate_Barcode(finalbarCode); + if (br!=null){ + if (br.message.startsWith("Records found")){ + if (br.data!=null && br.data.length>0){ + PatientRecord pr = br.data[0]; + if (!pr.medical_record_detail_id.isEmpty()){ + if (!pr.name.isEmpty()){ + super.succeeded(); + return pr; + } else System.out.println("PatientRecord name is empty"); + } else System.out.println("PatientRecord medical_record_detail_id is empty"); + } else System.out.println("BarcodeResullt data is empty"); + } else System.out.println("BarcodeResullt message is not Records found"); + } else System.out.println("BarcodeResullt is null"); + super.failed(); + return null; } - } - audioPlayer.PlayFile(audio_posisikan_muka, ps); + }; + + checkpatientID.setOnSucceeded(event -> { + PatientRecord pr = checkpatientID.getValue(); + if (pr!=null){ + int medrecid = toInt(pr.medical_record_detail_id); + medicalRecordID.setText(medrecid+""); + PatientName.setText(pr.name); + if (audioPlayer!=null && audioPlayer.isInited()){ + if (!audioPlayer.getCurrentFile().equals(audio_posisikan_muka)) { + audioPlayer.StopCurrentPlayback(); + Wait(200); + } + audioPlayer.PlayFile(audio_posisikan_muka, ps); + } + + } + }); + + checkpatientID.setOnFailed(event -> { + medicalRecordID.setText(""); + PatientName.setText(""); + barcodeData.setText(""); + System.out.println("checkpatientID failed"); + }); + + new Thread(checkpatientID).start(); + + } @@ -687,23 +933,21 @@ public class CaptureView { if (isTakingPhoto.get()) return; // other camera is taking picture System.out.println("Blink detected at camera "+title+" delay= "+counter); isTakingPhoto.set(true); - Platform.runLater(()->{ - - String prefix = prefixfile.getText(); - if (prefix.length()==10){ - System.out.println("Prefix valid, taking photo"); - btnTakePhoto.fire(); - } else { - System.out.println("Prefix not valid, not taking photo"); - isTakingPhoto.set(false); - if (audioPlayer.isPlaying()) { - if (!audio_scan_barcode.equals((audioPlayer.getCurrentFile()))){ - audioPlayer.StopCurrentPlayback(); - } + String prefix = medicalRecordID.getText(); + if (!prefix.isEmpty()){ + System.out.println("Prefix valid, taking photo"); + btnTakePhoto.fire(); + } else { + isTakingPhoto.set(false); + if (audioPlayer!=null && audioPlayer.isInited()){ + if (!audioPlayer.getCurrentFile().equals(audio_scan_barcode)) { + audioPlayer.StopCurrentPlayback(); + Wait(200); } audioPlayer.PlayFile(audio_scan_barcode, ps); } - }); + + } } @@ -916,7 +1160,10 @@ public class CaptureView { public void onUploadFinished(int total, int success, int failed, String[] files) { Logger.info("Upload Finished, Total: {}, Success: {}, Failed: {}", total, success, failed); Platform.runLater(()->{ - if (audioPlayer.isPlaying()) audioPlayer.StopCurrentPlayback(); + if (!audioPlayer.getCurrentFile().equals(audio_upload_berhasil)) { + audioPlayer.StopCurrentPlayback(); + Wait(200); + } audioPlayer.PlayFile(audio_upload_berhasil, ps); Alert Alert = new Alert(AlertType.INFORMATION); Alert.setTitle("Upload Finished"); diff --git a/src/main/java/id/co/gtc/erhacam/Detectors.java b/src/main/java/id/co/gtc/erhacam/Detectors.java index d2ca084..5cfed64 100644 --- a/src/main/java/id/co/gtc/erhacam/Detectors.java +++ b/src/main/java/id/co/gtc/erhacam/Detectors.java @@ -47,7 +47,7 @@ public class Detectors { private static void LoadFistDetector(){ String filename = SomeCodes.ExtractResource("/fist.xml"); if (filename!=null) { - System.out.println("Fist Detector file : " + filename); + Logger.info("Fist Detector file : " + filename); if (fistDetector ==null) { try{ @@ -64,7 +64,7 @@ public class Detectors { private static void LoadRightPalmDetector(){ String filename = SomeCodes.ExtractResource("/rpalm.xml"); if (filename!=null) { - System.out.println("Right Palm Detector file : " + filename); + Logger.info("Right Palm Detector file : " + filename); if (palmDetector ==null) { try{ @@ -81,7 +81,7 @@ public class Detectors { private static void LoadFrontalFaceDetector(){ String filename = SomeCodes.ExtractResource("/haarcascade_frontalface_default.xml"); if (filename!=null) { - System.out.println("Face Detector file : " + filename); + Logger.info("Face Detector file : " + filename); if (frontalfaceDetector==null) { try{ frontalfaceDetector = new CascadeClassifier(filename); @@ -97,7 +97,7 @@ public class Detectors { private static void LoadProfileFaceDetector(){ String filename = SomeCodes.ExtractResource("/haarcascade_profileface.xml"); if (filename!=null) { - System.out.println("Profile Face Detector file : " + filename); + Logger.info("Profile Face Detector file : " + filename); if (profilefaceDetector==null) { try{ profilefaceDetector = new CascadeClassifier(filename); @@ -113,7 +113,7 @@ public class Detectors { private static void LoadEyeDetector(){ String filename = SomeCodes.ExtractResource("/haarcascade_eye.xml"); if (filename!=null) { - System.out.println("Eye Detector file : " + filename); + Logger.info("Eye Detector file : " + filename); if (eyeDetector==null) { try{ @@ -200,14 +200,14 @@ public class Detectors { if (FaceminSize.width()!=value || FaceminSize.height()!=value) { FaceminSize = new Size(value, value); EyeminSize = new Size(value/EyetoFaceRatio, value/EyetoFaceRatio); - System.out.println("FaceMinSize changed to : " + FaceminSize.width()); - System.out.println("EyeMinSize changed to : " + EyeminSize.width()); + Logger.info("FaceMinSize changed to : " + FaceminSize.width()); + Logger.info("EyeMinSize changed to : " + EyeminSize.width()); } } else { FaceminSize = new Size(value, value); EyeminSize = new Size(value/EyetoFaceRatio, value/EyetoFaceRatio); - System.out.println("FaceMinSize created with value : " + FaceminSize.width()); - System.out.println("EyeMinSize created with value : " + EyeminSize.width()); + Logger.info("FaceMinSize created with value : " + FaceminSize.width()); + Logger.info("EyeMinSize created with value : " + EyeminSize.width()); } } @@ -217,14 +217,14 @@ public class Detectors { if (FacemaxSize.width()!=value || FacemaxSize.height()!=value) { FacemaxSize = new Size(value, value); EyemaxSize = new Size(value/EyetoFaceRatio, value/EyetoFaceRatio); - System.out.println("FaceMaxSize changed to : " + FacemaxSize.width()); - System.out.println("EyeMaxSize changed to : " + EyemaxSize.width()); + Logger.info("FaceMaxSize changed to : " + FacemaxSize.width()); + Logger.info("EyeMaxSize changed to : " + EyemaxSize.width()); } } else { FacemaxSize = new Size(value, value); EyemaxSize = new Size(value/EyetoFaceRatio, value/EyetoFaceRatio); - System.out.println("FaceMaxSize created with value : " + FacemaxSize.width()); - System.out.println("EyeMaxSize created with value : " + EyemaxSize.width()); + Logger.info("FaceMaxSize created with value : " + FacemaxSize.width()); + Logger.info("EyeMaxSize created with value : " + EyemaxSize.width()); } } diff --git a/src/main/java/id/co/gtc/erhacam/MainApplication.java b/src/main/java/id/co/gtc/erhacam/MainApplication.java index ff6f745..0af452b 100644 --- a/src/main/java/id/co/gtc/erhacam/MainApplication.java +++ b/src/main/java/id/co/gtc/erhacam/MainApplication.java @@ -1,42 +1,90 @@ package id.co.gtc.erhacam; import Config.SomeCodes; +import SecureDongle.SecureDongle; +import SecureDongle.SecureDongleEvent; import javafx.application.Application; +import javafx.application.Platform; import javafx.fxml.FXMLLoader; import javafx.geometry.Rectangle2D; import javafx.scene.Scene; +import javafx.scene.control.Alert; import javafx.stage.Screen; import javafx.stage.Stage; import org.tinylog.Logger; import java.io.IOException; +import static Config.SomeCodes.ShowAlert; import static Config.SomeCodes.config; public class MainApplication extends Application { @Override public void start(Stage stage) throws IOException { - FXMLLoader fxmlLoader = new FXMLLoader(MainApplication.class.getResource("main-view.fxml")); - Screen screen = Screen.getPrimary(); - Rectangle2D screenbound = screen.getVisualBounds(); - Scene scene = new Scene(fxmlLoader.load(), screenbound.getWidth(), screenbound.getHeight()); - stage.setTitle("MultiCam Capture App for ERHA 03022025-070"); - stage.setScene(scene); - stage.setResizable(true); - stage.setMaximized(true); - stage.setOnCloseRequest(e->{ - config.Save(); - MainView mainView = fxmlLoader.getController(); - mainView.Unload(); - Logger.info("Application closed"); - }); - SomeCodes.LoadQRReader(); - Detectors.LoadAllDetectors(); + SecureDongle sd = new SecureDongle((short)0x4B30, (short)0xA66C, (short)0x3109, (short)0x37B1); + if (sd.Find()){ + if (sd.Open()){ + String UserID = Integer.toHexString(sd.ReadUserID()) ; + sd.Close(); - stage.show(); + if (UserID.equals("14022025")){ + Logger.info("Secure Dongle UserID valid"); - Logger.info("Application started"); + FXMLLoader fxmlLoader = new FXMLLoader(MainApplication.class.getResource("main-view.fxml")); + Screen screen = Screen.getPrimary(); + Rectangle2D screenbound = screen.getVisualBounds(); + Scene scene = new Scene(fxmlLoader.load(), screenbound.getWidth(), screenbound.getHeight()); + stage.setTitle("MultiCam Capture App for ERHA 17022025-103"); + stage.setScene(scene); + stage.setResizable(true); + stage.setMaximized(true); + stage.setOnCloseRequest(e->{ + sd.StopMonitor(); + config.Save(); + MainView mainView = fxmlLoader.getController(); + mainView.Unload(); + Logger.info("Application closed"); + }); + SomeCodes.LoadQRReader(); + Detectors.LoadAllDetectors(); + + stage.show(); + + Logger.info("Application started"); + sd.setEvent(new SecureDongleEvent() { + @Override + public void onDongleMissing() { + Logger.error("Secure Dongle Missing"); + Platform.runLater(()->{ + ShowAlert(Alert.AlertType.ERROR, "Secure Dongle Missing", "Secure Dongle Missing", "Secure Dongle Missing"); + Platform.exit(); + }); + } + + @Override + public void onDongleError(String function, int errorCode) { + + } + }); + sd.StartMonitor(); + + } else { + ShowAlert(Alert.AlertType.ERROR, "Secure Dongle UserID not valid", "Secure Dongle UserID not valid", "Secure Dongle UserID not valid"); + Logger.error("Secure Dongle UserID not valid"); + Platform.exit(); + } + + } else { + ShowAlert(Alert.AlertType.ERROR, "Secure Dongle cannot be opened", "Secure Dongle cannot be opened", "Secure Dongle cannot be opened"); + Logger.error("Secure Dongle cannot be opened"); + Platform.exit(); + } + } else { + ShowAlert(Alert.AlertType.ERROR, "Secure Dongle not found", "Secure Dongle not found", "Secure Dongle not found"); + Logger.error("Secure Dongle not found"); + Platform.exit(); + } } @@ -45,5 +93,6 @@ public class MainApplication extends Application { SomeCodes.ExtractResource("/tinylog.properties"); launch(); + } } \ No newline at end of file diff --git a/src/main/java/id/co/gtc/erhacam/MainView.java b/src/main/java/id/co/gtc/erhacam/MainView.java index 1651a96..b0c19cd 100644 --- a/src/main/java/id/co/gtc/erhacam/MainView.java +++ b/src/main/java/id/co/gtc/erhacam/MainView.java @@ -92,8 +92,8 @@ public class MainView { currentcontroller = loader.getController(); } catch (Exception e) { - Logger.error("Unable to load " + fxmlfile + ", exception : " + e.getMessage()); + Logger.error("Unable to load " ,fxmlfile, ", exception : ", e.getMessage()); } - } else Logger.info("Not loading empty fxml file"); + } else Logger.error("loadContent Not loading empty fxml file"); } } \ No newline at end of file diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index b58d314..67050a3 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -15,11 +15,14 @@ module id.co.gtc.erhacam { requires org.tinylog.api; requires java.sql; requires javafx.graphics; + requires java.net.http; + opens id.co.gtc.erhacam to javafx.fxml; opens BASS to com.sun.jna; opens Config to com.google.gson; opens Database to javafx.base; + opens ErhaAPI to com.google.gson; exports id.co.gtc.erhacam; } \ No newline at end of file diff --git a/src/main/resources/id/co/gtc/erhacam/cameradetail.fxml b/src/main/resources/id/co/gtc/erhacam/cameradetail.fxml index 2174980..668a42b 100644 --- a/src/main/resources/id/co/gtc/erhacam/cameradetail.fxml +++ b/src/main/resources/id/co/gtc/erhacam/cameradetail.fxml @@ -5,7 +5,7 @@ - + @@ -46,15 +46,31 @@ - + - + - + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - diff --git a/src/main/resources/id/co/gtc/erhacam/cameradetail_landscape.fxml b/src/main/resources/id/co/gtc/erhacam/cameradetail_landscape.fxml new file mode 100644 index 0000000..2b72281 --- /dev/null +++ b/src/main/resources/id/co/gtc/erhacam/cameradetail_landscape.fxml @@ -0,0 +1,127 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/id/co/gtc/erhacam/capture-view.fxml b/src/main/resources/id/co/gtc/erhacam/capture-view.fxml index eb87cc5..11ad239 100644 --- a/src/main/resources/id/co/gtc/erhacam/capture-view.fxml +++ b/src/main/resources/id/co/gtc/erhacam/capture-view.fxml @@ -6,23 +6,35 @@ - + + + + + + + + + + + + + + + + + + + + - - - + - - - - - - + @@ -34,6 +46,8 @@ + + @@ -43,7 +57,7 @@ - @@ -53,7 +67,27 @@ -