Merge pull request #2887 from Bilb/fix-resize-images-thumbnail

fix: make sure we scale image before trying to compress it
pull/3060/head
Audric Ackermann 1 year ago committed by GitHub
commit 0ad6298ff5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -1 +0,0 @@
--install.frozen-lockfile true

@ -77,7 +77,7 @@
"auto-bind": "^4.0.0", "auto-bind": "^4.0.0",
"backbone": "1.3.3", "backbone": "1.3.3",
"blob-util": "2.0.2", "blob-util": "2.0.2",
"blueimp-load-image": "5.14.0", "blueimp-load-image": "^5.16.0",
"buffer-crc32": "0.2.13", "buffer-crc32": "0.2.13",
"bunyan": "https://github.com/Bilb/node-bunyan", "bunyan": "https://github.com/Bilb/node-bunyan",
"bytebuffer": "^5.0.1", "bytebuffer": "^5.0.1",
@ -138,7 +138,7 @@
"@commitlint/types": "^17.4.4", "@commitlint/types": "^17.4.4",
"@electron/notarize": "^2.1.0", "@electron/notarize": "^2.1.0",
"@types/backbone": "1.4.2", "@types/backbone": "1.4.2",
"@types/blueimp-load-image": "5.14.4", "@types/blueimp-load-image": "^5.16.2",
"@types/buffer-crc32": "^0.2.0", "@types/buffer-crc32": "^0.2.0",
"@types/bunyan": "^1.8.8", "@types/bunyan": "^1.8.8",
"@types/bytebuffer": "^5.0.41", "@types/bytebuffer": "^5.0.41",
@ -165,7 +165,7 @@
"@types/rimraf": "2.0.2", "@types/rimraf": "2.0.2",
"@types/semver": "5.5.0", "@types/semver": "5.5.0",
"@types/sinon": "9.0.4", "@types/sinon": "9.0.4",
"@types/styled-components": "^5.1.4", "@types/styled-components": "5.1.1",
"@types/uuid": "8.3.4", "@types/uuid": "8.3.4",
"@typescript-eslint/eslint-plugin": "7.1.0", "@typescript-eslint/eslint-plugin": "7.1.0",
"@typescript-eslint/parser": "7.1.0", "@typescript-eslint/parser": "7.1.0",

