<NME> ImageSelectActivity.java
<BEF> package cgeo.geocaching;

import cgeo.geocaching.activity.AbstractActivity;
import cgeo.geocaching.compatibility.Compatibility;
import cgeo.geocaching.utils.Log;

import org.apache.commons.lang3.StringUtils;
import cgeo.geocaching.storage.DataStore;
import cgeo.geocaching.ui.ImageActivityHelper;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.provider.MediaStore.MediaColumns;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;

import java.io.File;
import java.text.SimpleDateFormat;
public class ImageSelectActivity extends AbstractActionBarActivity {
    private ImageselectActivityBinding binding;

    private final TextSpinner<Integer> imageScale = new TextSpinner<>();
    static final String EXTRAS_CAPTION = "caption";
    static final String EXTRAS_DESCRIPTION = "description";
    static final String EXTRAS_URI_AS_STRING = "uri";

    private static final String SAVED_STATE_IMAGE_CAPTION = "cgeo.geocaching.saved_state_image_caption";
    private static final String SAVED_STATE_IMAGE_DESCRIPTION = "cgeo.geocaching.saved_state_image_description";
    private static final String SAVED_STATE_IMAGE_URI = "cgeo.geocaching.saved_state_image_uri";

    private static final int SELECT_NEW_IMAGE = 1;
    private static final int SELECT_STORED_IMAGE = 2;

    private EditText captionView;
    private EditText descriptionView;

    // Data to be saved while reconfiguring
    private String imageCaption;
    private String imageDescription;
    private Uri imageUri;

    public ImageSelectActivity() {
    @Override
    public void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setThemeAndContentView(R.layout.imageselect_activity);
        binding = ImageselectActivityBinding.bind(findViewById(R.id.imageselect_activity_viewroot));

        imageScale.setSpinner(findViewById(R.id.logImageScale))
                .setValues(Arrays.asList(ArrayUtils.toObject(getResources().getIntArray(R.array.log_image_scale_values))))
        setContentView(R.layout.visit_image);
        setTitle(res.getString(R.string.log_image));

        imageCaption = "";
        imageDescription = "";
        imageUri = Uri.EMPTY;
            imageIndex = extras.getInt(Intents.EXTRA_INDEX, -1);
            maxImageUploadSize = extras.getLong(Intents.EXTRA_MAX_IMAGE_UPLOAD_SIZE);
            imageCaptionMandatory = extras.getBoolean(Intents.EXTRA_IMAGE_CAPTION_MANDATORY);
            geocode = extras.getString(Intents.EXTRA_GEOCODE);
            imageCaption = extras.getString(EXTRAS_CAPTION);
            imageDescription = extras.getString(EXTRAS_DESCRIPTION);
            imageUri = Uri.parse(extras.getString(EXTRAS_URI_AS_STRING));
        }

        // Restore previous state
                if (cache != null) {
            imageCaption = savedInstanceState.getString(SAVED_STATE_IMAGE_CAPTION);
            imageDescription = savedInstanceState.getString(SAVED_STATE_IMAGE_DESCRIPTION);
            imageUri = Uri.parse(savedInstanceState.getString(SAVED_STATE_IMAGE_URI));
        }

        final Button cameraButton = (Button) findViewById(R.id.camera);
        // Restore previous state
        if (savedInstanceState != null) {
            image = savedInstanceState.getParcelable(SAVED_STATE_IMAGE);
            originalImage = savedInstanceState.getParcelable(SAVED_STATE_ORIGINAL_IMAGE);
            imageIndex = savedInstanceState.getInt(SAVED_STATE_IMAGE_INDEX, -1);
            imageScale.set(savedInstanceState.getInt(SAVED_STATE_IMAGE_SCALE));
            maxImageUploadSize = savedInstanceState.getLong(SAVED_STATE_MAX_IMAGE_UPLOAD_SIZE);
            imageCaptionMandatory = savedInstanceState.getBoolean(SAVED_STATE_IMAGE_CAPTION_MANDATORY);
            geocode = savedInstanceState.getString(SAVED_STATE_GEOCODE);
            imageActivityHelper.setState(savedInstanceState.getBundle(SAVED_STATE_IMAGEHELPER));
        }

