title: jCrop resize with correct coords when changing image
body: <p>Hoping this doesn't get flagged as a duplicate because none of the other q/as on SO have helped me fix this, I think I need a more specific line of help.</p>
  
  <p>I have a profile page on my site that allows the user to change their profile picture without page reloads (via AJAX / jQuery).</p>
  
  <p>This all works fine. The user opens the "Change Profile Picture" modal, selects a file to upload and presses "Crop this image". When this button is pressed, it uploads a file to the website, using the typical way of sending the file and formData (which I append the file data to).</p>
  
  <p>It gets sent backend with the following jQuery:</p>
  
  <pre><code>// Upload the image for cropping (Crop this Image!)
  $("#image-upload").click(function(){
  
      // File data
      var fileData = $("#image-select").prop("files")[0];
  
      // Set up a form
      var formData = new FormData();
  
      // Append the file to the new form for submission
      formData.append("file", fileData);
  
      // Send the file to be uploaded
      $.ajax({
  
          // Set the params
          cache: false,
          contentType: false,
          processData: false,
  
          // Page &amp; file information
          url: "index.php?action=uploadimage",
          dataType: "text",
          type: "POST",
  
          // The data to send
          data: formData,
  
          // On success...
          success: function(data){
  
              // If no image was returned
              // "not-image" is returned from the PHP script if we return it in case of an error
              if(data == "not-image"){
                  alert("That's not an image, please upload an image file.");
                  return false;
              }
  
              // Else, load the image on to the page so we don't need to reload
              $(profileImage).attr("src", data);
  
              // If the API is already set, then we should apply a new image
              if(jCropAPI){
                  jCropAPI.setImage(data + "?" + new Date().getTime());
              }
  
              // Initialise jCrop
              setJCrop();
  
              //$("#image-profile").show();
              $("#send-coords").show();
          }
      })
  });
  </code></pre>
  
  <p>setJcrop does the following</p>
  
  <pre><code>function setJCrop(){
  
      // Get width / height of the image
      var width = profileImage.width();
      var height = profileImage.height();
  
      // Var containing the source image
      var imgSource = profileImage.attr("src");
  
      // New image object to work on
      var image = new Image();
      image.src = imgSource;
  
      // The SOURCE (ORIGINAL) width / height
      var origWidth = image.width;
      var origHeight = image.height;
  
      // Set up the option to jCrop it
      $(profileImage).Jcrop({
          onSelect: setCoords,
          onChange: setCoords,
          setSelect: [0, 0, 51, 51],
          aspectRatio: 1,             // This locks it to a square image, so it fits the site better
          boxWidth: width,
          boxHeight: height,          // Fixes the size permanently so that we can load new images
      }, function(){jCropAPI = this});
  
      setOthers(width, height, origWidth, origHeight);
  }
  </code></pre>
  
  <p>And once backend, it does the following:</p>
  
  <pre><code>public function uploadImage($file){
  
      // See if there is already an error
      if(0 &lt; $file["file"]["error"]){
          return $file["file"]["error"] . " (error)";
      }else{
  
          // Set up the image
          $image = $file["file"];
          $imageSizes = getimagesize($image["tmp_name"]);
  
          // If there are no image sizes, return the not-image error
          if(!$imageSizes){
              return "not-image";
          }
  
          // SIZE LIMIT HERE SOON (TBI)
  
          // Set a name for the image
          $username = $_SESSION["user"]-&gt;getUsername();
          $fileName = "images/profile/$username-profile-original.jpg";
  
          // Move the image which is guaranteed a unique name (unless it is due to overwrite), to the profile pictures folder
          move_uploaded_file($image["tmp_name"], $fileName);
  
          // Return the new filename
          return $fileName;
      }
  }
  </code></pre>
  
  <p>Then, the user selects their area on the image with the selector and pressed "Change Profile Picture" which does the following</p>
  
  <pre><code>// Send the Coords and upload the new image
  $("#send-coords").click(function(){
  
      $.ajax({
          type: "POST",
          url: "index.php?action=uploadprofilepicture",
          data: {
              coordString: $("#coords").text() + $("#coords2").text(),
              imgSrc: $("#image-profile").attr("src")
          },
          success: function(data){
              if(data == "no-word"){
                  alert("Can not work with this image type, please try with another image");
              }else{
  
                  // Append a date to make sure it reloads the image without using a cached version
                  var dateNow = new Date();
                  var newImageLink = data + "?" + dateNow.getTime();
                  $("#profile-picture").attr("src", newImageLink);
  
                  // Hide the modal
                  $("#profile-picture-modal").modal("hide");
              }
          }
      });
  })
  </code></pre>
  
  <p>The backend is:</p>
  
  <pre><code>public function uploadProfilePicture($coordString, $imgSrc){
  
      // Target dimensions
      $tarWidth = $tarHeight = 150;
  
      // Split the coords in to an array (sent by a string that was created by JS)
      $coordsArray = explode(",", $coordString);
  
      //Set them all from the array
      $x =            $coordsArray[0];
      $y =            $coordsArray[1];
      $width =        $coordsArray[2];
      $height =       $coordsArray[3];
      $newWidth =     $coordsArray[4];
      $newHeight =    $coordsArray[5];
      $origWidth =    $coordsArray[6];
      $origHeight =   $coordsArray[7];
  
      // Validate the image and decide which image type to create the original resource from
      $imgDetails = getimagesize($imgSrc);
      $imgMime = $imgDetails["mime"];
  
      switch($imgMime){
          case "image/jpeg":
              $originalImage = imagecreatefromjpeg($imgSrc);
              break;
          case "image/png":
              $originalImage = imagecreatefrompng($imgSrc);
              break;
          default:
              return "no-work";
      }
  
      // Target image resource
      $imgTarget = imagecreatetruecolor($tarWidth, $tarHeight);
      $img = imagecreatetruecolor($newWidth, $newHeight);
  
      // Resize the original image to work with our coords
      imagecopyresampled($img, $originalImage, 0, 0, 0, 0,
          $newWidth, $newHeight, $origWidth, $origHeight);
  
      // Now copy the CROPPED image in to the TARGET resource
      imagecopyresampled(
          $imgTarget,     // Target resource
          $img,           // Target image
          0, 0,           // X / Y Coords of the target image; this will always be 0, 0 as we do not want any black nothingness
          $x, $y,         // X / Y Coords (top left) of the target area
          $tarWidth,
          $tarHeight,       // width / height of the target
          $width,
          $height         // Width / height of the source image crop
      );
  
      $username = $_SESSION["user"]-&gt;getUsername();
      $newPath = "images/profile/$username-profile-cropped.jpg";
  
      // Create that shit!
      imagejpeg($imgTarget, $newPath);
  
      // Return the path
      return $newPath;
  }
  </code></pre>
  
  <p>So basically this the returns the path of the new file, which gets changed to the user's profile picture (same name every time) and uploaded live with a time appended after <code>?</code> to refresh the image properly (no cache).</p>
  
  <p>This all works fine, however if the user selects another image to upload, after already uploading one, the coords get all messed up (e.g. they go from 50 to 250) and they end up cropping a totally different part of the image, leaving most of it black nothing-ness.</p>
  
  <p>Really sorry for the ridiculous amount of code that is in this question but I'd appreciate any help from people who might have worked around this before.</p>
  
  <p>Some of the code may seem out of place but that's just me trying to debug it.</p>
  
  <p>Thanks, and again, sorry for the size of this question.</p>
  
  <p>-Edit-</p>
  
  <p>My <code>setCoords()</code> and <code>setOthers()</code> functions look like so:</p>
  
  <pre><code>//Set the coords with this method, that is called every time the user makes / changes a selection on the crop panel
  function setCoords(c){
      $("#coords").text(c.x + "," + c.y + "," + c.w + "," + c.h + ",");
  }
  
  //This one adds the other parts to the second div; they will be concatenated in to the POST string
  function setOthers(width, height, origWidth, origHeight){
      $("#coords2").text(width + "," + height + "," + origWidth + "," + origHeight);
  }
  </code></pre>