[Perf] Message: Use Offscreen Canvas to detect appendix bg
This commit is contained in:
parent
590a6f5b4c
commit
f4200e5a64
@ -56,6 +56,7 @@ const Invoice: FC<OwnProps> = ({
|
||||
const photoUrl = useMedia(getWebDocumentHash(photo));
|
||||
const withBlurredBackground = Boolean(forcedWidth);
|
||||
const blurredBackgroundRef = useBlurredMediaThumbRef(photoUrl, !withBlurredBackground);
|
||||
const messageId = message.id;
|
||||
|
||||
useLayoutEffectWithPrevDeps(([prevShouldAffectAppendix]) => {
|
||||
if (!shouldAffectAppendix) {
|
||||
@ -67,14 +68,14 @@ const Invoice: FC<OwnProps> = ({
|
||||
|
||||
if (photoUrl) {
|
||||
const contentEl = ref.current!.closest<HTMLDivElement>(MESSAGE_CONTENT_SELECTOR)!;
|
||||
getCustomAppendixBg(photoUrl, false, isSelected, theme).then((appendixBg) => {
|
||||
getCustomAppendixBg(photoUrl, false, messageId, isSelected, theme).then((appendixBg) => {
|
||||
requestMutation(() => {
|
||||
contentEl.style.setProperty('--appendix-bg', appendixBg);
|
||||
contentEl.setAttribute(CUSTOM_APPENDIX_ATTRIBUTE, '');
|
||||
});
|
||||
});
|
||||
}
|
||||
}, [shouldAffectAppendix, photoUrl, isInSelectMode, isSelected, theme]);
|
||||
}, [shouldAffectAppendix, photoUrl, isInSelectMode, isSelected, theme, messageId]);
|
||||
|
||||
const width = forcedWidth || photo?.dimensions?.width;
|
||||
|
||||
|
||||
@ -179,7 +179,8 @@ const Photo = <T,>({
|
||||
|
||||
const contentEl = ref.current!.closest<HTMLDivElement>(MESSAGE_CONTENT_SELECTOR)!;
|
||||
if (fullMediaData) {
|
||||
getCustomAppendixBg(fullMediaData, Boolean(isOwn), isSelected, theme).then((appendixBg) => {
|
||||
const messageId = Number(contentEl.closest<HTMLDivElement>('.Message')!.dataset.messageId);
|
||||
getCustomAppendixBg(fullMediaData, Boolean(isOwn), messageId, isSelected, theme).then((appendixBg) => {
|
||||
requestMutation(() => {
|
||||
contentEl.style.setProperty('--appendix-bg', appendixBg);
|
||||
contentEl.setAttribute(CUSTOM_APPENDIX_ATTRIBUTE, '');
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
import type { ISettings } from '../../../../types';
|
||||
|
||||
import { MAX_WORKERS, requestMediaWorker } from '../../../../util/launchMediaWorkers';
|
||||
|
||||
const SELECTED_APPENDIX_COLORS = {
|
||||
dark: {
|
||||
outgoing: 'rgb(135,116,225)',
|
||||
@ -12,36 +14,14 @@ const SELECTED_APPENDIX_COLORS = {
|
||||
};
|
||||
|
||||
export default function getCustomAppendixBg(
|
||||
src: string, isOwn: boolean, isSelected?: boolean, theme?: ISettings['theme'],
|
||||
src: string, isOwn: boolean, id: number, isSelected?: boolean, theme?: ISettings['theme'],
|
||||
) {
|
||||
if (isSelected) {
|
||||
return Promise.resolve(SELECTED_APPENDIX_COLORS[theme || 'light'][isOwn ? 'outgoing' : 'incoming']);
|
||||
}
|
||||
return getAppendixColorFromImage(src, isOwn);
|
||||
}
|
||||
|
||||
async function getAppendixColorFromImage(src: string, isOwn: boolean) {
|
||||
const img = new Image();
|
||||
img.src = src;
|
||||
img.crossOrigin = 'anonymous';
|
||||
|
||||
if (!img.width) {
|
||||
await new Promise((resolve) => {
|
||||
img.onload = resolve;
|
||||
});
|
||||
}
|
||||
|
||||
const canvas = document.createElement('canvas');
|
||||
const ctx = canvas.getContext('2d')!;
|
||||
|
||||
canvas.width = img.width;
|
||||
canvas.height = img.height;
|
||||
|
||||
ctx.drawImage(img, 0, 0, img.width, img.height);
|
||||
|
||||
const x = isOwn ? img.width - 1 : 0;
|
||||
const y = img.height - 1;
|
||||
|
||||
const pixel = Array.from(ctx.getImageData(x, y, 1, 1).data);
|
||||
return `rgba(${pixel.join(',')})`;
|
||||
|
||||
return requestMediaWorker({
|
||||
name: 'offscreen-canvas:getAppendixColorFromImage',
|
||||
args: [src, isOwn],
|
||||
}, id % MAX_WORKERS);
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { useLayoutEffect, useMemo, useRef } from '../lib/teact/teact';
|
||||
|
||||
import cycleRestrict from '../util/cycleRestrict';
|
||||
import launchMediaWorkers, { MAX_WORKERS } from '../util/launchMediaWorkers';
|
||||
import { MAX_WORKERS, requestMediaWorker } from '../util/launchMediaWorkers';
|
||||
|
||||
const RADIUS = 7;
|
||||
|
||||
@ -25,12 +25,11 @@ export default function useOffscreenCanvasBlur(
|
||||
|
||||
offscreenRef.current = canvas.transferControlToOffscreen();
|
||||
|
||||
const { connector } = launchMediaWorkers()[workerIndex];
|
||||
connector.request({
|
||||
name: 'blurThumb',
|
||||
requestMediaWorker({
|
||||
name: 'offscreen-canvas:blurThumb',
|
||||
args: [offscreenRef.current, thumbData, radius],
|
||||
transferables: [offscreenRef.current],
|
||||
});
|
||||
}, workerIndex);
|
||||
}, [thumbData, isDisabled, radius, workerIndex]);
|
||||
|
||||
return canvasRef;
|
||||
|
||||
@ -22,6 +22,21 @@ export async function blurThumb(canvas: OffscreenCanvas, thumbData: string, radi
|
||||
}
|
||||
}
|
||||
|
||||
export async function getAppendixColorFromImage(blobUrl: string, isOwn: boolean) {
|
||||
const imageBitmap = await blobUrlToImageBitmap(blobUrl);
|
||||
const { width, height } = imageBitmap;
|
||||
const canvas = new OffscreenCanvas(width, height);
|
||||
const ctx = canvas.getContext('2d')!;
|
||||
|
||||
ctx.drawImage(imageBitmap, 0, 0, width, height);
|
||||
|
||||
const x = isOwn ? width - 1 : 0;
|
||||
const y = height - 1;
|
||||
|
||||
const pixel = Array.from(ctx.getImageData(x, y, 1, 1).data);
|
||||
return `rgba(${pixel.join(',')})`;
|
||||
}
|
||||
|
||||
function dataUriToImageBitmap(dataUri: string) {
|
||||
const byteString = atob(dataUri.split(',')[1]);
|
||||
const mimeString = dataUri.split(',')[0].split(':')[1].split(';')[0];
|
||||
@ -43,7 +58,10 @@ async function blobUrlToImageBitmap(blobUrl: string) {
|
||||
return createImageBitmap(blob);
|
||||
}
|
||||
|
||||
const api = { blurThumb };
|
||||
const api = {
|
||||
'offscreen-canvas:blurThumb': blurThumb,
|
||||
'offscreen-canvas:getAppendixColorFromImage': getAppendixColorFromImage,
|
||||
};
|
||||
|
||||
createWorkerInterface(api, 'media');
|
||||
|
||||
|
||||
@ -26,3 +26,7 @@ export default function launchMediaWorkers() {
|
||||
|
||||
return instances;
|
||||
}
|
||||
|
||||
export function requestMediaWorker(payload: Parameters<Connector<MediaWorkerApi>['request']>[0], index: number) {
|
||||
return launchMediaWorkers()[index].connector.request(payload);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user