3

I'm attempting to send the result of two merged html canvases via email.

My attempt was to do this by setting the value of an input field in a form with the base64 value of the converted canvas, I would then pass this to a php emailer script where in the message section I would set the source of a html image as the base64 value (as would work in normal html pages). This doesn't seem to work however.

My full function for merging the two canvases, converting to an image, downloading the image and then attempting to set the value of is as below

function convertImage() 
    {
        var bottleCanvas = document.getElementById('bottleCanvas');
        var designCanvas = document.getElementById('editorCanvas');
        var bottleContext = bottleCanvas.getContext('2d');

        if($('.colourCanvas500').is(':visible')) 
        {
            bottleContext.drawImage(designCanvas, 153, 250);
        }
        else if($('.colourCanvas600').is(':visible')) 
        {
            bottleContext.drawImage(designCanvas, 155, 238);
        }
        else if($('.whiteCanvas500').is(':visible')) 
        { 
            bottleContext.drawImage(designCanvas, 132, 235);
        }
        else if($('.whiteCanvas600').is(':visible'))  
        {
        bottleContext.drawImage(designCanvas, 132, 235);
        }

        var data = bottleCanvas.toDataURL("image/png");
        var link = document.createElement('a');
        link.download = "bottle-design.png";
        var dataLink = bottleCanvas.toDataURL("image/png").replace("image/png", "image/octet-stream");
        document.write(dataLink);
        link.href = dataLink;
        link.click();

        $('#imageInput').val(dataLink);
        $('form[name="bottleDetails"]').submit();
  }

How would I go about sending my canvas converted image via email?

HTML code for form is as below:

<form action="php/submit.php" method="post" name="bottleDetails" class="customise-bottle">    

        <ul class="options">

            <li id="header">
                <div class="container">
                    <h1>Customise your Bottle</h1><br/>
                </div>
            </li>     

            <li id="name">
                <div class="container">
                    <label>Name:</label>
                    <div class="contact-field">
                        <input class="contact-info" name="name" type="text" placeholder="Mr Water" />
                    </div>
                </div>
            </li>

            <li id="email">
                <div class="container">
                    <label>Email:</label>
                    <div class="contact-field">
                        <input class="contact-info" name="email" type="email" placeholder="bottle@givemetap.com" />
                    </div>
                </div>
            </li>

            <li id="company">
                <div class="container">
                    <label>Company:</label>
                    <div class="contact-field">
                        <input class="contact-info" name="company" type="text" placeholder="GiveMeTap" />
                    </div>
                </div>
            </li>

            <li id="bottle-size-section">
                <div class="container">
                    <label>Bottle Size:</label>
                    <ul id="size-buttons">
                        <li><button type="button" id="500ml" class="bottle-size selected">500ml</button></li>
                        <li><button type="button" id="600ml" class="bottle-size">600ml</button></li>
                        <input type="hidden" id="sizeInput" name="size" value="500ml" />
                </div>
            </li>

            <li id="bottle-colour-section">
                <div class="container">
                    <label>Bottle Colour:</label>
                    <div id="colours">
                        <button type="button" class="colour selected" id="blue"></button>
                        <button type="button" class="colour" id="pink"></button>
                        <button type="button" class="colour" id="silver"></button>
                        <button type="button" class="colour" id="black"></button>
                        <input type="hidden" id="colourInput" name="colour" value="blue" />
                    </div>
                </div>
            </li>

            <li id="bottle-lid-type">
                <div class="container">
                    <label>Lid Type:</label>
                    <ul id="size-buttons">
                        <li><button type="button" id="pull" class="bottle-size selected">Pull Up</button></li>
                        <li><button type="button" id="flip" class="bottle-size">Flip Up</button></li>
                        <input type="hidden" id="lidInput" name="lid" value="twist" />
                </div>
            </li>

            <li id="bottle-quantity-section">
                <div class="container">
                <label>Quantity:</label>
                <div id="quantity-dropdown">
                    <select name="quantity" id="quantity">
                        <option value="25-100">25-100</option>
                        <option value="100-250" selected>100-250</option>
                        <option value="250-500">250-500</option>
                        <option value="500+">500+</option>
                    </select>
                </div>
            </li>
            <input type="hidden" id="imageInput" name="image" value="testing" />
            <li id="purchase">
                <div class="container">
                    <ul id="final-buttons">
                    </ul>
                </div>
            </li>

        </ul>

    </form>
    <button type="submit" onclick="convertImage()" download="bottle-design.png" type="button" class="btn" id="save-design">Email</button>

