web-dev-qa-db-fra.com

Recadrage des images dans le navigateur AVANT le téléchargement

Beaucoup de bibliothèques que j'ai trouvées, comme Jcrop, ne font pas le rognage, cela ne fait que créer une interface utilisateur de rognage d'image. Cela dépend ensuite du serveur qui effectue le recadrage.

Comment puis-je faire le recadrage de l'image côté client en utilisant certains fonctionnalité HTML5 sans utiliser de code côté serveur.

Si oui, y a-t-il des exemples ou des astuces?

58
Lorraine Bernard

Oui, ça peut se faire.
Il est basé sur le nouvel attribut "download" html5 des balises d'ancrage.
Le flux devrait ressembler à ceci:

  1. charger l'image
  2. dessiner l'image dans une toile avec les limites de la culture spécifiées
  3. récupère les données d'image du canevas et en fait un attribut href pour une balise d'ancrage dans le dom
  4. ajouter l'attribut de téléchargement (download="desired-file-name") à cet élément a C'est tout. tout ce que l'utilisateur a à faire est de cliquer sur votre "lien de téléchargement" et l'image sera téléchargée sur son ordinateur.

Je reviendrai avec une démo quand j'en aurai l'occasion.

Mettre à jour
Voici la démo en direct comme promis. Il faut le logo jsfiddle et les cultures 5px de chaque marge.
Le code ressemble à ceci:

var img = new Image();
img.onload = function(){
    var cropMarginWidth = 5,
        canvas = $('<canvas/>')
                    .attr({
                         width: img.width - 2 * cropMarginWidth,
                         height: img.height - 2 * cropMarginWidth
                     })
                    .hide()
                    .appendTo('body'),
        ctx = canvas.get(0).getContext('2d'),
        a = $('<a download="cropped-image" title="click to download the image" />'),
        cropCoords = {
            topLeft : {
                x : cropMarginWidth,
                y : cropMarginWidth 
            },
            bottomRight :{
                x : img.width - cropMarginWidth,
                y : img.height - cropMarginWidth
            }
        };

    ctx.drawImage(img, cropCoords.topLeft.x, cropCoords.topLeft.y, cropCoords.bottomRight.x, cropCoords.bottomRight.y, 0, 0, img.width, img.height);
    var base64ImageData = canvas.get(0).toDataURL();


    a
        .attr('href', base64ImageData)
        .text('cropped image')
        .appendTo('body');

    a
        .clone()
        .attr('href', img.src)
        .text('original image')
        .attr('download','original-image')
        .appendTo('body');

    canvas.remove();
}
img.src = 'some-image-src';

Mise à jour II
J'ai oublié de mentionner: bien sûr, il y a un inconvénient :(.
En raison de la politique de même origine appliquée aux images également, si vous souhaitez accéder aux données d'une image (via la méthode de dessin toDataUrl).
Il vous faudrait donc toujours un proxy côté serveur qui servirait votre image comme si elle était hébergée sur votre domaine.

Mise à jour III Bien que je ne puisse pas fournir de démonstration en direct pour cela (pour des raisons de sécurité), voici un exemple de code PHP permettant de résoudre la politique de même origine :

fichier proxy.php:

$imgData = getimagesize($_GET['img']);
header("Content-type: " . $imgData['mime']);
echo file_get_contents($_GET['img']);  

Ainsi, au lieu de charger l’image externe directement à partir de son origine:

img.src = 'http://some-domain.com/imagefile.png';

Vous pouvez le charger via votre proxy:

img.src = 'proxy.php?img=' + encodeURIComponent('http://some-domain.com/imagefile.png');  

Et voici un exemple de code php pour enregistrer les données d'image (base64) dans une image réelle:

fichier save-image.php:

$data = preg_replace('/data:image\/(png|jpg|jpeg|gif|bmp);base64/','',$_POST['data']);
$data = base64_decode($data);
$img = imagecreatefromstring($data);

$path = 'path-to-saved-images/';
// generate random name
$name  = substr(md5(time()),10);
$ext = 'png';
$imageName = $path.$name.'.'.$ext;

// write the image to disk
imagepng($img,  $imageName);
imagedestroy($img);
// return the image path
echo $imageName;

Il vous suffit ensuite de poster les données de l'image dans ce fichier. Il enregistre l'image sur le disque et vous renvoie le nom de fichier de l'image existante.

Bien sûr, tout cela peut sembler un peu compliqué, mais je voulais vous montrer que ce que vous essayez de réaliser est possible.

43
gion_13

La bibliothèque Pixastic fait exactement ce que vous voulez . Toutefois, cela ne fonctionnera que sur les navigateurs prenant en charge les canevas. Pour les anciens navigateurs, vous devez soit:

  1. fournir une solution de secours côté serveur, ou
  2. dites à l'utilisateur que vous êtes vraiment désolé, mais il aura besoin d'un navigateur plus moderne.

Bien sûr, l'option n ° 2 n'est pas très conviviale. Toutefois, si votre intention est de fournir un outil exclusivement client et/ou si vous ne pouvez pas prendre en charge un découpeur de secours (par exemple, vous écrivez une extension de navigateur ou vous êtes hors ligne Chrome ou vous ne pouvez peut-être pas vous payer un fournisseur d’hébergement décent qui fournit des bibliothèques de manipulation d’images), il est probablement juste de limiter votre base d’utilisateurs aux navigateurs modernes.

[~ # ~] edit [~ # ~] : Si vous ne voulez pas apprendre Pixastic, j'ai ajouté un très simple cropper sur jsFiddle - ici . Il devrait être possible de modifier, d'intégrer et d'utiliser la fonction drawCroppedImage avec Jcrop.

7
apsillers

#change-avatar-file est une entrée de fichier #change-avatar-file est une balise img (la cible de jcrop). La "clé" est FR.onloadend Event https://developer.mozilla.org/en-US/docs/Web/API/FileReader

$('#change-avatar-file').change(function(){
        var currentImg;
        if ( this.files && this.files[0] ) {
            var FR= new FileReader();
            FR.onload = function(e) {
                $('#avatar-change-img').attr( "src", e.target.result );
                currentImg = e.target.result;
            };
            FR.readAsDataURL( this.files[0] );
            FR.onloadend = function(e){
                //console.log( $('#avatar-change-img').attr( "src"));
                var jcrop_api;

                $('#avatar-change-img').Jcrop({
                    bgFade:     true,
                    bgOpacity: .2,
                    setSelect: [ 60, 70, 540, 330 ]
                },function(){
                    jcrop_api = this;
                });
            }
        }
    });
3
user1925970