Fix custom color backup import/export

This commit is contained in:
ayumi-signal 2024-12-11 08:57:34 -08:00 committed by GitHub
parent 734929f74f
commit c7dc4279a1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 96 additions and 31 deletions

View file

@ -110,7 +110,7 @@ import {
AdhocCallStatus, AdhocCallStatus,
} from '../../types/CallDisposition'; } from '../../types/CallDisposition';
import { isAciString } from '../../util/isAciString'; import { isAciString } from '../../util/isAciString';
import { hslToRGB } from '../../util/hslToRGB'; import { hslToRGBInt } from '../../util/hslToRGB';
import type { AboutMe, LocalChatStyle } from './types'; import type { AboutMe, LocalChatStyle } from './types';
import { BackupType } from './types'; import { BackupType } from './types';
import { messageHasPaymentEvent } from '../../messages/helpers'; import { messageHasPaymentEvent } from '../../messages/helpers';
@ -2588,10 +2588,10 @@ export class BackupExportStream extends Readable {
const id = Long.fromNumber(result.length + 1); const id = Long.fromNumber(result.length + 1);
this.customColorIdByUuid.set(uuid, id); this.customColorIdByUuid.set(uuid, id);
const start = hslToRGBInt( const start = desktopHslToRgbInt(
color.start.hue, color.start.hue,
color.start.saturation, color.start.saturation,
color.start.luminance color.start.lightness
); );
if (color.end == null) { if (color.end == null) {
@ -2600,10 +2600,10 @@ export class BackupExportStream extends Readable {
solid: start, solid: start,
}); });
} else { } else {
const end = hslToRGBInt( const end = desktopHslToRgbInt(
color.end.hue, color.end.hue,
color.end.saturation, color.end.saturation,
color.end.luminance color.end.lightness
); );
result.push({ result.push({
@ -2776,10 +2776,13 @@ function checkServiceIdEquivalence(
return leftConvo && rightConvo && leftConvo === rightConvo; return leftConvo && rightConvo && leftConvo === rightConvo;
} }
function hslToRGBInt(hue: number, saturation: number, luminance = 1): number { function desktopHslToRgbInt(
const { r, g, b } = hslToRGB(hue, saturation, luminance); hue: number,
// eslint-disable-next-line no-bitwise saturation: number,
return ((0xff << 24) | (r << 16) | (g << 8) | b) >>> 0; lightness = 1
): number {
// Desktop stores saturation not as 0.123 (0 to 1.0) but 12.3 (percentage)
return hslToRGBInt(hue, saturation / 100, lightness);
} }
function toGroupCallStateProto(state: CallStatus): Backups.GroupCall.State { function toGroupCallStateProto(state: CallStatus): Backups.GroupCall.State {

View file

@ -89,7 +89,7 @@ import type { GroupV2ChangeDetailType } from '../../groups';
import { queueAttachmentDownloads } from '../../util/queueAttachmentDownloads'; import { queueAttachmentDownloads } from '../../util/queueAttachmentDownloads';
import { isNotNil } from '../../util/isNotNil'; import { isNotNil } from '../../util/isNotNil';
import { isGroup } from '../../util/whatTypeOfConversation'; import { isGroup } from '../../util/whatTypeOfConversation';
import { rgbToHSL } from '../../util/rgbToHSL'; import { rgbIntToHSL } from '../../util/rgbToHSL';
import { import {
convertBackupMessageAttachmentToAttachment, convertBackupMessageAttachmentToAttachment,
convertFilePointerToAttachment, convertFilePointerToAttachment,
@ -3061,7 +3061,7 @@ export class BackupImportStream extends Writable {
if (color.solid) { if (color.solid) {
value = { value = {
start: rgbIntToHSL(color.solid), start: rgbIntToDesktopHSL(color.solid),
}; };
} else { } else {
strictAssert(color.gradient != null, 'Either solid or gradient'); strictAssert(color.gradient != null, 'Either solid or gradient');
@ -3076,8 +3076,8 @@ export class BackupImportStream extends Writable {
strictAssert(deg != null, 'Missing angle'); strictAssert(deg != null, 'Missing angle');
value = { value = {
start: rgbIntToHSL(start), start: rgbIntToDesktopHSL(start),
end: rgbIntToHSL(end), end: rgbIntToDesktopHSL(end),
deg, deg,
}; };
} }
@ -3226,20 +3226,15 @@ export class BackupImportStream extends Writable {
} }
} }
function rgbIntToHSL(intValue: number): { function rgbIntToDesktopHSL(intValue: number): {
hue: number; hue: number;
saturation: number; saturation: number;
luminance: number; lightness: number;
} { } {
// eslint-disable-next-line no-bitwise const { h: hue, s: saturation, l: lightness } = rgbIntToHSL(intValue);
const r = (intValue >>> 16) & 0xff;
// eslint-disable-next-line no-bitwise
const g = (intValue >>> 8) & 0xff;
// eslint-disable-next-line no-bitwise
const b = intValue & 0xff;
const { h: hue, s: saturation, l: luminance } = rgbToHSL(r, g, b);
return { hue, saturation, luminance }; // Desktop stores saturation not as 0.123 (0 to 1.0) but 12.3 (percentage)
return { hue, saturation: saturation * 100, lightness };
} }
function fromGroupCallStateProto( function fromGroupCallStateProto(

View file

@ -0,0 +1,35 @@
// Copyright 2024 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { assert } from 'chai';
import { hslToRGB, hslToRGBInt } from '../../util/hslToRGB';
describe('hslToRGB', () => {
it('converts pure rgb colors', () => {
assert.deepStrictEqual(hslToRGB(0, 1, 0.5), { r: 255, g: 0, b: 0 });
assert.deepStrictEqual(hslToRGB(120, 1, 0.5), { r: 0, g: 255, b: 0 });
assert.deepStrictEqual(hslToRGB(240, 1, 0.5), { r: 0, g: 0, b: 255 });
});
it('converts random sampled hsl colors', () => {
assert.deepStrictEqual(hslToRGB(50, 0.233333, 0.41), {
r: 129,
g: 121,
b: 80,
});
assert.deepStrictEqual(hslToRGB(170, 0.97, 0.1), {
r: 1,
g: 50,
b: 42,
});
});
});
describe('hslToRGBInt', () => {
it('converts pure rgb colors', () => {
assert.equal(hslToRGBInt(0, 1, 0.5), 4294901760);
assert.equal(hslToRGBInt(120, 1, 0.5), 4278255360);
assert.equal(hslToRGBInt(240, 1, 0.5), 4278190335);
});
});

View file

@ -3,7 +3,7 @@
import { assert } from 'chai'; import { assert } from 'chai';
import { rgbToHSL } from '../../util/rgbToHSL'; import { rgbIntToHSL, rgbToHSL } from '../../util/rgbToHSL';
describe('rgbToHSL', () => { describe('rgbToHSL', () => {
it('converts pure rgb colors', () => { it('converts pure rgb colors', () => {
@ -40,3 +40,11 @@ describe('rgbToHSL', () => {
}); });
}); });
}); });
describe('rgbIntToHSL', () => {
it('converts pure rgb colors', () => {
assert.deepStrictEqual(rgbIntToHSL(4294901760), { h: 0, s: 1, l: 0.5 });
assert.deepStrictEqual(rgbIntToHSL(4278255360), { h: 120, s: 1, l: 0.5 });
assert.deepStrictEqual(rgbIntToHSL(4278190335), { h: 240, s: 1, l: 0.5 });
});
});

View file

@ -159,8 +159,8 @@ export const ContactNameColors = [
export type ContactNameColorType = (typeof ContactNameColors)[number]; export type ContactNameColorType = (typeof ContactNameColors)[number];
export type CustomColorType = { export type CustomColorType = {
start: { hue: number; saturation: number; luminance?: number }; start: { hue: number; saturation: number; lightness?: number };
end?: { hue: number; saturation: number; luminance?: number }; end?: { hue: number; saturation: number; lightness?: number };
deg?: number; deg?: number;
}; };

View file

@ -46,17 +46,17 @@ export function getHSL(
{ {
hue, hue,
saturation, saturation,
luminance, lightness,
}: { }: {
hue: number; hue: number;
saturation: number; saturation: number;
luminance?: number; lightness?: number;
}, },
adjustedLightness = 0 adjustedLightness = 0
): string { ): string {
return `hsl(${hue}, ${saturation}%, ${ return `hsl(${hue}, ${saturation}%, ${
luminance == null lightness == null
? adjustLightnessValue(calculateLightness(hue), adjustedLightness) ? adjustLightnessValue(calculateLightness(hue), adjustedLightness)
: luminance * 100 : lightness * 100
}%)`; }%)`;
} }

View file

@ -24,3 +24,13 @@ export function hslToRGB(
b: Math.round(255 * f(4)), b: Math.round(255 * f(4)),
}; };
} }
export function hslToRGBInt(
hue: number,
saturation: number,
lightness: number
): number {
const { r, g, b } = hslToRGB(hue, saturation, lightness);
// eslint-disable-next-line no-bitwise
return ((0xff << 24) | (r << 16) | (g << 8) | b) >>> 0;
}

View file

@ -26,7 +26,7 @@ export function rgbToHSL(
if (c === 0) { if (c === 0) {
h = 0; h = 0;
} else if (v === rn) { } else if (v === rn) {
h = 60 * (((gn - bn) / c) % 6); h = 60 * (((gn - bn) / c + 6) % 6);
} else if (v === gn) { } else if (v === gn) {
h = 60 * ((bn - rn) / c + 2); h = 60 * ((bn - rn) / c + 2);
} else { } else {
@ -43,3 +43,17 @@ export function rgbToHSL(
return { h, s, l }; return { h, s, l };
} }
export function rgbIntToHSL(intValue: number): {
h: number;
s: number;
l: number;
} {
// eslint-disable-next-line no-bitwise
const r = (intValue >>> 16) & 0xff;
// eslint-disable-next-line no-bitwise
const g = (intValue >>> 8) & 0xff;
// eslint-disable-next-line no-bitwise
const b = intValue & 0xff;
return rgbToHSL(r, g, b);
}