Make the camera much faster

This commit is contained in:
Astatin3
2024-04-07 17:31:36 -06:00
parent 3365a2ce99
commit bf64f8f6d1
6 changed files with 261 additions and 305 deletions
@@ -1,165 +0,0 @@
package com.astatin3.scoutingapp2025;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.ImageFormat;
import android.graphics.YuvImage;
import android.media.Image;
import android.renderscript.Allocation;
import android.renderscript.Element;
import android.renderscript.RenderScript;
import android.renderscript.ScriptIntrinsicYuvToRGB;
import android.renderscript.Type;
import androidx.annotation.Nullable;
import java.nio.ByteBuffer;
public class YuvConvertor {
private final Allocation in, out;
private final ScriptIntrinsicYuvToRGB script;
public YuvConvertor(Context context, int width, int height) {
RenderScript rs = RenderScript.create(context);
this.script = ScriptIntrinsicYuvToRGB.create(
rs, Element.U8_4(rs));
// NV21 YUV image of dimension 4 X 4 has following packing:
// YYYYYYYYYYYYYYYYVUVUVUVU
// With each pixel (of any channel) taking 8 bits.
int yuvByteArrayLength = (int) (width * height * 1.5f);
Type.Builder yuvType = new Type.Builder(rs, Element.U8(rs))
.setX(yuvByteArrayLength);
this.in = Allocation.createTyped(
rs, yuvType.create(), Allocation.USAGE_SCRIPT);
Type.Builder rgbaType = new Type.Builder(rs, Element.RGBA_8888(rs))
.setX(width)
.setY(height);
this.out = Allocation.createTyped(
rs, rgbaType.create(), Allocation.USAGE_SCRIPT);
}
public Bitmap toBitmap(Image image) {
if (image.getFormat() != ImageFormat.YUV_420_888) {
throw new IllegalArgumentException("Only supports YUV_420_888.");
}
byte[] yuvByteArray = toNv21(image);
in.copyFrom(yuvByteArray);
script.setInput(in);
script.forEach(out);
// Allocate memory for the bitmap to return. If you have a reusable Bitmap
// I recommending using that.
Bitmap bitmap = Bitmap.createBitmap(
image.getWidth(), image.getHeight(), Bitmap.Config.ARGB_8888);
out.copyTo(bitmap);
return bitmap;
}
private byte[] toNv21(Image image) {
int width = image.getWidth();
int height = image.getHeight();
// Order of U/V channel guaranteed, read more:
// https://developer.android.com/reference/android/graphics/ImageFormat#YUV_420_888
Image.Plane yPlane = image.getPlanes()[0];
Image.Plane uPlane = image.getPlanes()[1];
Image.Plane vPlane = image.getPlanes()[2];
ByteBuffer yBuffer = yPlane.getBuffer();
ByteBuffer uBuffer = uPlane.getBuffer();
ByteBuffer vBuffer = vPlane.getBuffer();
// Full size Y channel and quarter size U+V channels.
int numPixels = (int) (width * height * 1.5f);
byte[] nv21 = new byte[numPixels];
int idY = 0;
int idUV = width * height;
int uvWidth = width / 2;
int uvHeight = height / 2;
// Copy Y & UV channel.
// NV21 format is expected to have YYYYVU packaging.
// The U/V planes are guaranteed to have the same row stride and pixel stride.
int uvRowStride = uPlane.getRowStride();
int uvPixelStride = uPlane.getPixelStride();
int yRowStride = yPlane.getRowStride();
int yPixelStride = yPlane.getPixelStride();
for(int y = 0; y < height; ++y) {
int yOffset = y * yRowStride;
int uvOffset = y * uvRowStride;
for (int x = 0; x < width; ++x) {
nv21[idY++] = yBuffer.get(yOffset + x * yPixelStride);
if (y < uvHeight && x < uvWidth) {
int bufferIndex = uvOffset + (x * uvPixelStride);
// V channel.
nv21[idUV++] = vBuffer.get(bufferIndex);
// U channel.
nv21[idUV++] = uBuffer.get(bufferIndex);
}
}
}
return nv21;
}
YuvImage toYuvImage(Image image) {
if (image.getFormat() != ImageFormat.YUV_420_888) {
throw new IllegalArgumentException("Invalid image format");
}
int width = image.getWidth();
int height = image.getHeight();
// Order of U/V channel guaranteed, read more:
// https://developer.android.com/reference/android/graphics/ImageFormat#YUV_420_888
Image.Plane yPlane = image.getPlanes()[0];
Image.Plane uPlane = image.getPlanes()[1];
Image.Plane vPlane = image.getPlanes()[2];
ByteBuffer yBuffer = yPlane.getBuffer();
ByteBuffer uBuffer = uPlane.getBuffer();
ByteBuffer vBuffer = vPlane.getBuffer();
// Full size Y channel and quarter size U+V channels.
int numPixels = (int) (width * height * 1.5f);
byte[] nv21 = new byte[numPixels];
int index = 0;
// Copy Y channel.
int yRowStride = yPlane.getRowStride();
int yPixelStride = yPlane.getPixelStride();
for(int y = 0; y < height; ++y) {
for (int x = 0; x < width; ++x) {
nv21[index++] = yBuffer.get(y * yRowStride + x * yPixelStride);
}
}
// Copy VU data; NV21 format is expected to have YYYYVU packaging.
// The U/V planes are guaranteed to have the same row stride and pixel stride.
int uvRowStride = uPlane.getRowStride();
int uvPixelStride = uPlane.getPixelStride();
int uvWidth = width / 2;
int uvHeight = height / 2;
for(int y = 0; y < uvHeight; ++y) {
for (int x = 0; x < uvWidth; ++x) {
int bufferIndex = (y * uvRowStride) + (x * uvPixelStride);
// V channel.
nv21[index++] = vBuffer.get(bufferIndex);
// U channel.
nv21[index++] = uBuffer.get(bufferIndex);
}
}
return new YuvImage(
nv21, ImageFormat.NV21, width, height, /* strides= */ null);
}
}
@@ -37,12 +37,7 @@ public final class fileEditor {
public static char byteToChar(int num){ public static char byteToChar(int num){
if(num < 0 || num > 255){ return new String(toBytes(num, 1), StandardCharsets.UTF_8).charAt(0);
throw new BufferOverflowException();
}
byte[] bytes = new byte[1];
bytes[0] = (byte) num;
return new String(bytes, Charset.defaultCharset()).charAt(0);
} }
@@ -0,0 +1,67 @@
package com.astatin3.scoutingapp2025;
import android.graphics.Bitmap;
import android.os.AsyncTask;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.ChecksumException;
import com.google.zxing.DecodeHintType;
import com.google.zxing.FormatException;
import com.google.zxing.NotFoundException;
import com.google.zxing.RGBLuminanceSource;
import com.google.zxing.Reader;
import com.google.zxing.Result;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.QRCodeReader;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
public class qrScanTask extends AsyncTask<String, String, String>{
private Function<String, String> resultFunction = null;
private Bitmap image;
@Override
protected String doInBackground(String... str) {
if(image == null){return null;}
int width = image.getWidth();
int height = image.getHeight();
int[] pixels = new int[width * height];
image.getPixels(pixels, 0, width, 0, 0, width, height);
RGBLuminanceSource source = new RGBLuminanceSource(width, height, pixels);
BinaryBitmap binaryBitmap = new BinaryBitmap(new HybridBinarizer(source));
Map<DecodeHintType, Object> hints = new HashMap<>();
hints.put(DecodeHintType.CHARACTER_SET, "UTF-8");
// hints.put(DecodeHintType.PURE_BARCODE, Boolean.TRUE);
hints.put(DecodeHintType.POSSIBLE_FORMATS, EnumSet.of(BarcodeFormat.QR_CODE));
Reader reader = new QRCodeReader();
try {
Result result = reader.decode(binaryBitmap, hints);
return result.getText();
} catch (NotFoundException | ChecksumException | FormatException e) {
e.printStackTrace();
}
return null;
}
public void setImage(Bitmap image){this.image = image;}
public void onResult(Function<String, String> func) {
this.resultFunction = func;
}
@Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
if(resultFunction != null){
resultFunction.apply(result);
}
}
}
@@ -78,7 +78,7 @@ public class generatorView extends ConstraintLayout {
// The Charset must be UTF-8, Or data will not be transferred properly. IDK why. // The Charset must be UTF-8, Or data will not be transferred properly. IDK why.
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L); hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
hints.put(EncodeHintType.MARGIN, 0); /* default = 4 */ hints.put(EncodeHintType.MARGIN, 0); /* default = 4 */
MultiFormatWriter writer = new MultiFormatWriter(); MultiFormatWriter writer = new MultiFormatWriter();
@@ -1,35 +1,17 @@
package com.astatin3.scoutingapp2025.ui.transfer; package com.astatin3.scoutingapp2025.ui.transfer;
import static android.view.Surface.ROTATION_0;
import static androidx.core.math.MathUtils.clamp; import static androidx.core.math.MathUtils.clamp;
import android.app.ActionBar;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.content.Context; import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.ImageFormat;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.YuvImage;
import android.media.Image; import android.media.Image;
import android.os.Handler; import android.os.Handler;
import android.os.SystemClock;
import android.renderscript.Element;
import android.renderscript.RenderScript;
import android.renderscript.ScriptIntrinsicYuvToRGB; import android.renderscript.ScriptIntrinsicYuvToRGB;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.Log; import android.util.Log;
import android.util.Size;
import android.view.Surface; import android.view.Surface;
import android.view.View; import android.widget.SeekBar;
import android.widget.FrameLayout;
import android.widget.ImageView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.OptIn; import androidx.annotation.OptIn;
@@ -40,30 +22,25 @@ import androidx.camera.core.ExperimentalGetImage;
import androidx.camera.core.ImageAnalysis; import androidx.camera.core.ImageAnalysis;
import androidx.camera.core.ImageProxy; import androidx.camera.core.ImageProxy;
import androidx.camera.core.Preview; import androidx.camera.core.Preview;
import androidx.camera.core.impl.CameraFilters;
import androidx.camera.lifecycle.ProcessCameraProvider; import androidx.camera.lifecycle.ProcessCameraProvider;
import androidx.constraintlayout.widget.ConstraintLayout; import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleOwner; import androidx.lifecycle.LifecycleOwner;
import com.astatin3.scoutingapp2025.YuvConvertor;
import com.astatin3.scoutingapp2025.databinding.FragmentTransferBinding; import com.astatin3.scoutingapp2025.databinding.FragmentTransferBinding;
import com.astatin3.scoutingapp2025.fileEditor; import com.astatin3.scoutingapp2025.fileEditor;
import com.astatin3.scoutingapp2025.qrScanTask;
import com.dlazaro66.qrcodereaderview.QRCodeReaderView; import com.dlazaro66.qrcodereaderview.QRCodeReaderView;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.function.Function;
import java.util.zip.DataFormatException; import java.util.zip.DataFormatException;
//public class scannerView extends androidx.appcompat.widget.AppCompatImageView { //public class scannerView extends androidx.appcompat.widget.AppCompatImageView {
@@ -78,7 +55,6 @@ public class scannerView extends ConstraintLayout {
private qrOverlayView qrOverlayView; private qrOverlayView qrOverlayView;
private Handler uiHandler; private Handler uiHandler;
private ScriptIntrinsicYuvToRGB script; private ScriptIntrinsicYuvToRGB script;
private YuvConvertor yuvConvertor;
// private class codeReadListener implements QRCodeReaderView.OnQRCodeReadListener { // private class codeReadListener implements QRCodeReaderView.OnQRCodeReadListener {
// @Override // @Override
@@ -115,114 +91,153 @@ public class scannerView extends ConstraintLayout {
} }
private float scale = 0; private float scale = 0;
private double threshhold = 0.5;
private FragmentTransferBinding binding; private FragmentTransferBinding binding;
private LifecycleOwner lifecycle; private LifecycleOwner lifecycle;
private void setImage(Bitmap bmp){ private void setImage(Bitmap bmp){
if(scale == 0) { if(scale == 0) {
scale = ((float) ((View) getParent()).getWidth() / bmp.getWidth()) * ((float) 16 / 9); scale = ((float) getWidth() / bmp.getWidth()) * ((float) 16 / 9);
setScaleX(scale); binding.scannerImage.setTranslationX(0);
setScaleY(scale); binding.scannerImage.setTranslationY(0);
// binding.scannerImage.setScaleX(scale);
// binding.scannerImage.setScaleY(scale);
} }
scanQRCode(bmp);
binding.scannerImage.setImageBitmap(bmp); binding.scannerImage.setImageBitmap(bmp);
binding.scannerThreshold.bringToFront(); binding.scannerThreshold.bringToFront();
// alert("test", getChildCount()+"");
} }
private Bitmap toGreyscale(Bitmap originalBitmap){ // private Bitmap img
int width = originalBitmap.getWidth();
int height = originalBitmap.getHeight();
Bitmap oneBitBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); int[] levelMap = new int[256];
Canvas canvas = new Canvas(oneBitBitmap); private void recalcMap(){
Paint paint = new Paint(); for (int i = 0; i < 256; i++) {
paint.setColorFilter(new ColorMatrixColorFilter(new ColorMatrix(new float[] { levelMap[i] = clamp(
0.299f, 0.587f, 0.114f, 0, 0, (clamp(
0.299f, 0.587f, 0.114f, 0, 0, i-thresholdOffset, 0, 255) / (256 / numColors)) * (256 / numColors
0.299f, 0.587f, 0.114f, 0, 0, )+brightness, 0, 255
0, 0, 0, 1, 0 );
}))); }
}
canvas.drawBitmap(originalBitmap, 0, 0, paint); private Bitmap toGreyscale(Image image){
// Turns out the "Y" In YUV is the Luminance of the pixel.
// Makes converting to greyscale 1000x easier
ByteBuffer yBuffer = image.getPlanes()[0].getBuffer();
final int width = image.getWidth();
final int height = image.getHeight();
int[] pixels = new int[width * height]; int[] pixels = new int[width * height];
oneBitBitmap.getPixels(pixels, 0, width, 0, 0, width, height); for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int[] oneBitPixels = new int[width * height]; // int L = levelMap[clamp((yBuffer.get() & 0xff) - thresholdOffset, 0, 255)];
int threshold = 128; // Adjust this value to change the threshold // int L = clamp(levelMap[yBuffer.get() & 0xff]-thresholdOffset, 0, 255);
int L = levelMap[yBuffer.get() & 0xff];
for (int i = 0; i < pixels.length; i++) { pixels[y * width + x] = 0xff000000 | (L << 16) | (L << 8) | L;
int pixel = pixels[i]; // if(L > threshold) {
int red = Color.red(pixel); // pixels[y * width + x] = 0xffffffff;
int green = Color.green(pixel); // }else{
int blue = Color.blue(pixel); // pixels[y * width + x] = 0xff000000;
int average = (red + green + blue) / 3; // }
oneBitPixels[i] = (average > threshold) ? Color.WHITE : Color.BLACK; // pixels[y * width + x] = levelMap[L];
}
} }
oneBitBitmap.setPixels(oneBitPixels, 0, width, 0, 0, width, height); Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
return oneBitBitmap; return bitmap;
} }
public void scanQRCode(Bitmap bitmap) {
qrScanTask async = new qrScanTask();
async.setImage(bitmap);
async.onResult(new Function<String, String>() {
@Override
public String apply(String data) {
if(data != null){
// alert("test", ""+fileEditor.byteFromChar(data.charAt(0)));
compileData(
fileEditor.byteFromChar(data.charAt(0)),
fileEditor.byteFromChar(data.charAt(1)),
fileEditor.byteFromChar(data.charAt(2)),
(fileEditor.byteFromChar(data.charAt(3))+1),
data.substring(4)
);
}
return null;
}
});
async.execute();
// return contents;
}
private int numColors = 3;
private int thresholdOffset = 128;
private int brightness = 128;
public void start(FragmentTransferBinding binding, LifecycleOwner lifecycle){ public void start(FragmentTransferBinding binding, LifecycleOwner lifecycle){
this.binding = binding; this.binding = binding;
this.lifecycle = lifecycle; this.lifecycle = lifecycle;
yuvConvertor = new YuvConvertor(getContext(), 1280, 720);
uiHandler = new Handler(); uiHandler = new Handler();
// IntentIntegrator integrator = IntentIntegrator.forSupportFragment(TransferFragment);
// integrator.setPrompt("Scan a QR code"); binding.scannerThreshold.setProgress(thresholdOffset);
// integrator.setBeepEnabled(true); binding.scannerThreshold.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
// integrator.setOrientationLocked(true); @Override
// integrator.setCaptureActivity(CaptureActivity.class); public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
// integrator.initiateScan(); thresholdOffset = 127-progress;
recalcMap();
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {}
});
binding.scannerThreshold.setMax(255);
binding.scannerColors.setProgress(numColors);
binding.scannerColors.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
numColors = 18-(progress-2);
recalcMap();
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {}
});
binding.scannerColors.setMax(18);
binding.scannerBrightness.setProgress(brightness);
binding.scannerBrightness.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
brightness = progress-128;
recalcMap();
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {}
});
binding.scannerBrightness.setMax(256);
// ScanOptions options = new ScanOptions(); recalcMap();
// options.setDesiredBarcodeFormats(ScanOptions.QR_CODE);
// options.setPrompt("Scan a barcode");
// options.setCameraId(0); // Use a specific camera of the device
// options.setBeepEnabled(false);
// options.setBarcodeImageEnabled(true);
// barcodeLauncher.launch(options);
// qrCodeReaderView = new QRCodeReaderView(getContext()); qrOverlayView = new qrOverlayView(getContext());
// this.addView(qrCodeReaderView); qrOverlayView.bringToFront();
// ConstraintLayout.LayoutParams qrCodeReaderViewParams = (ConstraintLayout.LayoutParams) qrCodeReaderView.getLayoutParams(); ConstraintLayout.LayoutParams pointsOverlayViewParams = new ConstraintLayout.LayoutParams(
// qrCodeReaderViewParams.width = ActionBar.LayoutParams.MATCH_PARENT; LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT
// qrCodeReaderViewParams.height = ActionBar.LayoutParams.MATCH_PARENT; );
// qrCodeReaderView.setLayoutParams(qrCodeReaderViewParams);
// qrOverlayView.setLayoutParams(pointsOverlayViewParams);
// qrOverlayView = new qrOverlayView(getContext()); this.addView(qrOverlayView);
// qrOverlayView.bringToFront();
// this.addView(qrOverlayView);
// ConstraintLayout.LayoutParams pointsOverlayViewParams = (ConstraintLayout.LayoutParams) qrCodeReaderView.getLayoutParams();
// pointsOverlayViewParams.width = ActionBar.LayoutParams.MATCH_PARENT;
// pointsOverlayViewParams.height = ActionBar.LayoutParams.MATCH_PARENT;
// qrOverlayView.setLayoutParams(pointsOverlayViewParams);
//
// Map<DecodeHintType, Object> hints = new EnumMap<DecodeHintType, Object>(DecodeHintType.class);
// hints.put(DecodeHintType.POSSIBLE_FORMATS, BarcodeFormat.QR_CODE);
// hints.put(DecodeHintType.PURE_BARCODE, Boolean.TRUE);
//// hints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);
//
// qrCodeReaderView.setDecodeHints(hints);
//
//// qrCodeReaderView = (QRCodeReaderView) binding.qrdecoderview;
// qrCodeReaderView.setOnQRCodeReadListener(new codeReadListener());
//// qrCodeReaderView.setQRDecodingEnabled(true);
// qrCodeReaderView.setAutofocusInterval(2000L);
//// qrCodeReaderView.setFrontCamera();
// qrCodeReaderView.setBackCamera();
// qrCodeReaderView.setOnClickListener(new View.OnClickListener() {
// @Override
// public void onClick(View v) {
// qrCodeReaderView.forceAutoFocus();
// }
// });
// qrCodeReaderView.startCamera();
ListenableFuture<ProcessCameraProvider> cameraProviderFuture ListenableFuture<ProcessCameraProvider> cameraProviderFuture
= ProcessCameraProvider.getInstance(this.getContext()); = ProcessCameraProvider.getInstance(this.getContext());
@@ -267,14 +282,18 @@ public class scannerView extends ConstraintLayout {
@OptIn(markerClass = ExperimentalGetImage.class) @Override @OptIn(markerClass = ExperimentalGetImage.class) @Override
public void analyze(@NonNull ImageProxy image) { public void analyze(@NonNull ImageProxy image) {
Image img = Objects.requireNonNull(image.getImage()); Image img = Objects.requireNonNull(image.getImage());
Log.i("test", img.getWidth() + ", " + img.getHeight()); // Log.i("test", img.getWidth() + ", " + img.getHeight());
final Bitmap bmp = yuvConvertor.toBitmap(img); // final Bitmap bmp = yuvConvertor.toBitmap(img);
uiHandler.post(new Runnable() { if(img != null) {
@Override uiHandler.post(new Runnable() {
public void run() { Bitmap bmp = toGreyscale(img);
setImage(toGreyscale(bmp)); @Override
} public void run() {
}); // setImage(toGreyscale(bmp));
setImage(bmp);
}
});
}
image.close(); image.close();
} }
}); });
@@ -295,7 +314,7 @@ public class scannerView extends ConstraintLayout {
private int prevQrIndex; private int prevQrIndex;
private void compileData(int dataVersion, int randID, int qrIndex, int qrCount, String qrData){ private void compileData(int dataVersion, int randID, int qrIndex, int qrCount, String qrData){
if(dataVersion != fileEditor.internalDataVersion){ if(dataVersion != fileEditor.internalDataVersion){
alert("Error", "Incorrect data version"); alert("Error", "Incorrect data version ("+dataVersion+" != "+fileEditor.internalDataVersion+")");
return; return;
} }
@@ -324,14 +343,13 @@ public class scannerView extends ConstraintLayout {
if(updated && qrScannedCount >= qrCount){ if(updated && qrScannedCount >= qrCount){
// I guess String.join does not like non-ascii text String compiledString = "";
String compiledData = "";
for(int i=0;i<qrCount;i++){ for(int i=0;i<qrCount;i++){
compiledData += qrDataArr[i]; compiledString += qrDataArr[i];
} }
try { try {
byte[] compiledBytes = compiledData.getBytes(StandardCharsets.ISO_8859_1); byte[] compiledBytes = compiledString.getBytes(StandardCharsets.ISO_8859_1);
// alert(count+", "+compiledData.length()+", "+compiledBytes.length, ""+fileEditor.fromBytes(fileEditor.getByteBlock(compiledBytes, 0,2),2)); // alert(count+", "+compiledData.length()+", "+compiledBytes.length, ""+fileEditor.fromBytes(fileEditor.getByteBlock(compiledBytes, 0,2),2));
// alert("completed", new String(fileEditor.decompress(compiledBytes), StandardCharsets.ISO_8859_1)); // alert("completed", new String(fileEditor.decompress(compiledBytes), StandardCharsets.ISO_8859_1));
alert("completed", blockUncompress(compiledBytes)); alert("completed", blockUncompress(compiledBytes));
+53 -12
View File
@@ -141,37 +141,78 @@
<SeekBar <SeekBar
android:id="@+id/scannerThreshold" android:id="@+id/scannerColors"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="48dp" android:layout_height="48dp"
android:layout_marginBottom="60dp" android:layout_marginTop="15dp"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"/> app:layout_constraintStart_toStartOf="parent"/>
<SeekBar
android:id="@+id/scannerThreshold"
android:layout_width="match_parent"
android:layout_height="48dp"
app:layout_constraintTop_toBottomOf="@id/scannerColors"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"/>
<SeekBar
android:id="@+id/scannerBrightness"
android:layout_width="match_parent"
android:layout_height="48dp"
app:layout_constraintTop_toBottomOf="@id/scannerThreshold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"/>
<TextView
android:id="@+id/scannerColorsLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginBottom="-12dp"
android:text="Posterize"
app:layout_constraintBottom_toTopOf="@+id/scannerColors"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="@+id/scannerThresholdLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginBottom="-12dp"
android:text="Exposure"
app:layout_constraintBottom_toTopOf="@+id/scannerThreshold"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="@+id/scannerBrightnessLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginBottom="-12dp"
android:text="Brightness"
app:layout_constraintBottom_toTopOf="@+id/scannerBrightness"
app:layout_constraintStart_toStartOf="parent" />
<ImageView <ImageView
android:id="@+id/scannerImage" android:id="@+id/scannerImage"
android:layout_width="fill_parent" android:layout_width="wrap_content"
android:layout_height="fill_parent" android:layout_height="wrap_content"
android:layout_centerInParent="true" android:layout_centerInParent="true"
android:adjustViewBounds="true" android:adjustViewBounds="true"
android:rotation="90" android:rotation="90"
android:scaleType="fitCenter" android:scaleType="fitCenter"
android:scaleX="1" android:scaleX="1"
android:scaleY="1" android:scaleY="1"
android:translationY="-40dp"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
tools:context=".TransferFragment" /> tools:context=".TransferFragment" />
<!-- <Switch-->
<!-- android:id="@+id/switch1"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:text="Switch"-->
<!-- tools:ignore="UseSwitchCompatOrMaterialXml" />-->
</com.astatin3.scoutingapp2025.ui.transfer.scannerView> </com.astatin3.scoutingapp2025.ui.transfer.scannerView>