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

Unified Diff: trunk/src/tools/telemetry/telemetry/core/bitmap.py

Issue 138143020: Revert 245684 "[telemetry] bitmaptools as a standalone executable" (Closed) Base URL: svn://svn.chromium.org/chrome/
Patch Set: 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
Index: trunk/src/tools/telemetry/telemetry/core/bitmap.py
===================================================================
--- trunk/src/tools/telemetry/telemetry/core/bitmap.py (revision 245711)
+++ trunk/src/tools/telemetry/telemetry/core/bitmap.py (working copy)
@@ -1,18 +1,8 @@
# Copyright 2013 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.
-
-"""
-Bitmap is a basic wrapper for image pixels. It includes some basic processing
-tools: crop, find bounding box of a color and compute histogram of color values.
-"""
-
-import array
import base64
import cStringIO
-import struct
-import subprocess
-import sys
from telemetry.core import util
@@ -53,62 +43,6 @@
WHITE = RgbaColor(255, 255, 255)
-class _BitmapTools(object):
- """Wraps a child process of bitmaptools and allows for one command."""
- CROP_PIXELS = 0
- HISTOGRAM = 1
- BOUNDING_BOX = 2
-
- def __init__(self, dimensions, pixels):
- suffix = '.exe' if sys.platform == 'win32' else ''
- binary = util.FindSupportBinary('bitmaptools' + suffix)
- assert binary, 'You must build bitmaptools first!'
-
- self._popen = subprocess.Popen([binary],
- stdin=subprocess.PIPE,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
-
- # dimensions are: bpp, width, height, boxleft, boxtop, boxwidth, boxheight
- packed_dims = struct.pack('iiiiiii', *dimensions)
- self._popen.stdin.write(packed_dims)
- # If we got a list of ints, we need to convert it into a byte buffer.
- if type(pixels) is not bytearray:
- pixels = bytearray(pixels)
- self._popen.stdin.write(pixels)
-
- def _RunCommand(self, *command):
- assert not self._popen.stdin.closed, (
- 'Exactly one command allowed per instance of tools.')
- packed_command = struct.pack('i' * len(command), *command)
- self._popen.stdin.write(packed_command)
- self._popen.stdin.close()
- length_packed = self._popen.stdout.read(struct.calcsize('i'))
- if not length_packed:
- raise Exception(self._popen.stderr.read())
- length = struct.unpack('i', length_packed)[0]
- return self._popen.stdout.read(length)
-
- def CropPixels(self):
- return self._RunCommand(_BitmapTools.CROP_PIXELS)
-
- def Histogram(self, ignore_color, tolerance):
- ignore_color = -1 if ignore_color is None else int(ignore_color)
- response = self._RunCommand(_BitmapTools.HISTOGRAM, ignore_color, tolerance)
- out = array.array('i')
- out.fromstring(response)
- return out
-
- def BoundingBox(self, color, tolerance):
- response = self._RunCommand(_BitmapTools.BOUNDING_BOX, int(color),
- tolerance)
- unpacked = struct.unpack('iiiii', response)
- box, count = unpacked[:4], unpacked[-1]
- if box[2] < 0 or box[3] < 0:
- box = None
- return box, count
-
-
class Bitmap(object):
"""Utilities for parsing and inspecting a bitmap."""
@@ -124,7 +58,6 @@
self._height = height
self._pixels = pixels
self._metadata = metadata or {}
- self._crop_box = None
@property
def bpp(self):
@@ -134,27 +67,16 @@
@property
def width(self):
"""Width of the bitmap."""
- return self._crop_box[2] if self._crop_box else self._width
+ return self._width
@property
def height(self):
"""Height of the bitmap."""
- return self._crop_box[3] if self._crop_box else self._height
+ return self._height
- def _PrepareTools(self):
- """Prepares an instance of _BitmapTools which allows exactly one command.
- """
- crop_box = self._crop_box or (0, 0, self._width, self._height)
- return _BitmapTools((self._bpp, self._width, self._height) + crop_box,
- self._pixels)
-
@property
def pixels(self):
"""Flat pixel array of the bitmap."""
- if self._crop_box:
- self._pixels = self._PrepareTools().CropPixels()
- _, _, self._width, self._height = self._crop_box
- self._crop_box = None
if type(self._pixels) is not bytearray:
self._pixels = bytearray(self._pixels)
return self._pixels
@@ -168,13 +90,12 @@
def GetPixelColor(self, x, y):
"""Returns a RgbaColor for the pixel at (x, y)."""
- pixels = self.pixels
base = self._bpp * (y * self._width + x)
if self._bpp == 4:
- return RgbaColor(pixels[base + 0], pixels[base + 1],
- pixels[base + 2], pixels[base + 3])
- return RgbaColor(pixels[base + 0], pixels[base + 1],
- pixels[base + 2])
+ return RgbaColor(self._pixels[base + 0], self._pixels[base + 1],
+ self._pixels[base + 2], self._pixels[base + 3])
+ return RgbaColor(self._pixels[base + 0], self._pixels[base + 1],
+ self._pixels[base + 2])
def WritePngFile(self, path):
with open(path, "wb") as f:
@@ -258,19 +179,49 @@
"""Finds the minimum box surrounding all occurences of |color|.
Returns: (top, left, width, height), match_count
Ignores the alpha channel."""
- return self._PrepareTools().BoundingBox(color, tolerance)
+ # TODO(szym): Implement this.
+ raise NotImplementedError("GetBoundingBox not yet implemented.")
def Crop(self, left, top, width, height):
- """Crops the current bitmap down to the specified box."""
- cur_box = self._crop_box or (0, 0, self._width, self._height)
- cur_left, cur_top, cur_width, cur_height = cur_box
-
+ """Crops the current bitmap down to the specified box.
+ TODO(szym): Make this O(1).
+ """
if (left < 0 or top < 0 or
- (left + width) > cur_width or
- (top + height) > cur_height):
+ (left + width) > self.width or
+ (top + height) > self.height):
raise ValueError('Invalid dimensions')
- self._crop_box = cur_left + left, cur_top + top, width, height
+ img_data = [[0 for x in xrange(width * self.bpp)]
+ for y in xrange(height)]
+
+ # Copy each pixel in the sub-rect.
+ # TODO(tonyg): Make this faster by avoiding the copy and artificially
+ # restricting the dimensions.
+ for y in range(height):
+ for x in range(width):
+ c = self.GetPixelColor(x + left, y + top)
+ offset = x * self.bpp
+ img_data[y][offset] = c.r
+ img_data[y][offset + 1] = c.g
+ img_data[y][offset + 2] = c.b
+ if self.bpp == 4:
+ img_data[y][offset + 3] = c.a
+
+ # This particular method can only save to a file, so the result will be
+ # written into an in-memory buffer and read back into a Bitmap
+ crop_img = png.from_array(img_data, mode='RGBA' if self.bpp == 4 else 'RGB')
+ output = cStringIO.StringIO()
+ try:
+ crop_img.save(output)
+ width, height, pixels, meta = png.Reader(
+ bytes=output.getvalue()).read_flat()
+ self._width = width
+ self._height = height
+ self._pixels = pixels
+ self._metadata = meta
+ finally:
+ output.close()
+
return self
def ColorHistogram(self, ignore_color=None, tolerance=0):
@@ -283,4 +234,5 @@
A list of 3x256 integers formatted as
[r0, r1, ..., g0, g1, ..., b0, b1, ...].
"""
- return self._PrepareTools().Histogram(ignore_color, tolerance)
+ # TODO(szym): Implement this.
+ raise NotImplementedError("ColorHistogram not yet implemented.")
« no previous file with comments | « trunk/src/tools/telemetry/telemetry.gyp ('k') | trunk/src/tools/telemetry/telemetry/core/bitmap_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698