diff --git a/app/assets/javascripts/discourse/components/composer-editor.js.es6 b/app/assets/javascripts/discourse/components/composer-editor.js.es6
index 8042d248da4..876851b6588 100644
--- a/app/assets/javascripts/discourse/components/composer-editor.js.es6
+++ b/app/assets/javascripts/discourse/components/composer-editor.js.es6
@@ -836,7 +836,11 @@ export default Component.extend({
           return;
         }
 
-        const replacement = match.replace(imageScaleRegex, `$1,${scale}%$3`);
+        const replacement = match.replace(
+          imageScaleRegex,
+          `![$1|$2, ${scale}%]($4)`
+        );
+
         this.appEvents.trigger(
           "composer:replace-text",
           matchingPlaceholder[index],
@@ -851,11 +855,18 @@ export default Component.extend({
     // regex matches only upload placeholders with size defined,
     // which is required for resizing
 
-    // original string `![28|690x226,5%](upload://ceEfx3vO7bx7Cecv2co1SrnoTpW.png)`
-    // match 1 `![28|690x226`
-    // match 2 `5`
-    // match 3 `](upload://ceEfx3vO7bx7Cecv2co1SrnoTpW.png)`
-    const imageScaleRegex = /(!\[(?:\S*?(?=\|)\|)*?(?:\d{1,6}x\d{1,6})+?)(?:,?(\d{1,3})?%?)?(\]\(upload:\/\/\S*?\))/g;
+    // original string `![image|690x220, 50%](upload://1TjaobgKObzpU7xRMw2HuUc87vO.png "image title")`
+    // group 1 `image`
+    // group 2 `690x220`
+    // group 3 `, 50%`
+    // group 4 'upload://1TjaobgKObzpU7xRMw2HuUc87vO.png'
+    // group 4 'upload://1TjaobgKObzpU7xRMw2HuUc87vO.png "image title"'
+
+    // Notes:
+    // Group 3 is optional. group 4 can match images with or without a markdown title.
+    // All matches are whitespace tolerant as long it's still valid markdown
+
+    const imageScaleRegex = /!\[(.*?)\|(\d{1,4}x\d{1,4})(,\s*\d{1,3}%)?\]\((upload:\/\/.*?)\)/g;
 
     // wraps previewed upload markdown in a codeblock in its own class to keep a track
     // of indexes later on to replace the correct upload placeholder in the composer
diff --git a/test/javascripts/acceptance/composer-test.js.es6 b/test/javascripts/acceptance/composer-test.js.es6
index 39573aa31be..655df953570 100644
--- a/test/javascripts/acceptance/composer-test.js.es6
+++ b/test/javascripts/acceptance/composer-test.js.es6
@@ -721,49 +721,68 @@ QUnit.test("Image resizing buttons", async assert => {
   await click("#create-topic");
 
   let uploads = [
+    // 0 Default markdown with dimensions- should work
     "![test|690x313](upload://test.png)",
-    "[img]http://example.com/image.jpg[/img]",
-    "![anotherOne|690x463](upload://anotherOne.jpeg)",
-    "![](upload://withoutAltAndSize.jpeg)",
+    // 1 Image with scaling percentage, should work
+    "![test|690x313,50%](upload://test.png)",
+    // 2 image with scaling percentage and a proceeding whitespace, should work
+    "![test|690x313, 50%](upload://test.png)",
+    // 3 No dimensions, should not work
+    "![test](upload://test.jpeg)",
+    // 4 Wrapped in backquetes should not work
     "`![test|690x313](upload://test.png)`",
-    "![withoutSize](upload://withoutSize.png)",
+    // 5 html image - should not work
     "<img src='http://someimage.jpg' wight='20' height='20'>",
+    // 6 two images one the same line, but both are syntactically correct - both should work
     "![onTheSameLine1|200x200](upload://onTheSameLine1.jpeg) ![onTheSameLine2|250x250](upload://onTheSameLine2.jpeg)",
+    // 7 & 8 Identical images - both should work
     "![identicalImage|300x300](upload://identicalImage.png)",
-    "![identicalImage|300x300](upload://identicalImage.png)"
+    "![identicalImage|300x300](upload://identicalImage.png)",
+    // 9 Image with whitespaces in alt - should work
+    "![image with spaces in alt|690x220](upload://test.png)",
+    // 10 Image with markdown title - should work
+    `![image|690x220](upload://test.png "image title")`,
+    // 11 bbcode - should not work
+    "[img]http://example.com/image.jpg[/img]"
   ];
 
   await fillIn(".d-editor-input", uploads.join("\n"));
 
   assert.ok(
-    find(".button-wrapper").length === 6,
+    find(".button-wrapper").length === 9,
     "it adds correct amount of scaling button groups"
   );
 
-  uploads[0] = "![test|690x313,50%](upload://test.png)";
+  // Default
+  uploads[0] = "![test|690x313, 50%](upload://test.png)";
   await click(find(".button-wrapper .scale-btn[data-scale='50']")[0]);
   assertImageResized(assert, uploads);
 
-  uploads[2] = "![anotherOne|690x463,75%](upload://anotherOne.jpeg)";
-  await click(find(".button-wrapper .scale-btn[data-scale='75']")[1]);
+  // Targets the correct image if two on the same line
+  uploads[6] =
+    "![onTheSameLine1|200x200, 50%](upload://onTheSameLine1.jpeg) ![onTheSameLine2|250x250](upload://onTheSameLine2.jpeg)";
+  await click(find(".button-wrapper .scale-btn[data-scale='50']")[3]);
   assertImageResized(assert, uploads);
 
-  uploads[7] =
-    "![onTheSameLine1|200x200,50%](upload://onTheSameLine1.jpeg) ![onTheSameLine2|250x250](upload://onTheSameLine2.jpeg)";
-  await click(find(".button-wrapper .scale-btn[data-scale='50']")[2]);
+  // Try the other image on the same line
+  uploads[6] =
+    "![onTheSameLine1|200x200, 50%](upload://onTheSameLine1.jpeg) ![onTheSameLine2|250x250, 75%](upload://onTheSameLine2.jpeg)";
+  await click(find(".button-wrapper .scale-btn[data-scale='75']")[4]);
   assertImageResized(assert, uploads);
 
-  uploads[7] =
-    "![onTheSameLine1|200x200,50%](upload://onTheSameLine1.jpeg) ![onTheSameLine2|250x250,75%](upload://onTheSameLine2.jpeg)";
-  await click(find(".button-wrapper .scale-btn[data-scale='75']")[3]);
+  // Make sure we target the correct image if there are duplicates
+  uploads[7] = "![identicalImage|300x300, 50%](upload://identicalImage.png)";
+  await click(find(".button-wrapper .scale-btn[data-scale='50']")[5]);
   assertImageResized(assert, uploads);
 
-  uploads[8] = "![identicalImage|300x300,50%](upload://identicalImage.png)";
-  await click(find(".button-wrapper .scale-btn[data-scale='50']")[4]);
+  // Try the other dupe
+  uploads[8] = "![identicalImage|300x300, 75%](upload://identicalImage.png)";
+  await click(find(".button-wrapper .scale-btn[data-scale='75']")[6]);
   assertImageResized(assert, uploads);
 
-  uploads[9] = "![identicalImage|300x300,75%](upload://identicalImage.png)";
-  await click(find(".button-wrapper .scale-btn[data-scale='75']")[5]);
+  // Don't mess with image titles
+  uploads[10] = `![image|690x220, 75%](upload://test.png "image title")`;
+  await click(find(".button-wrapper .scale-btn[data-scale='75']")[8]);
   assertImageResized(assert, uploads);
 
   await fillIn(