PHP code is as below:

<?php

 if(!empty($_POST['email'])){

    $name = $_POST['name'];
    $email = $_POST['email'];
    $company = $_POST['company']; 
    $size = $_POST['size']; 
    $colour = $_POST['colour'];
    $lid = $_POST['lid']; 
    $quantity = $_POST['quantity'];
    $image = $_POST['image'];

    $subject = "Bottle Design Quote";
    $message = "Customer Name: $name<br/> Customer Email: $email<br/> Company Name: $company<br/> Bottle Size: $size<br/> Bottle Color: $colour<br/> Bottle Lid: $lid<br/> Quantity: $quantity<br/> Design: $image";
    $to = "test@test.com";
    $headers = "From: \"$name\"<$email>\n";
    $headers .= "Reply-To: $email\n";
    $headers .= "Content-Type: text/html; charset=\"utf-8\"";
    mail($to,$subject,$message,$headers);

    header('Location: success.php'); 

   }
   else 
   {
       header('Location: builder.php');
   }
?>
Alex Saidani
  • 1,277
  • 2
  • 16
  • 31
  • Well the main problem is the Base64 value is not being posted to the php script (which is just a normal php mailer script and works fine for all the other values in the form). So the problem lies with the javascript, although i'm still not entirely sure whether my method is the best anyway. – Alex Saidani Apr 16 '15 at 07:12
  • Please post your html as well then. – Daedalus Apr 16 '15 at 07:13
  • I've added both the HTML and PHP above. I don't believe the error is there though, as my hidden inputs work fine when I set their values using jQuery as above. – Alex Saidani Apr 16 '15 at 07:16
  • I'm not going to try to replicate your exact problem, because this is rather late for me and that's a rather involved thing; so instead, what exactly does your code do? When the button is clicked, I mean. I see a `document.write()` in there, which is normally a bad practice, given it usually replaces the document's html with whatever is given to it. – Daedalus Apr 16 '15 at 07:21
  • The document write was actually me testing whether the base64 value actually worked - which it does. I guess my two issues are it's not being set into the hidden input and whether or not it will work in the php mailer if I set it as the source for an img () – Alex Saidani Apr 16 '15 at 07:28
  • Was PHPMailer tagged intentionally, as I don't see it in your post? – David Mulder Apr 16 '15 at 08:04
  • Apologies this was to refer to the use of the mail function within PHP - forgot about PHPMailer. – Alex Saidani Apr 16 '15 at 08:26

3 Answers3

1

There's more to a data URL than sticking the base64 value in the src, but that's academic because data URLs are very poorly supported in email clients anyway, so it's not worth doing. PHPMailer's msgHTML function will convert data URLs into normal embedded attachments, so I suggest you make use of that, or if you want a bit more control you can decode the value (to avoid double-encoding) and attach it yourself using addStringAttachment or addStringEmbeddedImage.

Synchro
  • 35,538
  • 15
  • 81
  • 104
1

I got this working through a combination of javascript and PHP, in the following process: combine two canvases together, convert to base64, convert to image for downloading to user's computer, pass base64 to PHP script, email as attachment.

My Javascript (+jQuery) for doing this is as follows:

function convertImage() {
    var bottleCanvas = document.getElementById('bottleCanvas');
    var designCanvas = document.getElementById('editorCanvas');
    var bottleContext = bottleCanvas.getContext('2d');

    if($('.colourCanvas500').is(':visible')) {
        bottleContext.drawImage(designCanvas, 153, 250);
    }
    else if($('.colourCanvas600').is(':visible')) {
        bottleContext.drawImage(designCanvas, 155, 238);
    }
    else if($('.whiteCanvas500').is(':visible')) { 
        bottleContext.drawImage(designCanvas, 132, 235);
    }
    else if($('.whiteCanvas600').is(':visible')) {
        bottleContext.drawImage(designCanvas, 132, 235);
    }

    var data = bottleCanvas.toDataURL("image/png");
    var link = document.createElement('a');
    link.download = "bottle-design.png";
    var dataLink = bottleCanvas.toDataURL("image/png").replace("image/png", "image/octet-stream");
    //document.write(dataLink);
    link.href = dataLink;
    link.click();

    $('#imageInput').val(data);

    $('form[name="bottleDetails"]').submit();
}