@ -19,7 +19,7 @@ import {
import { import {
AttachmentType, AttachmentType,
AttachmentTypeWithPath, AttachmentTypeWithPath,
canDisplayImage, canDisplayImagePreview,
getExtensionForDisplay, getExtensionForDisplay,
hasImage, hasImage,
hasVideoScreenshot, hasVideoScreenshot,
@ -131,7 +131,7 @@ export const MessageAttachment = (props: Props) => {
} }
const firstAttachment = attachments[0]; const firstAttachment = attachments[0];
const displayImage = canDisplayImage(attachments); const displayImage = canDisplayImagePreview(attachments);
if (!isTrustedForAttachmentDownload) { if (!isTrustedForAttachmentDownload) {
return <ClickToTrustSender messageId={messageId} />; return <ClickToTrustSender messageId={messageId} />;

@ -21,7 +21,7 @@ import {
getShouldHighlightMessage, getShouldHighlightMessage,
} from '../../../../state/selectors/conversations'; } from '../../../../state/selectors/conversations';
import { useSelectedIsPrivate } from '../../../../state/selectors/selectedConversation'; import { useSelectedIsPrivate } from '../../../../state/selectors/selectedConversation';
import { canDisplayImage } from '../../../../types/Attachment'; import { canDisplayImagePreview } from '../../../../types/Attachment';
import { MessageAttachment } from './MessageAttachment'; import { MessageAttachment } from './MessageAttachment';
import { MessageAvatar } from './MessageAvatar'; import { MessageAvatar } from './MessageAvatar';
import { MessageHighlighter } from './MessageHighlighter'; import { MessageHighlighter } from './MessageHighlighter';
@ -154,7 +154,8 @@ export const MessageContent = (props: Props) => {
const toolTipTitle = moment(serverTimestamp || timestamp).format('llll'); const toolTipTitle = moment(serverTimestamp || timestamp).format('llll');
const isDetailViewAndSupportsAttachmentCarousel = isDetailView && canDisplayImage(attachments); const isDetailViewAndSupportsAttachmentCarousel =
isDetailView && canDisplayImagePreview(attachments);
return ( return (
<StyledMessageContent <StyledMessageContent

@ -1,4 +1,4 @@
import React, { ReactElement } from 'react'; import React from 'react';
import styled from 'styled-components'; import styled from 'styled-components';
import { isEmpty } from 'lodash'; import { isEmpty } from 'lodash';
@ -160,7 +160,7 @@ const ExpiresInItem = ({ expirationTimestamp }: { expirationTimestamp?: number |
); );
}; };
export const MessageReactBar = ({ action, additionalAction, messageId }: Props): ReactElement => { export const MessageReactBar = ({ action, additionalAction, messageId }: Props) => {
const recentReactions = getRecentReactions(); const recentReactions = getRecentReactions();
const expirationTimestamp = useIsRenderedExpiresInItem(messageId); const expirationTimestamp = useIsRenderedExpiresInItem(messageId);

@ -1,5 +1,5 @@
import { isEmpty, isEqual } from 'lodash'; import { isEmpty, isEqual } from 'lodash';
import React, { ReactElement, useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import styled from 'styled-components'; import styled from 'styled-components';
import { useIsDetailMessageView } from '../../../../contexts/isDetailViewContext'; import { useIsDetailMessageView } from '../../../../contexts/isDetailViewContext';
import { useMessageReactsPropsById } from '../../../../hooks/useParamSelector'; import { useMessageReactsPropsById } from '../../../../hooks/useParamSelector';
@ -66,7 +66,7 @@ const StyledReadLess = styled.span`
type ReactionsProps = Omit<ReactionProps, 'emoji'>; type ReactionsProps = Omit<ReactionProps, 'emoji'>;
const Reactions = (props: ReactionsProps): ReactElement => { const Reactions = (props: ReactionsProps) => {
const { messageId, reactions, inModal } = props; const { messageId, reactions, inModal } = props;
return ( return (
<StyledMessageReactions <StyledMessageReactions
@ -86,7 +86,7 @@ interface ExpandReactionsProps extends ReactionsProps {
handleExpand: () => void; handleExpand: () => void;
} }
const CompressedReactions = (props: ExpandReactionsProps): ReactElement => { const CompressedReactions = (props: ExpandReactionsProps) => {
const { messageId, reactions, inModal, handleExpand } = props; const { messageId, reactions, inModal, handleExpand } = props;
return ( return (
<StyledMessageReactions <StyledMessageReactions
@ -120,7 +120,7 @@ const CompressedReactions = (props: ExpandReactionsProps): ReactElement => {
); );
}; };
const ExpandedReactions = (props: ExpandReactionsProps): ReactElement => { const ExpandedReactions = (props: ExpandReactionsProps) => {
const { handleExpand } = props; const { handleExpand } = props;
return ( return (
<Flex container={true} flexDirection={'column'} alignItems={'center'} margin="4px 0 0"> <Flex container={true} flexDirection={'column'} alignItems={'center'} margin="4px 0 0">

@ -1,4 +1,4 @@
import React, { ReactElement, useRef, useState } from 'react'; import React, { useRef, useState } from 'react';
import { useMouse } from 'react-use'; import { useMouse } from 'react-use';
import styled from 'styled-components'; import styled from 'styled-components';
import { useRightOverlayMode } from '../../../../hooks/useUI'; import { useRightOverlayMode } from '../../../../hooks/useUI';
@ -62,7 +62,7 @@ export type ReactionProps = {
handlePopupClick?: () => void; handlePopupClick?: () => void;
}; };
export const Reaction = (props: ReactionProps): ReactElement => { export const Reaction = (props: ReactionProps) => {
const { const {
emoji, emoji,
messageId, messageId,

@ -1,11 +1,11 @@
import React, { ReactElement, useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import styled from 'styled-components'; import styled from 'styled-components';
import { Data } from '../../../../data/data'; import { Data } from '../../../../data/data';
import { findAndFormatContact } from '../../../../models/message';
import { PubKey } from '../../../../session/types/PubKey'; import { PubKey } from '../../../../session/types/PubKey';
import { isDarkTheme } from '../../../../state/selectors/theme'; import { isDarkTheme } from '../../../../state/selectors/theme';
import { nativeEmojiData } from '../../../../util/emoji'; import { nativeEmojiData } from '../../../../util/emoji';
import { findAndFormatContact } from '../../../../models/message';
export type TipPosition = 'center' | 'left' | 'right'; export type TipPosition = 'center' | 'left' | 'right';
@ -142,7 +142,7 @@ type Props = {
onClick: (...args: Array<any>) => void; onClick: (...args: Array<any>) => void;
}; };
export const ReactionPopup = (props: Props): ReactElement => { export const ReactionPopup = (props: Props) => {
const { messageId, emoji, count, senders, tooltipPosition = 'center', onClick } = props; const { messageId, emoji, count, senders, tooltipPosition = 'center', onClick } = props;
const [contacts, setContacts] = useState<Array<string>>([]); const [contacts, setContacts] = useState<Array<string>>([]);

@ -29,7 +29,7 @@ import {
useMessageTimestamp, useMessageTimestamp,
} from '../../../../../state/selectors'; } from '../../../../../state/selectors';
import { useSelectedConversationKey } from '../../../../../state/selectors/selectedConversation'; import { useSelectedConversationKey } from '../../../../../state/selectors/selectedConversation';
import { canDisplayImage } from '../../../../../types/Attachment'; import { canDisplayImagePreview } from '../../../../../types/Attachment';
import { isAudio } from '../../../../../types/MIME'; import { isAudio } from '../../../../../types/MIME';
import { import {
getAudioDuration, getAudioDuration,
@ -222,7 +222,7 @@ export const OverlayMessageInfo = () => {
const { errors, attachments } = messageInfo; const { errors, attachments } = messageInfo;
const hasAttachments = attachments && attachments.length > 0; const hasAttachments = attachments && attachments.length > 0;
const supportsAttachmentCarousel = canDisplayImage(attachments); const supportsAttachmentCarousel = canDisplayImagePreview(attachments);
const hasErrors = errors && errors.length > 0; const hasErrors = errors && errors.length > 0;
const handleChangeAttachment = (changeDirection: 1 | -1) => { const handleChangeAttachment = (changeDirection: 1 | -1) => {

@ -1,6 +1,6 @@
import { useDispatch } from 'react-redux'; import { useDispatch } from 'react-redux';
// eslint-disable-next-line import/no-named-default // eslint-disable-next-line import/no-named-default
import { ChangeEvent, MouseEvent, default as React, ReactElement, useState } from 'react'; import { ChangeEvent, MouseEvent, default as React, useState } from 'react';
import { QRCode } from 'react-qr-svg'; import { QRCode } from 'react-qr-svg';
import styled from 'styled-components'; import styled from 'styled-components';
import { Avatar, AvatarSize } from '../avatar/Avatar'; import { Avatar, AvatarSize } from '../avatar/Avatar';
@ -69,7 +69,7 @@ type ProfileAvatarProps = {
ourId: string; ourId: string;
}; };
export const ProfileAvatar = (props: ProfileAvatarProps): ReactElement => { export const ProfileAvatar = (props: ProfileAvatarProps) => {
const { newAvatarObjectUrl, avatarPath, profileName, ourId } = props; const { newAvatarObjectUrl, avatarPath, profileName, ourId } = props;
return ( return (
<Avatar <Avatar
@ -86,7 +86,7 @@ type ProfileHeaderProps = ProfileAvatarProps & {
setMode: (mode: ProfileDialogModes) => void; setMode: (mode: ProfileDialogModes) => void;
}; };
const ProfileHeader = (props: ProfileHeaderProps): ReactElement => { const ProfileHeader = (props: ProfileHeaderProps) => {
const { avatarPath, profileName, ourId, onClick, setMode } = props; const { avatarPath, profileName, ourId, onClick, setMode } = props;
return ( return (
@ -114,7 +114,8 @@ const ProfileHeader = (props: ProfileHeaderProps): ReactElement => {
}; };
type ProfileDialogModes = 'default' | 'edit' | 'qr'; type ProfileDialogModes = 'default' | 'edit' | 'qr';
export const EditProfileDialog = (): ReactElement => {
export const EditProfileDialog = () => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const _profileName = useOurConversationUsername() || ''; const _profileName = useOurConversationUsername() || '';

@ -1,14 +1,14 @@
import React, { ReactElement, useState } from 'react'; import React, { useState } from 'react';
import { useDispatch } from 'react-redux'; import { useDispatch } from 'react-redux';
import styled from 'styled-components'; import styled from 'styled-components';
import { useMessageReactsPropsById } from '../../hooks/useParamSelector'; import { useMessageReactsPropsById } from '../../hooks/useParamSelector';
import { clearSogsReactionByServerId } from '../../session/apis/open_group_api/sogsv3/sogsV3ClearReaction'; import { clearSogsReactionByServerId } from '../../session/apis/open_group_api/sogsv3/sogsV3ClearReaction';
import { getConversationController } from '../../session/conversations'; import { getConversationController } from '../../session/conversations';
import { updateReactClearAllModal } from '../../state/ducks/modalDialog'; import { updateReactClearAllModal } from '../../state/ducks/modalDialog';
import { SessionWrapperModal } from '../SessionWrapperModal';
import { Flex } from '../basic/Flex'; import { Flex } from '../basic/Flex';
import { SessionButton, SessionButtonColor, SessionButtonType } from '../basic/SessionButton'; import { SessionButton, SessionButtonColor, SessionButtonType } from '../basic/SessionButton';
import { SessionSpinner } from '../basic/SessionSpinner'; import { SessionSpinner } from '../basic/SessionSpinner';
import { SessionWrapperModal } from '../SessionWrapperModal';
type Props = { type Props = {
reaction: string; reaction: string;
@ -46,7 +46,7 @@ const StyledReactClearAllContainer = styled(Flex)`
} }
`; `;
export const ReactClearAllModal = (props: Props): ReactElement => { export const ReactClearAllModal = (props: Props) => {
const { reaction, messageId } = props; const { reaction, messageId } = props;
const [clearingInProgress, setClearingInProgress] = useState(false); const [clearingInProgress, setClearingInProgress] = useState(false);

@ -1,9 +1,10 @@
import { isEmpty, isEqual } from 'lodash'; import { isEmpty, isEqual } from 'lodash';
import React, { ReactElement, useEffect, useMemo, useState } from 'react'; import React, { useEffect, useMemo, useState } from 'react';
import { useDispatch } from 'react-redux'; import { useDispatch } from 'react-redux';
import styled from 'styled-components'; import styled from 'styled-components';
import { Data } from '../../data/data'; import { Data } from '../../data/data';
import { useMessageReactsPropsById } from '../../hooks/useParamSelector'; import { useMessageReactsPropsById } from '../../hooks/useParamSelector';
import { findAndFormatContact } from '../../models/message';
import { isUsAnySogsFromCache } from '../../session/apis/open_group_api/sogsv3/knownBlindedkeys'; import { isUsAnySogsFromCache } from '../../session/apis/open_group_api/sogsv3/knownBlindedkeys';
import { UserUtils } from '../../session/utils'; import { UserUtils } from '../../session/utils';
import { import {
@ -18,6 +19,7 @@ import {
import { SortedReactionList } from '../../types/Reaction'; import { SortedReactionList } from '../../types/Reaction';
import { nativeEmojiData } from '../../util/emoji'; import { nativeEmojiData } from '../../util/emoji';
import { Reactions } from '../../util/reactions'; import { Reactions } from '../../util/reactions';
import { SessionWrapperModal } from '../SessionWrapperModal';
import { Avatar, AvatarSize } from '../avatar/Avatar'; import { Avatar, AvatarSize } from '../avatar/Avatar';
import { Flex } from '../basic/Flex'; import { Flex } from '../basic/Flex';
import { SessionButton, SessionButtonColor, SessionButtonType } from '../basic/SessionButton'; import { SessionButton, SessionButtonColor, SessionButtonType } from '../basic/SessionButton';
@ -25,8 +27,6 @@ import { SessionHtmlRenderer } from '../basic/SessionHTMLRenderer';
import { ContactName } from '../conversation/ContactName'; import { ContactName } from '../conversation/ContactName';
import { MessageReactions } from '../conversation/message/message-content/MessageReactions'; import { MessageReactions } from '../conversation/message/message-content/MessageReactions';
import { SessionIconButton } from '../icon'; import { SessionIconButton } from '../icon';
import { SessionWrapperModal } from '../SessionWrapperModal';
import { findAndFormatContact } from '../../models/message';
const StyledReactListContainer = styled(Flex)` const StyledReactListContainer = styled(Flex)`
width: 376px; width: 376px;
@ -218,7 +218,7 @@ const handleSenders = (senders: Array<string>, me: string) => {
return updatedSenders; return updatedSenders;
}; };
export const ReactListModal = (props: Props): ReactElement => { export const ReactListModal = (props: Props) => {
const { reaction, messageId } = props; const { reaction, messageId } = props;
const dispatch = useDispatch(); const dispatch = useDispatch();

@ -2,7 +2,7 @@ import { isString } from 'lodash';
import React from 'react'; import React from 'react';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { AutoSizer, Index, List, ListRowProps } from 'react-virtualized'; import { AutoSizer, Index, List, ListRowProps } from 'react-virtualized';
import styled from 'styled-components'; import styled, { CSSProperties } from 'styled-components';
import { import {
DirectContactsByNameType, DirectContactsByNameType,
getDirectContactsByName, getDirectContactsByName,
@ -51,10 +51,10 @@ const renderRow = (props: ListRowProps) => {
} }
if (isString(item)) { if (isString(item)) {
return <ContactRowBreak style={style} key={key} char={item} />; return <ContactRowBreak style={style as CSSProperties} key={key} char={item} />;
} }
return <ContactRow style={style} key={key} {...item} />; return <ContactRow style={style as CSSProperties} key={key} {...item} />;
}; };
const unknownSection = 'unknown'; const unknownSection = 'unknown';

@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
export const AccentText: React.FC = () => ( export const AccentText = () => (
<div className="session-content-accent-text"> <div className="session-content-accent-text">
<div className="session-content-accent-text title">{window.i18n('beginYourSession')}</div> <div className="session-content-accent-text title">{window.i18n('beginYourSession')}</div>
</div> </div>

@ -1,8 +1,8 @@
import { isString } from 'lodash';
import React from 'react'; import React from 'react';
import styled, { CSSProperties } from 'styled-components';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { AutoSizer, List } from 'react-virtualized'; import { AutoSizer, List } from 'react-virtualized';
import { isString } from 'lodash'; import styled, { CSSProperties } from 'styled-components';
import { ConversationListItem } from '../leftpane/conversation-list-item/ConversationListItem'; import { ConversationListItem } from '../leftpane/conversation-list-item/ConversationListItem';
import { MessageSearchResult } from './MessageSearchResults'; import { MessageSearchResult } from './MessageSearchResults';
@ -65,14 +65,14 @@ const VirtualizedList = () => {
return null; return null;
} }
if (isString(row)) { if (isString(row)) {
return <SectionHeader title={row} style={style} key={key} />; return <SectionHeader title={row} style={style as CSSProperties} key={key} />;
} }
if (isContact(row)) { if (isContact(row)) {
return ( return (
<ConversationListItem conversationId={row.contactConvoId} style={style} key={key} /> <ConversationListItem conversationId={row.contactConvoId} style={style} key={key} />
); );
} }
return <MessageSearchResult style={style} key={key} {...row} />; return <MessageSearchResult style={style as CSSProperties} key={key} {...row} />;
}} }}
width={width} width={width}
autoHeight={false} autoHeight={false}

@ -3,6 +3,9 @@ import _ from 'lodash';
import { Attachment } from '../../types/Attachment'; import { Attachment } from '../../types/Attachment';
import { encryptAttachment } from '../../util/crypto/attachmentsEncrypter';
import { uploadFileToFsWithOnionV4 } from '../apis/file_server_api/FileServerApi';
import { addAttachmentPadding } from '../crypto/BufferPadding';
import { import {
AttachmentPointer, AttachmentPointer,
AttachmentPointerWithUrl, AttachmentPointerWithUrl,
@ -10,9 +13,6 @@ import {
Quote, Quote,
QuotedAttachmentWithUrl, QuotedAttachmentWithUrl,
} from '../messages/outgoing/visibleMessage/VisibleMessage'; } from '../messages/outgoing/visibleMessage/VisibleMessage';
import { addAttachmentPadding } from '../crypto/BufferPadding';
import { encryptAttachment } from '../../util/crypto/attachmentsEncrypter';
import { uploadFileToFsWithOnionV4 } from '../apis/file_server_api/FileServerApi';
interface UploadParams { interface UploadParams {
attachment: Attachment; attachment: Attachment;
@ -107,7 +107,9 @@ export async function uploadLinkPreviewToFileServer(
): Promise<PreviewWithAttachmentUrl | undefined> { ): Promise<PreviewWithAttachmentUrl | undefined> {
// some links do not have an image associated, and it makes the whole message fail to send // some links do not have an image associated, and it makes the whole message fail to send
if (!preview?.image) { if (!preview?.image) {
window.log.warn('tried to upload file to FileServer without image.. skipping'); if (!preview) {
window.log.warn('tried to upload file to FileServer without image.. skipping');
}
return preview as any; return preview as any;
} }
const image = await uploadToFileServer({ const image = await uploadToFileServer({

@ -104,9 +104,11 @@ export function isAudio(attachments?: Array<AttachmentType>) {
); );
} }
export function canDisplayImage(attachments?: Array<AttachmentType>) { export function canDisplayImagePreview(attachments?: Array<AttachmentType>) {
// Note: when we display an image we usually display the preview.
// The preview is usually downscaled
const { height, width } = const { height, width } =
attachments && attachments[0] ? attachments[0] : { height: 0, width: 0 }; attachments && attachments[0]?.thumbnail ? attachments[0].thumbnail : { height: 0, width: 0 };
return Boolean( return Boolean(
height && height &&

@ -2,7 +2,7 @@
import imageType from 'image-type'; import imageType from 'image-type';
import { arrayBufferToBlob } from 'blob-util'; import { arrayBufferToBlob } from 'blob-util';
import loadImage, { LoadImageOptions } from 'blueimp-load-image'; import loadImage from 'blueimp-load-image';
import { StagedAttachmentType } from '../components/conversation/composition/CompositionBox'; import { StagedAttachmentType } from '../components/conversation/composition/CompositionBox';
import { SignalService } from '../protobuf'; import { SignalService } from '../protobuf';
import { getDecryptedMediaUrl } from '../session/crypto/DecryptedAttachmentsManager'; import { getDecryptedMediaUrl } from '../session/crypto/DecryptedAttachmentsManager';
@ -68,7 +68,7 @@ export async function autoScaleForAvatar<T extends { contentType: string; blob:
} }
if (DEBUG_ATTACHMENTS_SCALE) { if (DEBUG_ATTACHMENTS_SCALE) {
window.log.info('autoscale for avatar', maxMeasurements); window.log.debug('autoscale for avatar', maxMeasurements);
} }
return autoScale(attachment, maxMeasurements); return autoScale(attachment, maxMeasurements);
} }
@ -96,7 +96,7 @@ export async function autoScaleForIncomingAvatar(incomingAvatar: ArrayBuffer) {
} }
if (DEBUG_ATTACHMENTS_SCALE) { if (DEBUG_ATTACHMENTS_SCALE) {
window.log.info('autoscale for incoming avatar', maxMeasurements); window.log.debug('autoscale for incoming avatar', maxMeasurements);
} }
return autoScale( return autoScale(
@ -121,7 +121,7 @@ export async function autoScaleForThumbnail<T extends { contentType: string; blo
}; };
if (DEBUG_ATTACHMENTS_SCALE) { if (DEBUG_ATTACHMENTS_SCALE) {
window.log.info('autoScaleForThumbnail', maxMeasurements); window.log.debug('autoScaleForThumbnail', maxMeasurements);
} }
return autoScale(attachment, maxMeasurements); return autoScale(attachment, maxMeasurements);
@ -189,44 +189,58 @@ export async function autoScale<T extends { contentType: string; blob: Blob }>(
throw new Error(`GIF is too large, required size is ${maxSize}`); throw new Error(`GIF is too large, required size is ${maxSize}`);
} }
const loadImgOpts: LoadImageOptions = {
maxWidth: makeSquare ? maxMeasurements?.maxSide : maxWidth,
maxHeight: makeSquare ? maxMeasurements?.maxSide : maxHeight,
crop: !!makeSquare,
orientation: 1,
aspectRatio: makeSquare ? 1 : undefined,
canvas: true,
imageSmoothingQuality: 'medium',
};
perfStart(`loadimage-*${blob.size}`); perfStart(`loadimage-*${blob.size}`);
const canvas = await loadImage(blob, loadImgOpts); const canvasLoad = await loadImage(blob, {});
const canvasScaled = loadImage.scale(
canvasLoad.image, // img or canvas element
{
maxWidth: makeSquare ? maxMeasurements?.maxSide : maxWidth,
maxHeight: makeSquare ? maxMeasurements?.maxSide : maxHeight,
crop: !!makeSquare,
cover: !!makeSquare,
orientation: 1,
canvas: true,
imageSmoothingQuality: 'medium',
meta: false,
}
);
perfEnd(`loadimage-*${blob.size}`, `loadimage-*${blob.size}`); perfEnd(`loadimage-*${blob.size}`, `loadimage-*${blob.size}`);
if (!canvas || !canvas.originalWidth || !canvas.originalHeight) { if (!canvasScaled || !canvasScaled.width || !canvasScaled.height) {
throw new Error('failed to scale image'); throw new Error('failed to scale image');
} }
let readAndResizedBlob = blob; let readAndResizedBlob = blob;
if ( if (
canvas.originalWidth <= maxWidth && canvasScaled.width <= maxWidth &&
canvas.originalHeight <= maxHeight && canvasScaled.height <= maxHeight &&
blob.size <= maxSize && blob.size <= maxSize &&
!makeSquare !makeSquare
) { ) {
if (DEBUG_ATTACHMENTS_SCALE) {
window.log.debug('canvasScaled used right away as width, height and size are fine', {
canvasScaledWidth: canvasScaled.width,
canvasScaledHeight: canvasScaled.height,
maxWidth,
maxHeight,
blobsize: blob.size,
maxSize,
makeSquare,
});
}
// the canvas has a size of whatever was given by the caller of autoscale(). // the canvas has a size of whatever was given by the caller of autoscale().
// so we have to return those measures as the loaded file has now those measures. // so we have to return those measures as the loaded file has now those measures.
return { return {
...attachment,
width: canvas.image.width,
height: canvas.image.height,
blob, blob,
contentType: attachment.contentType,
width: canvasScaled.width,
height: canvasScaled.height,
}; };
} }
if (DEBUG_ATTACHMENTS_SCALE) { if (DEBUG_ATTACHMENTS_SCALE) {
window.log.debug('canvas.originalWidth', { window.log.debug('canvasOri.originalWidth', {
canvasOriginalWidth: canvas.originalWidth, canvasOriginalWidth: canvasScaled.width,
canvasOriginalHeight: canvas.originalHeight, canvasOriginalHeight: canvasScaled.height,
maxWidth, maxWidth,
maxHeight, maxHeight,
blobsize: blob.size, blobsize: blob.size,
@ -240,10 +254,10 @@ export async function autoScale<T extends { contentType: string; blob: Blob }>(
do { do {
i -= 1; i -= 1;
if (DEBUG_ATTACHMENTS_SCALE) { if (DEBUG_ATTACHMENTS_SCALE) {
// window.log.info(`autoscale iteration: [${i}] for:`, attachment); window.log.debug(`autoscale iteration: [${i}] for:`, JSON.stringify(readAndResizedBlob.size));
} }
// eslint-disable-next-line no-await-in-loop // eslint-disable-next-line no-await-in-loop
const tempBlob = await canvasToBlob(canvas.image as HTMLCanvasElement, 'image/jpeg', quality); const tempBlob = await canvasToBlob(canvasScaled, 'image/jpeg', quality);
if (!tempBlob) { if (!tempBlob) {
throw new Error('Failed to get blob during canvasToBlob.'); throw new Error('Failed to get blob during canvasToBlob.');
@ -265,8 +279,8 @@ export async function autoScale<T extends { contentType: string; blob: Blob }>(
contentType: attachment.contentType, contentType: attachment.contentType,
blob: readAndResizedBlob, blob: readAndResizedBlob,
width: canvas.image.width, width: canvasScaled.width,
height: canvas.image.height, height: canvasScaled.height,
}; };
} }

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save