diff --git a/src/components/views/elements/ImageView.tsx b/src/components/views/elements/ImageView.tsx
index db63dbbfc2..56c81c937e 100644
--- a/src/components/views/elements/ImageView.tsx
+++ b/src/components/views/elements/ImageView.tsx
@@ -34,6 +34,7 @@ import { RoomPermalinkCreator } from "../../../utils/permalinks/Permalinks";
 import { MatrixEvent } from "matrix-js-sdk/src/models/event";
 import { normalizeWheelEvent } from "../../../utils/Mouse";
 import { IDialogProps } from '../dialogs/IDialogProps';
+import UIStore from '../../../stores/UIStore';
 
 // Max scale to keep gaps around the image
 const MAX_SCALE = 0.95;
@@ -56,8 +57,15 @@ interface IProps extends IDialogProps {
     // redactions, senders, timestamps etc.  Other descriptors are taken from the explicit
     // properties above, which let us use lightboxes to display images which aren't associated
     // with events.
-    mxEvent: MatrixEvent;
-    permalinkCreator: RoomPermalinkCreator;
+    mxEvent?: MatrixEvent;
+    permalinkCreator?: RoomPermalinkCreator;
+
+    thumbnailInfo?: {
+        positionX: number;
+        positionY: number;
+        width: number;
+        height: number;
+    };
 }
 
 interface IState {
@@ -75,13 +83,16 @@ interface IState {
 export default class ImageView extends React.Component<IProps, IState> {
     constructor(props) {
         super(props);
+
+        const { thumbnailInfo, width } = this.props;
+
         this.state = {
-            zoom: 0,
+            zoom: thumbnailInfo?.width / width ?? 0,
             minZoom: MAX_SCALE,
             maxZoom: MAX_SCALE,
             rotation: 0,
-            translationX: 0,
-            translationY: 0,
+            translationX: thumbnailInfo?.positionX + (thumbnailInfo?.width / 2) - (UIStore.instance.windowWidth / 2),
+            translationY: thumbnailInfo?.positionY + (thumbnailInfo?.height / 2) - (UIStore.instance.windowHeight / 2),
             moving: false,
             contextMenuDisplayed: false,
         };
@@ -105,15 +116,23 @@ export default class ImageView extends React.Component<IProps, IState> {
         // We want to recalculate zoom whenever the window's size changes
         window.addEventListener("resize", this.recalculateZoom);
         // After the image loads for the first time we want to calculate the zoom
-        this.image.current.addEventListener("load", this.recalculateZoom);
+        this.image.current.addEventListener("load", this.imageLoaded);
     }
 
     componentWillUnmount() {
         this.focusLock.current.removeEventListener('wheel', this.onWheel);
         window.removeEventListener("resize", this.recalculateZoom);
-        this.image.current.removeEventListener("load", this.recalculateZoom);
+        this.image.current.removeEventListener("load", this.imageLoaded);
     }
 
+    private imageLoaded =() => {
+        this.setZoomAndRotation();
+        this.setState({
+            translationX: 0,
+            translationY: 0,
+        });
+    };
+
     private recalculateZoom = () => {
         this.setZoomAndRotation();
     };
@@ -380,7 +399,7 @@ export default class ImageView extends React.Component<IProps, IState> {
         // image causing it translate in the wrong direction.
         const style = {
             cursor: cursor,
-            transition: this.state.moving ? null : "transform 200ms ease 0s",
+            transition: this.state.moving ? null : "transform 250ms ease 0s",
             transform: `translateX(${translatePixelsX})
                         translateY(${translatePixelsY})
                         scale(${zoom})
diff --git a/src/components/views/messages/MImageBody.tsx b/src/components/views/messages/MImageBody.tsx
index 44c15d50e7..c433ddb8e3 100644
--- a/src/components/views/messages/MImageBody.tsx
+++ b/src/components/views/messages/MImageBody.tsx
@@ -112,6 +112,17 @@ export default class MImageBody extends React.Component<IBodyProps, IState> {
                 params.fileSize = content.info.size;
             }
 
+            if (this.image.current) {
+                const clientRect = this.image.current.getBoundingClientRect();
+
+                params.thumbnailInfo = {
+                    width: clientRect.width,
+                    height: clientRect.height,
+                    positionX: clientRect.x,
+                    positionY: clientRect.y,
+                };
+            }
+
             Modal.createDialog(ImageView, params, "mx_Dialog_lightbox", null, true);
         }
     };
diff --git a/src/components/views/rooms/LinkPreviewWidget.tsx b/src/components/views/rooms/LinkPreviewWidget.tsx
index 55e123f4e0..5e7154dc8a 100644
--- a/src/components/views/rooms/LinkPreviewWidget.tsx
+++ b/src/components/views/rooms/LinkPreviewWidget.tsx
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
 limitations under the License.
 */
 
-import React, { createRef } from 'react';
+import React, { ComponentProps, createRef } from 'react';
 import { AllHtmlEntities } from 'html-entities';
 import { MatrixEvent } from 'matrix-js-sdk/src/models/event';
 import { IPreviewUrlResponse } from 'matrix-js-sdk/src/client';
@@ -36,6 +36,7 @@ interface IProps {
 @replaceableComponent("views.rooms.LinkPreviewWidget")
 export default class LinkPreviewWidget extends React.Component<IProps> {
     private readonly description = createRef<HTMLDivElement>();
+    private image = createRef<HTMLImageElement>();
 
     componentDidMount() {
         if (this.description.current) {
@@ -59,7 +60,7 @@ export default class LinkPreviewWidget extends React.Component<IProps> {
             src = mediaFromMxc(src).srcHttp;
         }
 
-        const params = {
+        const params: Omit<ComponentProps<typeof ImageView>, "onFinished"> = {
             src: src,
             width: p["og:image:width"],
             height: p["og:image:height"],
@@ -68,6 +69,17 @@ export default class LinkPreviewWidget extends React.Component<IProps> {
             link: this.props.link,
         };
 
+        if (this.image.current) {
+            const clientRect = this.image.current.getBoundingClientRect();
+
+            params.thumbnailInfo = {
+                width: clientRect.width,
+                height: clientRect.height,
+                positionX: clientRect.x,
+                positionY: clientRect.y,
+            };
+        }
+
         Modal.createDialog(ImageView, params, "mx_Dialog_lightbox", null, true);
     };
 
@@ -100,7 +112,7 @@ export default class LinkPreviewWidget extends React.Component<IProps> {
         let img;
         if (image) {
             img = <div className="mx_LinkPreviewWidget_image" style={{ height: thumbHeight }}>
-                <img style={{ maxWidth: imageMaxWidth, maxHeight: imageMaxHeight }} src={image} onClick={this.onImageClick} />
+                <img ref={this.image} style={{ maxWidth: imageMaxWidth, maxHeight: imageMaxHeight }} src={image} onClick={this.onImageClick} />
             </div>;
         }