Skip to content

Commit

Permalink
Send and respect MSC4230 is_animated flag (#28513)
Browse files Browse the repository at this point in the history
* PoC implementation for is_animated m.image flag

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Update MSC reference

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Iterate

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
  • Loading branch information
t3chguy authored Nov 22, 2024
1 parent 7d20bd4 commit 3d66641
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 18 deletions.
7 changes: 7 additions & 0 deletions src/@types/matrix-js-sdk.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ declare module "matrix-js-sdk/src/types" {
[BLURHASH_FIELD]?: string;
}

export interface ImageInfo {
/**
* @see https://github.com/matrix-org/matrix-spec-proposals/pull/4230
*/
"org.matrix.msc4230.is_animated"?: boolean;
}

export interface StateEvents {
// Jitsi-backed video room state events
[JitsiCallMemberEventType]: JitsiCallMemberContent;
Expand Down
8 changes: 7 additions & 1 deletion src/ContentMessages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ import { createThumbnail } from "./utils/image-media";
import { attachMentions, attachRelation } from "./components/views/rooms/SendMessageComposer";
import { doMaybeLocalRoomAction } from "./utils/local-room";
import { SdkContextClass } from "./contexts/SDKContext";
import { blobIsAnimated } from "./utils/Image.ts";

// scraped out of a macOS hidpi (5660ppm) screenshot png
// 5669 px (x-axis) , 5669 px (y-axis) , per metre
Expand Down Expand Up @@ -150,15 +151,20 @@ async function infoForImageFile(matrixClient: MatrixClient, roomId: string, imag
thumbnailType = "image/jpeg";
}

// We don't await this immediately so it can happen in the background
const isAnimatedPromise = blobIsAnimated(imageFile.type, imageFile);

const imageElement = await loadImageElement(imageFile);

const result = await createThumbnail(imageElement.img, imageElement.width, imageElement.height, thumbnailType);
const imageInfo = result.info;

imageInfo["org.matrix.msc4230.is_animated"] = await isAnimatedPromise;

// For lesser supported image types, always include the thumbnail even if it is larger
if (!ALWAYS_INCLUDE_THUMBNAIL.includes(imageFile.type)) {
// we do all sizing checks here because we still rely on thumbnail generation for making a blurhash from.
const sizeDifference = imageFile.size - imageInfo.thumbnail_info!.size;
const sizeDifference = imageFile.size - imageInfo.thumbnail_info!.size!;
if (
// image is small enough already
imageFile.size <= IMAGE_SIZE_THRESHOLD_THUMBNAIL ||
Expand Down
13 changes: 10 additions & 3 deletions src/components/views/messages/MImageBody.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ export default class MImageBody extends React.Component<IBodyProps, IState> {
}

const content = this.props.mxEvent.getContent<ImageContent>();
let isAnimated = mayBeAnimated(content.info?.mimetype);
let isAnimated = content.info?.["org.matrix.msc4230.is_animated"] ?? mayBeAnimated(content.info?.mimetype);

// If there is no included non-animated thumbnail then we will generate our own, we can't depend on the server
// because 1. encryption and 2. we can't ask the server specifically for a non-animated thumbnail.
Expand All @@ -298,8 +298,15 @@ export default class MImageBody extends React.Component<IBodyProps, IState> {
}

try {
const blob = await this.props.mediaEventHelper!.sourceBlob.value;
if (!(await blobIsAnimated(content.info?.mimetype, blob))) {
// If we didn't receive the MSC4230 is_animated flag
// then we need to check if the image is animated by downloading it.
if (
content.info?.["org.matrix.msc4230.is_animated"] === false ||
!(await blobIsAnimated(
content.info?.mimetype,
await this.props.mediaEventHelper!.sourceBlob.value,
))
) {
isAnimated = false;
}

Expand Down
16 changes: 2 additions & 14 deletions src/utils/image-media.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/

import { EncryptedFile } from "matrix-js-sdk/src/types";
import { ImageInfo } from "matrix-js-sdk/src/types";

import { BlurhashEncoder } from "../BlurhashEncoder";

Expand All @@ -15,19 +15,7 @@ type ThumbnailableElement = HTMLImageElement | HTMLVideoElement;
export const BLURHASH_FIELD = "xyz.amorgan.blurhash"; // MSC2448

interface IThumbnail {
info: {
thumbnail_info?: {
w: number;
h: number;
mimetype: string;
size: number;
};
w: number;
h: number;
[BLURHASH_FIELD]?: string;
thumbnail_url?: string;
thumbnail_file?: EncryptedFile;
};
info: ImageInfo;
thumbnail: Blob;
}

Expand Down

0 comments on commit 3d66641

Please sign in to comment.