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