# Canvas als .jpg speichern auf verständliche Art?



## nokiland (17. Mai 2015)

Hallilö,

diesmal geht es um HTML5 und dem Framework Kinetic.js.

Mit Hilfe von kinetic.js erstelle ich ein Canvas mit Bildcollage, Text und Drag & Drop. Funktioniert prima.

Der Besucher soll das Canvas auf seiner Festplatte als .jpg mit vernünftigem Dateinamen speichern können - zuverlässig von Chrome bis Safari.

Ja, es gibt "viele" Anleitungen im Internet, ist alles ganz einfach scheinbar. Doch verstehe ich weder englisch oder spanisch, noch helfen mir "Lösungen" von "Fach-Experten" die in ihrem ganzen Leben nur mit einem einzigen Browser arbeiten *g*.



Im Anhang ist ersichtlich um was es mir geht. Bilder werden ausgetauscht, der Text bleibt. Das Resultat/Bild möchte ich in allen aktuellen Browsern speichern können. Alles perfekt, doch ich möchte das "Bild im Canvas" einfach nur speichern können.


----------



## SpiceLab (17. Mai 2015)

nokiland hat gesagt.:


> Im Anhang ist ersichtlich um was es mir geht.


Ich sehe keinen Anhang.


----------



## nokiland (18. Mai 2015)

Hallo Spice, *g*.

Nimm den Anhang aus meinem anderen Post, in dem  Du mich um ein Demo gefragt hast.

Ist aber einfach erklärt: Neben einem Canvas ein Button - klick ---> Fenster zur Abfrage des Speicherortes wird geöffnet - User trifft seine Entscheidung. Der Bildname sollte der original Bildname der Bilddatei sein.


----------



## SpiceLab (18. Mai 2015)

nokiland hat gesagt.:


> Nimm den Anhang aus meinem anderen Post, in dem  Du mich um ein Demo gefragt hast.


Damit potenzielle Hilfeleistende nicht erst deine Beiträge nach dem Anhang durchforsten müssen: https://www.tutorials.de/attachments/screen_chrome-jpg.64132/ 

Abschließend hatte ich dich darin um deine gefundene Lösung gebeten, die wohl auf sich warten lässt.


----------



## Cromon (18. Mai 2015)

Hallo nokiland

Was hast du schon? Was fehlt noch?

Wie du in folgendem Thread entnehmen kannst ist das eine äusserst mühsame Angelegenheit um es in allen Browsern einwandfrei zu ermöglichen:
https://www.tutorials.de/threads/download-per-ajax-content-type-application-force-download.400357/

Viele Grüsse
Cromon


----------



## nokiland (18. Mai 2015)

Zuerst an Spice, ... Sorry, die Lösung war zu einfach, ich dachte Ihr fühlt  Euch dann verarscht. Siehe https://www.tutorials.de/threads/ei...geben-ohne-submit-bitton.401439/#post-2071804


----------



## SpiceLab (18. Mai 2015)

[offtopic]


nokiland hat gesagt.:


> Siehe https://www.tutorials.de/threads/ei...geben-ohne-submit-bitton.401439/#post-2071804


Ist tatsächlich der Beitrag von @einfach nur crack gemeint? Oder doch eher dein eigener: https://www.tutorials.de/threads/ei...geben-ohne-submit-bitton.401439/#post-2071851?


----------



## nokiland (18. Mai 2015)

@Spice, meiner


----------



## nokiland (18. Mai 2015)

Ich habe zum betrachten eine Version auf - entfernt - geladen. Das ist da, es fehlt aktuell die Speicherung des Canvas auf dem PC - MIT einem Button ....

Edit: Mußte Link wieder  raus nehmen, ich mag nicht daß Google die Seite listet. Per PN ist es aber möglich.


----------



## ComFreek (18. Mai 2015)

Am einfachsten ist es, ein neues <image>-Element basierend auf der Data-URI des <canvas> zu erstellen (canvas.toDataURL('image/jpeg')). Nun kann der Nutzer einen Rechtsklick auf das Bild tätigen und es speichern.
Allerdings weiß ich nicht, wie es sich mit der Browserkompatibilität älterer Browser aufgrund der Data-URI verhält.


----------



## nokiland (18. Mai 2015)

@comfreak - Danke für die Anregung. Wie würde das mit KineticsJS aussehen? Ich habe von HTML5 und JavaScript  leider wenig Ahnung und bin am ehesten in der Lage Codeschnipsel abzuändern *g*. Ich teste aber mal ......


