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 com.android.rs.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.util.Log; 26 import com.android.rs.refocus.image.RangeInverseDepthTransform; 27 import java.io.FileNotFoundException; 28 import java.io.IOException; 29 30 /** 31 * An RGBZ image, where Z stands for depth, i.e. a color+depth image. 32 * The RGBZ always has a preview image, which represents the latest rendering of the RGBZ. 33 * The preview is encoded as the normal jpeg content for client compatibility, 34 * while the color channel and depth channels are encoded as XMP data. 35 * The class supports lazy initialization where the XMP meta data is loaded only when first 36 * accessed. 37 */ 38 public class RGBZ { 39 public static final String TAG = "RGBZ"; 40 41 private Bitmap bitmap; 42 private Bitmap preview; 43 private Bitmap depthBitmap; 44 private DepthTransform depthTransform; 45 private DepthImage depthImage; 46 47 /** 48 * Creates an RGBZ from a content uri. 49 * 50 * @param uri The uri name of the RGBZ 51 * @throws FileNotFoundException if the RGBZ could not be read 52 */ RGBZ(Uri uri, ContentResolver contentResolver, Context context)53 public RGBZ(Uri uri, ContentResolver contentResolver, Context context) throws IOException { 54 preview = BitmapFactory.decodeStream(contentResolver.openInputStream(uri)); 55 if (preview == null) { 56 throw new FileNotFoundException(uri.toString()); 57 } 58 depthImage = DepthImage.createFromXMPMetadata(context, uri); 59 depthBitmap = depthImage.getDepthBitmap(); 60 //MediaStoreSaver.savePNG(depthBitmap, "depthmap", "depthmap", context); 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 RGBZ(Bitmap image, DepthImage depthImage)85 public RGBZ(Bitmap image, DepthImage depthImage) { 86 preview = image; 87 this.depthImage = depthImage; 88 depthBitmap = depthImage.getDepthBitmap(); 89 bitmap = setAlphaChannel(preview, depthBitmap); 90 depthTransform = depthImage.getDepthTransform(); 91 } 92 createFromBitmapDepthmap(Uri uriImage, Uri uriDepthmap, ContentResolver contentResolver, Context context)93 public static RGBZ createFromBitmapDepthmap(Uri uriImage, Uri uriDepthmap, 94 ContentResolver contentResolver, Context context) 95 throws IOException { 96 Bitmap image = BitmapFactory.decodeStream(contentResolver.openInputStream(uriImage)); 97 if (image == null) { 98 throw new FileNotFoundException(uriImage.toString()); 99 } 100 DepthImage depthImage = DepthImage.createFromDepthmap(context, uriDepthmap); 101 return new RGBZ(image, depthImage); 102 } 103 createFromPFMDepthmap(Uri uriImage, Uri uriDepthmap, ContentResolver contentResolver, Context context)104 public static RGBZ createFromPFMDepthmap(Uri uriImage, Uri uriDepthmap, 105 ContentResolver contentResolver, Context context) 106 throws IOException { 107 Bitmap image = BitmapFactory.decodeStream(contentResolver.openInputStream(uriImage)); 108 if (image == null) { 109 throw new FileNotFoundException(uriImage.toString()); 110 } 111 DepthImage depthImage = DepthImage.createFromPFM(context, uriDepthmap); 112 MediaStoreSaver.savePNG(depthImage.getDepthBitmap(), "depthmap", 113 "depthmap", context); 114 return new RGBZ(image, depthImage); 115 } 116 117 /** 118 * @return Whether the RGBZ has a depth channel 119 */ hasDepthmap()120 public boolean hasDepthmap() { 121 return depthTransform != null; 122 } 123 124 /** 125 * @return The color+depth {@code Bitmap} 126 */ getBitmap()127 public Bitmap getBitmap() { 128 return bitmap; 129 } 130 131 /** 132 * @return The depthmap component of this RGBZ 133 */ getDepthTransform()134 public DepthTransform getDepthTransform() { 135 return depthTransform; 136 } 137 getFocusDepth()138 public double getFocusDepth() { 139 return this.depthImage.getFocalDistance(); 140 } 141 getDepthOfField()142 public double getDepthOfField() { 143 return this.depthImage.getDepthOfField(); 144 } 145 getBlurInfinity()146 public double getBlurInfinity() { 147 return this.depthImage.getBlurAtInfinity(); 148 } 149 150 /** 151 * @return the width of this {@code RGBZ} 152 */ getWidth()153 public int getWidth() { 154 return bitmap.getWidth(); 155 } 156 157 /** 158 * @return the height of this {@code RGBZ} 159 */ getHeight()160 public int getHeight() { 161 return bitmap.getHeight(); 162 } 163 164 /** 165 * @return the depth value of the given pixel 166 */ 167 getDepth(int x, int y)168 public float getDepth(int x, int y) { 169 if (!hasDepthmap()) { 170 return 0.0f; 171 } 172 if (x < 0 || x > depthBitmap.getWidth() || 173 y < 0 || y > depthBitmap.getHeight()) { 174 Log.e("RGBZ getDepth", "index out of bound"); 175 return 0; 176 } 177 return getDepthTransform().reconstruct(Color.blue(depthBitmap.getPixel(x, y))); 178 } 179 180 /** 181 * Sets the depthmap as the alpha channel of the {@code Bitmap}. 182 */ setAlphaChannel(Bitmap bitmap, Bitmap depthBitmap)183 public Bitmap setAlphaChannel(Bitmap bitmap, Bitmap depthBitmap) { 184 if (bitmap == null) { 185 return bitmap; 186 } 187 Bitmap result = bitmap.copy(Bitmap.Config.ARGB_8888, true); 188 // set the alpha channel of depthBitmap to alpha of bitmap 189 result = setAlphaChannelFromBitmap(depthBitmap, bitmap, result); 190 return result; 191 } 192 setAlphaChannelFromBitmap(Bitmap depth, Bitmap orig, Bitmap dest)193 private Bitmap setAlphaChannelFromBitmap(Bitmap depth, Bitmap orig, Bitmap dest) { 194 int w = orig.getWidth(); 195 int h = orig.getHeight(); 196 int[] orig_data = new int[w*h]; 197 int[] depth_data = new int[w*h]; 198 199 orig.getPixels(orig_data, 0, w, 0, 0, w, h); 200 depth.getPixels(depth_data, 0, w, 0, 0, w, h); 201 for (int i = 0; i < orig_data.length; i++) { 202 int v = orig_data[i] & 0x00FFFFFF; 203 int temp = (depth_data[i] & 0x000000FF) << 24; 204 v = v | temp; 205 orig_data[i] = v; 206 } 207 dest.setPixels(orig_data, 0, w, 0, 0, w, h); 208 return dest; 209 } 210 } 211 212