QR code decoding by zxing

package com.ns.utils;

import java.awt.image.BufferedImage;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.util.Vector;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.rendering.PDFRenderer;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.LuminanceSource;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.NotFoundException;
import com.google.zxing.Result;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.common.HybridBinarizer;

public class QRCodeZxingUtil {

	public static Map<String, String> scanQRCode(String dir, String fileName, String textKey) {
		Map<String, String> mp = new HashMap<String, String>();
		// Hints for scanning
		Vector<BarcodeFormat> decodeFormat = new Vector<BarcodeFormat>();
		decodeFormat.add(BarcodeFormat.QR_CODE);

		Hashtable<DecodeHintType, Object> hintMap = new Hashtable<DecodeHintType, Object>();
		hintMap.put(DecodeHintType.TRY_HARDER, true);
		hintMap.put(DecodeHintType.POSSIBLE_FORMATS, decodeFormat);

		MultiFormatReader qrcodeReader = new MultiFormatReader();
		qrcodeReader.setHints(hintMap);
		// We try for several images of the PDF page at several DPI settings,
		// starting at the lowest setting, this might help for speed...
		int[] dpiSettings = { 96, 150, 200, 250, 300, 350 };
		for (int i = 0; i < dpiSettings.length; i++) {
			try {
				// Try lowest DPI first.
				BufferedImage pageImage = getPageImage(dir, fileName, dpiSettings[i]);
				if (pageImage != null) {
					LuminanceSource source = new BufferedImageLuminanceSource(pageImage);
					BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
					// By using decodeWithState, we keep the Hints that we set earlier.
					Result result = qrcodeReader.decodeWithState(bitmap);
					String text = result.getText();
					// System.out.println(" Sucess at DPI -> " + dpiSettings[i]);
					pageImage.flush();

					if (text != null && text.length() > 0) {
						mp.put(textKey, text);
						mp.put("DPI", Integer.toString(dpiSettings[i]));
					}
				}
				if (mp.containsKey(textKey)) {
					return mp;
				}
			} catch (IOException e) {
				System.out.print(" IOException at DPI -> " + dpiSettings[i]);
			} catch (NotFoundException e) {
				System.out.print(" NotFoundException at DPI -> " + dpiSettings[i]);
			}
		}
		return null;
	}

	private static BufferedImage getPageImage(String dir, String fileName, int dpi) throws IOException {
		BufferedImage image = null;
		Path docPath = Paths.get(dir.concat(fileName));
		PDDocument pdfDoc = PDDocument.load(docPath.toFile());
		try {
			PDFRenderer renderer = new PDFRenderer(pdfDoc);
			image = renderer.renderImageWithDPI(0, dpi, ImageType.BINARY); // entire page info
		} finally {
			pdfDoc.close();
		}		
		return image;
	}
}

QR code decoding by pdmodel

package com.ns.utils;

import java.awt.image.BufferedImage;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDResources;
import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObject;
import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObjectImage;

import com.ns.service.QRCodeDecoder;

public class QRCodePdModelUtil {

