semmixkolor i percepcja

Rozszerzenie aplikacji ($FF)

Rozszerzenie aplikacji pozwala programom zapisać w GIF własne dane. Każdy blok ma identyfikator, więc program rozpoznaje swoje dane, a pozostałe pomija. Najsłynniejszy z tych bloków to NETSCAPE2.0, który sprawia, że animacje się zapętlają.

Budowa

21 FF rozszerzenie, etykieta aplikacji 0B długość bloku stałego: zawsze 11 8 bajtów identyfikator aplikacji (ASCII) 3 bajty kod uwierzytelnienia (zwykle wersja) podbloki danych zawartość zależna od aplikacji 00 terminator

NETSCAPE2.0: pętla animacji

Specyfikacja GIF89a nie mówi, ile razy odtwarzać animację. Netscape Navigator 2.0 w 1995 roku dodał własny blok z liczbą powtórzeń i stał się on standardem de facto. Bez niego większość przeglądarek odtwarza animację tylko raz.

21 FF 0B 4E 45 54 53 43 41 50 45 "NETSCAPE" 32 2E 30 "2.0" 03 podblok: 3 bajty 01 identyfikator podbloku: liczba powtórzeń 00 00 liczba powtórzeń: 0 = w nieskończoność 00 terminator

Liczba powtórzeń to 16 bitów little-endian. 05 00 oznacza 5 powtórzeń, ale przeglądarki różnią się tym, czy pierwsze odtworzenie liczą jako powtórzenie. Blok powinien stać zaraz po palecie globalnej, przed pierwszą klatką. Niektóre programy zapisują "ANIMEXTS1.0" z tą samą zawartością.

Metadane XMP

Adobe zapisuje metadane XMP (autor, prawa, słowa kluczowe) w bloku o identyfikatorze "XMP Data" i kodzie "XMP". Dane XML nie są dzielone na zwykłe podbloki, tylko zapisane wprost, a na końcu dodano 258-bajtowy "magiczny" ogon. Jest tak dobrany, że dekoder, który czyta bajty jak długości podbloków, zawsze trafi na terminator i poprawnie pominie cały blok.

Profil kolorów ICC

Blok "ICCRGBG1" z kodem "012" przechowuje profil ICC w podblokach. Dzięki niemu GIF może przenosić informację, w jakiej przestrzeni barw zapisano paletę (zob. zarządzanie kolorem). Rzadko używany: zwykle przyjmuje się, że paleta GIF jest w sRGB.

// liczba powtórzeń z bloku NETSCAPE2.0; pos wskazuje bajt 21 bloku 21 FF
function readLoopCount(b, pos) {
  const id = String.fromCharCode(...b.subarray(pos + 3, pos + 14));
  if (id !== 'NETSCAPE2.0' && id !== 'ANIMEXTS1.0') return null;
  const sub = pos + 14;                    // podblok: 03 01 lo hi
  return b[sub] === 3 && b[sub + 1] === 1 ? b[sub + 2] | (b[sub + 3] << 8) : null;
}