ImageView-Skalierung TOP_CROP


88

Ich habe eine, ImageViewdie ein PNG anzeigt, das ein größeres Seitenverhältnis als das des Geräts hat (vertikal gesprochen - was bedeutet, dass es länger ist). Ich möchte dies anzeigen, während das Seitenverhältnis beibehalten, die Breite des übergeordneten Elements angepasst und die Bildansicht am oberen Bildschirmrand fixiert wird.

Das Problem bei der Verwendung CENTER_CROPals Skalierungstyp besteht darin, dass das skalierte Bild (verständlich) zentriert wird, anstatt die Oberkante an der Oberkante der Bildansicht auszurichten.

Das Problem dabei FIT_STARTist, dass das Bild zur Bildschirmhöhe passt und nicht die Breite ausfüllt.

Ich habe dieses Problem gelöst, indem ich eine benutzerdefinierte ImageView verwendet und onDraw(Canvas)diese manuell mithilfe der Zeichenfläche überschreibe und handhabe . Das Problem bei diesem Ansatz ist, dass 1) ich befürchte, dass es eine einfachere Lösung gibt, 2) ich beim Aufrufen super(AttributeSet)des Konstruktors eine VM-Mem-Ausnahme erhalte, wenn ich versuche, ein src-Bild von 330 KB festzulegen, wenn der Heap 3 MB frei hat (mit einer Heap-Größe von 6 MB) und kann nicht herausfinden, warum.

Irgendwelche Ideen / Vorschläge / Lösungen sind herzlich willkommen :)

Vielen Dank

ps ich dachte, dass eine Lösung darin bestehen könnte, einen Matrixskalentyp zu verwenden und es selbst zu tun, aber das scheint die gleiche oder mehr Arbeit zu sein als meine aktuelle Lösung!


1
Haben Sie es mit CENTER_CROP versucht und die Eigenschaft adjustViewBounds mit ImageView auf true gesetzt?
PravinCG

2
Ja, ich habe das versucht, kein Erfolg, ich fürchte, es wird die Ansicht erweitern, bis es das übergeordnete Element erweitert, das nicht größer als der Bildschirm ist, und dann das Bild auf dem Bildschirm zentrieren, wobei die überschüssige Höhe / 2 oben hervorsteht und unten
Dori

Antworten:


84

Ok, ich habe eine funktionierende Lösung. Die Eingabeaufforderung von Darko hat mich dazu gebracht, die ImageView-Klasse erneut zu betrachten (danke) und die Transformation mithilfe einer Matrix angewendet (wie ich ursprünglich vermutet hatte, aber bei meinem ersten Versuch keinen Erfolg hatte!). In meiner benutzerdefinierten Klasse Imageview Ich rufe setScaleType(ScaleType.MATRIX)nach super()im Konstruktor, und haben die folgende Methode.

    @Override
    protected boolean setFrame(int l, int t, int r, int b)
    {
        Matrix matrix = getImageMatrix(); 
        float scaleFactor = getWidth()/(float)getDrawable().getIntrinsicWidth();    
        matrix.setScale(scaleFactor, scaleFactor, 0, 0);
        setImageMatrix(matrix);
        return super.setFrame(l, t, r, b);
    }

Ich habe int in die setFrame()Methode eingefügt, da sich der Aufruf von in ImageView configureBounds()innerhalb dieser Methode befindet. Dort findet das gesamte Skalierungs- und Matrixmaterial statt. Dies erscheint mir logisch (sagen Sie, wenn Sie nicht einverstanden sind).

Unten finden Sie die Methode super.setFrame () von AOSP

 @Override
    protected boolean setFrame(int l, int t, int r, int b) {
        boolean changed = super.setFrame(l, t, r, b);
        mHaveFrame = true;
        configureBounds();
        return changed;
    }

Die vollständige Klasse src finden Sie hier


Danke für den Code, @doridori! Es hat gut funktioniert! Ich verstehe nur nicht, warum Sie die "setFrame" -Methode in Ihrer Erklärung wiederholt haben ... Ich habe nur die erste mit Erfolg verwendet (und die zweite xD völlig ignoriert)
Alesqui

