// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.sps;

import com.google.auto.value.AutoValue;

import com.google.common.io.ByteSource;

// Import the ZXing barcode image processing library.
import com.google.zxing.BinaryBitmap;
import com.google.zxing.ChecksumException;
import com.google.zxing.FormatException;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.NotFoundException;
import com.google.zxing.Reader;
import com.google.zxing.Result;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.common.HybridBinarizer;

import javax.imageio.ImageIO;

import java.awt.image.BufferedImage;

import java.io.IOException;
import java.io.InputStream;

/**
 * For a barcode image, detects the code, using the Java Apache Camel 
 * Barcode API based on the ZXing library, and returns it.
 */
public class BarcodeImageDetector {
  
  public String detect(byte[] imageBytes) throws PhotoDetectionException {
    // Convert byte array to InputStream.
    InputStream imageInputStream;
    try {
      imageInputStream = ByteSource.wrap(imageBytes).openStream();
    } catch (IOException exception) {
      throw new PhotoDetectionException("Failed to convert byte array to InputStream.", exception);
    }
    
    BufferedImage bufferedImage;
    try {
      bufferedImage = ImageIO.read(imageInputStream);
    } catch (IOException e) {
      throw new PhotoDetectionException("Failed to convert InputStream to BufferedImage.", e);
    }

    BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(
        new BufferedImageLuminanceSource(bufferedImage)));
    

    if (bitmap.getWidth() < bitmap.getHeight()) {
      if (bitmap.isRotateSupported()) {
        bitmap = bitmap.rotateCounterClockwise();
      }
    }
    return decode(bitmap).getText();
  }
  
  /** */
  private BarcodeInfo decode(BinaryBitmap bitmap) throws PhotoDetectionException {
    Reader reader = new MultiFormatReader();
    Result result;
    try {
      result = reader.decode(bitmap);
    } catch (NotFoundException e) {
      // No potential barcode is found.
      throw new PhotoDetectionException("No potential barcode found.", e);
    } catch (ChecksumException e) {
      // A potential barcode is found but does not pass its checksum.
      throw new PhotoDetectionException("Potential barcode does not pass its checksum.", e);
    } catch (FormatException e) {
      // A potential barcode is found but format is invalid.
      throw new PhotoDetectionException("Invalid format for potential barcode.", e);
    }
      
    return BarcodeInfo.create(result.getText(), result.getBarcodeFormat().toString());
  }
  
  /**
   * Nested class
   */
  @AutoValue
  public static abstract class BarcodeInfo {

    public static BarcodeInfo create(String text, String format) {
      return new AutoValue_BarcodeImageDetector_BarcodeInfo(text, format);
    }

    public abstract String getText();
    public abstract String getFormat();
  }
}

@@ -1548,18 +1548,116 @@
 utStream
+ by wrapping the byte array into the Guava ByteSource,%0A    // which then allows getting the stream
 .%0A
-
     Inpu
@@ -1904,24 +1904,96 @@
 %0A    %7D%0A    %0A
+    // Get the BufferedImage as the result of decoding the InputStream.%0A
     Buffered
@@ -2205,24 +2205,322 @@
  e);%0A    %7D%0A%0A
+    // ZXing Reader objects accept a BinaryBitmap and attempt to decode it, therefore%0A    // construct the BinaryBitmap object based on the %7B@code bufferedImage%7D.%0A    // The ZXing HybridBinarizer class is designed for high frequency images of barcodes %0A    // with black data on white backgrounds.%0A
     BinaryBi
@@ -2635,17 +2635,52 @@
 );%0A    %0A
+    // If needed, rotate the image.
 %0A
-
     if (
@@ -2821,24 +2821,25 @@
     %7D%0A    %7D%0A
+%0A
     return d
@@ -2874,17 +2874,8 @@
 %0A  %0A
-  /** */%0A
   pr
@@ -3706,38 +3706,8 @@
 %0A  %0A
-  /**%0A   * Nested class%0A   */%0A
   @A
@@ -3760,16 +3760,20 @@
 eInfo %7B%0A
+    
 %0A    pub

Update comments