Compare commits

...
44 Commits
Author SHA1 Message Date
Markus Fisch 2907c8c49c Advance version number to 1.53.0 2022-10-19 22:27:21 +02:00
Markus Fisch f28f956a8d Only generate barcode output when required 2022-10-19 21:45:15 +02:00
Markus Fisch 972eb6a0b0 Update to latest ZXing C++ wrapper 2022-10-19 21:43:48 +02:00
Markus Fisch 08bb3f2127 Replace RelativeLayout with LinearLayout
In decoding fragment.

All children were layed out linearly anyway and it's simpler
and more clear this way.
2022-10-19 19:54:33 +02:00
Markus Fisch b28e939f58 Refactor resolveFormat() and make it an extension 2022-10-19 13:04:48 +02:00
solokotandGitHub 2edb8112b7 Update Russian translation 2022-10-19 13:04:06 +02:00
Markus Fisch cf5a6dc8b8 Hide setting a custom locale from API 33 on
Android 13 allows to set per-app language preferences, so this
setting is no longer required from there on.

See:
https://developer.android.com/guide/topics/resources/app-languages
2022-10-15 18:43:40 +02:00
Markus Fisch 3ec6f18fe0 Hide sensitive content from clipboard
At the moment, this affects just the WiFi password.

See:
https://developer.android.com/about/versions/13/behavior-changes-all#copy-sensitive-content
2022-10-15 18:38:14 +02:00
Markus Fisch 3a8f6cb827 Target SDK 33, Android 13 2022-10-15 18:37:49 +02:00
Markus Fisch 65c7fe52ee Fix closing Cursor's below JELLY BEAN
Unfortunately, Cursor cannot be cast to Closeable below API level 16
JELLY BEAN. So we can't just use Kotlin's ".use" extension function
because it would implicitly cast Cursor to a Closeable.

So this adds a simple drop-in replacement that does exactly what ".use"
is doing but without casting Cursor.

Of course, this should be removed as soon as minSDK is increased to at
least JELLY_BEAN.
2022-10-13 23:02:32 +02:00
Markus Fisch 5d3b3eb195 Fix generating a date time string below API 18
Before API level 18, there was no 'H' but only 'k', which was
incorrectly implemented to produce what we now know as 'H'.
2022-10-13 22:39:52 +02:00
Markus Fisch 0e4c2963a5 Catch ParseException when parsing scan dates 2022-10-13 22:38:04 +02:00
Markus Fisch 791c50cd4a Update build tools 2022-10-13 22:37:00 +02:00
Markus Fisch c04b08ab87 Update to latest ZXing C++ wrapper
Which adds a ContentType so we can distinguish between text
and binary content.
2022-10-12 21:47:54 +02:00
Markus Fisch f07c4ac0f4 Update to latest Kotlin and coroutines version 2022-10-11 23:43:30 +02:00
Markus Fisch 05d63bd73f Fix vector image fill color for API < 21
`fillColor` cannot have Android resources below API 21.
2022-10-11 23:37:29 +02:00
Markus Fisch 558fd5212d Remove double support annotation 2022-10-11 23:34:54 +02:00
Markus Fisch b918be76e4 Fix getting version number from database 2022-10-11 23:33:59 +02:00
Markus Fisch 2136a8c73e Show version code for all supported barcodes
And the module count if it's a QR Code.
2022-10-11 23:29:59 +02:00
Markus Fisch 959c6e7d4d Always show QR Code version and remove setting
This comes no longer with a cost so it can be always there.
2022-10-11 23:02:47 +02:00
Markus Fisch 50930d07a6 Show binary data placeholder in edit name dialog
To show something instead of nothing in the dialog title.
Still not perfect, of course.
2022-10-11 22:47:14 +02:00
Markus Fisch 36e7aab27c Update to latest ZXing C++ AAR
Fixes getting HRI formatted result text instead of the real thing.
2022-10-11 22:39:14 +02:00
Markus Fisch bb4fc8ed08 Enable multi-select in history listing 2022-10-11 21:53:15 +02:00
Markus Fisch 7a33ebd1a3 Remove MicroQR from list of writable codes
ZXing C++ doesn't contain a writer for this format, yet.
2022-10-11 20:41:18 +02:00
solokotandGitHub c8444b8935 Update Russian translation 2022-10-10 12:22:06 +02:00
Markus Fisch 4c6d66a4aa Migrate to ZXing-C++
Replace the ZXing Java implementation with the C++ fork.

The C++ fork is faster, actively maintained and supports the MicroQR
Code barcode format.

The original Java implementation is in "Maintenance Mode Only",
what means that no new features or barcodes will be accepted.

Because the C++ fork is much faster, we can now drop RenderScript
which has been deprecated by Google anyway. Also, this removes a lot
of complications. RenderScript was never very robust.
2022-10-09 18:46:50 +02:00
Markus Fisch 39f95a1c04 Remove shortcut extra from EncodeFragment
And make it possible to open the EncodeFragment without content.
2022-10-04 21:19:47 +02:00
Markus Fisch 9e30b108e7 Reformat code and optimize imports
Let Android Studio clean up.
2022-09-29 18:42:00 +02:00
Markus Fisch 1b6b1cefe3 Convert charset for PDF417 in an extension
And run it from PickActivity too to apply this conversion when
scanning from still images too.
2022-09-29 18:39:01 +02:00
Mladen MilinkovicandGitHub b634370a0b Fix PDF-417 UTF-8 text encoding
This fixes reading PDF-417 barcodes containing international UTF-8 characters.
2022-09-29 18:23:07 +02:00
gonandGitHub f32d44c3a1 Update spanish translation 2022-09-27 20:59:12 +02:00
Markus Fisch 2e060d1ca8 Add Persian to list of custom languages
That can be changed in the app independently from the system settings.
2022-09-11 23:01:31 +02:00
Andreas KorbandGitHub 6acdce32f2 Add multidex dependency
Required on some systems/Android Studio versions.
2022-09-10 21:33:04 +02:00
Markus Fisch 092ec694f6 Fix terminating string tag in persian translation 2022-09-10 19:12:03 +02:00
7fed7877a0 Add persian translation
Co-authored-by: eshagh79 <eshagh094@gmail.com>
2022-09-10 19:09:05 +02:00
Markus Fisch b17393d5ef Invert plain text output
Because plain text will most likely end up being black text on a
white background on a mobile device.

But with night mode we can never be sure. So there's an "inverted"
parameter now if the text is bright on a dark background.
2022-08-21 00:36:49 +02:00
Markus Fisch 319ae53b3b Make conditional an argument
To avoid the repetition of the function invocation.

Also make bt a constant variable because it can be.
2022-08-20 19:03:29 +02:00
Markus Fisch 6a47a7e477 Fix indent of new code for generating text output
We're not mixing tabs and spaces.
2022-08-20 18:56:50 +02:00
Tom XinandGitHub 19fb733182 Improve plain text output of generated barcodes
Optimize the 'save as text' function to make its results more recognizable when
printing on the console.
2022-08-20 18:53:43 +02:00
Markus Fisch ce6c6f26d2 Advance version number to 1.52.0 2022-08-10 23:25:46 +02:00
Markus Fisch 3633af5e0a Fix parsing timezone in calendar dates
And add patterns for RFC 822 and ISO 8601 formats.

Before this 'Z' was quoted and therefore just a string in the pattern.
So the time zone was actually never really applied to the resulting date.
Now, it's pattern letter and the resulting date is adjusted accordingly.