3
Nachdem ich zwei Stunden lang über das XML-Layout damit gekämpft hatte, funktionierte dies. Ich wünschte, ich könnte dir mehr Boote geben.
Mark Beaton

5
Ich musste super () vor dem Körper aufrufen, sonst würde das Bild ohne ein
Repaint

1
@VitorHugoSchwaab Sie müssen thms wie matrix.postTranslate (..)
Anton Kizema

1
kann Hintergrund nicht verwenden? nur src verwenden?
Egos Zhang

43

Hier ist mein Code zum Zentrieren unten. Übrigens. in Doris Code ist ein kleiner Fehler: Da der super.frame()ganz am Ende aufgerufen wird, gibt die getWidth()Methode möglicherweise den falschen Wert zurück. Wenn Sie es oben zentrieren möchten, entfernen Sie einfach die postTranslate-Zeile und Sie sind fertig. Das Schöne ist, dass Sie ihn mit diesem Code an eine beliebige Stelle verschieben können. (rechts, Mitte => kein Problem;)

    public class CenterBottomImageView extends ImageView {

        public CenterBottomImageView(Context context) {
            super(context);
            setup();
        }

        public CenterBottomImageView(Context context, AttributeSet attrs) {
            super(context, attrs);
            setup();
        }

        public CenterBottomImageView(Context context, AttributeSet attrs,
                int defStyle) {
            super(context, attrs, defStyle);
            setup();
        }

        private void setup() {
            setScaleType(ScaleType.MATRIX);
        }

        @Override
        protected boolean setFrame(int frameLeft, int frameTop, int frameRight, int frameBottom) {
            if (getDrawable() == null) {
                return super.setFrame(frameLeft, frameTop, frameRight, frameBottom);
            }
            float frameWidth = frameRight - frameLeft;
            float frameHeight = frameBottom - frameTop;

            float originalImageWidth = (float)getDrawable().getIntrinsicWidth();
            float originalImageHeight = (float)getDrawable().getIntrinsicHeight();

            float usedScaleFactor = 1;

            if((frameWidth > originalImageWidth) || (frameHeight > originalImageHeight)) {
                // If frame is bigger than image
                // => Crop it, keep aspect ratio and position it at the bottom and center horizontally

                float fitHorizontallyScaleFactor = frameWidth/originalImageWidth;
                float fitVerticallyScaleFactor = frameHeight/originalImageHeight;

                usedScaleFactor = Math.max(fitHorizontallyScaleFactor, fitVerticallyScaleFactor);
            }

            float newImageWidth = originalImageWidth * usedScaleFactor;
            float newImageHeight = originalImageHeight * usedScaleFactor;

            Matrix matrix = getImageMatrix();
            matrix.setScale(usedScaleFactor, usedScaleFactor, 0, 0); // Replaces the old matrix completly
//comment matrix.postTranslate if you want crop from TOP
            matrix.postTranslate((frameWidth - newImageWidth) /2, frameHeight - newImageHeight);
            setImageMatrix(matrix);
            return super.setFrame(frameLeft, frameTop, frameRight, frameBottom);
        }

    }

Großartig, danke, dass Sie auf den Fehler hingewiesen haben. Ich habe diesen Code eine Weile nicht berührt, daher mag dies ein dummer Vorschlag sein, aber um den setWidth-Fehler zu beheben, auf den Sie hinweisen, könnte man ihn nicht einfach (r-l)stattdessen verwenden?
Dori

Sicherlich sollte die Linie if((frameWidth > originalImageWidth) || (frameHeight > originalImageHeight))umgekehrt werden? Mit anderen Worten, sollten Sie nicht testen, ob das Bild größer als der Rahmen ist? Ich schlage vor, es durchif((originalImageWidth > frameWidth ) || (originalImageHeight > frameHeight ))
Carlos P

Ich habe Breite von Eltern mit ((View) getParent()).getWidth()seit dem ImageViewhatMATCH_PARENT
sherpya

@ Jay es funktioniert super. Ich mache Matrixberechnungen in der onLayout () -Methode, die auch bei der Rotation aufgerufen wird, wo dies bei setFrame nicht der Fall ist.
Box

