@@ -60,15 +60,15 @@ private enum Mode {
6060
6161 // Scanner type enum
6262 private enum ScannerType {
63- ZXING ("ZXing" ),
63+ ZXING ("ZXing" ),
6464 DYNAMSOFT ("Dynamsoft Barcode Reader" );
65-
65+
6666 private final String displayName ;
67-
67+
6868 ScannerType (String displayName ) {
6969 this .displayName = displayName ;
7070 }
71-
71+
7272 @ Override
7373 public String toString () {
7474 return displayName ;
@@ -122,7 +122,7 @@ public String toString() {
122122 // Current overlay data
123123 private List <DetectedBarcode > currentOverlayBarcodes = new ArrayList <>();
124124 private final Object overlayLock = new Object ();
125-
125+
126126 // Remember last directory for file chooser
127127 private File lastDirectory ;
128128
@@ -210,7 +210,7 @@ private void initializeUI() {
210210
211211 // Enable overlay by default
212212 showOverlay = true ;
213-
213+
214214 // Enable drag-and-drop for file mode
215215 setupDragAndDrop ();
216216 }
@@ -294,7 +294,7 @@ private JPanel createControlPanel() {
294294 gbc .gridx = 0 ;
295295 gbc .gridy = 0 ;
296296 panel .add (new JLabel ("Scanner:" ), gbc );
297-
297+
298298 gbc .gridx = 1 ;
299299 scannerDropdown = new JComboBox <>(ScannerType .values ());
300300 scannerDropdown .setSelectedItem (currentScannerType );
@@ -359,11 +359,11 @@ private void onScannerChanged(ActionEvent e) {
359359 if (newType != currentScannerType ) {
360360 currentScannerType = newType ;
361361 logger .info ("Scanner changed to: {}" , currentScannerType );
362-
362+
363363 if (currentScannerType == ScannerType .DYNAMSOFT ) {
364- JOptionPane .showMessageDialog (this ,
365- "Dynamsoft Barcode Reader is not yet implemented.\n Currently using ZXing." ,
366- "Scanner Not Available" , JOptionPane .INFORMATION_MESSAGE );
364+ JOptionPane .showMessageDialog (this ,
365+ "Dynamsoft Barcode Reader is not yet implemented.\n Currently using ZXing." ,
366+ "Scanner Not Available" , JOptionPane .INFORMATION_MESSAGE );
367367 // Reset to ZXing
368368 currentScannerType = ScannerType .ZXING ;
369369 scannerDropdown .setSelectedItem (ScannerType .ZXING );
@@ -377,7 +377,7 @@ private void switchToFileMode() {
377377 cam .close ();
378378 logger .info ("Camera closed when switching to file mode" );
379379 }
380-
380+
381381 currentMode = Mode .FILE ;
382382 switchModeButton .setText ("Switch to Camera Mode" );
383383 loadFileButton .setVisible (true );
@@ -400,7 +400,7 @@ private void switchToCameraMode() {
400400 cam .setResolution (640 , 480 );
401401 logger .info ("Camera reopened for camera mode: {}x{}" , cam .getWidth (), cam .getHeight ());
402402 }
403-
403+
404404 currentMode = Mode .CAMERA ;
405405 switchModeButton .setText ("Switch to File Mode" );
406406 loadFileButton .setVisible (false );
@@ -409,44 +409,51 @@ private void switchToCameraMode() {
409409 clearOverlay ();
410410 repaintCamera ();
411411 updateStatus ();
412-
412+
413413 // Restart worker thread for camera mode
414414 startWorkerThread ();
415-
415+
416416 } catch (Exception e ) {
417417 logger .error ("Failed to switch to camera mode" , e );
418- JOptionPane .showMessageDialog (this , "Camera not available: " + e .getMessage (), "Error" , JOptionPane .ERROR_MESSAGE );
418+ JOptionPane .showMessageDialog (this , "Camera not available: " + e .getMessage (), "Error" ,
419+ JOptionPane .ERROR_MESSAGE );
419420 }
420421 }
421422
422423 private void loadImageFile (ActionEvent e ) {
423424 JFileChooser fileChooser = new JFileChooser ();
424-
425+
425426 // Remember the last directory
426427 if (lastDirectory != null && lastDirectory .exists ()) {
427428 fileChooser .setCurrentDirectory (lastDirectory );
428429 }
429-
430+
430431 fileChooser .setFileFilter (new FileNameExtensionFilter ("Image files" , "jpg" , "jpeg" , "png" , "bmp" , "gif" ));
431432
432433 if (fileChooser .showOpenDialog (this ) == JFileChooser .APPROVE_OPTION ) {
433434 File selectedFile = fileChooser .getSelectedFile ();
434-
435+
435436 // Remember the directory for next time
436437 lastDirectory = selectedFile .getParentFile ();
437-
438+
438439 try {
439440 fileImage = ImageIO .read (selectedFile );
440441 logger .info ("Loaded image: {}x{}" , fileImage .getWidth (), fileImage .getHeight ());
441442
442443 // Perform immediate scan on loaded image and display overlay
443444 List <DetectedBarcode > detections = detectBarcodes (fileImage );
444445
446+ // Update both overlay and latest results for rendering thread
445447 synchronized (overlayLock ) {
446448 currentOverlayBarcodes .clear ();
447449 currentOverlayBarcodes .addAll (detections );
448450 }
449451
452+ synchronized (resultsLock ) {
453+ latestBarcodeResults .clear ();
454+ latestBarcodeResults .addAll (detections );
455+ }
456+
450457 updateResultsDisplay (detections );
451458 repaintCamera ();
452459
@@ -482,7 +489,7 @@ private void startWorkerThread() {
482489 synchronized (resultsLock ) {
483490 latestBarcodeResults = new ArrayList <>(detections );
484491 }
485-
492+
486493 // Update results display if there are new detections
487494 if (!detections .isEmpty ()) {
488495 updateResultsDisplay (detections );
@@ -509,7 +516,8 @@ private void startRenderingThread() {
509516 currentResults = new ArrayList <>(latestBarcodeResults );
510517 }
511518
512- // Update overlay with current results (even if empty to clear overlay when no barcodes)
519+ // Update overlay with current results (even if empty to clear overlay when no
520+ // barcodes)
513521 synchronized (overlayLock ) {
514522 currentOverlayBarcodes .clear ();
515523 currentOverlayBarcodes .addAll (currentResults );
@@ -551,7 +559,7 @@ private List<DetectedBarcode> detectWithZXing(BufferedImage image) {
551559 try {
552560 LuminanceSource source = new BufferedImageLuminanceSource (image );
553561 BinaryBitmap bitmap = new BinaryBitmap (new HybridBinarizer (source ));
554-
562+
555563 // Try to detect multiple barcodes first
556564 try {
557565 Result [] results = multiReader .decodeMultiple (bitmap );
@@ -568,7 +576,7 @@ private List<DetectedBarcode> detectWithZXing(BufferedImage image) {
568576 } catch (NotFoundException e ) {
569577 // No multiple barcodes found, try single barcode detection
570578 }
571-
579+
572580 // Fallback to single barcode detection
573581 try {
574582 Result result = zxingReader .decode (bitmap );
@@ -789,20 +797,20 @@ public void drop(DropTargetDropEvent dtde) {
789797 try {
790798 dtde .acceptDrop (DnDConstants .ACTION_COPY );
791799 Transferable transferable = dtde .getTransferable ();
792-
800+
793801 if (transferable .isDataFlavorSupported (DataFlavor .javaFileListFlavor )) {
794802 @ SuppressWarnings ("unchecked" )
795803 List <File > files = (List <File >) transferable .getTransferData (DataFlavor .javaFileListFlavor );
796-
804+
797805 if (!files .isEmpty ()) {
798806 File file = files .get (0 ); // Take the first file
799807 if (isImageFile (file )) {
800808 loadImageFromFile (file );
801809 dtde .dropComplete (true );
802810 } else {
803- JOptionPane .showMessageDialog (BarcodeScanner .this ,
804- "Please drop an image file (jpg, jpeg, png, bmp, gif, tiff)" ,
805- "Invalid File Type" , JOptionPane .WARNING_MESSAGE );
811+ JOptionPane .showMessageDialog (BarcodeScanner .this ,
812+ "Please drop an image file (jpg, jpeg, png, bmp, gif, tiff)" ,
813+ "Invalid File Type" , JOptionPane .WARNING_MESSAGE );
806814 dtde .dropComplete (false );
807815 }
808816 } else {
@@ -818,30 +826,36 @@ public void drop(DropTargetDropEvent dtde) {
818826 }
819827 });
820828 }
821-
829+
822830 private boolean isImageFile (File file ) {
823831 String name = file .getName ().toLowerCase ();
824- return name .endsWith (".jpg" ) || name .endsWith (".jpeg" ) ||
825- name .endsWith (".png" ) || name .endsWith (".bmp" ) ||
826- name .endsWith (".gif" ) || name .endsWith (".tiff" );
832+ return name .endsWith (".jpg" ) || name .endsWith (".jpeg" ) ||
833+ name .endsWith (".png" ) || name .endsWith (".bmp" ) ||
834+ name .endsWith (".gif" ) || name .endsWith (".tiff" );
827835 }
828-
836+
829837 private void loadImageFromFile (File file ) {
830838 try {
831839 // Remember the directory for next time
832840 lastDirectory = file .getParentFile ();
833-
841+
834842 fileImage = ImageIO .read (file );
835843 logger .info ("Loaded image via drag-and-drop: {}x{}" , fileImage .getWidth (), fileImage .getHeight ());
836844
837845 // Perform immediate scan on loaded image and display overlay
838846 List <DetectedBarcode > detections = detectBarcodes (fileImage );
839847
848+ // Update both overlay and latest results for rendering thread
840849 synchronized (overlayLock ) {
841850 currentOverlayBarcodes .clear ();
842851 currentOverlayBarcodes .addAll (detections );
843852 }
844853
854+ synchronized (resultsLock ) {
855+ latestBarcodeResults .clear ();
856+ latestBarcodeResults .addAll (detections );
857+ }
858+
845859 updateResultsDisplay (detections );
846860 repaintCamera ();
847861
0 commit comments