HotXLS preslikava proizvoljne RGB i tematske boje na BIFF8 paletu od 56 slotova u dva sloja: NearestIndexedColor pronalazi perceptualno najbliži postojeći unos palete u OKLab prostoru, a BuildBiffPalettePlan sa ApplyBiffPalettePlan prepisuje slobodne slotove palete da workbook sa pravim bojama preživi čuvanje u klasični XLS. Okidač je uvek isti support tiket. Neko napravi izveštaj u XLSX-u sa korporativnim tamnoplavim zaglavljima i blagim tirkiznim akcentom, sačuva ga kao .xls za legacy potrošača, i zagavlja se vrate čisto crna dok tirkizna postane preglasna tirkizna. Ništa se nije srušilo i nijedno upozorenje se nije aktiviralo. Model boja starog formata jednostavno ne može da ponese ono što je novi opisao, i biblioteka je morala da izabere nešto
Zašto XLS fajl može da drži samo 56 boja?
Jer BIFF8 format ćelije nikada ne čuva RGB vrednost: fontovi, ispune i ivice nose indeks boje, a Palette record na nivou celog workbook-a ($0092, [MS-XLS] §2.4.188) snabdeva tačno 56 neprozirnih RGB unosa za indekse 8 do 63. Indeksi 0 do 7 su fiksne kopije osam osnovnih boja, a vrednosti iznad 63 uopšte nisu boje nego tokeni poput system foreground, system background i chart text. HotXLS izlaže paletu kroz javni ColorIndex od 1 do 56, što je fizički indeks umanjen za 7, a ResolveIndexedColor drži tri šeme numeracije odvojene kroz TXLSIndexedColorSpace: xicsPublicColorIndex za API vrednosti 1..56, xicsBiffIcv za sirove indekse sa diska, koje proverava prema podskupu IcvFont, IcvXF ili IcvChart za ulogu koju prosledite, i xicsOoxmlIndexed, gde 64 i 65 znače system foreground i background
var
Res: TXLSIndexedColorResolution;
begin
// $40 je BIFF icv token, a ne slot palete
Workbook.ResolveIndexedColor($40, xicsBiffIcv, Res);
case Res.Kind of
xickPalette: UseArgb(Res.ARGB); // slot palete, ako je razrešen
xickAutomatic,
xickSystem: UseSystemColor(Res.SystemColorRole);
xickInvalid: RejectToken(Res.RawIndex);
end;
end;
Obratite pažnju da primer grana po Res.Kind i ignoriše Boolean povratnu vrednost. ResolveIndexedColor vraća True samo kada je dobila konkretan ARGB, i kratki overload nikada ne čita Windows desktop, pa automatic ili system token legitimno vraća False dok je i dalje klasifikovan kao xickSystem. HotXLS se na to naišao u sopstvenom workbook serializatoru: kod koji tretira False kao „nema boje“ tiho odbacuje Automatic i System značenje tokena. Ako Vam trebaju prave RGB vrednosti za te tokene, pozovite dugi overload i dostavite TXLSTryResolveSystemColor callback koji primenjuje Vašu sopstvenu UI, export ili headless politiku
Zašto HotXLS upoređuje boje u OKLab-u umesto u RGB?
Jer su sRGB kanalske vrednosti gamma-kodirane, pa Euklidsko rastojanje u RGB ne prati ono što ljudsko oko vidi, i greška je najveća upravo u tamnim, zasićenim tonovima koje korporativne palete obožavaju. Uzmite tamnoplavu $000033. U RGB-u je rastojanje do crne 51, a do podrazumevanog navy unosa $000080 je 77, pa RGB matcher poverljivo ofarba Vaše zaglavlje u crno. U OKLab-u su kvadrirana rastojanja oko 0.0312 do crne i 0.0235 do navy, i HotXLS bira navy, ColorIndex 11 na fizičkom slotu 18; taj tačan slučaj je zakačen u test suite-u za oba, Classic i XLSX engine. Konverzija unutar ArgbToOklab linearizuje svaki sRGB kanal, primenjuje OKLab LMS matricu, izvlači kubne korene i projektuje na L, a i b, posle čega je obično kvadrirano Euklidsko rastojanje razumna aproksacija percipirane razlike. OKLab nije CIEDE2000 i ne pretvara se da jeste, ali nema piecewise korekcije nijanse, košta par množenja po boji, i dovoljno je stabilan da pogoni clustering petlju, gde zaista zarađuje svoje mesto
Šta NearestIndexedColor garantuje?
NearestIndexedColor garantuje deterministički, read-only odgovor: jednu konverziju ulaza, jedno fiksno skeniranje kroz 56 keširanih unosa i najniži javni indeks kad god su dva unosa podjednako blizu. Svaki workbook kešira normalizovani ARGB i OKLab koordinate svih 56 fizičkih slotova zajedno sa brojačem generacije palete. Reset palete gradi keš iznova, promena jednog slota ažurira samo taj slot, a upit nad zastarelom generacijom vraća False umesto da nagađa. Skeniranje koristi strogo manje-poređenje počevši od slota 8, po čemu paleta koja sadrži istu boju dva puta uvek odgovara nižim indeksom; to je bitno kada diff-ujete dva generisana fajla i očekujete bajt-identičan izlaz. Ulazna alpha prati uzan ugovor: nula alpha bajt tretira se kao neproziran, a delimično transparentna vrednost se odbija sa ColorIndex 0 i PaletteSlot -1, pošto unosi palete nemaju alpha. Pisaci ispuna i ivica Classic engine-a konvertuju RGB i tematske boje u indeks istom OKLab rutinom pri čuvanju, pa se API i sačuvani fajl slažu oko toga u koji slot boja pada
var
Match: TXLSNearestIndexedColorMatch;
begin
if Workbook.NearestIndexedColor($FF000033, Match) then
begin
// Match.ColorIndex = 11, Match.PaletteSlot = 18, Match.ARGB = $FF000080
if not Match.ExactMatch then
LogApproximation(Match.InputARGB, Match.ARGB, Match.DistanceSquared);
end;
end;
Kako BuildBiffPalettePlan utera prave boje u 56 slotova?
BuildBiffPalettePlan računa kompletan predlog za svih 56 slotova a da ne dodirne workbook, pa ga možete pregledati, logovati ili odbaciti. Planer prvo poziva ScanIndexedColorUsage: svaki slot koji font, ispuna, ivica, conditional format, shape, komentar ili gridline radnog lista referencira indeksom je zaključan, jer promena unosa palete prebojava svakog potrošača tog indeksa u jednom mahom. Mete su direktne RGB i razrešene tematske boje iz fontova, ispuna, ivica, differential stilova, data bar-ova i color scale-ova. Svaka meta dobija težinu po većem od broja referenci u iscrtanom sadržaju i broja definicija, a conditional format broji ćelije koje njegovi opsezi pokrivaju, pa boja preko cele kolone nadjačava onu iz jednog komentara. Postavljanje zatim ide fiksnim redom:
- Zaključani slotovi bezuslovno zadržavaju svoju izvornu boju
- Meta koja već postoji u paleti zadržava se na najnižem odgovarajućem slotu i taj slot postaje fiksiran
- Ako se preostale jedinstvene mete uklope u slobodne slotove, svaka dobija tačan slot, dodeljen u rastućem ARGB redosledu
- Inače se postavlja
Quantized, svaki slobodan slot se seje metom čije je rastojanje do najbližeg postojećeg centra, pomnoženo njenom težinom, najveće, i do 16 krugova frequency-weighted k-means u OKLab-u pomera samo slobodne centre dok dodele ne stanu
Budite iskreni prema sebi oko toga šta overflow putanja isporučuje. Clustering je ograničena lokalna optimizacija, ne globalni optimum, i slobodan slot na kraju drži centroid konvertovan nazad u sRGB sa klampingom, što može biti boja koju nijedna ćelija nije koristila doslovno. Ono što dobijate je ponovljivost: isti workbook uvek daje isti plan, a plan prijavljuje sopstvenu štetu kroz WeightedError, MaxDistanceSquared, ExactTargetWeight i TotalTargetWeight, pa batch posao može da odbije čuvanje kada aproksimacija postane previše gruba za brand smernice
var
Plan: TXLSBiffPalettePlan;
I: Integer;
begin
Plan := Workbook.BuildBiffPalettePlan; // samo za čitanje
if Plan.Quantized and (Plan.MaxDistanceSquared > MaxAcceptedError) then
raise Exception.Create('Too many distinct colors for a BIFF8 palette');
for I := 0 to High(Plan.Slots) do
if Plan.Slots[I].Changed then
LogSlot(Plan.Slots[I].ColorIndex, Plan.Slots[I].SourceARGB,
Plan.Slots[I].TargetARGB);
if not Workbook.ApplyBiffPalettePlan(Plan) then
raise Exception.Create('The palette changed after planning');
end;
Kako ApplyBiffPalettePlan odbija zastareli plan?
ApplyBiffPalettePlan validira ceo plan pre nego što upiše ijedan slot, i vraća False sa paletom netaknutom ako bilo šta ne odgovara trenutnom workbook-u. Plan nosi SourcePaletteGeneration i SourcePaletteHash, 64-bitni FNV-1a hash preko 56 izvornih boja; validacija takođe ponovo proverava svaki javni i fizički indeks, svaku izvornu boju, da nijedan zaključani slot nije označen kao promenjen, brojače zaključanih i promenjenih, i da je svaka meta neprozirna. Bilo koja efektivna promena palete u međuvremenu, uključujući uspešnu raniju primenu istog plana, čini plan zastarelim, pa su planovi efektivno jednokratni. Ispravan plan bez promenjenih slotova uspeva bez pomeranja generacije, a prava promena podiže generaciju jednom i gradi OKLab matcher iznova jednom, na Classic engine-u prepisivanjem fiksnog niza palete, a na XLSX engine-u uklapanjem pripremljene indexed-color override liste
Uključivanje za BIFF8 čuvanja i konverziju XLSX-a u XLS
Svojstvo BiffPaletteSavePolicy podrazumevano je xbpsPreserve, pa nadogradnja HotXLS-a nikome ne prepisuje paletu iza leđa. Postavljanje na xbpsOptimizeTrueColors tera Classic workbook da izgradi i primeni svež plan unutar SaveAs, ali samo kada je ciljni format xlExcel97; BIFF5, CSV, HTML, PDF, XLSX i ostali pisci ignorišu podešavanje. Posle uspešnog čuvanja optimizovana paleta ostaje u workbook modelu, pa kasniji upiti i čuvanja vide isto mapiranje. Ako čuvanje padne ili se otkaže, originalnih 56 boja i originalna generacija se vraćaju. Za XLSX izvore, SaveXLSXWorkbookAsXLS u lxXlsxExport gradi jedan plan iz učitanog workbook-a i upisuje ga u odredišnu paletu pre nego što bilo koji stil bude konvertovan, što je deterministički most koji demo za audit i konverziju workbook-a izvodi. Tematske boje prolaze kroz isti planer posle što im se tint razreši u RGB; ako biste radije držali teme živim u chart ispunama, članak o GelFrame tematskim bojama chart ispuna pokriva kako binarni XLS čuva scheme indeks umesto spljoštene boje
// Classic workbook: uključuje se eksplicitno, samo BIFF8
Workbook.BiffPaletteSavePolicy := xbpsOptimizeTrueColors;
if Workbook.SaveAs('report.xls', xlExcel97) <> 1 then
HandleSaveFailure; // paleta je već vraćena
// XLSX model u BIFF8 sa jednim determinističkim planom palete
XWorkbook := TXLSXWorkbook.Create;
try
if XWorkbook.Open('report.xlsx') = 1 then
SaveXLSXWorkbookAsXLS(XWorkbook, 'report.xls');
finally
XWorkbook.Free;
end;
HotXLS API-ji palete rade isto na IXLSWorkbook i TXLSXWorkbook, iz Delphi-ja i C++Builder-a podjednako. Preuzmite trial i usmerite ga na svoj najšareniji spreadsheet sa stranice HotXLS Delphi Excel komponente