NekoX/TMessagesProj/src/main/java/org/telegram/ui/Components/ClippingImageView.java

300 lines
9.7 KiB
Java
Raw Normal View History

/*
2019-01-23 18:03:33 +01:00
* This is the source code of Telegram for Android v. 5.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
2019-01-23 18:03:33 +01:00
* Copyright Nikolai Kudashov, 2013-2018.
*/
package org.telegram.ui.Components;
import android.content.Context;
2019-01-23 18:03:33 +01:00
import android.graphics.Bitmap;
2014-11-17 03:44:57 +01:00
import android.graphics.BitmapShader;
import android.graphics.Canvas;
2014-11-17 03:44:57 +01:00
import android.graphics.Matrix;
import android.graphics.Paint;
2020-01-23 07:15:40 +01:00
import android.graphics.Path;
2014-11-17 03:44:57 +01:00
import android.graphics.RectF;
import android.graphics.Shader;
2019-05-14 14:08:05 +02:00
import androidx.annotation.Keep;
import android.view.View;
2016-10-11 13:57:01 +02:00
import org.telegram.messenger.AndroidUtilities;
2014-07-20 01:31:49 +02:00
import org.telegram.messenger.FileLog;
2018-07-30 04:07:02 +02:00
import org.telegram.messenger.ImageReceiver;
2014-07-20 01:31:49 +02:00
2020-07-26 10:03:38 +02:00
import java.util.Arrays;
public class ClippingImageView extends View {
2015-04-09 20:00:14 +02:00
private int clipBottom;
private int clipLeft;
private int clipRight;
private int clipTop;
private int orientation;
2019-03-03 21:40:48 +01:00
private int imageY;
private int imageX;
private RectF drawRect;
private Paint paint;
2018-07-30 04:07:02 +02:00
private ImageReceiver.BitmapHolder bmp;
private Matrix matrix;
2014-11-17 03:44:57 +01:00
private boolean needRadius;
2020-01-23 07:15:40 +01:00
private int[] radius = new int[4];
2014-11-17 03:44:57 +01:00
private BitmapShader bitmapShader;
private Paint roundPaint;
private RectF roundRect;
private RectF bitmapRect;
private Matrix shaderMatrix;
2020-01-23 07:15:40 +01:00
private Path roundPath = new Path();
private static float[] radii = new float[8];
2014-11-17 03:44:57 +01:00
private float animationProgress;
2020-01-23 07:15:40 +01:00
private float[][] animationValues;
2020-02-13 19:26:53 +01:00
private float additionalTranslationY;
2020-07-26 10:03:38 +02:00
private float additionalTranslationX;
2020-02-13 19:26:53 +01:00
public ClippingImageView(Context context) {
super(context);
2019-03-03 21:40:48 +01:00
paint = new Paint(Paint.FILTER_BITMAP_FLAG);
paint.setFilterBitmap(true);
matrix = new Matrix();
drawRect = new RectF();
bitmapRect = new RectF();
2019-03-03 21:40:48 +01:00
roundPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
2016-04-22 15:49:00 +02:00
roundRect = new RectF();
shaderMatrix = new Matrix();
}
public void setAnimationValues(float[][] values) {
animationValues = values;
}
2020-02-13 19:26:53 +01:00
public void setAdditionalTranslationY(float value) {
additionalTranslationY = value;
}
2020-07-26 10:03:38 +02:00
public void setAdditionalTranslationX(float value) {
additionalTranslationX = value;
}
2020-02-13 19:26:53 +01:00
@Override
public void setTranslationY(float translationY) {
super.setTranslationY(translationY + additionalTranslationY);
}
@Override
public float getTranslationY() {
return super.getTranslationY() - additionalTranslationY;
}
2018-07-30 04:07:02 +02:00
@Keep
public float getAnimationProgress() {
return animationProgress;
}
2018-07-30 04:07:02 +02:00
@Keep
public void setAnimationProgress(float progress) {
animationProgress = progress;
setScaleX(animationValues[0][0] + (animationValues[1][0] - animationValues[0][0]) * animationProgress);
setScaleY(animationValues[0][1] + (animationValues[1][1] - animationValues[0][1]) * animationProgress);
2020-07-26 10:03:38 +02:00
setTranslationX(animationValues[0][2] + additionalTranslationX + (animationValues[1][2] + additionalTranslationX - animationValues[0][2] - additionalTranslationX) * animationProgress);
setTranslationY(animationValues[0][3] + (animationValues[1][3] - animationValues[0][3]) * animationProgress);
setClipHorizontal((int) (animationValues[0][4] + (animationValues[1][4] - animationValues[0][4]) * animationProgress));
setClipTop((int) (animationValues[0][5] + (animationValues[1][5] - animationValues[0][5]) * animationProgress));
setClipBottom((int) (animationValues[0][6] + (animationValues[1][6] - animationValues[0][6]) * animationProgress));
2020-01-23 07:15:40 +01:00
for (int a = 0; a < radius.length; a++) {
radius[a] = (int) (animationValues[0][7 + a] + (animationValues[1][7 + a] - animationValues[0][7 + a]) * animationProgress);
setRadius(radius);
}
if (animationValues[0].length > 11) {
setImageY((int) (animationValues[0][11] + (animationValues[1][11] - animationValues[0][11]) * animationProgress));
setImageX((int) (animationValues[0][12] + (animationValues[1][12] - animationValues[0][12]) * animationProgress));
2019-03-03 21:40:48 +01:00
}
invalidate();
}
2019-12-31 14:08:08 +01:00
public void getClippedVisibleRect(RectF rect) {
rect.left = getTranslationX();
rect.top = getTranslationY();
rect.right = rect.left + getMeasuredWidth() * getScaleX();
rect.bottom = rect.top + getMeasuredHeight() * getScaleY();
rect.left += clipLeft;
rect.top += clipTop;
rect.right -= clipRight;
rect.bottom -= clipBottom;
}
public int getClipBottom() {
return clipBottom;
}
public int getClipHorizontal() {
return clipRight;
}
public int getClipLeft() {
return clipLeft;
}
public int getClipRight() {
return clipRight;
}
public int getClipTop() {
return clipTop;
}
2020-01-23 07:15:40 +01:00
public int[] getRadius() {
2014-11-17 03:44:57 +01:00
return radius;
}
public void onDraw(Canvas canvas) {
2015-04-09 20:00:14 +02:00
if (getVisibility() != VISIBLE) {
return;
}
2018-07-30 04:07:02 +02:00
if (bmp != null && !bmp.isRecycled()) {
float scaleY = getScaleY();
canvas.save();
2014-11-17 03:44:57 +01:00
if (needRadius) {
shaderMatrix.reset();
2019-03-03 21:40:48 +01:00
roundRect.set(imageX / scaleY, imageY / scaleY, getWidth() - imageX / scaleY, getHeight() - imageY / scaleY);
bitmapRect.set(0, 0, bmp.getWidth(), bmp.getHeight());
AndroidUtilities.setRectToRect(shaderMatrix, bitmapRect, roundRect, orientation, false);
2014-11-17 03:44:57 +01:00
bitmapShader.setLocalMatrix(shaderMatrix);
2016-04-22 15:49:00 +02:00
canvas.clipRect(clipLeft / scaleY, clipTop / scaleY, getWidth() - clipRight / scaleY, getHeight() - clipBottom / scaleY);
2020-01-23 07:15:40 +01:00
for (int a = 0; a < radius.length; a++) {
radii[a * 2] = radius[a];
radii[a * 2 + 1] = radius[a];
}
roundPath.reset();
roundPath.addRoundRect(roundRect, radii, Path.Direction.CW);
roundPath.close();
canvas.drawPath(roundPath, roundPaint);
2014-11-17 03:44:57 +01:00
} else {
if (orientation == 90 || orientation == 270) {
drawRect.set(-getHeight() / 2, -getWidth() / 2, getHeight() / 2, getWidth() / 2);
matrix.setRectToRect(bitmapRect, drawRect, Matrix.ScaleToFit.FILL);
matrix.postRotate(orientation, 0, 0);
matrix.postTranslate(getWidth() / 2, getHeight() / 2);
} else if (orientation == 180) {
drawRect.set(-getWidth() / 2, -getHeight() / 2, getWidth() / 2, getHeight() / 2);
matrix.setRectToRect(bitmapRect, drawRect, Matrix.ScaleToFit.FILL);
matrix.postRotate(orientation, 0, 0);
matrix.postTranslate(getWidth() / 2, getHeight() / 2);
} else {
drawRect.set(0, 0, getWidth(), getHeight());
matrix.setRectToRect(bitmapRect, drawRect, Matrix.ScaleToFit.FILL);
}
2014-11-17 03:44:57 +01:00
canvas.clipRect(clipLeft / scaleY, clipTop / scaleY, getWidth() - clipRight / scaleY, getHeight() - clipBottom / scaleY);
try {
2018-07-30 04:07:02 +02:00
canvas.drawBitmap(bmp.bitmap, matrix, paint);
2014-11-17 03:44:57 +01:00
} catch (Exception e) {
2017-03-31 01:58:05 +02:00
FileLog.e(e);
2014-11-17 03:44:57 +01:00
}
2014-07-20 01:31:49 +02:00
}
canvas.restore();
}
}
public void setClipBottom(int value) {
clipBottom = value;
invalidate();
}
public void setClipHorizontal(int value) {
clipRight = value;
clipLeft = value;
invalidate();
}
public void setClipLeft(int value) {
clipLeft = value;
invalidate();
}
public void setClipRight(int value) {
clipRight = value;
invalidate();
}
public void setClipTop(int value) {
clipTop = value;
invalidate();
}
public void setClipVertical(int value) {
clipBottom = value;
clipTop = value;
invalidate();
}
2019-03-03 21:40:48 +01:00
public void setImageY(int value) {
imageY = value;
}
public void setImageX(int value) {
imageX = value;
}
public void setOrientation(int angle) {
orientation = angle;
}
2022-06-21 04:51:00 +02:00
public float getCenterX() {
float scaleY = getScaleY();
return getTranslationX() + (clipLeft / scaleY + (getWidth() - clipRight / scaleY)) / 2 * getScaleX();
}
public float getCenterY() {
float scaleY = getScaleY();
return getTranslationY() + (clipTop / scaleY + (getHeight() - clipBottom / scaleY)) / 2 * getScaleY();
}
2018-07-30 04:07:02 +02:00
public void setImageBitmap(ImageReceiver.BitmapHolder bitmap) {
if (bmp != null) {
bmp.release();
bitmapShader = null;
}
bmp = bitmap;
2019-01-23 18:03:33 +01:00
if (bitmap != null && bitmap.bitmap != null) {
2014-11-17 03:44:57 +01:00
bitmapRect.set(0, 0, bitmap.getWidth(), bitmap.getHeight());
2020-01-23 07:15:40 +01:00
bitmapShader = new BitmapShader(bmp.bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
roundPaint.setShader(bitmapShader);
2014-11-17 03:44:57 +01:00
}
invalidate();
}
2019-01-23 18:03:33 +01:00
public Bitmap getBitmap() {
return bmp != null ? bmp.bitmap : null;
}
public int getOrientation() {
return orientation;
}
2020-01-23 07:15:40 +01:00
public void setRadius(int[] value) {
if (value == null) {
needRadius = false;
2020-07-26 10:03:38 +02:00
Arrays.fill(radius, 0);
2020-01-23 07:15:40 +01:00
return;
}
System.arraycopy(value, 0, radius, 0, value.length);
needRadius = false;
for (int a = 0; a < value.length; a++) {
if (value[a] != 0) {
needRadius = true;
break;
}
}
2014-11-17 03:44:57 +01:00
}
}