Merge pull request #805 from nextcloud/svgViewRedone

Show SVG images
This commit is contained in:
Andy Scherzinger 2017-04-19 16:23:17 +02:00 committed by GitHub
commit 029b4a1a02
2 changed files with 135 additions and 71 deletions

View file

@ -2,7 +2,7 @@
Nextcloud Android client
Copyright (C) 2016 Nextcloud Project
Copyright (C) 2012-2016 ownCloud Inc.
Copyright (C) 2012-2016 ownCloud GmbH
Copyright (C) 2012 Bartek Przybylski
###################################################################
@ -37,24 +37,22 @@ that govern this software, for the purposes they are being used.
The third party software included and used by this project is:
* Apache JackRabbit, version 2.2.5.
Copyright (C) 2004-2010 The Apache Software Foundation.
* Apache JackRabbit 2.12.4.
Copyright (C) 2004-2016 The Apache Software Foundation.
Licensed under Apache License, Version 2.0.
Placed at libs/jackrabbit-webdav-2.2.5-jar-with-dependencies.jar
The jar file must be included in the ownCloud client APK.
Original license document included at libs/LICENSE.txt
The jar file must be included in the Nextcloud client APK.
See http://jackrabbit.apache.org/
* Transifex client.
Copyright (C) Transifex.
Licensed under GNU General Public License.
Placed at third_party/transifex-client.
Used as a helper tool, not included in the ownCloud client APK.
Used as a helper tool, not included in the Nextcloud client APK.
Original license document included at third_party/transifex-client/LICENSE.
See http://help.transifex.com/features/client/
* TouchImageView, commit 6dbeac4f11936185ba374c73144ac431c23c9aab
Copyright (c) 2012 Michael Ortiz
* TouchImageView, 1.2.0. commit 6dbeac4f11936185ba374c73144ac431c23c9aab
Copyright (c) 2014 Michael Ortiz
Licensed under MIT License
JAR file libs/touch-image-view.jar has been generated by ownCloud Inc., including without
modifications com.ortiz.touch.ExtendedViewPager and com.ortiz.touch.TouchImageView classes.
@ -63,5 +61,19 @@ The third party software included and used by this project is:
* floatingactionbutton 1.10.1.
Copyright (c) 2014 Jerzy Chalupski
Licensed under Apache License, Version 2.0.
placed at libs/com-getbase-floatingactionbutton-1-10-0-exploded-aar has been exploded by ownCloud Inc.
See https://github.com/futuresimple/android-floating-action-button
The jar file must be included in the Nextcloud client APK.
See https://github.com/futuresimple/android-floating-action-button
* AndroidSVG 1.2.1.
Copyright (c) 2014 Paul LeBeau
Licensed under Apache License, Version 2.0.
placed at libs/androidsvg-1.2.1.jar
The jar file must be included in the Nextcloud client APK.
See https://github.com/BigBadaboom/androidsvg
* Disk LRU Cache 2.0.2.
Copyright (c) 2013 Jake Wharton
Licensed under Apache License, Version 2.0.
placed at libs/disklrucache-2.0.2.jar
The jar file must be included in the Nextcloud client APK.
See https://github.com/JakeWharton/DiskLruCache

View file

