/*
* Copyright (C) 2013 Peng fei Pan <sky@xiaopan.me>
*
* 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 me.xiaopan.sketch.feature.large;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import me.xiaopan.sketch.SLog;
import me.xiaopan.sketch.SLogType;
import me.xiaopan.sketch.SketchImageView;
import me.xiaopan.sketch.decode.ImageType;
import me.xiaopan.sketch.drawable.LoadingDrawable;
import me.xiaopan.sketch.drawable.SketchDrawable;
import me.xiaopan.sketch.feature.zoom.ImageZoomer;
import me.xiaopan.sketch.util.SketchUtils;
/**
* 大图功能
*/
public class LargeImageFunction extends SketchImageView.Function implements ImageZoomer.OnMatrixChangeListener, LargeImageViewer.Callback {
private static final String NAME = "LargeImageFunction";
private SketchImageView imageView;
private LargeImageViewer largeImageViewer;
private Matrix tempDrawMatrix;
private Rect tempVisibleRect;
private String imageUri;
public LargeImageFunction(SketchImageView imageView) {
this.imageView = imageView;
this.largeImageViewer = new LargeImageViewer(imageView.getContext(), this);
if (!SketchUtils.sdkSupportBitmapRegionDecoder()) {
if (SLogType.LARGE.isEnabled()) {
SLog.w(SLogType.LARGE, NAME, "large image function the minimum support to GINGERBREAD_MR1");
}
}
}
/**
* 绑定图片缩放器
*/
public void bindImageZoomer(ImageZoomer imageZoomer) {
if (imageZoomer == null) {
throw new IllegalStateException("imageZoomer is null");
}
// 当缩放功能产生变化时回调大图功能
imageZoomer.addOnMatrixChangeListener(this);
// 大图功能的开关对缩放功能的缩放比例的计算有影响,因此需要更新一下缩放功能
imageZoomer.update();
}
@Override
public void onAttachedToWindow() {
if (!SketchUtils.sdkSupportBitmapRegionDecoder()) {
return;
}
resetImage();
}
@Override
public void onDraw(Canvas canvas) {
if (!SketchUtils.sdkSupportBitmapRegionDecoder()) {
return;
}
if (largeImageViewer.isReady()) {
largeImageViewer.draw(canvas);
}
}
@Override
public boolean onDetachedFromWindow() {
if (!SketchUtils.sdkSupportBitmapRegionDecoder()) {
return false;
}
recycle("onDetachedFromWindow");
return false;
}
@Override
public boolean onDrawableChanged(String callPosition, Drawable oldDrawable, Drawable newDrawable) {
if (!SketchUtils.sdkSupportBitmapRegionDecoder()) {
return false;
}
resetImage();
return false;
}
@Override
public void onMatrixChanged(ImageZoomer imageZoomer) {
if (!SketchUtils.sdkSupportBitmapRegionDecoder()) {
return;
}
if (!largeImageViewer.isReady() && !largeImageViewer.isInitializing()) {
if (SLogType.LARGE.isEnabled()) {
SLog.w(SLogType.LARGE, NAME, "largeImageViewer not available. onMatrixChanged. %s", imageUri);
}
return;
}
if (imageZoomer.getRotateDegrees() % 90 != 0) {
if (SLogType.LARGE.isEnabled()) {
SLog.w(SLogType.LARGE, NAME, "rotate degrees must be in multiples of 90. %s", imageUri);
}
return;
}
if (tempDrawMatrix == null) {
tempDrawMatrix = new Matrix();
tempVisibleRect = new Rect();
}
tempDrawMatrix.reset();
tempVisibleRect.setEmpty();
imageZoomer.getDrawMatrix(tempDrawMatrix);
imageZoomer.getVisibleRect(tempVisibleRect);
largeImageViewer.update(tempDrawMatrix, tempVisibleRect, imageZoomer.getDrawableSize(),
imageZoomer.getImageViewSize(), imageZoomer.isZooming());
}
private void resetImage() {
if (!SketchUtils.sdkSupportBitmapRegionDecoder()) {
return;
}
Drawable previewDrawable = SketchUtils.getLastDrawable(imageView.getDrawable());
SketchDrawable sketchDrawable = null;
boolean drawableQualified = false;
if (previewDrawable != null && previewDrawable instanceof SketchDrawable && !(previewDrawable instanceof LoadingDrawable)) {
sketchDrawable = (SketchDrawable) previewDrawable;
final int previewWidth = previewDrawable.getIntrinsicWidth();
final int previewHeight = previewDrawable.getIntrinsicHeight();
final int imageWidth = sketchDrawable.getOriginWidth();
final int imageHeight = sketchDrawable.getOriginHeight();
drawableQualified = previewWidth < imageWidth || previewHeight < imageHeight;
drawableQualified &= SketchUtils.sdkSupportBitmapRegionDecoder();
drawableQualified &= SketchUtils.formatSupportBitmapRegionDecoder(ImageType.valueOfMimeType(sketchDrawable.getMimeType()));
if (drawableQualified) {
if (SLogType.LARGE.isEnabled()) {
SLog.d(SLogType.LARGE, NAME, "Use large image function. previewDrawableSize: %dx%d, imageSize: %dx%d, mimeType: %s. %s",
previewWidth, previewHeight, imageWidth, imageHeight, sketchDrawable.getMimeType(), sketchDrawable.getKey());
}
} else {
if (SLogType.LARGE.isEnabled()) {
SLog.w(SLogType.LARGE, NAME, "Don't need to use large image function. previewDrawableSize: %dx%d, imageSize: %dx%d, mimeType: %s. %s",
previewWidth, previewHeight, imageWidth, imageHeight, sketchDrawable.getMimeType(), sketchDrawable.getKey());
}
}
}
if (drawableQualified) {
imageUri = sketchDrawable.getUri();
largeImageViewer.setImage(imageUri, sketchDrawable.getOrientation() != 0);
} else {
imageUri = null;
largeImageViewer.setImage(null, false);
}
}
public void recycle(String why) {
if (!SketchUtils.sdkSupportBitmapRegionDecoder()) {
return;
}
largeImageViewer.recycle(why);
}
@Override
public void invalidate() {
if (!SketchUtils.sdkSupportBitmapRegionDecoder()) {
return;
}
imageView.invalidate();
}
@Override
public void updateMatrix() {
ImageZoomer imageZoomer = imageView.isSupportZoom() ? imageView.getImageZoomer() : null;
if (imageZoomer != null) {
onMatrixChanged(imageZoomer);
}
}
public LargeImageViewer getLargeImageViewer() {
return largeImageViewer;
}
}