0

Ich habe eine Beispielanwendung geschrieben, mit der der Android-Benutzer ein Bild aufnehmen und den Textinhalt aus einer Ansicht als Überlagerung auf dem Bild speichern und in einem Galeriealbum speichern kann :So wandeln Sie ein Android-Bitmap in einen Zylinder um und ändern die Perspektive

Text on Camera Image

Was bevor er die beiden Bilder, die ich möchte, ist, den Text Bitmap transformieren. Insbesondere möchte ich, dass der Text an den Seiten hochkant wird (Simulation der Umschlingung eines Zylinders) und oben größer gemacht wird als der Boden (simuliert eine perspektivische Ansicht von oben), wie hier dargestellt:

Transformed Text on Camera Image

Es ist nicht notwendig, das Kamerabild zu interpretieren, um die Größe der Krümmung oder der Perspektive zu bestimmen. Die Frage ist, wie man die Bitmap so manipuliert, dass die beiden Transformationen gemacht werden können.

Hier ist der Code, den ich verwenden, um den nicht-transformierten Text in das Kamerabild zu erhalten und in die Galerie:

private void combinePictureWithText(String fileName) { 
    Log.v(TAG, "combinePictureWithText"); 

    int targetW = getWindowManager().getDefaultDisplay().getWidth(); 
    int targetH = getWindowManager().getDefaultDisplay().getHeight(); 

    /* Get the size of the image */ 
    BitmapFactory.Options bmOptions = new BitmapFactory.Options(); 
    bmOptions.inJustDecodeBounds = true; 
    BitmapFactory.decodeFile(fileName, bmOptions); 
    int photoW = bmOptions.outWidth; 
    int photoH = bmOptions.outHeight; 

    /* Figure out which way needs to be reduced less */ 
    int scaleFactor = 1; 
    if ((targetW > 0) || (targetH > 0)) { 
     scaleFactor = Math.min(photoW/targetW, photoH/targetH); 
    } 
    Log.v(TAG, "Scale Factor: " + scaleFactor); 

    /* Set bitmap options to scale the image decode target */ 
    bmOptions.inJustDecodeBounds = false; 
    bmOptions.inSampleSize = scaleFactor; 
    bmOptions.inPurgeable = true; 

    mBeerLayout.setDrawingCacheEnabled(true); 
    Bitmap mDrawingCache = mBeerLayout.getDrawingCache(); 

    Bitmap cameraBitmap = BitmapFactory.decodeFile(fileName, bmOptions); 
    Bitmap textBitmap = Bitmap.createBitmap(mDrawingCache); 
    Bitmap combinedBitmap = Bitmap.createBitmap(targetW, targetH, Bitmap.Config.ARGB_8888); 
    Canvas comboImage = new Canvas(combinedBitmap); 
    cameraBitmap = Bitmap.createScaledBitmap(cameraBitmap, targetW, targetH, true); 
    comboImage.drawBitmap(cameraBitmap, 0, 0, null); 
    comboImage.drawBitmap(textBitmap, 0, 0, null); // WAS: matrix (instead of 0, 0) 

    /* Save to the file system */ 
    Log.v(TAG, "save combined picture to the file system"); 
    try { 
     File aFile = new File(fileName); 
     if (aFile.exists()) { 
      Log.v(TAG, "File " + fileName + " existed. Deleting it."); 
      //aFile.delete(); 
     } else { 
      Log.v(TAG, "File " + fileName + " did not exist."); 
     } 
     FileOutputStream out = new FileOutputStream(fileName); 
     combinedBitmap.compress(Bitmap.CompressFormat.JPEG, 90, out); 
     out.flush(); 
     out.close(); 
     Log.v(TAG, "Saved " + fileName); 
    } catch (Exception e) { 
     Log.v(TAG, "Failed in file output stream " + e.getMessage()); 
    } 

    /* Associate the Bitmap to the ImageView */ 
    //mImageView.setImageBitmap(combinedBitmap); // DRS was "bitmap" 
    //mImageView.setVisibility(View.VISIBLE); 

    /* Add as a gallery picture */ 
    Log.v(TAG, "galleryAddPic"); 
    Intent mediaScanIntent = new Intent("android.intent.action.MEDIA_SCANNER_SCAN_FILE"); 
    File f = new File(fileName); 
    Uri contentUri = Uri.fromFile(f); 

    mediaScanIntent.setData(contentUri); 
    this.sendBroadcast(mediaScanIntent); 
} 

Diese question/answer könnten Informationen geben, wie die Perspektive Veränderung zu tun, aber ich glaube nicht, Es beantwortet die Frage nach der Simulation des Einwickelns von Text um einen Zylinder.

+0

Hast du Antwort auf diese finden? –

+0

