am 7eddc21b: Merge "CameraITS: check the reported crop region" into lmp-sprout-dev
* commit '7eddc21b70584fdede5af2b9d060deae63ee76f8':
CameraITS: check the reported crop region
Add tests for non-rectangular clipping
diff --git a/apps/CameraITS/pymodules/its/caps.py b/apps/CameraITS/pymodules/its/caps.py
index 6caebc0..b27e75e 100644
--- a/apps/CameraITS/pymodules/its/caps.py
+++ b/apps/CameraITS/pymodules/its/caps.py
@@ -152,6 +152,18 @@
"""
return manual_sensor(props) and manual_post_proc(props)
+def freeform_crop(props):
+ """Returns whether a device supports freefrom cropping.
+
+ Args:
+ props: Camera properties object.
+
+ Return:
+ Boolean.
+ """
+ return props.has_key("android.scaler.croppingType") and \
+ props["android.scaler.croppingType"] == 1
+
class __UnitTest(unittest.TestCase):
"""Run a suite of unit tests on this module.
"""
diff --git a/apps/CameraITS/pymodules/its/objects.py b/apps/CameraITS/pymodules/its/objects.py
index d11ef84..809a98a 100644
--- a/apps/CameraITS/pymodules/its/objects.py
+++ b/apps/CameraITS/pymodules/its/objects.py
@@ -159,6 +159,25 @@
req = manual_capture_request(s,e)
return req, out_spec
+def get_max_digital_zoom(props):
+ """Returns the maximum amount of zooming possible by the camera device.
+
+ Args:
+ props: the object returned from its.device.get_camera_properties().
+
+ Return:
+ A float indicating the maximum amount of zooming possible by the
+ camera device.
+ """
+
+ maxz = 1.0
+
+ if props.has_key("android.scaler.availableMaxDigitalZoom"):
+ maxz = props["android.scaler.availableMaxDigitalZoom"]
+
+ return maxz
+
+
class __UnitTest(unittest.TestCase):
"""Run a suite of unit tests on this module.
"""
diff --git a/apps/CameraITS/tests/scene1/test_crop_region_raw.py b/apps/CameraITS/tests/scene1/test_crop_region_raw.py
index 94c8e2b..07343dd 100644
--- a/apps/CameraITS/tests/scene1/test_crop_region_raw.py
+++ b/apps/CameraITS/tests/scene1/test_crop_region_raw.py
@@ -20,12 +20,32 @@
import numpy
import os.path
+
+def check_crop_region(expected, reported, active, err_threshold):
+ """Check if the reported region is within the tolerance.
+
+ Args:
+ expected: expected crop region
+ reported: reported crop region
+ active: active resolution
+ err_threshold: error threshold for the active resolution
+ """
+
+ ex = (active["right"] - active["left"]) * err_threshold
+ ey = (active["bottom"] - active["top"]) * err_threshold
+
+ assert ((abs(expected["left"] - reported["left"]) <= ex) and
+ (abs(expected["right"] - reported["right"]) <= ex) and
+ (abs(expected["top"] - reported["top"]) <= ey) and
+ (abs(expected["bottom"] - reported["bottom"]) <= ey))
+
def main():
"""Test that raw streams are not croppable.
"""
NAME = os.path.basename(__file__).split(".")[0]
DIFF_THRESH = 0.05
+ CROP_REGION_ERROR_THRESHOLD = 0.01
with its.device.ItsSession() as cam:
props = cam.get_camera_properties()
@@ -39,6 +59,13 @@
aw, ah = a["right"] - a["left"], a["bottom"] - a["top"]
print "Active sensor region: (%d,%d %dx%d)" % (ax, ay, aw, ah)
+ full_region = {
+ "left": 0,
+ "top": 0,
+ "right": aw,
+ "bottom": ah
+ }
+
# Capture without a crop region.
# Use a manual request with a linear tonemap so that the YUV and RAW
# should look the same (once converted by the its.image module).
@@ -46,31 +73,42 @@
req = its.objects.manual_capture_request(s,e, True)
cap1_raw, cap1_yuv = cam.do_capture(req, cam.CAP_RAW_YUV)
- # Capture with a center crop region.
+ # Calculate a center crop region.
+ zoom = min(3.0, its.objects.get_max_digital_zoom(props))
+ assert(zoom >= 1)
+ cropw = aw / zoom
+ croph = ah / zoom
+
req["android.scaler.cropRegion"] = {
- "top": ay + ah/3,
- "left": ax + aw/3,
- "right": ax + 2*aw/3,
- "bottom": ay + 2*ah/3}
+ "left": aw / 2 - cropw / 2,
+ "top": ah / 2 - croph / 2,
+ "right": aw / 2 + cropw / 2,
+ "bottom": ah / 2 + croph / 2
+ }
+
+ # when both YUV and RAW are requested, the crop region that's
+ # applied to YUV should be reported.
+ crop_region = req["android.scaler.cropRegion"]
+ if crop_region == full_region:
+ crop_region_err_thresh = 0.0
+ else:
+ crop_region_err_thresh = CROP_REGION_ERROR_THRESHOLD
+
cap2_raw, cap2_yuv = cam.do_capture(req, cam.CAP_RAW_YUV)
- reported_crops = []
imgs = {}
- for s,cap in [("yuv_full",cap1_yuv), ("raw_full",cap1_raw),
- ("yuv_crop",cap2_yuv), ("raw_crop",cap2_raw)]:
+ for s, cap, cr, err_delta in [("yuv_full", cap1_yuv, full_region, 0),
+ ("raw_full", cap1_raw, full_region, 0),
+ ("yuv_crop", cap2_yuv, crop_region, crop_region_err_thresh),
+ ("raw_crop", cap2_raw, crop_region, crop_region_err_thresh)]:
img = its.image.convert_capture_to_rgb_image(cap, props=props)
its.image.write_image(img, "%s_%s.jpg" % (NAME, s))
r = cap["metadata"]["android.scaler.cropRegion"]
- x, y = a["left"], a["top"]
- w, h = a["right"] - a["left"], a["bottom"] - a["top"]
- reported_crops.append((x,y,w,h))
+ x, y = r["left"], r["top"]
+ w, h = r["right"] - r["left"], r["bottom"] - r["top"]
imgs[s] = img
- print "Crop on %s: (%d,%d %dx%d)" % (s, x,y,w,h)
-
- # The metadata should report uncropped for all shots (since there is
- # at least 1 uncropped stream in each case).
- for (x,y,w,h) in reported_crops:
- assert((ax,ay,aw,ah) == (x,y,w,h))
+ print "Crop on %s: (%d,%d %dx%d)" % (s, x, y, w, h)
+ check_crop_region(cr, r, a, err_delta)
# Also check the image content; 3 of the 4 shots should match.
# Note that all the shots are RGB below; the variable names correspond
diff --git a/apps/CameraITS/tests/scene1/test_crop_regions.py b/apps/CameraITS/tests/scene1/test_crop_regions.py
index da0cd0a..5824363 100644
--- a/apps/CameraITS/tests/scene1/test_crop_regions.py
+++ b/apps/CameraITS/tests/scene1/test_crop_regions.py
@@ -35,7 +35,8 @@
with its.device.ItsSession() as cam:
props = cam.get_camera_properties()
- if not its.caps.compute_target_exposure(props):
+ if (not its.caps.compute_target_exposure(props) or
+ not its.caps.freeform_crop(props)):
print "Test skipped"
return
@@ -46,7 +47,7 @@
print "Active sensor region (%d,%d %dx%d)" % (ax, ay, aw, ah)
# Uses a 2x digital zoom.
- assert(props['android.scaler.availableMaxDigitalZoom'] >= 2)
+ assert(its.objects.get_max_digital_zoom(props) >= 2)
# Capture a full frame.
req = its.objects.manual_capture_request(s,e)
diff --git a/tests/tests/uirendering/res/layout/simple_rect_layout.xml b/tests/tests/uirendering/res/layout/simple_rect_layout.xml
index 24c9b6b..e64c4e9 100644
--- a/tests/tests/uirendering/res/layout/simple_rect_layout.xml
+++ b/tests/tests/uirendering/res/layout/simple_rect_layout.xml
@@ -17,11 +17,10 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="#f00">
+ android:layout_height="match_parent">
- <View android:layout_width="180px"
- android:layout_height="120px"
- android:background="#0f0" />
+ <View android:layout_width="100px"
+ android:layout_height="100px"
+ android:background="#00f" />
</LinearLayout>
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ExactCanvasTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ExactCanvasTests.java
index 3088142..afbad65 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ExactCanvasTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ExactCanvasTests.java
@@ -16,8 +16,6 @@
package android.uirendering.cts.testclasses;
-import com.android.cts.uirendering.R;
-
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
@@ -31,8 +29,7 @@
import android.uirendering.cts.bitmapverifiers.RectVerifier;
import android.uirendering.cts.testinfrastructure.ActivityTestBase;
import android.uirendering.cts.testinfrastructure.CanvasClient;
-import android.uirendering.cts.testinfrastructure.ViewInitializer;
-import android.view.View;
+import com.android.cts.uirendering.R;
public class ExactCanvasTests extends ActivityTestBase {
private final BitmapComparer mExactComparer = new ExactComparer();
@@ -212,14 +209,4 @@
.addLayout(R.layout.blue_padded_square, null)
.runWithVerifier(verifier);
}
-
- @SmallTest
- public void testClipping() {
- createTest().addLayout(R.layout.simple_red_layout, new ViewInitializer() {
- @Override
- public void intializeView(View view) {
- view.setClipBounds(new Rect(0, 0, 50, 50));
- }
- }).runWithComparer(mExactComparer);
- }
}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathClippingTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathClippingTests.java
new file mode 100644
index 0000000..8df8057
--- /dev/null
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathClippingTests.java
@@ -0,0 +1,146 @@
+package android.uirendering.cts.testclasses;
+
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.Point;
+import android.graphics.Typeface;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.uirendering.cts.bitmapcomparers.MSSIMComparer;
+import android.uirendering.cts.bitmapverifiers.SamplePointVerifier;
+import android.uirendering.cts.testinfrastructure.ActivityTestBase;
+import android.uirendering.cts.testinfrastructure.CanvasClient;
+import android.uirendering.cts.testinfrastructure.ViewInitializer;
+import android.view.View;
+import android.view.ViewGroup;
+import com.android.cts.uirendering.R;
+
+public class PathClippingTests extends ActivityTestBase {
+ // draw circle with whole in it, with stroked circle
+ static final CanvasClient sCircleDrawCanvasClient = new CanvasClient() {
+ @Override
+ public String getDebugString() {
+ return "StrokedCircleDraw";
+ }
+
+ @Override
+ public void draw(Canvas canvas, int width, int height) {
+ Paint paint = new Paint();
+ paint.setAntiAlias(false);
+ paint.setColor(Color.BLUE);
+ paint.setStyle(Paint.Style.STROKE);
+ paint.setStrokeWidth(20);
+ canvas.drawCircle(50, 50, 40, paint);
+ }
+ };
+
+ // draw circle with whole in it, by path operations + path clipping
+ static final CanvasClient sCircleClipCanvasClient = new CanvasClient() {
+ @Override
+ public String getDebugString() {
+ return "CircleClipDraw";
+ }
+
+ @Override
+ public void draw(Canvas canvas, int width, int height) {
+ canvas.save();
+
+ Path path = new Path();
+ path.addCircle(50, 50, 50, Path.Direction.CW);
+ path.addCircle(50, 50, 30, Path.Direction.CCW);
+
+ canvas.clipPath(path);
+ canvas.drawColor(Color.BLUE);
+
+ canvas.restore();
+ }
+ };
+
+ @SmallTest
+ public void testCircleWithCircle() {
+ createTest()
+ .addCanvasClient(sCircleDrawCanvasClient, false)
+ .addCanvasClient(sCircleClipCanvasClient)
+ .runWithComparer(new MSSIMComparer(0.90));
+ }
+
+ @SmallTest
+ public void testCircleWithPoints() {
+ createTest()
+ .addCanvasClient(sCircleClipCanvasClient)
+ .runWithVerifier(new SamplePointVerifier(
+ new Point[] {
+ // inside of circle
+ new Point(50, 50),
+ // on circle
+ new Point(50 + 32, 50 + 32),
+ // outside of circle
+ new Point(50 + 38, 50 + 38),
+ new Point(100, 100)
+ },
+ new int[] {
+ Color.WHITE,
+ Color.BLUE,
+ Color.WHITE,
+ Color.WHITE,
+ }));
+ }
+
+ @SmallTest
+ public void testViewRotate() {
+ createTest()
+ .addLayout(R.layout.blue_padded_layout, new ViewInitializer() {
+ @Override
+ public void intializeView(View view) {
+ ViewGroup rootView = (ViewGroup) view;
+ rootView.setClipChildren(true);
+ View childView = rootView.getChildAt(0);
+ childView.setPivotX(50);
+ childView.setPivotY(50);
+ childView.setRotation(45f);
+
+ }
+ })
+ .runWithVerifier(new SamplePointVerifier(
+ new Point[] {
+ // inside of rotated rect
+ new Point(50, 50),
+ new Point(50 + 32, 50 + 32),
+ // outside of rotated rect
+ new Point(50 + 38, 50 + 38),
+ new Point(100, 100)
+ },
+ new int[] {
+ Color.BLUE,
+ Color.BLUE,
+ Color.WHITE,
+ Color.WHITE,
+ }));
+ }
+
+ @SmallTest
+ public void testTextClip() {
+ createTest()
+ .addCanvasClient(new CanvasClient() {
+ @Override
+ public void draw(Canvas canvas, int width, int height) {
+ canvas.save();
+
+ Path path = new Path();
+ path.addCircle(0, 50, 50, Path.Direction.CW);
+ path.addCircle(100, 50, 50, Path.Direction.CW);
+ canvas.clipPath(path);
+
+ Paint paint = new Paint();
+ paint.setAntiAlias(true);
+ paint.setTextSize(100);
+ paint.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ canvas.drawText("STRING", 0, 100, paint);
+
+ canvas.restore();
+ }
+ })
+ .runWithComparer(new MSSIMComparer(0.90));
+ }
+}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/view/UnclippedBlueView.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/view/UnclippedBlueView.java
index e2037f7..7a16e3c 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/view/UnclippedBlueView.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/view/UnclippedBlueView.java
@@ -18,12 +18,12 @@
public UnclippedBlueView(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
- setWillNotDraw(false);
}
public UnclippedBlueView(Context context, AttributeSet attrs,
int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
+ setWillNotDraw(false);
}
@Override