	@SuppressWarnings("unchecked")
	public static Map<String, String> scanQRCode(String dir, String fileName, String textKey) {

		Map<String, String> map = new HashMap<String, String>();

		List<PDPage> pages = null;
		BufferedImage qrCodeImg = null;
		String qrCode = null;
		PDDocument pdfDoc = null;

		try {
			Path docPath = Paths.get(dir.concat(fileName));
			pdfDoc = PDDocument.load(docPath.toFile());
			QRCodeDecoder decoder = new QRCodeDecoder();

			pages = pdfDoc.getDocumentCatalog().getAllPages();
			int dpi = 0;
			int dpiEffective = 0;
			int dpiLow = 0;

			for (PDPage page : pages) {
				try {
					if (null == qrCode) {
						qrCodeImg = page.convertToImage(BufferedImage.TYPE_BYTE_GRAY, 100);
						qrCode = decoder.getCompressedQRCode(qrCodeImg);
					}
					if (null == qrCode) {
						dpi = detectPageDPI(page);
						dpiEffective = dpi;
						dpiLow = dpi - 5;
						for (; dpiLow < dpiEffective; dpiEffective--) {
							qrCodeImg = page.convertToImage(BufferedImage.TYPE_BYTE_GRAY, dpiEffective);
							qrCode = decoder.getCode(qrCodeImg);
							if (null != qrCode) {
								break;
							}
						}
					}
					if (null == qrCode) {
						qrCodeImg = page.convertToImage(BufferedImage.TYPE_BYTE_GRAY, 400);
						qrCode = decoder.getCompressedQRCode(qrCodeImg);
					}
					System.out.println("Code:::" + qrCode);
					if (null != qrCode) {
						map.put("DPI", Integer.toString(dpi));
						map.put(textKey, qrCode);
						return map;
					}
				} catch (Exception e) {
					System.out.println(e.getMessage());

				} finally {
					qrCodeImg = null;
					qrCode = null;
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (null != pdfDoc) {
				try {
					pdfDoc.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			pages = null;
		}
		return null;
	}

	private static int detectPageDPI(PDPage page) {
		PDResources res = page.getResources();
		Collection<PDXObject> xObjects = res.getXObjects().values();
		int imgHeight = 0;
		for (PDXObject xObject : xObjects) {
			if (xObject instanceof PDXObjectImage) {
				imgHeight = ((PDXObjectImage) xObject).getHeight();
			}
		}

		float pageHeight = page.getMediaBox().getHeight() / 72;
		int dpi = (int) (imgHeight / pageHeight);
		if (200 > dpi) {
			dpi = 200;
		}
		if (300 < dpi) {
			dpi = 300;
		}
		return dpi;
	}

}

package com.ns.service;

import java.awt.RenderingHints;
import java.awt.RenderingHints.Key;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.awt.image.ConvolveOp;
import java.awt.image.Kernel;
import java.awt.image.RasterFormatException;
import java.util.HashMap;
import java.util.Map;

import org.springframework.stereotype.Service;

import com.google.zxing.BinaryBitmap;
import com.google.zxing.ChecksumException;
import com.google.zxing.FormatException;
import com.google.zxing.LuminanceSource;
import com.google.zxing.NotFoundException;
import com.google.zxing.Result;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.QRCodeReader;

@Service
public class QRCodeDecoder {

	public String getCode(BufferedImage image) {
		String code = null;
		try {
			// vertical bottom scan
			BufferedImage procImage = image.getSubimage(0, image.getHeight() / 2, image.getWidth(), image.getHeight() / 2 - 20);
			code = decode(procImage);

		} catch (RasterFormatException e) {
			// continue
		}
		return code;
	}

	public String getCompressedQRCode(BufferedImage image) {
		String code = null;
		try {
			// vertical bottom scan
			BufferedImage procImage = image.getSubimage(150, image.getHeight() / 2, image.getWidth() - 150, image.getHeight() / 2 - 200);
			code = decode(procImage);
		} catch (RasterFormatException e) {
			// continue
		}
		return code;
	}

	public String decode(BufferedImage image) {
		RenderingHints hints = getRenderingHints();
		float[] kernelData = null;
		BufferedImageOp op = null;
		BufferedImage procImage = null;
		LuminanceSource source = null;
		BinaryBitmap bitmap = null;
		QRCodeReader reader = new QRCodeReader();
		Result result = null;
		String code = null;

		for (int denom = 10; denom <= 50; denom += 10) {
			try {
				procImage = image;
				float factor = (1.0f / ((float) denom));
				kernelData = getKernelData(factor);
				op = new ConvolveOp(new Kernel(4, 4, kernelData), ConvolveOp.EDGE_NO_OP, hints);
				source = new BufferedImageLuminanceSource(op.filter(procImage, null));
				bitmap = new BinaryBitmap(new HybridBinarizer(source));
				result = reader.decode(bitmap);
				code = result.getText();
				break;
			} catch (NotFoundException e) {
				// continue
			} catch (ChecksumException e) {
				// continue
			} catch (FormatException e) {
				// continue
			} finally {
				hints = null;
				kernelData = null;
				op = null;
				source = null;
				bitmap = null;
				procImage = null;
				result = null;
			}
		}
		return code;
	}

	protected RenderingHints getRenderingHints() {
		Map<Key, Object> map = new HashMap<Key, Object>();
		map.put(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
		map.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
		map.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		RenderingHints hints = new RenderingHints(map);
		return hints;
	}

	protected float[] getKernelData(float data) {
		return new float[] { data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data };
	}
}

Reading QR code within PDF file

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Hashtable;
import java.util.Vector;

import javax.activation.DataSource;
import javax.mail.util.ByteArrayDataSource;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.rendering.PDFRenderer;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.LuminanceSource;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.NotFoundException;
import com.google.zxing.Result;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.common.HybridBinarizer;

	private String scanQRCode() {

		// Hints for scanning
		Vector<BarcodeFormat> decodeFormat = new Vector<BarcodeFormat>();
		decodeFormat.add(BarcodeFormat.QR_CODE);

		Hashtable<DecodeHintType, Object> hintMap = new Hashtable<DecodeHintType, Object>();
		hintMap.put(DecodeHintType.TRY_HARDER, true);
		hintMap.put(DecodeHintType.POSSIBLE_FORMATS, decodeFormat);

		MultiFormatReader qrcodeReader = new MultiFormatReader();
		qrcodeReader.setHints(hintMap);

		try {
			// Try lowest DPI first.
			// BufferedImage pageImage = getPageImage(pageIndex, dpiSettings[i]);
			BufferedImage pageImage = getPageImage();
			LuminanceSource source = new BufferedImageLuminanceSource(pageImage);
			BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
			// By using decodeWithState, we keep the Hints that we set earlier.
			Result result = qrcodeReader.decodeWithState(bitmap);
			String text = result.getText();
			return text;
		} catch (IOException e) {
			e.printStackTrace();
		} catch (NotFoundException e) {
			e.printStackTrace();
		}
		// This should never happen, ever...
		return null;
	}

	private BufferedImage getPageImage() throws IOException {		
		Path docPath = Paths.get("C:\\NS2\\test_files\\java3.pdf");		
		PDDocument pdfDoc = PDDocument.load(docPath.toFile());
		PDFRenderer renderer = new PDFRenderer(pdfDoc);
		// renderImageWithDPI(page number, image size, format)
		BufferedImage image = renderer.renderImageWithDPI(0, 150, ImageType.BINARY); // entire page info
		pdfDoc.close();
		return image;
	}

Scan QR code in PDF

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Vector;

import javax.imageio.ImageIO;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.rendering.PDFRenderer;

import com.google.zxing.qrcode.QRCodeReader;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.EncodeHintType;
import com.google.zxing.LuminanceSource;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.NotFoundException;
import com.google.zxing.Result;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.ns.support.QrPdf;

public class My20190205QrCodeTest {

	private static String path = "C:\\NS2\\test_files\\520044839973-ARV.pdf";//

	public static void main(String[] args) {

		My20190205QrCodeTest a = new My20190205QrCodeTest();
		try {
			a.testPdf();
		} catch (Exception e) {
			e.printStackTrace();
		}
		System.out.println("---------------- END ------------------");
	}

	private void testPdf() {
		try {
			String line = scanQRCode(1);
			System.out.println("---------------- test7 result:::" + line);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	private String scanQRCode(int pageIndex) {

		// Hints for scanning
		Vector<BarcodeFormat> decodeFormat = new Vector<BarcodeFormat>();
		decodeFormat.add(BarcodeFormat.QR_CODE);

		Hashtable<DecodeHintType, Object> hintMap = new Hashtable<DecodeHintType, Object>();
		hintMap.put(DecodeHintType.TRY_HARDER, true);
		hintMap.put(DecodeHintType.POSSIBLE_FORMATS, decodeFormat);

		MultiFormatReader qrcodeReader = new MultiFormatReader();
		qrcodeReader.setHints(hintMap);

		try {
			// Try lowest DPI first.
			BufferedImage pageImage = getPageImage();
			LuminanceSource source = new BufferedImageLuminanceSource(pageImage);
			BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
			// By using decodeWithState, we keep the Hints that we set earlier.
			Result result = qrcodeReader.decodeWithState(bitmap);
			String text = result.getText();
			// System.out.println(" -- text:::" + text);
			return text;
		} catch (IOException e) {
			e.printStackTrace();
		} catch (NotFoundException e) {
			e.printStackTrace();

		}
		// This should never happen, ever...
		return null;
	}

	private BufferedImage getPageImage() throws IOException {
		Path docPath = Paths.get(path);
		PDDocument pdfDoc = PDDocument.load(docPath.toFile());
		PDFRenderer renderer = new PDFRenderer(pdfDoc);
		// renderImageWithDPI(page number, image size, format)
		BufferedImage image = renderer.renderImageWithDPI(0, 150, ImageType.BINARY); // entire page info
		// BufferedImage image = renderer.renderImage(0);
		pdfDoc.close();
		return image;
	}
}

LISTAGG vs XMLAGG

LISTAGG gives “java.sql.SQLException: ORA-01489: result of string concatenation is too long” due to limitation for VARCHAR2.

select
  CONCAT(CONCAT(t2.REF_NUM_TYPE,':'), (listagg(t2.REF_NUM,',') within group (order by t2.REF_NUM asc))) as REF_NUMS_BK
from
(
	select
		max(s.PIPELINE_TX_ID) as PIPELINE_TX_ID,
		rn.ref_num_type,
		rn.ref_num
	from 
		reference_numbers rn, 
		ouk_shipment_activity_cmpny s 
	where 1=1
	and rn.pipeline_tx_id = s.pipeline_tx_id
	and s.PIPELINE_TX_ID = '123132123123'
	group by
		rn.ref_num_type,
		rn.ref_num
	order by
		rn.ref_num_type,
		rn.ref_num
) t2
where 1=1
group by
  t2.ref_num_type

Therefore, XMLELEMENT can be workaround.

select
  CONCAT(CONCAT(t2.REF_NUM_TYPE,':'),(RTRIM(XMLAGG(XMLELEMENT(e,t2.REF_NUM,',').EXTRACT('//text()')).GetClobVal(),','))) AS REF_NUMS
from
(
	select
		max(s.PIPELINE_TX_ID) as PIPELINE_TX_ID,
		rn.ref_num_type,
		rn.ref_num
	from 
		reference_numbers rn, 
		ouk_shipment_activity_cmpny s 
	where 1=1
	and rn.pipeline_tx_id = s.pipeline_tx_id
	and s.PIPELINE_TX_ID = '123132123123'
	group by
		rn.ref_num_type,
		rn.ref_num
	order by
		rn.ref_num_type,
		rn.ref_num
) t2
where 1=1
group by
  t2.ref_num_type

It can be trim as well.

select
 CONCAT(
  CONCAT(t2.REF_NUM_TYPE,':'),
   SUBSTR(
    (RTRIM(XMLAGG(XMLELEMENT(e,t2.REF_NUM,',').EXTRACT('//text()')).GetClobVal(),',')
   ),1,1000
  )
 ) AS REF_NUMS
from
(
	select
		max(s.PIPELINE_TX_ID) as PIPELINE_TX_ID,
		rn.ref_num_type,
		rn.ref_num
	from 
		reference_numbers rn, 
		ouk_shipment_activity_cmpny s 
	where 1=1
	and rn.pipeline_tx_id = s.pipeline_tx_id
	and s.PIPELINE_TX_ID = '30277174594' -- 202501494 202498201 30277174594(too long)
	group by
		rn.ref_num_type,
		rn.ref_num
	order by
		rn.ref_num_type,
		rn.ref_num
) t2
where 1=1
group by
  t2.ref_num_type

Example for XMLAGG with order by

with ref_base as (
    select 
     max(a.PIPELINE_TX_ID) as ppl
    ,a.REF_NUM_TYPE
    ,a.REF_NUM
    from REFERENCE_NUMBERS a where 1=1
    and a.PIPELINE_TX_ID = '30277174594'
    group by a.REF_NUM_TYPE, a.REF_NUM
    order by a.REF_NUM_TYPE, a.REF_NUM
)
select
(
    select RTRIM((XMLAGG(XMLELEMENT(e, b.REF_NUM,',') order by b.REF_NUM).EXTRACT('//text()')).GetClobVal(),',') AS REF_NUMS
    from   ref_base b where  b.REF_NUM_TYPE = 'ED1'
    group  by b.REF_NUM_TYPE
) as REF_NUMS_ED1
from dual

Example for LISTAGG with limited elements

select
  LISTAGG(
   case
      when rownum <= 300 
      then (
        case
           when rownum = 300
           then rn.ref_num || ' MORE....'
           else rn.ref_num
        end
      )
      else null
   end,
   ','
  ) within group (order by rn.ref_num)
  as ref_nums
from reference_numbers rn
where rn.pipeline_tx_id = '123456'

How To Work on GitHub

github-hdr-img1
This used to be my personal memo to work on GitHub (basic operation), but I also thought it’s good to share to others who might have the same (or similar) problem.

Summary:

  • Creating Repository
  • How to clone the repository
  • How to upload your resource
  • GitHub website to add a SSH key
  • How to generating a SSH key
  • How to delete repository

Optimizing SQL

night-job-img1
While you are sleeping, there are lots of programs are running based on it’s scheduling. They are often called “Batch Jobs“. And one of batch jobs is to get rid of old transactions.

In Biz apps, we often need to do performance tuning. According to my experience, the SQL is usually the biggest reason to cause a performance issue.

I have a memory that I have a performance issue for this SQL.
This is to get the target records for Data Purge (Oracle):

SELECT
*
FROM TABLE_TO_BE_PURGED A
WHERE
EXISTS ( 
    SELECT '*' 
    FROM  
          PURGE_TARGET_TABLE TGT
    WHERE 1=1
    AND  TGT.INV_NUM  = A.REF_TXT_01
) OR EXISTS ( 
    SELECT '*' 
    FROM 
          INTEREFACE_TABLE ITFC, 
    PURGE_TARGET_TABLE     TGT 
    WHERE 
         ITFC.REF_NUM     = B.REF_NUM
    AND  ITFC.REF_SUB_NUM = B.REF_SUB_NUM
    AND  ITFC.INV_NUM     = TGT.INV_NUM
) 

And came up with this after struggling hours…

SELECT
*
FROM TABLE_TO_BE_PURGED A1
WHERE EXISTS (
    SELECT '*'
    FROM (
        SELECT 
            B1.PURGED_PK
        FROM 
            TABLE_TO_BE_PURGED  B1
        ,   PURGE_TARGET_TABLE  TGT
        WHERE 1=1
        AND TGT.INV_NUM = B1.REF_TXT_01
        UNION
        SELECT 
            B2.PURGED_PK
        FROM 
            TABLE_TO_BE_PURGED  B2
        ,   INTEREFACE_TABLE    ITFC
        ,   PURGE_TARGET_TABLE  TGT
        WHERE 
            ITFC.REF_NUM     = B2.REF_NUM
        AND ITFC.REF_SUB_NUM = B2.REF_SUB_NUM
        AND ITFC.INV_NUM     = TGT.INV_NUM
    ) T1
    WHERE T1.PURGED_PK = A1.PURGED_PK
)

The performance improved dramatically, but the interesting thing was that the execution plan (cost) was pretty much the same. The one above get slower when having more records. And the one below was fast enough although having many records.