private QrDecodingResult decodeQR(BufferedImage image, int filenumber) { // Create qr image from original for decoding BufferedImage qrcorner = extractTopRightCornerForQR(image); BufferedImage blackWhite = new BufferedImage( qrcorner.getWidth() / 2, qrcorner.getHeight() / 2, BufferedImage.TYPE_INT_RGB); Graphics2D g2d = blackWhite.createGraphics(); g2d.drawImage(qrcorner, 0, 0, qrcorner.getWidth() / 2, qrcorner.getHeight() / 2, null); g2d.dispose(); qrcorner = blackWhite; QrDecodingResult decodingresult = new QrDecodingResult(); try { // Decode QR Result result = null; Exception decodeException = null; // Try to decode at least three times int maxattempts = 3; int attempt = 1; while (attempt <= maxattempts) { logger.debug("Attempt " + attempt); try { BinaryBitmap bitmap = getBitmapFromBufferedImage(qrcorner); result = reader.decode(bitmap); decodeException = null; logger.debug("Success!"); break; } catch (Exception e) { decodeException = e; if (debugcorners) { try { ImageIO.write( (RenderedImage) qrcorner, "jpg", new File( tempdir.getAbsolutePath() + "/corner" + filenumber + "_" + attempt + ".jpg")); } catch (IOException ex) { ex.printStackTrace(); } } } attempt++; com.jhlabs.image.MedianFilter filter = new MedianFilter(); BufferedImage newqrcorner = new BufferedImage( qrcorner.getWidth(), qrcorner.getHeight(), BufferedImage.TYPE_BYTE_GRAY); filter.filter(qrcorner, newqrcorner); qrcorner = newqrcorner; } if (decodeException != null) throw decodeException; // Clean the output from the QR decodingresult.setOutput(result.getText().replace(" ", "").trim()); // The image filename will be the output decodingresult.setFilename(decodingresult.getOutput()); // Consistency checking if (decodingresult.getFilename().length() == 0) { decodingresult.setFilename("ERROR-EMPTYQR-" + (filenumber + 1)); } else { String[] parts = decodingresult.getFilename().split("-"); // Now check if the QR string has five parts (which indicates it is an answer sheet) if (parts.length == 5 && parts[4].trim().contains("BB")) { decodingresult.setAttemptId(Integer.parseInt(parts[3])); decodingresult.setAnswersheet(true); } // Now check if the QR string has a fourth component (image is rotated) if (parts.length == 4 && parts[3].trim().contains("R")) { decodingresult.setRotated(true); } // If everything looks well, parse the numbers from the decoded QR info if (parts.length >= 3) { // Parse the parts (any exception will be caught as an error) decodingresult.setUserid(Integer.parseInt(parts[0])); decodingresult.setCourseid(Integer.parseInt(parts[1])); decodingresult.setExampage(Integer.parseInt(parts[2])); // Set filename with the corresponding IDs decodingresult.setFilename( decodingresult.getUserid() + "-" + decodingresult.getCourseid() + "-" + decodingresult.getExampage()); // Processing was a success decodingresult.setSuccess(true); } else { logger.error("QR contains invalid information"); decodingresult.setFilename("ERROR-INVALIDPARTSQR-" + (filenumber + 1)); } } } catch (NotFoundException e) { decodingresult.setFilename("ERROR-NOTFOUND-" + (filenumber + 1)); } catch (ChecksumException e) { decodingresult.setFilename("ERROR-CHECKSUM-" + (filenumber + 1)); } catch (FormatException e) { decodingresult.setFilename("ERROR-CHECKSUM-" + (filenumber + 1)); } catch (Exception e) { decodingresult.setFilename("ERROR-NULL-" + (filenumber + 1)); } // Regardless of the result, the back-file name is the sames as the file with a b decodingresult.setBackfilename(decodingresult.getFilename() + "b"); return decodingresult; }
/* (non-Javadoc) * @see java.lang.Runnable#run() */ @Override public void run() { // First decode the frontpage this.qrResult = decodeQR(image, filenumber); // If we couldn't find a code, but we have a backpage, we try processing it if (!qrResult.isSuccess() && this.doubleside) { QrDecodingResult qrresultback = decodeQR(backimage, filenumber); // If the backpage contains a valid QR then it was flipped, we flip the front and backpages if (qrresultback.isSuccess()) { // Flip front and backpages BufferedImage tmp = this.image; this.image = this.backimage; this.backimage = tmp; // Replace decoding info with the backpage qrResult = qrresultback; } } float factor = 1200f / this.image.getWidth(); this.image = resizeImage(this.image, factor); if (this.backimage != null) { this.image = resizeImage(this.image, factor); } // If images were rotated, both are rotated if (qrResult.isSuccess() && qrResult.isRotated()) { this.image = rotateImage180(this.image); if (this.doubleside) { this.backimage = rotateImage180(this.backimage); } } // All numbers are ok, now create the anonymous version of the page this.anonymous = createAnonymousVersion(image); if (this.doubleside) { this.backanonymous = createAnonymousVersion(this.backimage); } this.success = qrResult.isSuccess(); this.rotated = qrResult.isRotated(); if (this.success && qrResult.isAnswersheet() && this.moodle.getOMRTemplate() != null) { TreeMap<String, String> answers = new TreeMap<String, String>(); FormTemplate formTemplate = null; try { File omrtemplatefile = new File(this.moodle.getOMRTemplate()); formTemplate = new FormTemplate(omrtemplatefile); FormTemplate filledForm = new FormTemplate(qrResult.getFilename(), formTemplate); filledForm.findCorners( anonymous, this.moodle.getOMRthreshold(), this.moodle.getOMRdensity()); filledForm.findPoints( anonymous, this.moodle.getOMRthreshold(), this.moodle.getOMRdensity(), this.moodle.getOMRshapeSize()); for (String key : filledForm.getFields().keySet()) { FormField ff = filledForm.getField(key); answers.put(key, ff.getValues()); } qrResult.setAnswers(answers); } catch (Exception e) { logger.error("Problem with the OMR template"); e.printStackTrace(); } } // Now write images as files try { ImageIO.write( (RenderedImage) image, imageExtension, new File( tempdir.getAbsolutePath() + "/" + qrResult.getFilename() + "." + imageExtension)); ImageIO.write( (RenderedImage) anonymous, imageExtension, new File( tempdir.getAbsolutePath() + "/" + qrResult.getFilename() + "_a." + imageExtension)); if (doubleside) { ImageIO.write( (RenderedImage) backimage, imageExtension, new File( tempdir.getAbsolutePath() + "/" + qrResult.getBackfilename() + "." + imageExtension)); ImageIO.write( (RenderedImage) backanonymous, imageExtension, new File( tempdir.getAbsolutePath() + "/" + qrResult.getBackfilename() + "_a." + imageExtension)); } } catch (IOException e) { e.printStackTrace(); } }