Vielen Dank dafür, funktioniert perfekt und auch vielen Dank dafür, dass Sie die untere Ernte schnell in die obere Ernte ändern können, indem Sie 1 Codezeile kommentieren
Moonbloom

38

Sie müssen keine benutzerdefinierte Bildansicht schreiben, um die TOP_CROPFunktionalität zu erhalten. Sie müssen nur das ändern matrixder ImageView.

  1. Stellen Sie das scaleTypeauf matrixfür ImageView:

    <ImageView
          android:id="@+id/imageView"
          android:contentDescription="Image"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:src="@drawable/image"
          android:scaleType="matrix"/>
  2. Legen Sie eine benutzerdefinierte Matrix für Folgendes fest ImageView:

    final ImageView imageView = (ImageView) findViewById(R.id.imageView);
    final Matrix matrix = imageView.getImageMatrix();
    final float imageWidth = imageView.getDrawable().getIntrinsicWidth();
    final int screenWidth = getResources().getDisplayMetrics().widthPixels;
    final float scaleRatio = screenWidth / imageWidth;
    matrix.postScale(scaleRatio, scaleRatio);
    imageView.setImageMatrix(matrix);

Auf diese Weise erhalten Sie die TOP_CROPFunktionalität.


2
Das hat bei mir funktioniert. Ich muss jedoch scaleRation überprüfen, wenn es <1 ist. Dann ändere ich einfach das scaleTypeauf, centerCropsonst sehe ich Leerzeichen an den Kanten.
Arst

Wie funktioniert dies in Fällen, in denen Bilder mit Ausrichtung nach unten erforderlich sind?
Sagar

26

Dieses Beispiel funktioniert mit Bildern, die nach dem Erstellen des Objekts + einer Optimierung geladen werden. Ich habe einige Kommentare in den Code eingefügt, die erklären, was los ist.

Denken Sie daran, anzurufen:

imageView.setScaleType(ImageView.ScaleType.MATRIX);

oder

android:scaleType="matrix"

Java-Quelle:

import com.appunite.imageview.OverlayImageView;

public class TopAlignedImageView extends ImageView {
    private Matrix mMatrix;
    private boolean mHasFrame;

    @SuppressWarnings("UnusedDeclaration")
    public TopAlignedImageView(Context context) {
        this(context, null, 0);
    }

    @SuppressWarnings("UnusedDeclaration")
    public TopAlignedImageView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    @SuppressWarnings("UnusedDeclaration")
    public TopAlignedImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        mHasFrame = false;
        mMatrix = new Matrix();
        // we have to use own matrix because:
        // ImageView.setImageMatrix(Matrix matrix) will not call
        // configureBounds(); invalidate(); because we will operate on ImageView object
    }

    @Override
    protected boolean setFrame(int l, int t, int r, int b)
    {
        boolean changed = super.setFrame(l, t, r, b);
        if (changed) {
            mHasFrame = true;
            // we do not want to call this method if nothing changed
            setupScaleMatrix(r-l, b-t);
        }
        return changed;
    }

    private void setupScaleMatrix(int width, int height) {
        if (!mHasFrame) {
            // we have to ensure that we already have frame
            // called and have width and height
            return;
        }
        final Drawable drawable = getDrawable();
        if (drawable == null) {
            // we have to check if drawable is null because
            // when not initialized at startup drawable we can
            // rise NullPointerException
            return;
        }
        Matrix matrix = mMatrix;
        final int intrinsicWidth = drawable.getIntrinsicWidth();
        final int intrinsicHeight = drawable.getIntrinsicHeight();

        float factorWidth = width/(float) intrinsicWidth;
        float factorHeight = height/(float) intrinsicHeight;
        float factor = Math.max(factorHeight, factorWidth);

        // there magic happen and can be adjusted to current
        // needs
        matrix.setTranslate(-intrinsicWidth/2.0f, 0);
        matrix.postScale(factor, factor, 0, 0);
        matrix.postTranslate(width/2.0f, 0);
        setImageMatrix(matrix);
    }

    @Override
    public void setImageDrawable(Drawable drawable) {
        super.setImageDrawable(drawable);
        // We have to recalculate image after chaning image
        setupScaleMatrix(getWidth(), getHeight());
    }

    @Override
    public void setImageResource(int resId) {
        super.setImageResource(resId);
        // We have to recalculate image after chaning image
        setupScaleMatrix(getWidth(), getHeight());
    }

    @Override
    public void setImageURI(Uri uri) {
        super.setImageURI(uri);
        // We have to recalculate image after chaning image
        setupScaleMatrix(getWidth(), getHeight());
    }

    // We do not have to overide setImageBitmap because it calls 
    // setImageDrawable method

}