        if (image == null) {
            image = Image.NONE;
            imageScale.set(Settings.getLogImageScale());
        } else {
            imageScale.set(image.targetScale);
        }
        updateScaleValueDisplay();

        binding.camera.setOnClickListener(view -> selectImageFromCamera());
        binding.stored.setOnClickListener(view -> selectImageFromStorage());

        if (image.hasTitle()) {
            descriptionView.setText(imageDescription);
        }

        final Button saveButton = (Button) findViewById(R.id.save);
        saveButton.setOnClickListener(new View.OnClickListener() {

        syncEditTexts();
        outState.putParcelable(SAVED_STATE_IMAGE, image);
        outState.putParcelable(SAVED_STATE_ORIGINAL_IMAGE, originalImage);
        outState.putInt(SAVED_STATE_IMAGE_INDEX, imageIndex);
        outState.putInt(SAVED_STATE_IMAGE_SCALE, imageScale.get());
        outState.putLong(SAVED_STATE_MAX_IMAGE_UPLOAD_SIZE, maxImageUploadSize);
        outState.putBoolean(SAVED_STATE_IMAGE_CAPTION_MANDATORY, imageCaptionMandatory);
        outState.putString(SAVED_STATE_GEOCODE, geocode);
        outState.putBundle(SAVED_STATE_IMAGEHELPER, imageActivityHelper.getState());
    }

    public void saveImageInfo(final boolean saveInfo, final boolean deleteImage) {
        if (saveInfo) {

            final Intent intent = new Intent();
            syncEditTexts();
            intent.putExtra(Intents.EXTRA_IMAGE, image);
            intent.putExtra(Intents.EXTRA_INDEX, imageIndex);
            //"originalImage" is now obsolete. But we never delete originalImage (in case log gets not stored)
            setResult(RESULT_OK, intent);
            finish();
        } else if (deleteImage) {
        outState.putString(SAVED_STATE_IMAGE_CAPTION, imageCaption);
        outState.putString(SAVED_STATE_IMAGE_DESCRIPTION, imageDescription);
        outState.putString(SAVED_STATE_IMAGE_URI, imageUri != null ? imageUri.getPath() : StringUtils.EMPTY);
    }

    public void saveImageInfo(boolean saveInfo) {
        if (saveInfo) {
            Intent intent = new Intent();
            syncEditTexts();
            intent.putExtra(EXTRAS_CAPTION, imageCaption);
            intent.putExtra(EXTRAS_DESCRIPTION, imageDescription);
            intent.putExtra(EXTRAS_URI_AS_STRING, imageUri.toString());

            setResult(RESULT_OK, intent);
        } else {
                .setDescription(binding.description.getText().toString())
                .build();
    }

    private void selectImageFromCamera() {
        imageActivityHelper.getImageFromCamera(this.geocode, false, null);
    private void syncEditTexts() {
        imageCaption = captionView.getText().toString();
        imageDescription = descriptionView.getText().toString();
    }

    private void selectImageFromCamera() {
        if (img != null && img.getUri() != null && (originalImage == null || !img.getUri().equals(originalImage.getUri()))) {
            return ImageUtils.deleteImage(img.getUri());
        }
        return false;
    }

    @Override
    protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
        super.onActivityResult(requestCode, resultCode, data);  // call super to make lint happy
        imageActivityHelper.onActivityResult(requestCode, resultCode, data);
    }

    private void loadImagePreview() {
        ImageActivityHelper.displayImageAsync(image, binding.imagePreview);
        updateScaleValueDisplay();
    }

    private void updateScaleValueDisplay() {
        int width = -1;
        int height = -1;
        if (image != null) {
            final ImmutablePair<Integer, Integer> size = ImageUtils.getImageSize(image.getUri());
            if (size != null) {
                width = size.left;
                height = size.right;
            }
        }
        updateScaleValueDisplayIntern(width, height);
    }

    private void updateScaleValueDisplayIntern(final int width, final int height) {
        imageScale.setDisplayMapper(scaleSize -> {
            if (width < 0 || height < 0) {
                return scaleSize < 0 ? getResources().getString(R.string.log_image_scale_option_noscaling) :
                        getResources().getString(R.string.log_image_scale_option_entry_noimage, scaleSize);
            }

            final ImmutableTriple<Integer, Integer, Boolean> scales = ImageUtils.calculateScaledImageSizes(width, height, scaleSize, scaleSize);
            String displayValue = getResources().getString(R.string.log_image_scale_option_entry, scales.left, scales.middle);
            if (scaleSize < 0) {
                displayValue += " (" + getResources().getString(R.string.log_image_scale_option_noscaling) + ")";
            }
            return displayValue;
        });

    }
}
        loadImagePreview();
    }

    private void showFailure() {
        showToast(getResources().getString(R.string.err_aquire_image_failed));
    }

<MSG> fixes #2533 - added image scaling

modifications suggested by Bananeweizen

next recommended changes and scaling now on leaving ImageSelectActivity

fixed wrong spelling

<DFF> @@ -2,6 +2,7 @@ package cgeo.geocaching;
 
 import cgeo.geocaching.activity.AbstractActivity;
 import cgeo.geocaching.compatibility.Compatibility;
+import cgeo.geocaching.utils.ImageHelper;
 import cgeo.geocaching.utils.Log;
 
 import org.apache.commons.lang3.StringUtils;
@@ -10,14 +11,18 @@ import android.content.Intent;
 import android.database.Cursor;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
+import android.graphics.drawable.BitmapDrawable;
 import android.net.Uri;
 import android.os.Bundle;
 import android.provider.MediaStore;
 import android.provider.MediaStore.MediaColumns;
 import android.view.View;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemSelectedListener;
 import android.widget.Button;
 import android.widget.EditText;
 import android.widget.ImageView;
+import android.widget.Spinner;
 
 import java.io.File;
 import java.text.SimpleDateFormat;
@@ -28,20 +33,24 @@ public class ImageSelectActivity extends AbstractActivity {
     static final String EXTRAS_CAPTION = "caption";
     static final String EXTRAS_DESCRIPTION = "description";
     static final String EXTRAS_URI_AS_STRING = "uri";
+    static final String EXTRAS_SCALE = "scale";
 
     private static final String SAVED_STATE_IMAGE_CAPTION = "cgeo.geocaching.saved_state_image_caption";
     private static final String SAVED_STATE_IMAGE_DESCRIPTION = "cgeo.geocaching.saved_state_image_description";
     private static final String SAVED_STATE_IMAGE_URI = "cgeo.geocaching.saved_state_image_uri";
+    private static final String SAVED_STATE_IMAGE_SCALE = "cgeo.geocaching.saved_state_image_scale";
 
     private static final int SELECT_NEW_IMAGE = 1;
     private static final int SELECT_STORED_IMAGE = 2;
 
     private EditText captionView;
     private EditText descriptionView;
+    private Spinner scaleView;
 
     // Data to be saved while reconfiguring
     private String imageCaption;
     private String imageDescription;
+    private int scaleChoiceIndex;
     private Uri imageUri;
 
     public ImageSelectActivity() {
@@ -56,6 +65,7 @@ public class ImageSelectActivity extends AbstractActivity {
         setContentView(R.layout.visit_image);
         setTitle(res.getString(R.string.log_image));
 
+        scaleChoiceIndex = Settings.getLogImageScale();
         imageCaption = "";
         imageDescription = "";
         imageUri = Uri.EMPTY;
@@ -66,6 +76,7 @@ public class ImageSelectActivity extends AbstractActivity {
             imageCaption = extras.getString(EXTRAS_CAPTION);
             imageDescription = extras.getString(EXTRAS_DESCRIPTION);
             imageUri = Uri.parse(extras.getString(EXTRAS_URI_AS_STRING));
+            scaleChoiceIndex = extras.getInt(EXTRAS_SCALE, scaleChoiceIndex);
         }
 
         // Restore previous state
@@ -73,6 +84,7 @@ public class ImageSelectActivity extends AbstractActivity {
             imageCaption = savedInstanceState.getString(SAVED_STATE_IMAGE_CAPTION);
             imageDescription = savedInstanceState.getString(SAVED_STATE_IMAGE_DESCRIPTION);
             imageUri = Uri.parse(savedInstanceState.getString(SAVED_STATE_IMAGE_URI));
+            scaleChoiceIndex = savedInstanceState.getInt(SAVED_STATE_IMAGE_SCALE);
         }
 
         final Button cameraButton = (Button) findViewById(R.id.camera);
@@ -103,6 +115,20 @@ public class ImageSelectActivity extends AbstractActivity {
             descriptionView.setText(imageDescription);
         }
 
+        scaleView = (Spinner) findViewById(R.id.logImageScale);
+        scaleView.setSelection(scaleChoiceIndex);
+        scaleView.setOnItemSelectedListener(new OnItemSelectedListener() {
+            @Override
+            public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
+                scaleChoiceIndex = scaleView.getSelectedItemPosition();
+                Settings.setLogImageScale(scaleChoiceIndex);
+            }
+
+            @Override
+            public void onNothingSelected(AdapterView<?> arg0) {
+            }
+        });
+
         final Button saveButton = (Button) findViewById(R.id.save);
         saveButton.setOnClickListener(new View.OnClickListener() {
 
@@ -131,15 +157,19 @@ public class ImageSelectActivity extends AbstractActivity {
         outState.putString(SAVED_STATE_IMAGE_CAPTION, imageCaption);
         outState.putString(SAVED_STATE_IMAGE_DESCRIPTION, imageDescription);
         outState.putString(SAVED_STATE_IMAGE_URI, imageUri != null ? imageUri.getPath() : StringUtils.EMPTY);
+        outState.putInt(SAVED_STATE_IMAGE_SCALE, scaleChoiceIndex);
     }
 
     public void saveImageInfo(boolean saveInfo) {
         if (saveInfo) {
+            String filename = writeScaledImage(imageUri.getPath());
+            imageUri = Uri.parse(filename);
             Intent intent = new Intent();
             syncEditTexts();
             intent.putExtra(EXTRAS_CAPTION, imageCaption);
             intent.putExtra(EXTRAS_DESCRIPTION, imageDescription);
             intent.putExtra(EXTRAS_URI_AS_STRING, imageUri.toString());
+            intent.putExtra(EXTRAS_SCALE, scaleChoiceIndex);
 
             setResult(RESULT_OK, intent);
         } else {
@@ -152,6 +182,7 @@ public class ImageSelectActivity extends AbstractActivity {
     private void syncEditTexts() {
         imageCaption = captionView.getText().toString();
         imageDescription = descriptionView.getText().toString();
+        scaleChoiceIndex = scaleView.getSelectedItemPosition();
     }
 
     private void selectImageFromCamera() {
@@ -231,6 +262,25 @@ public class ImageSelectActivity extends AbstractActivity {
         loadImagePreview();
     }
 
+    /**
+     * Scales and writes the scaled image.
+     *
+     * @param filePath
+     * @return
+     */
+    private String writeScaledImage(String filePath) {
+        Bitmap image = BitmapFactory.decodeFile(filePath);
+        scaleChoiceIndex = scaleView.getSelectedItemPosition();
+        int maxXY = getResources().getIntArray(R.array.log_image_scale_values)[scaleChoiceIndex];
+        String uploadFilename = filePath;
+        if (maxXY > 0) {
+            BitmapDrawable scaledImage = ImageHelper.scaleBitmapTo(image, maxXY, maxXY);
+            uploadFilename = getOutputImageFile().getPath();
+            ImageHelper.storeBitmap(scaledImage.getBitmap(), Bitmap.CompressFormat.JPEG, 75, uploadFilename);
+        }
+        return uploadFilename;
+    }
+
     private void showFailure() {
         showToast(getResources().getString(R.string.err_aquire_image_failed));
     }

fixes #2533 - added image scaling