HotPDF dekoduoja pasuktus QR simbolius įkeltame PDF puslapyje normalizuodamas paimtąjį modulių matricą per visas aštuonias D4 orientacijas pačiame dekoduotojo viduje. Išorinis rotacijos pakartotinis bandymas, kuris veikia linijinėms simbolikoms, QR atveju neveikia, ir šios priežasties supratimas sutaupo jums dieną, gaištant prie dekoduotojo, kuris atrodo sugedęs, bet nėra
Scenarijus pakankamai kasdieniai. Nuskaityti pristatymo dokumentai ateina kaip PDF, kiekvienas puslapis neša QR etiketę, o skaitytuvo operatorius į dėklą sukrovė lapų krūvą ta kryptimi, kuria jis priėmė. Kai kurios etiketės stačios, kitos pasislinkusios ketvirčiu apsukimo, keletas – aukštyn kojomis. Kviečiate barkodų dekoduotoją, pusė puslapių išsprendžiama, o kita pusė grįžta tuščia be jokios klaidos
Kodėl nuskaitymo kaukės sukimas niekada nepataiso pasukto QR?
Nes QR randamųjų ženklų išdėstymas sąmoningai asimetriškas, ir viso vaizdo sukimas tą asimetriją išsaugo, o ne pašalina. QR Code padeda tris randamuosius kvadratus viršutiniame kairiajame, viršutiniame dešiniajame ir apatiniame kairiajame kampe, o apatinį dešinįjį kampą palieka tuščią (ISO/IEC 18004:2015 §6.3.3). Tas dingęs kampas yra orientacijos užuomina. Pasukite puslapio bitmap devyniasdešimčia laipsnių, ir tuščia vieta tiesiog perkelia į kitą kampą. Nėra netrivios plokštumos sukimo, kuris trijų kampų išdėstymą sugrąžintų į save patį, tad dekoduotojas, priimantis tik kanoninį išdėstymą, atmes kiekvieną bandymą po vieną
Tai svarbu todėl, kad akivaizdus pataisymas yra neteisingas. Natūralus instinktas – pakartojimą pakabinti išorėje: atvaizduokite puslapį, paduokite kaukę dekoduotojui, o jei nepavyksta, pasukite kaukę ir bandykite dar kartą ties 90, 180 ir 270 laipsnių. Code 39 atveju ta politika yra tiksliai teisinga, nes linijinė simbolika turi starto ir stopo ženklus, kuriuos skaitytuvas randa, kai tik juostos bėga horizontaliai. QR atveju tai keturios garantuotos nesėkmės, po kurių seka pranešimas nieko nerasta
D4 grupė, pritaikyta modulių matricai
Teisinga normalizavimo vieta yra po paėmimo, ant boolean modulių gardės, o ne ant pikselių kaukės. Kai dekoduotojas išsprendžia simbolį į n į n matricą iš tamsių ir šviesių modulių, jis gali išvardyti kvadrato dihedrinę grupę: keturi sukimai kart du atspindžiai, iš viso aštuonios kandidatės orientacijos. Kiekvienai kandidatei jis tikrina randamųjų trikampį, ir pirmoji kandidatė, kurios trys randamieji pakliūva į viršutinį kairįjį, viršutinį dešinįjį ir apatinį kairįjį pozicijas, yra tikroji orientacija. Nuo ten esantis konvejeris bėga nepakitęs, nes formato informacijos bitai, zigzag duomenų išdėstymas ir Reed-Solomon korekcija visi mano gaunantys kanoninę matricą, ir dabar ją gauna
Dvi savybės daro tai pigu. Matrica maža, lyginant su atvaizduotu bitmap, tad aštuoni sukeitimai kainuoja gerokai mažiau nei aštuoni puslapių atvaizdavimai. Ir matrica yra švarus boolean masyvas, sukurtas paėmėjo, tad joks pakelio transformas negali įnešti reikšmių, kurios niekada nebuvo paimtos
Versijos aptikimas yra dalumo paieška, o ne dalyba
Modulių skaičiaus negalima išvesti padalinus paimtąjį plotį iš numanomo modulio dydžio, ir suklydimas čia yra subtilus dekodo nesėkmių šaltinis didelės raiškos atvaizdavimuose. QR simbolis versijos v yra 4v + 17 modulių per, tad versija 1 yra 21 modulis, o versija 40 – 177. Kaukė, matuojanti 126 pikselių plotį, vienodai dera su versija 1 po šešis pikselius moduliui ir su keliomis aukštesnėmis versijomis mažesniais modulio dydžiais. Tiesioginė dalyba pasirenka vieną iš jų ir paprastai klysta
Kas veikia, yra dalumo paieška per kandidačių versijas. Eikite nuo versijos 40 žemyn iki versijos 1, palikite kandidates, kurių modulių skaičius dalija paimtąjį plotį be liekanos ir palieka bent tris pikselius moduliui, ir imkite mažiausią išgyvenusią versiją. Trijų pikselių apatinė riba yra tai, kas sustabdo paiešką nuo absurdiškai tankaus šiurkštaus simbolio skaitymo priėmimo, o mažiausios versijos taisyklė išsprendžia likusį dviprasmiškumą skaitymo naudai, kurį tikrai pagamintų skaitytuvas
var
Pdf: THotPDF;
Options: THPDFBarcodeDecodeOptions;
Codes: THPDFDecodedBarcodes;
Info: THPDFBarcodeDecodeInfo;
I: Integer;
begin
Pdf := THotPDF.Create(nil);
try
Pdf.LoadFromFile('delivery-notes.pdf');
Options := THPDFBarcodeDecodeOptions.Default;
Options.DPI := 300;
Options.RotationPolicy := bdrpFallback;
Options.MinimumConfidence := 0.5;
Options.MaxResults := 16;
if Pdf.DecodeLoadedPageBarcodes(0, Options, Codes, Info) then
for I := 0 to High(Codes) do
if Codes[I].Symbology = bsyQRCode then
Writeln(Codes[I].Text, ' at ',
Format('%.0f', [Codes[I].OrientationDegrees]), ' degrees');
finally
Pdf.Free;
end;
end;
THPDFBarcodeDecodeOptions.Default grąžina užpildytą įrašą, o ne nulintą, kas svarbu, nes DPI lygus nuliui ar rezultatų riba lygi nuliui yra patikimai atrodantis būdas negauti nieko. RotationPolicy valdo tik išorinį pakartojimą: bdrpNone atvaizduoja kartą, bdrpFallback pakartoja kitas orientacijas po nesėkmingo pirmojo perėjimo, o bdrpAll atvaizduoja kiekvieną orientaciją besąlygiškai. Kadangi QR normalizacija vyksta dekoduotojo viduje, QR puslapiai išsprendžiami pirmu bandymu su bet kuria iš trijų politikų. Politika yra ten linijinėms simbolikoms, kurioms ji tikrai reikalinga
Kaip įrodyti, kad bitmap transformas neišgalvoja pikselių?
Suskaiciuokite dažus abiejose pusėse ir reikalaukite, kad sumos sutaptų. Sukimas yra pikselių perstatymas, nieko daugiau, tad nenulinių langelių skaičius išvestyje turi lygėti skaičiui įvestyje. Kai kaukės sukimas išoriniame pakartojimo kelyje pranešė 4800 nustatytų langelių įeinant ir 7439 išeinant, tas vienas palyginimas užteko nuteisti transformą neskaičius nė vienos jo geometrijos eilutės
Priežastis buvo kasdienė ir verta pasiimti kaip taisyklę. Dinaminis masyvas, išmatuotas su SetLength, negarantuojamas atkeliaująs nulintas, kai jis yra funkcijos rezultatas, keliaujantis keliu, kurio runtime neišvalo, ir langeliai, kurių sukimas niekada nerašo, tada neša tuos baitus, kurie ten buvo anksčiau. Kai kurie tie pasenę baitai yra nenuliniai, o nenulinis reiškia dažus. Pataisymas yra viena eilutė, FillChar(Result[0], N, 0) prieš perstatymo ciklą, ir drausmė, kurią tai implikuoja, platesnė: bet kuri funkcija, grąžinanti kaukės ar bitmap buferį, turėtų aiškiai išvalyti savo išvestį, o ne remtis alokacijos semantika
Kas padarė, kad defektas išgyveno tris leidimus, yra įdomiau už patį defektą. Kai QR perkėlė savo orientacijos apdorojimą į dekoduotoją, QR visai nustojo liesti išorinį kaukės sukimą, ir vienintelis likęs to kodo kelio naudotojas buvo Code 39. Bendra infrastruktūra tokias klaidas slepia nuolat: vienos funkcijos aprėptis padaro kelią atrodantį patirtą, kol funkcija, nuo jo tikrai priklausanti, neturi savosios. Kiekvienas kelias, kurio nauja funkcija nebenaudoja, reikalauja testo, kuris vis dar jį naudoja
Rezultatų skaitymas atgal puslapio koordinatėse
Kiekviena geometrinė reikšmė, kurią pagamina dekoduotojas, išreikšta bandymo bitmap koordinačių rėme, o kvietėjas jos reikia PDF naudotojo erdvėje. Ta konversija bėga dviem etapais: atšaukite ketvirčio apsukimą, kurį pritaikė pakartojimas, tada atšaukite atvaizdavimo transformą, mapavusį naudotojo erdvę į bitmap. Kas atkeliauja į THPDFDecodedBarcode, yra ašių kryptimi sulygiuotas aptvėrikas (bounding box) naudotojo erdvėje, su Left, Bottom, Right ir Top, laikantis PDF konvencijos, kad Y auga aukštyn, plius prieš laikrodžio rodyklę einantis OrientationDegrees
Suklydę dėl antrosios konversijos krypties gausite bjaurų simptomą: tekstas dekoduojasi tobulai, bet dėžė, kurią piešiate peržiūros sluoksniui, nusileidžia ant teisingos pozicijos veidrodinio atvaizdo. Kas bet stato peržiūros sąsają ant dekoduotojo, tas turėtų tikrintis prieš žinomą fikstūrą, su simboliu, sąmoningai padėtu prie vieno puslapio kampo, kad apversta Y ašis būtų matoma vienu žvilgsniu. Ta pati logika galioja bet kuriai koordinatei, kertančiai atvaizdavimo ribą, todėl verta suprasti PDF puslapio atvaizdavimą į bitmap Delphi, kol statote ant dekoduotojo
Ką įtaisytasis dekoduotojas daro ir ko nedaro
Įtaisytasis dekoduotojas yra apibrėžta, be priklausomybių realizacija, ir ji sąžininga dėl savo ribų, o ne tyliai degraduoja. Ji atpažįsta Code 39 ir QR, patvirtina BCH apsaugotus formato bitus ir kaukės ženklą prieš skelbdama bet kokius duomenis, ir nesistengia atkurti pažeistų simbolių. Jei jūsų įvestis yra išlenktos etiketės fotografija esant nelygiam apšvietimui, tai kita problemų klasė ir nori specializuoto variklio
// Įdėkite savąjį variklį: realizuokite IHPDFBarcodeDecoder ir paduokite
// jį dekoduotoją atpažįstančiai perkrajai. HotPDF vis dar valdo puslapių
// atvaizdavimą, biudžetus, koordinačių mapavimą ir dublių šalinimą
if not Pdf.DecodeLoadedPageBarcodes(PageIndex, MyDecoder, Options,
Codes, Info) then
case Info.Status of
bdsBudgetExceeded:
Log('raise MaxPixels or lower DPI: ' + string(Info.Diagnostic));
bdsRenderError:
Log('page did not render: ' + string(Info.Diagnostic));
bdsDecoderError:
Log(string(Info.DecoderName) + ' failed: ' + string(Info.Diagnostic));
end;
THPDFBarcodeDecodeInfo yra vieta, kur gamybinis konvejeris uždirba savo duoną. RotationAttemptCount ir DecoderCallCount pasako, ar išorinis pakartojimas apskritai bėgo, ReceivedResultCount prieš AcceptedResultCount atskiria dekoduotoją, neradusį nieko, nuo pasitikėjimo slenkscio, atmetusio viską, ką rado, o RenderedPixels su PeakWorkingBytes yra tai, ką grafinat, kai partijos darbas pradeda draskytis. Tuščias rezultatų rinkinys plius bdsSucceeded reiškia, kad puslapis tikrai neturi skaitomo simbolio, kas yra kitas operacinis faktas nei bdsBudgetExceeded
Biudžeto laukai nusipelno sąmoningo sprendimo, o ne numatytosios reikšmės. MaxPixels ir MaxWorkingBytes egzistuoja todėl, kad DPI dauginasi kvadratu: perkėlimas nuo 300 iki 600 DPI ant A4 puslapio keturiskart padidina ir atvaizdavimo kainą, ir pikinę alokaciją, o nepatikima įvestis, deklaruojanti milžinišką puslapio dėžę, gali paverti nuskaitymo darbą į atminties trūkumo incidentą. Nustatykite ribas pagal tai, ko reikia jūsų blogiausiam teisėtam dokumentui, tada leiskite bdsBudgetExceeded nukreipti išimtis į lėtesnį, izoliuotą kelią
Jei jūsų dokumentai maišo mašininio skaitomumo etiketes su spausdintu tekstu, kurį ketinate indeksuoti, barkodų dekoduotojas natūraliai poruojasi su atpažinimo varikliu, aprašytu straipsnyje šablonų atitikties OCR HotPDF viduje, o tos pačios istorijos generavimo pusė yra straipsnyje barkodų braižymas į PDF su HotPDF. Abu bėga ta pačia atvaizdavimo ir biudžeto infrastruktūra, tad konvejeris, kuris jau nustatė protingas ribas vienam, kitą gauna beveik už dyką
Sukimosi tolerancija yra viena tų funkcijų, kurios nematomos, kai veikia, ir įnervingos, kai neveikia, o inžinerinė pamoka apibendrinama toliau už QR: normalizuokite taip arti semantinės reprezentacijos, kad tik pasieksite, ne pikselių sluoksnyje, kuriame duomenys vis dar neša kiekvieną atsitiktinumą, kaip jie buvo paimti. HotPDF tiekia tai kaip HotPDF Delphi PDF komponento dalį, kartu su atvaizdavimo, OCR ir puslapių analizės gabalais, kurių tos pačios priėmimo konvejeriai paprastai reikia