Wie funktioniert dies in Fällen, in denen Bilder mit Ausrichtung nach unten erforderlich sind?
Sagar

13

Basierend auf Dori verwende ich eine Lösung, die das Bild entweder basierend auf der Breite oder Höhe des Bildes skaliert, um immer den umgebenden Container zu füllen. Auf diese Weise kann ein Bild skaliert werden, um den gesamten verfügbaren Platz zu füllen, wobei der obere linke Punkt des Bildes anstelle der Mitte als Ursprung verwendet wird (CENTER_CROP):

@Override
protected boolean setFrame(int l, int t, int r, int b)
{

    Matrix matrix = getImageMatrix(); 
    float scaleFactor, scaleFactorWidth, scaleFactorHeight;
    scaleFactorWidth = (float)width/(float)getDrawable().getIntrinsicWidth();
    scaleFactorHeight = (float)height/(float)getDrawable().getIntrinsicHeight();    

    if(scaleFactorHeight > scaleFactorWidth) {
        scaleFactor = scaleFactorHeight;
    } else {
        scaleFactor = scaleFactorWidth;
    }

    matrix.setScale(scaleFactor, scaleFactor, 0, 0);
    setImageMatrix(matrix);

    return super.setFrame(l, t, r, b);
}

Ich hoffe das hilft - funktioniert wie ein Vergnügen in meinem Projekt.


11
Dies ist die bessere Lösung ... Und fügen Sie hinzu: float width = r - l; Schwimmerhöhe = b - t;
Geltrude

9

Keine dieser Lösungen funktionierte für mich, da ich eine Klasse wollte, die eine beliebige Ernte entweder aus horizontaler oder vertikaler Richtung unterstützt, und ich wollte, dass ich die Ernte dynamisch ändern kann. Ich brauchte auch Picasso Kompatibilität, und Picasso setzt Bildzeichnungen träge.

Meine Implementierung wird direkt aus ImageView.java im AOSP angepasst. Um es zu verwenden, deklarieren Sie es in XML wie folgt:

    <com.yourapp.PercentageCropImageView
        android:id="@+id/view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="matrix"/>

Wenn Sie von der Quelle aus eine Top-Ernte wünschen, rufen Sie an:

imageView.setCropYCenterOffsetPct(0f);

Wenn Sie eine Bodenernte wünschen, rufen Sie an:

imageView.setCropYCenterOffsetPct(1.0f);

Wenn Sie eine Ernte von 1/3 des Weges nach unten wünschen, rufen Sie an:

imageView.setCropYCenterOffsetPct(0.33f);

Wenn Sie sich für eine andere Zuschneidemethode wie fit_center entscheiden, können Sie dies auch tun, und keine dieser benutzerdefinierten Logik wird ausgelöst. (Bei anderen Implementierungen können Sie NUR deren Zuschneidemethoden verwenden.)

Zuletzt habe ich eine Methode hinzugefügt, redraw (). Wenn Sie also Ihre Zuschneidemethode / Ihren Skalentyp dynamisch im Code ändern möchten, können Sie das Neuzeichnen der Ansicht erzwingen. Beispielsweise:

fullsizeImageView.setScaleType(ScaleType.FIT_CENTER);
fullsizeImageView.redraw();

Rufen Sie Folgendes auf, um zu Ihrer benutzerdefinierten Ernte in der oberen Mitte und im dritten Drittel zurückzukehren:

fullsizeImageView.setScaleType(ScaleType.MATRIX);
fullsizeImageView.redraw();

Hier ist die Klasse:

/* 
 * Adapted from ImageView code at: 
 * http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.4.4_r1/android/widget/ImageView.java
 */
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.ImageView;

public class PercentageCropImageView extends ImageView{

    private Float mCropYCenterOffsetPct;
    private Float mCropXCenterOffsetPct;

    public PercentageCropImageView(Context context) {
        super(context);
    }

    public PercentageCropImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

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

    public float getCropYCenterOffsetPct() {
        return mCropYCenterOffsetPct;
    }

    public void setCropYCenterOffsetPct(float cropYCenterOffsetPct) {
        if (cropYCenterOffsetPct > 1.0) {
            throw new IllegalArgumentException("Value too large: Must be <= 1.0");
        }
        this.mCropYCenterOffsetPct = cropYCenterOffsetPct;
    }

    public float getCropXCenterOffsetPct() {
        return mCropXCenterOffsetPct;
    }

    public void setCropXCenterOffsetPct(float cropXCenterOffsetPct) {
        if (cropXCenterOffsetPct > 1.0) {
            throw new IllegalArgumentException("Value too large: Must be <= 1.0");
        }
        this.mCropXCenterOffsetPct = cropXCenterOffsetPct;
    }

    private void myConfigureBounds() {
        if (this.getScaleType() == ScaleType.MATRIX) {
            /*
             * Taken from Android's ImageView.java implementation:
             * 
             * Excerpt from their source:
    } else if (ScaleType.CENTER_CROP == mScaleType) {
       mDrawMatrix = mMatrix;

       float scale;
       float dx = 0, dy = 0;

       if (dwidth * vheight > vwidth * dheight) {
           scale = (float) vheight / (float) dheight; 
           dx = (vwidth - dwidth * scale) * 0.5f;
       } else {
           scale = (float) vwidth / (float) dwidth;
           dy = (vheight - dheight * scale) * 0.5f;
       }

       mDrawMatrix.setScale(scale, scale);
       mDrawMatrix.postTranslate((int) (dx + 0.5f), (int) (dy + 0.5f));
    }
             */

            Drawable d = this.getDrawable();
            if (d != null) {
                int dwidth = d.getIntrinsicWidth();
                int dheight = d.getIntrinsicHeight();

                Matrix m = new Matrix();

                int vwidth = getWidth() - this.getPaddingLeft() - this.getPaddingRight();
                int vheight = getHeight() - this.getPaddingTop() - this.getPaddingBottom();

                float scale;
                float dx = 0, dy = 0;

                if (dwidth * vheight > vwidth * dheight) {
                    float cropXCenterOffsetPct = mCropXCenterOffsetPct != null ? 
                            mCropXCenterOffsetPct.floatValue() : 0.5f;
                    scale = (float) vheight / (float) dheight;
                    dx = (vwidth - dwidth * scale) * cropXCenterOffsetPct;
                } else {
                    float cropYCenterOffsetPct = mCropYCenterOffsetPct != null ? 
                            mCropYCenterOffsetPct.floatValue() : 0f;

                    scale = (float) vwidth / (float) dwidth;
                    dy = (vheight - dheight * scale) * cropYCenterOffsetPct;
                }

                m.setScale(scale, scale);
                m.postTranslate((int) (dx + 0.5f), (int) (dy + 0.5f));

                this.setImageMatrix(m);
            }
        }
    }

    // These 3 methods call configureBounds in ImageView.java class, which
    // adjusts the matrix in a call to center_crop (android's built-in 
    // scaling and centering crop method). We also want to trigger
    // in the same place, but using our own matrix, which is then set
    // directly at line 588 of ImageView.java and then copied over
    // as the draw matrix at line 942 of ImageVeiw.java
    @Override
    protected boolean setFrame(int l, int t, int r, int b) {
        boolean changed = super.setFrame(l, t, r, b);
        this.myConfigureBounds();
        return changed;
    }
    @Override
    public void setImageDrawable(Drawable d) {          
        super.setImageDrawable(d);
        this.myConfigureBounds();
    }
    @Override
    public void setImageResource(int resId) {           
        super.setImageResource(resId);
        this.myConfigureBounds();
    }

