2013-04-24 20 views
16

Po prostu chcę udostępnić ten fragment kodu, który napisałem. Próbowałem wyszukać niestandardową aktywność przycinania, ale większość z nich prowadzi do domyślnego "com.android.camera.action.CROP", pomimo pytania o niestandardowe przycinanie lub odręczne przycinanie. W każdym razie, zrobiłem to dla siebie i mam nadzieję, że ci to pomoże.Niestandardowe przycinanie obrazu Android

public class CropView extends ImageView { 

    Paint paint = new Paint(); 
    private int initial_size = 300; 
    private static Point leftTop, rightBottom, center, previous; 

    private static final int DRAG= 0; 
    private static final int LEFT= 1; 
    private static final int TOP= 2; 
    private static final int RIGHT= 3; 
    private static final int BOTTOM= 4; 

    private int imageScaledWidth,imageScaledHeight; 
    // Adding parent class constructors 
    public CropView(Context context) { 
     super(context); 
     initCropView(); 
    } 

    public CropView(Context context, AttributeSet attrs) { 
     super(context, attrs, 0); 
     initCropView(); 
    } 

    public CropView(Context context, AttributeSet attrs, int defStyle) { 
     super(context, attrs, defStyle); 
     initCropView(); 
    } 

    @Override 
    protected void onDraw(Canvas canvas) 
    { 
     super.onDraw(canvas); 
     if(leftTop.equals(0, 0)) 
      resetPoints(); 
     canvas.drawRect(leftTop.x, leftTop.y, rightBottom.x, rightBottom.y, paint); 
    } 

    @Override 
    public boolean onTouchEvent(MotionEvent event) { 
     int eventaction = event.getAction(); 
     switch (eventaction) { 
      case MotionEvent.ACTION_DOWN: 
       previous.set((int)event.getX(), (int)event.getY()); 
       break; 
      case MotionEvent.ACTION_MOVE: 
       if(isActionInsideRectangle(event.getX(), event.getY())) { 
        adjustRectangle((int)event.getX(), (int)event.getY()); 
        invalidate(); // redraw rectangle 
        previous.set((int)event.getX(), (int)event.getY()); 
       } 
       break; 
      case MotionEvent.ACTION_UP: 
       previous = new Point(); 
       break; 
     }   
     return true; 
    } 

    private void initCropView() { 
     paint.setColor(Color.YELLOW); 
     paint.setStyle(Style.STROKE); 
     paint.setStrokeWidth(5); 
     leftTop = new Point(); 
     rightBottom = new Point(); 
     center = new Point(); 
     previous = new Point(); 
    } 

    public void resetPoints() { 
     center.set(getWidth()/2, getHeight()/2); 
     leftTop.set((getWidth()-initial_size)/2,(getHeight()-initial_size)/2); 
     rightBottom.set(leftTop.x+initial_size, leftTop.y+initial_size); 
    } 

    private static boolean isActionInsideRectangle(float x, float y) { 
     int buffer = 10; 
     return (x>=(leftTop.x-buffer)&&x<=(rightBottom.x+buffer)&& y>=(leftTop.y-buffer)&&y<=(rightBottom.y+buffer))?true:false; 
    } 

    private boolean isInImageRange(PointF point) { 
     // Get image matrix values and place them in an array 
     float[] f = new float[9]; 
     getImageMatrix().getValues(f); 

     // Calculate the scaled dimensions 
     imageScaledWidth = Math.round(getDrawable().getIntrinsicWidth() * f[Matrix.MSCALE_X]); 
     imageScaledHeight = Math.round(getDrawable().getIntrinsicHeight() * f[Matrix.MSCALE_Y]); 

     return (point.x>=(center.x-(imageScaledWidth/2))&&point.x<=(center.x+(imageScaledWidth/2))&&point.y>=(center.y-(imageScaledHeight/2))&&point.y<=(center.y+(imageScaledHeight/2)))?true:false; 
    } 

