Browse Source

added support of RAW image format and zip-base64 packaging of the results

Oleksandr Kucherenko 6 years ago
parent
commit
de310f1b3d

+ 77
- 59
android/src/main/java/fr/greweb/reactnativeviewshot/RNViewShotModule.java View File

1
 
1
 
2
 package fr.greweb.reactnativeviewshot;
2
 package fr.greweb.reactnativeviewshot;
3
 
3
 
4
+import android.app.Activity;
4
 import android.content.Context;
5
 import android.content.Context;
5
-import android.graphics.Bitmap;
6
 import android.net.Uri;
6
 import android.net.Uri;
7
 import android.os.AsyncTask;
7
 import android.os.AsyncTask;
8
-import android.os.Environment;
8
+import android.support.annotation.NonNull;
9
 import android.util.DisplayMetrics;
9
 import android.util.DisplayMetrics;
10
-import android.view.View;
11
-
12
-import com.facebook.react.bridge.ReactApplicationContext;
13
-import com.facebook.react.bridge.ReactContextBaseJavaModule;
14
-import com.facebook.react.bridge.ReactMethod;
10
+import android.util.Log;
15
 
11
 
16
 import com.facebook.react.bridge.GuardedAsyncTask;
12
 import com.facebook.react.bridge.GuardedAsyncTask;
17
-import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
18
 import com.facebook.react.bridge.Promise;
13
 import com.facebook.react.bridge.Promise;
14
+import com.facebook.react.bridge.ReactApplicationContext;
19
 import com.facebook.react.bridge.ReactContext;
15
 import com.facebook.react.bridge.ReactContext;
16
+import com.facebook.react.bridge.ReactContextBaseJavaModule;
17
+import com.facebook.react.bridge.ReactMethod;
20
 import com.facebook.react.bridge.ReadableMap;
18
 import com.facebook.react.bridge.ReadableMap;
21
-import com.facebook.react.uimanager.UIBlock;
22
 import com.facebook.react.uimanager.UIManagerModule;
19
 import com.facebook.react.uimanager.UIManagerModule;
23
 
20
 
24
 import java.io.File;
21
 import java.io.File;
25
 import java.io.FilenameFilter;
22
 import java.io.FilenameFilter;
26
 import java.io.IOException;
23
 import java.io.IOException;
27
 import java.util.Collections;
24
 import java.util.Collections;
28
-import java.util.HashMap;
29
 import java.util.Map;
25
 import java.util.Map;
30
 
26
 
