@SuppressWarnings("static-method")
 protected ImmutablePair<BitmapDrawable, Boolean> scaleImage(
     final ImmutablePair<Bitmap, Boolean> loadResult) {
   final Bitmap bitmap = loadResult.left;
   return ImmutablePair.of(
       bitmap != null ? ImageUtils.scaleBitmapToFitDisplay(bitmap) : null, loadResult.right);
 }
  private void loadImagePreview() {
    if (imageUri == null) {
      return;
    }
    if (!new File(imageUri.getPath()).exists()) {
      Log.i("Image does not exist");
      return;
    }

    final Bitmap bitmap = ImageUtils.readAndScaleImageToFitDisplay(imageUri.getPath());
    imagePreview.setImageBitmap(bitmap);
    imagePreview.setVisibility(View.VISIBLE);
  }
  private void selectImageFromCamera() {
    // create Intent to take a picture and return control to the calling application
    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

    imageUri = ImageUtils.getOutputImageFileUri(); // create a file to save the image
    if (imageUri == null) {
      showFailure();
      return;
    }
    intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); // set the image file name

    // start the image capture Intent
    startActivityForResult(intent, SELECT_NEW_IMAGE);
  }
  // Caches are loaded from disk on a computation scheduler to avoid using more threads than cores
  // while decoding
  // the image. Downloads happen on downloadScheduler, in parallel with image decoding.
  private Observable<BitmapDrawable> fetchDrawableUncached(final String url) {
    if (StringUtils.isBlank(url) || ImageUtils.containsPattern(url, BLOCKED)) {
      return Observable.just(ImageUtils.getTransparent1x1Drawable(resources));
    }

    // Explicit local file URLs are loaded from the filesystem regardless of their age. The IO part
    // is short
    // enough to make the whole operation on the computation scheduler.
    if (FileUtils.isFileUrl(url)) {
      return Observable.defer(
              new Func0<Observable<BitmapDrawable>>() {
                @Override
                public Observable<BitmapDrawable> call() {
                  final Bitmap bitmap = loadCachedImage(FileUtils.urlToFile(url), true).left;
                  return bitmap != null
                      ? Observable.just(ImageUtils.scaleBitmapToFitDisplay(bitmap))
                      : Observable.<BitmapDrawable>empty();
                }
              })
          .subscribeOn(AndroidRxUtils.computationScheduler);
    }

    final boolean shared = url.contains("/images/icons/icon_");
    final String pseudoGeocode = shared ? SHARED : geocode;

    return Observable.create(
        new OnSubscribe<BitmapDrawable>() {
          @Override
          public void call(final Subscriber<? super BitmapDrawable> subscriber) {
            subscription.add(subscriber);
            subscriber.add(
                AndroidRxUtils.computationScheduler
                    .createWorker()
                    .schedule(
                        new Action0() {
                          @Override
                          public void call() {
                            final ImmutablePair<BitmapDrawable, Boolean> loaded = loadFromDisk();
                            final BitmapDrawable bitmap = loaded.left;
                            if (loaded.right) {
                              subscriber.onNext(bitmap);
                              subscriber.onCompleted();
                              return;
                            }
                            if (bitmap != null && !onlySave) {
                              subscriber.onNext(bitmap);
                            }
                            AndroidRxUtils.networkScheduler
                                .createWorker()
                                .schedule(
                                    new Action0() {
                                      @Override
                                      public void call() {
                                        downloadAndSave(subscriber);
                                      }
                                    });
                          }
                        }));
          }

          private ImmutablePair<BitmapDrawable, Boolean> loadFromDisk() {
            final ImmutablePair<Bitmap, Boolean> loadResult =
                loadImageFromStorage(url, pseudoGeocode, shared);
            return scaleImage(loadResult);
          }

          private void downloadAndSave(final Subscriber<? super BitmapDrawable> subscriber) {
            final File file = LocalStorage.getStorageFile(pseudoGeocode, url, true, true);
            if (url.startsWith("data:image/")) {
              if (url.contains(";base64,")) {
                ImageUtils.decodeBase64ToFile(StringUtils.substringAfter(url, ";base64,"), file);
              } else {
                Log.e("HtmlImage.getDrawable: unable to decode non-base64 inline image");
                subscriber.onCompleted();
                return;
              }
            } else if (subscriber.isUnsubscribed() || downloadOrRefreshCopy(url, file)) {
              // The existing copy was fresh enough or we were unsubscribed earlier.
              subscriber.onCompleted();
              return;
            }
            if (onlySave) {
              subscriber.onCompleted();
              return;
            }
            AndroidRxUtils.computationScheduler
                .createWorker()
                .schedule(
                    new Action0() {
                      @Override
                      public void call() {
                        final ImmutablePair<BitmapDrawable, Boolean> loaded = loadFromDisk();
                        final BitmapDrawable image = loaded.left;
                        if (image != null) {
                          subscriber.onNext(image);
                        } else {
                          subscriber.onNext(
                              returnErrorImage
                                  ? new BitmapDrawable(
                                      resources,
                                      BitmapFactory.decodeResource(
                                          resources, R.drawable.image_not_loaded))
                                  : ImageUtils.getTransparent1x1Drawable(resources));
                        }
                        subscriber.onCompleted();
                      }
                    });
          }
        });
  }
 /**
  * Scales and writes the scaled image.
  *
  * @param filePath
  * @return the scaled image path, or <tt>null</tt> if the image cannot be decoded
  */
 @Nullable
 private String writeScaledImage(@NonNull final String filePath) {
   scaleChoiceIndex = scaleView.getSelectedItemPosition();
   final int maxXY = getResources().getIntArray(R.array.log_image_scale_values)[scaleChoiceIndex];
   return ImageUtils.readScaleAndWriteImage(filePath, maxXY);
 }