Vuo  2.3.2
VuoBarcode.cc
Go to the documentation of this file.
1 
10 #include "VuoBarcode.h"
11 
12 #include <OpenGL/CGLMacro.h>
13 
14 #include <zxing/common/GreyscaleLuminanceSource.h>
15 #include <zxing/common/HybridBinarizer.h>
16 #include <zxing/MultiFormatReader.h>
17 #include <zxing/ReaderException.h>
18 
19 #include "module.h"
20 
21 extern "C"
22 {
23 #ifdef VUO_COMPILER
25  "title" : "VuoBarcode",
26  "dependencies" : [
27  "VuoImage",
28  "VuoRectangle",
29  "VuoText",
30  "VuoList_VuoText",
31  "zxing"
32  ]
33  });
34 #endif
35 }
36 
37 using namespace zxing;
38 
45 VuoText VuoBarcode_read(VuoImage image, VuoInteger format, VuoText *outputFormat, VuoRectangle *outputPosition)
46 {
47  if (!image)
48  return NULL;
49 
50  // For full-color images, GL_LUMINANCE only returns the red channel,
51  // but that's typically good enough for barcode detection
52  // (and much faster than doing a CPU-side grayscale mix).
53  const unsigned char *luma = VuoImage_getBuffer(image, GL_LUMINANCE);
54  unsigned char *lumaFlipped = (unsigned char *)malloc(image->pixelsWide * image->pixelsHigh);
55  for (int y = 0; y < image->pixelsHigh; ++y)
56  memcpy(lumaFlipped + (image->pixelsHigh - y - 1) * image->pixelsWide, luma + y * image->pixelsWide, image->pixelsWide);
57 
58  try
59  {
60  ArrayRef<char> d((char *)lumaFlipped, image->pixelsWide * image->pixelsHigh);
61  Ref<GreyscaleLuminanceSource> source(new GreyscaleLuminanceSource(d, image->pixelsWide, image->pixelsHigh, 0, 0, image->pixelsWide, image->pixelsHigh));
62 // Ref<Binarizer> binarizer(new HybridBinarizer(source));
63  Ref<Binarizer> binarizer(new GlobalHistogramBinarizer(source));
64  Ref<BinaryBitmap> bir(new BinaryBitmap(binarizer));
65 
66  DecodeHints hints(DecodeHints::DEFAULT_HINT);
67 // hints.setTryHarder(true);
68 
69  if (format != 0)
70  {
71  hints.clear();
72  if (format == 10) hints.addFormat(BarcodeFormat::CODABAR);
73  else if (format == 20) hints.addFormat(BarcodeFormat::CODE_39);
74  else if (format == 30) hints.addFormat(BarcodeFormat::CODE_93);
75  else if (format == 40) hints.addFormat(BarcodeFormat::CODE_128);
76  else if (format == 50) hints.addFormat(BarcodeFormat::EAN_8);
77  else if (format == 60) hints.addFormat(BarcodeFormat::EAN_13);
78  else if (format == 70) hints.addFormat(BarcodeFormat::RSS_14);
79  else if (format == 80) hints.addFormat(BarcodeFormat::RSS_EXPANDED);
80  else if (format == 90) hints.addFormat(BarcodeFormat::ITF);
81  else if (format == 100) hints.addFormat(BarcodeFormat::UPC_A);
82  else if (format == 110) hints.addFormat(BarcodeFormat::UPC_E);
83  else if (format == 200) hints.addFormat(BarcodeFormat::AZTEC);
84  else if (format == 210) hints.addFormat(BarcodeFormat::DATA_MATRIX);
85  else if (format == 220) hints.addFormat(BarcodeFormat::MAXICODE);
86  else if (format == 230) hints.addFormat(BarcodeFormat::PDF_417);
87  else if (format == 240) hints.addFormat(BarcodeFormat::QR_CODE);
88  }
89 
90  MultiFormatReader reader;
92  Ref<Result> result = reader.decode(bir, hints);
93  Ref<String> s = result->getText();
94  if (outputPosition)
95  {
96  // ResultPoints may be 4 corners of the barcode, or 2 line segment endpoints.
97  // Turn them into a typical axis-aligned Vuo Coordinates center/size pair.
98  ArrayRef< Ref<ResultPoint> > points = result->getResultPoints();
99  bool first = true;
100  for (int i = 0; i < points->size(); ++i)
101  {
102  VuoRectangle r = VuoRectangle_make( points[i]->getX()/(image->pixelsWide/2) - 1,
103  (image->pixelsHigh/2 - points[i]->getY())/(image->pixelsWide/2),
104  0, 0);
105  if (first)
106  {
107  first = false;
108  *outputPosition = r;
109  }
110  else
111  *outputPosition = VuoRectangle_union(*outputPosition, r);
112  }
113  }
114  free(lumaFlipped);
115 
116  int actualFormat = result->getBarcodeFormat().value;
117  if (actualFormat == BarcodeFormat::CODABAR) *outputFormat = VuoText_make("Codabar");
118  else if (actualFormat == BarcodeFormat::CODE_39) *outputFormat = VuoText_make("Code 39");
119  else if (actualFormat == BarcodeFormat::CODE_93) *outputFormat = VuoText_make("Code 93");
120  else if (actualFormat == BarcodeFormat::CODE_128) *outputFormat = VuoText_make("Code 128");
121  else if (actualFormat == BarcodeFormat::EAN_8) *outputFormat = VuoText_make("EAN-8");
122  else if (actualFormat == BarcodeFormat::EAN_13) *outputFormat = VuoText_make("EAN-13");
123  else if (actualFormat == BarcodeFormat::RSS_14) *outputFormat = VuoText_make("GS1 DataBar-14 (RSS-14)");
124  else if (actualFormat == BarcodeFormat::RSS_EXPANDED) *outputFormat = VuoText_make("GS1 DataBar Expanded (RSS Expanded)");
125  else if (actualFormat == BarcodeFormat::ITF) *outputFormat = VuoText_make("Interleaved 2 of 5 (ITF)");
126  else if (actualFormat == BarcodeFormat::UPC_A) *outputFormat = VuoText_make("UPC-A");
127  else if (actualFormat == BarcodeFormat::UPC_E) *outputFormat = VuoText_make("UPC-E");
128  else if (actualFormat == BarcodeFormat::AZTEC) *outputFormat = VuoText_make("Aztec");
129  else if (actualFormat == BarcodeFormat::DATA_MATRIX) *outputFormat = VuoText_make("Data Matrix");
130  else if (actualFormat == BarcodeFormat::MAXICODE) *outputFormat = VuoText_make("MaxiCode");
131  else if (actualFormat == BarcodeFormat::PDF_417) *outputFormat = VuoText_make("PDF417");
132  else if (actualFormat == BarcodeFormat::QR_CODE) *outputFormat = VuoText_make("QR Code");
133  else *outputFormat = VuoText_make("(unknown)");
134 
135  unsigned long len = s->length();
136  char *outputText = (char *)malloc(len+1);
137  for(int i = 0; i < len; ++i)
138  outputText[i] = s->charAt(i);
139  outputText[len] = 0;
140  VuoRegister(outputText, free);
141  return outputText;
142  }
143  catch (Exception e)
144  {
145  // Why does zxing throw an exception for the perfectly normal no-code-detected situation.
146  if (strcmp(e.what(), "No code detected"))
147  VDebugLog("Exception: %s", e.what());
148  }
149 
150  free(lumaFlipped);
151  return NULL;
152 }