Я хочу сгенерировать QR-код, который должен поместить логотип в центр. Я проверил библиотеку zxing и сделал это с приложением Java, прочитав этот код (Как сгенерировать QR-код с логотипом внутри?). Но, насколько я знаю, мы не можем использовать свинг в android/ios. Итак, как с этим справиться?
Как сгенерировать qr-код с наложением изображения в Gluon?
Ответы (2)
На основании ссылки, на которую вы ссылаетесь, принятый ответ указал на этот сообщение, где вы можете видеть, что трюк для создания QR, который позволяет скрыть его центральную часть, не влияя на его читаемость сканером QR, может быть выполнен путем увеличения ошибки уровень:
30% (H) исправления ошибок, где исправление ошибок уровня H должно привести к QRCode, который все еще действителен, даже если он скрыт на 30%
В качестве продолжения этого вопрос, вы можете просто включить подсказку при кодировании текста:
public Image generateQR(int width, int height) {
File root = Services.get(StorageService.class)
.flatMap(StorageService::getPrivateStorage)
.orElseThrow(() -> new RuntimeException("Storage Service not found"));
String uuid = Services.get(DeviceService.class)
.map(DeviceService::getUuid)
.orElse("123456789");
MultiFormatWriter codeWriter = new MultiFormatWriter();
// Add maximum correction
Map<EncodeHintType, ErrorCorrectionLevel> hints = new HashMap<>();
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
try {
BarcodeFormat format = BarcodeFormat.QR_CODE;
BitMatrix bitMatrix = codeWriter.encode(uuid, format,
width, height, hints); // <--- add hints
...
return writableImage;
}
}
Вы получите изображение QR-кода без наложения.
Следующим шагом является объединение этого изображения с изображением вашего логотипа без использования Swing. Но на самом деле нам этого делать не нужно: мы можем просто использовать два узла ImageView
!
ImageView imageView = new ImageView();
imageView.setFitWidth(256);
imageView.setFitHeight(256);
imageView.setImage(service.generateQR(256, 256));
ImageView overlay = new ImageView(
new Image(getClass().getResourceAsStream("/icon.png")));
overlay.setFitWidth(80);
overlay.setFitHeight(80);
StackPane combinedQR = new StackPane(imageView, overlay);
...
Полученный код по-прежнему читабелен.
Вы также можете поиграть с результатом, добавив к изображениям эффект смешивания, например:
overlay.setBlendMode(BlendMode.ADD);
но это будет зависеть от того, как изображение вашего логотипа сочетается с QR.
Наконец, если вам все еще нужно одно комбинированное изображение, вы можете создать снимок панели стека:
WritableImage snapshot = combinedQR.snapshot(new SnapshotParameters(), null);
StackPane
, так как они складываются в кучу, сохраняя их по центру, поэтому, если вам нужно скомпоновать два изображения, естественным решением является использование двух узлов ImageView
в StackPane
. Swing вообще не нужен. Имеет ли это смысл?
- person José Pereda; 13.02.2019
Вдохновленный ответом Хосе, я написал собственное решение на Kotlin для устройств Android. Во-первых, добавьте ZXing в свой проект:
implementation "com.google.zxing:core:3.4.0"
Создайте фиктивный рисунок и поместите его в свою папку res/drawable
:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/colorAccent" />
<size
android:width="48dp"
android:height="48dp" />
</shape>
Затем добавьте в проект следующие расширения:
String.encodeAsQrCodeBitmap
преобразует строку в растровое изображение QR-кода. Он также принимает overlayBitmap
, если ноль, то только строка преобразуется в QR-код, и вы можете настроить цвета QR-кода.
Bitmap.addOverlayToCenter
объединяет два растровых изображения в одно и помещает наложенное растровое изображение в центр.
Int.dpToPx()
преобразует DP в пиксели.
@Throws(WriterException::class)
fun String.encodeAsQrCodeBitmap(
dimension: Int,
overlayBitmap: Bitmap? = null,
@ColorInt color1: Int = Color.BLACK,
@ColorInt color2: Int = Color.WHITE
): Bitmap? {
val result: BitMatrix
try {
result = MultiFormatWriter().encode(
this,
BarcodeFormat.QR_CODE,
dimension,
dimension,
hashMapOf(EncodeHintType.ERROR_CORRECTION to ErrorCorrectionLevel.H)
)
} catch (e: IllegalArgumentException) {
// Unsupported format
return null
}
val w = result.width
val h = result.height
val pixels = IntArray(w * h)
for (y in 0 until h) {
val offset = y * w
for (x in 0 until w) {
pixels[offset + x] = if (result.get(x, y)) color1 else color2
}
}
val bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888)
bitmap.setPixels(pixels, 0, dimension, 0, 0, w, h)
return if (overlayBitmap != null) {
bitmap.addOverlayToCenter(overlayBitmap)
} else {
bitmap
}
}
fun Bitmap.addOverlayToCenter(overlayBitmap: Bitmap): Bitmap {
val bitmap2Width = overlayBitmap.width
val bitmap2Height = overlayBitmap.height
val marginLeft = (this.width * 0.5 - bitmap2Width * 0.5).toFloat()
val marginTop = (this.height * 0.5 - bitmap2Height * 0.5).toFloat()
val canvas = Canvas(this)
canvas.drawBitmap(this, Matrix(), null)
canvas.drawBitmap(overlayBitmap, marginLeft, marginTop, null)
return this
}
fun Int.dpToPx(): Int {
return (this * Resources.getSystem().displayMetrics.density).toInt()
}
Затем выполните в своем фрагменте/действии следующее: получите наложение из ресурсов, преобразуйте строку в QR-код и отобразите ее в ImageView:
try {
val displayMetrics = DisplayMetrics()
activity?.windowManager?.defaultDisplay?.getMetrics(displayMetrics)
val size = displayMetrics.widthPixels.coerceAtMost(displayMetrics.heightPixels)
val overlay = ContextCompat.getDrawable(requireContext(), R.drawable.dummy_round)
?.toBitmap(72.dpToPx(), 72.dpToPx())
val bitmap = "https://www.example.com".encodeAsQrCodeBitmap(size, overlay)
imageView.setImageBitmap(bitmap)
} catch (e: Exception) {
// handle Errors here
}
Результат:
SwingFXUtils#toFXImage
, поскольку Gluon Mobile не поддерживает модули Swing. - person ItachiUchiha   schedule 11.02.2019BufferedImage
, вы можете преобразовать его в изображение JavaFX, используя ссылку, которую я разместил в своем комментарии выше. - person ItachiUchiha   schedule 12.02.2019