Improve auto background color
Colors need to be normalized per border so that the multiplier is applied to the sum of the normalized colors. Normalize the returned color with adjusted thresholds compared to the normalization for the color extraction. During the extraction the normalization shouldn't be too aggressive to prevent messing up the detection for the color with the highest proportion. Once we have detected the color, we want to be more aggressive about normalizing white and black colors to ensure the background color matches true white and black instead of being slightly off
This commit is contained in:
@@ -25,6 +25,7 @@ import {
|
|||||||
isContinuousReadingMode,
|
isContinuousReadingMode,
|
||||||
isContinuousVerticalReadingMode,
|
isContinuousVerticalReadingMode,
|
||||||
} from '@/features/reader/settings/ReaderSettings.utils.tsx';
|
} from '@/features/reader/settings/ReaderSettings.utils.tsx';
|
||||||
|
import { Colors } from '@/lib/Colors.ts';
|
||||||
|
|
||||||
export const getInitialReaderPageIndex = (
|
export const getInitialReaderPageIndex = (
|
||||||
resumeMode: ReaderResumeMode,
|
resumeMode: ReaderResumeMode,
|
||||||
@@ -157,52 +158,69 @@ const getPageBackgroundColor = (
|
|||||||
return [top, right, bottom, left];
|
return [top, right, bottom, left];
|
||||||
})();
|
})();
|
||||||
|
|
||||||
const blackThreshold = 10;
|
// oxlint-disable-next-line unicorn/consistent-function-scoping
|
||||||
const whiteThreshold = 246;
|
const considerBlack = (hex: string | undefined | null, threshold: number): boolean => {
|
||||||
|
if (!hex) {
|
||||||
const considerBlack = (color: ColorThief.Color | null): boolean => {
|
|
||||||
if (!color) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { r, g, b } = color.rgb();
|
const { r, g, b } = Colors.hexToRgb(hex);
|
||||||
return r <= blackThreshold && g <= blackThreshold && b <= blackThreshold;
|
return r <= threshold && g <= threshold && b <= threshold;
|
||||||
};
|
};
|
||||||
|
|
||||||
const considerWhite = (color: ColorThief.Color | null): boolean => {
|
// oxlint-disable-next-line unicorn/consistent-function-scoping
|
||||||
if (!color) {
|
const considerWhite = (hex: string | undefined | null, threshold: number): boolean => {
|
||||||
|
if (!hex) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { r, g, b } = color.rgb();
|
const { r, g, b } = Colors.hexToRgb(hex);
|
||||||
return r >= whiteThreshold && g >= whiteThreshold && b >= whiteThreshold;
|
return r >= threshold && g >= threshold && b >= threshold;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getHexValue = (color: ColorThief.Color | null) => {
|
const getNormalizedColor = (hex: string | undefined | null, threshold: { white: number; black: number }) => {
|
||||||
if (considerBlack(color)) {
|
if (!hex || considerWhite(hex, threshold.white)) {
|
||||||
return '#000000';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (considerWhite(color)) {
|
|
||||||
return '#ffffff';
|
return '#ffffff';
|
||||||
}
|
}
|
||||||
|
|
||||||
return color!.hex();
|
if (considerBlack(hex, threshold.black)) {
|
||||||
|
return '#000000';
|
||||||
|
}
|
||||||
|
|
||||||
|
return hex;
|
||||||
};
|
};
|
||||||
const colorsByHexValue = groupBy((color) => getHexValue(color), borderColorPalettes.flat().filter(Boolean));
|
|
||||||
const proportionByHexValue = mapValues(
|
const determinationThresholds = { white: 235, black: 10 };
|
||||||
(colors) =>
|
|
||||||
sumBy((color) => {
|
const normalizedBorderColorPalettes = borderColorPalettes.map((borderPalette) => {
|
||||||
const fillsWholeBorder = color!.proportion >= 0.97;
|
const borderPaletteColorsByHexValue = groupBy(
|
||||||
|
(color) => getNormalizedColor(color?.hex(), determinationThresholds),
|
||||||
|
borderPalette?.filter(Boolean),
|
||||||
|
);
|
||||||
|
|
||||||
|
return Object.values(
|
||||||
|
mapValues((colors) => {
|
||||||
|
const proportionSum = sumBy((color) => color!.proportion, colors);
|
||||||
|
const populationSum = sumBy((color) => color!.population, colors);
|
||||||
|
|
||||||
|
const fillsWholeBorder = proportionSum >= 0.97;
|
||||||
const multiplier = fillsWholeBorder ? borderColorPalettes.length : 1;
|
const multiplier = fillsWholeBorder ? borderColorPalettes.length : 1;
|
||||||
|
|
||||||
return color!.proportion * multiplier;
|
const [color] = colors;
|
||||||
}, colors),
|
const { r, g, b } = color.rgb();
|
||||||
colorsByHexValue,
|
|
||||||
);
|
|
||||||
const [hexValue] = maxBy(([_hex, proportion]) => proportion, Object.entries(proportionByHexValue))!;
|
|
||||||
|
|
||||||
return hexValue;
|
return ColorThief.createColor(r, g, b, populationSum, proportionSum * multiplier, color.gamut);
|
||||||
|
}, borderPaletteColorsByHexValue),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
const colorsByHexValue = groupBy(
|
||||||
|
(color) => getNormalizedColor(color?.hex(), determinationThresholds),
|
||||||
|
normalizedBorderColorPalettes.flat().filter(Boolean),
|
||||||
|
);
|
||||||
|
const proportionByHexValue = mapValues((colors) => sumBy((color) => color!.proportion, colors), colorsByHexValue);
|
||||||
|
const [hex] = maxBy(([_hex, proportion]) => proportion, Object.entries(proportionByHexValue))!;
|
||||||
|
|
||||||
|
return getNormalizedColor(hex, { white: 235, black: 30 });
|
||||||
};
|
};
|
||||||
|
|
||||||
const updatePageBackgroundColor = async (
|
const updatePageBackgroundColor = async (
|
||||||
|
|||||||
Reference in New Issue
Block a user