mirror of https://github.com/vector-im/riot-web
Scale all mxc thumbs using device pixel ratio for hidpi
as we are notoriously bad at doing it everywhere we ought to, like the TopLeftMenu avatarpull/21833/head
parent
9401a6d6dc
commit
915f8b3c9c
|
@ -27,11 +27,7 @@ export type ResizeMethod = "crop" | "scale";
|
||||||
export function avatarUrlForMember(member: RoomMember, width: number, height: number, resizeMethod: ResizeMethod) {
|
export function avatarUrlForMember(member: RoomMember, width: number, height: number, resizeMethod: ResizeMethod) {
|
||||||
let url: string;
|
let url: string;
|
||||||
if (member?.getMxcAvatarUrl()) {
|
if (member?.getMxcAvatarUrl()) {
|
||||||
url = mediaFromMxc(member.getMxcAvatarUrl()).getThumbnailOfSourceHttp(
|
url = mediaFromMxc(member.getMxcAvatarUrl()).getThumbnailOfSourceHttp(width, height, resizeMethod);
|
||||||
Math.floor(width * window.devicePixelRatio),
|
|
||||||
Math.floor(height * window.devicePixelRatio),
|
|
||||||
resizeMethod,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if (!url) {
|
if (!url) {
|
||||||
// member can be null here currently since on invites, the JS SDK
|
// member can be null here currently since on invites, the JS SDK
|
||||||
|
@ -44,11 +40,7 @@ export function avatarUrlForMember(member: RoomMember, width: number, height: nu
|
||||||
|
|
||||||
export function avatarUrlForUser(user: User, width: number, height: number, resizeMethod?: ResizeMethod) {
|
export function avatarUrlForUser(user: User, width: number, height: number, resizeMethod?: ResizeMethod) {
|
||||||
if (!user.avatarUrl) return null;
|
if (!user.avatarUrl) return null;
|
||||||
return mediaFromMxc(user.avatarUrl).getThumbnailOfSourceHttp(
|
return mediaFromMxc(user.avatarUrl).getThumbnailOfSourceHttp(width, height, resizeMethod);
|
||||||
Math.floor(width * window.devicePixelRatio),
|
|
||||||
Math.floor(height * window.devicePixelRatio),
|
|
||||||
resizeMethod,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function isValidHexColor(color: string): boolean {
|
function isValidHexColor(color: string): boolean {
|
||||||
|
|
|
@ -136,7 +136,7 @@ const Tile: React.FC<ITileProps> = ({
|
||||||
|
|
||||||
let url: string;
|
let url: string;
|
||||||
if (room.avatar_url) {
|
if (room.avatar_url) {
|
||||||
url = mediaFromMxc(room.avatar_url).getSquareThumbnailHttp(Math.floor(20 * window.devicePixelRatio));
|
url = mediaFromMxc(room.avatar_url).getSquareThumbnailHttp(20);
|
||||||
}
|
}
|
||||||
|
|
||||||
let description = _t("%(count)s members", { count: room.num_joined_members });
|
let description = _t("%(count)s members", { count: room.num_joined_members });
|
||||||
|
|
|
@ -68,8 +68,8 @@ export default class MemberAvatar extends React.Component<IProps, IState> {
|
||||||
let imageUrl = null;
|
let imageUrl = null;
|
||||||
if (props.member.getMxcAvatarUrl()) {
|
if (props.member.getMxcAvatarUrl()) {
|
||||||
imageUrl = mediaFromMxc(props.member.getMxcAvatarUrl()).getThumbnailOfSourceHttp(
|
imageUrl = mediaFromMxc(props.member.getMxcAvatarUrl()).getThumbnailOfSourceHttp(
|
||||||
Math.floor(props.width * window.devicePixelRatio),
|
props.width,
|
||||||
Math.floor(props.height * window.devicePixelRatio),
|
props.height,
|
||||||
props.resizeMethod,
|
props.resizeMethod,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,8 +93,8 @@ export default class RoomAvatar extends React.Component<IProps, IState> {
|
||||||
let oobAvatar = null;
|
let oobAvatar = null;
|
||||||
if (props.oobData.avatarUrl) {
|
if (props.oobData.avatarUrl) {
|
||||||
oobAvatar = mediaFromMxc(props.oobData.avatarUrl).getThumbnailOfSourceHttp(
|
oobAvatar = mediaFromMxc(props.oobData.avatarUrl).getThumbnailOfSourceHttp(
|
||||||
Math.floor(props.width * window.devicePixelRatio),
|
props.width,
|
||||||
Math.floor(props.height * window.devicePixelRatio),
|
props.height,
|
||||||
props.resizeMethod,
|
props.resizeMethod,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -109,12 +109,7 @@ export default class RoomAvatar extends React.Component<IProps, IState> {
|
||||||
private static getRoomAvatarUrl(props: IProps): string {
|
private static getRoomAvatarUrl(props: IProps): string {
|
||||||
if (!props.room) return null;
|
if (!props.room) return null;
|
||||||
|
|
||||||
return Avatar.avatarUrlForRoom(
|
return Avatar.avatarUrlForRoom(props.room, props.width, props.height, props.resizeMethod);
|
||||||
props.room,
|
|
||||||
Math.floor(props.width * window.devicePixelRatio),
|
|
||||||
Math.floor(props.height * window.devicePixelRatio),
|
|
||||||
props.resizeMethod,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private onRoomAvatarClick = () => {
|
private onRoomAvatarClick = () => {
|
||||||
|
|
|
@ -130,7 +130,7 @@ export default class IncomingSasDialog extends React.Component {
|
||||||
const oppProfile = this.state.opponentProfile;
|
const oppProfile = this.state.opponentProfile;
|
||||||
if (oppProfile) {
|
if (oppProfile) {
|
||||||
const url = oppProfile.avatar_url
|
const url = oppProfile.avatar_url
|
||||||
? mediaFromMxc(oppProfile.avatar_url).getSquareThumbnailHttp(Math.floor(48 * window.devicePixelRatio))
|
? mediaFromMxc(oppProfile.avatar_url).getSquareThumbnailHttp(48)
|
||||||
: null;
|
: null;
|
||||||
profile = <div className="mx_IncomingSasDialog_opponentProfile">
|
profile = <div className="mx_IncomingSasDialog_opponentProfile">
|
||||||
<BaseAvatar name={oppProfile.displayname}
|
<BaseAvatar name={oppProfile.displayname}
|
||||||
|
|
|
@ -185,9 +185,8 @@ export default class MImageBody extends React.Component {
|
||||||
// So either we need to support custom timeline widths here, or reimpose the cap, otherwise the
|
// So either we need to support custom timeline widths here, or reimpose the cap, otherwise the
|
||||||
// thumbnail resolution will be unnecessarily reduced.
|
// thumbnail resolution will be unnecessarily reduced.
|
||||||
// custom timeline widths seems preferable.
|
// custom timeline widths seems preferable.
|
||||||
const pixelRatio = window.devicePixelRatio;
|
const thumbWidth = 800;
|
||||||
const thumbWidth = Math.round(800 * pixelRatio);
|
const thumbHeight = 600;
|
||||||
const thumbHeight = Math.round(600 * pixelRatio);
|
|
||||||
|
|
||||||
const content = this.props.mxEvent.getContent();
|
const content = this.props.mxEvent.getContent();
|
||||||
const media = mediaFromContent(content);
|
const media = mediaFromContent(content);
|
||||||
|
|
|
@ -96,6 +96,9 @@ export class Media {
|
||||||
*/
|
*/
|
||||||
public getThumbnailHttp(width: number, height: number, mode: ResizeMethod = "scale"): string | null | undefined {
|
public getThumbnailHttp(width: number, height: number, mode: ResizeMethod = "scale"): string | null | undefined {
|
||||||
if (!this.hasThumbnail) return null;
|
if (!this.hasThumbnail) return null;
|
||||||
|
// scale using the device pixel ratio to keep images clear
|
||||||
|
width = Math.floor(width * window.devicePixelRatio);
|
||||||
|
height = Math.floor(height * window.devicePixelRatio);
|
||||||
return this.client.mxcUrlToHttp(this.thumbnailMxc, width, height, mode);
|
return this.client.mxcUrlToHttp(this.thumbnailMxc, width, height, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,6 +110,9 @@ export class Media {
|
||||||
* @returns {string} The HTTP URL which points to the thumbnail.
|
* @returns {string} The HTTP URL which points to the thumbnail.
|
||||||
*/
|
*/
|
||||||
public getThumbnailOfSourceHttp(width: number, height: number, mode: ResizeMethod = "scale"): string {
|
public getThumbnailOfSourceHttp(width: number, height: number, mode: ResizeMethod = "scale"): string {
|
||||||
|
// scale using the device pixel ratio to keep images clear
|
||||||
|
width = Math.floor(width * window.devicePixelRatio);
|
||||||
|
height = Math.floor(height * window.devicePixelRatio);
|
||||||
return this.client.mxcUrlToHttp(this.srcMxc, width, height, mode);
|
return this.client.mxcUrlToHttp(this.srcMxc, width, height, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,6 +123,7 @@ export class Media {
|
||||||
* @returns {string} An HTTP URL for the thumbnail.
|
* @returns {string} An HTTP URL for the thumbnail.
|
||||||
*/
|
*/
|
||||||
public getSquareThumbnailHttp(dim: number): string {
|
public getSquareThumbnailHttp(dim: number): string {
|
||||||
|
dim = Math.floor(dim * window.devicePixelRatio); // scale using the device pixel ratio to keep images clear
|
||||||
if (this.hasThumbnail) {
|
if (this.hasThumbnail) {
|
||||||
return this.getThumbnailHttp(dim, dim, 'crop');
|
return this.getThumbnailHttp(dim, dim, 'crop');
|
||||||
}
|
}
|
||||||
|
|
|
@ -341,11 +341,7 @@ class RoomPillPart extends PillPart {
|
||||||
|
|
||||||
setAvatar(node: HTMLElement) {
|
setAvatar(node: HTMLElement) {
|
||||||
let initialLetter = "";
|
let initialLetter = "";
|
||||||
let avatarUrl = Avatar.avatarUrlForRoom(
|
let avatarUrl = Avatar.avatarUrlForRoom(this.room, 16, 16, "crop");
|
||||||
this.room,
|
|
||||||
16 * window.devicePixelRatio,
|
|
||||||
16 * window.devicePixelRatio,
|
|
||||||
"crop");
|
|
||||||
if (!avatarUrl) {
|
if (!avatarUrl) {
|
||||||
initialLetter = Avatar.getInitialLetter(this.room ? this.room.name : this.resourceId);
|
initialLetter = Avatar.getInitialLetter(this.room ? this.room.name : this.resourceId);
|
||||||
avatarUrl = Avatar.defaultAvatarUrlForString(this.room ? this.room.roomId : this.resourceId);
|
avatarUrl = Avatar.defaultAvatarUrlForString(this.room ? this.room.roomId : this.resourceId);
|
||||||
|
@ -383,11 +379,7 @@ class UserPillPart extends PillPart {
|
||||||
}
|
}
|
||||||
const name = this.member.name || this.member.userId;
|
const name = this.member.name || this.member.userId;
|
||||||
const defaultAvatarUrl = Avatar.defaultAvatarUrlForString(this.member.userId);
|
const defaultAvatarUrl = Avatar.defaultAvatarUrlForString(this.member.userId);
|
||||||
const avatarUrl = Avatar.avatarUrlForMember(
|
const avatarUrl = Avatar.avatarUrlForMember(this.member, 16, 16, "crop");
|
||||||
this.member,
|
|
||||||
16 * window.devicePixelRatio,
|
|
||||||
16 * window.devicePixelRatio,
|
|
||||||
"crop");
|
|
||||||
let initialLetter = "";
|
let initialLetter = "";
|
||||||
if (avatarUrl === defaultAvatarUrl) {
|
if (avatarUrl === defaultAvatarUrl) {
|
||||||
initialLetter = Avatar.getInitialLetter(name);
|
initialLetter = Avatar.getInitialLetter(name);
|
||||||
|
|
Loading…
Reference in New Issue