Home | History | Annotate | Download | only in ui
      1 /*
      2  * Copyright (C) 2013 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.gallery3d.filtershow.ui;
     18 
     19 import android.content.Intent;
     20 import android.graphics.Bitmap;
     21 import android.graphics.Rect;
     22 import android.net.Uri;
     23 import android.os.Bundle;
     24 import android.os.Handler;
     25 import android.support.v4.app.DialogFragment;
     26 import android.text.Editable;
     27 import android.text.TextWatcher;
     28 import android.view.LayoutInflater;
     29 import android.view.View;
     30 import android.view.ViewGroup;
     31 import android.widget.EditText;
     32 import android.widget.SeekBar;
     33 import android.widget.TextView;
     34 
     35 import com.android.gallery3d.R;
     36 import com.android.gallery3d.filtershow.FilterShowActivity;
     37 import com.android.gallery3d.filtershow.imageshow.MasterImage;
     38 import com.android.gallery3d.filtershow.pipeline.ImagePreset;
     39 import com.android.gallery3d.filtershow.pipeline.ProcessingService;
     40 import com.android.gallery3d.filtershow.tools.SaveImage;
     41 
     42 import java.io.ByteArrayOutputStream;
     43 import java.io.File;
     44 
     45 public class ExportDialog extends DialogFragment implements View.OnClickListener,
     46         SeekBar.OnSeekBarChangeListener {
     47     SeekBar mSeekBar;
     48     TextView mSeekVal;
     49     EditText mWidthText;
     50     EditText mHeightText;
     51     TextView mEstimatedSize;
     52     int mQuality = 95;
     53     int mExportWidth = 0;
     54     int mExportHeight = 0;
     55     Rect mOriginalBounds;
     56     int mCompressedSize;
     57     Rect mCompressedBounds;
     58     float mExportCompressionMargin = 1.1f;
     59     float mRatio;
     60     String mSliderLabel;
     61     boolean mEditing = false;
     62     Handler mHandler;
     63     int mUpdateDelay = 1000;
     64     Runnable mUpdateRunnable = new Runnable() {
     65         @Override
     66         public void run() {
     67             updateCompressionFactor();
     68             updateSize();
     69         }
     70     };
     71 
     72     private class Watcher implements TextWatcher {
     73         private EditText mEditText;
     74         Watcher(EditText text) {
     75             mEditText = text;
     76         }
     77 
     78         @Override
     79         public void beforeTextChanged(CharSequence s, int start, int count, int after) {
     80         }
     81 
     82         @Override
     83         public void onTextChanged(CharSequence s, int start, int before, int count) {
     84         }
     85 
     86         @Override
     87         public void afterTextChanged(Editable s) {
     88             textChanged(mEditText);
     89         }
     90     }
     91 
     92     @Override
     93     public View onCreateView(LayoutInflater inflater, ViewGroup container,
     94             Bundle savedInstanceState) {
     95         mHandler = new Handler(getActivity().getMainLooper());
     96 
     97         View view = inflater.inflate(R.layout.filtershow_export_dialog, container);
     98         mSeekBar = (SeekBar) view.findViewById(R.id.qualitySeekBar);
     99         mSeekVal = (TextView) view.findViewById(R.id.qualityTextView);
    100         mSliderLabel = getString(R.string.quality) + ": ";
    101         mSeekBar.setProgress(mQuality);
    102         mSeekVal.setText(mSliderLabel + mSeekBar.getProgress());
    103         mSeekBar.setOnSeekBarChangeListener(this);
    104         mWidthText = (EditText) view.findViewById(R.id.editableWidth);
    105         mHeightText = (EditText) view.findViewById(R.id.editableHeight);
    106         mEstimatedSize = (TextView) view.findViewById(R.id.estimadedSize);
    107 
    108         mOriginalBounds = MasterImage.getImage().getOriginalBounds();
    109         ImagePreset preset = MasterImage.getImage().getPreset();
    110         mOriginalBounds = preset.finalGeometryRect(mOriginalBounds.width(),
    111                 mOriginalBounds.height());
    112         mRatio = mOriginalBounds.width() / (float) mOriginalBounds.height();
    113         mWidthText.setText("" + mOriginalBounds.width());
    114         mHeightText.setText("" + mOriginalBounds.height());
    115         mExportWidth = mOriginalBounds.width();
    116         mExportHeight = mOriginalBounds.height();
    117         mWidthText.addTextChangedListener(new Watcher(mWidthText));
    118         mHeightText.addTextChangedListener(new Watcher(mHeightText));
    119 
    120         view.findViewById(R.id.cancel).setOnClickListener(this);
    121         view.findViewById(R.id.done).setOnClickListener(this);
    122         getDialog().setTitle(R.string.export_flattened);
    123 
    124         updateCompressionFactor();
    125         updateSize();
    126         return view;
    127     }
    128 
    129     @Override
    130     public void onStopTrackingTouch(SeekBar arg0) {
    131         // Do nothing
    132     }
    133 
    134     @Override
    135     public void onStartTrackingTouch(SeekBar arg0) {
    136         // Do nothing
    137     }
    138 
    139     @Override
    140     public void onProgressChanged(SeekBar arg0, int arg1, boolean arg2) {
    141         mSeekVal.setText(mSliderLabel + arg1);
    142         mQuality = mSeekBar.getProgress();
    143         scheduleUpdateCompressionFactor();
    144     }
    145 
    146     private void scheduleUpdateCompressionFactor() {
    147         mHandler.removeCallbacks(mUpdateRunnable);
    148         mHandler.postDelayed(mUpdateRunnable, mUpdateDelay);
    149     }
    150 
    151     @Override
    152     public void onClick(View v) {
    153         switch (v.getId()) {
    154             case R.id.cancel:
    155                 dismiss();
    156                 break;
    157             case R.id.done:
    158                 FilterShowActivity activity = (FilterShowActivity) getActivity();
    159                 Uri sourceUri = MasterImage.getImage().getUri();
    160                 File dest = SaveImage.getNewFile(activity,  activity.getSelectedImageUri());
    161                 float scaleFactor = mExportWidth / (float) mOriginalBounds.width();
    162                 Intent processIntent = ProcessingService.getSaveIntent(activity, MasterImage
    163                         .getImage().getPreset(), dest, activity.getSelectedImageUri(), sourceUri,
    164                         true, mSeekBar.getProgress(), scaleFactor, false);
    165                 activity.startService(processIntent);
    166                 dismiss();
    167                 break;
    168         }
    169     }
    170 
    171     public void updateCompressionFactor() {
    172         Bitmap bitmap = MasterImage.getImage().getFilteredImage();
    173         if (bitmap == null) {
    174             return;
    175         }
    176         ByteArrayOutputStream out = new ByteArrayOutputStream();
    177         bitmap.compress(Bitmap.CompressFormat.JPEG, mQuality, out);
    178         mCompressedSize = out.size();
    179         mCompressedBounds = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
    180     }
    181 
    182     public void updateSize() {
    183         if (mCompressedBounds == null) {
    184             return;
    185         }
    186         // This is a rough estimate of the final save size. There's some loose correlation
    187         // between a compressed jpeg and a larger version of it in function of the image
    188         // area. Not a perfect estimate by far.
    189         float originalArea = mCompressedBounds.width() * mCompressedBounds.height();
    190         float newArea = mExportWidth * mExportHeight;
    191         float factor = originalArea / (float) mCompressedSize;
    192         float compressedSize = newArea / factor;
    193         compressedSize *= mExportCompressionMargin;
    194         float size = compressedSize / 1024.f / 1024.f;
    195         size = ((int) (size * 100)) / 100f;
    196         String estimatedSize = "" + size + " Mb";
    197         mEstimatedSize.setText(estimatedSize);
    198     }
    199 
    200     private void textChanged(EditText text) {
    201         if (mEditing) {
    202             return;
    203         }
    204         mEditing = true;
    205         int width = 1;
    206         int height = 1;
    207         if (text.getId() == R.id.editableWidth) {
    208             if (mWidthText.getText() != null) {
    209                 String value = String.valueOf(mWidthText.getText());
    210                 if (value.length() > 0) {
    211                     width = Integer.parseInt(value);
    212                     if (width > mOriginalBounds.width()) {
    213                         width = mOriginalBounds.width();
    214                         mWidthText.setText("" + width);
    215                     }
    216                     if (width <= 0) {
    217                         width = (int) Math.ceil(mRatio);
    218                         mWidthText.setText("" + width);
    219                     }
    220                     height = (int) (width / mRatio);
    221                 }
    222                 mHeightText.setText("" + height);
    223             }
    224         } else if (text.getId() == R.id.editableHeight) {
    225             if (mHeightText.getText() != null) {
    226                 String value = String.valueOf(mHeightText.getText());
    227                 if (value.length() > 0) {
    228                     height = Integer.parseInt(value);
    229                     if (height > mOriginalBounds.height()) {
    230                         height = mOriginalBounds.height();
    231                         mHeightText.setText("" + height);
    232                     }
    233                     if (height <= 0) {
    234                         height = 1;
    235                         mHeightText.setText("" + height);
    236                     }
    237                     width = (int) (height * mRatio);
    238                 }
    239                 mWidthText.setText("" + width);
    240             }
    241         }
    242         mExportWidth = width;
    243         mExportHeight = height;
    244         updateSize();
    245         mEditing = false;
    246     }
    247 
    248 }
    249