15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
25d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// found in the LICENSE file.
45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <stdio.h>
65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <stdlib.h>
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <string.h>
85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#if defined(WIN32)
105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <fcntl.h>
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <io.h>
125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)enum Commands {
155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CROP_PIXELS = 0,
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  HISTOGRAM = 1,
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  BOUNDING_BOX = 2
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool ReadInt(int* out) {
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return fread(out, sizeof(*out), 1, stdin) == 1;
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void WriteResponse(void* data, int size) {
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  fwrite(&size, sizeof(size), 1, stdout);
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  fwrite(data, size, 1, stdout);
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  fflush(stdout);
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)struct Box {
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Box() : left(), top(), right(), bottom() {}
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Expected input is:
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // left, top, width, height
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool Read() {
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int width;
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int height;
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!(ReadInt(&left) && ReadInt(&top) &&
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          ReadInt(&width) && ReadInt(&height))) {
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      fprintf(stderr, "Could not parse Box.\n");
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return false;
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (left < 0 || top < 0 || width < 0 || height < 0) {
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      fprintf(stderr, "Box dimensions must be non-negative.\n");
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return false;
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    right = left + width;
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bottom = top + height;
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return true;
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void Union(int x, int y) {
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (left > x) left = x;
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (right <= x) right = x + 1;
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (top > y) top = y;
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (bottom <= y) bottom = y + 1;
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int width() const { return right - left; }
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int height() const { return bottom - top; }
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int left;
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int top;
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int right;
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int bottom;
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Represents a bitmap buffer with a crop box.
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)struct Bitmap {
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Bitmap() : pixels(NULL) {}
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ~Bitmap() {
745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (pixels)
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      delete[] pixels;
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Expected input is:
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // bpp, width, height, box, pixels
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool Read() {
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int bpp;
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int width;
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int height;
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!(ReadInt(&bpp) && ReadInt(&width) && ReadInt(&height))) {
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      fprintf(stderr, "Could not parse Bitmap initializer.\n");
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return false;
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (bpp <= 0 || width <= 0 || height <= 0) {
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      fprintf(stderr, "Dimensions must be positive.\n");
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return false;
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int size = width * height * bpp;
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    row_stride = width * bpp;
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    pixel_stride = bpp;
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    total_size = size;
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    row_size = row_stride;
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!box.Read()) {
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      fprintf(stderr, "Expected crop box argument not found.\n");
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return false;
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (box.bottom * row_stride > total_size ||
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        box.right * pixel_stride > row_size) {
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      fprintf(stderr, "Crop box overflows the bitmap.\n");
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return false;
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    pixels = new unsigned char[size];
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (fread(pixels, sizeof(pixels[0]), size, stdin) <
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        static_cast<size_t>(size)) {
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      fprintf(stderr, "Not enough pixels found,\n");
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return false;
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    total_size = (box.bottom - box.top) * row_stride;
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    row_size = (box.right - box.left) * pixel_stride;
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    data = pixels + box.top * row_stride + box.left * pixel_stride;
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return true;
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void WriteCroppedPixels() const {
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int out_size = row_size * box.height();
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    unsigned char* out = new unsigned char[out_size];
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    unsigned char* dst = out;
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    for (const unsigned char* row = data;
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        row < data + total_size;
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        row += row_stride, dst += row_size) {
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // No change in pixel_stride, so we can copy whole rows.
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      memcpy(dst, row, row_size);
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    WriteResponse(out, out_size);
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    delete[] out;
1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  unsigned char* pixels;
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Box box;
1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Points at the top-left pixel in |pixels|.
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const unsigned char* data;
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // These counts are in bytes.
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int row_stride;
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int pixel_stride;
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int total_size;
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int row_size;
1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)static inline
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool PixelsEqual(const unsigned char* pixel1, const unsigned char* pixel2,
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 int tolerance) {
1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Note: this works for both RGB and RGBA. Alpha channel is ignored.
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return (abs(pixel1[0] - pixel2[0]) <= tolerance) &&
1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)         (abs(pixel1[1] - pixel2[1]) <= tolerance) &&
1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)         (abs(pixel1[2] - pixel2[2]) <= tolerance);
1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)static inline
1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool PixelsEqual(const unsigned char* pixel, int color, int tolerance) {
1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  unsigned char pixel2[3] = { color >> 16, color >> 8, color };
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return PixelsEqual(pixel, pixel2, tolerance);
1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)static
1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool Histogram(const Bitmap& bmp) {
1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int ignore_color;
1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int tolerance;
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!(ReadInt(&ignore_color) && ReadInt(&tolerance))) {
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    fprintf(stderr, "Could not parse HISTOGRAM command.\n");
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const int kLength = 3 * 256;
1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int counts[kLength] = {};
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (const unsigned char* row = bmp.data; row < bmp.data + bmp.total_size;
1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       row += bmp.row_stride) {
1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    for (const unsigned char* pixel = row; pixel < row + bmp.row_size;
1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       pixel += bmp.pixel_stride) {
1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (ignore_color >= 0 && PixelsEqual(pixel, ignore_color, tolerance))
1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        continue;
1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ++(counts[256 * 0 + pixel[0]]);
1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ++(counts[256 * 1 + pixel[1]]);
1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ++(counts[256 * 2 + pixel[2]]);
1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  WriteResponse(counts, sizeof(counts));
1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return true;
1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)static
1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool BoundingBox(const Bitmap& bmp) {
1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int color;
2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int tolerance;
2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!(ReadInt(&color) && ReadInt(&tolerance))) {
2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    fprintf(stderr, "Could not parse BOUNDING_BOX command.\n");
2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Box box;
2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  box.left = bmp.total_size;
2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  box.top = bmp.total_size;
2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  box.right = 0;
2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  box.bottom = 0;
2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int count = 0;
2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int y = 0;
2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (const unsigned char* row = bmp.data; row < bmp.data + bmp.total_size;
2155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       row += bmp.row_stride, ++y) {
2165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int x = 0;
2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    for (const unsigned char* pixel = row; pixel < row + bmp.row_size;
2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)         pixel += bmp.pixel_stride, ++x) {
2195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (!PixelsEqual(pixel, color, tolerance))
2205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        continue;
2215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      box.Union(x, y);
2225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ++count;
2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
2245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int response[] = { box.left, box.top, box.width(), box.height(), count };
2275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  WriteResponse(response, sizeof(response));
2285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return true;
2295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)int main() {
2335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Bitmap bmp;
2345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int command;
2355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#if defined(WIN32)
2375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  _setmode(_fileno(stdin), _O_BINARY);
2385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  _setmode(_fileno(stdout), _O_BINARY);
2395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#else
2405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  FILE* unused_stdin = freopen(NULL, "rb", stdin);
2415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  FILE* unused_stdout = freopen(NULL, "wb", stdout);
2425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif
2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!bmp.Read()) return -1;
2455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!ReadInt(&command)) {
2465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    fprintf(stderr, "Expected command.\n");
2475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return -1;
2485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  switch (command) {
2505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case CROP_PIXELS:
2515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      bmp.WriteCroppedPixels();
2525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      break;
2535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case BOUNDING_BOX:
2545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (!BoundingBox(bmp)) return -1;
2555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      break;
2565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case HISTOGRAM:
2575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (!Histogram(bmp)) return -1;
2585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      break;
2595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    default:
2605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      fprintf(stderr, "Unrecognized command\n");
2615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return -1;
2625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return 0;
2645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
265