Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added ability to import a barcode from a local image #317

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 66 additions & 4 deletions app/src/main/java/protect/card_locker/LoyaltyCardEditActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.provider.MediaStore;
import android.support.design.widget.Snackbar;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AlertDialog;
Expand All @@ -24,16 +26,26 @@
import android.widget.Toast;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.LuminanceSource;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.NotFoundException;
import com.google.zxing.RGBLuminanceSource;
import com.google.zxing.Result;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.integration.android.IntentIntegrator;
import com.google.zxing.integration.android.IntentResult;
import com.jaredrummler.android.colorpicker.ColorPickerDialog;
import com.jaredrummler.android.colorpicker.ColorPickerDialogListener;

import java.io.IOException;

public class LoyaltyCardEditActivity extends AppCompatActivity
{
private static final String TAG = "CardLocker";

private static final int SELECT_BARCODE_REQUEST = 1;
private static final int SELECT_IMAGE_REQUEST = 2;

EditText storeFieldEdit;
EditText noteFieldEdit;
Expand All @@ -50,6 +62,7 @@ public class LoyaltyCardEditActivity extends AppCompatActivity
View barcodeCaptureLayout;

Button captureButton;
Button importImageButton;
Button enterButton;

int loyaltyCardId;
Expand Down Expand Up @@ -102,6 +115,7 @@ protected void onCreate(Bundle savedInstanceState)
barcodeCaptureLayout = findViewById(R.id.barcodeCaptureLayout);

captureButton = findViewById(R.id.captureButton);
importImageButton = findViewById(R.id.importImageButton);
enterButton = findViewById(R.id.enterButton);
}

Expand Down Expand Up @@ -260,6 +274,20 @@ public void onClick(View v)

captureButton.setOnClickListener(captureCallback);

View.OnClickListener importImageCallback = new View.OnClickListener()
{
@Override
public void onClick(View v)
{
Intent photoPickerIntent = new Intent(Intent.ACTION_PICK);
photoPickerIntent.setType("image/*");
photoPickerIntent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
startActivityForResult(photoPickerIntent, SELECT_IMAGE_REQUEST);
}
};

importImageButton.setOnClickListener(importImageCallback);

enterButton.setOnClickListener(new View.OnClickListener()
{
@Override
Expand Down Expand Up @@ -449,12 +477,46 @@ public void onActivityResult(int requestCode, int resultCode, Intent intent)
format = result.getFormatName();
}

if(requestCode == SELECT_BARCODE_REQUEST && resultCode == Activity.RESULT_OK)
if (resultCode == Activity.RESULT_OK)
{
Log.i(TAG, "Received barcode information from typing it");
if(requestCode == SELECT_BARCODE_REQUEST)
{
Log.i(TAG, "Received barcode information from typing it");

contents = intent.getStringExtra(BarcodeSelectorActivity.BARCODE_CONTENTS);
format = intent.getStringExtra(BarcodeSelectorActivity.BARCODE_FORMAT);
contents = intent.getStringExtra(BarcodeSelectorActivity.BARCODE_CONTENTS);
format = intent.getStringExtra(BarcodeSelectorActivity.BARCODE_FORMAT);
}
else if (requestCode == SELECT_IMAGE_REQUEST)
{
Log.i(TAG, "Received barcode image");

Bitmap bitmap = null;
try {
bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), intent.getData());
} catch (IOException e) {
Log.e(TAG, "Error getting the image data");
e.printStackTrace();
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, should this be logged instead?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, printStacktrace() is, in fact, logged, but without the TAG. I'll move it into the Log.e call.

return;
}

// In order to decode it, the Bitmap must first be converted into a pixel array...
int[] intArray = new int[bitmap.getWidth()*bitmap.getHeight()];
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you know what the failure mode is if a user selects an image which "is too big"? For example, in generating the barcode for display I've sometimes encountered issues with memory:

https://github.com/brarcher/loyalty-card-locker/blob/master/app/src/main/java/protect/card_locker/BarcodeImageWriterTask.java#L152

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't actually know... I looked around and I'm still not sure about an OOM exception, however I did stumble upon people having issues with codes in huge images not being recognized.

I'll do some more testing and maybe add a downscale step before processing.

bitmap.getPixels(intArray, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());

// ...and then turned into a binary bitmap from its luminance
LuminanceSource source = new RGBLuminanceSource(bitmap.getWidth(), bitmap.getHeight(), intArray);
BinaryBitmap binaryBitmap = new BinaryBitmap(new HybridBinarizer(source));

try {
Result qrCodeResult = new MultiFormatReader().decode(binaryBitmap);

contents = qrCodeResult.getText();
format = qrCodeResult.getBarcodeFormat().name();
} catch (NotFoundException e) {
Log.i(TAG, "No barcode was found");
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this exception be logged? The e.printStackTrace() would not be captured, right?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I don't believe it should be. All it says is that there was no barcode in the image - which isn't truly an exception.
Now that I think about it - maybe a toast would be useful?

The printStacktrace() was left there accidentally. I'll remove it.

e.printStackTrace();
}
}
}

if(contents != null && contents.isEmpty() == false &&
Expand Down
11 changes: 10 additions & 1 deletion app/src/main/res/layout/loyalty_card_edit_activity.xml
Original file line number Diff line number Diff line change
Expand Up @@ -368,12 +368,21 @@
android:padding="10.0dip"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/barcodeCaptureLayout">
android:id="@+id/barcodeCaptureLayout"
android:baselineAligned="false">
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understand correctly from

https://medium.com/@pareshmayani/androiddev-tip-set-android-baselinealigned-false-on-this-element-for-better-performance-810fa3148043

this was likely necessary to get the buttons to align up correctly, correct?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. The new button spans two lines on narrower devices and the default is to align by text, not by their bounding boxes.


<Button android:id="@+id/captureButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/capture"
android:layout_weight="1.0"/>

<Button android:id="@+id/importImageButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/importImage"
android:layout_weight="1.0"/>

<Button android:id="@+id/enterButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -123,4 +123,5 @@
<string name="settings_key_display_barcode_max_brightness" translatable="false">pref_display_card_max_brightness</string>
<string name="settings_lock_barcode_orientation">Lock barcode orientation</string>
<string name="settings_key_lock_barcode_orientation" translatable="false">pref_lock_barcode_orientation</string>
<string name="importImage">Import from image</string>
</resources>