Fix avatar upload failing on JPEG/WebP/GIF without a profile color.
embedMetadataInImage returned null for non-PNG when there was nothing to embed, which blocked plain avatar saves after format/library churn.
This commit is contained in:
@@ -12,6 +12,8 @@ import {
|
||||
getMimeType,
|
||||
getExtension,
|
||||
ImageMetadata,
|
||||
convertImageDataToPng,
|
||||
uint8ArrayToBlob,
|
||||
} from '../utils/imageMetadata';
|
||||
|
||||
/**
|
||||
@@ -137,27 +139,39 @@ export function useUserBanner(): [
|
||||
throw new Error('Failed to fetch current avatar');
|
||||
}
|
||||
|
||||
// Detect image format
|
||||
const format = detectImageFormat(avatarData);
|
||||
|
||||
// Detect image format — banner lives in PNG tEXt, so convert other formats first
|
||||
let workingData: ArrayBuffer | Uint8Array = avatarData;
|
||||
let format = detectImageFormat(workingData);
|
||||
|
||||
if (format === 'unknown') {
|
||||
throw new Error('Unsupported avatar image format');
|
||||
}
|
||||
|
||||
if (format !== 'png') {
|
||||
console.log('[updateBanner] Converting', format, 'avatar to PNG for banner metadata');
|
||||
const pngData = await convertImageDataToPng(workingData);
|
||||
if (!pngData) {
|
||||
throw new Error('Failed to convert avatar to PNG for banner metadata');
|
||||
}
|
||||
workingData = pngData;
|
||||
format = 'png';
|
||||
}
|
||||
|
||||
// Get existing metadata to preserve
|
||||
const existingMetadata = extractMetadataFromImage(avatarData);
|
||||
const existingMetadata = extractMetadataFromImage(workingData);
|
||||
console.log('[updateBanner] Existing metadata:', existingMetadata);
|
||||
|
||||
// Modify image metadata with new banner, preserving color
|
||||
|
||||
// Modify image metadata with new banner, preserving color.
|
||||
// Empty string clears banner (PNG embed drops falsy fields after stripping old chunks).
|
||||
const newMetadata: ImageMetadata = {
|
||||
color: existingMetadata.color,
|
||||
banner: newBanner,
|
||||
banner: newBanner ?? '',
|
||||
avatarBorderColor: existingMetadata.avatarBorderColor,
|
||||
gradient: existingMetadata.gradient,
|
||||
};
|
||||
console.log('[updateBanner] New metadata to embed:', newMetadata);
|
||||
|
||||
const newAvatarData = embedMetadataInImage(avatarData, newMetadata);
|
||||
|
||||
const newAvatarData = embedMetadataInImage(workingData, newMetadata);
|
||||
|
||||
if (!newAvatarData) {
|
||||
throw new Error('Failed to embed banner in avatar metadata');
|
||||
@@ -166,8 +180,8 @@ export function useUserBanner(): [
|
||||
// Verify the banner was embedded correctly before uploading
|
||||
const verifyMetadata = extractMetadataFromImage(newAvatarData);
|
||||
console.log('[updateBanner] Verification - extracted metadata from new avatar:', verifyMetadata);
|
||||
|
||||
if (newBanner && verifyMetadata.banner !== newBanner) {
|
||||
|
||||
if ((newBanner || undefined) !== verifyMetadata.banner) {
|
||||
console.error('[updateBanner] Banner verification FAILED!', 'Expected:', newBanner, 'Got:', verifyMetadata.banner);
|
||||
throw new Error('Banner verification failed');
|
||||
}
|
||||
@@ -176,8 +190,8 @@ export function useUserBanner(): [
|
||||
// Upload modified avatar with correct MIME type
|
||||
const mimeType = getMimeType(format);
|
||||
const extension = getExtension(format);
|
||||
const blob = new Blob([newAvatarData], { type: mimeType });
|
||||
|
||||
const blob = uint8ArrayToBlob(newAvatarData, mimeType);
|
||||
|
||||
const uploadResponse = await mx.uploadContent(blob, {
|
||||
name: `avatar.${extension}`,
|
||||
type: mimeType,
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
detectImageFormat,
|
||||
getMimeType,
|
||||
getExtension,
|
||||
uint8ArrayToBlob,
|
||||
} from '../utils/imageMetadata';
|
||||
|
||||
/**
|
||||
@@ -176,7 +177,7 @@ export function useUserColor(): [
|
||||
// Upload modified avatar with correct MIME type
|
||||
const mimeType = getMimeType(format);
|
||||
const extension = getExtension(format);
|
||||
const blob = new Blob([newAvatarData], { type: mimeType });
|
||||
const blob = uint8ArrayToBlob(newAvatarData, mimeType);
|
||||
const uploadResponse = await mx.uploadContent(blob, {
|
||||
name: `avatar.${extension}`,
|
||||
type: mimeType,
|
||||
|
||||
@@ -11,6 +11,8 @@ import { mxcUrlToHttp } from '../utils/matrix';import { getCurrentAccessToken }
|
||||
getExtension,
|
||||
ImageMetadata,
|
||||
ProfileGradient,
|
||||
convertImageDataToPng,
|
||||
uint8ArrayToBlob,
|
||||
} from '../utils/imageMetadata';
|
||||
|
||||
/**
|
||||
@@ -142,14 +144,24 @@ export function useUserProfileStyle(): [
|
||||
throw new Error('Failed to fetch current avatar');
|
||||
}
|
||||
|
||||
// Detect image format
|
||||
const format = detectImageFormat(avatarData);
|
||||
// Border/gradient live in PNG tEXt — convert other formats first
|
||||
let workingData: ArrayBuffer | Uint8Array = avatarData;
|
||||
let format = detectImageFormat(workingData);
|
||||
if (format === 'unknown') {
|
||||
throw new Error('Unsupported avatar image format');
|
||||
}
|
||||
|
||||
if (format !== 'png') {
|
||||
const pngData = await convertImageDataToPng(workingData);
|
||||
if (!pngData) {
|
||||
throw new Error('Failed to convert avatar to PNG for style metadata');
|
||||
}
|
||||
workingData = pngData;
|
||||
format = 'png';
|
||||
}
|
||||
|
||||
// Get existing metadata to preserve
|
||||
const existingMetadata = extractMetadataFromImage(avatarData);
|
||||
const existingMetadata = extractMetadataFromImage(workingData);
|
||||
|
||||
// Merge with new style
|
||||
const newMetadata: ImageMetadata = {
|
||||
@@ -159,7 +171,7 @@ export function useUserProfileStyle(): [
|
||||
};
|
||||
|
||||
// Embed updated metadata
|
||||
const newAvatarData = embedMetadataInImage(avatarData, newMetadata);
|
||||
const newAvatarData = embedMetadataInImage(workingData, newMetadata);
|
||||
if (!newAvatarData) {
|
||||
throw new Error('Failed to embed style in avatar metadata');
|
||||
}
|
||||
@@ -167,7 +179,7 @@ export function useUserProfileStyle(): [
|
||||
// Upload modified avatar with correct MIME type
|
||||
const mimeType = getMimeType(format);
|
||||
const extension = getExtension(format);
|
||||
const blob = new Blob([newAvatarData], { type: mimeType });
|
||||
const blob = uint8ArrayToBlob(newAvatarData, mimeType);
|
||||
|
||||
const uploadResponse = await mx.uploadContent(blob, {
|
||||
name: `avatar.${extension}`,
|
||||
|
||||
Reference in New Issue
Block a user