And the PHP code:

 <?php
 session_start();

 if(!empty($_POST['email'])){

    //Here the session variables are converted back into standard variables.
    $name = $_POST['name'];
    $email = $_POST['email'];
    $company = $_POST['company']; 
    $size = $_POST['size']; 
    $colour = $_POST['colour'];
    $lid = $_POST['lid']; 
    $quantity = $_POST['quantity'];

    $image = $_POST['image'];
    $_SESSION['finalImage'] = $image;

    $img = str_replace('data:image/png;base64,', '', $image);

    $subject = "Bottle Design Quote";
    $message = "Customer Name: $name<br/> Customer Email: $email<br/> Company Name: $company<br/> Bottle Size: $size<br/> Bottle Color: $colour<br/> Bottle Lid: $lid<br/> Quantity: $quantity<br/> Design: $image";
    $to = "alex@givemetap.com,alex@saidani.co.uk,sanum@givemetap.com,waleed@givemetap.com";
    $headers = "From: \"$name\"<$email>\n";
    $headers .= "Reply-To: $email\n";
    $headers .= 'Content-Type: multipart/related; boundary="boundary-bottle"; type="text/html"';
    $headers .= "MIME-Version: 1.0\r\n";

        $body = "

--boundary-bottle
Content-Type: text/html; charset='US-ASCII'

Customer Name: $name<br/> Customer Email: $email<br/> Company Name: $company<br/> Bottle Size: $size<br/> Bottle Color: $colour<br/> Bottle Lid: $lid<br/> Quantity: $quantity<br/> Design:

<IMG SRC='cid:bottle-design' ALT='Bottle Design'>

--boundary-bottle
Content-Location: CID:somethingatelse ; this header is disregarded
Content-ID: <bottle-design>
Content-Type: IMAGE/PNG
Content-Transfer-Encoding: BASE64

$img

--boundary-bottle--";

    mail($to,$subject,$body,$headers);

    header('Location: ../success.php'); 

   }
   else 
   {
       header('Location: ../builder.php'); //We direct the user to the error page if a session does not exist - or if they have refreshed the page.
   }
?>
Alex Saidani
  • 1,277
  • 2
  • 16
  • 31
0

To back up Synchro answer up on the support of mail clients part I was only able to find information that was a bit outdated, but here is a list from 2013 with which clients support data uri's.

Secondly I am not sure you consciously tagged the PHPMailer library or whether you just believed it to be a generic tag for scripts that use PHP to mail stuff. If it was not conscious then Synchro's answer won't help, so I thought I would post a separate answer (although using PHPMailer is definitely a good idea).

  1. You don't need to do the weird .replace("image/png", "image/octet-stream"), that's only when you wish to force a download (as is the link stuff). You do need to replace it with nothing though for the next step.
  2. You can find out how to add an attachment using PHP in this SO answer. As you already have it base64 encoded you can skip to the $content = chunk_split(base64_encode($content));, though you still will need to chunk it.
  3. And this answer describes how to embed it inline.
Community
  • 1
  • 1
David Mulder
  • 26,123
  • 9
  • 51
  • 114
  • As you said - I forgot about PHPMailer so tagged it to refer to mailing through php, so this answer is much more helpful. The downloading of the file is required as it's a design downloaded to the user's computer and also emailed too. – Alex Saidani Apr 16 '15 at 08:25
  • Although, I believe there may be an issue in terms of the javascript - as the canvas needs converting through that I'm not entirely sure on the best way to pass it to php? – Alex Saidani Apr 16 '15 at 08:27
  • @AlexSaidani Not sure I understand your last comment, but you should just send it base64 encoded like you're doing now in a hidden field. If the field is empty then it could be happening that the original submit is firing before the onclick has finished. Instead the 'correct' way to do it is to bind to the onsubmit itself. – David Mulder Apr 16 '15 at 08:37