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