----------



## ComFreek (18. Mai 2015)

Hast du ein KineticsJS-Canvas-Objekt? Wenn ja, dann hat dieses Objekt die Methode "toDataURL", siehe http://agavestorm.com/kineticjs/Kinetic.Canvas.html (ganz unten).


```
var canvas = new Canvas(/* ... */)
// Tue irgendwas...
// Das Canvas ist nun fertig zum Speichern

// Im DOM hast du ein <image id="img" /> Element
var img = document.getElementById("img");
img.src = canvas.toDataURL("image/jpeg", 1);
```


----------



## nokiland (18. Mai 2015)

@comfreak - Danke, ich bin  schon am wursteln in dieser Richtung. Meine "Lehrseite" ist: http://www.html5canvastutorials.com/advanced/html5-canvas-get-image-data-url/.

Mein Code ist:


```
<script defer>
// =================================================================================
// Collage im Canvas mit Kinetic.JS
// =================================================================================
var stage = new Kinetic.Stage({
    container: 'container', width: <?php echo $CanvasWidth;?>, height: <?php echo $CanvasHeight;?>
    // container: 'container',     width: 578,    height: 220
});

var layer = new Kinetic.Layer();

window.onload = function(){
// Bild laden
    var img = new Image();
    img.src ="<?php echo $HintergrundBild;?>";
    img.onload = function(){ZitatBild = new Kinetic.Image({ x: 0, y: 0, width:<?php echo $CanvasWidth;?>, height:<?php echo $CanvasHeight;?>,image: img});   

//  Höhe des Textes berechnen .... Komplexer Text über mehrere Zeilen
    var TextZitat2 = new Kinetic.Text({x: 00,     y: 0,        text: '<?php echo $CanvasZitat;?>',<?php echo $CanvasZitatSchrift;?>});
   
// Komplexer Text über mehrere Zeilen
    var TextZitat = new Kinetic.Text({x: 00,     y: <?php echo $CanvasHeight;?>-<?php echo $CanvasHeightAutor;?>-TextZitat2.getHeight(), text: '<?php echo $CanvasZitat;?>', <?php echo $CanvasZitatSchrift;?>});
   
    layer.add(ZitatBild);

    var group = new Kinetic.Group({
        draggable: true
    });
    group.add(TextZitat);
    layer.add(group);
    group.on('dragend',function(){
        console.log(group.getPosition());
    });

    layer.draw();
    stage.add(layer);
    }

}
</script>
```


----------



## Quaese (19. Mai 2015)

Hi,

oder ohne Framework: http://canvas.quaese.de/index.php?nav=13,73&doc_id=73

Ciao
Quasese


----------



## nokiland (20. Mai 2015)

Zuerst ein großes "Danke" an alle helfenden Hirnchen und die Auflösung unten.


```
<head>
<script src="kinetic.min.js"></script>
</head>

<body>
<div id="container"></div>
<div id="savePanel"><button onclick="speicherbild()">Dieses Bild im Canvas speichern!</button></div>

<script>
var stage = new Kinetic.Stage({
    container: 'container', width: <?php echo $CanvasWidth;?>, height: <?php echo $CanvasHeight;?>
});

var layer = new Kinetic.Layer();

window.onload = function(){
    // Bild laden
    var img = new Image();
    img.src ="<?php echo $HintergrundBild;?>";
    img.onload = function(){
    ZitatBild = new Kinetic.Image({ x: 0, y: 0, width:<?php echo $CanvasWidth;?>, height:<?php echo $CanvasHeight;?>,image: img});  

    layer.add(ZitatBild);
    layer.draw();
    stage.add(layer);
    }
}

function speicherbild() {
        var dataURL = layer.toDataURL("image/jpeg";
        window.open(dataURL, "MeinVanvasBild");
}
</script>


....
Code
....

</body>
```

In Zeile 30:


```
var dataURL = layer.toDataURL("image/jpeg";
```


... gab ich immer "stage" statt "layer" ein.  Jetzt klappt es von der Sache her. Nicht perfekt, aber ansatzweise die richtige Richtung. Geplant war nicht eine neue Seite für das Bild zu öffnen, aber damit bin ich erst einmal zufrieden.


Einfach Frage hätte ich noch: Das Bild wird dennoch nach .PNG konvertiert, nicht .jpeg wie angegeben. Sieht jemand den Fehler in meinem Code?


----------



## Cromon (20. Mai 2015)

