如何实现旋转图像算法并放大或缩小图像? 我尝试实现旋转算法,但图像不显示,我不知道算法是否正常,请检查旋转算法是否正常,请帮我在旋转后显示图像并在缩放后显示图像。我想在没有预定义功能的情况下旋转和缩放图像。
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Rotation extends JPanel{
public static void main(String []args){
JFrame f = new JFrame();
f.add(new Rotation());
f.setSize(750, 600);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
BufferedImage img = null;
try {
img = ImageIO.read(new File("img.jpg"));
} catch (IOException e) {
e.printStackTrace();
}
Rotation r = new Rotation();
r.rotateCw(img, null);
}
public static void rotateCw( BufferedImage img, Graphics g )
{
int width = img.getWidth();
int height = img.getHeight();
BufferedImage newImage = new BufferedImage( height, width, img.getType() );
for( int i=0 ; i < width ; i++ ){
for( int j=0 ; j < height ; j++ ){
newImage.setRGB( height-1-j, i, img.getRGB(i,j) );;
}
}
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(newImage, 25, 25, null);
}
}
答案 0 :(得分:1)
您还没有将rotateCW传递给图形对象。你的代码看起来像这样......
Rotation r = new Rotation();
Graphics graphics = f.getGraphics();
r.rotateCw(img, graphics);
graphics.dispose();
它需要看起来像这样..从JFrame获取一个Graphics对象以将结果绘制到。
{{1}}
我测试了你的代码并添加了它并且它有效:)在你的情况下,它会在丢失的Graphics对象上抛出一个异常,只留下空的JPanel。
答案 1 :(得分:0)
您可以通过以下方式执行此操作: 首先创建一个DraggableBitmap类
public class DraggableBitmap {
private boolean activated;
private Matrix currentMatrix;
public Bitmap mBitmap;
private int mId;
private Matrix marginMatrix;
private Matrix savedMatrix;
private boolean touched;
public DraggableBitmap(Bitmap b) {
this.mId = -1;
this.currentMatrix = null;
this.savedMatrix = null;
this.mBitmap = b;
this.activated = false;
}
public void setCurrentMatrix(Matrix m) {
this.currentMatrix = null;
this.currentMatrix = new Matrix(m);
}
public void setSavedMatrix(Matrix m) {
this.savedMatrix = null;
this.savedMatrix = new Matrix(m);
}
public Matrix getCurrentMatrix() {
return this.currentMatrix;
}
public Matrix getSavedMatrix() {
return this.savedMatrix;
}
public void activate() {
this.activated = true;
}
public void deActivate() {
this.activated = false;
}
public boolean isActivate() {
return this.activated;
}
public boolean isTouched() {
return this.touched;
}
public void setTouched(boolean touched) {
this.touched = touched;
}
public Matrix getMarginMatrix() {
return this.marginMatrix;
}
public void setMarginMatrix(Matrix marginMatrix) {
this.marginMatrix = null;
this.marginMatrix = new Matrix(marginMatrix);
}
public int getmId() {
return this.mId;
}
public void setmId(int mId) {
this.mId = mId;
}
}
现在创建DraggableImageView,它扩展了imageview
public class DraggableImageView extends ImageView {
// some private variable use for detect multi touch
public enum EDITMODE {
NONE, DRAG, ZOOM, ROTATE
}
private static final String TAG = "Draggable Bitmap";
private boolean mDrawOpacityBackground = false;
private Paint mPaint = new Paint();
private DraggableBitmap mActiveBitmap = null;
private RectF mInnerImageBounds = null;
private Stack<BitmapOperationMap> mOperationStack = new Stack<BitmapOperationMap>();
public Context context;
// list of stamp bitmaps
private List<DraggableBitmap> mOverlayBitmaps;
// constructors
public DraggableImageView(Context context) {
super(context);
initMembers();
this.setOnTouchListener(touchListener);
this.context=context;
}
public DraggableImageView(Context context, AttributeSet attrs) {
super(context, attrs);
initMembers();
this.setOnTouchListener(touchListener);
this.context=context;
}
private void initMembers() {
mOverlayBitmaps = new ArrayList<DraggableBitmap>();
}
// listeners
private OnTouchListener touchListener = new OnTouchListener() {
// to get mode [drag, zoom, rotate]
private EDITMODE mEditMode = EDITMODE.NONE;
private float[] mLastEvent;
private PointF mStart = new PointF();
private PointF mMid = new PointF();
private float mOldDistance;
private float mNewRotation = 0f;
private float mDist = 0f;
// this variable use to deal with android odd touch behavior (MOVE -> UP
// -> MOVE -> UP)
private boolean touchMoveEndChecker = false;
@Override
public boolean onTouch(View v, MotionEvent event) {
// switch finger events
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case (MotionEvent.ACTION_DOWN):
touchMoveEndChecker = true;
mDrawOpacityBackground = true;
int activebmpIdx = getActiveBitmap(event.getX(), event.getY());
if (activebmpIdx != -1) {
mActiveBitmap = mOverlayBitmaps.get(activebmpIdx);
rearrangeOverlayList();
} else {
mActiveBitmap = null;
break;
}
mLastEvent = null;
mEditMode = EDITMODE.DRAG;
mStart.set(event.getX(), event.getY());
if (mActiveBitmap != null) {
mActiveBitmap.setSavedMatrix(mActiveBitmap.getCurrentMatrix());
}
facePlacer.showInvisible(context);
break;
case (MotionEvent.ACTION_POINTER_DOWN):
touchMoveEndChecker = false;
mDrawOpacityBackground = true;
if (mActiveBitmap != null) {
mOldDistance = spacing(event);
if (mOldDistance > 10f) {
mActiveBitmap.setSavedMatrix(mActiveBitmap.getCurrentMatrix());
midPoint(mMid, event);
mEditMode = EDITMODE.ZOOM;
}
mLastEvent = new float[4];
mLastEvent[0] = event.getX(0);
mLastEvent[1] = event.getX(1);
mLastEvent[2] = event.getY(0);
mLastEvent[3] = event.getY(1);
mDist = rotation(event);
}
break;
case (MotionEvent.ACTION_POINTER_UP):
mEditMode = EDITMODE.NONE;
break;
case (MotionEvent.ACTION_MOVE):
touchMoveEndChecker = false;
mDrawOpacityBackground = true;
if (mActiveBitmap != null) {
if (mEditMode == EDITMODE.DRAG) {
mActiveBitmap.setCurrentMatrix(mActiveBitmap.getSavedMatrix());
mActiveBitmap.getCurrentMatrix().postTranslate(event.getX() - mStart.x,
event.getY() - mStart.y);
} else if (mEditMode == EDITMODE.ZOOM && event.getPointerCount() == 2) {
float newDistance = spacing(event);
mActiveBitmap.setCurrentMatrix(mActiveBitmap.getSavedMatrix());
if (newDistance > 10f) {
float scale = newDistance / mOldDistance;
mActiveBitmap.getCurrentMatrix()
.postScale(scale, scale, mMid.x, mMid.y);
}
if (mLastEvent != null) {
mNewRotation = rotation(event);
float r = mNewRotation - mDist;
RectF rec = new RectF(0, 0, mActiveBitmap.mBitmap.getWidth(),
mActiveBitmap.mBitmap.getHeight());
mActiveBitmap.getCurrentMatrix().mapRect(rec);
mActiveBitmap.getCurrentMatrix().postRotate(r,
rec.left + rec.width() / 2, rec.top + rec.height() / 2);
}
}
}
case (MotionEvent.ACTION_UP):
if (touchMoveEndChecker) { // means 2 continuous ACTION_UP, or
// real finger up after moving
mDrawOpacityBackground = false;
if (mActiveBitmap != null) {
// push a map to bitmap and clone of current matrix
mOperationStack
.push(new BitmapOperationMap(mActiveBitmap, new Matrix(
mActiveBitmap.getCurrentMatrix()),
BitmapOperationMap.OPERATION.ADD));
mActiveBitmap.deActivate();
}
facePlacer.showvisible(context);
}
touchMoveEndChecker = true;
default:
break;
}
invalidate();
return true;
}
};
public int addOverlayBitmap(DraggableBitmap dBitmap) {
Matrix marginMtx = new Matrix();
marginMtx.postTranslate(mInnerImageBounds.left, mInnerImageBounds.top);
dBitmap.setMarginMatrix(marginMtx);
Matrix curMtx = new Matrix();
curMtx.postConcat(marginMtx);
dBitmap.setCurrentMatrix(curMtx);
mOperationStack
.push(new BitmapOperationMap(dBitmap, null, BitmapOperationMap.OPERATION.NEW));
mOperationStack.push(new BitmapOperationMap(dBitmap, dBitmap.getCurrentMatrix(),
BitmapOperationMap.OPERATION.ADD));
dBitmap.setmId(this.mOverlayBitmaps.size());
mOverlayBitmaps.add(dBitmap);
invalidate();
return dBitmap.getmId();
}
private int getActiveBitmap(float event_x, float event_y) {
int size = mOverlayBitmaps.size();
int retidx = -1;
DraggableBitmap retBmp = null;
// search for all bitmap to find closest to finger
for (int i = 0; i < size; i++) {
DraggableBitmap dBmp = mOverlayBitmaps.get(i);
dBmp.deActivate();
float bmp_x = 0;
float bmp_y = 0;
RectF r = new RectF(0, 0, dBmp.mBitmap.getWidth(), dBmp.mBitmap.getHeight());
Matrix mtx = dBmp.getCurrentMatrix() == null ? dBmp.getMarginMatrix() : dBmp
.getCurrentMatrix();
mtx.mapRect(r);
bmp_x = r.left;
bmp_y = r.top;
if (event_x >= bmp_x && event_x < (bmp_x + r.width()) && event_y >= bmp_y
&& event_y < (bmp_y + r.height())) {
retBmp = dBmp;
retidx = i;
}
}
if (retBmp != null) {
if (!retBmp.isTouched()) {
retBmp.setTouched(true);
}
retBmp.activate();
}
return retidx;
}
private float spacing(MotionEvent event) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return (float) Math.sqrt(x * x + y * y);
}
/**
* Calculate the mid point of the first two fingers
*/
private void midPoint(PointF point, MotionEvent event) {
float x = event.getX(0) + event.getX(1);
float y = event.getY(0) + event.getY(1);
point.set(x / 2, y / 2);
}
private float rotation(MotionEvent event) {
double delta_x = (event.getX(0) - event.getX(1));
double delta_y = (event.getY(0) - event.getY(1));
double rad = Math.atan2(delta_y, delta_x);
return (float) Math.toDegrees(rad);
}
public List<DraggableBitmap> getOverlayList() {
return mOverlayBitmaps;
}
public void undo() {
if (!mOperationStack.empty()) {
BitmapOperationMap prev = mOperationStack.pop();
if (!mOperationStack.empty()) { // current stack is final operation
prev = mOperationStack.peek();
}
DraggableBitmap bmp = prev.getDraggableBitmap();
Matrix mtx = prev.getOperationMatrix();
switch (prev.getOption()) {
case NEW: // if action is create new, then delete
mOverlayBitmaps.remove(bmp);
break;
case ADD:
bmp.setCurrentMatrix(mtx);
break;
case DELETE: // not implement yet
break;
default:
break;
}
}
}
@Override
protected void onDraw(Canvas canvas) { // [TODO] khi xoay man hinh error
super.onDraw(canvas);
RectF bitmapRect = getInnerBitmapSize();
if (bitmapRect == null) return;
mInnerImageBounds = bitmapRect;
canvas.clipRect(bitmapRect);
// loop to draw all bitmap
Enumeration<DraggableBitmap> e = Collections.enumeration(mOverlayBitmaps);
while (e.hasMoreElements()) {
DraggableBitmap dBmp = (DraggableBitmap) e.nextElement();
if (true) {
if (dBmp.getCurrentMatrix() != null) {
canvas.drawBitmap(dBmp.mBitmap, dBmp.getCurrentMatrix(), null);
RectF r = getStampBounding(dBmp);
if (mDrawOpacityBackground && dBmp == mActiveBitmap) {
mPaint.setColor(0x00000000);
mPaint.setStyle(Style.FILL);
mPaint.setAlpha(20);
canvas.drawRect(r, mPaint);
}
}
}
}
}
public RectF getInnerBitmapSize() {
RectF bitmapRect = new RectF();
if (this.getDrawable() == null) return null;
bitmapRect.right = this.getDrawable().getIntrinsicWidth();
bitmapRect.bottom = this.getDrawable().getIntrinsicHeight();
Matrix m = this.getImageMatrix();
m.mapRect(bitmapRect);
return bitmapRect;
}
private RectF getStampBounding(DraggableBitmap bmp) {
if (bmp.mBitmap == null) return null;
RectF r = new RectF(0, 0, bmp.mBitmap.getWidth(), bmp.mBitmap.getHeight());
bmp.getCurrentMatrix().mapRect(r);
return r;
}
public void deleteActiveBitmap() {
if (mActiveBitmap == null) return;
mOverlayBitmaps.remove(mActiveBitmap);
}
public void replaceOverlayBitmap(DraggableBitmap dBitmap, int replaceIndex) {
if (replaceIndex <= this.mOverlayBitmaps.size()) {
this.mActiveBitmap = (DraggableBitmap) this.mOverlayBitmaps.get(replaceIndex);
dBitmap.setCurrentMatrix(this.mActiveBitmap.getCurrentMatrix());
this.mOverlayBitmaps.add(replaceIndex, dBitmap);
this.mOverlayBitmaps.remove(this.mActiveBitmap);
this.mActiveBitmap = (DraggableBitmap) this.mOverlayBitmaps.get(replaceIndex);
invalidate();
}
}
public void flipActiveBitmap() {
try {
Matrix flipHorizontalMtx = new Matrix();
flipHorizontalMtx.setScale(-1, 1);
flipHorizontalMtx.postTranslate((float) (mActiveBitmap.mBitmap.getWidth()), (float) 0);
Matrix mtx = mActiveBitmap.getCurrentMatrix();
mtx.preConcat(flipHorizontalMtx);
mActiveBitmap.setCurrentMatrix(mtx);
} catch (NullPointerException e) {
Log.v(TAG, "active bitmap is null");
} catch (Exception e) {
Log.v(TAG, "error ocurred");
}
}
public void rearrangeOverlayList() {
int idx = mOverlayBitmaps.indexOf(mActiveBitmap);
mOverlayBitmaps.add(mActiveBitmap);
mOverlayBitmaps.remove(idx);
}
public void removeAll() {
mOverlayBitmaps.clear();
mOverlayBitmaps = new ArrayList();
invalidate();
}
}
现在扩展了imageview的ProportionalImageView
public class ProportionalImageView extends ImageView {
public ProportionalImageView(Context context) {
super(context);
}
public ProportionalImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ProportionalImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Drawable d = getDrawable();
if (d != null) {
int w = MeasureSpec.getSize(widthMeasureSpec);
int h = w * d.getIntrinsicHeight() / d.getIntrinsicWidth();
setMeasuredDimension(w, h);
} else super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
现在只需将这些类用作
DraggableBitmap stamp1 = new DraggableBitmap(thumbnail);
replaceMap.put(1, canvasImage.addOverlayBitmap(stamp1));
Replacemap是用于存储图像的哈希映射。
答案 2 :(得分:0)
我只是添加另一个答案,向您展示如何使用您在其他答案中询问的旋转代码。我只需更改引用Picture类的代码即可使用BufferedImages。您还必须考虑制作新图像的大小。
public static void rotateCw( BufferedImage img, Graphics g, double degrees ) {
int width = img.getWidth();
int height = img.getHeight();
BufferedImage newImage = new BufferedImage( width, height, img.getType() );
double angle = Math.toRadians( degrees );
double sin = Math.sin(angle);
double cos = Math.cos(angle);
double x0 = 0.5 * (width - 1); // point to rotate about
double y0 = 0.5 * (height - 1); // center of image
// rotation
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
double a = x - x0;
double b = y - y0;
int xx = (int) (+a * cos - b * sin + x0);
int yy = (int) (+a * sin + b * cos + y0);
if (xx >= 0 && xx < width && yy >= 0 && yy < height) {
newImage.setRGB(x, y, img.getRGB(xx, yy));
}
}
}
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(newImage, 0, 0, null);
}