27
+import fr.greweb.reactnativeviewshot.ViewShot.Formats;
28
+import fr.greweb.reactnativeviewshot.ViewShot.Results;
29
+
31
 public class RNViewShotModule extends ReactContextBaseJavaModule {
30
 public class RNViewShotModule extends ReactContextBaseJavaModule {
32
 
31
 
32
+    public static final String RNVIEW_SHOT = "RNViewShot";
33
+
33
     private final ReactApplicationContext reactContext;
34
     private final ReactApplicationContext reactContext;
34
 
35
 
35
     public RNViewShotModule(ReactApplicationContext reactContext) {
36
     public RNViewShotModule(ReactApplicationContext reactContext) {
39
 
40
 
40
     @Override
41
     @Override
41
     public String getName() {
42
     public String getName() {
42
-        return "RNViewShot";
43
+        return RNVIEW_SHOT;
43
     }
44
     }
44
 
45
 
45
     @Override
46
     @Override
67
 
68
 
68
     @ReactMethod
69
     @ReactMethod
69
     public void captureRef(int tag, ReadableMap options, Promise promise) {
70
     public void captureRef(int tag, ReadableMap options, Promise promise) {
70
-        ReactApplicationContext context = getReactApplicationContext();
71
-        String format = options.getString("format");
72
-        Bitmap.CompressFormat compressFormat =
73
-          format.equals("jpg")
74
-          ? Bitmap.CompressFormat.JPEG
75
-          : format.equals("webm")
76
-          ? Bitmap.CompressFormat.WEBP
77
-          : Bitmap.CompressFormat.PNG;
78
-        double quality = options.getDouble("quality");
79
-        DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
80
-        Integer width = options.hasKey("width") ? (int)(displayMetrics.density * options.getDouble("width")) : null;
81
-        Integer height = options.hasKey("height") ? (int)(displayMetrics.density * options.getDouble("height")) : null;
82
-        String result = options.getString("result");
83
-        Boolean snapshotContentContainer = options.getBoolean("snapshotContentContainer");
71
+        final ReactApplicationContext context = getReactApplicationContext();
72
+        final DisplayMetrics dm = context.getResources().getDisplayMetrics();
73
+
74
+        final String extension = options.getString("format");
75
+        final int imageFormat = "jpg".equals(extension)
76
+                ? Formats.JPEG
77
+                : "webm".equals(extension)
78
+                ? Formats.WEBP
79
+                : "raw".equals(extension)
80
+                ? Formats.RAW
81
+                : Formats.PNG;
82
+
83
+        final double quality = options.getDouble("quality");
84
+        final Integer scaleWidth = options.hasKey("width") ? (int) (dm.density * options.getDouble("width")) : null;
85
+        final Integer scaleHeight = options.hasKey("height") ? (int) (dm.density * options.getDouble("height")) : null;
86
+        final String resultStreamFormat = options.getString("result");
87
+        final Boolean snapshotContentContainer = options.getBoolean("snapshotContentContainer");
88
+
84
         try {
89
         try {
85
-            File file = null;
86
-            if ("tmpfile".equals(result)) {
87
-              file = createTempFile(getReactApplicationContext(), format);
90
+            File outputFile = null;
91
+            if (Results.TEMP_FILE.equals(resultStreamFormat)) {
92
+                outputFile = createTempFile(getReactApplicationContext(), extension);
88
             }
93
             }
89
-            UIManagerModule uiManager = this.reactContext.getNativeModule(UIManagerModule.class);
90
-            uiManager.addUIBlock(new ViewShot(tag, format, compressFormat, quality, width, height, file, result, snapshotContentContainer,reactContext, getCurrentActivity(), promise));
91
-        }
92
-        catch (Exception e) {
93
-            promise.reject(ViewShot.ERROR_UNABLE_TO_SNAPSHOT, "Failed to snapshot view tag "+tag);
94
+
95
+            final Activity activity = getCurrentActivity();
96
+            final UIManagerModule uiManager = this.reactContext.getNativeModule(UIManagerModule.class);
97
+
98
+            uiManager.addUIBlock(new ViewShot(
99
+                    tag, extension, imageFormat, quality,
100
+                    scaleWidth, scaleHeight, outputFile, resultStreamFormat,
101
+                    snapshotContentContainer, reactContext, activity, promise)
102
+            );
103
+        } catch (final Throwable ignored) {
104
+            promise.reject(ViewShot.ERROR_UNABLE_TO_SNAPSHOT, "Failed to snapshot view tag " + tag);
94
         }
105
         }
95
     }
106
     }
96
 
107
 
106
      * image files. This is run when the catalyst instance is being destroyed (i.e. app is shutting
117
      * image files. This is run when the catalyst instance is being destroyed (i.e. app is shutting
107
      * down) and when the module is instantiated, to handle the case where the app crashed.
118
      * down) and when the module is instantiated, to handle the case where the app crashed.
108
      */
119
      */
109
-    private static class CleanTask extends GuardedAsyncTask<Void, Void> {
110
-        private final Context mContext;
120
+    private static class CleanTask extends GuardedAsyncTask<Void, Void> implements FilenameFilter {
121
+        private final File cacheDir;
122
+        private final File externalCacheDir;
111
 
123
 
112
         private CleanTask(ReactContext context) {
124
         private CleanTask(ReactContext context) {
113
             super(context);
125
             super(context);
114
-            mContext = context;
126
+
127
+            cacheDir = context.getCacheDir();
128
+            externalCacheDir = context.getExternalCacheDir();
115
         }
129
         }
116
 
130
 
117
         @Override
131
         @Override
118
         protected void doInBackgroundGuarded(Void... params) {
132
         protected void doInBackgroundGuarded(Void... params) {
119
-            cleanDirectory(mContext.getCacheDir());
120
-            File externalCacheDir = mContext.getExternalCacheDir();
133
+            if (null != cacheDir) {
134
+                cleanDirectory(cacheDir);
135
+            }
136
+
121
             if (externalCacheDir != null) {
137
             if (externalCacheDir != null) {
122
                 cleanDirectory(externalCacheDir);
138
                 cleanDirectory(externalCacheDir);
123
             }
139
             }
124
         }
140
         }
125
 
141
 
126
-        private void cleanDirectory(File directory) {
127
-            File[] toDelete = directory.listFiles(
128
-                    new FilenameFilter() {
129
-                        @Override
130
-                        public boolean accept(File dir, String filename) {
131
-                            return filename.startsWith(TEMP_FILE_PREFIX);
132
-                        }
133
-                    });
142
+        @Override
143
+        public final boolean accept(File dir, String filename) {
144
+            return filename.startsWith(TEMP_FILE_PREFIX);
145
+        }
146
+
147
+        private void cleanDirectory(@NonNull final File directory) {
148
+            final File[] toDelete = directory.listFiles(this);
149
+
134
             if (toDelete != null) {
150
             if (toDelete != null) {
135
-                for (File file: toDelete) {
136
-                    file.delete();
151
+                for (File file : toDelete) {
152
+                    if (file.delete()) {
153
+                        Log.d(RNVIEW_SHOT, "deleted file: " + file.getAbsolutePath());
154
+                    }
137
                 }
155
                 }
138
             }
156
             }
139
         }
157
         }
143
      * Create a temporary file in the cache directory on either internal or external storage,
161
      * Create a temporary file in the cache directory on either internal or external storage,
144
      * whichever is available and has more free space.
162
      * whichever is available and has more free space.
145
      */
163
      */
146
-    private File createTempFile(Context context, String ext)
147
-            throws IOException {
148
-        File externalCacheDir = context.getExternalCacheDir();
149
-        File internalCacheDir = context.getCacheDir();
150
-        File cacheDir;
164
+    @NonNull
165
+    private File createTempFile(@NonNull final Context context, @NonNull final String ext) throws IOException {
166
+        final File externalCacheDir = context.getExternalCacheDir();
167
+        final File internalCacheDir = context.getCacheDir();
168
+        final File cacheDir;
169
+
151
         if (externalCacheDir == null && internalCacheDir == null) {
170
         if (externalCacheDir == null && internalCacheDir == null) {
152
             throw new IOException("No cache directory available");
171
             throw new IOException("No cache directory available");
153
         }
172
         }
173
+
154
         if (externalCacheDir == null) {
174
         if (externalCacheDir == null) {
155
             cacheDir = internalCacheDir;
175
             cacheDir = internalCacheDir;
156
-        }
157
-        else if (internalCacheDir == null) {
176
+        } else if (internalCacheDir == null) {
158
             cacheDir = externalCacheDir;
177
             cacheDir = externalCacheDir;
159
         } else {
178
         } else {
160
             cacheDir = externalCacheDir.getFreeSpace() > internalCacheDir.getFreeSpace() ?
179
             cacheDir = externalCacheDir.getFreeSpace() > internalCacheDir.getFreeSpace() ?
161
                     externalCacheDir : internalCacheDir;
180
                     externalCacheDir : internalCacheDir;
162
         }
181
         }
163
-        String suffix = "." + ext;
164
-        File tmpFile = File.createTempFile(TEMP_FILE_PREFIX, suffix, cacheDir);
165
-        return tmpFile;
166
-    }
167
 
182
 
183
+        final String suffix = "." + ext;
184
+        return File.createTempFile(TEMP_FILE_PREFIX, suffix, cacheDir);
185
+    }
168
 }
186
 }