    public void redraw() {
        Drawable d = this.getDrawable();

        if (d != null) {
            // Force toggle to recalculate our bounds
            this.setImageDrawable(null);
            this.setImageDrawable(d);
        }
    }
}

5

Vielleicht gehen Sie in den Quellcode für die Bildansicht auf Android und sehen Sie, wie es die mittlere Ernte usw. zeichnet .. und kopieren Sie vielleicht einen Teil dieses Codes in Ihre Methoden. Ich weiß nicht wirklich nach einer besseren Lösung als dieser. Ich habe Erfahrung mit der manuellen Größenänderung und dem Zuschneiden der Bitmap (Suche nach Bitmap-Transformationen), wodurch die tatsächliche Größe verringert wird, aber dennoch ein gewisser Overhead entsteht.


3
public class ImageViewTopCrop extends ImageView {
public ImageViewTopCrop(Context context) {
    super(context);
    setScaleType(ScaleType.MATRIX);
}

public ImageViewTopCrop(Context context, AttributeSet attrs) {
    super(context, attrs);
    setScaleType(ScaleType.MATRIX);
}

public ImageViewTopCrop(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    setScaleType(ScaleType.MATRIX);
}

@Override
protected boolean setFrame(int l, int t, int r, int b) {
    computMatrix();
    return super.setFrame(l, t, r, b);
}

@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    super.onLayout(changed, left, top, right, bottom);
    computMatrix();
}

private void computMatrix() {
    Matrix matrix = getImageMatrix();
    float scaleFactor = getWidth() / (float) getDrawable().getIntrinsicWidth();
    matrix.setScale(scaleFactor, scaleFactor, 0, 0);
    setImageMatrix(matrix);
}

}}


setFrame && onLayout
Tianxia

computMatrix: Hier können Sie jede Matrix erstellen.
Tianxia

onLayoutspart mir viel! Vielen Dank! Ich bin auf ein Problem gestoßen, bei dem die Matrix berechnet wird, das Bild jedoch nicht sofort angezeigt wird und das Hinzufügen onLayoutdes Codes mein Problem löst.
Natsumiyu

1

Wenn Sie Fresco (SimpleDraweeView) verwenden , können Sie dies ganz einfach tun mit:

 PointF focusPoint = new PointF(0.5f, 0f);
 imageDraweeView.getHierarchy().setActualImageFocusPoint(focusPoint);

Dieser wäre für eine Spitzenernte.

Weitere Infos unter Referenzlink


0

Hier gibt es zwei Probleme mit den Lösungen:

  • Sie werden im Android Studio-Layout-Editor nicht gerendert (sodass Sie eine Vorschau auf verschiedene Bildschirmgrößen und Seitenverhältnisse anzeigen können).
  • Es wird nur nach Breite skaliert. Abhängig von den Seitenverhältnissen des Geräts und des Bildes kann unten ein leerer Streifen angezeigt werden

Diese kleine Änderung behebt das Problem (platzieren Sie den Code in onDraw und überprüfen Sie die Skalierungsfaktoren für Breite und Höhe):

@Override
protected void onDraw(Canvas canvas) {

    Matrix matrix = getImageMatrix();

    float scaleFactorWidth = getWidth() / (float) getDrawable().getIntrinsicWidth();
    float scaleFactorHeight = getHeight() / (float) getDrawable().getIntrinsicHeight();

    float scaleFactor = (scaleFactorWidth > scaleFactorHeight) ? scaleFactorWidth : scaleFactorHeight;

    matrix.setScale(scaleFactor, scaleFactor, 0, 0);
    setImageMatrix(matrix);

    super.onDraw(canvas);
}

-1

Einfachste Lösung: Schneiden Sie das Bild aus

 @Override
    public void draw(Canvas canvas) {
        if(getWidth() > 0){
            int clipHeight = 250;
            canvas.clipRect(0,clipHeight,getWidth(),getHeight());
         }
        super.draw(canvas);
    }

Dadurch wird das Bild nicht vergrößert, wenn es kleiner als die Ansicht ist, weshalb die anderen Lösungen nicht so einfach sind.
OldSchool4664
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.