Update ImagePicker.java

Added localization feature for message boxes
This commit is contained in:
D4rthR4tz3
2016-04-22 15:02:26 +02:00
parent 103875b5c8
commit 32f3c646fd

View File

@@ -1,72 +1,705 @@
/**
* An Image Picker Plugin for Cordova/PhoneGap.
/*
* Copyright (c) 2012, David Erosa
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDIN G NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE
*
* Code modified by Andrew Stephan for Sync OnSet
*
*/
package com.synconset;
import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaPlugin;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.net.URI;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import com.synconset.FakeR;
import android.app.Activity;
import android.app.ActionBar;
import android.app.AlertDialog;
import android.app.LoaderManager;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.CursorLoader;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.Loader;
import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.Matrix;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
import android.util.SparseBooleanArray;
import android.view.Display;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.TextView;
public class ImagePicker extends CordovaPlugin {
public static String TAG = "ImagePicker";
private CallbackContext callbackContext;
private JSONObject params;
public boolean execute(String action, final JSONArray args, final CallbackContext callbackContext) throws JSONException {
this.callbackContext = callbackContext;
this.params = args.getJSONObject(0);
if (action.equals("getPictures")) {
Intent intent = new Intent(cordova.getActivity(), MultiImageChooserActivity.class);
int max = 20;
int desiredWidth = 0;
int desiredHeight = 0;
int quality = 100;
if (this.params.has("maximumImagesCount")) {
max = this.params.getInt("maximumImagesCount");
}
if (this.params.has("width")) {
desiredWidth = this.params.getInt("width");
}
if (this.params.has("height")) {
desiredWidth = this.params.getInt("height");
}
if (this.params.has("quality")) {
quality = this.params.getInt("quality");
}
intent.putExtra("MAX_IMAGES", max);
intent.putExtra("WIDTH", desiredWidth);
intent.putExtra("HEIGHT", desiredHeight);
intent.putExtra("QUALITY", quality);
if (this.cordova != null) {
this.cordova.startActivityForResult((CordovaPlugin) this, intent, 0);
}
import org.chromium.ui.resources.Resource;
import de.awenko.mobile.R;
public class MultiImageChooserActivity extends Activity implements OnItemClickListener,
LoaderManager.LoaderCallbacks<Cursor> {
private static final String TAG = "ImagePicker";
public static final int NOLIMIT = -1;
public static final String MAX_IMAGES_KEY = "MAX_IMAGES";
public static final String WIDTH_KEY = "WIDTH";
public static final String HEIGHT_KEY = "HEIGHT";
public static final String QUALITY_KEY = "QUALITY";
private ImageAdapter ia;
private Cursor imagecursor, actualimagecursor;
private int image_column_index, image_column_orientation, actual_image_column_index, orientation_column_index;
private int colWidth;
private static final int CURSORLOADER_THUMBS = 0;
private static final int CURSORLOADER_REAL = 1;
private Map<String, Integer> fileNames = new HashMap<String, Integer>();
private SparseBooleanArray checkStatus = new SparseBooleanArray();
private int maxImages;
private int maxImageCount;
private int desiredWidth;
private int desiredHeight;
private int quality;
private GridView gridView;
private final ImageFetcher fetcher = new ImageFetcher();
private int selectedColor = 0xff32b2e1;
private boolean shouldRequestThumb = true;
private FakeR fakeR;
private ProgressDialog progress;
private Resources resources;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
fakeR = new FakeR(this);
setContentView(fakeR.getId("layout", "multiselectorgrid"));
fileNames.clear();
maxImages = getIntent().getIntExtra(MAX_IMAGES_KEY, NOLIMIT);
desiredWidth = getIntent().getIntExtra(WIDTH_KEY, 0);
desiredHeight = getIntent().getIntExtra(HEIGHT_KEY, 0);
quality = getIntent().getIntExtra(QUALITY_KEY, 0);
maxImageCount = maxImages;
Display display = getWindowManager().getDefaultDisplay();
int width = display.getWidth();
colWidth = width / 4;
gridView = (GridView) findViewById(fakeR.getId("id", "gridview"));
gridView.setOnItemClickListener(this);
gridView.setOnScrollListener(new OnScrollListener() {
private int lastFirstItem = 0;
private long timestamp = System.currentTimeMillis();
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if (scrollState == SCROLL_STATE_IDLE) {
shouldRequestThumb = true;
ia.notifyDataSetChanged();
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
float dt = System.currentTimeMillis() - timestamp;
if (firstVisibleItem != lastFirstItem) {
double speed = 1 / dt * 1000;
lastFirstItem = firstVisibleItem;
timestamp = System.currentTimeMillis();
// Limit if we go faster than a page a second
shouldRequestThumb = speed < visibleItemCount;
}
}
});
ia = new ImageAdapter(this);
gridView.setAdapter(ia);
resources = getResources();
LoaderManager.enableDebugLogging(false);
getLoaderManager().initLoader(CURSORLOADER_THUMBS, null, this);
getLoaderManager().initLoader(CURSORLOADER_REAL, null, this);
setupHeader();
updateAcceptButton();
progress = new ProgressDialog(this);
progress.setTitle(resources.getString(R.string.processing_images_header));
progress.setMessage(resources.getString(R.string.processing_images_message));
}
@Override
public void onItemClick(AdapterView<?> arg0, View view, int position, long id) {
String name = getImageName(position);
int rotation = getImageRotation(position);
if (name == null) {
return;
}
boolean isChecked = !isChecked(position);
if (maxImages == 0 && isChecked) {
isChecked = false;
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(resources.getString(R.string.maximum_selection_count_error_header));
builder.setMessage(String.format(resources.getString(R.string.maximum_selection_count_error_message), maxImageCount));
builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
AlertDialog alert = builder.create();
alert.show();
} else if (isChecked) {
fileNames.put(name, new Integer(rotation));
if (maxImageCount == 1) {
this.selectClicked(null);
} else {
maxImages--;
ImageView imageView = (ImageView)view;
if (android.os.Build.VERSION.SDK_INT>=16) {
imageView.setImageAlpha(128);
} else {
imageView.setAlpha(128);
}
view.setBackgroundColor(selectedColor);
}
} else {
fileNames.remove(name);
maxImages++;
ImageView imageView = (ImageView)view;
if (android.os.Build.VERSION.SDK_INT>=16) {
imageView.setImageAlpha(255);
} else {
imageView.setAlpha(255);
}
view.setBackgroundColor(Color.TRANSPARENT);
}
checkStatus.put(position, isChecked);
updateAcceptButton();
}
@Override
public Loader<Cursor> onCreateLoader(int cursorID, Bundle arg1) {
CursorLoader cl = null;
ArrayList<String> img = new ArrayList<String>();
switch (cursorID) {
case CURSORLOADER_THUMBS:
img.add(MediaStore.Images.Media._ID);
img.add(MediaStore.Images.Media.ORIENTATION);
break;
case CURSORLOADER_REAL:
img.add(MediaStore.Images.Thumbnails.DATA);
img.add(MediaStore.Images.Media.ORIENTATION);
break;
default:
break;
}
cl = new CursorLoader(MultiImageChooserActivity.this, MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
img.toArray(new String[img.size()]), null, null, "DATE_MODIFIED DESC");
return cl;
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
if (cursor == null) {
// NULL cursor. This usually means there's no image database yet....
return;
}
switch (loader.getId()) {
case CURSORLOADER_THUMBS:
imagecursor = cursor;
image_column_index = imagecursor.getColumnIndex(MediaStore.Images.Media._ID);
image_column_orientation = imagecursor.getColumnIndex(MediaStore.Images.Media.ORIENTATION);
ia.notifyDataSetChanged();
break;
case CURSORLOADER_REAL:
actualimagecursor = cursor;
String[] columns = actualimagecursor.getColumnNames();
actual_image_column_index = actualimagecursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
orientation_column_index = actualimagecursor.getColumnIndexOrThrow(MediaStore.Images.Media.ORIENTATION);
break;
default:
break;
}
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
if (loader.getId() == CURSORLOADER_THUMBS) {
imagecursor = null;
} else if (loader.getId() == CURSORLOADER_REAL) {
actualimagecursor = null;
}
}
public void cancelClicked(View ignored) {
setResult(RESULT_CANCELED);
finish();
}
public void selectClicked(View ignored) {
((TextView) getActionBar().getCustomView().findViewById(fakeR.getId("id", "actionbar_done_textview"))).setEnabled(false);
getActionBar().getCustomView().findViewById(fakeR.getId("id", "actionbar_done")).setEnabled(false);
progress.show();
Intent data = new Intent();
if (fileNames.isEmpty()) {
this.setResult(RESULT_CANCELED);
progress.dismiss();
finish();
} else {
new ResizeImagesTask().execute(fileNames.entrySet());
}
}
/*********************
* Helper Methods
********************/
private void updateAcceptButton() {
((TextView) getActionBar().getCustomView().findViewById(fakeR.getId("id", "actionbar_done_textview")))
.setEnabled(fileNames.size() != 0);
getActionBar().getCustomView().findViewById(fakeR.getId("id", "actionbar_done")).setEnabled(fileNames.size() != 0);
}
private void setupHeader() {
// From Roman Nkk's code
// https://plus.google.com/113735310430199015092/posts/R49wVvcDoEW
// Inflate a "Done/Discard" custom action bar view
/*
* Copyright 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.
*/
LayoutInflater inflater = (LayoutInflater) getActionBar().getThemedContext().getSystemService(
LAYOUT_INFLATER_SERVICE);
final View customActionBarView = inflater.inflate(fakeR.getId("layout", "actionbar_custom_view_done_discard"), null);
customActionBarView.findViewById(fakeR.getId("id", "actionbar_done")).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// "Done"
selectClicked(null);
}
});
customActionBarView.findViewById(fakeR.getId("id", "actionbar_discard")).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
// Show the custom action bar view and hide the normal Home icon and title.
final ActionBar actionBar = getActionBar();
actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM, ActionBar.DISPLAY_SHOW_CUSTOM
| ActionBar.DISPLAY_SHOW_HOME | ActionBar.DISPLAY_SHOW_TITLE);
actionBar.setCustomView(customActionBarView, new ActionBar.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
}
private String getImageName(int position) {
actualimagecursor.moveToPosition(position);
String name = null;
try {
name = actualimagecursor.getString(actual_image_column_index);
} catch (Exception e) {
return null;
}
return name;
}
private int getImageRotation(int position) {
actualimagecursor.moveToPosition(position);
int rotation = 0;
try {
rotation = actualimagecursor.getInt(orientation_column_index);
} catch (Exception e) {
return rotation;
}
return rotation;
}
public boolean isChecked(int position) {
boolean ret = checkStatus.get(position);
return ret;
}
/*********************
* Nested Classes
********************/
private class SquareImageView extends ImageView {
public SquareImageView(Context context) {
super(context);
}
return true;
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == Activity.RESULT_OK && data != null) {
ArrayList<String> fileNames = data.getStringArrayListExtra("MULTIPLEFILENAMES");
JSONArray res = new JSONArray(fileNames);
this.callbackContext.success(res);
} else if (resultCode == Activity.RESULT_CANCELED && data != null) {
String error = data.getStringExtra("ERRORMESSAGE");
this.callbackContext.error(error);
} else if (resultCode == Activity.RESULT_CANCELED) {
JSONArray res = new JSONArray();
this.callbackContext.success(res);
} else {
this.callbackContext.error("No images selected");
}
}
}
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, widthMeasureSpec);
}
}
private class ImageAdapter extends BaseAdapter {
private final Bitmap mPlaceHolderBitmap;
public ImageAdapter(Context c) {
Bitmap tmpHolderBitmap = BitmapFactory.decodeResource(getResources(), fakeR.getId("drawable", "loading_icon"));
mPlaceHolderBitmap = Bitmap.createScaledBitmap(tmpHolderBitmap, colWidth, colWidth, false);
if (tmpHolderBitmap != mPlaceHolderBitmap) {
tmpHolderBitmap.recycle();
tmpHolderBitmap = null;
}
}
public int getCount() {
if (imagecursor != null) {
return imagecursor.getCount();
} else {
return 0;
}
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
// create a new ImageView for each item referenced by the Adapter
public View getView(int pos, View convertView, ViewGroup parent) {
if (convertView == null) {
ImageView temp = new SquareImageView(MultiImageChooserActivity.this);
temp.setScaleType(ImageView.ScaleType.CENTER_CROP);
convertView = (View)temp;
}
ImageView imageView = (ImageView)convertView;
imageView.setImageBitmap(null);
final int position = pos;
if (!imagecursor.moveToPosition(position)) {
return imageView;
}
if (image_column_index == -1) {
return imageView;
}
final int id = imagecursor.getInt(image_column_index);
final int rotate = imagecursor.getInt(image_column_orientation);
if (isChecked(pos)) {
if (android.os.Build.VERSION.SDK_INT>=16) {
imageView.setImageAlpha(128);
} else {
imageView.setAlpha(128);
}
imageView.setBackgroundColor(selectedColor);
} else {
if (android.os.Build.VERSION.SDK_INT>=16) {
imageView.setImageAlpha(255);
} else {
imageView.setAlpha(255);
}
imageView.setBackgroundColor(Color.TRANSPARENT);
}
if (shouldRequestThumb) {
fetcher.fetch(Integer.valueOf(id), imageView, colWidth, rotate);
}
return imageView;
}
}
private class ResizeImagesTask extends AsyncTask<Set<Entry<String, Integer>>, Void, ArrayList<String>> {
private Exception asyncTaskError = null;
@Override
protected ArrayList<String> doInBackground(Set<Entry<String, Integer>>... fileSets) {
Set<Entry<String, Integer>> fileNames = fileSets[0];
ArrayList<String> al = new ArrayList<String>();
try {
Iterator<Entry<String, Integer>> i = fileNames.iterator();
Bitmap bmp;
while(i.hasNext()) {
Entry<String, Integer> imageInfo = i.next();
File file = new File(imageInfo.getKey());
int rotate = imageInfo.getValue().intValue();
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 1;
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(file.getAbsolutePath(), options);
int width = options.outWidth;
int height = options.outHeight;
float scale = calculateScale(width, height);
if (scale < 1) {
int finalWidth = (int)(width * scale);
int finalHeight = (int)(height * scale);
int inSampleSize = calculateInSampleSize(options, finalWidth, finalHeight);
options = new BitmapFactory.Options();
options.inSampleSize = inSampleSize;
try {
bmp = this.tryToGetBitmap(file, options, rotate, true);
} catch (OutOfMemoryError e) {
options.inSampleSize = calculateNextSampleSize(options.inSampleSize);
try {
bmp = this.tryToGetBitmap(file, options, rotate, false);
} catch (OutOfMemoryError e2) {
throw new IOException("Unable to load image into memory.");
}
}
} else {
try {
bmp = this.tryToGetBitmap(file, null, rotate, false);
} catch(OutOfMemoryError e) {
options = new BitmapFactory.Options();
options.inSampleSize = 2;
try {
bmp = this.tryToGetBitmap(file, options, rotate, false);
} catch(OutOfMemoryError e2) {
options = new BitmapFactory.Options();
options.inSampleSize = 4;
try {
bmp = this.tryToGetBitmap(file, options, rotate, false);
} catch (OutOfMemoryError e3) {
throw new IOException("Unable to load image into memory.");
}
}
}
}
file = this.storeImage(bmp, file.getName());
al.add(Uri.fromFile(file).toString());
}
return al;
} catch(IOException e) {
try {
asyncTaskError = e;
for (int i = 0; i < al.size(); i++) {
URI uri = new URI(al.get(i));
File file = new File(uri);
file.delete();
}
} catch(Exception exception) {
// the finally does what we want to do
} finally {
return new ArrayList<String>();
}
}
}
@Override
protected void onPostExecute(ArrayList<String> al) {
Intent data = new Intent();
if (asyncTaskError != null) {
Bundle res = new Bundle();
res.putString("ERRORMESSAGE", asyncTaskError.getMessage());
data.putExtras(res);
setResult(RESULT_CANCELED, data);
} else if (al.size() > 0) {
Bundle res = new Bundle();
res.putStringArrayList("MULTIPLEFILENAMES", al);
if (imagecursor != null) {
res.putInt("TOTALFILES", imagecursor.getCount());
}
data.putExtras(res);
setResult(RESULT_OK, data);
} else {
setResult(RESULT_CANCELED, data);
}
progress.dismiss();
finish();
}
private Bitmap tryToGetBitmap(File file, BitmapFactory.Options options, int rotate, boolean shouldScale) throws IOException, OutOfMemoryError {
Bitmap bmp;
if (options == null) {
bmp = BitmapFactory.decodeFile(file.getAbsolutePath());
} else {
bmp = BitmapFactory.decodeFile(file.getAbsolutePath(), options);
}
if (bmp == null) {
throw new IOException("The image file could not be opened.");
}
if (options != null && shouldScale) {
float scale = calculateScale(options.outWidth, options.outHeight);
bmp = this.getResizedBitmap(bmp, scale);
}
if (rotate != 0) {
Matrix matrix = new Matrix();
matrix.setRotate(rotate);
bmp = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), matrix, true);
}
return bmp;
}
/*
* The following functions are originally from
* https://github.com/raananw/PhoneGap-Image-Resizer
*
* They have been modified by Andrew Stephan for Sync OnSet
*
* The software is open source, MIT Licensed.
* Copyright (C) 2012, webXells GmbH All Rights Reserved.
*/
private File storeImage(Bitmap bmp, String fileName) throws IOException {
int index = fileName.lastIndexOf('.');
String name = fileName.substring(0, index);
String ext = fileName.substring(index);
File file = File.createTempFile("tmp_" + name, ext);
OutputStream outStream = new FileOutputStream(file);
if (ext.compareToIgnoreCase(".png") == 0) {
bmp.compress(Bitmap.CompressFormat.PNG, quality, outStream);
} else {
bmp.compress(Bitmap.CompressFormat.JPEG, quality, outStream);
}
outStream.flush();
outStream.close();
return file;
}
private Bitmap getResizedBitmap(Bitmap bm, float factor) {
int width = bm.getWidth();
int height = bm.getHeight();
// create a matrix for the manipulation
Matrix matrix = new Matrix();
// resize the bit map
matrix.postScale(factor, factor);
// recreate the new Bitmap
Bitmap resizedBitmap = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, false);
return resizedBitmap;
}
}
private int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
private int calculateNextSampleSize(int sampleSize) {
double logBaseTwo = (int)(Math.log(sampleSize) / Math.log(2));
return (int)Math.pow(logBaseTwo + 1, 2);
}
private float calculateScale(int width, int height) {
float widthScale = 1.0f;
float heightScale = 1.0f;
float scale = 1.0f;
if (desiredWidth > 0 || desiredHeight > 0) {
if (desiredHeight == 0 && desiredWidth < width) {
scale = (float)desiredWidth/width;
} else if (desiredWidth == 0 && desiredHeight < height) {
scale = (float)desiredHeight/height;
} else {
if (desiredWidth > 0 && desiredWidth < width) {
widthScale = (float)desiredWidth/width;
}
if (desiredHeight > 0 && desiredHeight < height) {
heightScale = (float)desiredHeight/height;
}
if (widthScale < heightScale) {
scale = widthScale;
} else {
scale = heightScale;
}
}
}
return scale;
}
}