@selva_pollachi, es gibt noch keine Antwort. Ich habe vor, diese Frage mit meinen Fortschritten beizubehalten. Ich nehme an, dass die Antwort "OpenGL", "GLSurfaceView.Renderer" usw. enthalten wird. – Dale

+1

okay dude.Wenn Sie Antwort in nativem als OpenGL finden, geben Sie hier –

Antwort

2

Eine Lösung für dieses Problem ist die Verwendung Canvas.drawBitmapMesh(). Diese Lösung hat den Vorteil, dass nicht die zusätzliche Komplexität von OpenGL erfordert.

Die Idee hinter der Verwendung eines ist, dass Bitmap, das in die Funktion eingefügt wird, verzogen wird, um die definierten Punkte zu erfüllen. Das Bild zeigt, was mit nur 5 Punkten pro Ellipse passiert: mesh definition So wird der Teil der Bitmap, der in den linken, rechteckigen Bereich fällt, so bearbeitet, dass er in die Form des linken Polygons des durch die Scheitelpunkte definierten Bereichs passt Berechnung.

Modellierung Teile von zwei Ellipsen liefern die Werte der Mesh.

Es gibt viele Möglichkeiten, Vertices zu berechnen, die im Allgemeinen tun würden, was erforderlich ist, und diese Implementierung ist nicht unbedingt die beste, effizienteste, verständlichste, usw., aber sie hat den Vorteil, zu tun, worum gefragt wird in der ursprünglichen Frage.

private static float[] computeVerticesFromEllipse(int width, int height, int steps, float curveFactor, float topBottomRatio) { 
    double p = width/2d; 
    double q = 0d; 
    double a = width/2d; 
    double b = curveFactor * a; 

    float[] verticies = new float[(steps-1) * 4]; 
    int j = 0; 

    double increment = width/(double)steps; 

    for (int i = 1; i < steps; i++, j=j+2) { 
     verticies[j] = (float)(increment * (double)i); 
     verticies[j+1] =-(float) (-Math.sqrt((1-Math.pow(((increment * (double)i)-p), 2)/Math.pow(a,2)) * Math.pow(b,2)) + q); 
     Log.v(TAG, "Point, " + verticies[j] + ", " + verticies[j+1] + ", " + j + ", " +(j+1)); 
    } 

    double width2 = topBottomRatio * width; 
    p = width2/2d; 
    q = (width - width2)/2d; 
    a = width2/2d; 
    b = curveFactor * a; 
    increment = width2/(double)steps; 

    double shift = width * (1d - topBottomRatio)/2d; 

    for (int i = 1; i < steps; i++, j=j+2) { 
     verticies[j] = (float)(increment * (double)i) + (float)shift; 
     verticies[j+1] =(float) -(-Math.sqrt((1-Math.pow(((increment * (double)i)-p), 2)/Math.pow(a,2)) * Math.pow(b,2)) + q)+ height; 
     Log.v(TAG, "Point, " + verticies[j] + ", " + verticies[j+1] + ", " + j + ", " +(j+1)); 
    } 

    return verticies; 
} 

Um diese neue Methode in den Code der ursprünglichen Frage zu integrieren, definieren wir einige Elemente der aussehen des Ergebnisses zu steuern (curveFactor, topBottomRatio). Die Variable steps kann angepasst werden, um ein glatteres Ergebnis zu erzielen. Schließlich haben wir Artikel definiert, die in die drawBitmapMesh()-Methode (columns, scaledVertices) eingegeben werden sollen. Anstatt drawBitmap() zu verwenden, verwenden wir drawBitmapMesh().

// 2017 03 22 - Added 5 
    float curveFactor = 0.4f; 
    float topBottomRatio = 0.7f; 
    int steps = 48; 
    float[] scaledVertices = computeVerticesFromEllipse(textBitmap.getWidth(), textBitmap.getHeight(), steps, curveFactor, topBottomRatio); 
    int columns = (scaledVertices.length/4) - 1; // divide by 2 since for two points, divide by 2 again for two rows 

    Bitmap combinedBitmap = Bitmap.createBitmap(targetW, targetH, Bitmap.Config.ARGB_8888); 
    Canvas comboImage = new Canvas(combinedBitmap); 
    cameraBitmap = Bitmap.createScaledBitmap(cameraBitmap, targetW, targetH, true); 
    comboImage.drawBitmap(cameraBitmap, 0, 0, null); 
    // 2017 03 22 - Commented 1, Added 1 
    // comboImage.drawBitmap(textBitmap, 0, 0, null); 
    comboImage.drawBitmapMesh(textBitmap, columns, 1, scaledVertices, 0, null, 0, null); 

Android Layout wrapped around a cylinder

+0

Danke dude. Ich werde es mir ansehen –

Verwandte Themen