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
17package com.android.gallery3d.filtershow.ui;
18
19import android.content.Intent;
20import android.graphics.Bitmap;
21import android.graphics.Rect;
22import android.net.Uri;
23import android.os.Bundle;
24import android.os.Handler;
25import android.support.v4.app.DialogFragment;
26import android.text.Editable;
27import android.text.TextWatcher;
28import android.view.LayoutInflater;
29import android.view.View;
30import android.view.ViewGroup;
31import android.widget.EditText;
32import android.widget.SeekBar;
33import android.widget.TextView;
34
35import com.android.gallery3d.R;
36import com.android.gallery3d.filtershow.FilterShowActivity;
37import com.android.gallery3d.filtershow.imageshow.MasterImage;
38import com.android.gallery3d.filtershow.pipeline.ImagePreset;
39import com.android.gallery3d.filtershow.pipeline.ProcessingService;
40import com.android.gallery3d.filtershow.tools.SaveImage;
41
42import java.io.ByteArrayOutputStream;
43import java.io.File;
44
45public 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