title: How to generate Image Histogram in Android?
body: <p>I tried to generate histogram of Image using following code,<br/><br/></p>
  
  <pre><code>package com.example.viewfinderee368;
  
  import java.nio.ByteBuffer;
  
  import android.annotation.SuppressLint;
  import android.app.Activity;
  import android.content.Context;
  import android.graphics.Bitmap;
  import android.graphics.Canvas;
  import android.graphics.Color;
  import android.graphics.Paint;
  import android.graphics.RectF;
  import android.graphics.drawable.BitmapDrawable;
  import android.os.Bundle;
  import android.view.View;
  import android.widget.ImageView;
  import android.widget.LinearLayout;
  
  @SuppressLint("DrawAllocation")
  public class HistogramDemo extends Activity {
  
      Bitmap mainImage;
      Bitmap histroImage;
  
      ImageView mainImageView;
      LinearLayout histroImageView;
  
      private DrawOnTop mDrawOnTop;
  
      @Override
      protected void onCreate(Bundle savedInstanceState) {
          // TODO Auto-generated method stub
          super.onCreate(savedInstanceState);
          setContentView(R.layout.histrogram);
  
          mainImageView = (ImageView) findViewById(R.id.img);
          histroImageView = (LinearLayout) findViewById(R.id.histroImg);
  
          mainImage = ((BitmapDrawable) mainImageView.getDrawable()).getBitmap();
          histroImage = Bitmap.createBitmap(mainImage);
  
          mDrawOnTop = new DrawOnTop(this);
  
            mDrawOnTop.mImageWidth = mainImage.getWidth();
            mDrawOnTop.mImageHeight = mainImage.getHeight();
            mDrawOnTop.mBitmap = Bitmap.createBitmap(mDrawOnTop.mImageWidth, 
                    mDrawOnTop.mImageHeight, Bitmap.Config.RGB_565);
            mDrawOnTop.mRGBData = new int[mDrawOnTop.mImageWidth * mDrawOnTop.mImageHeight]; 
  
            int bytes = mainImage.getByteCount();
            //or we can calculate bytes this way. Use a different value than 4 if you don't use 32bit images.
            //int bytes = b.getWidth()*b.getHeight()*4; 
  
              ByteBuffer buffer = ByteBuffer.allocate(bytes); //Create a new buffer
              mainImage.copyPixelsToBuffer(buffer); //Move the byte data to the buffer
  
  
              byte[] array = buffer.array();
            mDrawOnTop.mYUVData =array;  
  
            System.arraycopy(array, 0, mDrawOnTop.mYUVData, 0, array.length);
  //        mDrawOnTop.invalidate();
            histroImageView.addView(mDrawOnTop);
  
      }
  
      class DrawOnTop extends View {
          Bitmap mBitmap;
          Paint mPaintBlack;
          Paint mPaintYellow;
          Paint mPaintRed;
          Paint mPaintGreen;
          Paint mPaintBlue;
          Paint mPaintGray;
  
          byte[] mYUVData;
          int[] mRGBData;
          int mImageWidth, mImageHeight;
          int[] mRedHistogram;
          int[] mGreenHistogram;
          int[] mBlueHistogram;
          double[] mBinSquared;
  
          private DrawOnTop(Context context) {
              super(context);
  
              mPaintBlack = new Paint();
              mPaintBlack.setStyle(Paint.Style.FILL);
              mPaintBlack.setColor(Color.BLACK);
              mPaintBlack.setTextSize(25);
  
              mPaintYellow = new Paint();
              mPaintYellow.setStyle(Paint.Style.FILL);
              mPaintYellow.setColor(Color.YELLOW);
              mPaintYellow.setTextSize(25);
  
              mPaintRed = new Paint();
              mPaintRed.setStyle(Paint.Style.FILL);
              mPaintRed.setColor(Color.RED);
              mPaintRed.setTextSize(25);
  
              mPaintGreen = new Paint();
              mPaintGreen.setStyle(Paint.Style.FILL);
              mPaintGreen.setColor(Color.GREEN);
              mPaintGreen.setTextSize(25);
  
              mPaintBlue = new Paint();
              mPaintBlue.setStyle(Paint.Style.FILL);
              mPaintBlue.setColor(Color.BLUE);
              mPaintBlue.setTextSize(25);
  
              mPaintGray = new Paint();
              mPaintGray.setStyle(Paint.Style.FILL);
              mPaintGray.setColor(Color.GRAY);
              mPaintGray.setTextSize(25);
  
  
              mBitmap = null;
              mYUVData = null;
              mRGBData = null;
              mRedHistogram = new int[256];
              mGreenHistogram = new int[256];
              mBlueHistogram = new int[256];
              mBinSquared = new double[256];
              for (int bin = 0; bin &lt; 256; bin++)
              {
                  mBinSquared[bin] = ((double)bin) * bin;
              } // bin
          }
          @Override
          protected void onDraw(Canvas canvas) {
              if (mBitmap != null)
              {
                  canvas.drawColor(Color.WHITE);
  
                  int canvasWidth = 255;
                  int canvasHeight =255;
                  int newImageWidth = canvasWidth;
                  int newImageHeight = canvasHeight;
                  int marginWidth = (canvasWidth - newImageWidth)/2;
  
                  // Convert from YUV to RGB
                  decodeYUV420SP(mRGBData, mYUVData, mImageWidth, mImageHeight);
  
                  // Draw bitmap
                  mBitmap.setPixels(mRGBData, 0, mImageWidth, 0, 0, 
                          mImageWidth, mImageHeight);
  
                  // Draw black borders                       
                  canvas.drawRect(0, 0, marginWidth, canvasHeight, mPaintBlack);
                  canvas.drawRect(canvasWidth - marginWidth, 0, 
                          canvasWidth, canvasHeight, mPaintBlack);
  
                  // Calculate histogram
                  calculateIntensityHistogram(mRGBData, mRedHistogram, 
                          mImageWidth, mImageHeight, 0);
                  calculateIntensityHistogram(mRGBData, mGreenHistogram, 
                          mImageWidth, mImageHeight, 1);
                  calculateIntensityHistogram(mRGBData, mBlueHistogram, 
                          mImageWidth, mImageHeight, 2);
  
                  // Calculate mean
                  double imageRedMean = 0, imageGreenMean = 0, imageBlueMean = 0;
                  double redHistogramSum = 0, greenHistogramSum = 0, blueHistogramSum = 0;
  
                      for (int bin = 0; bin &lt; 256; bin++)
                  {
                      imageRedMean += mRedHistogram[bin] * bin;
                      redHistogramSum += mRedHistogram[bin];
                      imageGreenMean += mGreenHistogram[bin] * bin;
                      greenHistogramSum += mGreenHistogram[bin];
                      imageBlueMean += mBlueHistogram[bin] * bin;
                      blueHistogramSum += mBlueHistogram[bin];
                  } // bin
                  imageRedMean /= redHistogramSum;
                  imageGreenMean /= greenHistogramSum;
                  imageBlueMean /= blueHistogramSum;
  
                  // Draw red intensity histogram
                  float barMaxHeight = 5000;
                  float barWidth = ((float)newImageWidth) / 256;
                  float barMarginHeight = 2;
                  RectF barRect = new RectF();
                  barRect.bottom = canvasHeight -50 ;
                  barRect.left = marginWidth;
                  barRect.right = barRect.left + barWidth;
                  for (int bin = 0; bin &lt; 255; bin++)
                  {
                      float prob = (float)mRedHistogram[bin] / (float)redHistogramSum;
                      barRect.top = barRect.bottom - 
                          Math.min(100,prob*barMaxHeight) - barMarginHeight;
                      canvas.drawRect(barRect, mPaintBlack);
                      barRect.top += barMarginHeight;
                      canvas.drawRect(barRect, mPaintGray);
                      barRect.left += barWidth;
                      barRect.right += barWidth;
                  } // bin
  
                  // Draw green intensity histogram
                  barRect.bottom = canvasHeight -50 ;
                  barRect.left = marginWidth;
                  barRect.right = barRect.left + barWidth;
                  for (int bin = 0; bin &lt; 255; bin++)
                  {
                      barRect.top = barRect.bottom - Math.min(100, ((float)mGreenHistogram[bin])/((float)greenHistogramSum) * barMaxHeight) - barMarginHeight;
                      canvas.drawRect(barRect, mPaintBlack);
                      barRect.top += barMarginHeight;
                      canvas.drawRect(barRect, mPaintGray);
                      barRect.left += barWidth;
                      barRect.right += barWidth;
                  } // bin
  
                  // Draw blue intensity histogram
                  barRect.bottom = canvasHeight -50 ;
                  barRect.left = marginWidth;
                  barRect.right = barRect.left + barWidth;
                  for (int bin = 0; bin &lt; 255; bin++)
                  {
                      barRect.top = barRect.bottom - Math.min(100, ((float)mBlueHistogram[bin])/((float)blueHistogramSum) * barMaxHeight) - barMarginHeight;
                      canvas.drawRect(barRect, mPaintBlack);
                      barRect.top += barMarginHeight;
                      canvas.drawRect(barRect, mPaintGray);
                      barRect.left += barWidth;
                      barRect.right += barWidth;
                  } // bin
              } // end if statement
  
              super.onDraw(canvas);
  
          }
  
          private void decodeYUV420SP(int[] rgb, byte[] yuv420sp, int width, int height) {
              final int frameSize = width * height;
  
              for (int j = 0, yp = 0; j &lt; height; j++) {
                  int uvp = frameSize + (j &gt;&gt; 1) * width, u = 0, v = 0;
                  for (int i = 0; i &lt; width; i++, yp++) {
                      int y = (0xff &amp; ((int) yuv420sp[yp])) - 16;
                      if (y &lt; 0) y = 0;
                      if ((i &amp; 1) == 0) {
                          v = (0xff &amp; yuv420sp[uvp++]) - 128;
                          u = (0xff &amp; yuv420sp[uvp++]) - 128;
                      }
  
                      int y1192 = 1192 * y;
                      int r = (y1192 + 1634 * v);
                      int g = (y1192 - 833 * v - 400 * u);
                      int b = (y1192 + 2066 * u);
  
                      if (r &lt; 0) r = 0; else if (r &gt; 262143) r = 262143;
                      if (g &lt; 0) g = 0; else if (g &gt; 262143) g = 262143;
                      if (b &lt; 0) b = 0; else if (b &gt; 262143) b = 262143;
  
                      rgb[yp] = 0xff000000 | ((r &lt;&lt; 6) &amp; 0xff0000) | ((g &gt;&gt; 2) &amp; 0xff00) | ((b &gt;&gt; 10) &amp; 0xff);
                  }
              }
          }
  
  
          private void calculateIntensityHistogram(int[] rgb, int[] histogram, int width, int height, int component)
          {
              for (int bin = 0; bin &lt; 256; bin++)
              {
                  histogram[bin] = 0;
              } // bin
              if (component == 0) // red
              {
                  for (int pix = 0; pix &lt; width*height; pix += 3)
                  {
                      int pixVal = (rgb[pix] &gt;&gt; 16) &amp; 0xff;
                      histogram[ pixVal ]++;
                  } // pix
              }
              else if (component == 1) // green
              {
                  for (int pix = 0; pix &lt; width*height; pix += 3)
                  {
                      int pixVal = (rgb[pix] &gt;&gt; 8) &amp; 0xff;
                      histogram[ pixVal ]++;
                  } // pix
              }
              else // blue
              {
                  for (int pix = 0; pix &lt; width*height; pix += 3)
                  {
                      int pixVal = rgb[pix] &amp; 0xff;
                      histogram[ pixVal ]++;
                  } // pix
              }
          }
      } 
  }
  </code></pre>
  
  <p><br/> <br/>
  But its not generating reliable histogram, I need to generate same histogram as in Adobe Photoshop. <br/> In <strong>ios</strong> its generating same histogram as in Adobe Photoshop using following code.<br/></p>
  
  <pre><code> -(void)readImage:(UIImage*)image
  {
      CGImageRef imageRef = [image CGImage];
      NSUInteger width = CGImageGetWidth(imageRef);
      NSUInteger height = CGImageGetHeight(imageRef);
  //    NSLog(@"histogram width:- %d",width);
  //    NSLog(@"histogram height:- %d",height);
      CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
      unsigned char *rawData = (unsigned char*) calloc(height * width * 4, sizeof(unsigned char));
      NSUInteger bytesPerPixel = 4;
      NSUInteger bytesPerRow = bytesPerPixel * width;
      NSUInteger bitsPerComponent = 8;
      CGContextRef context = CGBitmapContextCreate(rawData, width, height, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
      CGColorSpaceRelease(colorSpace);
      CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
      CGContextRelease(context);
  
      for (int yy=0;yy&lt;height; yy++)
      {
          for (int xx=0; xx&lt;width; xx++)
          {
              // Now your rawData contains the image data in the RGBA8888 pixel format.
              int byteIndex = (bytesPerRow * yy) + xx * bytesPerPixel;
              for (int ii = 0 ; ii &lt; 1 ; ++ii)
              {
                  CGFloat red   = (rawData[byteIndex]     * 1.0) ;
                  CGFloat green = (rawData[byteIndex + 1] * 1.0) ;
                  CGFloat blue  = (rawData[byteIndex + 2] * 1.0) ;
                  // CGFloat alpha = (rawData[byteIndex + 3] * 1.0) / 255.0;
                  byteIndex += 4;
  
                  // TYPE CASTING ABOVE FLOAT VALUES TO THAT THEY CAN BE MATCHED WITH ARRAY'S INDEX.
  
                  int redValue = (int)red;
                  int greenValue = (int)green;
                  int blueValue = (int)blue;
  
  
                  // THESE COUNTERS COUNT " TOTAL NUMBER OF PIXELS " FOR THAT  Red , Green or Blue Value IN ENTIRE IMAGE.
  
                  fltR[redValue]++;
                  fltG[greenValue]++;
                  fltB[blueValue]++;
              }
          }
      }
      [self makeArrays];
  
  
  //    for (int yy=0;yy&lt;height; yy++)
  //    {
  //        for (int xx=0; xx&lt;width; xx++)
  //        {
  //            int byteIndex = (bytesPerRow * yy) + xx * bytesPerPixel;
  //            rawData [byteIndex] = nil;
  //        }
  //    }
  //    rawData = 0;
  //    rawData = nil;
      static unsigned updateCounter = 0;
      memset(rawData, updateCounter &amp; 0xff, width*height*4);
      free(rawData);
      rawData = NULL;
  
      for(int i=0;i&lt;=255;i++){
          fltR[i]=0;
          fltG[i]=0;
          fltB[i]=0;
      }
      colorSpace = nil;
  }
  
  -(void)makeArrays
  {
      float max=0;
      int maxR=0;
      int maxG=0;
      int maxB=0;
  
  
  
      // PERFORMING SUMMESION OF ALL RED , GREEN AND BLUE VLAUES GRADUALLY TO TAKE AVERAGE OF THEM
  //    NSLog(@"makeArray :- ,fltR[i]  = %f ,fltG[i]  = %f ,fltB[i] = %f",fltR[i],fltG[i],fltB[i])
      for (int i=0; i&lt;=255; i++)
      {
  //        NSLog(@"makeArray :- ,fltR[i]  = %f ,fltG[i]  = %f ,fltB[i] = %f",fltR[i],fltG[i],fltB[i]);
          maxR += fltR[i];
          maxG += fltG[i];
          maxB += fltB[i];
      }
  
  
      // CALCULATING AVERAGE OF ALL red, green and blue values.
      maxR = maxR/255;
      maxG = maxG/255;
      maxB = maxB/255;
  
  
      // As  I AM GENERATING 3 GRAPHS , ITS COMPULSARY TO KEEP THEM ON SCREEN SO TAKING THEIR AVERAGE.
      max = (maxR+maxG+maxB)/3;
  
      // DEVIDED BY 8 TO GET GRAPH OF THE SAME SIZE AS ITS IN PREVIEW
      max = max*2.5;
      arrAllPoints = [[NSMutableArray alloc] init];
      for (int i=0; i&lt;=255; i++)
      {
          ClsDrawPoint *objPoint = [[ClsDrawPoint alloc] init];
          objPoint.x = i;
          objPoint.y = fltR[i]*scale/max;
          [arrAllPoints addObject:objPoint];
      }
  
      redGraphView.arrRedPoints = arrAllPoints;
  //    redGraphView.graphColor = [UIColor redColor];
      redGraphView.graphColor = [UIColor whiteColor];
      [redGraphView drawGraphForArray:arrAllPoints];       /* redGraphView is an object of ClsDraw (custom class of UIView) and this call drws graph from the points of arrAllPoints */
  
      arrAllPoints = [[NSMutableArray alloc] init];
  
      for (int i=0; i&lt;=255; i++)
      {
          ClsDrawPoint *objPoint = [[ClsDrawPoint alloc] init];
          objPoint.x = i;
          objPoint.y = fltG[i]*scale/max;
          [arrAllPoints addObject:objPoint];
      }
  
      greenGraphView.arrRedPoints = arrAllPoints;
  //    greenGraphView.graphColor = [UIColor greenColor];
      greenGraphView.graphColor = [UIColor whiteColor];
      [greenGraphView drawGraphForArray:arrAllPoints];         /* greenGraphView is an object of ClsDraw (custom class of UIView) and this call drws graph from the points of arrAllPoints */
  
      arrAllPoints = [[NSMutableArray alloc] init];
  
      for (int i=0; i&lt;=255; i++)
      {
          ClsDrawPoint *objPoint = [[ClsDrawPoint alloc] init];
          objPoint.x = i;
          objPoint.y = fltB[i]*scale/max;
          [arrAllPoints addObject:objPoint];
      }
      blueGraphView.arrRedPoints = arrAllPoints;
  //    blueGraphView.graphColor = [UIColor blueColor];
      blueGraphView.graphColor = [UIColor whiteColor];
      [blueGraphView drawGraphForArray:arrAllPoints];         /* blueGraphView is an object of ClsDraw (custom class of UIView) and this call drws graph from the points of arrAllPoints */
  
  
      // THE COORDINATE SYSTEM OF IOS IS TOTALLY OPPOSITE TO THAT OF THE MAC'S SO ROTATED IT WITH REFERENCE TO X - axis.
      blueGraphView.layer.transform = CATransform3DMakeRotation(M_PI, 1.0,0.0, 0.0);
      redGraphView.layer.transform = CATransform3DMakeRotation(M_PI, 1.0,0.0, 0.0);
      greenGraphView.layer.transform = CATransform3DMakeRotation(M_PI, 1.0,0.0, 0.0);
  }
  </code></pre>
  
  <p>I tried to find Adobe Photoshop android api for it but i didn't find. Is there other api to develop histogram app?</p>
  
  <p><br/><br/>
  Thanks, </p>