    private void adjustRectangle(int x, int y) { 
     int movement; 
     switch(getAffectedSide(x,y)) { 
      case LEFT: 
       movement = x-leftTop.x; 
       if(isInImageRange(new PointF(leftTop.x+movement,leftTop.y+movement))) 
        leftTop.set(leftTop.x+movement,leftTop.y+movement); 
       break; 
      case TOP: 
       movement = y-leftTop.y; 
       if(isInImageRange(new PointF(leftTop.x+movement,leftTop.y+movement))) 
        leftTop.set(leftTop.x+movement,leftTop.y+movement); 
       break; 
      case RIGHT: 
       movement = x-rightBottom.x; 
       if(isInImageRange(new PointF(rightBottom.x+movement,rightBottom.y+movement))) 
        rightBottom.set(rightBottom.x+movement,rightBottom.y+movement); 
       break; 
      case BOTTOM: 
       movement = y-rightBottom.y; 
       if(isInImageRange(new PointF(rightBottom.x+movement,rightBottom.y+movement))) 
        rightBottom.set(rightBottom.x+movement,rightBottom.y+movement); 
       break;  
      case DRAG: 
       movement = x-previous.x; 
       int movementY = y-previous.y; 
       if(isInImageRange(new PointF(leftTop.x+movement,leftTop.y+movementY)) && isInImageRange(new PointF(rightBottom.x+movement,rightBottom.y+movementY))) { 
        leftTop.set(leftTop.x+movement,leftTop.y+movementY); 
        rightBottom.set(rightBottom.x+movement,rightBottom.y+movementY); 
       } 
       break; 
     } 
    } 

    private static int getAffectedSide(float x, float y) { 
     int buffer = 10; 
     if(x>=(leftTop.x-buffer)&&x<=(leftTop.x+buffer)) 
      return LEFT; 
     else if(y>=(leftTop.y-buffer)&&y<=(leftTop.y+buffer)) 
      return TOP; 
     else if(x>=(rightBottom.x-buffer)&&x<=(rightBottom.x+buffer)) 
      return RIGHT; 
     else if(y>=(rightBottom.y-buffer)&&y<=(rightBottom.y+buffer)) 
      return BOTTOM; 
     else 
      return DRAG; 
    } 

    public byte[] getCroppedImage() { 
     BitmapDrawable drawable = (BitmapDrawable)getDrawable(); 
     float x = leftTop.x-center.x+(drawable.getBitmap().getWidth()/2); 
     float y = leftTop.y-center.y+(drawable.getBitmap().getHeight()/2); 
     Bitmap cropped = Bitmap.createBitmap(drawable.getBitmap(),(int)x,(int)y,(int)rightBottom.x-(int)leftTop.x,(int)rightBottom.y-(int)leftTop.y); 
     ByteArrayOutputStream stream = new ByteArrayOutputStream(); 
     cropped.compress(Bitmap.CompressFormat.PNG, 100, stream); 
     return stream.toByteArray(); 
    } 
} 

To, co zrobiłem, rozszerzyłem ImageView i dodałem moc przycinania. Jest dość łatwy w użyciu. Gdy klasa zostanie zapisana, po prostu użyj jej w takim układzie.

<"your package name".CropView 
     android:id="@+id/image_preview" 
     android:layout_width="fill_parent" 
     android:layout_height="match_parent" /> 

To wszystko! Mam nadzieję, że to pomoże! W przypadku napotkania jakichkolwiek wątpliwości prosimy pytać :)

+0

Użyłem powyższego kodu, ale przycięte zdjęcie nie robi się prawidłowo, robi się zbliżanie. – Santosh

+0

Ten sam problem nie przycina obrazu w granicach prostokąta. To przybliża jak. Próbowałem odpowiedzi @ TheHippo wciąż ten sam problem. – Hasham

+0

ale zostały należy umieścić ten kod < "Twoja nazwa pakietu" .CropView android: id = "@ + id/image_preview" android: layout_width = "fill_parent" android: layout_height = "match_parent" /> I – Matthew

Odpowiedz

2

Należy starać:

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    // TODO Auto-generated method stub 
    super.onCreate(savedInstanceState); 

    setContentView(R.layout.crop_layout); 


    myCropView = new CropView(this); 

    Uri imageUri = getIntent().getExtras().getParcelable("path"); 

    b = (BitmapDrawable) BitmapDrawable.createFromPath(imageUri.getPath()); 

    myCropView.setImageURI(imageUri); 
} 

