Ei kuvausta

ViewShot.java 7.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. package fr.greweb.reactnativeviewshot;
  2. import javax.annotation.Nullable;
  3. import android.app.Activity;
  4. import android.content.Intent;
  5. import android.graphics.Bitmap;
  6. import android.graphics.Canvas;
  7. import android.net.Uri;
  8. import android.util.Base64;
  9. import android.view.TextureView;
  10. import android.view.View;
  11. import android.view.ViewGroup;
  12. import android.widget.ScrollView;
  13. import com.facebook.react.bridge.Promise;
  14. import com.facebook.react.bridge.ReactApplicationContext;
  15. import com.facebook.react.uimanager.NativeViewHierarchyManager;
  16. import com.facebook.react.uimanager.UIBlock;
  17. import java.io.ByteArrayOutputStream;
  18. import java.io.File;
  19. import java.io.FileOutputStream;
  20. import java.io.IOException;
  21. import java.io.OutputStream;
  22. import java.util.ArrayList;
  23. import java.util.List;
  24. /**
  25. * Snapshot utility class allow to screenshot a view.
  26. */
  27. public class ViewShot implements UIBlock {
  28. static final String ERROR_UNABLE_TO_SNAPSHOT = "E_UNABLE_TO_SNAPSHOT";
  29. private int tag;
  30. private String extension;
  31. private Bitmap.CompressFormat format;
  32. private double quality;
  33. private Integer width;
  34. private Integer height;
  35. private File output;
  36. private String result;
  37. private Promise promise;
  38. private Boolean snapshotContentContainer;
  39. private ReactApplicationContext reactContext;
  40. private Activity currentActivity;
  41. public ViewShot(
  42. int tag,
  43. String extension,
  44. Bitmap.CompressFormat format,
  45. double quality,
  46. @Nullable Integer width,
  47. @Nullable Integer height,
  48. File output,
  49. String result,
  50. Boolean snapshotContentContainer,
  51. ReactApplicationContext reactContext,
  52. Activity currentActivity,
  53. Promise promise) {
  54. this.tag = tag;
  55. this.extension = extension;
  56. this.format = format;
  57. this.quality = quality;
  58. this.width = width;
  59. this.height = height;
  60. this.output = output;
  61. this.result = result;
  62. this.snapshotContentContainer = snapshotContentContainer;
  63. this.reactContext = reactContext;
  64. this.currentActivity = currentActivity;
  65. this.promise = promise;
  66. }
  67. @Override
  68. public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) {
  69. OutputStream os = null;
  70. View view = null;
  71. if (tag == -1) {
  72. view = currentActivity.getWindow().getDecorView().findViewById(android.R.id.content);
  73. } else {
  74. view = nativeViewHierarchyManager.resolveView(tag);
  75. }
  76. if (view == null) {
  77. promise.reject(ERROR_UNABLE_TO_SNAPSHOT, "No view found with reactTag: "+tag);
  78. return;
  79. }
  80. try {
  81. if ("tmpfile".equals(result)) {
  82. os = new FileOutputStream(output);
  83. captureView(view, os);
  84. String uri = Uri.fromFile(output).toString();
  85. promise.resolve(uri);
  86. }
  87. else if ("base64".equals(result)) {
  88. os = new ByteArrayOutputStream();
  89. captureView(view, os);
  90. byte[] bytes = ((ByteArrayOutputStream) os).toByteArray();
  91. String data = Base64.encodeToString(bytes, Base64.NO_WRAP);
  92. promise.resolve(data);
  93. }
  94. else if ("data-uri".equals(result)) {
  95. os = new ByteArrayOutputStream();
  96. captureView(view, os);
  97. byte[] bytes = ((ByteArrayOutputStream) os).toByteArray();
  98. String data = Base64.encodeToString(bytes, Base64.NO_WRAP);
  99. // correct the extension if JPG
  100. if ("jpg".equals(extension)) {
  101. extension = "jpeg";
  102. }
  103. data = "data:image/"+extension+";base64," + data;
  104. promise.resolve(data);
  105. }
  106. }
  107. catch (Exception e) {
  108. e.printStackTrace();
  109. promise.reject(ERROR_UNABLE_TO_SNAPSHOT, "Failed to capture view snapshot");
  110. }
  111. finally {
  112. if (os != null) {
  113. try {
  114. os.close();
  115. } catch (IOException e) {
  116. e.printStackTrace();
  117. }
  118. }
  119. }
  120. }
  121. private List<View> getAllChildren(View v) {
  122. if (!(v instanceof ViewGroup)) {
  123. ArrayList<View> viewArrayList = new ArrayList<View>();
  124. viewArrayList.add(v);
  125. return viewArrayList;
  126. }
  127. ArrayList<View> result = new ArrayList<View>();
  128. ViewGroup viewGroup = (ViewGroup) v;
  129. for (int i = 0; i < viewGroup.getChildCount(); i++) {
  130. View child = viewGroup.getChildAt(i);
  131. //Do not add any parents, just add child elements
  132. result.addAll(getAllChildren(child));
  133. }
  134. return result;
  135. }
  136. /**
  137. * Screenshot a view and return the captured bitmap.
  138. * @param view the view to capture
  139. * @return the screenshot or null if it failed.
  140. */
  141. private void captureView (View view, OutputStream os) {
  142. int w = view.getWidth();
  143. int h = view.getHeight();
  144. if (w <= 0 || h <= 0) {
  145. throw new RuntimeException("Impossible to snapshot the view: view is invalid");
  146. }
  147. //evaluate real height
  148. if (snapshotContentContainer) {
  149. h=0;
  150. ScrollView scrollView = (ScrollView)view;
  151. for (int i = 0; i < scrollView.getChildCount(); i++) {
  152. h += scrollView.getChildAt(i).getHeight();
  153. }
  154. }
  155. Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
  156. Bitmap childBitmapBuffer;
  157. Canvas c = new Canvas(bitmap);
  158. view.draw(c);
  159. //after view is drawn, go through children
  160. List<View> childrenList = getAllChildren(view);
  161. for (View child : childrenList) {
  162. if(child instanceof TextureView) {
  163. ((TextureView) child).setOpaque(false);
  164. childBitmapBuffer = ((TextureView) child).getBitmap(child.getWidth(), child.getHeight());
  165. if (childBitmapBuffer != null) {
  166. int left = child.getLeft();
  167. int top = child.getTop();
  168. View parentElem = (View)child.getParent();
  169. while (parentElem != null) {
  170. if (parentElem == view) {
  171. break;
  172. }
  173. left += parentElem.getLeft();
  174. top += parentElem.getTop();
  175. parentElem = (View)parentElem.getParent();
  176. }
  177. c.drawBitmap(childBitmapBuffer, left + child.getPaddingLeft(), top + child.getPaddingTop(), null);
  178. }
  179. }
  180. }
  181. if (width != null && height != null && (width != w || height != h)) {
  182. bitmap = Bitmap.createScaledBitmap(bitmap, width, height, true);
  183. }
  184. if (bitmap == null) {
  185. throw new RuntimeException("Impossible to snapshot the view");
  186. }
  187. bitmap.compress(format, (int)(100.0 * quality), os);
  188. }
  189. }