diff options
author | nicolasroard <nicolasroard@google.com> | 2013-08-11 13:55:29 -0700 |
---|---|---|
committer | nicolasroard <nicolasroard@google.com> | 2013-08-11 15:13:08 -0700 |
commit | 55d6abe58c3a7574a5d76c68ec5c21848848e399 (patch) | |
tree | a4b96fd123ab6a0c71a41366754329d89c15c54b /src | |
parent | fc4700c0e9f1804d4b61bd586f066172a25c7035 (diff) | |
download | android_packages_apps_Gallery2-55d6abe58c3a7574a5d76c68ec5c21848848e399.tar.gz android_packages_apps_Gallery2-55d6abe58c3a7574a5d76c68ec5c21848848e399.tar.bz2 android_packages_apps_Gallery2-55d6abe58c3a7574a5d76c68ec5c21848848e399.zip |
Fix export dialog (size export)
Change-Id: Ifa4bb6a990622bfc00f6b4fe4998417fec32e650
Diffstat (limited to 'src')
6 files changed, 188 insertions, 12 deletions
diff --git a/src/com/android/gallery3d/filtershow/imageshow/GeometryMathUtils.java b/src/com/android/gallery3d/filtershow/imageshow/GeometryMathUtils.java index 8358e1a55..1cefe085e 100644 --- a/src/com/android/gallery3d/filtershow/imageshow/GeometryMathUtils.java +++ b/src/com/android/gallery3d/filtershow/imageshow/GeometryMathUtils.java @@ -282,6 +282,15 @@ public final class GeometryMathUtils { unpackGeometry(outHolder, geometry); } + public static Rect finalGeometryRect(int width, int height, + Collection<FilterRepresentation> geometry) { + GeometryHolder holder = unpackGeometry(geometry); + RectF crop = getTrueCropRect(holder, width, height); + Rect frame = new Rect(); + crop.roundOut(frame); + return frame; + } + private static Bitmap applyFullGeometryMatrix(Bitmap image, GeometryHolder holder) { int width = image.getWidth(); int height = image.getHeight(); diff --git a/src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java b/src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java index e28cc356b..88e8d42e8 100644 --- a/src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java +++ b/src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java @@ -421,6 +421,10 @@ public class ImagePreset { return null; } + public Rect finalGeometryRect(int width, int height) { + return GeometryMathUtils.finalGeometryRect(width, height, getGeometryFilters()); + } + public Bitmap applyGeometry(Bitmap bitmap, FilterEnvironment environment) { // Apply any transform -- 90 rotate, flip, straighten, crop // Returns a new bitmap. diff --git a/src/com/android/gallery3d/filtershow/pipeline/ImageSavingTask.java b/src/com/android/gallery3d/filtershow/pipeline/ImageSavingTask.java index b760edd5a..c29376f6e 100644 --- a/src/com/android/gallery3d/filtershow/pipeline/ImageSavingTask.java +++ b/src/com/android/gallery3d/filtershow/pipeline/ImageSavingTask.java @@ -18,6 +18,7 @@ package com.android.gallery3d.filtershow.pipeline; import android.content.res.Resources; import android.graphics.Bitmap; +import android.graphics.Rect; import android.net.Uri; import com.android.gallery3d.filtershow.cache.ImageLoader; import com.android.gallery3d.filtershow.filters.FiltersManager; @@ -35,6 +36,7 @@ public class ImageSavingTask extends ProcessingTask { ImagePreset preset; boolean flatten; int quality; + float sizeFactor; } static class UpdateBitmap implements Update { @@ -55,7 +57,8 @@ public class ImageSavingTask extends ProcessingTask { } public void saveImage(Uri sourceUri, Uri selectedUri, - File destinationFile, ImagePreset preset, boolean flatten, int quality) { + File destinationFile, ImagePreset preset, boolean flatten, + int quality, float sizeFactor) { SaveRequest request = new SaveRequest(); request.sourceUri = sourceUri; request.selectedUri = selectedUri; @@ -63,6 +66,7 @@ public class ImageSavingTask extends ProcessingTask { request.preset = preset; request.flatten = flatten; request.quality = quality; + request.sizeFactor = sizeFactor; postRequest(request); } @@ -89,7 +93,8 @@ public class ImageSavingTask extends ProcessingTask { postUpdate(updateProgress); } }); - Uri uri = saveImage.processAndSaveImage(preset, !flatten, request.quality); + Uri uri = saveImage.processAndSaveImage(preset, !flatten, + request.quality, request.sizeFactor); URIResult result = new URIResult(); result.uri = uri; return result; diff --git a/src/com/android/gallery3d/filtershow/pipeline/ProcessingService.java b/src/com/android/gallery3d/filtershow/pipeline/ProcessingService.java index 4f736f868..518f232f9 100644 --- a/src/com/android/gallery3d/filtershow/pipeline/ProcessingService.java +++ b/src/com/android/gallery3d/filtershow/pipeline/ProcessingService.java @@ -32,7 +32,6 @@ import com.android.gallery3d.R; import com.android.gallery3d.filtershow.FilterShowActivity; import com.android.gallery3d.filtershow.filters.FiltersManager; import com.android.gallery3d.filtershow.filters.ImageFilter; -import com.android.gallery3d.filtershow.imageshow.MasterImage; import com.android.gallery3d.filtershow.tools.SaveImage; import java.io.File; @@ -51,6 +50,7 @@ public class ProcessingService extends Service { private static final String DESTINATION_FILE = "destinationFile"; private static final String SAVING = "saving"; private static final String FLATTEN = "flatten"; + private static final String SIZE_FACTOR = "sizeFactor"; private ProcessingTaskController mProcessingTaskController; private ImageSavingTask mImageSavingTask; @@ -139,13 +139,14 @@ public class ProcessingService extends Service { } public static Intent getSaveIntent(Context context, ImagePreset preset, File destination, - Uri selectedImageUri, Uri sourceImageUri, boolean doFlatten, int quality) { + Uri selectedImageUri, Uri sourceImageUri, boolean doFlatten, int quality, float sizeFactor) { Intent processIntent = new Intent(context, ProcessingService.class); processIntent.putExtra(ProcessingService.SOURCE_URI, sourceImageUri.toString()); processIntent.putExtra(ProcessingService.SELECTED_URI, selectedImageUri.toString()); processIntent.putExtra(ProcessingService.QUALITY, quality); + processIntent.putExtra(ProcessingService.SIZE_FACTOR, sizeFactor); if (destination != null) { processIntent.putExtra(ProcessingService.DESTINATION_FILE, destination.toString()); } @@ -192,6 +193,7 @@ public class ProcessingService extends Service { String selected = intent.getStringExtra(SELECTED_URI); String destination = intent.getStringExtra(DESTINATION_FILE); int quality = intent.getIntExtra(QUALITY, 100); + float sizeFactor = intent.getFloatExtra(SIZE_FACTOR, 1); boolean flatten = intent.getBooleanExtra(FLATTEN, false); Uri sourceUri = Uri.parse(source); Uri selectedUri = null; @@ -206,7 +208,8 @@ public class ProcessingService extends Service { preset.readJsonFromString(presetJson); mNeedsAlive = false; mSaving = true; - handleSaveRequest(sourceUri, selectedUri, destinationFile, preset, flatten, quality); + handleSaveRequest(sourceUri, selectedUri, destinationFile, preset, + flatten, quality, sizeFactor); } return START_REDELIVER_INTENT; } @@ -224,7 +227,8 @@ public class ProcessingService extends Service { } public void handleSaveRequest(Uri sourceUri, Uri selectedUri, - File destinationFile, ImagePreset preset, boolean flatten, int quality) { + File destinationFile, ImagePreset preset, boolean flatten, + int quality, float sizeFactor) { mNotifyMgr = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); mNotificationId++; @@ -242,7 +246,7 @@ public class ProcessingService extends Service { // Process the image mImageSavingTask.saveImage(sourceUri, selectedUri, destinationFile, - preset, flatten, quality); + preset, flatten, quality, sizeFactor); } public void updateNotificationWithBitmap(Bitmap bitmap) { diff --git a/src/com/android/gallery3d/filtershow/tools/SaveImage.java b/src/com/android/gallery3d/filtershow/tools/SaveImage.java index 83cbd0136..5aafbff33 100644 --- a/src/com/android/gallery3d/filtershow/tools/SaveImage.java +++ b/src/com/android/gallery3d/filtershow/tools/SaveImage.java @@ -310,7 +310,8 @@ public class SaveImage { } } - public Uri processAndSaveImage(ImagePreset preset, boolean doAuxBackup, int quality) { + public Uri processAndSaveImage(ImagePreset preset, boolean doAuxBackup, + int quality, float sizeFactor) { Uri uri = resetToOriginalImageIfNeeded(preset, doAuxBackup); if (uri != null) { @@ -341,6 +342,12 @@ public class SaveImage { if (bitmap == null) { return null; } + if (sizeFactor != 1f) { + // if we have a valid size + int w = (int) (bitmap.getWidth() * sizeFactor); + int h = (int) (bitmap.getHeight() * sizeFactor); + bitmap = Bitmap.createScaledBitmap(bitmap, w, h, true); + } updateProgress(); CachingPipeline pipeline = new CachingPipeline(FiltersManager.getManager(), "Saving"); @@ -458,7 +465,7 @@ public class SaveImage { Uri sourceImageUri = MasterImage.getImage().getUri(); Intent processIntent = ProcessingService.getSaveIntent(filterShowActivity, preset, - destination, selectedImageUri, sourceImageUri, false, 90); + destination, selectedImageUri, sourceImageUri, false, 90, 1f); filterShowActivity.startService(processIntent); diff --git a/src/com/android/gallery3d/filtershow/ui/ExportDialog.java b/src/com/android/gallery3d/filtershow/ui/ExportDialog.java index 4b30e7b18..b0046e1bb 100644 --- a/src/com/android/gallery3d/filtershow/ui/ExportDialog.java +++ b/src/com/android/gallery3d/filtershow/ui/ExportDialog.java @@ -17,40 +17,112 @@ package com.android.gallery3d.filtershow.ui; import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.Rect; import android.net.Uri; import android.os.Bundle; +import android.os.Handler; import android.support.v4.app.DialogFragment; +import android.text.Editable; +import android.text.TextWatcher; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.EditText; import android.widget.SeekBar; import android.widget.TextView; import com.android.gallery3d.R; import com.android.gallery3d.filtershow.FilterShowActivity; import com.android.gallery3d.filtershow.imageshow.MasterImage; +import com.android.gallery3d.filtershow.pipeline.ImagePreset; import com.android.gallery3d.filtershow.pipeline.ProcessingService; import com.android.gallery3d.filtershow.tools.SaveImage; +import java.io.ByteArrayOutputStream; import java.io.File; -public class ExportDialog extends DialogFragment implements View.OnClickListener, SeekBar.OnSeekBarChangeListener{ +public class ExportDialog extends DialogFragment implements View.OnClickListener, + SeekBar.OnSeekBarChangeListener { SeekBar mSeekBar; TextView mSeekVal; + EditText mWidthText; + EditText mHeightText; + TextView mEstimatedSize; + int mQuality = 95; + int mExportWidth = 0; + int mExportHeight = 0; + Rect mOriginalBounds; + int mCompressedSize; + Rect mCompressedBounds; + float mExportCompressionMargin = 1.1f; + float mRatio; String mSliderLabel; + boolean mEditing = false; + Handler mHandler; + int mUpdateDelay = 1000; + Runnable mUpdateRunnable = new Runnable() { + @Override + public void run() { + updateCompressionFactor(); + updateSize(); + } + }; + + private class Watcher implements TextWatcher { + private EditText mEditText; + Watcher(EditText text) { + mEditText = text; + } + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + } + + @Override + public void afterTextChanged(Editable s) { + textChanged(mEditText); + } + } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + mHandler = new Handler(getActivity().getMainLooper()); + View view = inflater.inflate(R.layout.filtershow_export_dialog, container); mSeekBar = (SeekBar) view.findViewById(R.id.qualitySeekBar); mSeekVal = (TextView) view.findViewById(R.id.qualityTextView); mSliderLabel = getString(R.string.quality) + ": "; + mSeekBar.setProgress(mQuality); mSeekVal.setText(mSliderLabel + mSeekBar.getProgress()); mSeekBar.setOnSeekBarChangeListener(this); + mWidthText = (EditText) view.findViewById(R.id.editableWidth); + mHeightText = (EditText) view.findViewById(R.id.editableHeight); + mEstimatedSize = (TextView) view.findViewById(R.id.estimadedSize); + + mOriginalBounds = MasterImage.getImage().getOriginalBounds(); + ImagePreset preset = MasterImage.getImage().getPreset(); + mOriginalBounds = preset.finalGeometryRect(mOriginalBounds.width(), + mOriginalBounds.height()); + mRatio = mOriginalBounds.width() / (float) mOriginalBounds.height(); + mWidthText.setText("" + mOriginalBounds.width()); + mHeightText.setText("" + mOriginalBounds.height()); + mExportWidth = mOriginalBounds.width(); + mExportHeight = mOriginalBounds.height(); + mWidthText.addTextChangedListener(new Watcher(mWidthText)); + mHeightText.addTextChangedListener(new Watcher(mHeightText)); + view.findViewById(R.id.cancel).setOnClickListener(this); view.findViewById(R.id.done).setOnClickListener(this); getDialog().setTitle(R.string.export_flattened); + + updateCompressionFactor(); + updateSize(); return view; } @@ -61,12 +133,19 @@ public class ExportDialog extends DialogFragment implements View.OnClickListener @Override public void onStartTrackingTouch(SeekBar arg0) { - // Do nothing + // Do nothing } @Override public void onProgressChanged(SeekBar arg0, int arg1, boolean arg2) { mSeekVal.setText(mSliderLabel + arg1); + mQuality = mSeekBar.getProgress(); + scheduleUpdateCompressionFactor(); + } + + private void scheduleUpdateCompressionFactor() { + mHandler.removeCallbacks(mUpdateRunnable); + mHandler.postDelayed(mUpdateRunnable, mUpdateDelay); } @Override @@ -79,12 +158,80 @@ public class ExportDialog extends DialogFragment implements View.OnClickListener FilterShowActivity activity = (FilterShowActivity) getActivity(); Uri sourceUri = MasterImage.getImage().getUri(); File dest = SaveImage.getNewFile(activity, sourceUri); + float scaleFactor = mExportWidth / (float) mOriginalBounds.width(); Intent processIntent = ProcessingService.getSaveIntent(activity, MasterImage .getImage().getPreset(), dest, activity.getSelectedImageUri(), sourceUri, - true, mSeekBar.getProgress()); + true, mSeekBar.getProgress(), scaleFactor); activity.startService(processIntent); dismiss(); break; } } + + public void updateCompressionFactor() { + Bitmap bitmap = MasterImage.getImage().getFilteredImage(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + bitmap.compress(Bitmap.CompressFormat.JPEG, mQuality, out); + mCompressedSize = out.size(); + mCompressedBounds = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()); + } + + public void updateSize() { + if (mCompressedBounds == null) { + return; + } + // This is a rough estimate of the final save size. There's some loose correlation + // between a compressed jpeg and a larger version of it in function of the image + // area. Not a perfect estimate by far. + float originalArea = mCompressedBounds.width() * mCompressedBounds.height(); + float newArea = mExportWidth * mExportHeight; + float factor = originalArea / (float) mCompressedSize; + float compressedSize = newArea / factor; + compressedSize *= mExportCompressionMargin; + float size = compressedSize / 1024.f / 1024.f; + size = ((int) (size * 100)) / 100f; + String estimatedSize = "" + size + " Mb"; + mEstimatedSize.setText(estimatedSize); + } + + private void textChanged(EditText text) { + if (mEditing) { + return; + } + mEditing = true; + int width = 0; + int height = 0; + if (text.getId() == R.id.editableWidth) { + if (mWidthText.getText() != null) { + String value = String.valueOf(mWidthText.getText()); + if (value.length() > 0) { + width = Integer.parseInt(value); + if (width > mOriginalBounds.width()) { + width = mOriginalBounds.width(); + mWidthText.setText("" + width); + } + height = (int) (width / mRatio); + } + mHeightText.setText("" + height); + } + } else if (text.getId() == R.id.editableHeight) { + if (mHeightText.getText() != null) { + String value = String.valueOf(mHeightText.getText()); + if (value.length() > 0) { + height = Integer.parseInt(value); + if (height > mOriginalBounds.height()) { + height = mOriginalBounds.height(); + mHeightText.setText("" + height); + } + width = (int) (height * mRatio); + } + mWidthText.setText("" + width); + } + } + mExportWidth = width; + mExportHeight = height; + updateSize(); + mEditing = false; + } + } |