1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.renderscript.cts.refocus;
18 
19 import android.content.ContentResolver;
20 import android.content.Context;
21 import android.graphics.Bitmap;
22 import android.graphics.BitmapFactory;
23 import android.graphics.Color;
24 import android.net.Uri;
25 import android.renderscript.cts.refocus.image.RangeInverseDepthTransform;
26 import android.util.Log;
27 
28 import java.io.FileNotFoundException;
29 import java.io.IOException;
30 
31 /**
32  * An RGBZ image, where Z stands for depth, i.e. a color+depth image.
33  * The RGBZ always has a preview image, which represents the latest rendering of the RGBZ.
34  * The preview is encoded as the normal jpeg content for client compatibility,
35  * while the color channel and depth channels are encoded as XMP data.
36  * The class supports lazy initialization where the XMP meta data is loaded only when first
37  * accessed.
38  */
39 public class RGBZ {
40   public static final String TAG = "RGBZ";
41 
42   private Bitmap bitmap;
43   private Bitmap preview;
44   private Bitmap depthBitmap;
45   private DepthTransform depthTransform;
46   private DepthImage depthImage;
47 
48   /**
49    * Creates an RGBZ from a content uri.
50    *
51    * @param uri The uri name of the RGBZ
52    * @throws FileNotFoundException if the RGBZ could not be read
53    */
RGBZ(Uri uri, ContentResolver contentResolver, Context context)54   public RGBZ(Uri uri, ContentResolver contentResolver, Context context) throws IOException {
55     preview = BitmapFactory.decodeStream(contentResolver.openInputStream(uri));
56     if (preview == null) {
57       throw new FileNotFoundException(uri.toString());
58     }
59     depthImage = DepthImage.createFromXMPMetadata(context, uri);
60     depthBitmap = depthImage.getDepthBitmap();
61     bitmap = setAlphaChannel(preview, depthBitmap);
62     depthTransform = depthImage.getDepthTransform();
63   }
64 
65   /**
66    * Creates an RGBZ from uris to an image and a depthmap.
67    *
68    * @param uriImage The uri name of the image
69    * @param uriDepthmap The uri name of the depthmap
70    * @throws FileNotFoundException if the RGBZ could not be read
71    */
RGBZ(Uri uriImage, Uri uriDepthmap, ContentResolver contentResolver, Context context)72   public RGBZ(Uri uriImage, Uri uriDepthmap, ContentResolver contentResolver,
73               Context context) throws IOException {
74     preview = BitmapFactory.decodeStream(contentResolver.openInputStream(uriImage));
75     if (preview == null) {
76       throw new FileNotFoundException(uriImage.toString());
77     }
78     depthImage = DepthImage.createFromDepthmap(context, uriDepthmap);
79     depthBitmap = depthImage.getDepthBitmap();
80     bitmap = setAlphaChannel(preview, depthBitmap);
81     depthTransform = depthImage.getDepthTransform();
82   }
83 
84   /**
85    * @return Whether the RGBZ has a depth channel
86    */
hasDepthmap()87   public boolean hasDepthmap() {
88     return depthTransform != null;
89   }
90 
91   /**
92    * @return The color+depth {@code Bitmap}
93    */
getBitmap()94   public Bitmap getBitmap() {
95     return bitmap;
96   }
97 
98   /**
99    * @return The depthmap component of this RGBZ
100    */
getDepthTransform()101   public DepthTransform getDepthTransform() {
102     return depthTransform;
103   }
104 
getFocusDepth()105   public double getFocusDepth() {
106     return this.depthImage.getFocalDistance();
107   }
108 
getDepthOfField()109   public double getDepthOfField() {
110     return this.depthImage.getDepthOfField();
111   }
112 
getBlurInfinity()113   public double getBlurInfinity() {
114     return this.depthImage.getBlurAtInfinity();
115   }
116 
117   /**
118    * @return the width of this {@code RGBZ}
119    */
getWidth()120   public int getWidth() {
121     return bitmap.getWidth();
122   }
123 
124   /**
125    * @return the height of this {@code RGBZ}
126    */
getHeight()127   public int getHeight() {
128     return bitmap.getHeight();
129   }
130 
131   /**
132    * @return the depth value of the given pixel
133    */
134 
getDepth(int x, int y)135   public float getDepth(int x, int y) {
136     if (!hasDepthmap()) {
137       return 0.0f;
138     }
139     if (x < 0 || x > depthBitmap.getWidth() ||
140             y < 0 || y > depthBitmap.getHeight()) {
141       Log.e("RGBZ getDepth", "index out of bound");
142       return 0;
143     }
144     return getDepthTransform().reconstruct(Color.blue(depthBitmap.getPixel(x, y)));
145   }
146 
147   /**
148    * Sets the depthmap as the alpha channel of the {@code Bitmap}.
149    */
setAlphaChannel(Bitmap bitmap, Bitmap depthBitmap)150   public Bitmap setAlphaChannel(Bitmap bitmap, Bitmap depthBitmap) {
151     if (bitmap == null) {
152       return bitmap;
153     }
154     Bitmap result = bitmap.copy(Bitmap.Config.ARGB_8888, true);
155     // set the alpha channel of depthBitmap to alpha of bitmap
156     result = setAlphaChannelFromBitmap(depthBitmap, bitmap, result);
157     return result;
158   }
159 
setAlphaChannelFromBitmap(Bitmap depth, Bitmap orig, Bitmap dest)160   private Bitmap setAlphaChannelFromBitmap(Bitmap depth, Bitmap orig, Bitmap dest) {
161     int w = orig.getWidth();
162     int h = orig.getHeight();
163     int[] orig_data = new int[w*h];
164     int[] depth_data = new int[w*h];
165 
166     orig.getPixels(orig_data, 0, w, 0, 0, w, h);
167     depth.getPixels(depth_data, 0, w, 0, 0, w, h);
168     for (int i = 0; i < orig_data.length; i++) {
169       int v = orig_data[i] & 0x00FFFFFF;
170       int temp = (depth_data[i] & 0x000000FF) << 24;
171       v = v | temp;
172       orig_data[i] = v;
173     }
174     dest.setPixels(orig_data, 0, w, 0, 0, w, h);
175     return dest;
176   }
177 }
178 
179