@ -29,6 +29,7 @@ import android.graphics.Point;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.graphics.drawable.PictureDrawable;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.DrawableRes;
@ -48,6 +49,8 @@ import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.caverock.androidsvg.SVG;
import com.caverock.androidsvg.SVGParseException;
import com.owncloud.android.R;
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.files.FileMenuFilter;
@ -59,6 +62,8 @@ import com.owncloud.android.utils.BitmapUtils;
import com.owncloud.android.utils.DisplayUtils;
import com.owncloud.android.utils.MimeTypeUtil;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.lang.ref.WeakReference;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
@ -109,10 +114,10 @@ public class PreviewImageFragment extends FileFragment {
*
* This method hides to client objects the need of doing the construction in two steps.
*
* @param imageFile An {@link OCFile} to preview as an image in the fragment
* @param ignoreFirstSavedState Flag to work around an unexpected behaviour of
* {@link FragmentStatePagerAdapter}
* ; TODO better solution
* @param imageFile An {@link OCFile} to preview as an image in the fragment
* @param ignoreFirstSavedState Flag to work around an unexpected behaviour of
* {@link FragmentStatePagerAdapter}
* ; TODO better solution
*/
public static PreviewImageFragment newInstance(OCFile imageFile, boolean ignoreFirstSavedState) {
PreviewImageFragment frag = new PreviewImageFragment();
@ -125,13 +130,13 @@ public class PreviewImageFragment extends FileFragment {
/**
* Creates an empty fragment for image previews.
* Creates an empty fragment for image previews.
*
* MUST BE KEPT: the system uses it when tries to reinstantiate a fragment automatically
* (for instance, when the device is turned a aside).
* MUST BE KEPT: the system uses it when tries to reinstantiate a fragment automatically
* (for instance, when the device is turned a aside).
*
* DO NOT CALL IT: an {@link OCFile} and {@link Account} must be provided for a successful
* construction
* DO NOT CALL IT: an {@link OCFile} and {@link Account} must be provided for a successful
* construction
*/
public PreviewImageFragment() {
mIgnoreFirstSavedState = false;
@ -180,7 +185,7 @@ public class PreviewImageFragment extends FileFragment {
toggleImageBackground();
}
});
mMultiView = (RelativeLayout) view.findViewById(R.id.multi_view);
setupMultiView(view);
@ -337,7 +342,7 @@ public class PreviewImageFragment extends FileFragment {
case R.id.action_share_file:
mContainerActivity.getFileOperationsHelper().showShareFile(getFile());
return true;
case R.id.action_open_file_with:
openFile();
return true;
@ -419,12 +424,14 @@ public class PreviewImageFragment extends FileFragment {
* @param imageView Target {@link ImageView} where the bitmap will be loaded into.
*/
public LoadBitmapTask(ImageViewCustom imageView) {
mImageViewRef = new WeakReference<ImageViewCustom>(imageView);
mImageViewRef = new WeakReference<>(imageView);
}
@Override
protected LoadImage doInBackground(OCFile... params) {
Bitmap result = null;
Bitmap bitmapResult = null;
Drawable drawableResult = null;
if (params.length != 1) {
return null;
}
@ -436,51 +443,72 @@ public class PreviewImageFragment extends FileFragment {
Point screenSize = DisplayUtils.getScreenSize(getActivity());
int minWidth = screenSize.x;
int minHeight = screenSize.y;
for (int i = 0; i < maxDownScale && result == null; i++) {
if (isCancelled()) {
return null;
}
try {
result = BitmapUtils.decodeSampledBitmapFromFile(storagePath, minWidth,
minHeight);
for (int i = 0; i < maxDownScale && bitmapResult == null && drawableResult == null; i++) {
if (ocFile.getMimetype().equalsIgnoreCase("image/svg+xml")) {
if (isCancelled()) {
return new LoadImage(result, ocFile);
return null;
}
if (result == null) {
mErrorMessageId = R.string.preview_image_error_unknown_format;
Log_OC.e(TAG, "File could not be loaded as a bitmap: " + storagePath);
break;
} else {
if (ocFile.getMimetype().equalsIgnoreCase("image/jpeg")) {
// Rotate image, obeying exif tag.
result = BitmapUtils.rotateImage(result, storagePath);
try {
SVG svg = SVG.getFromInputStream(new FileInputStream(storagePath));
drawableResult = new PictureDrawable(svg.renderToPicture());
if (isCancelled()) {
return new LoadImage(null, drawableResult, ocFile);
}
} catch (FileNotFoundException e) {
mErrorMessageId = R.string.common_error_unknown;
Log_OC.e(TAG, "File not found trying to load " + getFile().getStoragePath(), e);
} catch (SVGParseException e) {
mErrorMessageId = R.string.common_error_unknown;
Log_OC.e(TAG, "Couldn't parse SVG " + getFile().getStoragePath(), e);
}
} else {
if (isCancelled()) {
return null;
}
} catch (OutOfMemoryError e) {
mErrorMessageId = R.string.common_error_out_memory;
if (i < maxDownScale - 1) {
Log_OC.w(TAG, "Out of memory rendering file " + storagePath +
" ; scaling down");
minWidth = minWidth / 2;
minHeight = minHeight / 2;
try {
bitmapResult = BitmapUtils.decodeSampledBitmapFromFile(storagePath, minWidth,
minHeight);
} else {
Log_OC.w(TAG, "Out of memory rendering file " + storagePath +
" ; failing");
if (isCancelled()) {
return new LoadImage(bitmapResult, null, ocFile);
}
if (bitmapResult == null) {
mErrorMessageId = R.string.preview_image_error_unknown_format;
Log_OC.e(TAG, "File could not be loaded as a bitmap: " + storagePath);
break;
} else {
if (ocFile.getMimetype().equalsIgnoreCase("image/jpeg")) {
// Rotate image, obeying exif tag.
bitmapResult = BitmapUtils.rotateImage(bitmapResult, storagePath);
}
}
} catch (OutOfMemoryError e) {
mErrorMessageId = R.string.common_error_out_memory;
if (i < maxDownScale - 1) {
Log_OC.w(TAG, "Out of memory rendering file " + storagePath + " ; scaling down");
minWidth = minWidth / 2;
minHeight = minHeight / 2;
} else {
Log_OC.w(TAG, "Out of memory rendering file " + storagePath + " ; failing");
}
if (bitmapResult != null) {
bitmapResult.recycle();
}
bitmapResult = null;
}
if (result != null) {
result.recycle();
}
result = null;
}
}
} catch (NoSuchFieldError e) {
mErrorMessageId = R.string.common_error_unknown;
Log_OC.e(TAG, "Error from access to unexisting field despite protection; file "
Log_OC.e(TAG, "Error from access to non-existing field despite protection; file "
+ storagePath, e);
} catch (Throwable t) {
@ -489,7 +517,7 @@ public class PreviewImageFragment extends FileFragment {
}
return new LoadImage(result, ocFile);
return new LoadImage(bitmapResult, drawableResult, ocFile);
}
@Override
@ -501,7 +529,7 @@ public class PreviewImageFragment extends FileFragment {
@Override
protected void onPostExecute(LoadImage result) {
if (result.bitmap != null) {
if (result.bitmap != null || result.drawable != null) {
showLoadedImage(result);
} else {
showErrorMessage();
@ -516,23 +544,43 @@ public class PreviewImageFragment extends FileFragment {
private void showLoadedImage(LoadImage result) {
final ImageViewCustom imageView = mImageViewRef.get();
Bitmap bitmap = result.bitmap;
if (imageView != null) {
Log_OC.d(TAG, "Showing image with resolution " + bitmap.getWidth() + "x" +
bitmap.getHeight());
if (bitmap != null) {
Log_OC.d(TAG, "Showing image with resolution " + bitmap.getWidth() + "x" +
bitmap.getHeight());
}
if (result.ocFile.getMimetype().equalsIgnoreCase("image/png")) {
if (result.ocFile.getMimetype().equalsIgnoreCase("image/png") ||
result.ocFile.getMimetype().equals("image/svg+xml")) {
if (getResources() != null) {
Resources r = getResources();
Drawable[] layers = new Drawable[2];
layers[0] = r.getDrawable(R.color.white);
Drawable bitmapDrawable = new BitmapDrawable(getResources(), bitmap);
Drawable bitmapDrawable;
if (result.ocFile.getMimetype().equalsIgnoreCase("image/png") ) {
bitmapDrawable = new BitmapDrawable(getResources(), bitmap);
} else {
bitmapDrawable = result.drawable;
}
layers[1] = bitmapDrawable;
LayerDrawable layerDrawable = new LayerDrawable(layers);
layerDrawable.setLayerHeight(0, convertDpToPixel(bitmap.getHeight(), getActivity()));
layerDrawable.setLayerHeight(1, convertDpToPixel(bitmap.getHeight(), getActivity()));
layerDrawable.setLayerWidth(0, convertDpToPixel(bitmap.getWidth(), getActivity()));
layerDrawable.setLayerWidth(1, convertDpToPixel(bitmap.getWidth(), getActivity()));
if (result.ocFile.getMimetype().equalsIgnoreCase("image/png") ) {
layerDrawable.setLayerHeight(0, convertDpToPixel(bitmap.getHeight(), getActivity()));
layerDrawable.setLayerHeight(1, convertDpToPixel(bitmap.getHeight(), getActivity()));
layerDrawable.setLayerWidth(0, convertDpToPixel(bitmap.getWidth(), getActivity()));
layerDrawable.setLayerWidth(1, convertDpToPixel(bitmap.getWidth(), getActivity()));
} else {
layerDrawable.setLayerHeight(0, convertDpToPixel(bitmapDrawable.getIntrinsicHeight(),
getActivity()));
layerDrawable.setLayerHeight(1, convertDpToPixel(bitmapDrawable.getIntrinsicHeight(),
getActivity()));
layerDrawable.setLayerWidth(0, convertDpToPixel(bitmapDrawable.getIntrinsicWidth(),
getActivity()));
layerDrawable.setLayerWidth(1, convertDpToPixel(bitmapDrawable.getIntrinsicWidth(),
getActivity()));
}
imageView.setImageDrawable(layerDrawable);
} else {
imageView.setImageBitmap(bitmap);
@ -541,7 +589,8 @@ public class PreviewImageFragment extends FileFragment {
if (result.ocFile.getMimetype().equalsIgnoreCase("image/gif")) {
imageView.setGIFImageFromStoragePath(result.ocFile.getStoragePath());
} else if (!result.ocFile.getMimetype().equalsIgnoreCase("image/png")) {
} else if (!result.ocFile.getMimetype().equalsIgnoreCase("image/png") &&
!result.ocFile.getMimetype().equals("image/svg+xml")) {
imageView.setImageBitmap(bitmap);
}
@ -589,8 +638,8 @@ public class PreviewImageFragment extends FileFragment {
* Helper method to test if an {@link OCFile} can be passed to a {@link PreviewImageFragment}
* to be previewed.
*
* @param file File to test if can be previewed.
* @return 'True' if the file can be handled by the fragment.
* @param file File to test if can be previewed.
* @return 'True' if the file can be handled by the fragment.
*/
public static boolean canBePreviewed(OCFile file) {
return (file != null && MimeTypeUtil.isImage(file));
@ -606,7 +655,8 @@ public class PreviewImageFragment extends FileFragment {
}
private void toggleImageBackground() {
if (getFile() != null && getFile().getMimetype().equalsIgnoreCase("image/png") && getActivity() != null
if (getFile() != null && (getFile().getMimetype().equalsIgnoreCase("image/png") ||
getFile().getMimetype().equalsIgnoreCase("image/svg+xml")) && getActivity() != null
&& getActivity() instanceof PreviewImageActivity && getResources() != null) {
PreviewImageActivity previewImageActivity = (PreviewImageActivity) getActivity();
LayerDrawable layerDrawable = (LayerDrawable) mImageView.getDrawable();
@ -640,10 +690,12 @@ public class PreviewImageFragment extends FileFragment {
private class LoadImage {
private Bitmap bitmap;
private Drawable drawable;
private OCFile ocFile;
public LoadImage(Bitmap bitmap, OCFile ocFile) {
public LoadImage(Bitmap bitmap, Drawable drawable, OCFile ocFile) {
this.bitmap = bitmap;
this.drawable = drawable;
this.ocFile = ocFile;
}