(Zrobione z edycji na Twoje pytanie.)

+2

whats użycie 'b = (BitmapDrawable) BitmapDrawable.createFromPath (imageUri.getPath());' ?? – xmen

+0

@ theHippo jak mogę użyć w mojej działalności – Matthew

0

dzięki thehippo ... ale już rozwiązany znalezienie widok przez układ

Uri imageUri = getIntent().getExtras().getParcelable("path"); 
    b = (BitmapDrawable) BitmapDrawable.createFromPath(getRealPathFromURI(imageUri)); 
    myCropView = (CropView) findViewById(R.id.image_preview); 
    myCropView.setBackground(b); 

ale teraz nie mogę obsłużyć zdarzenie dotykowy . Prostokąt pozostaje nieruchomy, nawet jeśli dotknę ekranu ...

EDYCJA: ok, sprawiłem, że działa. Teraz jednak prostokąt porusza się tylko wewnątrz mniejszego obszaru, a nie na całym obrazie. Przypuszczam, że coś jest nie tak tutaj

private boolean isInImageRange(PointF point) { 
    // Get image matrix values and place them in an array 
    float[] f = new float[9]; 
    getImageMatrix().getValues(f); 

    // Calculate the scaled dimensions 
    imageScaledWidth = Math.round(getBackground().getIntrinsicWidth() * f[Matrix.MSCALE_X]); 
    imageScaledHeight = Math.round(getBackground().getIntrinsicHeight() * f[Matrix.MSCALE_Y]); 

    return (point.x>=(center.x-(imageScaledWidth/2))&&point.x<=(center.x+(imageScaledWidth/2))&&point.y>=(center.y-(imageScaledHeight/2))&&point.y<=(center.y+(imageScaledHeight/2)))?true:false; 
} 

Zrobiłem małą zmianę, aby praca kod: getBackground() zamiast getDrawable

EDIT 2: OK Ive got to, że robi to w zły kierunek. Twój kod jest dobry. Aby ustawić obraz używam view.seBackground() ... zamiast view.setImageDrawable(). Teraz wszystko działa. Może będę tylko sprawdzić, czy to możliwe, aby utworzyć większy obszar, który wyzwala skalowania prostokąta

+0

hi @ Vahn84! przepraszam, ale mylić z kodem.Jak naprawiłeś swój problem? Zgubiłem się w wątku.Także dzięki @TheHippo dla sugestia Myślę, że jego odpowiedź jest najlepszym sposobem na ustawienie obrazu w miejscu –

+1

Czy ktokolwiek, kto ma to działa edytować końcowy kod i sposób powyżej? – Hasham

+0

Witam! Kod opublikowany przez TheHippo Prace! To robiłem to w niewłaściwy sposób! – Vahn84

0

I znalazłem bibliotekę, która obsługuje to: SimpleCropView od https://android-arsenal.com/details/1/2366. Generalnie nie polecam go, jego wydajność jest daleka od natywnych aplikacji do uprawy Androida.

Próbowałem go używać, a moje myśli są:

  • naprawdę proste do wykonania w swojej aplikacji, zajęło mi około 5 minut, aby dostać upraw i funkcjonalność rotacja pracy z mojej istniejącej aplikacji

  • Zmiana rozmiaru obszaru uprawy jest boleśnie powolna, nie chciałbym, aby mój użytkownik to zobaczył.

UPDATE: W rzeczywistości, znalazłem bardzo dobrym rozwiązaniem jako jdamcd/Android upraw na Github: https://github.com/jdamcd/android-crop Podsumowanie:

  • Bardzo prosty w użyciu w swojej aplikacji

  • szybki, ponieważ wykorzystuje kod z natywnej aplikacji galerii

  • konfigurowalny, jeśli chcesz spędzić trochę czasu na graniu z nim. Domyślnie zapewnia aktywność, w której wykonuje się kadrowanie. Jeśli chcesz zintegrować go z własną działalnością, zajmie to trochę więcej czasu. (W moim projekcie chciałbym go zintegrować i zrobię to w przyszłości, ale na razie wystarczające jest oddzielne działanie).

Mam nadzieję, że to zapewni pewien wgląd!