diff --git a/ghost/admin/.lint-todo b/ghost/admin/.lint-todo
index 920a6bc85f..a360d0e4c4 100644
--- a/ghost/admin/.lint-todo
+++ b/ghost/admin/.lint-todo
@@ -567,3 +567,9 @@ add|ember-template-lint|no-invalid-interactive|5|53|5|53|9647ef6afba919b2af04fe5
remove|ember-template-lint|no-invalid-interactive|1|103|1|103|f5a46b2538fbf79a40f2683ff1151ca60e0fa0ca|1680652800000|1691020800000|1696204800000|app/components/gh-context-menu.hbs
add|ember-template-lint|no-invalid-interactive|1|103|1|103|534029ab0ba1b74eff4a2f31c8b4dd9f1460316a|1681430400000|1691798400000|1696982400000|app/components/gh-context-menu.hbs
add|ember-template-lint|no-action|7|49|7|49|141d456b03124abca146e58e4ae15825fdd040bb|1681689600000|1692057600000|1697241600000|app/components/modal-post-history.hbs
+add|ember-template-lint|no-invalid-interactive|3|4|3|4|8e05ced79d8f5f5e13cd43033670b3b1e14db3ab|1681776000000|1692144000000|1697328000000|app/components/gh-editor-feature-image.hbs
+remove|ember-template-lint|no-invalid-interactive|3|4|3|4|66accf6cbc192fd9273063ef67798572309ff1bb|1675296000000|1685660400000|1690844400000|app/components/gh-editor-feature-image.hbs
+add|ember-template-lint|link-href-attributes|4|8|4|8|2078c6e43d1e5548ae745b7ac8cb736f7d2aaf68|1681776000000|1692144000000|1697328000000|app/components/gh-image-uploader-with-preview.hbs
+add|ember-template-lint|no-invalid-interactive|4|60|4|60|2078c6e43d1e5548ae745b7ac8cb736f7d2aaf68|1681776000000|1692144000000|1697328000000|app/components/gh-image-uploader-with-preview.hbs
+remove|ember-template-lint|link-href-attributes|4|8|4|8|a9119f612d27ee1fc92e9bb2c77b6fd30cab622a|1675296000000|1685660400000|1690844400000|app/components/gh-image-uploader-with-preview.hbs
+remove|ember-template-lint|no-invalid-interactive|4|47|4|47|a9119f612d27ee1fc92e9bb2c77b6fd30cab622a|1675296000000|1685660400000|1690844400000|app/components/gh-image-uploader-with-preview.hbs
diff --git a/ghost/admin/app/components/gh-editor-feature-image.hbs b/ghost/admin/app/components/gh-editor-feature-image.hbs
index 9379c749d6..6330f05223 100644
--- a/ghost/admin/app/components/gh-editor-feature-image.hbs
+++ b/ghost/admin/app/components/gh-editor-feature-image.hbs
@@ -39,7 +39,13 @@
-
+
{{svg-jar "trash"}}
Delete
diff --git a/ghost/admin/app/components/koenig-image-editor.hbs b/ghost/admin/app/components/koenig-image-editor.hbs
new file mode 100644
index 0000000000..2fdecc9eef
--- /dev/null
+++ b/ghost/admin/app/components/koenig-image-editor.hbs
@@ -0,0 +1,5 @@
+{{#if this.isEditorEnabled}}
+
+{{/if}}
diff --git a/ghost/admin/app/components/koenig-image-editor.js b/ghost/admin/app/components/koenig-image-editor.js
new file mode 100644
index 0000000000..9daf1aba44
--- /dev/null
+++ b/ghost/admin/app/components/koenig-image-editor.js
@@ -0,0 +1,140 @@
+import Component from '@glimmer/component';
+import {action} from '@ember/object';
+import {inject} from 'ghost-admin/decorators/inject';
+import {inject as service} from '@ember/service';
+import {tracked} from '@glimmer/tracking';
+
+export default class KoenigImageEditor extends Component {
+ @service ajax;
+ @service feature;
+ @service ghostPaths;
+ @tracked scriptLoaded = false;
+ @tracked cssLoaded = false;
+
+ @inject config;
+
+ get isEditorEnabled() {
+ return this.scriptLoaded && this.cssLoaded;
+ }
+
+ getImageEditorJSUrl() {
+ if (!this.config.pintura?.js) {
+ return null;
+ }
+ let importUrl = this.config.pintura.js;
+
+ // load the script from admin root if relative
+ if (importUrl.startsWith('/')) {
+ importUrl = window.location.origin + this.ghostPaths.adminRoot.replace(/\/$/, '') + importUrl;
+ }
+ return importUrl;
+ }
+
+ getImageEditorCSSUrl() {
+ if (!this.config.pintura?.css) {
+ return null;
+ }
+ let cssImportUrl = this.config.pintura.css;
+
+ // load the css from admin root if relative
+ if (cssImportUrl.startsWith('/')) {
+ cssImportUrl = window.location.origin + this.ghostPaths.adminRoot.replace(/\/$/, '') + cssImportUrl;
+ }
+ return cssImportUrl;
+ }
+
+ loadImageEditorJavascript() {
+ const jsUrl = this.getImageEditorJSUrl();
+
+ if (!jsUrl) {
+ return;
+ }
+
+ if (window.pintura) {
+ this.scriptLoaded = true;
+ return;
+ }
+
+ try {
+ const url = new URL(jsUrl);
+
+ let importScriptPromise;
+
+ if (url.protocol === 'http:') {
+ importScriptPromise = import(`http://${url.host}${url.pathname}`);
+ } else {
+ importScriptPromise = import(`https://${url.host}${url.pathname}`);
+ }
+
+ importScriptPromise.then(() => {
+ this.scriptLoaded = true;
+ }).catch(() => {
+ // log script loading failure
+ });
+ } catch (e) {
+ // Log script loading error
+ }
+ }
+
+ loadImageEditorCSS() {
+ let cssUrl = this.getImageEditorCSSUrl();
+ if (!cssUrl) {
+ return;
+ }
+
+ try {
+ // Check if the CSS file is already present in the document's head
+ let cssLink = document.querySelector(`link[href="${cssUrl}"]`);
+ if (cssLink) {
+ this.cssLoaded = true;
+ } else {
+ let link = document.createElement('link');
+ link.rel = 'stylesheet';
+ link.type = 'text/css';
+ link.href = cssUrl;
+ link.onload = () => {
+ this.cssLoaded = true;
+ };
+ document.head.appendChild(link);
+ }
+ } catch (e) {
+ // Log css loading error
+ }
+ }
+
+ constructor() {
+ super(...arguments);
+
+ // Load the image editor script and css if not already loaded
+ this.loadImageEditorJavascript();
+ this.loadImageEditorCSS();
+ }
+
+ @action
+ async handleClick() {
+ if (window.pintura) {
+ const editor = window.pintura.openDefaultEditor({
+ src: this.args.imageSrc,
+ util: 'crop',
+ utils: [
+ 'crop',
+ 'filter',
+ 'finetune',
+ 'redact'
+ ],
+ locale: {
+ labelButtonExport: 'Save and close'
+ }
+ });
+
+ editor.on('loaderror', () => {
+ // TODO: log error message
+ });
+
+ editor.on('process', (result) => {
+ // save edited image
+ this.args.saveImage(result.dest);
+ });
+ }
+ }
+}
diff --git a/ghost/admin/app/components/settings/staff/modals/upload-image.hbs b/ghost/admin/app/components/settings/staff/modals/upload-image.hbs
index fd638d619d..e035a6d766 100644
--- a/ghost/admin/app/components/settings/staff/modals/upload-image.hbs
+++ b/ghost/admin/app/components/settings/staff/modals/upload-image.hbs
@@ -3,7 +3,7 @@
{{#if this.url}}
-
+