public bool DetectQRCode() { var qrReader = new QRCodeMultiReader(); var qrReaderHints = new Dictionary<DecodeHintType, object>() { { DecodeHintType.TRY_HARDER, true } }; var qrImageSource = new BitmapLuminanceSource((Bitmap)Image); var qrBinarizer = new HybridBinarizer(qrImageSource); var qrBinaryBitmap = new BinaryBitmap(qrBinarizer); try { qrCodeResult = qrReader.decodeMultiple(qrBinaryBitmap, qrReaderHints)?.FirstOrDefault(); qrCodeResultScale = 1F; } catch (ReaderException) { // QR Detection Failed qrCodeResult = null; } if (qrCodeResult == null) { var sizePoints = PdfiumDocument.PageSizes[PageIndex]; // Try at 175% using (var image = PdfiumDocument.Render(PageIndex, (int)(sizePoints.Width * 1.75), (int)(sizePoints.Height * 1.75), 72F, 72F, false)) { qrImageSource = new BitmapLuminanceSource((Bitmap)image); // Try Entire Image qrBinarizer = new HybridBinarizer(qrImageSource); qrBinaryBitmap = new BinaryBitmap(qrBinarizer); try { qrCodeResult = qrReader.decodeMultiple(qrBinaryBitmap, qrReaderHints)?.FirstOrDefault(); qrCodeResultScale = 1.75F; } catch (ReaderException) { // QR Detection Failed qrCodeResult = null; } } if (qrCodeResult == null) { // Try at 200% using (var image = PdfiumDocument.Render(PageIndex, (int)(sizePoints.Width * 2), (int)(sizePoints.Height * 2), 72F, 72F, false)) { qrImageSource = new BitmapLuminanceSource((Bitmap)image); // Try Entire Image qrBinarizer = new HybridBinarizer(qrImageSource); qrBinaryBitmap = new BinaryBitmap(qrBinarizer); try { qrCodeResult = qrReader.decodeMultiple(qrBinaryBitmap, qrReaderHints)?.FirstOrDefault(); qrCodeResultScale = 2F; } catch (ReaderException) { // QR Detection Failed qrCodeResult = null; } } } } if (qrCodeResult != null) { // Detect Rotation var rotationAngle = Math.Atan2( qrCodeResult.ResultPoints[2].Y - qrCodeResult.ResultPoints[1].Y, qrCodeResult.ResultPoints[2].X - qrCodeResult.ResultPoints[1].X) * 180 / Math.PI; if (rotationAngle <= 45 || rotationAngle > 315) { detectedRotation = RotateFlipType.RotateNoneFlipNone; } else if (rotationAngle <= 135) { detectedRotation = RotateFlipType.Rotate270FlipNone; } else if (rotationAngle <= 225) { detectedRotation = RotateFlipType.Rotate180FlipNone; } else { detectedRotation = RotateFlipType.Rotate90FlipNone; } // Reset Thumbnail if (renderedThumbnail != null) { renderedThumbnail.Dispose(); renderedThumbnail = null; } // Try binary encoding (from v2) if (qrCodeResult.ResultMetadata.ContainsKey(ResultMetadataType.BYTE_SEGMENTS)) { var byteSegments = (List<byte[]>)qrCodeResult.ResultMetadata[ResultMetadataType.BYTE_SEGMENTS]; var qrBytes = byteSegments[0]; if (DocumentUniqueIdentifier.IsDocumentUniqueIdentifier(qrBytes)) { Identifier = DocumentUniqueIdentifier.Parse(Database, qrBytes); } } // Fall back to v1 if (Identifier == null) { Identifier = DocumentUniqueIdentifier.Parse(Database, qrCodeResult.Text); } return true; } return false; }
/// <summary> /// Tries to decode barcodes within an image which is given by a luminance source. /// That method gives a chance to prepare a luminance source completely before calling /// the time consuming decoding method. On the other hand there is a chance to create /// a luminance source which is independent from external resources (like Bitmap objects) /// and the decoding call can be made in a background thread. /// </summary> /// <param name="luminanceSource">The luminance source.</param> /// <returns></returns> private Result[] DecodeMultiple(LuminanceSource luminanceSource) { var results = default(Result[]); var binarizer = CreateBinarizer(luminanceSource); var binaryBitmap = new BinaryBitmap(binarizer); var rotationCount = 0; var rotationMaxCount = 1; MultipleBarcodeReader multiReader = null; if (AutoRotate) { Options.Hints[DecodeHintType.TRY_HARDER_WITHOUT_ROTATION] = true; rotationMaxCount = 4; } var formats = Options.PossibleFormats; if (formats != null && formats.Length == 1 && formats[0] == BarcodeFormat.QR_CODE) { multiReader = new QRCodeMultiReader(); } else { multiReader = new GenericMultipleBarcodeReader(Reader); } for (; rotationCount < rotationMaxCount; rotationCount++) { results = multiReader.decodeMultiple(binaryBitmap, Options.Hints); if (results == null) { if (TryInverted && luminanceSource.InversionSupported) { binaryBitmap = new BinaryBitmap(CreateBinarizer(luminanceSource.invert())); results = multiReader.decodeMultiple(binaryBitmap, Options.Hints); } } if (results != null || !luminanceSource.RotateSupported || !AutoRotate) break; binaryBitmap = new BinaryBitmap(CreateBinarizer(luminanceSource.rotateCounterClockwise())); } if (results != null) { foreach (var result in results) { if (result.ResultMetadata == null) { result.putMetadata(ResultMetadataType.ORIENTATION, rotationCount * 90); } else if (!result.ResultMetadata.ContainsKey(ResultMetadataType.ORIENTATION)) { result.ResultMetadata[ResultMetadataType.ORIENTATION] = rotationCount * 90; } else { // perhaps the core decoder rotates the image already (can happen if TryHarder is specified) result.ResultMetadata[ResultMetadataType.ORIENTATION] = ((int)(result.ResultMetadata[ResultMetadataType.ORIENTATION]) + rotationCount * 90) % 360; } } OnResultsFound(results); } return results; }