ImageImportProcessor implements FileImportProcessor { @NonNull @Override public Single<File> process(@NonNull final Uri uri) { return Single.create(emitter -> { InputStream inputStream = null; try { inputStream = mContentResolver.openInputStream(uri); if (inputStream != null) { final int scale = getImageScaleFactor(uri); final BitmapFactory.Options smallerOpts = new BitmapFactory.Options(); smallerOpts.inSampleSize = scale; Bitmap bitmap = BitmapFactory.decodeStream(inputStream, null, smallerOpts); if (smallerOpts.outHeight <= 0 && smallerOpts.outWidth <= 0) { emitter.onError(new InvalidImageException("Looks like selected file is not an image")); return; } if (mPreferences.get(UserPreference.Camera.SaveImagesInGrayScale)) { bitmap = ImageUtils.convertToGrayScale(bitmap); } if (mPreferences.get(UserPreference.Camera.AutomaticallyRotateImages)) { Logger.debug(ImageImportProcessor.this, "Configured for auto-rotation. Attempting to determine the orientation"); int orientation = getOrientationFromMediaStore(uri); if (orientation == ExifInterface.ORIENTATION_UNDEFINED) { Logger.warn(ImageImportProcessor.this, "Failed to fetch orientation information from the content store. Trying from Exif."); InputStream exifInputStream = null; try { exifInputStream = mContentResolver.openInputStream(uri); if (exifInputStream != null) { final ExifInterface exif = new ExifInterface(exifInputStream); orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED); Logger.info(ImageImportProcessor.this, "Read exif orientation as {}", orientation); } } catch (IOException e) { Logger.error(ImageImportProcessor.this, "An Exif parsing exception occurred", e); } finally { StorageManager.closeQuietly(exifInputStream); } } if (orientation != ExifInterface.ORIENTATION_UNDEFINED) { Logger.info(ImageImportProcessor.this, "Image orientation determined as {}. Rotating...", orientation); bitmap = ImageUtils.rotateBitmap(bitmap, orientation); } else { Logger.warn(ImageImportProcessor.this, "Indeterminate orientation. Skipping rotation"); } } else { Logger.info(ImageImportProcessor.this, "Image import rotation is disabled. Ignoring..."); } if (bitmap != null) { final File destination = mStorageManner.getFile(mTrip.getDirectory(), System.currentTimeMillis() + ".jpg"); final Bitmap.CompressFormat compressFormat = Bitmap.CompressFormat.JPEG; if (!mStorageManner.writeBitmap(Uri.fromFile(destination), bitmap, compressFormat, COMPRESSION_QUALITY)) { Logger.error(ImageImportProcessor.this, "Failed to write the image data. Aborting"); emitter.onError(new IOException("Failed to write the image data. Aborting")); } else { Logger.info(ImageImportProcessor.this, "Successfully saved the image to {}.", destination); emitter.onSuccess(destination); } } } else { emitter.onError(new FileNotFoundException()); } } catch (IOException e) { emitter.onError(e); } finally { StorageManager.closeQuietly(inputStream); } }); } ImageImportProcessor(@NonNull Trip trip, @NonNull StorageManager storageManager, @NonNull UserPreferenceManager preferences, @NonNull Context context);  ImageImportProcessor(@NonNull Trip trip, @NonNull StorageManager storageManager, @NonNull UserPreferenceManager preferences, @NonNull Context context, @NonNull ContentResolver contentResolver); @NonNull @Override Single<File> process(@NonNull final Uri uri);  }
@Test public void importUriWithNullStream() throws Exception { final Uri uri = mock(Uri.class); when(contentResolver.openInputStream(uri)).thenReturn(null); importProcessor.process(uri) .test() .assertError(FileNotFoundException.class); }
@Test public void importUriThrowsFileNotFoundException() throws Exception { final Uri uri = mock(Uri.class); when(contentResolver.openInputStream(uri)).thenThrow(new FileNotFoundException("test")); importProcessor.process(uri) .test() .assertError(FileNotFoundException.class); }
@Test public void importUriWhenSaveFails() throws Exception { final Uri uri = Uri.fromFile(destination); configureUriForStream(uri, SAMPLE_JPG); when(preferences.get(UserPreference.Camera.AutomaticallyRotateImages)).thenReturn(false); when(storageManager.writeBitmap(any(Uri.class), bitmapCaptor.capture(), eq(Bitmap.CompressFormat.JPEG), eq(ImageImportProcessor.COMPRESSION_QUALITY))).thenReturn(false); importProcessor.process(uri) .test() .assertError(IOException.class); }
@Test public void importUriWithoutAlterations() throws Exception { final Uri uri = Uri.fromFile(destination); configureUriForStream(uri, SAMPLE_JPG); when(preferences.get(UserPreference.Camera.AutomaticallyRotateImages)).thenReturn(false); when(storageManager.writeBitmap(any(Uri.class), bitmapCaptor.capture(), eq(Bitmap.CompressFormat.JPEG), eq(ImageImportProcessor.COMPRESSION_QUALITY))).thenReturn(true); importProcessor.process(uri) .test() .assertValue(destination) .assertComplete(); final Bitmap bitmap = bitmapCaptor.getValue(); assertNotNull(bitmap); assertEquals(550, bitmap.getWidth()); assertEquals(400, bitmap.getHeight()); }
@Test public void importExifUriWithoutAlterations() throws Exception { final Uri uri = Uri.fromFile(destination); configureUriForStream(uri, SAMPLE_JPG_WITH_EXIF); when(preferences.get(UserPreference.Camera.AutomaticallyRotateImages)).thenReturn(false); when(storageManager.writeBitmap(any(Uri.class), bitmapCaptor.capture(), eq(Bitmap.CompressFormat.JPEG), eq(ImageImportProcessor.COMPRESSION_QUALITY))).thenReturn(true); importProcessor.process(uri) .test() .assertValue(destination) .assertComplete(); final Bitmap bitmap = bitmapCaptor.getValue(); assertNotNull(bitmap); assertEquals(400, bitmap.getWidth()); assertEquals(550, bitmap.getHeight()); }
@Test public void importUriScalesDownSizes() throws Exception { final Uri uri = Uri.fromFile(destination); configureUriForStream(uri, SAMPLE_JPG_BIG); when(preferences.get(UserPreference.Camera.AutomaticallyRotateImages)).thenReturn(false); when(storageManager.writeBitmap(any(Uri.class), bitmapCaptor.capture(), eq(Bitmap.CompressFormat.JPEG), eq(ImageImportProcessor.COMPRESSION_QUALITY))).thenReturn(true); importProcessor.process(uri) .test() .assertValue(destination) .assertComplete(); final Bitmap bitmap = bitmapCaptor.getValue(); assertNotNull(bitmap); assertEquals(1100, bitmap.getWidth()); assertEquals(800, bitmap.getHeight()); }
@Test public void importUriWithRotateOn() throws Exception { final Uri uri = Uri.fromFile(destination); configureUriForStream(uri, SAMPLE_JPG); when(preferences.get(UserPreference.Camera.AutomaticallyRotateImages)).thenReturn(true); when(storageManager.writeBitmap(any(Uri.class), bitmapCaptor.capture(), eq(Bitmap.CompressFormat.JPEG), eq(ImageImportProcessor.COMPRESSION_QUALITY))).thenReturn(true); importProcessor.process(uri) .test() .assertValue(destination) .assertComplete(); final Bitmap bitmap = bitmapCaptor.getValue(); assertNotNull(bitmap); assertEquals(550, bitmap.getWidth()); assertEquals(400, bitmap.getHeight()); }
@Test public void importExifUriWithRotateOn() throws Exception { final Uri uri = Uri.fromFile(destination); configureUriForStream(uri, SAMPLE_JPG_WITH_EXIF); when(preferences.get(UserPreference.Camera.AutomaticallyRotateImages)).thenReturn(true); when(storageManager.writeBitmap(any(Uri.class), bitmapCaptor.capture(), eq(Bitmap.CompressFormat.JPEG), eq(ImageImportProcessor.COMPRESSION_QUALITY))).thenReturn(true); importProcessor.process(uri) .test() .assertValue(destination) .assertComplete(); final Bitmap bitmap = bitmapCaptor.getValue(); assertNotNull(bitmap); final ShadowBitmap shadowBitmap = Shadows.shadowOf(bitmap); final ShadowMatrix shadowMatrix = Shadows.shadowOf(shadowBitmap.getCreatedFromMatrix()); assertEquals(shadowMatrix.getSetOperations().get(ShadowMatrix.ROTATE), "90.0"); }