Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(171)

Unified Diff: tools/telemetry/telemetry/core/bitmaptools.cc

Issue 136793022: [telemetry] bitmaptools as a standalone executable (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix binary mode for stdio on win32 Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « tools/telemetry/telemetry/core/bitmap_unittest.py ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tools/telemetry/telemetry/core/bitmaptools.cc
diff --git a/tools/telemetry/telemetry/core/bitmaptools.cc b/tools/telemetry/telemetry/core/bitmaptools.cc
new file mode 100644
index 0000000000000000000000000000000000000000..833f1c750dc2e332cbb1236a0d23f765ad97f74c
--- /dev/null
+++ b/tools/telemetry/telemetry/core/bitmaptools.cc
@@ -0,0 +1,264 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(WIN32)
+#include <fcntl.h>
+#include <io.h>
+#endif
+
+enum Commands {
+ CROP_PIXELS = 0,
+ HISTOGRAM = 1,
+ BOUNDING_BOX = 2
+};
+
+bool ReadInt(int* out) {
+ return fread(out, sizeof(*out), 1, stdin) == 1;
+}
+
+void WriteResponse(void* data, int size) {
+ fwrite(&size, sizeof(size), 1, stdout);
+ fwrite(data, size, 1, stdout);
+ fflush(stdout);
+}
+
+struct Box {
+ Box() : left(), top(), right(), bottom() {}
+
+ // Expected input is:
+ // left, top, width, height
+ bool Read() {
+ int width;
+ int height;
+ if (!(ReadInt(&left) && ReadInt(&top) &&
+ ReadInt(&width) && ReadInt(&height))) {
+ fprintf(stderr, "Could not parse Box.\n");
+ return false;
+ }
+ if (left < 0 || top < 0 || width < 0 || height < 0) {
+ fprintf(stderr, "Box dimensions must be non-negative.\n");
+ return false;
+ }
+ right = left + width;
+ bottom = top + height;
+ return true;
+ }
+
+ void Union(int x, int y) {
+ if (left > x) left = x;
+ if (right <= x) right = x + 1;
+ if (top > y) top = y;
+ if (bottom <= y) bottom = y + 1;
+ }
+
+ int width() const { return right - left; }
+ int height() const { return bottom - top; }
+
+ int left;
+ int top;
+ int right;
+ int bottom;
+};
+
+
+// Represents a bitmap buffer with a crop box.
+struct Bitmap {
+ Bitmap() : pixels(NULL) {}
+
+ ~Bitmap() {
+ if (pixels)
+ delete[] pixels;
+ }
+
+ // Expected input is:
+ // bpp, width, height, box, pixels
+ bool Read() {
+ int bpp;
+ int width;
+ int height;
+ if (!(ReadInt(&bpp) && ReadInt(&width) && ReadInt(&height))) {
+ fprintf(stderr, "Could not parse Bitmap initializer.\n");
+ return false;
+ }
+ if (bpp <= 0 || width <= 0 || height <= 0) {
+ fprintf(stderr, "Dimensions must be positive.\n");
+ return false;
+ }
+
+ int size = width * height * bpp;
+
+ row_stride = width * bpp;
+ pixel_stride = bpp;
+ total_size = size;
+ row_size = row_stride;
+
+ if (!box.Read()) {
+ fprintf(stderr, "Expected crop box argument not found.\n");
+ return false;
+ }
+
+ if (box.bottom * row_stride > total_size ||
+ box.right * pixel_stride > row_size) {
+ fprintf(stderr, "Crop box overflows the bitmap.\n");
+ return false;
+ }
+
+ pixels = new unsigned char[size];
+ if (fread(pixels, sizeof(pixels[0]), size, stdin) <
+ static_cast<size_t>(size)) {
+ fprintf(stderr, "Not enough pixels found,\n");
+ return false;
+ }
+
+ total_size = (box.bottom - box.top) * row_stride;
+ row_size = (box.right - box.left) * pixel_stride;
+ data = pixels + box.top * row_stride + box.left * pixel_stride;
+ return true;
+ }
+
+ void WriteCroppedPixels() const {
+ int out_size = row_size * box.height();
+ unsigned char* out = new unsigned char[out_size];
+ unsigned char* dst = out;
+ for (const unsigned char* row = data;
+ row < data + total_size;
+ row += row_stride, dst += row_size) {
+ // No change in pixel_stride, so we can copy whole rows.
+ memcpy(dst, row, row_size);
+ }
+
+ WriteResponse(out, out_size);
+ delete[] out;
+ }
+
+ unsigned char* pixels;
+ Box box;
+ // Points at the top-left pixel in |pixels|.
+ const unsigned char* data;
+ // These counts are in bytes.
+ int row_stride;
+ int pixel_stride;
+ int total_size;
+ int row_size;
+};
+
+
+static inline
+bool PixelsEqual(const unsigned char* pixel1, const unsigned char* pixel2,
+ int tolerance) {
+ // Note: this works for both RGB and RGBA. Alpha channel is ignored.
+ return (abs(pixel1[0] - pixel2[0]) <= tolerance) &&
+ (abs(pixel1[1] - pixel2[1]) <= tolerance) &&
+ (abs(pixel1[2] - pixel2[2]) <= tolerance);
+}
+
+
+static inline
+bool PixelsEqual(const unsigned char* pixel, int color, int tolerance) {
+ unsigned char pixel2[3] = { color >> 16, color >> 8, color };
+ return PixelsEqual(pixel, pixel2, tolerance);
+}
+
+
+static
+bool Histogram(const Bitmap& bmp) {
+ int ignore_color;
+ int tolerance;
+ if (!(ReadInt(&ignore_color) && ReadInt(&tolerance))) {
+ fprintf(stderr, "Could not parse HISTOGRAM command.\n");
+ return false;
+ }
+
+ const int kLength = 3 * 256;
+ int counts[kLength] = {};
+
+ for (const unsigned char* row = bmp.data; row < bmp.data + bmp.total_size;
+ row += bmp.row_stride) {
+ for (const unsigned char* pixel = row; pixel < row + bmp.row_size;
+ pixel += bmp.pixel_stride) {
+ if (ignore_color >= 0 && PixelsEqual(pixel, ignore_color, tolerance))
+ continue;
+ ++(counts[256 * 0 + pixel[0]]);
+ ++(counts[256 * 1 + pixel[1]]);
+ ++(counts[256 * 2 + pixel[2]]);
+ }
+ }
+
+ WriteResponse(counts, sizeof(counts));
+ return true;
+}
+
+
+static
+bool BoundingBox(const Bitmap& bmp) {
+ int color;
+ int tolerance;
+ if (!(ReadInt(&color) && ReadInt(&tolerance))) {
+ fprintf(stderr, "Could not parse BOUNDING_BOX command.\n");
+ return false;
+ }
+
+ Box box;
+ box.left = bmp.total_size;
+ box.top = bmp.total_size;
+ box.right = 0;
+ box.bottom = 0;
+
+ int count = 0;
+ int y = 0;
+ for (const unsigned char* row = bmp.data; row < bmp.data + bmp.total_size;
+ row += bmp.row_stride, ++y) {
+ int x = 0;
+ for (const unsigned char* pixel = row; pixel < row + bmp.row_size;
+ pixel += bmp.pixel_stride, ++x) {
+ if (!PixelsEqual(pixel, color, tolerance))
+ continue;
+ box.Union(x, y);
+ ++count;
+ }
+ }
+
+ int response[] = { box.left, box.top, box.width(), box.height(), count };
+ WriteResponse(response, sizeof(response));
+ return true;
+}
+
+
+int main() {
+ Bitmap bmp;
+ int command;
+
+#if defined(WIN32)
+ _setmode(_fileno(stdin), _O_BINARY);
+ _setmode(_fileno(stdout), _O_BINARY);
+#else
+ freopen(NULL, "rb", stdin);
+ freopen(NULL, "wb", stdout);
+#endif
+
+ if (!bmp.Read()) return -1;
+ if (!ReadInt(&command)) {
+ fprintf(stderr, "Expected command.\n");
+ return -1;
+ }
+ switch (command) {
+ case CROP_PIXELS:
+ bmp.WriteCroppedPixels();
+ break;
+ case BOUNDING_BOX:
+ if (!BoundingBox(bmp)) return -1;
+ break;
+ case HISTOGRAM:
+ if (!Histogram(bmp)) return -1;
+ break;
+ default:
+ fprintf(stderr, "Unrecognized command\n");
+ return -1;
+ }
+ return 0;
+}
« no previous file with comments | « tools/telemetry/telemetry/core/bitmap_unittest.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698