Koyu mavi $000033, uzaklık RGB kanal değerleri üzerinden düz Öklid uzaklığı olarak ölçüldüğünde siyaha 51 birim, klasik lacivert girdisi $000080'e ise 77 birim uzaktadır. En yakın RGB eşlemesiyle klasik .xls dosyaları yazan bir dönüştürücü bu yüzden koyu mavi bir başlık satırını siyaha boyar; palet indeksine tek başına bakan her okuyucu da siyahı görüntüler. Format yazıcıya hiçbir alan bırakmaz: bir hücre formatı bir palet indeksi saklar ve palet 56 girdi tutar. Başlığı doğru tutturmak iki şey ister: insanların gördüğünü izleyen bir uzaklık ölçüsü ve bir çalışma kitabı paletin tutabileceğinden daha fazla farklı renk kullandığında paletin kendisini yeniden yazmanın bir yolu
Bir XLS dosyası neden yalnızca 56 renk tutabiliyor?
Bir BIFF8 font, dolgu ya da kenarlık kaydı asla RGB değeri taşımaz. Bir renk indeksi taşır; çalışma kitabı genelindeki Palette kaydı ($0092, [MS-XLS] §2.4.188), 8 ile 63 arasındaki indeksler için tam olarak 56 opak RGB girdisi sağlar. 0 ile 7 arasındaki indeksler sekiz temel rengin sabit kopyalarıdır. 63 üzerindeki değerler renk değil token'dır: $40 sistem ön planı, $41 sistem arka planı, $4D ile $4F grafik metni, grafik arka planı ve nötr grafik rengidir, $7FFF ise otomatik demektir. Excel 2007, bir hücre formatına tam RGB ya da tema rengi ekleyebilen XFExt kaydını ($087D, §2.4.355) ekledi ama Excel 97-2003 ve yalnızca XF kaydını okuyan her ayrıştırıcı, indeks dışında hiçbir şey görmez
HotXLS paleti, fiziksel indeksin eksi 7'si olan 1-56 arası herkese açık bir ColorIndex üzerinden açar. Üç numaralandırma şeması devrededir ve ResolveIndexedColor, onları TXLSIndexedColorSpace ile ayrı tutar: 1..56 API değerleri için xicsPublicColorIndex, ham disk-üzeri indeksler için xicsBiffIcv ve 64 ile 65'in sistem ön planı ile arka planını ifade ettiği xicsOoxmlIndexed. Ham BIFF indeksleri ayrıca TXLSIndexedColorRole olarak geçtiğiniz role karşı denetlenir; çünkü bir font, bir dolgu ve bir grafik farklı token kümeleri kabul eder: $51 bir font için geçerli, bir dolgu için geçersizdir
ResolveIndexedColor'un Boolean sonucu, çağıranların tökezlediği yerdir. Yalnızca somut bir ARGB değeri elde ettiğinde True döner ve kısa overload masaüstü renkleri için işletim sistemine hiç soru sormaz. Bir sistem ya da otomatik token bu yüzden Res.Kind xickSystem ya da xickAutomatic ayarlıyken False döner ve False'ı "renk yok" okuyan kod, token'ın anlamını sessizce çöpe atar. Tek istisna $4F'dir, nötr grafik rengi; hiç yardım almadan siyaha çözümlenir. Öteki token'lar için gerçek RGB değerleri istiyorsanız, uzun overload'a bir TXLSTryResolveSystemColor metodu geçirin ve UI, bir dışa aktarma ya da headless bir hizmet için kendi politikanızı uygulayın:
type
TExportColors = class
function ResolveSystemColor(AColor: TXLSSystemColorRole;
ARole: TXLSIndexedColorRole; out AArgb: LongWord): Boolean;
end;
function TExportColors.ResolveSystemColor(AColor: TXLSSystemColorRole;
ARole: TXLSIndexedColorRole; out AArgb: LongWord): Boolean;
begin
// Headless dışa aktarma: güncel masaüstü teması yerine sabit renkler
Result := True;
case AColor of
xscrWindowText, xscrChartText, xscrToolTipText:
AArgb := $FF000000;
xscrWindowBackground, xscrChartBackground:
AArgb := $FFFFFFFF;
else
Result := False;
end;
end;
var
Colors: TExportColors; // dışa aktarma kodunuz tarafından bir kez kurulur
Res: TXLSIndexedColorResolution;
begin
// $41 sistem arka planı token'ıdır, bir dolgu için geçerlidir
if Workbook.ResolveIndexedColor($41, xicsBiffIcv, xicrFillBackground,
Colors.ResolveSystemColor, Res) then
PaintBackground(Res.ARGB) // kendi çizim yordamınız
else if Res.Kind = xickInvalid then
RejectToken(Res.RawIndex); // kendi hata işlemeniz
end;
RGB uzaklığı neden yanlış palet girdisini seçiyor?
sRGB kanal değerleri gamma-kodlanmıştır; sayılardaki eşit adımlar, bir insanın gördüğünde eşit adımlar değildir ve hata, tam da kurumsal şablonların sevdiği koyu, doygun tonlarda en büyüktür. RGB'de $000033 siyaha 51, laciverte 77 uzaktadır; siyah kazanır. Her kanal doğrusallaştırılıp renk OKLab'a izdüşürüldüğünde karesel uzaklıklar siyaha yaklaşık 0.0312, laciverte 0.0235'tir ve lacivert kazanır. Eşleme, fiziksel yuva 18'de ColorIndex 11'dir ve Classic ile XLSX motorları aynı cevabı verir
Varsayılan palet bir kıvrım ekler. Lacivert iki kez görünür, ColorIndex 11'de ve yine 25'te; yani $000033 ikisine de tam olarak aynı uzaktadır. Farklı bir sırada tarayan ya da küçüktür-eşittir kullanan bir eşleştirici bir derlemede 25'i, ötekinde 11'i seçer ve iki üretilmiş dosya diff'te temiz eşleşmeyi bırakır. HotXLS yuva 8'den yukarı doğru katı küçüktür karşılaştırmasıyla tarar; bir beraberlik daima daha düşük indekse gider
OKLab bilinçli bir takastır. CIEDE2000 bazı ton çiftlerini daha doğru sıralardı ama parçalı düzeltmeleri onu yavaş yapar ve yinelemeli bir döngünün içinde akıl yürütmesi zorlaşır. OKLab renk başına bir doğrusallaştırma, iki küçük matris çarpımı ve üç küp köküne mal olur; sonrasında düz bir karesel uzaklık, algılanan fark için yeterince iyi bir vekildir. Her renk atamasında ve bir kümeleme geçişinin içinde koşan 56 girdili palet taraması için daha ucuz ve daha akıcı ölçüt doğru seçimdir
NearestIndexedColor ne döndürür?
NearestIndexedColor, bir ARGB değeri alır, çalışma kitabını değiştirmeden bir TXLSNearestIndexedColorMatch kaydını doldurur. Her çalışma kitabı 56 palet rengini OKLab koordinatlarıyla ve bir palet üretim sayacıyla birlikte tutar; bir sorgu, bir girdi dönüşümü ve bir sabit taramaya mal olur. Paleti sıfırlamak o önbelleği yeniden kurar, tek bir girdiyi değiştirmek yalnızca o yuvayı günceller ve güncel üretimle uyumsuz bir önbelleğe yapılan sorgu tahmin yürütmek yerine False döner
Alfa dar bir kural izler. Sıfır alfa baytı opak sayılır; bu, Delphi kodunun çoğunun düz RGB değerlerini nasıl geçtiğiyle uyumludur ve $FF tanım gereği opaktır. Aradaki her şey reddedilir: fonksiyon ColorIndex 0 ve PaletteSlot -1 ile False döner, çünkü bir palet girdisinin saydamlığı saklayacak yeri yoktur
var
Match: TXLSNearestIndexedColorMatch;
begin
if Workbook.NearestIndexedColor($FF000033, Match) then
begin
// Varsayılan palet: Match.ColorIndex = 11, Match.PaletteSlot = 18,
// Match.ARGB = $FF000080
if not Match.ExactMatch then
LogApproximation(Match.InputARGB, Match.ARGB, // kendi günlükçünüz
Match.DistanceSquared);
end;
end;
Aynı eşleştirici RGB atayıcılarının arkasındadır. Classic bir çalışma kitabında Interior.Color, Font.Color ya da Border.Color atamak, tam rengi XFExt kaydı için tutar ve XF kaydına yazılan indeksi bu taramayla seçer; dolgu ve kenarlık yazarları RGB ile tema renklerini aynı yolla indekse çözer. NearestIndexedColor bir renk için ne rapor ediyorsa, yalnızca indeks okuyan bir okuyucu o yuvayı gösterecektir
Gerçek renkli bir çalışma kitabını 56 yuvaya sığdırmak
Varsayılan palete karşı eşleme bir avuç renk için yeterlidir. Bir düzine birbirine çok yakın mavisi olan bir marka şablonu daha fazlasını ister: paletin kendisinin değişmesi gerekir. BuildBiffPalettePlan 56 yuvanın tamamı için eksiksiz bir öneri hesaplar ve çalışma kitabına dokunmaz; günlüğe yazabilir, bir eşikle karşılaştırabilir ya da çöpe atabilirsiniz
Planlayıcı ScanIndexedColorUsage ile başlar. Bir font, dolgu, kenarlık, koşullu biçimlendirme, şekil, yorum, grafik fontu ya da çalışma sayfası kılavuz çizgisinin indeksle başvurduğu her yuva kilitlenir; çünkü o girdiyi değiştirmek indeksin tüm tüketicilerini tek seferde yeniden renklendirir. Hedefler, fontlardan, dolgulardan, gradyan duraklarından, kenarlıklardan, koşullu biçimlendirme stillerinden, veri çubuklarından ve renk ölçeklerinden gelen doğrudan RGB ve çözülmüş tema renkleridir. Her hedef, başvuru sayısı ile tanım sayısından büyüğüyle ağırlıklandırılır ve bir koşullu biçimlendirme, aralıklarının kapladığı her hücreyi sayar; tüm bir sütuna boyanan dolgu, tek bir yorumda kullanılan bir rengi geride bırakır. Yerleştirme sonra sabit bir sırayı izler:
- Kilitli yuvalar güncel renklerini koşulsuz korur
- Palette zaten var olan bir hedef, en düşük eşleşen yuvasını korur ve o yuva sabitlenir
- Kalan farklı hedefler boş yuvalara sığıyorsa her biri, artan ARGB sırasıyla atanan tam bir yuva alır
- Aksi hâlde
Quantizedset edilir, her boş yuva, en yakın mevcut merkezine uzaklığının ağırlığıyla çarpımı en büyük olan hedefle tohumlanır ve OKLab'da 16 tura kadar ağırlıklı k-means, atamalar değişmeyi bırakana dek yalnızca boş merkezleri oynatır
Taşma yolunu gözü açık okumak gerekir. Buradaki k-means sınırlı bir yerel optimizasyondur; bir boş yuva sonunda, kelepçelenerek sRGB'ye geri çevrilmiş bir küme merkezi taşır ve bu, hiçbir hücrenin aynen kullanmadığı bir renk olabilir. Planlayıcının gerçekten sunduğu şey tekrarlanabilirliktir: aynı çalışma kitabı daima aynı planı üretir. Plan, ne kadar bükülmek zorunda kaldığını da WeightedError, MaxDistanceSquared, ExactTargetWeight ve TotalTargetWeight ile raporlar; yaklaşım bir marka kılavuzu için fazla kabalaştığında bir toplu işin kaydı reddetmesine yeter. Targets dizisi her girdi renk için hangi yuvaya eşlendiğini ve karesel uzaklığını gösterir
const
MaxAcceptedError = 0.002; // sizin eşiğiniz, karesel OKLab birimi cinsinden
var
Plan: TXLSBiffPalettePlan;
I: Integer;
begin
Plan := Workbook.BuildBiffPalettePlan; // salt-okunur
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); // kendi günlükçünüz
if not Workbook.ApplyBiffPalettePlan(Plan) then
raise Exception.Create('The palette changed after planning');
end;
ApplyBiffPalettePlan bayat bir planı nasıl reddediyor?
ApplyBiffPalettePlan, tek bir yuva yazmadan önce planın tamamını denetler ve herhangi bir şey güncel çalışma kitabıyla uyuşmazsa palet hiç dokunulmadan False döner. Plan, SourcePaletteGeneration ile 56 kaynak renk üzerinden 64 bitlik bir FNV-1a hash'i olan SourcePaletteHash taşır. Doğrulama ayrıca her genel ve fiziksel indeksi, her kaynak rengi yeniden denetler; kilitli hiçbir yuvanın değişmiş olarak işaretlenmediğini, kilitli ve değişmiş sayılarının toplandığını ve her hedefin opak olduğunu kontrol eder
Planlama ile uygulama arasındaki her gerçek palet değişikliği planı bayatlatır; aynı planın daha önceki başarılı bir uygulaması dâhil. Planlar pratikte tek kullanımlıktır: kurun, inceleyin, uygulayın; bir tane daha gerekiyorsa yeniden kurun. Değişmiş yuvası olmayan geçerli bir plan, üretimi ilerletmeden başarılı olur. Gerçek bir değişiklik üretimi bir kez ilerletir ve eşleştiriciyi bir kez tazeler. Classic motorunda yeni renkler doğrudan palete girer; XLSX motorunda özel indeksli renklere dönüşürler, HasCustomIndexedColor ile CustomIndexedColorCount bunları rapor eder ve XLSX yazıcısı bunları bir indexedColors bloğu olarak yazar
XLS kayıtları ve XLSX'ten XLS'e dönüşüm için isteğe bağlı açmak
BiffPaletteSavePolicy özelliği varsayılan olarak xbpsPreserve gelir; bir çalışma kitabının paleti yalnızca siz istediğinde değişir. xbpsOptimizeTrueColors yapmak, Classic bir çalışma kitabının SaveAs içinde taze bir plan kurup uygulamasını sağlar ve yalnızca hedef format xlExcel97 olduğunda; BIFF5, CSV, HTML, PDF, XLSX ve öteki yazıcılar bu ayarı yok sayar. Başarılı bir kayıttan sonra optimize edilmiş palet çalışma kitabında kalır; sonraki sorgular ve kayıtlar aynı eşlemeyi görür. Kayıt başarısız olursa, iptal edilirse ya da istisna fırlatırsa özgün 56 renk ve özgün üretim geri yüklenir
Üretilen raporlar için optimize edici politikayı açın. O çalışma kitapları RGB ve tema renklerinden kurulur, paleti kimse elle ayarlamamıştır ve yalnızca indeks okuyan bir okuyucu, politikayla birlikte onları özgüne çok daha yakın gösterir. xbpsPreserve'i, paletin sözleşmenin parçası olduğu çalışma kitapları için koruyun; alt akış kodun ColorIndex ile düzenlediği bir şablon gibi, bir yuvanın rengini sessizce değiştirmesi o kodu kıran yerlerde
XLSX kaynakları başka bir güzergâh izler. lxXlsxExport içindeki SaveXLSXWorkbookAsXLS, yüklenen TXLSXWorkbook'dan tek bir plan kurar ve herhangi bir stili dönüştürmeden önce onu hedef palete yazar; böylece her dönüştürülen hücre nihai palete karşı eşlenir. Çalışma kitabı denetimi ve dönüşüm workbench demosu tam olarak bu yolu koşar. Tema renkleri, tint'leri RGB'ye çözüldükten sonra aynı planlayıcıdan geçer; canlı tema referansı olarak kalmaları gereken grafik dolguları ayrı bir durumdur ve GelFrame tema renkli grafik dolguları yazısında ele alınır; ikili XLS orada düzleştirilmiş renk yerine bir şema indeksi saklar
// Classic çalışma kitabı: opt-in, yalnızca BIFF8 kayıtlarına uygulanır
Workbook.BiffPaletteSavePolicy := xbpsOptimizeTrueColors;
if Workbook.SaveAs('report.xls', xlExcel97) <> 1 then
HandleSaveFailure; // kendi işleyiciniz; palet çoktan geri yüklendi
// XLSX modelden BIFF8'e, tek deterministik palet planıyla
XWorkbook := TXLSXWorkbook.Create;
try
if XWorkbook.Open('report.xlsx') = 1 then
if SaveXLSXWorkbookAsXLS(XWorkbook, 'report.xls') <> 1 then
HandleSaveFailure;
finally
XWorkbook.Free;
end;
Palet çağrıları (ResolveIndexedColor, NearestIndexedColor, ScanIndexedColorUsage, BuildBiffPalettePlan ve ApplyBiffPalettePlan), Delphi ve C++Builder'da IXLSWorkbook ile TXLSXWorkbook üzerinde aynı imzalara sahiptir. HotXLS Delphi Excel component sayfasındaki deneme derlemesi, hiçbir şey yazılmadan önce en renkli şablonunuza karşı bir plan koşmaya ve MaxDistanceSquared'i okumaya yeter