From 8f0065ba9aefe1c6b53c941b6d2438b7b9cb2c66 Mon Sep 17 00:00:00 2001 From: Ruben Brunk Date: Thu, 1 Aug 2013 19:05:18 -0700 Subject: Add quality selector to export. - Adds the option to change the quality of the jpeg compression when flattening an exported bitmap. Change-Id: I252913fc15ff32a0fcff683edb5b33e17b5daac4 --- .../gallery3d/filtershow/FilterShowActivity.java | 28 +++---- .../filtershow/pipeline/ImageSavingTask.java | 6 +- .../filtershow/pipeline/ProcessingService.java | 12 ++- .../gallery3d/filtershow/tools/SaveImage.java | 22 ++++-- .../gallery3d/filtershow/ui/ExportDialog.java | 90 ++++++++++++++++++++++ 5 files changed, 132 insertions(+), 26 deletions(-) create mode 100644 src/com/android/gallery3d/filtershow/ui/ExportDialog.java (limited to 'src') diff --git a/src/com/android/gallery3d/filtershow/FilterShowActivity.java b/src/com/android/gallery3d/filtershow/FilterShowActivity.java index ab508b6f2..4700fccfe 100644 --- a/src/com/android/gallery3d/filtershow/FilterShowActivity.java +++ b/src/com/android/gallery3d/filtershow/FilterShowActivity.java @@ -59,22 +59,19 @@ import android.widget.Toast; import com.android.gallery3d.R; import com.android.gallery3d.app.PhotoPage; import com.android.gallery3d.data.LocalAlbum; -import com.android.gallery3d.filtershow.editors.EditorChanSat; -import com.android.gallery3d.filtershow.editors.EditorGrad; -import com.android.gallery3d.filtershow.data.FilterStackSource; -import com.android.gallery3d.filtershow.data.UserPresetsManager; -import com.android.gallery3d.filtershow.filters.FilterUserPresetRepresentation; -import com.android.gallery3d.filtershow.pipeline.CachingPipeline; import com.android.gallery3d.filtershow.cache.ImageLoader; import com.android.gallery3d.filtershow.category.Action; import com.android.gallery3d.filtershow.category.CategoryAdapter; import com.android.gallery3d.filtershow.category.MainPanel; +import com.android.gallery3d.filtershow.data.UserPresetsManager; import com.android.gallery3d.filtershow.editors.BasicEditor; import com.android.gallery3d.filtershow.editors.Editor; +import com.android.gallery3d.filtershow.editors.EditorChanSat; import com.android.gallery3d.filtershow.editors.EditorCrop; import com.android.gallery3d.filtershow.editors.EditorDraw; -import com.android.gallery3d.filtershow.editors.EditorMirror; +import com.android.gallery3d.filtershow.editors.EditorGrad; import com.android.gallery3d.filtershow.editors.EditorManager; +import com.android.gallery3d.filtershow.editors.EditorMirror; import com.android.gallery3d.filtershow.editors.EditorPanel; import com.android.gallery3d.filtershow.editors.EditorRedEye; import com.android.gallery3d.filtershow.editors.EditorRotate; @@ -82,14 +79,15 @@ import com.android.gallery3d.filtershow.editors.EditorStraighten; import com.android.gallery3d.filtershow.editors.EditorTinyPlanet; import com.android.gallery3d.filtershow.editors.ImageOnlyEditor; import com.android.gallery3d.filtershow.filters.FilterRepresentation; +import com.android.gallery3d.filtershow.filters.FilterUserPresetRepresentation; import com.android.gallery3d.filtershow.filters.FiltersManager; import com.android.gallery3d.filtershow.filters.ImageFilter; -import com.android.gallery3d.filtershow.history.HistoryManager; import com.android.gallery3d.filtershow.history.HistoryItem; -import com.android.gallery3d.filtershow.imageshow.ImageCrop; +import com.android.gallery3d.filtershow.history.HistoryManager; import com.android.gallery3d.filtershow.imageshow.ImageShow; import com.android.gallery3d.filtershow.imageshow.MasterImage; import com.android.gallery3d.filtershow.imageshow.Spline; +import com.android.gallery3d.filtershow.pipeline.CachingPipeline; import com.android.gallery3d.filtershow.pipeline.ImagePreset; import com.android.gallery3d.filtershow.pipeline.ProcessingService; import com.android.gallery3d.filtershow.presets.PresetManagementDialog; @@ -99,6 +97,7 @@ import com.android.gallery3d.filtershow.state.StateAdapter; import com.android.gallery3d.filtershow.tools.SaveImage; import com.android.gallery3d.filtershow.tools.XmpPresets; import com.android.gallery3d.filtershow.tools.XmpPresets.XMresults; +import com.android.gallery3d.filtershow.ui.ExportDialog; import com.android.gallery3d.filtershow.ui.FramedTextButton; import com.android.gallery3d.util.GalleryUtils; import com.android.gallery3d.util.UsageStatistics; @@ -821,11 +820,7 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL return true; } case R.id.exportFlattenButton: { - Uri sourceUri = MasterImage.getImage().getUri(); - File dest = SaveImage.getNewFile(this, sourceUri); - Intent processIntent = ProcessingService.getSaveIntent(this, MasterImage.getImage() - .getPreset(), dest, getSelectedImageUri(), sourceUri, true); - startService(processIntent); + showExportOptionsDialog(); return true; } case android.R.id.home: { @@ -845,6 +840,11 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL dialog.show(getSupportFragmentManager(), "NoticeDialogFragment"); } + private void showExportOptionsDialog() { + DialogFragment dialog = new ExportDialog(); + dialog.show(getSupportFragmentManager(), "ExportDialogFragment"); + } + public void updateUserPresetsFromAdapter(UserPresetsAdapter adapter) { ArrayList representations = adapter.getDeletedRepresentations(); diff --git a/src/com/android/gallery3d/filtershow/pipeline/ImageSavingTask.java b/src/com/android/gallery3d/filtershow/pipeline/ImageSavingTask.java index ebd3ed91b..b760edd5a 100644 --- a/src/com/android/gallery3d/filtershow/pipeline/ImageSavingTask.java +++ b/src/com/android/gallery3d/filtershow/pipeline/ImageSavingTask.java @@ -34,6 +34,7 @@ public class ImageSavingTask extends ProcessingTask { File destinationFile; ImagePreset preset; boolean flatten; + int quality; } static class UpdateBitmap implements Update { @@ -54,13 +55,14 @@ public class ImageSavingTask extends ProcessingTask { } public void saveImage(Uri sourceUri, Uri selectedUri, - File destinationFile, ImagePreset preset, boolean flatten) { + File destinationFile, ImagePreset preset, boolean flatten, int quality) { SaveRequest request = new SaveRequest(); request.sourceUri = sourceUri; request.selectedUri = selectedUri; request.destinationFile = destinationFile; request.preset = preset; request.flatten = flatten; + request.quality = quality; postRequest(request); } @@ -87,7 +89,7 @@ public class ImageSavingTask extends ProcessingTask { postUpdate(updateProgress); } }); - Uri uri = saveImage.processAndSaveImage(preset, !flatten); + Uri uri = saveImage.processAndSaveImage(preset, !flatten, request.quality); 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 f0f3e5399..d0504d11f 100644 --- a/src/com/android/gallery3d/filtershow/pipeline/ProcessingService.java +++ b/src/com/android/gallery3d/filtershow/pipeline/ProcessingService.java @@ -44,6 +44,7 @@ public class ProcessingService extends Service { private Notification.Builder mBuilder = null; private static final String PRESET = "preset"; + private static final String QUALITY = "quality"; private static final String SOURCE_URI = "sourceUri"; private static final String SELECTED_URI = "selectedUri"; private static final String DESTINATION_FILE = "destinationFile"; @@ -117,12 +118,13 @@ public class ProcessingService extends Service { } public static Intent getSaveIntent(Context context, ImagePreset preset, File destination, - Uri selectedImageUri, Uri sourceImageUri, boolean doFlatten) { + Uri selectedImageUri, Uri sourceImageUri, boolean doFlatten, int quality) { 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); if (destination != null) { processIntent.putExtra(ProcessingService.DESTINATION_FILE, destination.toString()); } @@ -166,6 +168,7 @@ public class ProcessingService extends Service { String source = intent.getStringExtra(SOURCE_URI); String selected = intent.getStringExtra(SELECTED_URI); String destination = intent.getStringExtra(DESTINATION_FILE); + int quality = intent.getIntExtra(QUALITY, 100); boolean flatten = intent.getBooleanExtra(FLATTEN, false); Uri sourceUri = Uri.parse(source); Uri selectedUri = null; @@ -180,7 +183,7 @@ public class ProcessingService extends Service { preset.readJsonFromString(presetJson); mNeedsAlive = false; mSaving = true; - handleSaveRequest(sourceUri, selectedUri, destinationFile, preset, flatten); + handleSaveRequest(sourceUri, selectedUri, destinationFile, preset, flatten, quality); } return START_REDELIVER_INTENT; } @@ -198,7 +201,7 @@ public class ProcessingService extends Service { } public void handleSaveRequest(Uri sourceUri, Uri selectedUri, - File destinationFile, ImagePreset preset, boolean flatten) { + File destinationFile, ImagePreset preset, boolean flatten, int quality) { mNotifyMgr = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); mNotificationId++; @@ -215,7 +218,8 @@ public class ProcessingService extends Service { // Process the image - mImageSavingTask.saveImage(sourceUri, selectedUri, destinationFile, preset, flatten); + mImageSavingTask.saveImage(sourceUri, selectedUri, destinationFile, + preset, flatten, quality); } 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 d5fe29584..83cbd0136 100644 --- a/src/com/android/gallery3d/filtershow/tools/SaveImage.java +++ b/src/com/android/gallery3d/filtershow/tools/SaveImage.java @@ -32,10 +32,10 @@ import android.util.Log; import com.android.gallery3d.common.Utils; import com.android.gallery3d.exif.ExifInterface; import com.android.gallery3d.filtershow.FilterShowActivity; -import com.android.gallery3d.filtershow.pipeline.CachingPipeline; import com.android.gallery3d.filtershow.cache.ImageLoader; import com.android.gallery3d.filtershow.filters.FiltersManager; import com.android.gallery3d.filtershow.imageshow.MasterImage; +import com.android.gallery3d.filtershow.pipeline.CachingPipeline; import com.android.gallery3d.filtershow.pipeline.ImagePreset; import com.android.gallery3d.filtershow.pipeline.ProcessingService; import com.android.gallery3d.util.UsageStatistics; @@ -46,6 +46,7 @@ import java.io.FileNotFoundException; import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; import java.sql.Date; import java.text.SimpleDateFormat; import java.util.TimeZone; @@ -257,15 +258,24 @@ public class SaveImage { return exif; } - public boolean putExifData(File file, ExifInterface exif, Bitmap image) { + public boolean putExifData(File file, ExifInterface exif, Bitmap image, + int jpegCompressQuality) { boolean ret = false; + OutputStream s = null; try { - exif.writeExif(image, file.getAbsolutePath()); + s = exif.getExifWriterStream(file.getAbsolutePath()); + image.compress(Bitmap.CompressFormat.JPEG, + (jpegCompressQuality > 0) ? jpegCompressQuality : 1, s); + s.flush(); + s.close(); + s = null; ret = true; } catch (FileNotFoundException e) { Log.w(LOGTAG, "File not found: " + file.getAbsolutePath(), e); } catch (IOException e) { Log.w(LOGTAG, "Could not write exif: ", e); + } finally { + Utils.closeSilently(s); } return ret; } @@ -300,7 +310,7 @@ public class SaveImage { } } - public Uri processAndSaveImage(ImagePreset preset, boolean doAuxBackup) { + public Uri processAndSaveImage(ImagePreset preset, boolean doAuxBackup, int quality) { Uri uri = resetToOriginalImageIfNeeded(preset, doAuxBackup); if (uri != null) { @@ -354,7 +364,7 @@ public class SaveImage { updateProgress(); // If we succeed in writing the bitmap as a jpeg, return a uri. - if (putExifData(mDestinationFile, exif, bitmap)) { + if (putExifData(mDestinationFile, exif, bitmap, quality)) { putPanoramaXMPData(mDestinationFile, xmp); // mDestinationFile will save the newSourceUri info in the XMP. XmpPresets.writeFilterXMP(mContext, newSourceUri, @@ -448,7 +458,7 @@ public class SaveImage { Uri sourceImageUri = MasterImage.getImage().getUri(); Intent processIntent = ProcessingService.getSaveIntent(filterShowActivity, preset, - destination, selectedImageUri, sourceImageUri, false); + destination, selectedImageUri, sourceImageUri, false, 90); filterShowActivity.startService(processIntent); diff --git a/src/com/android/gallery3d/filtershow/ui/ExportDialog.java b/src/com/android/gallery3d/filtershow/ui/ExportDialog.java new file mode 100644 index 000000000..4b30e7b18 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/ui/ExportDialog.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.gallery3d.filtershow.ui; + +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.support.v4.app.DialogFragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +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.ProcessingService; +import com.android.gallery3d.filtershow.tools.SaveImage; + +import java.io.File; + +public class ExportDialog extends DialogFragment implements View.OnClickListener, SeekBar.OnSeekBarChangeListener{ + SeekBar mSeekBar; + TextView mSeekVal; + String mSliderLabel; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + 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) + ": "; + mSeekVal.setText(mSliderLabel + mSeekBar.getProgress()); + mSeekBar.setOnSeekBarChangeListener(this); + view.findViewById(R.id.cancel).setOnClickListener(this); + view.findViewById(R.id.done).setOnClickListener(this); + getDialog().setTitle(R.string.export_flattened); + return view; + } + + @Override + public void onStopTrackingTouch(SeekBar arg0) { + // Do nothing + } + + @Override + public void onStartTrackingTouch(SeekBar arg0) { + // Do nothing + } + + @Override + public void onProgressChanged(SeekBar arg0, int arg1, boolean arg2) { + mSeekVal.setText(mSliderLabel + arg1); + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.cancel: + dismiss(); + break; + case R.id.done: + FilterShowActivity activity = (FilterShowActivity) getActivity(); + Uri sourceUri = MasterImage.getImage().getUri(); + File dest = SaveImage.getNewFile(activity, sourceUri); + Intent processIntent = ProcessingService.getSaveIntent(activity, MasterImage + .getImage().getPreset(), dest, activity.getSelectedImageUri(), sourceUri, + true, mSeekBar.getProgress()); + activity.startService(processIntent); + dismiss(); + break; + } + } +} -- cgit v1.2.3