This also fixes using dates without a time zone.
2022-08-10 23:07:17 +02:00
87502f7226 Update translation (#280)
* Syntax correction (omitted point)

* Update french translation

Co-authored-by: Grena <grena@grenabox.fr>
2022-06-22 13:30:53 +02:00
Markus Fisch f4af35ad46 Advance version number to 1.51.1 2022-06-16 16:51:39 +02:00
Markus Fisch 60f0d8bd87 Convert result text with ISO_8859_1 encoding
Important to suppress UTF-8 encoding.
2022-06-16 16:45:31 +02:00
90 changed files with 1357 additions and 1692 deletions
+20
View File
@@ -1,5 +1,25 @@
# Change Log
## 1.53.0
* Migrate to ZXing-C++ and add support for Micro QR Codes
* Multi-select scans in history listing
* Remove preset content for Encode shortcut
* Always show QR Code version and remove setting
* Fix PDF-417 UTF-8 text encoding
* Hide sensitive content from clipboard
* Remove setting a custom language on Android 13+
* Condense text output of generated barcodes
* Update Russian translation
* Update Spanish translation
* Add Persian translation
## 1.52.0
* Fix parsing timezone in calendar dates
* Update French translation
## 1.51.1
* Fix extraction of raw bytes for some barcodes
## 1.51.0
* Add support for Deutsche Post Matrixcode stamp
* Allow free image rotation for scanning from images
-3
View File
@@ -20,9 +20,6 @@ infer: clean
test:
./gradlew test
cat:
./gradlew test cAT
testview:
adb shell am start -W -a android.intent.action.VIEW -d 'binaryeye://scan'
+6 -36
View File
@@ -7,8 +7,8 @@ This one is free, without any ads and open source.
Works in portrait and landscape orientation, can read inverted codes,
comes in Material Design and can also generate barcodes.
Binary Eye uses the [ZXing][zxing] ("Zebra Crossing") barcode scanning
library.
Binary Eye uses the [ZXing-C++][zxing_cpp] ("Zebra Crossing") barcode
scanning library.
## Screenshots
@@ -39,10 +39,10 @@ ZXing can read the following barcode formats:
* [EAN 8][ean_8]
* [EAN 13][ean_13]
* [ITF][itf]
* [MAXICODE][maxicode] (only when unrotated and unskewed, see [77][77],
because of which Binary Eye *cannot* read this barcode)
* [MAXICODE][maxicode] (partial)
* [PDF417][pdf417]
* [QR CODE][qr_code]
* [Micro QR Code][micro_qr_code]
* [RSS 14][rss]
* [RSS EXPANDED][rss]
* [UPC A][upc_a]
@@ -135,37 +135,8 @@ class YourActivity : Activity() {
}
```
## RenderScript
This app uses [RenderScript][rs] to resize and rotate the camera image.
Unfortunately, RenderScript has some nasty gotchas.
### RenderScript.forceCompat()
It's necessary to call `RenderScript.forceCompat()` on some devices/roms.
`RenderScript.forceCompat()` needs to be run before any other RenderScript
function and unfortunately there is no way to know if invoking `forceCompat()`
is necessary or not.
If `RenderScript.forceCompat()` is necessary, a `RSRuntimeException` will
be thrown and the only option is to restart the app, this time with calling
`forceCompat()` first.
Calling `RenderScript.forceCompat()` means the processing is done in
software so you probably don't want to enable it by default.
### 2D barcodes
If you want to fork this and are only interested in reading 2D barcodes
(like QR or Aztec), you may want to remove the custom rotation kernel
altogether as ZXing can read 2D barcodes in any orientation.
This will make your app a bit simpler and saves you from compiling a
custom RenderScript kernel for each architecture you want to support.
[play]: https://play.google.com/store/search?q=barcode%20scanner&c=apps
[zxing]: https://github.com/zxing/zxing
[zxing_cpp]: https://github.com/zxing-cpp/zxing-cpp
[kotlin]: http://kotlinlang.org/
[aztec]: https://en.wikipedia.org/wiki/Aztec_Code
[codabar]: https://en.wikipedia.org/wiki/Codabar
@@ -179,12 +150,11 @@ custom RenderScript kernel for each architecture you want to support.
[maxicode]: https://en.wikipedia.org/wiki/MaxiCode
[pdf417]: https://en.wikipedia.org/wiki/PDF417
[qr_code]: https://en.wikipedia.org/wiki/QR_code
[micro_qr_code]: https://en.wikipedia.org/wiki/QR_code#Micro_QR_code
[rss]: https://en.wikipedia.org/wiki/GS1_DataBar
[upc_a]: https://en.wikipedia.org/wiki/Universal_Product_Code
[upc_e]: https://en.wikipedia.org/wiki/Universal_Product_Code#UPC-E
[upc_ean]: https://en.wikipedia.org/wiki/Universal_Product_Code#EAN-13
[77]: https://github.com/markusfisch/BinaryEye/issues/77
[rs]: https://developer.android.com/guide/topics/renderscript/compute
[start_activity]: https://developer.android.com/reference/android/app/Activity#startActivityForResult(android.content.Intent,%20int)
[on_activity_result]: https://developer.android.com/reference/android/app/Activity#onActivityResult(int,%20int,%20android.content.Intent)
[intent_result]: https://developer.android.com/training/basics/intents/result
+4 -36
View File
@@ -9,19 +9,8 @@ android {
minSdkVersion 9
targetSdkVersion sdk_version
versionCode 98
versionName '1.51.0'
// Required for desugaring.
multiDexEnabled true
// It's recommended to set this value to the lowest API level
// able to provide all the functionality.
renderscriptTargetApi 24
renderscriptSupportModeEnabled true
renderscriptSupportModeBlasEnabled true
testInstrumentationRunner 'android.support.test.runner.AndroidJUnitRunner'
versionCode 101
versionName '1.53.0'
}
signingConfigs {
@@ -64,39 +53,18 @@ android {
enableSplit = false
}
}
compileOptions {
// To desugar fancy Java features in ZXing 3.4.+ that don't
// work on SDK < 24. See:
// https://github.com/zxing/zxing/issues/1170
coreLibraryDesugaringEnabled true
}
lint {
// Because at the time of writing, even the latest version
// of RenderScript is raising this error no matter if
// renderscriptTargetApi matches targetSdkVersion.
disable 'GradleCompatible'
}
}
dependencies {
androidTestImplementation('com.android.support.test:runner:1.0.2') {
exclude module: 'support-annotations'
}
androidTestImplementation('com.android.support.test:rules:1.0.2') {
exclude module: 'support-annotations'
}
testImplementation 'junit:junit:4.13.2'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.1"
implementation "com.android.support:appcompat-v7:$support_version"
implementation "com.android.support:design:$support_version"
implementation "com.android.support:preference-v7:$support_version"
implementation "com.android.support:preference-v14:$support_version"
implementation 'com.google.zxing:core:3.5.0'
implementation 'com.github.markusfisch:CameraView:1.9.1'
implementation 'com.github.markusfisch:ScalingImageView:1.4.0'
implementation 'com.github.markusfisch:zxing-cpp:v1.4.0.4'
}
+2 -1
View File
@@ -3,4 +3,5 @@
-dontwarn android.support.v8.**
-keep class android.support.v7.widget.SearchView { *; }
-keep class android.support.v8.renderscript.** { *; }
-keep class com.kurzdigital.android.zxingcpp.** { *; }
Binary file not shown.

Before

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

@@ -1,107 +0,0 @@
package de.markusfisch.android.binaryeye
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.support.test.InstrumentationRegistry
import android.support.test.runner.AndroidJUnit4
import android.support.v8.renderscript.RenderScript
import de.markusfisch.android.binaryeye.rs.Preprocessor
import de.markusfisch.android.binaryeye.zxing.Zxing
import org.junit.Assert.fail;
import org.junit.Test
import org.junit.runner.RunWith
import java.util.regex.Pattern
@RunWith(AndroidJUnit4::class)
class PreprocessorTest {
@Test
fun processSamples() {
val assets = InstrumentationRegistry.getInstrumentation()
.context.assets
val samples = assets.list("samples")
checkNotNull(samples) { "no samples found" }
val pattern = Pattern.compile(
"[0-9]+-([0-9]+)deg.jpg"
)
val rs = RenderScript.create(
InstrumentationRegistry.getTargetContext(),
)
val zxing = Zxing()
for (sample in samples) {
val m = pattern.matcher(sample)
if (!m.find() || m.groupCount() < 1) {
fail("invalid sample: $sample")
}
val bitmap = BitmapFactory.decodeStream(
assets.open("samples/$sample")
)
val frameData = getNV21(bitmap)
val frameWidth = bitmap.width
val frameHeight = bitmap.height
val frameOrientation = m.group(1) ?: return
val preprocessor = Preprocessor(
rs,
frameWidth,
frameHeight,
null
)
val outWidth: Int
val outHeight: Int
val orientation = frameOrientation.toInt()
if (orientation == 90 || orientation == 270) {
preprocessor.resizeAndRotate(frameData)
outWidth = preprocessor.outHeight
outHeight = preprocessor.outWidth
} else {
preprocessor.resizeOnly(frameData)
outWidth = preprocessor.outWidth
outHeight = preprocessor.outHeight
}
val result = zxing.decode(frameData, outWidth, outHeight)
preprocessor.destroy()
checkNotNull(result) { "no barcode found in $sample" }
}
rs.destroy()
}
}
fun getNV21(bitmap: Bitmap): ByteArray {
val width = bitmap.width
val height = bitmap.height
val argb = IntArray(width * height)
bitmap.getPixels(argb, 0, width, 0, 0, width, height)
return encodeYUV420SP(argb, width, height)
}
private fun encodeYUV420SP(argb: IntArray, width: Int, height: Int): ByteArray {
val yuv = ByteArray(ceilIfUneven(width) * ceilIfUneven(height) * 3 / 2)
var yIndex = 0
var uvIndex = width * height
var r: Int
var g: Int
var b: Int
var y: Int
var u: Int
var v: Int
var index = 0
for (t in 0 until height) {
for (s in 0 until width) {
val pixel = argb[index]
r = pixel and 0xff0000 shr 16
g = pixel and 0xff00 shr 8
b = pixel and 0xff
y = (66 * r + 129 * g + 25 * b + 128 shr 8) + 16
u = (-38 * r - 74 * g + 112 * b + 128 shr 8) + 128
v = (112 * r - 94 * g - 18 * b + 128 shr 8) + 128
yuv[yIndex++] = (if (y < 0) 0 else if (y > 255) 255 else y).toByte()
if (t % 2 == 0 && index % 2 == 0) {
yuv[uvIndex++] = (if (v < 0) 0 else if (v > 255) 255 else v).toByte()
yuv[uvIndex++] = (if (u < 0) 0 else if (u > 255) 255 else u).toByte()
}
++index
}
}
return yuv
}
private fun ceilIfUneven(n: Int) = if (n and 1 == 1) n + 1 else n
@@ -39,8 +39,10 @@ abstract class SchemeAction : IAction {
final override fun canExecuteOn(data: ByteArray): Boolean {
val content = String(data)
return if (buildRegex) {
content.matches("""^$scheme://[\w\W]+$""".toRegex(
RegexOption.IGNORE_CASE)
content.matches(
"""^$scheme://[\w\W]+$""".toRegex(
RegexOption.IGNORE_CASE
)
)
} else {
content.startsWith("$scheme://", ignoreCase = true)
@@ -4,8 +4,8 @@ import android.content.Context
import de.markusfisch.android.binaryeye.R
import de.markusfisch.android.binaryeye.actions.IAction
import de.markusfisch.android.binaryeye.app.alertDialog
import de.markusfisch.android.binaryeye.app.urlEncode
import de.markusfisch.android.binaryeye.app.prefs
import de.markusfisch.android.binaryeye.app.urlEncode
import de.markusfisch.android.binaryeye.content.openUrl
object OpenOrSearchAction : IAction {
@@ -9,7 +9,6 @@ import de.markusfisch.android.binaryeye.R
import de.markusfisch.android.binaryeye.actions.IntentAction
import de.markusfisch.android.binaryeye.actions.vtype.VTypeParser
import java.util.*
import kotlin.collections.ArrayList
object VCardAction : IntentAction() {
override val iconResId: Int
@@ -1,6 +1,5 @@
package de.markusfisch.android.binaryeye.actions.vtype.vevent
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.os.Build
@@ -47,7 +46,7 @@ object VEventAction : IntentAction() {
dateFormats.simpleFindParse(eventStart.value)?.also {
putExtra(
CalendarContract.EXTRA_EVENT_BEGIN_TIME,
it.localTime()
it.time
)
}
}
@@ -55,37 +54,39 @@ object VEventAction : IntentAction() {
dateFormats.simpleFindParse(eventEnd.value)?.also {
putExtra(
CalendarContract.EXTRA_EVENT_END_TIME,
it.localTime()
it.time
)
}
}
}
}
// We definitely don't wan't the local format.
@SuppressLint("SimpleDateFormat")
private val dateFormats = listOf(
SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"),
SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"),
SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'"),
SimpleDateFormat("yyyyMMdd'T'HHmmss"),
SimpleDateFormat("yyyy-MM-dd"),
SimpleDateFormat("yyyyMMdd")
)
private fun List<SimpleDateFormat>.simpleFindParse(data: String): Date? {
for (simpleDataFormat in this) {
return simpleDataFormat.simpleParse(data) ?: continue
}
return null
}
private fun SimpleDateFormat.simpleParse(data: String): Date? = try {
this.parse(data)
} catch (e: Exception) {
null
}
}
private fun Date.localTime() = time - timezoneOffset * 60000L
private val dateFormats = listOf(
"yyyy-MM-dd'T'HH:mm:ssXXX",
"yyyy-MM-dd'T'HH:mm:ssZ",
"yyyy-MM-dd'T'HH:mm:ssz",
"yyyy-MM-dd'T'HH:mm:ss",
"yyyyMMdd'T'HHmmssXXX",
"yyyyMMdd'T'HHmmssZ",
"yyyyMMdd'T'HHmmssz",
"yyyyMMdd'T'HHmmss",
"yyyy-MM-dd",
"yyyyMMdd"
)
private fun List<String>.simpleFindParse(date: String): Date? {
for (pattern in this) {
return SimpleDateFormat(
pattern,
Locale.getDefault()
).simpleParse(date) ?: continue
}
return null
}
private fun SimpleDateFormat.simpleParse(date: String): Date? = try {
parse(date)
} catch (e: Exception) {
null
}
@@ -6,9 +6,10 @@ import de.markusfisch.android.binaryeye.actions.IAction
import de.markusfisch.android.binaryeye.content.openUrl
object WebAction : IAction {
private val colloquialRegex = """^(http[s]*://)*([a-z0-9]+[a-z0-9-]*[a-z0-9]+[.])+[a-z]{2,}([?#/]+[\w/=&;._-]*)*$""".toRegex(
RegexOption.IGNORE_CASE
)
private val colloquialRegex =
"""^(http[s]*://)*([a-z0-9]+[a-z0-9-]*[a-z0-9]+[.])+[a-z]{2,}([?#/]+[\w/=&;._-]*)*$""".toRegex(
RegexOption.IGNORE_CASE
)
override val iconResId: Int = R.drawable.ic_action_open
override val titleResId: Int = R.string.open_url
@@ -7,7 +7,6 @@ import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Matrix
import android.graphics.Rect
import android.graphics.RectF
import android.hardware.Camera
import android.media.AudioManager
import android.media.ToneGenerator
@@ -17,15 +16,11 @@ import android.os.Vibrator
import android.support.design.widget.FloatingActionButton
import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.Toolbar
import android.support.v8.renderscript.RSRuntimeException
import android.support.v8.renderscript.RenderScript
import android.view.Menu
import android.view.MenuItem
import android.view.MotionEvent
import android.view.View
import android.widget.SeekBar
import com.google.zxing.Result
import com.google.zxing.ResultMetadataType
import de.markusfisch.android.binaryeye.R
import de.markusfisch.android.binaryeye.adapter.prettifyFormatName
import de.markusfisch.android.binaryeye.app.*
@@ -33,50 +28,39 @@ import de.markusfisch.android.binaryeye.content.copyToClipboard
import de.markusfisch.android.binaryeye.content.execShareIntent
import de.markusfisch.android.binaryeye.content.openUrl
import de.markusfisch.android.binaryeye.database.toScan
import de.markusfisch.android.binaryeye.graphics.getFrameToViewMatrix
import de.markusfisch.android.binaryeye.graphics.map
import de.markusfisch.android.binaryeye.graphics.FrameMetrics
import de.markusfisch.android.binaryeye.graphics.mapPosition
import de.markusfisch.android.binaryeye.graphics.setFrameRoi
import de.markusfisch.android.binaryeye.graphics.setFrameToView
import de.markusfisch.android.binaryeye.net.sendAsync
import de.markusfisch.android.binaryeye.os.error
import de.markusfisch.android.binaryeye.os.getVibrator
import de.markusfisch.android.binaryeye.os.vibrate
import de.markusfisch.android.binaryeye.rs.Preprocessor
import de.markusfisch.android.binaryeye.view.initSystemBars
import de.markusfisch.android.binaryeye.view.setPaddingFromWindowInsets
import de.markusfisch.android.binaryeye.widget.DetectorView
import de.markusfisch.android.binaryeye.widget.toast
import de.markusfisch.android.binaryeye.zxing.Zxing
import de.markusfisch.android.cameraview.widget.CameraView
import de.markusfisch.android.zxingcpp.ZxingCpp
import de.markusfisch.android.zxingcpp.ZxingCpp.Format
import de.markusfisch.android.zxingcpp.ZxingCpp.Result
import java.nio.charset.Charset
import kotlin.math.max
import kotlin.math.min
import kotlin.math.roundToInt
class CameraActivity : AppCompatActivity() {
private val zxing = Zxing { point ->
point ?: return@Zxing
val matrix = getMappingMatrix() ?: return@Zxing
detectorView.post {
detectorView.update(
matrix.map(
arrayOf(point),
detectorView.coordinates
)
)
}
}
private val frameRoi = Rect()
private val matrix = Matrix()
private lateinit var rs: RenderScript
private lateinit var vibrator: Vibrator
private lateinit var cameraView: CameraView
private lateinit var detectorView: DetectorView
private lateinit var zoomBar: SeekBar
private lateinit var flashFab: FloatingActionButton
private var preprocessor: Preprocessor? = null
private var nativeMappingMatrix: Matrix? = null
private var rotatedMappingMatrix: Matrix? = null
private var recreatePreprocessor = false
private var rotate = false
private var invert = false
private var formats = setOf<String>()
private var frameMetrics = FrameMetrics()
private var decoding = true
private var returnResult = false
private var returnUrlTemplate: String? = null
@@ -132,7 +116,6 @@ class CameraActivity : AppCompatActivity() {
// custom locale.
setTitle(R.string.scan_code)
rs = RenderScript.create(this)
vibrator = getVibrator()
initSystemBars(this)
@@ -156,11 +139,9 @@ class CameraActivity : AppCompatActivity() {
override fun onDestroy() {
super.onDestroy()
resetPreProcessor()
fallbackBuffer = null
saveZoom()
detectorView.saveCropHandlePos()
rs.destroy()
}
override fun onResume() {
@@ -180,7 +161,7 @@ class CameraActivity : AppCompatActivity() {
private fun updateHints() {
val restriction = restrictFormat
val formats = if (restriction != null) {
formats = if (restriction != null) {
title = getString(
R.string.scan_format,
prettifyFormatName(restriction)
@@ -190,7 +171,6 @@ class CameraActivity : AppCompatActivity() {
setTitle(R.string.scan_code)
prefs.barcodeFormats
}
zxing.updateHints(prefs.tryHarder, formats)
}
private fun setReturnTarget(intent: Intent?) {
@@ -205,11 +185,6 @@ class CameraActivity : AppCompatActivity() {
}
}
private fun resetPreProcessor() {
preprocessor?.destroy()
preprocessor = null
}
private fun openCamera() {
cameraView.openAsync(
CameraView.findCameraId(
@@ -441,25 +416,30 @@ class CameraActivity : AppCompatActivity() {
}
override fun onCameraReady(camera: Camera) {
// Reset preprocessor to make sure it always fits the current
// frame orientation. Important for landscape to landscape
// orientation changes.
resetPreProcessor()
val frameWidth = cameraView.frameWidth
val frameHeight = cameraView.frameHeight
val frameOrientation = cameraView.frameOrientation
frameMetrics = FrameMetrics(
cameraView.frameWidth,
cameraView.frameHeight,
cameraView.frameOrientation
)
updateFrameRoiAndMappingMatrix()
ignoreNext = null
decoding = true
camera.setPreviewCallback { frameData, _ ->
if (decoding) {
decodeFrame(
ZxingCpp.readByteArray(
frameData,
frameWidth,
frameHeight,
frameOrientation
frameMetrics.width,
frameRoi.left, frameRoi.top,
frameRoi.width(), frameRoi.height(),
frameMetrics.orientation,
formats.joinToString(),
prefs.tryHarder,
prefs.autoRotate,
tryInvert = true,
tryDownscale = true
)?.let { result ->
if (result.text != ignoreNext) {
postResult(result)
postResult(result.redact())
decoding = false
}
}
@@ -526,12 +506,23 @@ class CameraActivity : AppCompatActivity() {
}
detectorView.onRoiChanged = {
decoding = true
recreatePreprocessor = true
updateFrameRoiAndMappingMatrix()
}
detectorView.setPaddingFromWindowInsets()
detectorView.restoreCropHandlePos()
}
private fun updateFrameRoiAndMappingMatrix() {
val viewRect = cameraView.previewRect
val viewRoi = if (detectorView.roi.width() < 1) {
viewRect
} else {
detectorView.roi
}
frameRoi.setFrameRoi(frameMetrics, viewRect, viewRoi)
matrix.setFrameToView(frameMetrics, viewRect, viewRoi)
}
private fun updateFlashFab(unavailable: Boolean) {
if (unavailable) {
flashFab.setImageResource(R.drawable.ic_action_create)
@@ -560,158 +551,11 @@ class CameraActivity : AppCompatActivity() {
}
}
private fun decodeFrame(
frameData: ByteArray?,
frameWidth: Int,
frameHeight: Int,
frameOrientation: Int
): Result? {
frameData ?: return null
rotate = if (prefs.autoRotate) {
rotate xor true
} else {
invert = invert xor true
isPortrait(frameOrientation)
}
return try {
if (recreatePreprocessor) {
resetPreProcessor()
recreatePreprocessor = false
}
val pp = preprocessor ?: createPreprocessorAndMapping(
frameWidth,
frameHeight,
frameOrientation
)
val w: Int
val h: Int
if (rotate) {
pp.resizeAndRotate(frameData)
w = pp.outHeight
h = pp.outWidth
} else {
invert = invert xor true
pp.resizeOnly(frameData)
w = pp.outWidth
h = pp.outHeight
}
preprocessor = pp
zxing.decode(frameData, w, h, invert)
} catch (e: RSRuntimeException) {
prefs.forceCompat = prefs.forceCompat xor true
// Now the only option is to restart the app because
// RenderScript.forceCompat() needs to be called before
// RenderScript is initialized.
restartApp()
null
}
}
private fun createPreprocessorAndMapping(
frameWidth: Int,
frameHeight: Int,
frameOrientation: Int
): Preprocessor {
val frameRoi = calculateFrameRect(
frameWidth,
frameHeight,
frameOrientation
)
val pp = Preprocessor(
rs,
frameWidth,
frameHeight,
frameRoi
)
val viewRect = if (frameRoi != null) {
detectorView.roi
} else {
cameraView.previewRect
}
nativeMappingMatrix = getFrameToViewMatrix(
pp.outWidth,
pp.outHeight,
frameOrientation,
viewRect
)
rotatedMappingMatrix = getFrameToViewMatrix(
pp.outHeight,
pp.outWidth,
(frameOrientation - 90 + 360) % 360,
viewRect
)
return pp
}
private fun calculateFrameRect(
frameWidth: Int,
frameHeight: Int,
frameOrientation: Int
): Rect? {
val viewRoi = detectorView.roi
return if (
viewRoi.width() == 0 ||
viewRoi.height() == 0
) {
null
} else {
// Map ROI in detectorView to cameraView.
val previewRect = cameraView.previewRect
// previewRect may be larger than the screen (and thus as the
// detectorView) in which case its left and/or top coordinate
// will be negative which must then be clamped to the
// screen/DetectorView.
val previewLeft = max(0, previewRect.left)
val previewTop = max(0, previewRect.top)
val previewRoi = Rect(
previewLeft + viewRoi.left,
previewTop + viewRoi.top,
previewLeft + viewRoi.right,
previewTop + viewRoi.bottom
)
val previewRectWidth = previewRect.width().toFloat()
val previewRectHeight = previewRect.height().toFloat()
val normalizedRoi = RectF(
previewRoi.left.toFloat() / previewRectWidth,
previewRoi.top.toFloat() / previewRectHeight,
previewRoi.right.toFloat() / previewRectWidth,
previewRoi.bottom.toFloat() / previewRectHeight
)
// Since the ROI is always centered and symmetric, we don't
// need to distinguish between 0 and 180 or 90 and 270 degree.
val errectedRoi = if (isPortrait(frameOrientation)) {
RectF(
normalizedRoi.top,
normalizedRoi.left,
normalizedRoi.bottom,
normalizedRoi.right
)
} else {
normalizedRoi
}
Rect(
(errectedRoi.left * frameWidth.toFloat()).roundToInt(),
(errectedRoi.top * frameHeight.toFloat()).roundToInt(),
(errectedRoi.right * frameWidth.toFloat()).roundToInt(),
(errectedRoi.bottom * frameHeight.toFloat()).roundToInt()
)
}
}
private fun postResult(result: Result) {
// Get matrix for the current rotate value.
val matrix = getMappingMatrix()
val resultPoints = result.resultPoints
if (matrix == null ||
resultPoints == null ||
resultPoints.isEmpty()
) {
return
}
cameraView.post {
detectorView.update(
matrix.map(
resultPoints,
matrix.mapPosition(
result.position,
detectorView.coordinates
)
)
@@ -761,12 +605,6 @@ class CameraActivity : AppCompatActivity() {
}
}
private fun getMappingMatrix() = if (rotate) {
rotatedMappingMatrix
} else {
nativeMappingMatrix
}
companion object {
private const val PICK_FILE_RESULT_CODE = 1
private const val ZOOM_MAX = "zoom_max"
@@ -777,6 +615,34 @@ class CameraActivity : AppCompatActivity() {
}
}
fun Result.redact() = if (
format == Format.PDF_417.name &&
text.isNotEmpty()
) {
Result(
format,
contentType,
String(
text.toByteArray(Charset.forName("ISO-8859-1")),
Charset.forName("UTF-8")
),
position,
orientation,
rawBytes,
ecLevel,
symbologyIdentifier,
sequenceSize,
sequenceIndex,
sequenceId,
readerInit,
lineCount,
versionNumber,
gtin
)
} else {
this
}
fun showResult(
activity: Activity,
result: Result,
@@ -821,45 +687,14 @@ fun showResult(
}
}
fun getReturnIntent(result: Result): Intent {
val intent = Intent()
intent.putExtra("SCAN_RESULT", result.text)
intent.putExtra(
"SCAN_RESULT_FORMAT",
result.barcodeFormat.toString()
)
if (result.rawBytes?.isNotEmpty() == true) {
intent.putExtra("SCAN_RESULT_BYTES", result.rawBytes)
private fun getReturnIntent(result: Result) = Intent().apply {
putExtra("SCAN_RESULT", result.text)
putExtra("SCAN_RESULT_FORMAT", result.format)
putExtra("SCAN_RESULT_ORIENTATION", result.orientation)
putExtra("SCAN_RESULT_ERROR_CORRECTION_LEVEL", result.ecLevel)
if (result.rawBytes.isNotEmpty()) {
putExtra("SCAN_RESULT_BYTES", result.rawBytes)
}
result.resultMetadata?.let { metadata ->
metadata[ResultMetadataType.ORIENTATION]?.let {
intent.putExtra(
"SCAN_RESULT_ORIENTATION",
it.toString()
)
}
metadata[ResultMetadataType.ERROR_CORRECTION_LEVEL]?.let {
intent.putExtra(
"SCAN_RESULT_ERROR_CORRECTION_LEVEL",
it.toString()
)
}
metadata[ResultMetadataType.UPC_EAN_EXTENSION]?.let {
intent.putExtra(
"SCAN_RESULT_UPC_EAN_EXTENSION",
it.toString()
)
}
metadata[ResultMetadataType.BYTE_SEGMENTS]?.let {
var i = 0
@Suppress("UNCHECKED_CAST")
for (seg in it as Iterable<ByteArray>) {
intent.putExtra("SCAN_RESULT_BYTE_SEGMENTS_$i", seg)
++i
}
}
}
return intent
}
private fun String.isReturnUrl() = listOf(
@@ -871,12 +706,9 @@ private fun String.isReturnUrl() = listOf(
private fun completeUrl(urlTemplate: String, result: Result) = Uri.parse(
urlTemplate
.replace("{RESULT}", result.text.urlEncode())
.replace("{RESULT_BYTES}", result.rawBytes?.toHexString() ?: "")
.replace("{RESULT_BYTES}", result.rawBytes.toHexString())
.replace(
"{FORMAT}", result.barcodeFormat.toString().urlEncode()
)
.replace(
"{META}", result.resultMetadata?.toString()?.urlEncode() ?: ""
"{FORMAT}", result.format.urlEncode()
)
// And support {CODE} from the old ZXing app, too.
.replace("{CODE}", result.text.urlEncode())
@@ -897,7 +729,3 @@ private fun beepBeepBeep() {
1000
)
}
private fun isPortrait(
orientation: Int
) = orientation == 90 || orientation == 270
@@ -80,9 +80,7 @@ class MainActivity : AppCompatActivity() {
return when {
intent.hasExtra(PREFERENCES) -> PreferencesFragment()
intent.hasExtra(HISTORY) -> HistoryFragment()
intent.hasExtra(ENCODE) -> EncodeFragment.newInstance(
intent.getStringExtra(ENCODE)!!
)
intent.hasExtra(ENCODE) -> EncodeFragment.newInstance()
intent.hasExtra(DECODED) -> DecodeFragment.newInstance(
intent.getParcelableExtra(DECODED)!!
)
@@ -3,6 +3,7 @@ package de.markusfisch.android.binaryeye.activity
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.Matrix
import android.graphics.Rect
import android.graphics.RectF
import android.net.Uri
@@ -11,19 +12,17 @@ import android.os.Parcelable
import android.os.Vibrator
import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.Toolbar
import android.support.v8.renderscript.RenderScript
import android.view.Menu
import android.view.MenuItem
import com.google.zxing.Result
import de.markusfisch.android.binaryeye.R
import de.markusfisch.android.binaryeye.app.applyLocale
import de.markusfisch.android.binaryeye.app.prefs
import de.markusfisch.android.binaryeye.graphics.crop
import de.markusfisch.android.binaryeye.graphics.fixTransparency
import de.markusfisch.android.binaryeye.graphics.loadImageUri
import de.markusfisch.android.binaryeye.graphics.mapResultToView
import de.markusfisch.android.binaryeye.graphics.mapPosition
import de.markusfisch.android.binaryeye.os.getVibrator
import de.markusfisch.android.binaryeye.os.vibrate
import de.markusfisch.android.binaryeye.rs.fixTransparency
import de.markusfisch.android.binaryeye.view.colorSystemAndToolBars
import de.markusfisch.android.binaryeye.view.initSystemBars
import de.markusfisch.android.binaryeye.view.recordToolbarHeight
@@ -31,16 +30,18 @@ import de.markusfisch.android.binaryeye.view.setPaddingFromWindowInsets
import de.markusfisch.android.binaryeye.widget.CropImageView
import de.markusfisch.android.binaryeye.widget.DetectorView
import de.markusfisch.android.binaryeye.widget.toast
import de.markusfisch.android.binaryeye.zxing.Zxing
import de.markusfisch.android.scalingimageview.widget.ScalingImageView
import de.markusfisch.android.zxingcpp.ZxingCpp
import de.markusfisch.android.zxingcpp.ZxingCpp.Result
import kotlinx.coroutines.*
import kotlin.math.max
import kotlin.math.min
import kotlin.math.roundToInt
class PickActivity : AppCompatActivity() {
private val zxing = Zxing()
private val matrix = Matrix()
private val parentJob = Job()
private val scope = CoroutineScope(Dispatchers.IO + parentJob)
private lateinit var rs: RenderScript
private lateinit var vibrator: Vibrator
private lateinit var cropImageView: CropImageView
private lateinit var detectorView: DetectorView
@@ -60,11 +61,6 @@ class PickActivity : AppCompatActivity() {
// locale.
setTitle(R.string.pick_code_to_scan)
zxing.updateHints(
true,
prefs.barcodeFormats
)
rs = RenderScript.create(this)
vibrator = getVibrator()
initSystemBars(this)
@@ -76,7 +72,7 @@ class PickActivity : AppCompatActivity() {
colorSystemAndToolBars(this@PickActivity)
}
val bitmap = fixTransparency(rs, getBitmapFromIntent())
val bitmap = getBitmapFromIntent()?.fixTransparency()
if (bitmap == null) {
applicationContext.toast(R.string.error_no_content)
finish()
@@ -118,40 +114,55 @@ class PickActivity : AppCompatActivity() {
}
private fun scanWithinBounds(bitmap: Bitmap) {
val roi = Rect(detectorView.roi)
val rectInView = if (roi.width() < 1) {
val viewRoi = if (detectorView.roi.width() < 1) {
cropImageView.getBoundsRect()
} else {
roi
detectorView.roi
}
val imageRect = cropImageView.mappedRect
val rectInImage = normalizeRoi(imageRect, rectInView)
val mappedRect = cropImageView.mappedRect
val cropped = bitmap.crop(
rectInImage,
getNormalizedRoi(mappedRect, viewRoi),
cropImageView.imageRotation,
cropImageView.pivotX,
cropImageView.pivotY
) ?: return
val croppedInView = Rect(
max(viewRoi.left, mappedRect.left.roundToInt()),
max(viewRoi.top, mappedRect.top.roundToInt()),
min(viewRoi.right, mappedRect.right.roundToInt()),
min(viewRoi.bottom, mappedRect.bottom.roundToInt())
)
matrix.apply {
setScale(
croppedInView.width().toFloat() / cropped.width,
croppedInView.height().toFloat() / cropped.height
)
postTranslate(
croppedInView.left.toFloat(),
croppedInView.top.toFloat()
)
}
scope.launch {
result = zxing.decodePositiveNegative(cropped)
result?.let {
ZxingCpp.readBitmap(
cropped,
0, 0,
cropped.width, cropped.height,
0,
prefs.barcodeFormats.joinToString(),
tryHarder = true,
tryRotate = true,
tryInvert = true,
tryDownscale = true
)?.let {
withContext(Dispatchers.Main) {
if (isFinishing) {
return@withContext
}
result = it
vibrator.vibrate()
val rc = Rect()
imageRect.round(rc)
if (!rectInView.intersect(rc)) {
return@withContext
}
detectorView.update(
mapResultToView(
cropped.width,
cropped.height,
0,
rectInView,
it.resultPoints,
matrix.mapPosition(
it.position,
detectorView.coordinates
)
)
@@ -163,7 +174,6 @@ class PickActivity : AppCompatActivity() {
override fun onDestroy() {
super.onDestroy()
detectorView.saveCropHandlePos()
rs.destroy()
parentJob.cancel()
}
@@ -201,7 +211,7 @@ class PickActivity : AppCompatActivity() {
private fun showResult() {
val r = result
if (r != null) {
showResult(this, r, vibrator)
showResult(this, r.redact(), vibrator)
finish()
} else {
applicationContext.toast(R.string.no_barcode_found)
@@ -209,7 +219,7 @@ class PickActivity : AppCompatActivity() {
}
}
private fun normalizeRoi(imageRect: RectF, roi: Rect): RectF {
private fun getNormalizedRoi(imageRect: RectF, roi: Rect): RectF {
val w = imageRect.width()
val h = imageRect.height()
return RectF(
@@ -3,7 +3,6 @@ package de.markusfisch.android.binaryeye.activity
import android.content.Intent
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import de.markusfisch.android.binaryeye.app.setRestartCount
class SplashActivity : AppCompatActivity() {
override fun onCreate(state: Bundle?) {
@@ -13,7 +12,6 @@ class SplashActivity : AppCompatActivity() {
// because that would happen after the app is fully
// initialized what is too late.
intent?.setRestartCount()
startActivity(Intent(applicationContext, CameraActivity::class.java))
finish()
}
@@ -2,6 +2,7 @@ package de.markusfisch.android.binaryeye.adapter
import android.content.Context
import android.database.Cursor
import android.support.v4.content.ContextCompat
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@@ -10,41 +11,71 @@ import android.widget.TextView
import de.markusfisch.android.binaryeye.R
import de.markusfisch.android.binaryeye.database.Database
import java.text.DateFormat
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.*
class ScansAdapter(context: Context, cursor: Cursor) :
CursorAdapter(context, cursor, false) {
var selectedScanId = 0L
var selectedScanPosition = -1
private val idIndex = cursor.getColumnIndex(Database.SCANS_ID)
private val timeIndex = cursor.getColumnIndex(Database.SCANS_DATETIME)
private val nameIndex = cursor.getColumnIndex(Database.SCANS_NAME)
private val contentIndex = cursor.getColumnIndex(Database.SCANS_CONTENT)
private val formatIndex = cursor.getColumnIndex(Database.SCANS_FORMAT)
private val selections = mutableMapOf<Long, Int>()
private val selectedColor = ContextCompat.getColor(
context, R.color.selected_row
)
fun select(id: Long, position: Int) {
selectedScanId = id
selectedScanPosition = position
fun select(view: View, id: Long, position: Int) {
view.select(
if (selections[id] == null) {
selections[id] = position
true
} else {
selections.remove(id)
false
}
)
}
fun clearSelection() {
selectedScanId = 0L
selectedScanPosition = -1
selections.clear()
}
fun getSelectedContent() = if (selectedScanPosition < 0) {
null
} else {
val cursor = getItem(selectedScanPosition)
if (cursor is Cursor) {
cursor.getString(contentIndex)
} else {
null
fun forSelection(callback: (Long, Int) -> Unit) {
selections.forEach {
callback.invoke(it.key, it.value)
}
}
fun getSelectedIds(): List<Long> = mutableListOf<Long>().apply {
forSelection { id, _ ->
add(id)
}
}
fun getSelectedContent(separator: String): String {
val sb = StringBuilder()
forSelection { _, position ->
getContent(position)?.let {
if (sb.isNotEmpty()) {
sb.append(separator)
}
sb.append(it)
}
}
return sb.toString()
}
fun getName(
position: Int
) = (getItem(position) as Cursor?)?.getString(nameIndex)
fun getContent(
position: Int
) = (getItem(position) as Cursor?)?.getString(contentIndex)
override fun newView(
context: Context,
cursor: Cursor,
@@ -78,13 +109,17 @@ class ScansAdapter(context: Context, cursor: Cursor) :
)
formatView.text = prettifyFormatName(cursor.getString(formatIndex))
}
// view.isSelected needs to be put on the queue to work.
val selected = cursor.getLong(idIndex) == selectedScanId
val selected = selections[cursor.getLong(idIndex)] != null
view.post {
view.isSelected = selected
// Needs to be put on the queue to work.
view.select(selected)
}
}
private fun View.select(selected: Boolean) {
setBackgroundColor(if (selected) selectedColor else 0)
}
private fun getViewHolder(
view: View
): ViewHolder = view.tag as ViewHolder? ?: ViewHolder(
@@ -105,11 +140,15 @@ class ScansAdapter(context: Context, cursor: Cursor) :
fun prettifyFormatName(format: String) = format.replace("_", " ")
private fun formatDateTime(rfc: String): String {
SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US).parse(rfc)?.let {
return DateFormat.getDateTimeInstance(
DateFormat.LONG,
DateFormat.SHORT
).format(it)
try {
SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US).parse(rfc)?.let {
return DateFormat.getDateTimeInstance(
DateFormat.LONG,
DateFormat.SHORT
).format(it)
}
} catch (e: ParseException) {
// Ignore and fall through.
}
return rfc
}
@@ -1,7 +1,7 @@
package de.markusfisch.android.binaryeye.app
import android.content.Context
import android.app.AlertDialog
import android.content.Context
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlin.coroutines.resume
@@ -1,21 +1,16 @@
package de.markusfisch.android.binaryeye.app
import android.support.multidex.MultiDexApplication;
import android.support.v8.renderscript.RenderScript
import android.app.Application
import de.markusfisch.android.binaryeye.database.Database
import de.markusfisch.android.binaryeye.preference.Preferences
val db = Database()
val prefs = Preferences()
class BinaryEyeApp : MultiDexApplication() {
class BinaryEyeApp : Application() {
override fun onCreate() {
super.onCreate()
db.open(this)
prefs.init(this)
if (prefs.forceCompat) {
RenderScript.forceCompat()
}
}
}
@@ -5,9 +5,6 @@ import android.os.Build
import java.io.UnsupportedEncodingException
import java.net.URLEncoder
private val nonPrintable = "[\\x00-\\x08\\x0e-\\x1f]".toRegex()
fun String.hasNonPrintableCharacters() = nonPrintable.containsMatchIn(this)
private val nonAlNum = "[^a-zA-Z0-9]".toRegex()
private val multipleDots = "[…]+".toRegex()
fun String.foldNonAlNum() = replace(nonAlNum, "")
@@ -1,24 +0,0 @@
package de.markusfisch.android.binaryeye.app
import android.app.Activity
import android.content.Intent
import de.markusfisch.android.binaryeye.activity.SplashActivity
private const val RESTART_COUNT = "restart_count"
private var restartCount = 0
fun Intent.setRestartCount() {
restartCount = getIntExtra(RESTART_COUNT, restartCount)
}
fun Activity.restartApp() {
if (restartCount < 3) {
startActivity(Intent(this, SplashActivity::class.java).apply {
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
putExtra(RESTART_COUNT, ++restartCount)
})
finish()
}
Runtime.getRuntime().exit(0)
}
@@ -1,17 +1,28 @@
package de.markusfisch.android.binaryeye.content
import android.content.ClipData
import android.content.ClipDescription
import android.content.Context
import android.os.Build
import android.os.PersistableBundle
fun Context.copyToClipboard(text: String) {
fun Context.copyToClipboard(text: String, isSensitive: Boolean = false) {
val service = getSystemService(Context.CLIPBOARD_SERVICE)
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
@Suppress("DEPRECATION")
(service as android.text.ClipboardManager).text = text
} else {
(service as android.content.ClipboardManager).setPrimaryClip(
ClipData.newPlainText("plain text", text)
ClipData.newPlainText("plain text", text).apply {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
description.extras = PersistableBundle().apply {
putBoolean(
ClipDescription.EXTRA_IS_SENSITIVE,
isSensitive
)
}
}
}
)
}
}
}
@@ -34,13 +34,14 @@ private fun exportCsv(
Database.SCANS_FORMAT,
Database.SCANS_CONTENT,
Database.SCANS_ERROR_CORRECTION_LEVEL,
Database.SCANS_ISSUE_NUMBER,
Database.SCANS_ORIENTATION,
Database.SCANS_OTHER_META_DATA,
Database.SCANS_PDF417_EXTRA_METADATA,
Database.SCANS_POSSIBLE_COUNTRY,
Database.SCANS_SUGGESTED_PRICE,
Database.SCANS_UPC_EAN_EXTENSION
Database.SCANS_VERSION_NUMBER,
Database.SCANS_SEQUENCE_SIZE,
Database.SCANS_SEQUENCE_INDEX,
Database.SCANS_SEQUENCE_ID,
Database.SCANS_GTIN_COUNTRY,
Database.SCANS_GTIN_ADD_ON,
Database.SCANS_GTIN_PRICE,
Database.SCANS_GTIN_ISSUE_NUMBER
)
val indices = columns.map {
cursor.getColumnIndex(it)
@@ -2,6 +2,25 @@ package de.markusfisch.android.binaryeye.database
import android.database.Cursor
// Overwrite Kotlin's ".use" function for Cursor because Cursor cannot
// be cast to Closeable below API level 16. This should be removed when
// the minSDK is increased to at least JELLY_BEAN (16).
inline fun <R> Cursor.use(block: (Cursor) -> R): R = try {
block.invoke(this)
} finally {
close()
}
fun Cursor.getInt(name: String): Int {
val idx = getColumnIndex(name)
return if (idx < 0) 0 else getInt(idx)
}
fun Cursor.getLong(name: String): Long {
val idx = getColumnIndex(name)
return if (idx < 0) 0L else getLong(idx)
}
fun Cursor.getString(name: String): String {
val idx = getColumnIndex(name)
return if (idx < 0) "" else getString(idx) ?: ""
@@ -11,8 +30,3 @@ fun Cursor.getBlob(name: String): ByteArray? {
val idx = getColumnIndex(name)
return if (idx < 0) null else getBlob(idx)
}
fun Cursor.getLong(name: String): Long {
val idx = getColumnIndex(name)
return if (idx < 0) 0L else getLong(idx)
}
@@ -36,13 +36,14 @@ class Database {
$SCANS_RAW,
$SCANS_FORMAT,
$SCANS_ERROR_CORRECTION_LEVEL,
$SCANS_ISSUE_NUMBER,
$SCANS_ORIENTATION,
$SCANS_OTHER_META_DATA,
$SCANS_PDF417_EXTRA_METADATA,
$SCANS_POSSIBLE_COUNTRY,
$SCANS_SUGGESTED_PRICE,
$SCANS_UPC_EAN_EXTENSION
$SCANS_VERSION_NUMBER,
$SCANS_SEQUENCE_SIZE,
$SCANS_SEQUENCE_INDEX,
$SCANS_SEQUENCE_ID,
$SCANS_GTIN_COUNTRY,
$SCANS_GTIN_ADD_ON,
$SCANS_GTIN_PRICE,
$SCANS_GTIN_ISSUE_NUMBER
FROM $SCANS
${getWhereClause(query)}
ORDER BY $SCANS_DATETIME DESC
@@ -77,13 +78,14 @@ class Database {
$SCANS_RAW,
$SCANS_FORMAT,
$SCANS_ERROR_CORRECTION_LEVEL,
$SCANS_ISSUE_NUMBER,
$SCANS_ORIENTATION,
$SCANS_OTHER_META_DATA,
$SCANS_PDF417_EXTRA_METADATA,
$SCANS_POSSIBLE_COUNTRY,
$SCANS_SUGGESTED_PRICE,
$SCANS_UPC_EAN_EXTENSION
$SCANS_VERSION_NUMBER,
$SCANS_SEQUENCE_SIZE,
$SCANS_SEQUENCE_INDEX,
$SCANS_SEQUENCE_ID,
$SCANS_GTIN_COUNTRY,
$SCANS_GTIN_ADD_ON,
$SCANS_GTIN_PRICE,
$SCANS_GTIN_ISSUE_NUMBER
FROM $SCANS
WHERE $SCANS_ID = ?
""".trimMargin(), arrayOf("$id")
@@ -94,13 +96,14 @@ class Database {
it.getBlob(SCANS_RAW),
it.getString(SCANS_FORMAT),
it.getString(SCANS_ERROR_CORRECTION_LEVEL),
it.getString(SCANS_ISSUE_NUMBER),
it.getString(SCANS_ORIENTATION),
it.getString(SCANS_OTHER_META_DATA),
it.getString(SCANS_PDF417_EXTRA_METADATA),
it.getString(SCANS_POSSIBLE_COUNTRY),
it.getString(SCANS_SUGGESTED_PRICE),
it.getString(SCANS_UPC_EAN_EXTENSION),
it.getInt(SCANS_VERSION_NUMBER),
it.getInt(SCANS_SEQUENCE_SIZE),
it.getInt(SCANS_SEQUENCE_INDEX),
it.getString(SCANS_SEQUENCE_ID),
it.getString(SCANS_GTIN_COUNTRY),
it.getString(SCANS_GTIN_ADD_ON),
it.getString(SCANS_GTIN_PRICE),
it.getString(SCANS_GTIN_ISSUE_NUMBER),
it.getString(SCANS_DATETIME),
it.getLong(SCANS_ID)
)
@@ -125,13 +128,14 @@ class Database {
scan.errorCorrectionLevel?.let {
put(SCANS_ERROR_CORRECTION_LEVEL, it)
}
scan.issueNumber?.let { put(SCANS_ISSUE_NUMBER, it) }
scan.orientation?.let { put(SCANS_ORIENTATION, it) }
scan.otherMetaData?.let { put(SCANS_OTHER_META_DATA, it) }
scan.pdf417ExtraMetaData?.let { put(SCANS_PDF417_EXTRA_METADATA, it) }
scan.possibleCountry?.let { put(SCANS_POSSIBLE_COUNTRY, it) }
scan.suggestedPrice?.let { put(SCANS_SUGGESTED_PRICE, it) }
scan.upcEanExtension?.let { put(SCANS_UPC_EAN_EXTENSION, it) }
put(SCANS_VERSION_NUMBER, scan.versionNumber)
put(SCANS_SEQUENCE_SIZE, scan.sequenceSize)
put(SCANS_SEQUENCE_INDEX, scan.sequenceIndex)
put(SCANS_SEQUENCE_ID, scan.sequenceId)
scan.country?.let { put(SCANS_GTIN_COUNTRY, it) }
scan.addOn?.let { put(SCANS_GTIN_ADD_ON, it) }
scan.price?.let { put(SCANS_GTIN_PRICE, it) }
scan.issueNumber?.let { put(SCANS_GTIN_ISSUE_NUMBER, it) }
if (prefs.ignoreConsecutiveDuplicates) {
val id = getIdOfLastScan(
get(SCANS_CONTENT) as String,
@@ -188,7 +192,7 @@ class Database {
}
private class OpenHelper(context: Context) :
SQLiteOpenHelper(context, FILE_NAME, null, 4) {
SQLiteOpenHelper(context, FILE_NAME, null, 5) {
override fun onCreate(db: SQLiteDatabase) {
createScans(db)
}
@@ -207,6 +211,9 @@ class Database {
if (oldVersion < 4) {
addNameColumn(db)
}
if (oldVersion < 5) {
migrateToZxingCpp(db)
}
}
}
@@ -220,6 +227,7 @@ class Database {
const val SCANS_RAW = "raw"
const val SCANS_FORMAT = "format"
const val SCANS_ERROR_CORRECTION_LEVEL = "error_correction_level"
const val SCANS_VERSION_NUMBER = "version_number"
const val SCANS_ISSUE_NUMBER = "issue_number"
const val SCANS_ORIENTATION = "orientation"
const val SCANS_OTHER_META_DATA = "other_meta_data"
@@ -227,6 +235,13 @@ class Database {
const val SCANS_POSSIBLE_COUNTRY = "possible_country"
const val SCANS_SUGGESTED_PRICE = "suggested_price"
const val SCANS_UPC_EAN_EXTENSION = "upc_ean_extension"
const val SCANS_SEQUENCE_SIZE = "sequence_size"
const val SCANS_SEQUENCE_INDEX = "sequence_index"
const val SCANS_SEQUENCE_ID = "sequence_id"
const val SCANS_GTIN_COUNTRY = "gtin_country"
const val SCANS_GTIN_ADD_ON = "gtin_add_on"
const val SCANS_GTIN_PRICE = "gtin_price"
const val SCANS_GTIN_ISSUE_NUMBER = "gtin_issue_number"
private fun createScans(db: SQLiteDatabase) {
db.execSQL("DROP TABLE IF EXISTS $SCANS".trimMargin())
@@ -239,13 +254,14 @@ class Database {
$SCANS_RAW BLOB,
$SCANS_FORMAT TEXT NOT NULL,
$SCANS_ERROR_CORRECTION_LEVEL TEXT,
$SCANS_ISSUE_NUMBER INT,
$SCANS_ORIENTATION INT,
$SCANS_OTHER_META_DATA TEXT,
$SCANS_PDF417_EXTRA_METADATA TEXT,
$SCANS_POSSIBLE_COUNTRY TEXT,
$SCANS_SUGGESTED_PRICE TEXT,
$SCANS_UPC_EAN_EXTENSION TEXT
$SCANS_VERSION_NUMBER INTEGER,
$SCANS_SEQUENCE_SIZE INTEGER,
$SCANS_SEQUENCE_INDEX INTEGER,
$SCANS_SEQUENCE_ID TEXT,
$SCANS_GTIN_COUNTRY TEXT,
$SCANS_GTIN_ADD_ON TEXT,
$SCANS_GTIN_PRICE TEXT,
$SCANS_GTIN_ISSUE_NUMBER TEXT
)""".trimMargin()
)
}
@@ -270,5 +286,24 @@ class Database {
private fun addNameColumn(db: SQLiteDatabase) {
db.execSQL("ALTER TABLE $SCANS ADD COLUMN $SCANS_NAME TEXT".trimMargin())
}
private fun migrateToZxingCpp(db: SQLiteDatabase) {
db.apply {
execSQL("ALTER TABLE $SCANS ADD COLUMN $SCANS_VERSION_NUMBER INTEGER".trimMargin())
execSQL("ALTER TABLE $SCANS ADD COLUMN $SCANS_SEQUENCE_SIZE INTEGER".trimMargin())
execSQL("ALTER TABLE $SCANS ADD COLUMN $SCANS_SEQUENCE_INDEX INTEGER".trimMargin())
execSQL("ALTER TABLE $SCANS ADD COLUMN $SCANS_SEQUENCE_ID TEXT".trimMargin())
execSQL("ALTER TABLE $SCANS ADD COLUMN $SCANS_GTIN_COUNTRY TEXT".trimMargin())
execSQL("ALTER TABLE $SCANS ADD COLUMN $SCANS_GTIN_ADD_ON TEXT".trimMargin())
execSQL("ALTER TABLE $SCANS ADD COLUMN $SCANS_GTIN_PRICE TEXT".trimMargin())
execSQL("ALTER TABLE $SCANS ADD COLUMN $SCANS_GTIN_ISSUE_NUMBER TEXT".trimMargin())
execSQL("UPDATE $SCANS SET $SCANS_SEQUENCE_SIZE = -1")
execSQL("UPDATE $SCANS SET $SCANS_SEQUENCE_INDEX = -1")
execSQL("UPDATE $SCANS SET $SCANS_GTIN_COUNTRY = $SCANS_POSSIBLE_COUNTRY")
execSQL("UPDATE $SCANS SET $SCANS_GTIN_ADD_ON = $SCANS_UPC_EAN_EXTENSION")
execSQL("UPDATE $SCANS SET $SCANS_GTIN_PRICE = $SCANS_SUGGESTED_PRICE")
execSQL("UPDATE $SCANS SET $SCANS_GTIN_ISSUE_NUMBER = $SCANS_ISSUE_NUMBER")
}
}
}
}
@@ -26,13 +26,14 @@ fun Cursor.exportJson(): String? {
Database.SCANS_FORMAT,
Database.SCANS_CONTENT,
Database.SCANS_ERROR_CORRECTION_LEVEL,
Database.SCANS_ISSUE_NUMBER,
Database.SCANS_ORIENTATION,
Database.SCANS_OTHER_META_DATA,
Database.SCANS_PDF417_EXTRA_METADATA,
Database.SCANS_POSSIBLE_COUNTRY,
Database.SCANS_SUGGESTED_PRICE,
Database.SCANS_UPC_EAN_EXTENSION
Database.SCANS_VERSION_NUMBER,
Database.SCANS_SEQUENCE_SIZE,
Database.SCANS_SEQUENCE_INDEX,
Database.SCANS_SEQUENCE_ID,
Database.SCANS_GTIN_COUNTRY,
Database.SCANS_GTIN_ADD_ON,
Database.SCANS_GTIN_PRICE,
Database.SCANS_GTIN_ISSUE_NUMBER
)
val indices = columns.map {
Pair(getColumnIndex(it), it)
@@ -1,29 +1,30 @@
package de.markusfisch.android.binaryeye.database
import android.os.Build
import android.os.Parcel
import android.os.Parcelable
import android.text.format.DateFormat
import com.google.zxing.Result
import com.google.zxing.ResultMetadataType
import de.markusfisch.android.binaryeye.app.hasNonPrintableCharacters
import de.markusfisch.android.zxingcpp.ZxingCpp.ContentType
import de.markusfisch.android.zxingcpp.ZxingCpp.Result
data class Scan(
val content: String,
val raw: ByteArray?,
val format: String,
val errorCorrectionLevel: String?,
val issueNumber: String?,
val orientation: String?,
val otherMetaData: String?,
val pdf417ExtraMetaData: String?,
val possibleCountry: String?,
val suggestedPrice: String?,
val upcEanExtension: String?,
val errorCorrectionLevel: String? = null,
val versionNumber: Int = 0,
val sequenceSize: Int = -1,
val sequenceIndex: Int = -1,
val sequenceId: String = "",
val country: String? = null,
val addOn: String? = null,
val price: String? = null,
val issueNumber: String? = null,
val dateTime: String = getDateTime(),
var id: Long = 0L
) : Parcelable {
// Needs to be overwritten manually, as ByteArray is an array and
// this isn't handled well by Kotlin
// this isn't handled well by Kotlin.
override fun equals(other: Any?): Boolean {
if (this === other) {
return true
@@ -41,17 +42,18 @@ data class Scan(
(raw != null && other.raw != null && raw.contentEquals(other.raw))) &&
format == other.format &&
errorCorrectionLevel == other.errorCorrectionLevel &&
issueNumber == other.issueNumber &&
orientation == other.orientation &&
otherMetaData == other.otherMetaData &&
pdf417ExtraMetaData == other.pdf417ExtraMetaData &&
possibleCountry == other.possibleCountry &&
suggestedPrice == other.suggestedPrice &&
upcEanExtension == other.upcEanExtension
versionNumber == other.versionNumber &&
sequenceSize == other.sequenceSize &&
sequenceIndex == other.sequenceIndex &&
sequenceId == other.sequenceId &&
country == other.country &&
addOn == other.addOn &&
price == other.price &&
issueNumber == other.issueNumber
}
// Needs to be overwritten manually, as ByteArray is an array and
// this isn't handled well by Kotlin
// this isn't handled well by Kotlin.
override fun hashCode(): Int {
var result = id.hashCode()
result = 31 * result + dateTime.hashCode()
@@ -59,13 +61,14 @@ data class Scan(
result = 31 * result + (raw?.contentHashCode() ?: 0)
result = 31 * result + format.hashCode()
result = 31 * result + (errorCorrectionLevel?.hashCode() ?: 0)
result = 31 * result + versionNumber
result = 31 * result + sequenceSize
result = 31 * result + sequenceIndex
result = 31 * result + sequenceId.hashCode()
result = 31 * result + (country?.hashCode() ?: 0)
result = 31 * result + (addOn?.hashCode() ?: 0)
result = 31 * result + (price?.hashCode() ?: 0)
result = 31 * result + (issueNumber?.hashCode() ?: 0)
result = 31 * result + (orientation?.hashCode() ?: 0)
result = 31 * result + (otherMetaData?.hashCode() ?: 0)
result = 31 * result + (pdf417ExtraMetaData?.hashCode() ?: 0)
result = 31 * result + (possibleCountry?.hashCode() ?: 0)
result = 31 * result + (suggestedPrice?.hashCode() ?: 0)
result = 31 * result + (upcEanExtension?.hashCode() ?: 0)
return result
}
@@ -74,13 +77,14 @@ data class Scan(
raw = parcel.readSizedByteArray(),
format = parcel.readString() ?: "",
errorCorrectionLevel = parcel.readString(),
versionNumber = parcel.readInt(),
sequenceSize = parcel.readInt(),
sequenceIndex = parcel.readInt(),
sequenceId = parcel.readString() ?: "",
country = parcel.readString(),
addOn = parcel.readString(),
price = parcel.readString(),
issueNumber = parcel.readString(),
orientation = parcel.readString(),
otherMetaData = parcel.readString(),
pdf417ExtraMetaData = parcel.readString(),
possibleCountry = parcel.readString(),
suggestedPrice = parcel.readString(),
upcEanExtension = parcel.readString(),
dateTime = parcel.readString() ?: "",
id = parcel.readLong()
)
@@ -91,13 +95,14 @@ data class Scan(
writeSizedByteArray(raw)
writeString(format)
writeString(errorCorrectionLevel)
writeInt(versionNumber)
writeInt(sequenceSize)
writeInt(sequenceIndex)
writeString(sequenceId)
writeString(country)
writeString(addOn)
writeString(price)
writeString(issueNumber)
writeString(orientation)
writeString(otherMetaData)
writeString(pdf417ExtraMetaData)
writeString(possibleCountry)
writeString(suggestedPrice)
writeString(upcEanExtension)
writeString(dateTime)
writeLong(id)
}
@@ -114,8 +119,16 @@ data class Scan(
}
}
private fun getDateTime(time: Long = System.currentTimeMillis()) = DateFormat.format(
"yyyy-MM-dd HH:mm:ss",
private fun getDateTime(
time: Long = System.currentTimeMillis()
) = DateFormat.format(
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
// Up to API level 17, 'k' was interpreted as 'H', which wasn't
// implemented until API level 18.
"yyyy-MM-dd kk:mm:ss"
} else {
"yyyy-MM-dd HH:mm:ss"
},
time
).toString()
@@ -141,47 +154,28 @@ private fun Parcel.readSizedByteArray(): ByteArray? {
fun Result.toScan(): Scan {
val content: String
val raw: ByteArray?
if (text.hasNonPrintableCharacters()) {
content = ""
raw = getRawData() ?: text.toByteArray()
} else {
content = text
raw = null
when (contentType) {
ContentType.TEXT -> {
content = text
raw = null
}
else -> {
content = ""
raw = rawBytes
}
}
return Scan(
content,
raw,
barcodeFormat.toString(),
getMetaString(ResultMetadataType.ERROR_CORRECTION_LEVEL),
getMetaString(ResultMetadataType.ISSUE_NUMBER),
getMetaString(ResultMetadataType.ORIENTATION),
getMetaString(ResultMetadataType.OTHER),
getMetaString(ResultMetadataType.PDF417_EXTRA_METADATA),
getMetaString(ResultMetadataType.POSSIBLE_COUNTRY),
getMetaString(ResultMetadataType.SUGGESTED_PRICE),
getMetaString(ResultMetadataType.UPC_EAN_EXTENSION)
format,
ecLevel,
versionNumber,
sequenceSize,
sequenceIndex,
sequenceId,
gtin?.country,
gtin?.addOn,
gtin?.price,
gtin?.issueNumber
)
}
private fun Result.getRawData(): ByteArray? {
val metadata = resultMetadata ?: return null
val segments = metadata[ResultMetadataType.BYTE_SEGMENTS] ?: return null
var bytes = ByteArray(0)
@Suppress("UNCHECKED_CAST")
for (seg in segments as Iterable<ByteArray>) {
bytes += seg
}
// If the byte segments are shorter than the converted string, the
// content of the QR Code has been encoded with different encoding
// modes (e.g. some parts in alphanumeric, some in byte encoding).
// This is because Zxing only records byte segments for byte encoded
// parts. Please note the byte segments can actually be longer than
// the string because Zxing cuts off prefixes like "WIFI:".
return if (bytes.size >= text.length) bytes else null
}
private fun Result.getMetaString(
key: ResultMetadataType
): String? = this.resultMetadata?.let {
it[key]?.toString()
}
@@ -9,8 +9,6 @@ import android.os.Bundle
import android.support.v4.app.Fragment
import android.view.*
import android.widget.EditText
import com.google.zxing.BarcodeFormat
import com.google.zxing.EncodeHintType
import de.markusfisch.android.binaryeye.R
import de.markusfisch.android.binaryeye.app.hasWritePermission
import de.markusfisch.android.binaryeye.content.copyToClipboard
@@ -23,9 +21,8 @@ import de.markusfisch.android.binaryeye.view.doOnApplyWindowInsets
import de.markusfisch.android.binaryeye.view.setPaddingFromWindowInsets
import de.markusfisch.android.binaryeye.widget.ConfinedScalingImageView
import de.markusfisch.android.binaryeye.widget.toast
import de.markusfisch.android.binaryeye.zxing.encodeAsBitmap
import de.markusfisch.android.binaryeye.zxing.encodeAsSvg
import de.markusfisch.android.binaryeye.zxing.encodeAsText
import de.markusfisch.android.zxingcpp.ZxingCpp
import de.markusfisch.android.zxingcpp.ZxingCpp.Format
import kotlinx.coroutines.*
import java.io.File
import java.io.FileOutputStream
@@ -41,11 +38,7 @@ class BarcodeFragment : Fragment() {
private val parentJob = Job()
private val scope = CoroutineScope(Dispatchers.IO + parentJob)
private var barcodeBitmap: Bitmap? = null
private var barcodeSvg: String? = null
private var barcodeTxt: String? = null
private var content: String = ""
private var format: BarcodeFormat? = null
private lateinit var barcode: Barcode
override fun onCreate(state: Bundle?) {
super.onCreate(state)
@@ -66,15 +59,13 @@ class BarcodeFragment : Fragment() {
false
)
val args = arguments ?: return view
val content = args.getString(CONTENT) ?: return view
val format = args.getSerializable(FORMAT) as BarcodeFormat? ?: return view
val hints = args.getSerializable(HINTS) as EnumMap<EncodeHintType, Any>?
val size = args.getInt(SIZE)
val bitmap: Bitmap
try {
barcodeBitmap = encodeAsBitmap(content, format, size, size, hints)
barcodeSvg = encodeAsSvg(content, format, hints)
barcodeTxt = encodeAsText(content, format, hints)
barcode = arguments?.toProperties() ?: throw IllegalArgumentException(
"Illegal arguments"
)
// Catch exceptions from encoding.
bitmap = barcode.bitmap
} catch (e: Exception) {
var message = e.message
if (message == null || message.isEmpty()) {
@@ -86,13 +77,11 @@ class BarcodeFragment : Fragment() {
fragmentManager.popBackStack()
return null
}
this.content = content
this.format = format
val imageView = view.findViewById<ConfinedScalingImageView>(
R.id.barcode
)
imageView.setImageBitmap(barcodeBitmap)
imageView.setImageBitmap(bitmap)
imageView.post {
// Make sure to invoke this after ScalingImageView.onLayout().
imageView.minWidth /= 2f
@@ -114,6 +103,19 @@ class BarcodeFragment : Fragment() {
return view
}
private fun Bundle.toProperties() = Barcode(
getString(CONTENT) ?: throw IllegalArgumentException(
"content cannot be null"
),
Format.valueOf(
getString(FORMAT) ?: throw IllegalArgumentException(
"format cannot be null"
)
),
getInt(SIZE),
getInt(EC_LEVEL)
)
override fun onDestroyView() {
super.onDestroyView()
parentJob.cancel()
@@ -126,9 +128,9 @@ class BarcodeFragment : Fragment() {
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.copy_to_clipboard -> {
barcodeTxt?.let {
context.copyToClipboard(it)
context.toast(R.string.copied_to_clipboard)
context.apply {
copyToClipboard(barcode.text)
toast(R.string.copied_to_clipboard)
}
true
}
@@ -167,7 +169,9 @@ class BarcodeFragment : Fragment() {
}
val view = ac.layoutInflater.inflate(R.layout.dialog_save_file, null)
val editText = view.findViewById<EditText>(R.id.file_name)
editText.setText(encodeFileName("${format.toString()}_$content"))
editText.setText(
encodeFileName("${barcode.format}_${barcode.content}")
)
AlertDialog.Builder(ac)
.setView(view)
.setPositiveButton(android.R.string.ok) { _, _ ->
@@ -177,23 +181,19 @@ class BarcodeFragment : Fragment() {
addSuffixIfNotGiven(fileName, ".png"),
MIME_PNG
) {
barcodeBitmap?.saveAsPng(it)
barcode.bitmap.saveAsPng(it)
}
FileType.SVG -> saveAs(
addSuffixIfNotGiven(fileName, ".svg"),
MIME_SVG
) { outputStream ->
barcodeSvg?.let {
outputStream.write(it.toByteArray())
}
outputStream.write(barcode.svg.toByteArray())
}
FileType.TXT -> saveAs(
addSuffixIfNotGiven(fileName, ".txt"),
MIME_TXT
) { outputStream ->
barcodeTxt?.let {
outputStream.write(it.toByteArray())
}
outputStream.write(barcode.text.toByteArray())
}
}
}
@@ -218,9 +218,9 @@ class BarcodeFragment : Fragment() {
private fun Context.shareAs(fileType: FileType) {
when (fileType) {
FileType.PNG -> barcodeBitmap?.let { share(it) }
FileType.SVG -> barcodeSvg?.let { shareText(it, MIME_SVG) }
FileType.TXT -> barcodeTxt?.let { shareText(it) }
FileType.PNG -> share(barcode.bitmap)
FileType.SVG -> shareText(barcode.svg, MIME_SVG)
FileType.TXT -> shareText(barcode.text)
}
}
@@ -251,25 +251,23 @@ class BarcodeFragment : Fragment() {
companion object {
private const val CONTENT = "content"
private const val FORMAT = "format"
private const val HINTS = "hints"
private const val SIZE = "size"
private const val EC_LEVEL = "ec_level"
private const val MIME_PNG = "image/png"
private const val MIME_SVG = "image/svg+xmg"
private const val MIME_TXT = "text/plain"
fun newInstance(
content: String,
format: BarcodeFormat,
format: Format,
size: Int,
hints: EnumMap<EncodeHintType, Any>? = null
ecLevel: Int = -1
): Fragment {
val args = Bundle()
args.putString(CONTENT, content)
args.putSerializable(FORMAT, format)
hints?.let {
args.putSerializable(HINTS, it)
}
args.putString(FORMAT, format.name)
args.putInt(SIZE, size)
args.putInt(EC_LEVEL, ecLevel)
val fragment = BarcodeFragment()
fragment.arguments = args
return fragment
@@ -277,6 +275,26 @@ class BarcodeFragment : Fragment() {
}
}
private data class Barcode(
val content: String,
val format: Format,
val size: Int,
val ecLevel: Int
) {
val bitmap: Bitmap
get() = ZxingCpp.encodeAsBitmap(
content, format, size, size, -1, ecLevel
)
val svg: String
get() = ZxingCpp.encodeAsSvg(
content, format, -1, ecLevel
)
val text: String
get() = ZxingCpp.encodeAsText(
content, format, -1, ecLevel
)
}
private fun Bitmap.saveAsPng(outputStream: OutputStream, quality: Int = 90) =
compress(Bitmap.CompressFormat.PNG, quality, outputStream)
@@ -13,8 +13,6 @@ import android.widget.EditText
import android.widget.TableLayout
import android.widget.TableRow
import android.widget.TextView
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel
import com.google.zxing.qrcode.encoder.Encoder
import de.markusfisch.android.binaryeye.R
import de.markusfisch.android.binaryeye.actions.ActionRegistry
import de.markusfisch.android.binaryeye.actions.wifi.WifiAction
@@ -215,18 +213,27 @@ class DecodeFragment : Fragment() {
private fun fillMetaView(tableLayout: TableLayout, scan: Scan) {
val items = linkedMapOf(
R.string.error_correction_level to scan.errorCorrectionLevel,
R.string.issue_number to scan.issueNumber,
R.string.orientation to scan.orientation,
R.string.other_meta_data to scan.otherMetaData,
R.string.pdf417_extra_metadata to scan.pdf417ExtraMetaData,
R.string.possible_country to scan.possibleCountry,
R.string.suggested_price to scan.suggestedPrice,
R.string.upc_ean_extension to scan.upcEanExtension
R.string.sequence_size to scan.sequenceSize.positiveToString(),
R.string.sequence_index to scan.sequenceIndex.positiveToString(),
R.string.sequence_id to scan.sequenceId,
R.string.gtin_country to scan.country,
R.string.gtin_add_on to scan.addOn,
R.string.gtin_price to scan.price,
R.string.gtin_issue_number to scan.issueNumber,
)
if (prefs.showQrVersion && scan.format == "QR_CODE") {
if (scan.versionNumber > 0) {
val versionString = if (scan.format == "QR_CODE") {
getString(
R.string.qr_version_and_modules,
scan.versionNumber,
scan.versionNumber * 4 + 17
)
} else {
scan.versionNumber.toString()
}
items.putAll(
linkedMapOf(
R.string.qr_version to "${scan.version()}"
R.string.barcode_version_number to versionString
)
)
}
@@ -237,6 +244,10 @@ class DecodeFragment : Fragment() {
tableLayout: TableLayout,
items: LinkedHashMap<Int, String?>
) {
if (items.isEmpty()) {
tableLayout.visibility = View.GONE
return
}
val ctx = tableLayout.context
val spaceBetween = (16f * ctx.resources.displayMetrics.density).toInt()
items.forEach { item ->
@@ -253,9 +264,6 @@ class DecodeFragment : Fragment() {
tableLayout.addView(tr)
}
}
if (tableLayout.childCount > 0) {
tableLayout.setPadding(0, 0, 0, spaceBetween)
}
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
@@ -317,16 +325,16 @@ class DecodeFragment : Fragment() {
if (ac is WifiAction) {
ac.password?.let { password ->
activity?.apply {
copyToClipboard(password)
copyToClipboard(password, isSensitive = true)
toast(R.string.copied_password_to_clipboard)
}
}
}
}
private fun copyToClipboard(text: String) {
private fun copyToClipboard(text: String, isSensitive: Boolean = false) {
activity?.apply {
copyToClipboard(text)
copyToClipboard(text, isSensitive)
toast(R.string.copied_to_clipboard)
}
}
@@ -395,6 +403,8 @@ class DecodeFragment : Fragment() {
}
}
private fun Int.positiveToString() = if (this > -1) this.toString() else ""
private fun hexDump(bytes: ByteArray, charsPerLine: Int = 33): String {
if (charsPerLine < 4 || bytes.isEmpty()) {
return ""
@@ -500,8 +510,3 @@ private fun crc4(input: ByteArray): Int {
crc = crc and 0xF
return crc
}
private fun Scan.version(): Int = Encoder.encode(
content,
ErrorCorrectionLevel.valueOf(errorCorrectionLevel ?: "L")
).version.versionNumber
@@ -6,16 +6,13 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.*
import com.google.zxing.BarcodeFormat
import com.google.zxing.EncodeHintType
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel
import de.markusfisch.android.binaryeye.R
import de.markusfisch.android.binaryeye.adapter.prettifyFormatName
import de.markusfisch.android.binaryeye.app.addFragment
import de.markusfisch.android.binaryeye.app.prefs
import de.markusfisch.android.binaryeye.view.hideSoftKeyboard
import de.markusfisch.android.binaryeye.view.setPaddingFromWindowInsets
import java.util.*
import de.markusfisch.android.zxingcpp.ZxingCpp.Format
class EncodeFragment : Fragment() {
private lateinit var formatView: Spinner
@@ -26,17 +23,17 @@ class EncodeFragment : Fragment() {
private lateinit var contentView: EditText
private val writers = arrayListOf(
BarcodeFormat.AZTEC,
BarcodeFormat.CODABAR,
BarcodeFormat.CODE_39,
BarcodeFormat.CODE_128,
BarcodeFormat.DATA_MATRIX,
BarcodeFormat.EAN_8,
BarcodeFormat.EAN_13,
BarcodeFormat.ITF,
BarcodeFormat.PDF_417,
BarcodeFormat.QR_CODE,
BarcodeFormat.UPC_A
Format.AZTEC,
Format.CODABAR,
Format.CODE_39,
Format.CODE_128,
Format.DATA_MATRIX,
Format.EAN_8,
Format.EAN_13,
Format.ITF,
Format.PDF_417,
Format.QR_CODE,
Format.UPC_A
)
override fun onCreateView(
@@ -71,7 +68,7 @@ class EncodeFragment : Fragment() {
id: Long
) {
val visibility = if (
writers[position] == BarcodeFormat.QR_CODE
writers[position] == Format.QR_CODE
) {
View.VISIBLE
} else {
@@ -94,14 +91,14 @@ class EncodeFragment : Fragment() {
contentView = view.findViewById(R.id.content)
val args = arguments
args?.also {
contentView.setText(it.getString(CONTENT))
args?.getString(CONTENT)?.let {
contentView.setText(it)
}
val barcodeFormat = args?.getString(FORMAT)
if (barcodeFormat != null) {
formatView.setSelection(
writers.indexOf(resolveFormat(barcodeFormat))
writers.indexOf(barcodeFormat.toFormat())
)
} else if (state == null) {
formatView.post {
@@ -125,17 +122,6 @@ class EncodeFragment : Fragment() {
}
private fun encode() {
val hints = EnumMap<EncodeHintType, Any>(EncodeHintType::class.java)
val format = writers[formatView.selectedItemPosition]
if (format == BarcodeFormat.QR_CODE) {
hints[EncodeHintType.ERROR_CORRECTION] = arrayListOf(
ErrorCorrectionLevel.L,
ErrorCorrectionLevel.M,
ErrorCorrectionLevel.Q,
ErrorCorrectionLevel.H
)[errorCorrectionLevel.selectedItemPosition]
}
val size = getSize(sizeBarView.progress)
val content = contentView.text.toString()
if (content.isEmpty()) {
Toast.makeText(
@@ -146,7 +132,12 @@ class EncodeFragment : Fragment() {
} else {
activity?.hideSoftKeyboard(contentView)
fragmentManager?.addFragment(
BarcodeFragment.newInstance(content, format, size, hints)
BarcodeFragment.newInstance(
content,
writers[formatView.selectedItemPosition],
getSize(sizeBarView.progress),
errorCorrectionLevel.selectedItemPosition
)
)
}
}
@@ -181,11 +172,11 @@ class EncodeFragment : Fragment() {
private const val FORMAT = "format"
fun newInstance(
content: String,
content: String? = null,
format: String? = null
): Fragment {
val args = Bundle()
args.putString(CONTENT, content)
content?.let { args.putString(CONTENT, content) }
format?.let { args.putString(FORMAT, it) }
val fragment = EncodeFragment()
fragment.arguments = args
@@ -194,8 +185,8 @@ class EncodeFragment : Fragment() {
}
}
private fun resolveFormat(name: String): BarcodeFormat = try {
BarcodeFormat.valueOf(name)
private fun String.toFormat(default: Format = Format.QR_CODE): Format = try {
Format.valueOf(this)
} catch (_: IllegalArgumentException) {
BarcodeFormat.QR_CODE
default
}
@@ -24,13 +24,14 @@ import de.markusfisch.android.binaryeye.app.*
import de.markusfisch.android.binaryeye.content.copyToClipboard
import de.markusfisch.android.binaryeye.content.shareText
import de.markusfisch.android.binaryeye.database.Database
import de.markusfisch.android.binaryeye.database.getString
import de.markusfisch.android.binaryeye.database.exportCsv
import de.markusfisch.android.binaryeye.database.exportDatabase
import de.markusfisch.android.binaryeye.database.exportJson
import de.markusfisch.android.binaryeye.database.use
import de.markusfisch.android.binaryeye.io.askForFileName
import de.markusfisch.android.binaryeye.io.toSaveResult
import de.markusfisch.android.binaryeye.view.*
import de.markusfisch.android.binaryeye.widget.ellipsize
import de.markusfisch.android.binaryeye.widget.toast
import kotlinx.coroutines.*
@@ -76,7 +77,7 @@ class HistoryFragment : Fragment() {
val ac = activity ?: return false
return when (item.itemId) {
R.id.copy_scan -> {
scansAdapter?.getSelectedContent()?.let {
scansAdapter?.getSelectedContent("\n")?.let {
ac.copyToClipboard(it)
ac.toast(R.string.copied_to_clipboard)
}
@@ -84,19 +85,21 @@ class HistoryFragment : Fragment() {
true
}
R.id.edit_scan -> {
scansAdapter?.let {
askForName(
ac,
it.selectedScanId,
getScanName(it.selectedScanPosition)
scansAdapter?.forSelection { id, position ->
ac.askForName(
id,
scansAdapter?.getName(position),
scansAdapter?.getContent(position)
)
}
closeActionMode()
true
}
R.id.remove_scan -> {
scansAdapter?.let {
askToRemoveScan(ac, it.selectedScanId)
scansAdapter?.getSelectedIds()?.let {
if (it.isNotEmpty()) {
ac.askToRemoveScans(it)
}
}
closeActionMode()
true
@@ -146,8 +149,7 @@ class HistoryFragment : Fragment() {
showScan(id)
}
listView.setOnItemLongClickListener { _, v, position, id ->
v.isSelected = true
scansAdapter?.select(id, position)
scansAdapter?.select(v, id, position)
if (actionMode == null && ac is AppCompatActivity) {
actionMode = ac.delegate.startSupportActionMode(
actionModeCallback
@@ -159,7 +161,7 @@ class HistoryFragment : Fragment() {
fab = view.findViewById(R.id.share)
fab.setOnClickListener { v ->
pickListSeparatorAndShare(v.context)
v.context.pickListSeparatorAndShare()
}
progressView = view.findViewById(R.id.progress_view)
@@ -221,7 +223,7 @@ class HistoryFragment : Fragment() {
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.clear -> {
askToRemoveScans(context)
context.askToRemoveScans()
true
}
R.id.export_history -> {
@@ -300,20 +302,22 @@ class HistoryFragment : Fragment() {
}
}
private fun getScanName(position: Int): String? {
val cursor = scansAdapter?.getItem(position) as Cursor?
return cursor?.getString(Database.SCANS_NAME)
}
// Dialogs don't have a parent layout.
@SuppressLint("InflateParams")
private fun askForName(context: Context, id: Long, text: String?) {
val view = LayoutInflater.from(context).inflate(
private fun Context.askForName(id: Long, text: String?, content: String?) {
val view = LayoutInflater.from(this).inflate(
R.layout.dialog_enter_name, null
)
val nameView = view.findViewById<EditText>(R.id.name)
nameView.setText(text)
AlertDialog.Builder(context)
AlertDialog.Builder(this)
.setTitle(
if (content.isNullOrEmpty()) {
getString(R.string.binary_data)
} else {
content.ellipsize(64)
}
)
.setView(view)
.setPositiveButton(android.R.string.ok) { _, _ ->
val name = nameView.text.toString()
@@ -324,11 +328,17 @@ class HistoryFragment : Fragment() {
.show()
}
private fun askToRemoveScan(context: Context, id: Long) {
AlertDialog.Builder(context)
.setMessage(R.string.really_remove_scan)
private fun Context.askToRemoveScans(ids: List<Long>) {
AlertDialog.Builder(this)
.setMessage(
if (ids.size > 1) {
R.string.really_remove_selected_scans
} else {
R.string.really_remove_scan
}
)
.setPositiveButton(android.R.string.ok) { _, _ ->
db.removeScan(id)
ids.forEach { db.removeScan(it) }
if (scansAdapter?.count == 1) {
updateAndClearFilter()
} else {
@@ -340,8 +350,8 @@ class HistoryFragment : Fragment() {
.show()
}
private fun askToRemoveScans(context: Context) {
AlertDialog.Builder(context)
private fun Context.askToRemoveScans() {
AlertDialog.Builder(this)
.setMessage(
if (filter == null) {
R.string.really_remove_all_scans
@@ -402,11 +412,11 @@ class HistoryFragment : Fragment() {
}
}
private fun pickListSeparatorAndShare(context: Context) {
val separators = context.resources.getStringArray(
private fun Context.pickListSeparatorAndShare() {
val separators = resources.getStringArray(
R.array.list_separators_values
)
AlertDialog.Builder(context)
AlertDialog.Builder(this)
.setTitle(R.string.pick_list_separator)
.setItems(R.array.list_separators_names) { _, which ->
shareScans(separators[which])
@@ -52,28 +52,28 @@ class PreferencesFragment : PreferenceFragmentCompat() {
pref.isVisible = false
} else {
pref.setOnPreferenceClickListener {
askToClearNetworkSuggestions(context)
context.askToClearNetworkSuggestions()
true
}
}
}
@RequiresApi(Build.VERSION_CODES.Q)
private fun askToClearNetworkSuggestions(context: Context) {
AlertDialog.Builder(context)
private fun Context.askToClearNetworkSuggestions() {
AlertDialog.Builder(this)
.setMessage(R.string.really_remove_all_networks)
.setPositiveButton(android.R.string.ok) { _, _ ->
clearNetworkSuggestions(context)
clearNetworkSuggestions()
}
.setNegativeButton(android.R.string.cancel) { _, _ -> }
.show()
}
@RequiresApi(Build.VERSION_CODES.Q)
private fun clearNetworkSuggestions(context: Context) {
context.toast(
private fun Context.clearNetworkSuggestions() {
toast(
if (
removeNetworkSuggestions(context) == WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS
removeNetworkSuggestions(this) == WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS
) {
R.string.clear_network_suggestions_success
} else {
@@ -50,15 +50,7 @@ class UrlDialogFragment : PreferenceDialogFragmentCompat() {
Scan(
"test",
null,
"none",
null,
null,
null,
null,
null,
null,
null,
null
"none"
).sendAsync(url, prefs.sendScanType) { code, body ->
textView.text = when {
code != null -> "$code"
@@ -2,61 +2,86 @@ package de.markusfisch.android.binaryeye.graphics
import android.graphics.Matrix
import android.graphics.Rect
import com.google.zxing.ResultPoint
import android.graphics.RectF
import de.markusfisch.android.zxingcpp.ZxingCpp.Position
import kotlin.math.roundToInt
fun mapResultToView(
frameWidth: Int,
frameHeight: Int,
frameOrientation: Int,
viewRect: Rect,
resultPoints: Array<ResultPoint?>,
targetArray: FloatArray
): Int = getFrameToViewMatrix(
frameWidth,
frameHeight,
frameOrientation,
viewRect
).map(
resultPoints,
targetArray
data class FrameMetrics(
var width: Int = 0,
var height: Int = 0,
var orientation: Int = 0
)
fun getFrameToViewMatrix(
frameWidth: Int,
frameHeight: Int,
frameOrientation: Int,
viewRect: Rect
) = Matrix().apply {
// Normalize to frame dimensions for rotation.
postScale(
1f / frameWidth,
1f / frameHeight
)
// Rotate around center.
postRotate(frameOrientation.toFloat(), 0.5f, 0.5f)
// Scale up to view size.
postScale(viewRect.width().toFloat(), viewRect.height().toFloat())
// Apply view displacement.
postTranslate(viewRect.left.toFloat(), viewRect.top.toFloat())
fun Rect.setFrameRoi(
frameMetrics: FrameMetrics,
viewRect: Rect,
viewRoi: Rect
) {
Matrix().apply {
// Map ROI from view coordinates to frame coordinates.
setScale(1f / viewRect.width(), 1f / viewRect.height())
postRotate(-frameMetrics.orientation.toFloat(), .5f, .5f)
postScale(frameMetrics.width.toFloat(), frameMetrics.height.toFloat())
postTranslate(-viewRect.left.toFloat(), -viewRect.top.toFloat())
val frameRoiF = RectF()
val viewRoiF = RectF(
viewRoi.left.toFloat(),
viewRoi.top.toFloat(),
viewRoi.right.toFloat(),
viewRoi.bottom.toFloat()
)
mapRect(frameRoiF, viewRoiF)
set(
frameRoiF.left.roundToInt(),
frameRoiF.top.roundToInt(),
frameRoiF.right.roundToInt(),
frameRoiF.bottom.roundToInt()
)
}
}
fun Matrix.map(
resultPoints: Array<ResultPoint?>,
targetArray: FloatArray
): Int {
val max = targetArray.size
var i = 0
for (resultPoint in resultPoints) {
// Because ZXing apparently returns null in this array sometimes.
if (resultPoint == null) {
continue
fun Matrix.setFrameToView(
frameMetrics: FrameMetrics,
viewRect: Rect,
viewRoi: Rect? = null
) {
// Configure this matrix to map points in frame coordinates to
// view coordinates.
val uprightWidth: Int
val uprightHeight: Int
when (frameMetrics.orientation) {
90, 270 -> {
uprightWidth = frameMetrics.height
uprightHeight = frameMetrics.width
}
targetArray[i++] = resultPoint.x
targetArray[i++] = resultPoint.y
if (i >= max) {
break
else -> {
uprightWidth = frameMetrics.width
uprightHeight = frameMetrics.height
}
}
mapPoints(targetArray, 0, targetArray, 0, i)
setScale(
viewRect.width().toFloat() / uprightWidth,
viewRect.height().toFloat() / uprightHeight
)
viewRoi?.let {
postTranslate(viewRoi.left.toFloat(), viewRoi.top.toFloat())
}
}
fun Matrix.mapPosition(
position: Position,
coords: FloatArray
): Int {
var i = 0
setOf(
position.topLeft,
position.topRight,
position.bottomRight,
position.bottomLeft
).forEach {
coords[i++] = it.x.toFloat()
coords[i++] = it.y.toFloat()
}
mapPoints(coords)
return i
}
@@ -0,0 +1,57 @@
package de.markusfisch.android.binaryeye.graphics
import android.graphics.Bitmap
import android.graphics.Canvas
fun Bitmap.fixTransparency(): Bitmap {
val result = analyzeTransparency()
return if (result.hasTransparentPixels) {
val copy = Bitmap.createBitmap(
width,
height,
config
)
Canvas(copy).apply {
drawColor(result.backgroundColor)
drawBitmap(this@fixTransparency, 0f, 0f, null)
}
copy
} else {
this
}
}
private fun Bitmap.analyzeTransparency(): Result {
val pixels = IntArray(width * height)
getPixels(pixels, 0, width, 0, 0, width, height)
var transparent = 0
var visible = 0
var bright = 0
for (pixel in pixels) {
val alpha = (pixel shr 24) and 0xff
if (alpha < 0xff) {
++transparent
}
if (alpha > 0) {
++visible
if (
((pixel shr 16) and 0xff) +
((pixel shr 8) and 0xff) +
(pixel and 0xff) > 128
) ++bright
}
}
return Result(
transparent > 0,
if (bright > 0 && visible / bright < 2) {
0xff000000.toInt()
} else {
0xffffffff.toInt()
}
)
}
private data class Result(
val hasTransparentPixels: Boolean,
val backgroundColor: Int
)
@@ -69,13 +69,14 @@ private fun Scan.getMap(): Map<String, String> = mapOf(
"raw" to raw?.toHexString(),
"format" to format,
"errorCorrectionLevel" to errorCorrectionLevel,
"versionNumber" to versionNumber.toString(),
"sequenceSize" to sequenceSize.toString(),
"sequenceIndex" to sequenceIndex.toString(),
"sequenceId" to sequenceId,
"country" to country,
"addOn" to addOn,
"price" to price,
"issueNumber" to issueNumber,
"orientation" to orientation,
"otherMetaData" to otherMetaData,
"pdf417ExtraMetaData" to pdf417ExtraMetaData,
"possibleCountry" to possibleCountry,
"suggestedPrice" to suggestedPrice,
"upcEanExtension" to upcEanExtension,
"timestamp" to dateTime
).filterNullValues()
@@ -5,28 +5,29 @@ import android.content.SharedPreferences
import android.os.Build
import android.preference.PreferenceManager
import android.support.annotation.RequiresApi
import de.markusfisch.android.zxingcpp.ZxingCpp.Format
class Preferences {
lateinit var preferences: SharedPreferences
var barcodeFormats = setOf(
"AZTEC",
"CODABAR",
"CODE_39",
"CODE_93",
"CODE_128",
"DATA_MATRIX",
"EAN_8",
"EAN_13",
"ITF",
"MAXICODE",
"PDF_417",
"QR_CODE",
"RSS_14",
"RSS_EXPANDED",
"UPC_A",
"UPC_E",
"UPC_EAN_EXTENSION"
Format.AZTEC.name,
Format.CODABAR.name,
Format.CODE_39.name,
Format.CODE_93.name,
Format.CODE_128.name,
Format.DATA_BAR.name,
Format.DATA_BAR_EXPANDED.name,
Format.DATA_MATRIX.name,
Format.EAN_8.name,
Format.EAN_13.name,
Format.ITF.name,
Format.MAXICODE.name,
Format.PDF_417.name,
Format.QR_CODE.name,
Format.MICRO_QR_CODE.name,
Format.UPC_A.name,
Format.UPC_E.name,
)
@RequiresApi(Build.VERSION_CODES.HONEYCOMB)
set(value) {
@@ -123,11 +124,6 @@ class Preferences {
apply(SHOW_META_DATA, value)
field = value
}
var showQrVersion = false
set(value) {
apply(SHOW_QR_VERSION, value)
field = value
}
var showHexDump = true
set(value) {
apply(SHOW_HEX_DUMP, value)
@@ -229,7 +225,6 @@ class Preferences {
openImmediately
)
showMetaData = preferences.getBoolean(SHOW_META_DATA, showMetaData)
showQrVersion = preferences.getBoolean(SHOW_QR_VERSION, showQrVersion)
showHexDump = preferences.getBoolean(SHOW_HEX_DUMP, showHexDump)
closeAutomatically = preferences.getBoolean(
CLOSE_AUTOMATICALLY,
@@ -293,7 +288,7 @@ class Preferences {
}
companion object {
private const val BARCODE_FORMATS = "barcode_formats"
private const val BARCODE_FORMATS = "formats"
private const val CROP_HANDLE_X = "crop_handle_x"
private const val CROP_HANDLE_Y = "crop_handle_y"
private const val CROP_HANDLE_ORIENTATION = "crop_handle_orientation"
@@ -310,7 +305,6 @@ class Preferences {
private const val OPEN_IMMEDIATELY = "open_immediately"
private const val COPY_IMMEDIATELY = "copy_immediately"
private const val SHOW_META_DATA = "show_meta_data"
private const val SHOW_QR_VERSION = "show_qr_version"
private const val SHOW_HEX_DUMP = "show_hex_dump"
private const val CLOSE_AUTOMATICALLY = "close_automatically"
private const val DEFAULT_SEARCH_URL = "default_search_url"
@@ -1,42 +0,0 @@
package de.markusfisch.android.binaryeye.rs
import android.graphics.Bitmap
import android.graphics.Canvas
import android.support.v8.renderscript.Allocation
import android.support.v8.renderscript.RenderScript
fun fixTransparency(rs: RenderScript, bitmap: Bitmap?): Bitmap? {
bitmap ?: return null
val result = analyze(rs, bitmap)
return if (result.hasTransparentPixels) {
val copy = Bitmap.createBitmap(
bitmap.width,
bitmap.height,
bitmap.config
)
Canvas(copy).apply {
drawColor(result.backgroundColor)
drawBitmap(bitmap, 0f, 0f, null)
}
copy
} else {
bitmap
}
}
private fun analyze(rs: RenderScript, bitmap: Bitmap): Result {
val analyzeScript = ScriptC_analyze(rs)
val bitmapAllocation = Allocation.createFromBitmap(rs, bitmap)
val result = analyzeScript.reduce_analyze(bitmapAllocation).get()
bitmapAllocation.destroy()
analyzeScript.destroy()
return Result(
result.x > 0,
if (result.y > 0) 0xff000000.toInt() else 0xffffffff.toInt()
)
}
private data class Result(
val hasTransparentPixels: Boolean,
val backgroundColor: Int
)
@@ -1,156 +0,0 @@
package de.markusfisch.android.binaryeye.rs
import android.graphics.Rect
import android.support.v8.renderscript.*
import kotlin.math.max
import kotlin.math.roundToInt
private const val SCALE_FACTOR = .75f
class Preprocessor(
rs: RenderScript,
width: Int,
height: Int,
private val roi: Rect?
) {
var outWidth = 0
var outHeight = 0
private val resizeScript = ScriptIntrinsicResize.create(rs)
private val rotateScript = ScriptC_rotate(rs)
private var yuvType: Type? = null
private var yuvAlloc: Allocation? = null
private var roiType: Type? = null
private var roiAlloc: Allocation? = null
private var resizedType: Type? = null
private var resizedAlloc: Allocation? = null
private var rotatedType: Type? = null
private var rotatedAlloc: Allocation? = null
init {
yuvType = Type.createXY(
rs,
Element.U8(rs),
width,
height // use only grayscale part
)
yuvAlloc = Allocation.createTyped(
rs,
yuvType,
Allocation.USAGE_SCRIPT
)
if (roi != null) {
val roiWidth = roi.width()
val roiHeight = roi.height()
roiType = Type.createXY(
rs,
Element.U8(rs),
roiWidth,
roiHeight
)
roiAlloc = Allocation.createTyped(
rs,
roiType,
Allocation.USAGE_SCRIPT
)
outWidth = (roiWidth * SCALE_FACTOR).roundToInt()
outHeight = (roiHeight * SCALE_FACTOR).roundToInt()
// Make sure the dimensions are always a multiple of 4.
outWidth -= outWidth % 4
outHeight -= outHeight % 4
// Make sure the dimensions are always greater than 4.
outWidth = max(4, outWidth)
outHeight = max(4, outHeight)
} else {
outWidth = (width * SCALE_FACTOR).roundToInt()
outHeight = (height * SCALE_FACTOR).roundToInt()
}
resizedType = Type.createXY(
rs,
Element.U8(rs),
outWidth,
outHeight
)
resizedAlloc = Allocation.createTyped(
rs,
resizedType,
Allocation.USAGE_SCRIPT
)
rotatedType = Type.createXY(
rs,
Element.U8(rs),
outHeight,
outWidth
)
rotatedAlloc = Allocation.createTyped(
rs,
rotatedType,
Allocation.USAGE_SCRIPT
)
}
fun destroy() {
yuvType?.destroy()
yuvType = null
yuvAlloc?.destroy()
yuvAlloc = null
roiType?.destroy()
roiType = null
roiAlloc?.destroy()
roiAlloc = null
resizedType?.destroy()
resizedType = null
resizedAlloc?.destroy()
resizedAlloc = null
rotatedType?.destroy()
rotatedType = null
rotatedAlloc?.destroy()
rotatedAlloc = null
resizeScript.destroy()
rotateScript.destroy()
}
fun resizeOnly(frame: ByteArray) {
resize(frame)
resizedAlloc?.copyTo(frame)
}
fun resizeAndRotate(frame: ByteArray) {
resize(frame)
val t = resizedType ?: return
rotateScript._inImage = resizedAlloc
rotateScript._inWidth = t.x
rotateScript._inHeight = t.y
rotateScript.forEach_rotate90(
rotatedAlloc, // Ignored in kernel, just to satisfy forEach.
rotatedAlloc
)
rotatedAlloc?.copyTo(frame)
}
private fun resize(frame: ByteArray) {
yuvAlloc?.copyFrom(frame)
resizeScript.setInput(
if (roi != null) {
roiAlloc?.copy2DRangeFrom(
0, 0,
roi.width(), roi.height(),
yuvAlloc,
max(0, roi.left), max(0, roi.top)
)
roiAlloc
} else {
yuvAlloc
}
)
resizeScript.forEach_bicubic(resizedAlloc)
}
}
@@ -8,11 +8,10 @@ import de.markusfisch.android.binaryeye.activity.CameraActivity
@RequiresApi(Build.VERSION_CODES.N)
class ScanTileService : TileService() {
@RequiresApi(Build.VERSION_CODES.N)
override fun onClick() {
super.onClick()
val intent = Intent(applicationContext, CameraActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
startActivityAndCollapse(intent)
}
}
}
@@ -15,7 +15,7 @@ fun Context.toast(message: String) = Toast.makeText(
Toast.LENGTH_LONG
).show()
private fun String.ellipsize(max: Int) = if (length < max) {
fun String.ellipsize(max: Int) = if (length < max) {
this
} else {
"${take(max)}"
@@ -1,196 +0,0 @@
package de.markusfisch.android.binaryeye.zxing
import android.graphics.Bitmap
import com.google.zxing.*
import com.google.zxing.common.BitMatrix
import com.google.zxing.common.HybridBinarizer
import java.util.*
class Zxing(possibleResultPoint: ResultPointCallback? = null) {
private val hints = EnumMap<DecodeHintType, Any>(DecodeHintType::class.java)
private val multiFormatReader = MultiFormatReader()
init {
possibleResultPoint?.let {
hints[DecodeHintType.NEED_RESULT_POINT_CALLBACK] = it
}
}
fun updateHints(tryHarder: Boolean, formats: Set<String>) {
if (tryHarder) {
hints[DecodeHintType.TRY_HARDER] = java.lang.Boolean.TRUE
} else {
hints.remove(DecodeHintType.TRY_HARDER)
}
setDecodeFormats(formats)
}
private fun setDecodeFormats(formats: Set<String>) {
hints[DecodeHintType.POSSIBLE_FORMATS] = EnumSet.noneOf(
BarcodeFormat::class.java
).apply {
addAll(
EnumSet.copyOf(
formats.map { BarcodeFormat.valueOf(it) }
)
)
}
}
fun decode(
yuvData: ByteArray,
width: Int,
height: Int,
invert: Boolean = false
): Result? = decodeLuminanceSource(
PlanarYUVLuminanceSource(
yuvData,
width,
height,
0,
0,
width,
height,
false
),
invert
)
fun decodePositiveNegative(bitmap: Bitmap): Result? =
decode(bitmap, false) ?: decode(bitmap, true)
private fun decode(
bitmap: Bitmap,
invert: Boolean = false
): Result? {
val width = bitmap.width
val height = bitmap.height
val pixels = IntArray(width * height)
if (bitmap.config != Bitmap.Config.ARGB_8888) {
bitmap.copy(Bitmap.Config.ARGB_8888, true)
} else {
bitmap
}.getPixels(pixels, 0, width, 0, 0, width, height)
return decodeLuminanceSource(
RGBLuminanceSource(width, height, pixels),
invert
)
}
private fun decodeLuminanceSource(
source: LuminanceSource,
invert: Boolean
): Result? = decodeLuminanceSource(
if (invert) {
source.invert()
} else {
source
}
)
private fun decodeLuminanceSource(source: LuminanceSource): Result? = try {
multiFormatReader.decode(
BinaryBitmap(HybridBinarizer(source)),
hints
)
} catch (e: Exception) {
// Usually it's bad practice to blindly catch *all* exceptions
// because this can hide problems we want to know about. But
// since ZXing has some errors (like all software) and I don't
// want this app to break in the hands of my users, which won't
// see the stack trace anyway, it's better to just catch all
// exceptions here and live on.
null
} finally {
multiFormatReader.reset()
}
}
private const val BLACK = 0xff000000.toInt()
private const val WHITE = 0xffffffff.toInt()
fun encodeAsBitmap(
text: String,
format: BarcodeFormat,
width: Int,
height: Int,
hints: EnumMap<EncodeHintType, Any>? = null
): Bitmap? {
val bitMatrix = encode(text, format, hints, width, height)
val w = bitMatrix.width
val h = bitMatrix.height
val pixels = IntArray(w * h)
var offset = 0
for (y in 0 until h) {
for (x in 0 until w) {
pixels[offset + x] = if (bitMatrix.get(x, y)) {
BLACK
} else {
WHITE
}
}
offset += w
}
val bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888)
bitmap.setPixels(pixels, 0, w, 0, 0, w, h)
return bitmap
}
fun encodeAsSvg(
text: String,
format: BarcodeFormat,
hints: EnumMap<EncodeHintType, Any>? = null
): String {
val bitMatrix = encode(text, format, hints)
val sb = StringBuilder()
val w = bitMatrix.width
var h = bitMatrix.height
val moduleHeight = if (h == 1) w / 2 else 1
for (y in 0 until h) {
for (x in 0 until w) {
if (bitMatrix.get(x, y)) {
sb.append(" M${x},${y}h1v${moduleHeight}h-1z")
}
}
}
h *= moduleHeight
return """<svg width="$w" height="$h"
viewBox="0 0 $w $h"
xmlns="http://www.w3.org/2000/svg">
<path d="$sb"/>
</svg>
"""
}
fun encodeAsText(
text: String,
format: BarcodeFormat,
hints: EnumMap<EncodeHintType, Any>? = null
): String {
val bitMatrix = encode(text, format, hints)
val w = bitMatrix.width
val h = bitMatrix.height
val sb = StringBuilder()
for (y in 0 until h) {
for (x in 0 until w) {
sb.append(if (bitMatrix.get(x, y)) "" else " ")
}
sb.append("\n")
}
return sb.toString()
}
private fun encode(
text: String,
format: BarcodeFormat,
encodeHints: EnumMap<EncodeHintType, Any>? = null,
width: Int = 0,
height: Int = 0
): BitMatrix = MultiFormatWriter().encode(
text, format, width, height,
(encodeHints ?: EnumMap<EncodeHintType, Any>(EncodeHintType::class.java)).apply {
if (!contains(EncodeHintType.CHARACTER_SET)) {
this[EncodeHintType.CHARACTER_SET] = "utf-8"
}
}
)
@@ -1,3 +1,3 @@
<vector android:height="24dp" android:tint="#FFFFFF" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M3 11h8V3H3v8zm2-6h4v4H5V5zM3 21h8v-8H3v8zm2-6h4v4H5v-4zm8-12v8h8V3h-8zm6 6h-4V5h4v4zm0 10h2v2h-2zm-6-6h2v2h-2zm2 2h2v2h-2zm-2 2h2v2h-2zm2 2h2v2h-2zm2-2h2v2h-2zm0-4h2v2h-2zm2 2h2v2h-2z"/>
<path android:fillColor="#FF000000" android:pathData="M3 11h8V3H3v8zm2-6h4v4H5V5zM3 21h8v-8H3v8zm2-6h4v4H5v-4zm8-12v8h8V3h-8zm6 6h-4V5h4v4zm0 10h2v2h-2zm-6-6h2v2h-2zm2 2h2v2h-2zm-2 2h2v2h-2zm2 2h2v2h-2zm2-2h2v2h-2zm0-4h2v2h-2zm2 2h2v2h-2z"/>
</vector>
+1 -3
View File
@@ -1,7 +1,5 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@color/selected_row"
<item android:drawable="@color/pressed_row"
android:state_pressed="true"/>
<item android:drawable="@color/selected_row"
android:state_selected="true"/>
<item android:drawable="@android:color/transparent"/>
</selector>
+7 -31
View File
@@ -8,18 +8,15 @@
android:clipToPadding="false"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<EditText
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginStart="16dp"
android:layout_marginLeft="16dp"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:gravity="start|top"
android:hint="@string/content"
android:imeOptions="flagNoExtractUi"
@@ -32,38 +29,22 @@
android:id="@+id/format"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/content"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:layout_marginBottom="16dp"
android:gravity="end|top"/>
<TableLayout
android:id="@+id/data"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/format"
android:layout_marginEnd="16dp"
android:layout_marginStart="16dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"/>
android:layout_marginBottom="16dp"/>
<TableLayout
android:id="@+id/meta"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/data"
android:layout_marginEnd="16dp"
android:layout_marginStart="16dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"/>
android:layout_marginBottom="16dp"/>
<TextView
android:id="@+id/hex"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/meta"
android:layout_marginStart="16dp"
android:layout_marginLeft="16dp"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:layout_marginBottom="16dp"
android:typeface="monospace"
android:textSize="12sp"
@@ -72,15 +53,10 @@
android:id="@+id/stamp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/hex"
android:layout_marginStart="16dp"
android:layout_marginLeft="16dp"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:layout_marginBottom="16dp"
android:textSize="12sp"
android:typeface="monospace"/>
</RelativeLayout>
</LinearLayout>
</de.markusfisch.android.binaryeye.widget.ConfinedScrollView>
<android.support.design.widget.CoordinatorLayout
android:id="@+id/inset_layout"
+1 -1
View File
@@ -6,7 +6,7 @@
android:id="@+id/scans"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:choiceMode="singleChoice"
android:choiceMode="multipleChoice"
android:clipToPadding="false"
android:divider="@color/separator"
android:dividerHeight="1px"/>
+9 -10
View File
@@ -15,14 +15,15 @@
<string name="error_correction_level_m" formatted="false">মধ্যম (~১৫&#37; ঠিককরণ)</string>
<string name="error_correction_level_q" formatted="false">বেশি (~২৫&#37; ঠিককরণ)</string>
<string name="error_correction_level_h" formatted="false">অনেক বেশি (~৩০&#37; ঠিককরণ)</string>
<string name="issue_number">সমস্যা ক্রম</string>
<string name="orientation">দিক</string>
<string name="other_meta_data">মেটাতথ্য</string>
<string name="pdf417_extra_metadata">পিডিএফ৪১৭ মেটাতথ্য</string>
<string name="possible_country">তৈরির সম্ভাব্য দেশ</string>
<string name="suggested_price">প্রস্তসবিত দাম</string>
<string name="upc_ean_extension">ইউপিসি ইএএন বর্ধিত</string>
<string name="qr_version">QR version</string>
<string name="sequence_size">Sequence size</string>
<string name="sequence_index">Sequence index</string>
<string name="sequence_id">Sequence ID</string>
<string name="gtin_issue_number">সমস্যা ক্রম</string>
<string name="gtin_country">তৈরির সম্ভাব্য দেশ</string>
<string name="gtin_price">প্রস্তসবিত দাম</string>
<string name="gtin_add_on">ইউপিসি ইএএন বর্ধিত</string>
<string name="barcode_version_number">Version</string>
<string name="qr_version_and_modules">%1$d (%2$d modules)</string>
<string name="toggle_flash">আলো</string>
<string name="error_flash">Error toggling flash</string>
<string name="share">ভাগ করো</string>
@@ -85,8 +86,6 @@
<string name="copy_immediately_summary">স্বয়ংক্রিয়ভাবে ক্লিপবোর্ডে অনুলিপি করো। বিশেষ দ্রষ্টব্য অন্য অ্যাপ পটভূমিতে এই তথ্য দেখে ফেলতে পারে।</string>
<string name="show_meta_data">মেটাতথ্য দেখাও</string>
<string name="show_meta_data_summary">সনাক্তকৃত বারকোড নিয়ে অতিরিক্ত তথ্য দেখাও।</string>
<string name="show_qr_version">Show QR version</string>
<string name="show_qr_version_summary">Show QR version number.</string>
<string name="show_hex_dump">ষড়(hex) সংকেত দেখাও</string>
<string name="show_hex_dump_summary">পড়া তথ্যের ষড় সংকেত দেখাও</string>
<string name="close_automatically">অনুলিপি/ভাগ করার পরে পিছনে যাও</string>
+9 -10
View File
@@ -17,14 +17,15 @@
<string name="error_correction_level_m" formatted="false">Střední (~15&#37; korekce)</string>
<string name="error_correction_level_q" formatted="false">Čtvrtinový (~25&#37; korekce)</string>
<string name="error_correction_level_h" formatted="false">Vysoký (~30&#37; korekce)</string>
<string name="issue_number">Číslo edice</string>
<string name="orientation">Orientace</string>
<string name="other_meta_data">Metadata</string>
<string name="pdf417_extra_metadata">PDF417 metadata</string>
<string name="possible_country">Možná země původu</string>
<string name="suggested_price">Doporučená cena</string>
<string name="upc_ean_extension">rozšíření UPC EAN</string>
<string name="qr_version">QR version</string>
<string name="sequence_size">Sequence size</string>
<string name="sequence_index">Sequence index</string>
<string name="sequence_id">Sequence ID</string>
<string name="gtin_issue_number">Číslo edice</string>
<string name="gtin_country">Možná země původu</string>
<string name="gtin_price">Doporučená cena</string>
<string name="gtin_add_on">rozšíření UPC EAN</string>
<string name="barcode_version_number">Version</string>
<string name="qr_version_and_modules">%1$d (%2$d modules)</string>
<string name="toggle_flash">Zap/vyp blesk</string>
<string name="error_flash">Zapnutí/vypnutí blesku selhalo</string>
<string name="share">Sdílet</string>
@@ -87,8 +88,6 @@
<string name="copy_immediately_summary">Automaticky zkopírovat naskenovaný obsah do schránky. Pozor, jiné aplikace jej mohou ze schránky přečíst, i když neběží.</string>
<string name="show_meta_data">Zobrazit metadata</string>
<string name="show_meta_data_summary">Zobrazí další data o naskenovaném čárovém kódu.</string>
<string name="show_qr_version">Show QR version</string>
<string name="show_qr_version_summary">Show QR version number.</string>
<string name="show_hex_dump">Zobrazit hex dump</string>
<string name="show_hex_dump_summary">Zobrazí hex dump naskenovaného obsahu.</string>
<string name="close_automatically">Vrátit se po zkopírování/sdílení</string>
+9 -10
View File
@@ -15,14 +15,15 @@
<string name="error_correction_level_m" formatted="false">Medium (~15&#37; wiederherstellbar)</string>
<string name="error_correction_level_q" formatted="false">Quartile (~25&#37; wiederherstellbar)</string>
<string name="error_correction_level_h" formatted="false">High (~30&#37; wiederherstellbar)</string>
<string name="issue_number">Ausgabe Nummer</string>
<string name="orientation">Orientierung</string>
<string name="other_meta_data">Metadaten</string>
<string name="pdf417_extra_metadata">PDF417 Metadaten</string>
<string name="possible_country">Mögliches Ursprungsland</string>
<string name="suggested_price">Preisvorschlag</string>
<string name="upc_ean_extension">UPC EAN Erweiterung</string>
<string name="qr_version">QR Version</string>
<string name="sequence_size">Sequence size</string>
<string name="sequence_index">Sequence index</string>
<string name="sequence_id">Sequence ID</string>
<string name="gtin_issue_number">Ausgabe Nummer</string>
<string name="gtin_country">Mögliches Ursprungsland</string>
<string name="gtin_price">Preisvorschlag</string>
<string name="gtin_add_on">UPC EAN Erweiterung</string>
<string name="barcode_version_number">Version</string>
<string name="qr_version_and_modules">%1$d (%2$d Module)</string>
<string name="toggle_flash">Licht an/ausschalten</string>
<string name="error_flash">Fehler beim ein/ausschalten des Lichts</string>
<string name="share">Teilen</string>
@@ -85,8 +86,6 @@
<string name="copy_immediately_summary">Eingelesene Inhalte werden automatisch in die Zwischenablage kopiert. Bitte beachten Sie, dass andere Anwendungen die Zwischenablage im Hintergrund auslesen können.</string>
<string name="show_meta_data">Meta Daten anzeigen</string>
<string name="show_meta_data_summary">Zusätzliche Daten über den eingelesenen Barcode anzeigen.</string>
<string name="show_qr_version">QR Version anzeigen</string>
<string name="show_qr_version_summary">Versionsnummer für QR Codes anzeigen.</string>
<string name="show_hex_dump">Hex Dump anzeigen</string>
<string name="show_hex_dump_summary">Zeigt einen Hexdump des eingelesenen Inhalts an.</string>
<string name="close_automatically">Automatisch zurückkehren</string>
+29 -30
View File
@@ -1,5 +1,5 @@
<resources>
<string name="no_camera_no_fun">Esta aplicación no tiene sentido usar sin acceso a la cámara. Adiós.</string>
<string name="no_camera_no_fun">No tiene sentido usar esta aplicación sin acceso a la cámara. Adiós.</string>
<string name="camera_error">No se puede acceder a la cámara, por favor, inténtelo de nuevo</string>
<string name="scan_code">Escanear código de barras</string>
<string name="compose_barcode">Componer código de barras</string>
@@ -15,15 +15,16 @@
<string name="error_correction_level_m" formatted="false">Medio (~15&#37; de correción)</string>
<string name="error_correction_level_q" formatted="false">Cuartil (~25&#37; de correción)</string>
<string name="error_correction_level_h" formatted="false">Alto (~30&#37; de correción)</string>
<string name="issue_number">Número de emisión</string>
<string name="orientation">Orientación</string>
<string name="other_meta_data">Metadatos</string>
<string name="pdf417_extra_metadata">Metadatos PDF417</string>
<string name="possible_country">Posible país de fabricación</string>
<string name="suggested_price">Precio sugerido</string>
<string name="upc_ean_extension">Extensión UPC EAN</string>
<string name="qr_version">QR version</string>
<string name="toggle_flash">Activar la linterna</string>
<string name="sequence_size">Sequence size</string>
<string name="sequence_index">Sequence index</string>
<string name="sequence_id">Sequence ID</string>
<string name="gtin_issue_number">Número de emisión</string>
<string name="gtin_country">Posible país de fabricación</string>
<string name="gtin_price">Precio sugerido</string>
<string name="gtin_add_on">Extensión UPC EAN</string>
<string name="barcode_version_number">Version</string>
<string name="qr_version_and_modules">%1$d (%2$d modules)</string>
<string name="toggle_flash">Activar el flash</string>
<string name="error_flash">Error toggling flash</string>
<string name="share">Compartir</string>
<string name="share_as">¿Compartir como?</string>
@@ -46,15 +47,15 @@
<string name="switch_camera">Cambiar cámara</string>
<string name="bulk_mode">Escanear constantemente</string>
<string name="bulk_mode_summary">Siempre iniciar escaneando constantemente</string>
<string name="bulk_mode_delay">Delay between continuous scans</string>
<string name="restrict_format">Restrict format</string>
<string name="remove_restriction">Remove restriction</string>
<string name="scan_format">Scan %s</string>
<string name="quarter_second">A quarter second</string>
<string name="half_second">Half a second</string>
<string name="a_second">One second</string>
<string name="two_seconds">Two seconds</string>
<string name="five_seconds">Five seconds</string>
<string name="bulk_mode_delay">Demora entre escaneos continuos</string>
<string name="restrict_format">Restringir formato</string>
<string name="remove_restriction">Eliminar restricción</string>
<string name="scan_format">Escanear %s</string>
<string name="quarter_second">Un cuarto de segundo</string>
<string name="half_second">Medio segundo</string>
<string name="a_second">Un segundo</string>
<string name="two_seconds">Dos segundos</string>
<string name="five_seconds">Cinco segundos</string>
<string name="history">Historial</string>
<string name="preferences">Configuración</string>
<string name="scan_category">Escanear</string>
@@ -85,8 +86,6 @@
<string name="copy_immediately_summary">Copiar contenido al portapapeles automáticamente. Ten en cuenta que otras aplicaciones pueden husmear en tu portapapeles en segundo plano.</string>
<string name="show_meta_data">Mostrar metadatos</string>
<string name="show_meta_data_summary">Mostrar datos adicionales del código escaneado.</string>
<string name="show_qr_version">Show QR version</string>
<string name="show_qr_version_summary">Show QR version number.</string>
<string name="show_hex_dump">Mostrar dump hexadecimal</string>
<string name="show_hex_dump_summary">Mostrar un dump hexadecimal del contenido escaneado.</string>
<string name="close_automatically">Retroceder luego de Copiar/Compartir</string>
@@ -108,7 +107,7 @@
<string name="send_type_get_query_string">GET con consulta completa</string>
<string name="send_type_post_form">POST application/x-www-form-urlencoded</string>
<string name="send_type_post_json">POST application/json</string>
<string name="send_type_external_browser">Open in external browser</string>
<string name="send_type_external_browser">Abrir en el navegador</string>
<string name="test_url">URL de prueba</string>
<string name="really_remove_scan">¿Realmente desea borrar el escaneo seleccionado?</string>
<string name="really_remove_all_scans">¿Realmente desea borrar todo lo escaneado?</string>
@@ -158,13 +157,13 @@
<string name="shortcut_preferences">Ajustes</string>
<string name="background_request_failed">Solicitud de fondo fallida</string>
<string name="entry_type">Type</string>
<string name="wifi_network">Wi-Fi network</string>
<string name="wifi_ssid">Name</string>
<string name="wifi_type">Authentication type</string>
<string name="wifi_password">Password</string>
<string name="wifi_hidden">Hidden network</string>
<string name="wifi_eap">EAP method</string>
<string name="wifi_anonymous_identity">Anonymous identity</string>
<string name="wifi_identity">Identity</string>
<string name="wifi_network">Red wi-fi</string>
<string name="wifi_ssid">Nombre</string>
<string name="wifi_type">Tipo de autenticación</string>
<string name="wifi_password">Contraseña</string>
<string name="wifi_hidden">Red oculta</string>
<string name="wifi_eap">Método EAP</string>
<string name="wifi_anonymous_identity">Identidad anónima</string>
<string name="wifi_identity">Identidad</string>
<string name="wifi_phase2">Phase 2 method</string>
</resources>
@@ -0,0 +1,24 @@
<resources>
<string-array name="search_engines_names">
<item>@string/always_ask</item>
<item>گوگل</item>
<item>داک‌داک‌گو</item>
<item>Qwant</item>
<item>بینگ</item>
<item>یاندکس</item>
<item>OpenFoodFacts.org</item>
<item>OpenBeautyFacts.org</item>
<item>OpenPetFoodFacts.org</item>
</string-array>
<string-array name="search_engines_values">
<item></item>
<item>https://www.google.com/search?q=</item>
<item>https://duckduckgo.com/?q=</item>
<item>https://www.qwant.com/?q=</item>
<item>https://bing.com/?q=</item>
<item>https://yandex.com/?q=</item>
<item>https://world.openfoodfacts.org/cgi/search.pl?search_terms=</item>
<item>https://world.openbeautyfacts.org/cgi/search.pl?search_terms=</item>
<item>https://world.openpetfoodfacts.org/cgi/search.pl?search_terms=</item>
</string-array>
</resources>
+169
View File
@@ -0,0 +1,169 @@
<resources>
<string name="no_camera_no_fun">این برنامه بدون دسترسی به دوربین هیچ کارایی ندارد. خدانگهدار.</string>
<string name="camera_error">نمی‌توان به دوربین دسترسی داشت، لطفاً دوباره تلاش کنید</string>
<string name="scan_code">پویش کد</string>
<string name="compose_barcode">ایجاد بارکد</string>
<string name="decode_barcode">رمزگشایی بارکد</string>
<string name="content">محتویات</string>
<string name="binary_data">(دادهٔ دودویی)</string>
<plurals name="barcode_info">
<item quantity="one">%2$d نویسه، %1$s</item>
<item quantity="other">%2$d نویسه، %1$s</item>
</plurals>
<string name="error_correction_level">سطح تصحیح خطا</string>
<string name="error_correction_level_l" formatted="false">کم (~۷٪⁩ تصحیح)</string>
<string name="error_correction_level_m" formatted="false">متوسط (⁦~۱۵٪⁩ تصحیح)</string>
<string name="error_correction_level_q" formatted="false">یک‌چهارم (⁦~۲۵٪⁩ تصحیح)</string>
<string name="error_correction_level_h" formatted="false">زیاد (~۳۰٪⁩ تصحیح)</string>
<string name="sequence_size">Sequence size</string>
<string name="sequence_index">Sequence index</string>
<string name="sequence_id">Sequence ID</string>
<string name="gtin_issue_number">شمارهٔ اشکال</string>
<string name="gtin_country">کشور احتمالی سازنده</string>
<string name="gtin_price">قیمت پیشنهادی</string>
<string name="gtin_add_on">UPC EAN extension</string>
<string name="barcode_version_number">Version</string>
<string name="qr_version_and_modules">%1$d (%2$d modules)</string>
<string name="toggle_flash">روشن/خاموش کردن چراغ</string>
<string name="error_flash">خطا هنگام روشن/خاموش کردن چراغ</string>
<string name="share">هم‌رسانی</string>
<string name="share_as">هم‌رسانی به عنوان؟</string>
<string name="copy_to_clipboard">رونوشت به تخه‌گیره</string>
<string name="copied_to_clipboard">به تخته‌گیره رونوشت شد</string>
<string name="copy_password">رونوشت گذرواژه به تخته‌گیره</string>
<string name="copied_password_to_clipboard">گذرواژه به تخته‌گیره رونوشت شد</string>
<string name="open_url">گشودن نشانی</string>
<string name="cannot_resolve_action">هیچ برنامه‌ای نمی‌تواند آن را بگشاید</string>
<string name="pick_search_engine">یک موتور جست‌وجو برگزینید</string>
<string name="format">قالب</string>
<string name="size">اندازه به پیکسل</string>
<string name="width_by_height">%1$d×%2$d</string>
<string name="input_content_here">محتویات ورودی را اینجا بنویسید</string>
<string name="encode">رمزگذاری</string>
<string name="error_no_content">محتویاتی نیست</string>
<string name="error_encoding_barcode">بارکد نمی‌تواند ایجاد شود</string>
<string name="view_barcode">نمایش بارکد</string>
<string name="info">اطّلاعات</string>
<string name="switch_camera">تغییر دوربین</string>
<string name="bulk_mode">به طور مداوم پویش کن</string>
<string name="bulk_mode_summary">همیشه پویش را به طور مداوم شروع می‌کند.</string>
<string name="bulk_mode_delay">تأخیر بین پویش‌های مداوم</string>
<string name="restrict_format">محدود کردن قالب</string>
<string name="remove_restriction">برداشتن محدودیت</string>
<string name="scan_format">پویش %s</string>
<string name="quarter_second">یک‌چهارم ثانیه</string>
<string name="half_second">نیم ثانیه</string>
<string name="a_second">یک ثانیه</string>
<string name="two_seconds">دو ثانیه</string>
<string name="five_seconds">پنج ثانیه</string>
<string name="history">تاریخچه</string>
<string name="preferences">ترجیحات</string>
<string name="scan_category">پویش</string>
<string name="content_category">محتویات</string>
<string name="locale_category">زبان</string>
<string name="custom_locale">زبان سفارشی</string>
<string name="follow_system_settings">پیروی از زبان سامانه</string>
<string name="show_crop_handle">نمایش محدود کننده برش</string>
<string name="show_crop_handle_summary">پویش را به یک منطقه قابل تنظیم محدود می‌کند.</string>
<string name="barcode_formats">قالب‌های بارکد</string>
<string name="zoom_by_swiping">برای بزرگنمایی به بالا یا پایین بکشید</string>
<string name="zoom_by_swiping_summary">برای کنترل بزرگنمایی دوربین، در صفحهٔ دوربین به بالا یا پایین بکشید.</string>
<string name="auto_rotate">تشخیص بارکدهای یک بعدی عمودی</string>
<string name="auto_rotate_summary">قاب دوربین را به صورت خودکار بچرخانید تا بارکدهای یک بعدی عمودی را تشخیص دهید. بسته به دستگاه، این ممکن است بر عملکرد تأثیر بگذارد.</string>
<string name="try_harder">بهینه کردن خواننده برای دقت بیشتر</string>
<string name="try_harder_summary">این گزینه را برای کدهایی که بسیار سخت خوانده می‌شوند، فعال کنید. بر عملکرد تأثیر خواهد گذاشت.</string>
<string name="show_toast_in_bulk_mode">نمایش داده‌ها در حالت پیوسته</string>
<string name="show_toast_in_bulk_mode_summary">هنگام پویش مداوم، داده‌های پویش شده را به طور خلاصه نشان می‌دهید.</string>
<string name="vibrate">لرزش هنگام تشخیص</string>
<string name="vibrate_summary">اگر می‌خواهید دستگاهتان هنگام شناسایی کد بلرزد، این را فعال کنید.</string>
<string name="use_history">ذخیرهٔ تاریخچهٔ پویش</string>
<string name="use_history_summary">کدهای شناسایی شده را در همین دستگاه ذخیره می‌کند.</string>
<string name="ignore_consecutive_duplicates">نادیده گرفتن موارد تکراری</string>
<string name="ignore_consecutive_duplicates_summary">موارد تکراری متوالی را در تاریخچهٔ پویش ذخیره نمی‌کند.</string>
<string name="open_immediately">گشودن بلافاصله</string>
<string name="open_immediately_summary">بازرسی را رها کنید و محتویات را فورا باز کنید. در صورت فعال بودن ممکن است محتوای مضر را باز کند.</string>
<string name="copy_immediately">قرار دادن در تخته‌گیره</string>
<string name="copy_immediately_summary">به طور خودکار محتوای پویش شده را در تخته‌گیره رونوشت می‌کند. لطفاً توجه داشته باشید که برنامه‌های دیگر ممکن است در پس‌زمینه تخته‌گیرهٔ شما را شنود کنند.</string>
<string name="show_meta_data">نمایش فراداده</string>
<string name="show_meta_data_summary">نمایش داده‌های اضافی در مورد بارکد پویش شده.</string>
<string name="show_hex_dump">نمایش کد هگز استخراج شده</string>
<string name="show_hex_dump_summary">نمایش کد هگز استخراج شده از محتویات پویش شده.</string>
<string name="close_automatically">بازگشت پس از رونوشت یا هم‌رسانی</string>
<string name="close_automatically_summary">پس از رونوشت یا هم‌رسانی مطالب خوانده شده، به طور خودکار به صفحهٔ پویش بازگردید.</string>
<string name="default_search_engine">گشودن دادهٔ نامشخص در</string>
<string name="always_ask">همیشه بپرس</string>
<string name="open_with_url">داده‌های ناشناخته را با URL باز کنید</string>
<string name="clear_network_suggestions">پاک کردن پیشنهادات شبکه</string>
<string name="clear_network_suggestions_summary">همه پیشنهادات شبکه را که قبلاً توسط این برنامه ارائه شده است حذف کنید.</string>
<string name="really_remove_all_networks">واقعاً همه شبکه‌ها را حذف می‌کنید؟</string>
<string name="clear_network_suggestions_success">پیشنهادات شبکه پاک شد</string>
<string name="clear_network_suggestions_nothing_to_remove">چیزی برای حذف نیست</string>
<string name="send_category">هدایت کردن</string>
<string name="send_scan_active">هدایت پویش‌ها</string>
<string name="send_scan_active_summary">برای هدایت پویش‌ها به نشانی مشخص شده، آن را به کار بیاندازید.</string>
<string name="send_scan_url">نشانی برای هدایت به آن</string>
<string name="send_scan_type">گونهٔ درخواست</string>
<string name="send_type_get_add_content">GET و به سادگی محتوا را اضافه کنید</string>
<string name="send_type_get_query_string">GET با رشته پرس‌وجو کامل</string>
<string name="send_type_post_form">POST application/x-www-form-urlencoded</string>
<string name="send_type_post_json">POST application/json</string>
<string name="send_type_external_browser">گشودن در مرورگر خارجی</string>
<string name="test_url">آزمودن نشانی</string>
<string name="really_remove_scan">برای برداشتن پویش مطمئنید؟</string>
<string name="really_remove_all_scans">برای برداشتن همهٔ پویش‌ها مطمئنید؟</string>
<string name="really_remove_selected_scans">برای برداشتن پویش‌های برگزیده شده مطمئنید؟</string>
<string name="clear_history">پاک کردن تاریخچه</string>
<string name="copy_scan">رونوشت پویش</string>
<string name="edit_scan">ویرایش عنوان</string>
<string name="remove_scan">برداشتن پویش</string>
<string name="enter_name">یک نام برای توضیح پویش وارد کنید</string>
<string name="enter_name_hint">نام پویش</string>
<string name="no_barcode_found">بارکدی یافت نشد</string>
<string name="pick_list_separator">چگونه موارد فهرست را جدا کنیم؟</string>
<string name="separator_line_break">خط بعدی</string>
<string name="separator_ruler">خط كش</string>
<string name="save_as_file_name">به عنوان پرونده در بارگیری‌ها ذخیره شود؟</string>
<string name="file_name">نام پرونده</string>
<string name="error_saving_file">نمی‌توان پرونده را ذخیره کرد</string>
<string name="error_file_exists">پرونده هم‌اکنون وجود دارد</string>
<string name="connect_to_wifi">اتّصال به وای‌فای</string>
<string name="wifi_config_failed">نمی‌توان وای‌فای را پیکربندی کرد</string>
<string name="wifi_added">وای‌فای اضافه شد</string>
<string name="sms_send">ارسال اس‌ام‌اس</string>
<string name="sms_error">نمی‌توان اس‌ام‌اس فرستاد</string>
<string name="tel_dial">تماس با شماره</string>
<string name="tel_error">نمی‌توان با شماره تماس گرفت</string>
<string name="mail_send">ارسال رایانامه</string>
<string name="mail_error">نمی‌توان رایانامه فرستاد</string>
<string name="vcard_add">افزودن به مخاطبین</string>
<string name="vcard_failed">نمی‌توان به مخاطبین اضافه کرد</string>
<string name="vevent_add">افزودن به تقویم</string>
<string name="vevent_failed">نمی‌توان به تقویم اضافه کرد</string>
<string name="otpauth_add">افزودن احراز هویت چندعاملی(2FA)</string>
<string name="search_web">جست‌وجوی وب</string>
<string name="search_scan">جست‌وجوی پویش</string>
<string name="export_to_file">برون‌ریزی به پرونده</string>
<string name="export_as">برون‌ریزی به عنوان؟</string>
<string name="export_csv_comma">پروندهٔ سی‌اس‌وی با ویرگول</string>
<string name="export_csv_semicolon">پروندهٔ سی‌اس‌وی با نقطه‌ویرگول</string>
<string name="export_json">پروندهٔ جی‌سون</string>
<string name="export_database">پایگاه‌دادهٔ اس‌کیولایت</string>
<string name="saved_in_downloads">در بارگیری‌ها ذخیره شد</string>
<string name="rotate_image_cw">تصویر را در جهت ساعتگرد بچرخانید</string>
<string name="pick_file">پروندهٔ تصویری را برگزینید</string>
<string name="pick_code_to_scan">کدی را برای پویش برگزینید</string>
<string name="shortcut_decode">پویش یک بارکد</string>
<string name="shortcut_encode">ایجاد یک بارکد</string>
<string name="shortcut_preferences">تنظیمات</string>
<string name="background_request_failed">درخواست پس‌زمینه انجام نشد</string>
<string name="entry_type">گونه</string>
<string name="wifi_network">شبکهٔ وای‌فای</string>
<string name="wifi_ssid">نام</string>
<string name="wifi_type">گونهٔ تأیید اعتبار</string>
<string name="wifi_password">گذرواژه</string>
<string name="wifi_hidden">شبکهٔ پنهان</string>
<string name="wifi_eap">روش EAP</string>
<string name="wifi_anonymous_identity">هویت ناشناس</string>
<string name="wifi_identity">هویت</string>
<string name="wifi_phase2">روش دو مرحله‌ای</string>
</resources>
+27 -28
View File
@@ -16,16 +16,17 @@
<string name="error_correction_level_m" formatted="false">Moyen (~15% de correction)</string>
<string name="error_correction_level_q" formatted="false">Quartile (~25% de correction)</string>
<string name="error_correction_level_h" formatted="false">Élevé (~30% de correction)</string>
<string name="issue_number">Issue number</string>
<string name="orientation">Orientation</string>
<string name="other_meta_data">Métadonnées</string>
<string name="pdf417_extra_metadata">Métadonnées PDF417</string>
<string name="possible_country">Pays de fabrication possible</string>
<string name="suggested_price">Prix suggéré</string>
<string name="upc_ean_extension">Extension UPC EAN</string>
<string name="qr_version">QR version</string>
<string name="sequence_size">Sequence size</string>
<string name="sequence_index">Sequence index</string>
<string name="sequence_id">Sequence ID</string>
<string name="gtin_issue_number">Numéro du problème</string>
<string name="gtin_country">Pays de fabrication possible</string>
<string name="gtin_price">Prix suggéré</string>
<string name="gtin_add_on">Extension UPC EAN</string>
<string name="barcode_version_number">Version</string>
<string name="qr_version_and_modules">%1$d (%2$d modules)</string>
<string name="toggle_flash">Activer le flash</string>
<string name="error_flash">Error toggling flash</string>
<string name="error_flash">Erreur de basculement du flash</string>
<string name="share">Partager</string>
<string name="share_as">Partager comme ?</string>
<string name="copy_to_clipboard">Copier dans le presse-papiers</string>
@@ -46,10 +47,10 @@
<string name="info">Info</string>
<string name="switch_camera">Changer de camera</string>
<string name="bulk_mode">Scan continu</string>
<string name="bulk_mode_summary">Toujours démarrer en scannant en continu.</string>
<string name="bulk_mode_summary">Démarre toujours en scan continu.</string>
<string name="bulk_mode_delay">Délai entre les scans continus</string>
<string name="restrict_format">Restrict format</string>
<string name="remove_restriction">Remove restriction</string>
<string name="restrict_format">Restreindre le format</string>
<string name="remove_restriction">Supprimer la restriction</string>
<string name="scan_format">Scan %s</string>
<string name="quarter_second">Un quart de seconde</string>
<string name="half_second">Une demi-seconde</string>
@@ -64,47 +65,45 @@
<string name="custom_locale">Langue personnalisée</string>
<string name="follow_system_settings">Suivre les réglages du système</string>
<string name="show_crop_handle">Afficher le bouton de rognage</string>
<string name="show_crop_handle_summary">Restreindre le scan à une région personnalisée.</string>
<string name="show_crop_handle_summary">Restreint le scan à une région personnalisée.</string>
<string name="barcode_formats">Formats de codes-barres</string>
<string name="zoom_by_swiping">Balayage haut/bas pour zoomer</string>
<string name="zoom_by_swiping_summary">Balayez vers le haut ou vers le bas dans l’écran de la caméra pour contrôler le zoom de la caméra.</string>
<string name="auto_rotate">Reconnaître les codes-barres 1D verticaux</string>
<string name="auto_rotate_summary">Tourner automatiquement le cadre de la caméra pour reconnaître les codes-barres 1D verticaux. En fonction de l\'appareil, cela peut affecter les performances.</string>
<string name="auto_rotate_summary">Tourne automatiquement le cadre de la caméra pour reconnaître les codes-barres 1D verticaux. En fonction de l\'appareil, cela peut affecter les performances.</string>
<string name="try_harder">Optimiser la précision du lecteur</string>
<string name="try_harder_summary">Activez cette option pour les codes très difficiles à lire. Affectera les performances.</string>
<string name="show_toast_in_bulk_mode">Afficher les données en mode continu</string>
<string name="show_toast_in_bulk_mode_summary">Afficher brièvement les données lors d\'un scan en continu.</string>
<string name="vibrate">Vibrer à la détection</string>
<string name="vibrate_summary">Activez ceci si vous voulez que votre appareil vibre lorsquun code est reconnu.</string>
<string name="vibrate_summary">Fait vibrer l\'appareil lorsqu\'un code est reconnu.</string>
<string name="use_history">Sauvegarder l\'historique des scans</string>
<string name="use_history_summary">Sauvegarder les codes reconnus sur votre appareil.</string>
<string name="use_history_summary">Sauvegarde les codes reconnus sur votre appareil.</string>
<string name="ignore_consecutive_duplicates">Ignorer les doublons</string>
<string name="ignore_consecutive_duplicates_summary">Ne pas sauvegarder les doublons dans l\'historique des scans.</string>
<string name="ignore_consecutive_duplicates_summary">Ne sauvegarde pas les doublons dans l\'historique des scans.</string>
<string name="open_immediately">Ouvrir immédiatement</string>
<string name="open_immediately_summary">Sauter l\'inspection et ouvrir le contenu immédiatement. Si activé, cela peut ouvrir un contenu nocif.</string>
<string name="open_immediately_summary">Saute l\'inspection et ouvre le contenu immédiatement. Si activé, cela peut ouvrir un contenu nocif.</string>
<string name="copy_immediately">Mettre dans le presse-papiers</string>
<string name="copy_immediately_summary">Copier automatiquement les contenus scannés dans le presse-papiers. Veuillez noter que les autres applications peuvent fouiner dans votre presse-papiers en arrière-plan.</string>
<string name="copy_immediately_summary">Copie automatiquement les contenus scannés dans le presse-papiers. Veuillez noter que les autres applications peuvent fouiner dans votre presse-papiers en arrière-plan.</string>
<string name="show_meta_data">Afficher les méta-données</string>
<string name="show_meta_data_summary">Afficher les données supplémentaires sur le code-barres scanné.</string>
<string name="show_qr_version">Show QR version</string>
<string name="show_qr_version_summary">Show QR version number.</string>
<string name="show_meta_data_summary">Affiche les données supplémentaires sur le code-barres scanné.</string>
<string name="show_hex_dump">Afficher le dump hexa</string>
<string name="show_hex_dump_summary">Affiche un dump hexadécimal du contenu scanné.</string>
<string name="show_hex_dump_summary">Affiche le dump hexadécimal du contenu scanné.</string>
<string name="close_automatically">Revenir après une copie/partage</string>
<string name="close_automatically_summary">Revient automatiquement sur l\'écran de scan après avoir copié ou partagé le contenu lu.</string>
<string name="default_search_engine">Ouvrir les données inconnues dans</string>
<string name="always_ask">Toujours demander</string>
<string name="open_with_url">Ouvrir des données inconnues avec lURL</string>
<string name="clear_network_suggestions">Supprimer les suggestions de réseau</string>
<string name="clear_network_suggestions_summary">Supprimez toutes les suggestions de réseau précédemment fournies par cette application.</string>
<string name="clear_network_suggestions_summary">Supprime toutes les suggestions de réseau précédemment fournies par cette application.</string>
<string name="really_remove_all_networks">Supprimer vraiment tous les réseaux ?</string>
<string name="clear_network_suggestions_success">Suggestions de réseau supprimées</string>
<string name="clear_network_suggestions_nothing_to_remove">Rien à supprimer</string>
<string name="send_category">Transfert</string>
<string name="send_scan_active">Forward scans</string>
<string name="send_scan_active_summary">Enable to forward scans to a the given URL</string>
<string name="send_scan_url">Envoyer chaque scan vers une URL</string>
<string name="send_scan_type">Type de requête pour chaque scan</string>
<string name="send_scan_active">Transférer les scans</string>
<string name="send_scan_active_summary">Transfère les scans vers une URL donnée.</string>
<string name="send_scan_url">URL de transfert</string>
<string name="send_scan_type">Type de requête</string>
<string name="send_type_get_add_content">GET et ajouter simplement le contenu</string>
<string name="send_type_get_query_string">GET avec chaîne de requête complète</string>
<string name="send_type_post_form">POST application/x-www-form-urlencoded</string>
+9 -10
View File
@@ -15,14 +15,15 @@
<string name="error_correction_level_m" formatted="false">Közepes (~15&#37; javítás)</string>
<string name="error_correction_level_q" formatted="false">Kvartilis (~25&#37; javítás)</string>
<string name="error_correction_level_h" formatted="false">Magas (~30&#37; javítás)</string>
<string name="issue_number">Hibaszám</string>
<string name="orientation">Tájolás</string>
<string name="other_meta_data">Metaadat</string>
<string name="pdf417_extra_metadata">PDF417 metaadat</string>
<string name="possible_country">Gyártó lehetséges országa</string>
<string name="suggested_price">Ajánlott ár</string>
<string name="upc_ean_extension">UPC EAN kiterjesztés</string>
<string name="qr_version">QR version</string>
<string name="sequence_size">Sequence size</string>
<string name="sequence_index">Sequence index</string>
<string name="sequence_id">Sequence ID</string>
<string name="gtin_issue_number">Hibaszám</string>
<string name="gtin_country">Gyártó lehetséges országa</string>
<string name="gtin_price">Ajánlott ár</string>
<string name="gtin_add_on">UPC EAN kiterjesztés</string>
<string name="barcode_version_number">Version</string>
<string name="qr_version_and_modules">%1$d (%2$d modules)</string>
<string name="toggle_flash">Vaku be- vagy kikapcsolása</string>
<string name="error_flash">Hiba a vaku be- vagy kikapcsolásakor</string>
<string name="share">Megosztás</string>
@@ -85,8 +86,6 @@
<string name="copy_immediately_summary">Beolvasott tartalom automatikus másolása a vágólapra. Ne feledje, hogy más alkalmazások megfigyelhetik a vágólapját a háttérben.</string>
<string name="show_meta_data">Metaadatok megjelenítése</string>
<string name="show_meta_data_summary">További adatok megjelenítése a beolvasott vonalkódokról.</string>
<string name="show_qr_version">Show QR version</string>
<string name="show_qr_version_summary">Show QR version number.</string>
<string name="show_hex_dump">Hexakiírás megjelenítése</string>
<string name="show_hex_dump_summary">A beolvasott tartalom hexakiírásának megjelenítése.</string>
<string name="close_automatically">Ugrás vissza másolás vagy megosztás után</string>
+9 -10
View File
@@ -14,14 +14,15 @@
<string name="error_correction_level_m" formatted="false">Medium (~15&#37; koreksi)</string>
<string name="error_correction_level_q" formatted="false">Kuartil (~25&#37; koreksi)</string>
<string name="error_correction_level_h" formatted="false">Tinggi (~30&#37; koreksi)</string>
<string name="issue_number">Nomor pindaian</string>
<string name="orientation">Orientasi</string>
<string name="other_meta_data">Metadata</string>
<string name="pdf417_extra_metadata">Metadata PDF417</string>
<string name="possible_country">Kemungkinan negara pembuat</string>
<string name="suggested_price">Harga yang disarankan</string>
<string name="upc_ean_extension">Ekstensi UPC EAN</string>
<string name="qr_version">QR version</string>
<string name="sequence_size">Sequence size</string>
<string name="sequence_index">Sequence index</string>
<string name="sequence_id">Sequence ID</string>
<string name="gtin_issue_number">Nomor pindaian</string>
<string name="gtin_country">Kemungkinan negara pembuat</string>
<string name="gtin_price">Harga yang disarankan</string>
<string name="gtin_add_on">Ekstensi UPC EAN</string>
<string name="barcode_version_number">Version</string>
<string name="qr_version_and_modules">%1$d (%2$d modules)</string>
<string name="toggle_flash">Nyala/matikan blitz</string>
<string name="error_flash">Error toggling flash</string>
<string name="share">Bagikan</string>
@@ -84,8 +85,6 @@
<string name="copy_immediately_summary">Otomatis menyalin konten yang dipindai ke dalam clipboard. Harap diingat bahwa apl lain bisa melihat isi dari clipboard anda di latar belakang.</string>
<string name="show_meta_data">Tampilkan metadata</string>
<string name="show_meta_data_summary">Tampilkan data tambahan tentang barcode yang dipindai.</string>
<string name="show_qr_version">Show QR version</string>
<string name="show_qr_version_summary">Show QR version number.</string>
<string name="show_hex_dump">Tampilkan hex dump</string>
<string name="show_hex_dump_summary">Tampilkan hex dump dari konten hasil pemindaian.</string>
<string name="close_automatically">Go back after Copy/Share</string>
+9 -10
View File
@@ -15,14 +15,15 @@
<string name="error_correction_level_m" formatted="false">Medio (Correzione del ~15&#37;)</string>
<string name="error_correction_level_q" formatted="false">Quartile (Correzione del ~25&#37;)</string>
<string name="error_correction_level_h" formatted="false">Alto (Correzione del ~30&#37;)</string>
<string name="issue_number">Numero di edizione</string>
<string name="orientation">Orientamento</string>
<string name="other_meta_data">Metadati</string>
<string name="pdf417_extra_metadata">Metadati PDF417</string>
<string name="possible_country">Probabile Paese di fabbricazione</string>
<string name="suggested_price">Prezzo consigliato</string>
<string name="upc_ean_extension">Estensione UPC EAN</string>
<string name="qr_version">Versione QR</string>
<string name="sequence_size">Sequence size</string>
<string name="sequence_index">Sequence index</string>
<string name="sequence_id">Sequence ID</string>
<string name="gtin_issue_number">Numero di edizione</string>
<string name="gtin_country">Probabile Paese di fabbricazione</string>
<string name="gtin_price">Prezzo consigliato</string>
<string name="gtin_add_on">Estensione UPC EAN</string>
<string name="barcode_version_number">Versione</string>
<string name="qr_version_and_modules">%1$d (%2$d modules)</string>
<string name="toggle_flash">Attiva/Disattiva flash</string>
<string name="error_flash">Errore durante l\'attivazione/disattivazione del flash</string>
<string name="share">Condividi</string>
@@ -85,8 +86,6 @@
<string name="copy_immediately_summary">Copia automaticamente i contenuti scansionati negli appunti. Nota che altre app potrebbero leggere gli appunti in secondo piano.</string>
<string name="show_meta_data">Mostra metadati</string>
<string name="show_meta_data_summary">Mostra dati aggiuntivi sul codice a barre scansionato.</string>
<string name="show_qr_version">Mostra versione QR</string>
<string name="show_qr_version_summary">Show QR version number.</string>
<string name="show_hex_dump">Mostra dump esadecimale</string>
<string name="show_hex_dump_summary">Mostra un dump esadecimale dei contenuti scansionati.</string>
<string name="close_automatically">Vai indietro dopo la Copia/Condivisione</string>
+9 -10
View File
@@ -14,14 +14,15 @@
<string name="error_correction_level_m" formatted="false">中 (~15&#37; の正確性)</string>
<string name="error_correction_level_q" formatted="false">高 (~25&#37; の正確性)</string>
<string name="error_correction_level_h" formatted="false">最高 (~30&#37; の正確性)</string>
<string name="issue_number">発行番号</string>
<string name="orientation">方向</string>
<string name="other_meta_data">メタデータ</string>
<string name="pdf417_extra_metadata">PDF417 メタデータ</string>
<string name="possible_country">製造国</string>
<string name="suggested_price">価格</string>
<string name="upc_ean_extension">UPC/EAN 拡張型</string>
<string name="qr_version">QR version</string>
<string name="sequence_size">Sequence size</string>
<string name="sequence_index">Sequence index</string>
<string name="sequence_id">Sequence ID</string>
<string name="gtin_issue_number">発行番号</string>
<string name="gtin_country">製造国</string>
<string name="gtin_price">価格</string>
<string name="gtin_add_on">UPC/EAN 拡張型</string>
<string name="barcode_version_number">Version</string>
<string name="qr_version_and_modules">%1$d (%2$d modules)</string>
<string name="toggle_flash">フラッシュの切り替え</string>
<string name="error_flash">フラッシュの切り替えエラー</string>
<string name="share">共有</string>
@@ -84,8 +85,6 @@
<string name="copy_immediately_summary">スキャンされたコンテンツを自動的にクリップボードにコピーします。他のアプリはクリップボードの内容を見ることができることにご注意ください。</string>
<string name="show_meta_data">メタデータを表示</string>
<string name="show_meta_data_summary">スキャンされたバーコードの追加データを確認できるようにします。</string>
<string name="show_qr_version">Show QR version</string>
<string name="show_qr_version_summary">Show QR version number.</string>
<string name="show_hex_dump">16進数を表示</string>
<string name="show_hex_dump_summary">スキャンされたコンテンツの16進数データを確認できるようにします。</string>
<string name="close_automatically">コピー/共有後に戻る</string>
+9 -10
View File
@@ -15,14 +15,15 @@
<string name="error_correction_level_m" formatted="false">Medium (~15&#37; correction)</string>
<string name="error_correction_level_q" formatted="false">Quartile (~25&#37; correction)</string>
<string name="error_correction_level_h" formatted="false">High (~30&#37; correction)</string>
<string name="issue_number">გამოშვების ნომერი</string>
<string name="orientation">ორიენტაცია</string>
<string name="other_meta_data">მეტამონაცემები</string>
<string name="pdf417_extra_metadata">PDF417 მეტამონაცემე</string>
<string name="possible_country">შესაძლო მწარმოებელი ქვეყანა</string>
<string name="suggested_price">დაახლოებითი ფასი</string>
<string name="upc_ean_extension">UPC EAN გაფართოება</string>
<string name="qr_version">QR version</string>
<string name="sequence_size">Sequence size</string>
<string name="sequence_index">Sequence index</string>
<string name="sequence_id">Sequence ID</string>
<string name="gtin_issue_number">გამოშვების ნომე</string>
<string name="gtin_country">შესაძლო მწარმოებელი ქვეყანა</string>
<string name="gtin_price">დაახლოებითი ფასი</string>
<string name="gtin_add_on">UPC EAN გაფართოება</string>
<string name="barcode_version_number">Version</string>
<string name="qr_version_and_modules">%1$d (%2$d modules)</string>
<string name="toggle_flash">განათების ჩართვა</string>
<string name="error_flash">Error toggling flash</string>
<string name="share">გაზიარება</string>
@@ -85,8 +86,6 @@
<string name="copy_immediately_summary">სკანირებული შტრიხ-კოდის კონტენტის ავტომატური კოპირება გაცვლის ბუფერში. გთხოვთ გაითვალისწინოთ,ზოგიერთ პროგრამას შესაძლოა ჰქონდეს ფონური წვდომა გაცვლის ბუფერთან.</string>
<string name="show_meta_data">მეტამონაცემების ჩვენება</string>
<string name="show_meta_data_summary">სკანირებულ შტრიხ-კოდებზე დამატებითი ინფორმაციის ჩვენება.</string>
<string name="show_qr_version">Show QR version</string>
<string name="show_qr_version_summary">Show QR version number.</string>
<string name="show_hex_dump">თექვსმეტობითი dump-ის ჩვენება</string>
<string name="show_hex_dump_summary">სკანირებული შტრიხ-კოდის კონტენტის თექვსმეტობითი dump-ის ჩვენება.</string>
<string name="close_automatically">Go back after Copy/Share</string>
+9 -10
View File
@@ -15,14 +15,15 @@
<string name="error_correction_level_m" formatted="false">Middelhoog (~15&#37; correction)</string>
<string name="error_correction_level_q" formatted="false">Kwartiel (~25&#37; correction)</string>
<string name="error_correction_level_h" formatted="false">Hoog (~30&#37; correction)</string>
<string name="issue_number">Uitgiftenummer</string>
<string name="orientation">Oriëntatie</string>
<string name="other_meta_data">Metadata</string>
<string name="pdf417_extra_metadata">PDF417 metadata</string>
<string name="possible_country">Mogelijk land van fabricage</string>
<string name="suggested_price">Adviesprijs</string>
<string name="upc_ean_extension">UPC EAN extensie</string>
<string name="qr_version">QR version</string>
<string name="sequence_size">Sequence size</string>
<string name="sequence_index">Sequence index</string>
<string name="sequence_id">Sequence ID</string>
<string name="gtin_issue_number">Uitgiftenummer</string>
<string name="gtin_country">Mogelijk land van fabricage</string>
<string name="gtin_price">Adviesprijs</string>
<string name="gtin_add_on">UPC EAN extensie</string>
<string name="barcode_version_number">Version</string>
<string name="qr_version_and_modules">%1$d (%2$d modules)</string>
<string name="toggle_flash">Zaklamp aan/uit</string>
<string name="error_flash">Error toggling flash</string>
<string name="share">Delen</string>
@@ -85,8 +86,6 @@
<string name="copy_immediately_summary">Kopieer de gescande inhoud automatisch naar het klembord. Let op: andere apps kunnen mogelijk meelezen op de achtergrond.</string>
<string name="show_meta_data">Metadata tonen</string>
<string name="show_meta_data_summary">Toon extra gegevens over de gescande barcode.</string>
<string name="show_qr_version">Show QR version</string>
<string name="show_qr_version_summary">Show QR version number.</string>
<string name="show_hex_dump">Hex-dump tonen</string>
<string name="show_hex_dump_summary">Hex-dump van de gescande inhoud tonen.</string>
<string name="close_automatically">Teruggaan na kopiëren/delen</string>
+9 -10
View File
@@ -30,6 +30,9 @@
<string name="error_correction_level_m" formatted="false">Średni (~15&#37; korekcji)</string>
<string name="error_correction_level_q" formatted="false">Kwartyl (~25&#37; korekcji)</string>
<string name="error_correction_level_h" formatted="false">Wysoki (~30&#37; korekcji)</string>
<string name="sequence_size">Sequence size</string>
<string name="sequence_index">Sequence index</string>
<string name="sequence_id">Sequence ID</string>
<string name="export_csv_comma">CSV z przecinkami</string>
<string name="export_csv_semicolon">CSV ze średnikami</string>
<string name="shortcut_encode">Stwórz kod kreskowy</string>
@@ -61,8 +64,6 @@
<string name="close_automatically_summary">Automatycznie powracaj do ekranu skanowania po skopiowaniu lub udostępnieniu przeczytanej zawartości.</string>
<string name="show_meta_data">Pokazuj metadane</string>
<string name="show_meta_data_summary">Pokaż dodatkowe dane o zeskanowanym kodzie kreskowym.</string>
<string name="show_qr_version">Show QR version</string>
<string name="show_qr_version_summary">Show QR version number.</string>
<string name="switch_camera">Przełącz aparat</string>
<string name="bulk_mode">Skanuj w sposób ciągły</string>
<string name="bulk_mode_summary">Zawsze rozpoczynaj skanowanie w sposób ciągły.</string>
@@ -81,10 +82,8 @@
<string name="zoom_by_swiping">Przybliżaj kamerę, przesuwając w górę/dół</string>
<string name="zoom_by_swiping_summary">Przesuń palcem w górę lub w dół na ekranie aparatu, aby sterować powiększeniem aparatu.</string>
<string name="view_barcode">Wyświetl kod kreskowy</string>
<string name="orientation">Orientacja</string>
<string name="error_encoding_barcode">Nie można utworzyć kodu kreskowego</string>
<string name="otpauth_add">Dodaj 2FA</string>
<string name="other_meta_data">Metadane</string>
<string name="remove_scan">Usuń skan</string>
<string name="separator_line_break">Przerwanie linii</string>
<string name="shortcut_decode">Zeskanuj kod kreskowy</string>
@@ -125,8 +124,7 @@
<string name="test_url">Testuj URL</string>
<string name="copy_password">Skopiuj hasło do schowka</string>
<string name="copied_password_to_clipboard">Hasło skopiowane do schowka</string>
<string name="pdf417_extra_metadata">Metadane PDF417</string>
<string name="suggested_price">Sugerowana cena</string>
<string name="gtin_price">Sugerowana cena</string>
<string name="preferences">Ustawienia</string>
<string name="scan_category">Skanowanie</string>
<string name="content_category">Zawarość</string>
@@ -134,9 +132,10 @@
<string name="custom_locale">Język niestandardowy</string>
<string name="follow_system_settings">Zgodny z ustawieniami systemu</string>
<string name="decode_barcode">Dekoduj kod kreskowy</string>
<string name="upc_ean_extension">Dodatek UPC EAN</string>
<string name="qr_version">QR version</string>
<string name="possible_country">Możliwy kraj produkcji</string>
<string name="gtin_add_on">Dodatek UPC EAN</string>
<string name="barcode_version_number">Version</string>
<string name="qr_version_and_modules">%1$d (%2$d modules)</string>
<string name="gtin_country">Możliwy kraj produkcji</string>
<string name="encode">ZAKODUJ</string>
<string name="error_no_content">Brak zawartości</string>
<string name="try_harder">Zoptymalizuj czytnik pod kątem dokładności, a nie prędkości</string>
@@ -151,7 +150,7 @@
<string name="auto_rotate">Rozpoznawaj kody kreskowe 1D pionowo</string>
<string name="auto_rotate_summary">Automatycznie obracaj ramkę aparatu, aby rozpoznać pionowe kody kreskowe 1D. W zależności od urządzenia może to mieć wpływ na wydajność.</string>
<string name="save_as_file_name">Jak zapisać plik w pobranych?</string>
<string name="issue_number">Numer wydania</string>
<string name="gtin_issue_number">Numer wydania</string>
<string name="background_request_failed">Żądanie w tle nie powiodło się</string>
<string name="entry_type">Typ</string>
<string name="wifi_network">Sieć Wi-Fi</string>
+9 -10
View File
@@ -15,14 +15,15 @@
<string name="error_correction_level_m" formatted="false">Médio (~15&#37; correção)</string>
<string name="error_correction_level_q" formatted="false">Quartil (~25&#37; correção)</string>
<string name="error_correction_level_h" formatted="false">Alto (~30&#37; correção)</string>
<string name="issue_number">Número de emissão</string>
<string name="orientation">Orientação</string>
<string name="other_meta_data">Metadados</string>
<string name="pdf417_extra_metadata">Metadados PDF417</string>
<string name="possible_country">Possível país de fabricação</string>
<string name="suggested_price">Preço sugerido</string>
<string name="upc_ean_extension">Extensão UPC EAN</string>
<string name="qr_version">Versão do QR</string>
<string name="sequence_size">Sequence size</string>
<string name="sequence_index">Sequence index</string>
<string name="sequence_id">Sequence ID</string>
<string name="gtin_issue_number">Número de emissão</string>
<string name="gtin_country">Possível país de fabricação</string>
<string name="gtin_price">Preço sugerido</string>
<string name="gtin_add_on">Extensão UPC EAN</string>
<string name="barcode_version_number">Versão</string>
<string name="qr_version_and_modules">%1$d (%2$d modules)</string>
<string name="toggle_flash">Ativar lanterna</string>
<string name="error_flash">Falha ao ligar a lanterna</string>
<string name="share">Compartilhar</string>
@@ -85,8 +86,6 @@
<string name="copy_immediately_summary">Copiar automaticamente ao clipboard o conteúdo digitalizado. Tem cuidado porque outros apps podem examinar seu clipboard em segundo plano.</string>
<string name="show_meta_data">Mostrar metadados</string>
<string name="show_meta_data_summary">Mostrar dados adicionais de código digitalizado.</string>
<string name="show_qr_version">Mostrar a versão do QR</string>
<string name="show_qr_version_summary">Mostrar o número de versão do código QR.</string>
<string name="show_hex_dump">Mostrar impressão hexadecimal</string>
<string name="show_hex_dump_summary">Mostrar a impressão hexadecimal do conteúdo digitalizado.</string>
<string name="close_automatically">Voltar após copiar/compartilhar</string>
+9 -10
View File
@@ -17,14 +17,15 @@
<string name="error_correction_level_m" formatted="false">Средний (≈15&#37; исправлений)</string>
<string name="error_correction_level_q" formatted="false">Квартиль (≈25&#37; исправлений)</string>
<string name="error_correction_level_h" formatted="false">Высокий (≈30&#37; исправлений)</string>
<string name="issue_number">Номер выпуска</string>
<string name="orientation">Ориентация</string>
<string name="other_meta_data">Метаданные</string>
<string name="pdf417_extra_metadata">Метаданные PDF417</string>
<string name="possible_country">Возможная страна изготовления</string>
<string name="suggested_price">Предположительная цена</string>
<string name="upc_ean_extension">Расширение UPC EAN</string>
<string name="qr_version">QR version</string>
<string name="sequence_size">Размер последовательности</string>
<string name="sequence_index">Индекс последовательности</string>
<string name="sequence_id">Идентификатор последовательности</string>
<string name="gtin_issue_number">Номер выпуска</string>
<string name="gtin_country">Возможная страна изготовления</string>
<string name="gtin_price">Предположительная цена</string>
<string name="gtin_add_on">Расширение UPC EAN</string>
<string name="barcode_version_number">Версия</string>
<string name="qr_version_and_modules">%1$d (модули: %2$d)</string>
<string name="toggle_flash">Включить вспышку</string>
<string name="error_flash">Ошибка при переключении вспышки</string>
<string name="share">Поделиться</string>
@@ -87,8 +88,6 @@
<string name="copy_immediately_summary">Автоматически копировать содержимое считанного штрих-кода в буфер обмена. Имейте в виду, что другие приложения могут иметь доступ к буферу обмена в фоне.</string>
<string name="show_meta_data">Показывать метаданные</string>
<string name="show_meta_data_summary">Показывать дополнительную информацию о считанных штрих-кодах.</string>
<string name="show_qr_version">Показывать версию QR</string>
<string name="show_qr_version_summary">Показывать номер версии QR-кода.</string>
<string name="show_hex_dump">Показывать шестнадцатеричный дамп</string>
<string name="show_hex_dump_summary">Показывать шестнадцатеричный дамп содержимого считанного штрих-кода.</string>
<string name="close_automatically">Возврат после копирования/обмена</string>
+9 -10
View File
@@ -15,14 +15,15 @@
<string name="error_correction_level_m" formatted="false">Orta (~&#37;15 düzeltim)</string>
<string name="error_correction_level_q" formatted="false">Dörtte Bir (~&#37;25 düzeltim)</string>
<string name="error_correction_level_h" formatted="false">Yüksek (~&#37;30 düzeltim)</string>
<string name="issue_number">Basım sayısı</string>
<string name="orientation">Yönelim</string>
<string name="other_meta_data">Üst veri</string>
<string name="pdf417_extra_metadata">PDF417 üst verisi</string>
<string name="possible_country">Olası üretim yeri</string>
<string name="suggested_price">Önerilen fiyat</string>
<string name="upc_ean_extension">UPC EAN eklentisi</string>
<string name="qr_version">QR version</string>
<string name="sequence_size">Sequence size</string>
<string name="sequence_index">Sequence index</string>
<string name="sequence_id">Sequence ID</string>
<string name="gtin_issue_number">Basım sayısı</string>
<string name="gtin_country">Olası üretim yeri</string>
<string name="gtin_price">Önerilen fiyat</string>
<string name="gtin_add_on">UPC EAN eklentisi</string>
<string name="barcode_version_number">Version</string>
<string name="qr_version_and_modules">%1$d (%2$d modules)</string>
<string name="toggle_flash">Flaşı aç</string>
<string name="error_flash">Error toggling flash</string>
<string name="share">Paylaş</string>
@@ -85,8 +86,6 @@
<string name="copy_immediately_summary">Taranan içerikleri kendiliğinden panoya kopyala. Unutmayın ki, diğer uygulamalar arka planda panonuzu gözetleyebilir.</string>
<string name="show_meta_data">Üst veriyi göster</string>
<string name="show_meta_data_summary">Taranan barkod ile ilgili ek veriyi göster</string>
<string name="show_qr_version">Show QR version</string>
<string name="show_qr_version_summary">Show QR version number.</string>
<string name="show_hex_dump">Hex yığınını göster</string>
<string name="show_hex_dump_summary">Taranan içeriklerin hex yığınını göster.</string>
<string name="close_automatically">Kopyala/Paylaş\'tan sonra geri dön</string>
+9 -10
View File
@@ -16,14 +16,15 @@
<string name="error_correction_level_m" formatted="false">Середній (~15&#37; виправлення)</string>
<string name="error_correction_level_q" formatted="false">Квартиль (~25&#37; виправлення)</string>
<string name="error_correction_level_h" formatted="false">Високий (~30&#37; виправлення)</string>
<string name="issue_number">Номер випуску</string>
<string name="orientation">Орієнтація</string>
<string name="other_meta_data">Метадані</string>
<string name="pdf417_extra_metadata">Метадані PDF417</string>
<string name="possible_country">Можлива країна-виробник</string>
<string name="suggested_price">Рекомендована ціна</string>
<string name="upc_ean_extension">Розширення UPC EAN</string>
<string name="qr_version">QR version</string>
<string name="sequence_size">Sequence size</string>
<string name="sequence_index">Sequence index</string>
<string name="sequence_id">Sequence ID</string>
<string name="gtin_issue_number">Номер випуску</string>
<string name="gtin_country">Можлива країна-виробник</string>
<string name="gtin_price">Рекомендована ціна</string>
<string name="gtin_add_on">Розширення UPC EAN</string>
<string name="barcode_version_number">Version</string>
<string name="qr_version_and_modules">%1$d (%2$d modules)</string>
<string name="toggle_flash">Увімкнути спалах</string>
<string name="error_flash">Error toggling flash</string>
<string name="share">Поділитися</string>
@@ -86,8 +87,6 @@
<string name="copy_immediately_summary">Автоматично копіювати відсканований вміст у буфер обміну. Зверніть увагу, що інші програми можуть стежити за буфером обміну в фоновому режимі.</string>
<string name="show_meta_data">Показувати метадані</string>
<string name="show_meta_data_summary">Показувати додаткові дані про відскановані штрих-коди.</string>
<string name="show_qr_version">Show QR version</string>
<string name="show_qr_version_summary">Show QR version number.</string>
<string name="show_hex_dump">Показувати шістнадцятковий дамп</string>
<string name="show_hex_dump_summary">Показувати шістнадцятковий дамп відсканованого вмісту.</string>
<string name="close_automatically">Повернутися після копіювання/поширення</string>
+9 -10
View File
@@ -14,14 +14,15 @@
<string name="error_correction_level_m" formatted="false">Trung bình (sửa ~15&#37;)</string>
<string name="error_correction_level_q" formatted="false">Một phần tư (sửa ~25&#37;)</string>
<string name="error_correction_level_h" formatted="false">Cao (sửa ~30&#37;)</string>
<string name="issue_number">Số</string>
<string name="orientation">Hướng</string>
<string name="other_meta_data">Dữ liệu</string>
<string name="pdf417_extra_metadata">Dữ liệu PDF417</string>
<string name="possible_country">Có thể được sản xuất ở nước</string>
<string name="suggested_price">Giá được gợi ý</string>
<string name="upc_ean_extension">Phần mở rộng UPC EAN</string>
<string name="qr_version">QR version</string>
<string name="sequence_size">Sequence size</string>
<string name="sequence_index">Sequence index</string>
<string name="sequence_id">Sequence ID</string>
<string name="gtin_issue_number">Số</string>
<string name="gtin_country">Có thể được sản xuất ở nước</string>
<string name="gtin_price">Giá được gợi ý</string>
<string name="gtin_add_on">Phần mở rộng UPC EAN</string>
<string name="barcode_version_number">Version</string>
<string name="qr_version_and_modules">%1$d (%2$d modules)</string>
<string name="toggle_flash">Bật/tắt đèn</string>
<string name="error_flash">Error toggling flash</string>
<string name="share">Chia sẻ</string>
@@ -84,8 +85,6 @@
<string name="copy_immediately_summary">Tự động sao chép kết quả. Lưu ý: ứng dụng khác có thể xem nội dung bạn đã sao chép.</string>
<string name="show_meta_data">Hiện dữ liệu</string>
<string name="show_meta_data_summary">Hiện thêm thông tin về mã vạch quét được.</string>
<string name="show_qr_version">Show QR version</string>
<string name="show_qr_version_summary">Show QR version number.</string>
<string name="show_hex_dump">Hiện mã thập lục phân</string>
<string name="show_hex_dump_summary">Hiện mã thập lục phân từ mã quét được.</string>
<string name="close_automatically">Quay lại sau khi Sao chép/Chia sẻ</string>
+9 -10
View File
@@ -14,14 +14,15 @@
<string name="error_correction_level_m" formatted="false">Medium (~15&#37; 准确度)</string>
<string name="error_correction_level_q" formatted="false">Quartile (~25&#37; 准确度)</string>
<string name="error_correction_level_h" formatted="false">High (~30&#37; 准确度)</string>
<string name="issue_number">发行编号</string>
<string name="orientation">方向</string>
<string name="other_meta_data">元数据</string>
<string name="pdf417_extra_metadata">PDF417 元数据</string>
<string name="possible_country">可能产地</string>
<string name="suggested_price">建议价格</string>
<string name="upc_ean_extension">UPC EAN 扩展</string>
<string name="qr_version">QR 版本</string>
<string name="sequence_size">Sequence size</string>
<string name="sequence_index">Sequence index</string>
<string name="sequence_id">Sequence ID</string>
<string name="gtin_issue_number">发行编号</string>
<string name="gtin_country">可能产地</string>
<string name="gtin_price">建议价格</string>
<string name="gtin_add_on">UPC EAN 扩展</string>
<string name="barcode_version_number">版本</string>
<string name="qr_version_and_modules">%1$d (%2$d modules)</string>
<string name="toggle_flash">开关闪光灯</string>
<string name="error_flash">开关闪光灯出错</string>
<string name="share">分享</string>
@@ -84,8 +85,6 @@
<string name="copy_immediately_summary">注意其他 APP 可能会在后台监控剪贴板</string>
<string name="show_meta_data">显示元数据</string>
<string name="show_meta_data_summary">显示已扫描条码的额外数据</string>
<string name="show_qr_version">显示 QR 版本</string>
<string name="show_qr_version_summary">显示 QR Code 的版本号</string>
<string name="show_hex_dump">显示16进制数据</string>
<string name="show_hex_dump_summary">显示已扫描条码的16进制数据</string>
<string name="close_automatically">复制/分享后自动返回</string>
+9 -10
View File
@@ -14,14 +14,15 @@
<string name="error_correction_level_m" formatted="false">中 (~15&#37; 準確度)</string>
<string name="error_correction_level_q" formatted="false">Quartile (~25&#37; 準確度)</string>
<string name="error_correction_level_h" formatted="false">高 (~30&#37; 準確度)</string>
<string name="issue_number">發行編號</string>
<string name="orientation">方向</string>
<string name="other_meta_data">Metadata</string>
<string name="pdf417_extra_metadata">PDF417 metadata</string>
<string name="possible_country">可能製作國家</string>
<string name="suggested_price">建議價格</string>
<string name="upc_ean_extension">UPC EAN 擴充</string>
<string name="qr_version">QR version</string>
<string name="sequence_size">Sequence size</string>
<string name="sequence_index">Sequence index</string>
<string name="sequence_id">Sequence ID</string>
<string name="gtin_issue_number">發行編號</string>
<string name="gtin_country">可能製作國家</string>
<string name="gtin_price">建議價格</string>
<string name="gtin_add_on">UPC EAN 擴充</string>
<string name="barcode_version_number">Version</string>
<string name="qr_version_and_modules">%1$d (%2$d modules)</string>
<string name="toggle_flash">開關閃光燈</string>
<string name="error_flash">Error toggling flash</string>
<string name="share">分享</string>
@@ -84,8 +85,6 @@
<string name="copy_immediately_summary">自動將掃描的內容複製到剪貼簿。請注意,其他 App 可能會在背景監控剪貼簿。</string>
<string name="show_meta_data">顯示 Metadata</string>
<string name="show_meta_data_summary">顯示已掃描條碼的額外資訊。</string>
<string name="show_qr_version">Show QR version</string>
<string name="show_qr_version_summary">Show QR version number.</string>
<string name="show_hex_dump">顯示 Hex dump</string>
<string name="show_hex_dump_summary">顯示已掃描條碼的 Hex dump。</string>
<string name="close_automatically">複製/分享後自動返回</string>
+6 -6
View File
@@ -5,6 +5,8 @@
<item>CODE 39</item>
<item>CODE 93</item>
<item>CODE 128</item>
<item>DATA BAR</item>
<item>DATA BAR EXPANDED</item>
<item>DATA MATRIX</item>
<item>EAN 8</item>
<item>EAN 13</item>
@@ -12,11 +14,9 @@
<item>MAXICODE</item>
<item>PDF 417</item>
<item>QR CODE</item>
<item>RSS 14</item>
<item>RSS EXPANDED</item>
<item>MICRO QR CODE</item>
<item>UPC A</item>
<item>UPC E</item>
<item>UPC EAN EXTENSION</item>
</string-array>
<string-array name="barcode_formats_values">
<item>AZTEC</item>
@@ -24,6 +24,8 @@
<item>CODE_39</item>
<item>CODE_93</item>
<item>CODE_128</item>
<item>DATA_BAR</item>
<item>DATA_BAR_EXPANDED</item>
<item>DATA_MATRIX</item>
<item>EAN_8</item>
<item>EAN_13</item>
@@ -31,10 +33,8 @@
<item>MAXICODE</item>
<item>PDF_417</item>
<item>QR_CODE</item>
<item>RSS_14</item>
<item>RSS_EXPANDED</item>
<item>MICRO_QR_CODE</item>
<item>UPC_A</item>
<item>UPC_E</item>
<item>UPC_EAN_EXTENSION</item>
</string-array>
</resources>
+2 -1
View File
@@ -6,7 +6,8 @@
<color name="background_color">#111</color>
<color name="background_progress">#8000</color>
<color name="button_text">#fff</color>
<color name="selected_row">#222</color>
<color name="selected_row">#8666</color>
<color name="pressed_row">#8222</color>
<color name="separator">#333</color>
<color name="crop_bound">#fff</color>
<color name="dot">#80b6d46f</color>
+2
View File
@@ -10,6 +10,7 @@
<item>Italian</item>
<item>Georgian</item>
<item>Dutch</item>
<item>Persian</item>
<item>Polski</item>
<item>Português do Brasil</item>
<item>Russian</item>
@@ -32,6 +33,7 @@
<item>it</item>
<item>ka</item>
<item>nl</item>
<item>fa</item>
<item>pl</item>
<item>pt-rBR</item>
<item>ru-rRU</item>
+10 -11
View File
@@ -15,14 +15,15 @@
<string name="error_correction_level_m" formatted="false">Medium (~15&#37; correction)</string>
<string name="error_correction_level_q" formatted="false">Quartile (~25&#37; correction)</string>
<string name="error_correction_level_h" formatted="false">High (~30&#37; correction)</string>
<string name="issue_number">Issue number</string>
<string name="orientation">Orientation</string>
<string name="other_meta_data">Metadata</string>
<string name="pdf417_extra_metadata">PDF417 metadata</string>
<string name="possible_country">Possible country of manufacture</string>
<string name="suggested_price">Suggested price</string>
<string name="upc_ean_extension">UPC EAN extension</string>
<string name="qr_version">QR version</string>
<string name="sequence_size">Sequence size</string>
<string name="sequence_index">Sequence index</string>
<string name="sequence_id">Sequence ID</string>
<string name="gtin_issue_number">Issue number</string>
<string name="gtin_country">Possible country of manufacture</string>
<string name="gtin_price">Suggested price</string>
<string name="gtin_add_on">UPC EAN extension</string>
<string name="barcode_version_number">Version</string>
<string name="qr_version_and_modules">%1$d (%2$d modules)</string>
<string name="toggle_flash">Toggle flash</string>
<string name="error_flash">Error toggling flash</string>
<string name="share">Share</string>
@@ -85,8 +86,6 @@
<string name="copy_immediately_summary">Automatically copy scanned contents into clipboard. Please note that other apps may snoop on your clipboard in the background.</string>
<string name="show_meta_data">Show metadata</string>
<string name="show_meta_data_summary">Show additional data about the scanned barcode.</string>
<string name="show_qr_version">Show QR version</string>
<string name="show_qr_version_summary">Show QR version number.</string>
<string name="show_hex_dump">Show hex dump</string>
<string name="show_hex_dump_summary">Show a hex dump of the scanned contents.</string>
<string name="close_automatically">Go back after Copy/Share</string>
@@ -101,7 +100,7 @@
<string name="clear_network_suggestions_nothing_to_remove">Nothing to remove</string>
<string name="send_category">Forwarding</string>
<string name="send_scan_active">Forward scans</string>
<string name="send_scan_active_summary">Enable to forward scans to a the given URL</string>
<string name="send_scan_active_summary">Enable to forward scans to a the given URL.</string>
<string name="send_scan_url">URL to forward to</string>
<string name="send_scan_type">Request type</string>
<string name="send_type_get_add_content">GET and simply add content</string>
-5
View File
@@ -92,11 +92,6 @@
android:key="show_meta_data"
android:title="@string/show_meta_data"
android:summary="@string/show_meta_data_summary"/>
<android.support.v7.preference.SwitchPreferenceCompat
android:defaultValue="false"
android:key="show_qr_version"
android:title="@string/show_qr_version"
android:summary="@string/show_qr_version_summary"/>
<android.support.v7.preference.SwitchPreferenceCompat
android:defaultValue="true"
android:key="show_hex_dump"
+119
View File
@@ -0,0 +1,119 @@
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
android:title="@string/preferences"
android:key="preferences">
<PreferenceCategory android:title="@string/scan_category">
<MultiSelectListPreference
android:key="barcode_formats"
android:title="@string/barcode_formats"
android:entries="@array/barcode_formats_names"
android:entryValues="@array/barcode_formats_values"/>
<android.support.v7.preference.SwitchPreferenceCompat
android:defaultValue="true"
android:key="show_crop_handle"
android:title="@string/show_crop_handle"
android:summary="@string/show_crop_handle_summary"/>
<android.support.v7.preference.SwitchPreferenceCompat
android:defaultValue="true"
android:key="zoom_by_swiping"
android:title="@string/zoom_by_swiping"
android:summary="@string/zoom_by_swiping_summary"/>
<android.support.v7.preference.SwitchPreferenceCompat
android:defaultValue="false"
android:key="auto_rotate"
android:title="@string/auto_rotate"
android:summary="@string/auto_rotate_summary"/>
<android.support.v7.preference.SwitchPreferenceCompat
android:defaultValue="false"
android:key="try_harder"
android:title="@string/try_harder"
android:summary="@string/try_harder_summary"/>
<android.support.v7.preference.SwitchPreferenceCompat
android:defaultValue="false"
android:key="bulk_mode"
android:title="@string/bulk_mode"
android:summary="@string/bulk_mode_summary"/>
<ListPreference
android:key="bulk_mode_delay"
android:title="@string/bulk_mode_delay"
android:entries="@array/bulk_mode_delays_names"
android:entryValues="@array/bulk_mode_delays_values"
android:defaultValue="500"/>
<android.support.v7.preference.SwitchPreferenceCompat
android:defaultValue="true"
android:key="show_toast_in_bulk_mode"
android:title="@string/show_toast_in_bulk_mode"
android:summary="@string/show_toast_in_bulk_mode_summary"/>
<android.support.v7.preference.SwitchPreferenceCompat
android:defaultValue="true"
android:key="vibrate"
android:title="@string/vibrate"
android:summary="@string/vibrate_summary"/>
<android.support.v7.preference.SwitchPreferenceCompat
android:defaultValue="true"
android:key="use_history"
android:title="@string/use_history"
android:summary="@string/use_history_summary"/>
<android.support.v7.preference.SwitchPreferenceCompat
android:defaultValue="true"
android:key="ignore_consecutive_duplicates"
android:title="@string/ignore_consecutive_duplicates"
android:summary="@string/ignore_consecutive_duplicates_summary"/>
<android.support.v7.preference.SwitchPreferenceCompat
android:defaultValue="false"
android:key="copy_immediately"
android:title="@string/copy_immediately"
android:summary="@string/copy_immediately_summary"/>
</PreferenceCategory>
<PreferenceCategory android:title="@string/send_category">
<android.support.v7.preference.SwitchPreferenceCompat
android:defaultValue="true"
android:key="send_scan_active"
android:title="@string/send_scan_active"
android:summary="@string/send_scan_active_summary"/>
<de.markusfisch.android.binaryeye.preference.UrlPreference
android:key="send_scan_url"
android:title="@string/send_scan_url"/>
<ListPreference
android:key="send_scan_type"
android:title="@string/send_scan_type"
android:entries="@array/send_type_names"
android:entryValues="@array/send_type_values"
android:defaultValue="0"/>
</PreferenceCategory>
<PreferenceCategory android:title="@string/content_category">
<android.support.v7.preference.SwitchPreferenceCompat
android:defaultValue="false"
android:key="open_immediately"
android:title="@string/open_immediately"
android:summary="@string/open_immediately_summary"/>
<android.support.v7.preference.SwitchPreferenceCompat
android:defaultValue="true"
android:key="show_meta_data"
android:title="@string/show_meta_data"
android:summary="@string/show_meta_data_summary"/>
<android.support.v7.preference.SwitchPreferenceCompat
android:defaultValue="true"
android:key="show_hex_dump"
android:title="@string/show_hex_dump"
android:summary="@string/show_hex_dump_summary"/>
<android.support.v7.preference.SwitchPreferenceCompat
android:defaultValue="true"
android:key="close_automatically"
android:title="@string/close_automatically"
android:summary="@string/close_automatically_summary"/>
<ListPreference
android:key="default_search_url"
android:title="@string/default_search_engine"
android:entries="@array/search_engines_names"
android:entryValues="@array/search_engines_values"
android:defaultValue=""/>
<de.markusfisch.android.binaryeye.preference.UrlPreference
android:key="open_with_url"
android:title="@string/open_with_url"/>
<Preference
android:key="clear_network_suggestions"
android:title="@string/clear_network_suggestions"
android:summary="@string/clear_network_suggestions_summary"/>
</PreferenceCategory>
</PreferenceScreen>
-5
View File
@@ -87,11 +87,6 @@
android:key="show_meta_data"
android:title="@string/show_meta_data"
android:summary="@string/show_meta_data_summary"/>
<android.support.v7.preference.SwitchPreferenceCompat
android:defaultValue="false"
android:key="show_qr_version"
android:title="@string/show_qr_version"
android:summary="@string/show_qr_version_summary"/>
<android.support.v7.preference.SwitchPreferenceCompat
android:defaultValue="true"
android:key="show_hex_dump"
-40
View File
@@ -1,40 +0,0 @@
#pragma version(1)
#pragma rs java_package_name(de.markusfisch.android.binaryeye.rs)
#pragma rs reduce(analyze) initializer(analyzeInit) accumulator(analyzeAccumulator) combiner(analyzeCombiner) outconverter(analyzeConverter)
const static float3 relativeLuminance = {0.2126f, 0.7152f, 0.0722f};
typedef struct {
int transparent;
int visible;
int bright;
} Report;
static void analyzeInit(Report *report) {
report->transparent = 0;
report->visible = 0;
report->bright = 0;
}
static void analyzeAccumulator(Report *accum, uchar4 val) {
if (val.a < 255) {
accum->transparent = 1;
}
if (val.a > 0) {
++accum->visible;
float4 f4 = rsUnpackColor8888(val);
float3 result = dot(f4.rgb, relativeLuminance);
accum->bright += step(0.5f, result.r + result.g + result.b);
}
}
static void analyzeCombiner(Report *accum, const Report *val) {
accum->transparent += val->transparent;
accum->visible += val->visible;
accum->bright += val->bright;
}
static void analyzeConverter(int2 *result, const Report *report) {
result->x = report->transparent;
result->y = report->bright > 0 && report->visible / report->bright < 2;
}
-25
View File
@@ -1,25 +0,0 @@
#pragma version(1)
#pragma rs java_package_name(de.markusfisch.android.binaryeye.rs)
#pragma rs_fp_relaxed
rs_allocation inImage;
int inWidth;
int inHeight;
uchar RS_KERNEL rotate90(const uchar in, uint32_t x, uint32_t y) {
const uchar *out = rsGetElementAt(inImage, y, inHeight - 1 - x);
return *out;
}
uchar RS_KERNEL rotate180(const uchar in, uint32_t x, uint32_t y) {
const uchar *out = rsGetElementAt(
inImage,
inWidth - 1 - x,
inHeight - 1 - y);
return *out;
}
uchar RS_KERNEL rotate270(const uchar in, uint32_t x, uint32_t y) {
const uchar *out = rsGetElementAt(inImage, inWidth - 1 - y, x);
return *out;
}
@@ -1,6 +1,6 @@
package de.markusfisch.android.binaryeye.actions.vtype
import junit.framework.TestCase.*
import junit.framework.TestCase.assertEquals
import org.junit.Test
class VTypeTest {
@@ -1,6 +1,6 @@
package de.markusfisch.android.binaryeye.actions.web
import junit.framework.TestCase.*
import junit.framework.TestCase.assertEquals
import org.junit.Test
class WebTest {
+3 -3
View File
@@ -1,8 +1,8 @@
buildscript {
ext {
kotlin_version = '1.6.21'
tools_version = '7.2.0'
sdk_version = 32
kotlin_version = '1.7.10'
tools_version = '7.3.0'
sdk_version = 33
support_version = '25.3.1'
}
@@ -0,0 +1,10 @@
* افزودن پشتیبانی از قالب MATMSG
* افزودن قابلیت نمایش نگارش کیوآرکد در تنظیمات
* Add timezone offset in calendar dates
* Recognize colloquial incomplete URLs
* به‌روز رسانی کتابخانهٔ ZXing به آخرین نگارش
* به‌روز رسانی ترجمهٔ چکوسلواکی
* به‌روز رسانی ترجمهٔ روسی
* به‌روز رسانی ترجمهٔ ژاپنی
* به‌روز رسانی ترجمهٔ مجارستانی
@@ -0,0 +1,11 @@
در هر دو جهت افقی و عمودی کار می‌کند، می‌تواند بارکدهای وارونه را بخواند،
از طراحی متریال پیروی می‌کند و همچنین قابلیت ایجاد بارکد را نیز داراست.
از کتابخانهٔ پویش بارکد ZXing ("Zebra Crossing") استفاده می‌کند.
قالب‌های بارکد پشتیبانی‌شده:
AZTEC, CODABAR, CODE 39, CODE 93, CODE 128, RSS 14,
DATA MATRIX, EAN 8, EAN 13, ITF, PDF417, QR CODE,
RSS EXPANDED, UPC A, UPC E, UPC EAN EXTENSION.
این کاره متن‌باز است:
https://github.com/markusfisch/BinaryEye
@@ -0,0 +1 @@
یک پویشگر بارکد دیگر برای اندروید. آزاد، بدون تبلیغات و متن‌باز.
+1
View File
@@ -0,0 +1 @@
یک پویشگر بارکد دیگر
+1
View File
@@ -0,0 +1 @@
باینری آی
+1 -1
View File
@@ -1,6 +1,6 @@
#Wed Jan 26 11:58:22 CET 2022
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME