fix(totp): scan QR ecran - indices Byte dans ZXing (boucle infinie a 100 % CPU)

ZXing.Delphi declarait rgbIndex/luminanceIndex en Byte dans les conversions
octets bruts -> luminance : au-dela de 255 ils repassaient a 0, la boucle ne
finissait jamais. L'APK n'y passait pas (CreateFromBitmap). Mesure apres
correctif : 60 ms sur un ecran 1920x1080 avec TRY_HARDER, 86 ms sans QR.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
r-zakarya
2026-09-18 22:35:49 +01:00
parent 72f9acd733
commit e3904236a7
2 changed files with 25 additions and 15 deletions
@@ -364,7 +364,7 @@ procedure TRGBLuminanceSource.CalculateLuminanceRGB24(
const rgbRawBytes: TArray<Byte>);
var
rgbIndex,
luminanceIndex,
luminanceIndex : Integer; // pmserver: etaient Byte -> boucle infinie au-dela de 255 octets
r, g, b : Integer;
begin
rgbIndex := 0;
@@ -389,7 +389,7 @@ procedure TRGBLuminanceSource.CalculateLuminanceBGR24(
const rgbRawBytes: TArray<Byte>);
var
rgbIndex,
luminanceIndex,
luminanceIndex : Integer; // pmserver: etaient Byte -> boucle infinie au-dela de 255 octets
b, g, r : Byte;
begin
rgbIndex := 0;
@@ -414,7 +414,7 @@ procedure TRGBLuminanceSource.CalculateLuminanceRGB32(
const rgbRawBytes: TArray<Byte>);
var
rgbIndex,
luminanceIndex,
luminanceIndex : Integer; // pmserver: etaient Byte -> boucle infinie au-dela de 255 octets
r, g, b : Byte;
begin
rgbIndex := 0;
@@ -439,7 +439,7 @@ procedure TRGBLuminanceSource.CalculateLuminanceBGR32(
const rgbRawBytes: TArray<Byte>);
var
rgbIndex,
luminanceIndex,
luminanceIndex : Integer; // pmserver: etaient Byte -> boucle infinie au-dela de 255 octets
b, g, r : Byte;
begin
rgbIndex := 0;
@@ -464,7 +464,7 @@ procedure TRGBLuminanceSource.CalculateLuminanceBGRA32(
const rgbRawBytes: TArray<Byte>);
var
rgbIndex,
luminanceIndex,
luminanceIndex : Integer; // pmserver: etaient Byte -> boucle infinie au-dela de 255 octets
b, g, r,
alpha : Byte;
luminance : Byte;
@@ -495,7 +495,7 @@ procedure TRGBLuminanceSource.CalculateLuminanceRGBA32(
const rgbRawBytes: TArray<Byte>);
var
rgbIndex,
luminanceIndex,
luminanceIndex : Integer; // pmserver: etaient Byte -> boucle infinie au-dela de 255 octets
r, g, b,
alpha : Byte;
luminance : Byte;
@@ -526,7 +526,7 @@ procedure TRGBLuminanceSource.CalculateLuminanceARGB32(
const rgbRawBytes: TArray<Byte>);
var
rgbIndex,
luminanceIndex,
luminanceIndex : Integer; // pmserver: etaient Byte -> boucle infinie au-dela de 255 octets
r, g, b,
alpha : Byte;
luminance : Byte;
+18 -8
View File
@@ -13,6 +13,10 @@ interface
/// Texte du premier QR trouve a l'ecran, '' si aucun.
function ScanScreenForQr: string;
// Exposees pour le banc d'essai (mesure du temps de decodage).
function CaptureVirtualScreen(out AWidth, AHeight: Integer): TArray<Byte>;
function DecodeQrPixels(const APixels: TArray<Byte>; AW, AH: Integer;
ATryHarder: Boolean): string;
implementation
@@ -65,10 +69,9 @@ begin
end;
end;
function ScanScreenForQr: string;
function DecodeQrPixels(const APixels: TArray<Byte>; AW, AH: Integer;
ATryHarder: Boolean): string;
var
LPixels: TArray<Byte>;
LW, LH: Integer;
LSource: TLuminanceSource;
LBinarizer: THybridBinarizer;
LImage: TBinaryBitmap;
@@ -78,19 +81,16 @@ var
LRes: TReadResult;
begin
Result := '';
LPixels := CaptureVirtualScreen(LW, LH);
if LPixels = nil then Exit;
LFormats := TList<TBarcodeFormat>.Create;
LFormats.Add(TBarcodeFormat.QR_CODE);
LHints := TDictionary<TDecodeHintType, TObject>.Create;
LHints.Add(TDecodeHintType.POSSIBLE_FORMATS, LFormats);
LHints.Add(TDecodeHintType.TRY_HARDER, nil);
if ATryHarder then LHints.Add(TDecodeHintType.TRY_HARDER, nil);
LReader := TMultiFormatReader.Create;
LReader.Hints := LHints;
// BGR32 et non BGRA32 : le 4e octet d'une capture GDI vaut 0, et la
// conversion BGRA le lirait comme une transparence totale - image blanche.
LSource := TRGBLuminanceSource.Create(LPixels, LW, LH, TBitmapFormat.BGR32);
LSource := TRGBLuminanceSource.Create(APixels, AW, AH, TBitmapFormat.BGR32);
LBinarizer := THybridBinarizer.Create(LSource);
LImage := TBinaryBitmap.Create(LBinarizer);
LRes := nil;
@@ -112,4 +112,14 @@ begin
end;
end;
function ScanScreenForQr: string;
var
LPixels: TArray<Byte>;
LW, LH: Integer;
begin
Result := '';
LPixels := CaptureVirtualScreen(LW, LH);
if LPixels <> nil then Result := DecodeQrPixels(LPixels, LW, LH, True);
end;
end.