From eac22e1c91b43dd6564ace4616d688b87c3ba98b Mon Sep 17 00:00:00 2001 From: Astatin3 <77305074+Astatin3@users.noreply.github.com> Date: Thu, 4 Apr 2024 14:48:29 -0600 Subject: [PATCH] Make QR Codes Better --- .../astatin3/scoutingapp2025/fileEditor.java | 55 ++++++++++-- .../scoutingapp2025/qrPointsOverlayView.java | 53 ----------- .../ui/transfer/TransferFragment.java | 4 +- .../ui/transfer/generatorView.java | 75 ++++++++++------ .../ui/transfer/qrOverlayView.java | 88 +++++++++++++++++++ .../ui/transfer/scannerView.java | 79 ++++++++++++----- app/src/main/res/layout/fragment_transfer.xml | 10 +-- 7 files changed, 247 insertions(+), 117 deletions(-) delete mode 100644 app/src/main/java/com/astatin3/scoutingapp2025/qrPointsOverlayView.java create mode 100644 app/src/main/java/com/astatin3/scoutingapp2025/ui/transfer/qrOverlayView.java diff --git a/app/src/main/java/com/astatin3/scoutingapp2025/fileEditor.java b/app/src/main/java/com/astatin3/scoutingapp2025/fileEditor.java index d2eb44d..0d5171e 100644 --- a/app/src/main/java/com/astatin3/scoutingapp2025/fileEditor.java +++ b/app/src/main/java/com/astatin3/scoutingapp2025/fileEditor.java @@ -1,19 +1,18 @@ package com.astatin3.scoutingapp2025; import android.content.Context; +import android.util.Log; import com.astatin3.scoutingapp2025.Utils.frcMatch; import com.astatin3.scoutingapp2025.Utils.frcTeam; import java.io.ByteArrayOutputStream; -import java.io.File; import java.io.IOException; import java.io.OutputStreamWriter; import java.nio.BufferOverflowException; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.ArrayList; -import java.util.Arrays; import java.util.zip.DataFormatException; import java.util.zip.Deflater; import java.util.zip.Inflater; @@ -21,6 +20,9 @@ import java.util.zip.Inflater; public final class fileEditor { // private final static String baseDir = android.os.Environment.getExternalStorageDirectory().getAbsolutePath(); public static final byte internalDataVersion = 0x01; + public static final int maxCompressedBlockSize = 4096; + + public static String binaryVisualize(byte[] bytes){ String returnStr = ""; @@ -33,7 +35,9 @@ public final class fileEditor { return returnStr; } - public static char toChar(int num){ + + + public static char byteToChar(int num){ if(num < 0 || num > 255){ throw new BufferOverflowException(); } @@ -42,18 +46,55 @@ public final class fileEditor { return new String(bytes, Charset.defaultCharset()).charAt(0); } - public static int fromChar(char c){ + + + public static byte[] toBytes(int num, int byteCount){ + if(num < 0 || num > (Math.pow(2,byteCount*8)-1)){ + throw new BufferOverflowException(); + } + byte[] bytes = new byte[byteCount]; + for(int i=0;i> (i*8)); + } + return bytes; + } + + + + public static int fromBytes(byte[] bytes, int byteCount){ + int returnInt = 0; + for(int i=0;i hints = new EnumMap(EncodeHintType.class); hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); - hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L); // H = 30% damage + hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); // H = 30% damage // hints.put(EncodeHintType.QR_COMPACT, true); hints.put(EncodeHintType.MARGIN, 0); /* default = 4 */ - int size = 200; + int size = 512; BitMatrix bitMatrix = qrCodeWriter.encode(myCodeText, BarcodeFormat.QR_CODE, size, size, hints); @@ -99,31 +96,48 @@ public class generatorView extends ConstraintLayout { } public void start(FragmentTransferBinding binding, String inputData){ + start(binding, inputData.getBytes(StandardCharsets.ISO_8859_1)); + } + public void start(FragmentTransferBinding binding, byte[] inputData){ qrImage = binding.qrImage; qrSpeedSlider = binding.qrSpeedSlider; qrSizeSlider = binding.qrSizeSlider; qrIndexN = binding.qrIndexN; qrIndexD = binding.qrIndexD; - String compiledData = null; -// try { - byte[] tempData = fileEditor.compress(inputData.getBytes(StandardCharsets.ISO_8859_1)); - compiledData = new String(tempData, StandardCharsets.ISO_8859_1); -// alert(""+tempData.length, fileEditor.binaryVisualize(tempData)); -// Log.i("Info", fileEditor.binaryVisualize(tempData)); +// byte[] randomData = new byte[4596]; +// new Random().nextBytes(randomData); +// inputData = randomData; -// }catch (UnsupportedEncodingException e){ -// e.printStackTrace(); -// } - alert(""+compiledData.length(), compiledData); + String compiledData = ""; - if(compiledData == null || inputData.length() < compiledData.length()){ - sendData(inputData); - }else{ - sendData(compiledData); + for(int i=0;i inputData.length) { + end = inputData.length; + } + + byte[] dataBlock = fileEditor.getByteBlock(inputData, start, end); + + final String compressedBlock = + new String( + fileEditor.compress(dataBlock), + StandardCharsets.ISO_8859_1); + + compiledData += + new String( + fileEditor.toBytes(compressedBlock.length(), 2), + StandardCharsets.ISO_8859_1) + + + compressedBlock; } +// byte[] tempData = fileEditor.compress(inputData); +// String compiledData = new String(tempData, StandardCharsets.ISO_8859_1); + + sendData(compiledData); } private void alert(String title, String content) { @@ -137,7 +151,8 @@ public class generatorView extends ConstraintLayout { private void sendData(String data){ - minQrSize = Math.round(data.length()/maxQrCount); +// minQrSize = 0; + minQrSize = Math.round(data.length()/maxQrCount)+1; qrSizeSlider.setMax(maxQrSize-minQrSize); qrSpeedSlider.setMax((minQrSpeed-maxQrSpeed)*2); @@ -165,8 +180,9 @@ public class generatorView extends ConstraintLayout { public void onStartTrackingTouch(SeekBar seekBar) {} @Override public void onStopTrackingTouch(SeekBar seekBar) { - qrSize = seekBar.getProgress() + minQrSpeed; - qrCount = (data.length()/qrSize)+1; + qrSize = seekBar.getProgress() + minQrSize; +// qrCount = (int)Math.ceil((double) (data.length()+1)/qrSize); + qrCount = (int)((data.length()+1)/qrSize)+1; qrIndexD.setText(String.valueOf(qrCount)); sendData(data); } @@ -175,6 +191,9 @@ public class generatorView extends ConstraintLayout { qrSpeedSlider.setProgress(defaultQrDelay+5); qrBitmaps = new ArrayList(); + + int randID = new Random().nextInt(255); + for(int i=0;i<=((data.length()+1)/qrSize);i++){ final int start = i*qrSize; int end = (i+1)*qrSize; @@ -184,9 +203,10 @@ public class generatorView extends ConstraintLayout { try { // alert("test", ""+Math.ceil((double)data.length()/(double)qrSize)); qrBitmaps.add(generateQrCode( - String.valueOf(fileEditor.toChar(fileEditor.internalDataVersion)) + - String.valueOf(fileEditor.toChar(i)) + - String.valueOf(fileEditor.toChar(qrCount-1)) + + String.valueOf(fileEditor.byteToChar(fileEditor.internalDataVersion)) + + String.valueOf(fileEditor.byteToChar(randID)) + + String.valueOf(fileEditor.byteToChar(i)) + + String.valueOf(fileEditor.byteToChar(qrCount-1)) + data.substring(start, end) )); }catch (WriterException e){ @@ -202,6 +222,7 @@ public class generatorView extends ConstraintLayout { private void updateQr(){ qrImage.setImageBitmap(qrBitmaps.get(qrIndex)); + Log.i("test", qrIndex+", "+qrCount); if(qrDelay > 0) { this.qrIndex += 1; if (this.qrIndex >= this.qrCount) { diff --git a/app/src/main/java/com/astatin3/scoutingapp2025/ui/transfer/qrOverlayView.java b/app/src/main/java/com/astatin3/scoutingapp2025/ui/transfer/qrOverlayView.java new file mode 100644 index 0000000..c934fdb --- /dev/null +++ b/app/src/main/java/com/astatin3/scoutingapp2025/ui/transfer/qrOverlayView.java @@ -0,0 +1,88 @@ +package com.astatin3.scoutingapp2025.ui.transfer; + +// From https://github.com/dlazaro66/QRCodeReaderView/blob/master/samples/src/main/java/com/example/qr_readerexample/PointsOverlayView.java + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.PointF; +import android.graphics.Rect; +import android.util.AttributeSet; +import android.view.View; + +public class qrOverlayView extends View { + + PointF[] points; + int[] barColors; + private Paint paint; + private final int barHeight = 50; + private final int barMargin = 5; + + public qrOverlayView(Context context) { + super(context); + init(); + } + + public qrOverlayView(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + public qrOverlayView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(); + } + + private void init() { + paint = new Paint(); + paint.setColor(Color.YELLOW); + paint.setStyle(Paint.Style.FILL); + } + + public void setPoints(PointF[] points) { + this.points = points; + invalidate(); + } + + public void setBar(int[] barColors){ + this.barColors = barColors; + invalidate(); + } + + @Override + public void draw(Canvas canvas) { + super.draw(canvas); + if (points != null) { + for (PointF pointF : points) { + canvas.drawCircle(pointF.x, pointF.y, 10, paint); + } + } + if(barColors != null){ + final int width = (int)(getWidth()/barColors.length); + + final int top = 0; + final int bottom = barHeight; + + for(int i=0;i= qrCount){ + qrOverlayView.setBar(barColors); + + if(updated && count >= qrCount){ // I guess String.join does not like non-ascii text String compiledData = ""; @@ -128,13 +145,31 @@ public class scannerView extends ConstraintLayout { try { byte[] compiledBytes = compiledData.getBytes(StandardCharsets.ISO_8859_1); - alert("completed", new String(fileEditor.decompress(compiledBytes), StandardCharsets.ISO_8859_1)); -// alert(""+compiledBytes.length, fileEditor.binaryVisualize(compiledBytes)); -// Log.i("Info", fileEditor.binaryVisualize(compiledBytes)); +// alert("completed", new String(fileEditor.decompress(compiledBytes), StandardCharsets.ISO_8859_1)); + alert("completed", blockUncompress(compiledBytes)); }catch (Exception e){ -// alert("completed", compiledData); e.printStackTrace(); } } } + + private static String blockUncompress(byte[] data) throws DataFormatException { + String uncompressedData = ""; + int curIndex = 0; + while(curIndex < data.length){ + final int blockLength = fileEditor.fromBytes(fileEditor.getByteBlock(data, curIndex, curIndex+2), 2); + + Log.i("test", ""+blockLength); + + uncompressedData += new String( + fileEditor.decompress( + fileEditor.getByteBlock( + data, curIndex+2, curIndex+blockLength+2) + ), StandardCharsets.ISO_8859_1 + ); + + curIndex += blockLength+2; + } + return uncompressedData; + } } diff --git a/app/src/main/res/layout/fragment_transfer.xml b/app/src/main/res/layout/fragment_transfer.xml index 105c41a..7fccc2a 100644 --- a/app/src/main/res/layout/fragment_transfer.xml +++ b/app/src/main/res/layout/fragment_transfer.xml @@ -134,13 +134,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:visibility="gone" - tools:visibility="gone"> - - - + tools:visibility="gone" /> + tools:visibility="gone">