Auf jeden Fall schon mal, die nicht schliessende Klammer bei toDataURL("image/jpeg";


----------



## nokiland (20. Mai 2015)

Hallo Crome, nee, sorry, das ist es nicht. Ich habe das nur fehlerhaft getippt/rein kopiert.  Im produktiven Code steht es scheinbar richtig drin:

```
function speicherbild() {
    var dataURL = layer.toDataURL("image/jpg");
    window.open(dataURL, "MeinCanvasBild"); // öffnet Bild in neuen Browserfenster
}
```


----------



## Cromon (20. Mai 2015)

Siehe Dokumentation:
http://agavestorm.com/kineticjs/Kinetic.Layer.html#toDataURL

toDataURL({ mimeType: "image/jpeg" });

Also einerseits config-Objekt, andererseits jpeg und nicht jpg.

Viele Grüsse
Cromon


----------



## nokiland (20. Mai 2015)

Danke Cromon, ich habe natürlich auch "jpeg" genutzt. Das jpg ist vom letzten Versuch noch drin. Bei "richtiger" Syntax speichert der FF es als .png ab, der Safari hingegen als Datei ohne Extension.  Alles für die Katz. Andere Ideen? Ich meine, ich sitze ja selber tagelang vor Google und lese das ganze  (deutsche) Web durch. Auch während meiner Arbeitszeit wo andere Dinge anstehen. Aber es klappt nicht. Es ist der Teufel im Detail. 

Sag mal, wie kann ich hier PNs versenden, ich sehe keinen Link?


----------



## nokiland (20. Mai 2015)

Was meinst Du aber mit config Objekt? Ich habe keine Ahnung von Objekten .....


----------



## Cromon (20. Mai 2015)

Hallo nokiland

Nur jpg nach jpeg zu korrigieren bringt nichts, das wesentliche Problem ist, dass du den Mime-Type als String übergibst anstatt als Feld in einem Objekt wie es die Dokumentation vorsieht.

So wie es in der Dokumentation steht:
http://agavestorm.com/kineticjs/Kinetic.Layer.html#toDataURL

toDataURL erwartet ein Objekt als Parameter in welchem dann die entsprechenden Elemente gesetzt sind, die du brauchst, z.B. mimeType.

Grüsse
Cromon


----------



## Quaese (21. Mai 2015)

Hi,

was @Cromon sagen möchte, ist, dass Kinetic die *toDataUrl* überschreibt. Diese Methode verlangt im Gegensatz zu ihrem nativen Pandon als Übergabeparameter ein Objekt, das unter dem obigen Link beschrieben ist. Der Aufruf sollte also wie folgt aussehen:

```
var dataURL = layer.toDataURL({
  mimeType: "image/jpeg"
});
```
Ciao
Quaese


----------



## nokiland (21. Mai 2015)

Ein  riesiges Danke Cromon und Quäse! Gäbe es auch noch eine Möglichkeit einen bestimmten Dateinamen für das Bild zu übergeben?

Ach, auf dem Smartphone geht das speichern nicht - immer wieder was Neues *g*. Samsung - normale Bilder speichern "ja", .jpg eines Vanvas "nein". Aber da mache ich mich gleich mal schlau ......


----------



## Quaese (21. Mai 2015)

Hi,

vielleicht hängt es damit zusammen bzw. hilft es bei der Lösung:
- https://github.com/scottjehl/Device-Bugs/issues/33
- https://ghinda.net/article/jpeg-blob-ajax-android/

Ciao
Quaese


----------



## nokiland (21. Mai 2015)

Hallo Quäse,

Danke für die Anregung. Leider kann ich besser russisch als englisch *g* (DDR Geborener, U880 Architektur, Basic, Pascal, alternativ FORTRAN *g*) . Vermutlich werde ich Smartphone Nutzer erst einmal ablehnen müssen. Ist zwar total unprofessionell, aber ich bekomme es nicht gebacken ohne JavaScript erlernen zu müssen. Zumal der nächste Punkt wäre: "Teilen der Grafik auf Facebook.". Und das mit jeder Plattform. Ich dachte auch schon daran bei "MyHammer" einen Auftrag einzustellen. Lieber einen finanziellen  Betrag für Leistung "xyz" offerieren, als 6 Monate lang herum zu kaspern - doch bin ich nicht einmal in der Lage einen "realen Betrag" zu ermitteln. Am Ende wäre der Job ein Witz und in 10 Minuten erledigt. Oder ein Halsabschneider redet mir ein 10 Tage zu benötigen*g*.


----------

