2026/09/10

Roncsoljunk JPEG-et újra

Az inspirációt ez a videó adta, és az alatta meghivatkozott online kis eszköz, ami annyival több egy sima hexEditornál, hogy képes lokalizálni a JPEG-anatómiai részeit, és azt színkódosan jelölni, hogy célzottan tudjuk az egyes részeket támadni. Sőt egyből updateli is a beavatkozást és mutatja a hatást, nem kell menteni, megnyitani mindegyre. Mondjuk érdemes lenne még tovább fejleszteni azzal, hogy kijelölje az egyes támadható byteokat is, amiket elbarmolva nem teszik olvashatatlanná a képet. De ne legyünk telhetetlenek, sőt az a jó, hogy ezt meghagyta a kolléga nekünk, így magunknak kell felfedezni. Lássunk hozzá.

A JPEG-nél markerek vezetik be az egyes szekciókat, ezek két byteból állnak, az első byte értéke pedig FF. Például:
FF D8 - a képfile kezdete, nem érdemes babrálni, mert a kép értelmezhetetlenné válik
FF D9 - a képfile vége, babrálható, de nincs látványos értelme
vagy:
FF E1 - az EXIF kezdete, amit még két byte követ, ami a szegmens hosszát írja le.  Például:
FF E1 13 1B, ami annyit jelent, hogy az EXIF szegmens hossza 13 1B (hexában), vagyis 4891 byte (decimálisan), ebbe mindig beleszámítandó, a két hossz-leíró byte is, vagyis az FF E1 után 4891 bytera fog következni a következő szegmens markere.  Azért nem egyszerűen a következő marker mondja meg, honnan következik a következő szekció, mert magában az adatsorban is lehet markernek kinéző adat. 

A megadott hossz és a következő valid marker közé beszúrhatunk ugyan byteokat, de ennek a glitch szempontjából nincs értéke, esetleg szteganográfiára használható, de változó, hogyan reagálnak rá a képszerkesztő programok, és ha meg is nyitják, újramentésnél valószínűsíthetően nem fogják tovább vinni a számukra irreleváns, szegmensek közötti adatot, amit feltehetően be sem olvasnak.
A ChatGPT mondott egy érdekeset, nem csak a JPEG struktúráját hekkeljük a glitchelés, databending alatt, hanem a képnézegetők hibatűrését is. Sőt, mint ki fog derülni, a képet elmentő program által beépített hibakezelést is.

1. QT

A JPEG struktúrájában az első, vizuális szempontból értelmes, támadási lehetőség a Quantazation table szegmensben van, amiből az első 5 byteot nem érdemes babrálni:

Értelmezzük, az FF DB a szegmens markere, a 00 84, ami decimálisan 132 byte. Hogy is jön ez ki? Ebbe beleszámít a hosszat leíró két byte (00 84) plusz általában van egy Luminance és egy Chrominance táblánk, egyenként 8*8 byteosak. Tehát: 
2 (hossz-byte) + 1 (luminance azonosító) + 64 (tábla mérete) + 1 (chromninance azonosító) + 64 (tábla mérete) = 132



FF DB 00 84 00 - a marker, majd a hossz után a 00 byte határozza meg milyen tábláról van szó, ez a Luminosity tábla, az ötödik byteig tehát nem piszkálható, de az utána következő értékeket már igenis érdemes. Pontosan 64 byte hosszan. 

Mert utána megint egy 01 byte következik, ami a Chrominance táblát vezeti fel, ezt átírva megint kuka a kép. De utána 64 byte hosszan megint baszkurálhatjuk. 

A Luminance és a Chrominance (képzeletbeli 8*8-as) tábla 64 byteja a bal felső saroktól cikk-cakkban halad a jobb alsó sarok felé. Mitől van benne annyi 01, majd 02 és 03? Ez egy Photoshopban, 12-es minőségre mentett kép, egy régebbi posztunkból meghivatkozzuk a DQT tábla képét:


Minél jobban tömörített képről van szó (Level 0), a számok annál nagyobbak. De fentről jobbra és lefele haladva, bántalmazva a byteokat, azt is megfigyelhetjük, hogy előbb hatalmas, nagy felületre kiterjedő, kis frekvenciájú glitchek jelennek meg, de a tábla vége felé már csak az apró, nagy frekvenciás artifactek. A Luminancia táblában még van értelme a 02 byteok átírásának, de a chroma táblában már alig van látható hatása. De hét ennek is tudjuk az okát, a luminancia eltérésekre érzékenyebb az emberi szem, mint a színekre

1.1 Luminancia-tábla támadása:



1.2. Krominancia-tábla támadása:



2. Frame Header

Ez elég rövidke:
FF C0 00 11 08 03 E8 01 C2 03 01 11 00 02 11 01 03 11 01

lássuk mi van benne:

FF C0 SOF0

00 11   szegmens hossza         17
08     precision                 8 bit
03 E8  magasság                 1000            - ezzel csak kroppoljuk vagy növeljük a magasságot
01 C2  szélesség                  450            - ezzel azonban jól össze lehet kuszálni a képet. 
03     komponensek száma 3                
01     komponens ID         1 = Y
11     sampling          H=1, V=1    - káosz, érdemes (hex)11 és 44 között minden variációt kipróbálni
00     DQT                         #0
02     komponens ID         2 = Cb
11     sampling          H=1, V=1   - káosz, érdemes (hex) 11 és 44 között minden variációt kipróbálni
01     DQT                         #1
03     komponens ID         3 = Cr
11     sampling        H=1, V=1    - káosz, érdemes  (hex) 11 és 44 között minden variációt kipróbálni
01     DQT                         #1


Érdekesség, hogy amikor a HexEditorral rákerestem az FF C0 markerre, totál mást találtam, egy kisfelbontású, szét-szubsamplingezett képre utaló headert, ami nem lehet más, mint a thumbnail. De mint ilyen, az EXIF része, tehát az EXIF APP1 (FF E1 11 45) 4421 bytejában lapul egy teljes, komplett JPEG, kvantálási táblástól, Headerestől, Huffmannostól és adatstreamestől. Persze a fileban hátrább megtaláltam a teljes kép headerjét is, már nem beágyazva az EXIF adatfolyamába. Na ezért fontos, hogy egy marker után (pl EXIF) azt is megadjuk, hogy a szegmens milyen hosszú (4421 byte), mert így tudjuk, hogy a talált kis JPEG összes markere, szőröstől-bőröstől az EXIF része, tehát nem az igazi kép, csak egy thumbnail. 


3. Restart Interval


Célja, hogy a bitstreamben keletkezett hibát lokalizálja, tűzfalként szolgáljon a glitch továbbterjedése ellen. Ez itt csak a fejléc, ami elmondja a szabályokat, de a bitstreamben majd lesznek meghatározott MCU-szám után konkrét két byteos restart markerek is.

FF DD 00 04 00 39 - vagyis a Restart interval marker 4 byte hosszú, és a 00 39 azt jelenti, hogy 57 MCU-nként szinkronizálja a bitstreamet. 
A bitstreamen belül tehát restart markereink vannak, FF D0 - FF D7 között, majd kezdi elölről, összesen 124 ilyen van ezen a konkrét képen. Hogy jön ez ki? A kép 450*1000 pixeles, egy MCU 8*8 pixel, vagyis a képben 7125 MCU van. Ha 57 MCU-nként van egy Restart interval, akkor 7125/57 az 125 interval, az utolsó végére nem tesz markert (ott amúgy is lezárja a teljes JPEG-et FF D9-markerrel), tehát 124 restart marker van az adatfolyamban. A képünk 1000 pixel magas, 125*8 az meg pont 1000.
Azt is megfigyelhetjük, hogy mivel MCU-soronként (57 MCU) alkalmazza a restart intervalt, ha belerondítunk a bitstreambe, a glitch a sor végéig tart. Utána minden helyreáll. Ezért van tűzfal szerepe a hibák ellen, tehát 8 pixel magas képsor tud sérülni csak egy hiba miatt, nem a fél, vagy az egész kép. (ezt néha sikerült kijátszanunk)


Itt most a 00 39 helyett írtunk 00 38-at, ami azt hazudja a dekódernek, hogy a Restart Interval 56 MCU. Ez azt okozza, hogy soronként egy-egy MCU-val tolódik el a kép. 

3.1. Restart Interval marker a bitstreamben. 

Láttuk, hogy ennél a képnél 57 MCU egy intervallum, az adatfolyamban ez után egy Restart interval marker következik, az első MCU-sor után  FF D0, a második MCU-sor után FF D1 és így tovább. 
Mi történik, ha ezt a markert hazudjuk el az első 57 MCU végén? 


Nyilván a dekóder a frame headerből tudja a kép pontos geometriáját, vagyis, hogy 450 pixel, felkerekítve 57MCU széles, de a bitfolyam kiolvasásának pillanatában azt nem tudhatja, hogy az 57 MCU pontosan hány bitnyi adat.  Az MCU bitstream-hossza soronként is eltérő lehet, például homogén kék égből egy erdő aprólékos textúrájára vált, ami nagyságrendekkel hosszabb adatfolyamot eredményez elkódolva. 
Mivel nem kapja meg a restart interval markert, mert  FF D0 -t elhazudtuk 11 D0-nak, azt hiszi ez még mindig a bitstream része és az azelőtti DC és Huffman szabályokkal próbálja értelmezni tovább, amitől szürke MCU-sor keletkezik (nem értjük a pontos okát, de szabályszerűen történik, hogy 128-ra normalizálódik). Majd amikor végigrájra magát a következő sor adatain is, azt feltételezve, hogy az még az első soré, a második sor végén megtalálja az FF D1 markert, restart és helyreáll a rend. 

4. Huffman tábla támadása

FF C4 01 A2, vagyis a tábláink 418 (416) byte hosszúak, és itt lapul az az információ (fa-struktúra), ami alapján értelmezni lehet majd a kép lényegét rejtő bit-streamet. 



Nem nagyon világos, hogy melyik byte pontosan micsoda, gyaníthatóan nem is egyszerű visszafejteni, mivel képi információ-függő. Találomra próbáltunk benne byteokat kicserélni, a legtöbb kinyírta a képet, de volt olyan is, ami nagyon szép artifacteket okozott, de ezekre is jellemző volt, hogy csak kicsit kellett megváltoztatni, egy nagyon nagy adat beírása ezekre a byteokra, szintén megölte a képet. Ha ezt a támadást komolyan akarnánk csinálni, akkor mindenképpen szoftveres segítség kellene, ami feltérképezi az adott fotó Huffman struktúráját, sajnos a bejegyzés elején meghivatkozott online eszköz ennyire nem részletezi. De nézzük ezt a konkrét esetet:

FF C4 01 A2  - Huffman táblák, hossza 418 byte hosszú
00  - Első tábla fejléce  felső 4 bit vagyis a baloldali 0 a típusa (0-DC, 1 AC)
- a baloldali 0 vagy 1 lehet, hanem döglik a kép, de a 0-t 1-re átírva szép glitchet kapunk
     - a jobboldali 0 vagyis alsó 4 bit a tábla azonosítója, ez 0-3 között bármire átírható, de ugyanazt a glitchet kapjuk, mint a baloldali 4 bitnél, nagyobb értékekre döglik  kép


00 00 06 02 03 01 00 00 00 00 00 00 00 00 00 00 - BITS tömb, 16 byte szokott lenni, balról jobbra azt mondja meg, hány darab 1 bit hosszúságú kód van, majd hány darab 2 bit hosszúságú... egészen hány darab 16 bit hosszúságú a fában.
- itt most 6 darab van 3 bitesből, 2 darab a négybitesből és így tovább
- ha összeadjuk a 16 byteot, ennyi byte lesz a HUFFVAL hossza  - most ez 12
Az értékek átírása legtöbbször a kép kinyírását okozza, néha full fehér képet kapunk (túlcsordul), ha a byteokat cserélgetjük random, akkor néha kapunk glitchet is. Nem túl kiszámítható.


07 08 06 05 04 09 03 0A 02 01 00 0B
- HUFVAL - szimbólum értékek. hossza (12 byte) megegyezik a BITS 16 számának összegével

Bármelyik byte átírható 00-tól 0F-ig (0-15 között decimálisan) és glitchet kapunk, 10-FF (16-255 decimálisan) között sem döglik meg a kép, de hófehér lesz, vagyis túlcsordul. Ha kicsi értékkel írjuk felül, ilyesmi az eredmény, itt most  az első 07-et 00-ra cseréltük:


de minél nagyobb értékre cseréljül annál durvább a hatás, itt ha a 07-et 0F-re cseréljük (10 hex-től már csordul):


És így végig a HUFVAL minden byteján, de haladva jobbra egyre gyengébb (nem olyan nagy kiterjedésű) a glitch-hatás. Az utolsó 0B byte bántalmazása meg semmi láthatót nem okoz 00-0F között, afölött meg itt is túlcsordul az egész kép fehérbe..
Ez a csökkenő glitch hatás azért van, mert a 07 a legyakoribb fényerő különbségeket kódolja és így haladunk az egyre ritkábbakig 0B-ig. Nem kizárt, hogy a 0B is okoz valamit, csak éppen észre sem vevődik.

01  - következő tábla (DC-, mert a baloldali 0, a második DC tábla, mert a jobboldali 1)
00 00 06 03 01 01 01 00 00 00 00 00 00 00 00 00 -  BITS tömb, 16 byte, a számok összege 12, tehát
06 05 04 03 07 02 08 01 09 00 0A 0B  - a HUFAL 12 byte lesz

Hasonlóan viselkedik, mint az előbbi. 

10   a baloldali, felső 4 bit 1 a jobboldali pedig 0, tehát ez az első AC tábla, ezt a byteot DC-nek (00, vagy 01) hazudva fehér képet kapunk, tehát csak 11-nek hazudhatjuk, ekkor glitchet kapunk. más, nagyobb értékekkel megnyithatatlan lesz a kép.
00 02 01 03 04 01 03 03 02 03 03 03 02 06 09 75  - összeadva 162, tehát ennyi byte a következő HUFVAL 

01 02 03 04 11 05 12 06 21 07 13 22 00 08 31 14 41 32 23 15 09 51 42 16 61 24 33 17 52 71 81 18 62 91 25 43 A1 B1 F0 26 34 72 0A 19 C1 D1 35 27 E1 53 36 82 F1 92 A2 44 54 73 45 46 37 47 63 28 55 56 57 1A B2 C2 D2 E2 F2 64 83 74 93 84 65 A3 B3 C3 D3 E3 29 38 66 F3 75 2A 39 3A 48 49 4A 58 59 5A 67 68 69 6A 76 77 78 79 7A 85 86 87 88 89 8A 94 95 96 97 98 99 9A A4 A5 A6 A7 A8 A9 AA B4 B5 B6 B7 B8 B9 BA C4 C5 C6 C7 C8 C9 CA D4 D5 D6 D7 D8 D9 DA E4 E5 E6 E7 E8 E9 EA F4 F5 F6 F7 F8 F9 FA 

Ez a tábla sokkal érzékenyebb a BITS tömb értékeinek a cserélgetésére, módosítására, viszont a HUFVAL-t lehet küldeni mindenfélével FF-ig is akár. Az elől levő byteok nagyobb hatást érnek el. Nagyjából a felétől hátrább levőknek nincs látható hatása.

11 - AC következő tábla ez is csak AC táblának hazudható, hanem fehér képet kapunk, vagy megnyithatatlan képet nagyobb értékek esetén
00 02 01 03 02 04 04 03 05 04 04 04 06 06 05 6D  - összeadva szintén 162 byte lesz a következő rész

01 02 03 11 04 21 12 05 31 06 00 22 13 41 51 07 32 61 14 71 08 42 81 23 91 15 52 A1 62 16 33 09 B1 24 C1 D1 43 72 F0 17 E1 82 34 25 92 53 18 63 44 F1 A2 B2 26 35 19 54 36 45 64 27 0A 73 83 93 46 74 C2 D2 E2 F2 55 65 75 56 37 84 85 A3 B3 C3 D3 E3 F3 29 1A 94 A4 B4 C4 D4 E4 F4 95 A5 B5 C5 D5 E5 F5 28 47 57 66 38 76 86 96 A6 B6 C6 D6 E6 F6 67 77 87 97 A7 B7 C7 D7 E7 F7 48 58 68 78 88 98 A8 B8 C8 D8 E8 F8 39 49 59 69 79 89 99 A9 B9 C9 D9 E9 F9 2A 3A 4A 5A 6A 7A 8A 9A AA BA CA DA EA FA

Erre is igaz nagyjából az amit az előbbi táblánál tapasztaltunk. 

5. Scan header támadása



FF DA SOS – Start Of Scan
00 0C SOS hossza = 12 byte
03 komponensek száma = 3
01 00 komponens 1 → Huffman DC=0, AC=0    
02 11 komponens 2 → Huffman DC=1, AC=1
03 11 komponens 3 → Huffman DC=1, AC=1
00 spectral selection start = 0
3F spectral selection end = 63
00 successive approximation = 0

Nincs sok támadható byte, a három komponens második bytejait lehet elhazudni, de csak valid Hufmantábla azonosítóra (00, 01, 10, 11), ilyenkor glitch az eredmény, más értékekre meghal a file. Az utolsó 3 byte meg a progresszívre mentett JPEG-ekre vonatkozik, itt semmi hatása nincs, ha átírjuk őket. 

De azért mentettünk egy Progressive képet is 5-ös scans értékkel. A Successive approximation (utolsó) byte támadása elég érdekes, rég elfeledett CGA grafikus megjelenést idézett.


De számos más különbséget is észrevettünk a normál JPEG-hez képest, ebben nincsenek Restart markerke a bit-streamben, viszont van 14 darab Scan header. Ha például a második Scan header utolsó byteját támadjuk, akkor meg ezt kapjuk:



De sorra magtámadhatjuk a harmadik, negyedik, stb. Scan headert is, bár a glitch egyre vékonyabb, egyre kevésbé karakteres, viszont minden esetben más és más. Azzal is érdemes játszani, hogy az egyes Scan headereket semmisítjük meg, FF DA átírásával. ilyenkor nagyon nem mindegy, hogy az elsőket, vagy az utolsókat nyírjuk ki, teljesen más rétegek érvényesülnek. Rá kellett ébredjek, hogy érdemes lenne az egészet elölről kezdeni ezzel a progresszív képpel is, mert vélhetően az elejétől felsorolt beavatkozások zöme is totál más geometriájú glitcheket eredményezne. 

6. magának az adatfolyamnak a támadása

Itt teljességgel kitalálhatatlan, hogy melyik byte átírása hova fog ütni. Eleve mi byteokat látunk egy hexeditorban, de a valóságban ez egy bitfolyam, amiben az adathosszúságok bárhány bitesek lehetnek. Jellemzően mégis, ha az adatfolyam elejét támadjuk, akkor a glitch a kép felső részét fogja érinteni, míg ha a végét, akkor az alját. Azt hogy a hiba melyik MCU-t fogja érinteni azt szinte lehetetlen eltalálni de próbálgatással azért lehet közelíteni. A sorhossznyi restart intervalos képeknél a glitch a sor végéig tart, de néha előfordult, hogy a kép végéig az összes MCU-sor megnyikkant. Leginkább 8 pixel magas szürke sávként jelentkezik a hiba, de néha sikerül színes találatot is csinálni. Ami viszont nagyon érdekes, hogyha sorban írjuk át a byteokat és keletkezik egy sor glitch, a következő néhány byte átírásánál nagyon gyakran visszaáll a helyes kép. Kifejezetten gyakori és könnyen előidézhető jelenség. Hiba * hiba = jó kép, mindenesetre furcsa, de biztos a dolog matematikája miatt determinisztikus.

Hosszú és kimerítő utazás volt, két MI-t is fárasztottunk a kérdéseinkkel, nélkülük esélyünk se lett volna a byteok értelmezésében, a végére így is mindketten elkezdtek hallucinálni. De nem sikerült mélységében megérteni a dolgot, inkább rengeteg új perspektívát nyitott ki. Ez csak egyetlen típusú JPEG (plusz egy progresszív a végén bónusznak) körüljárása volt, és az is csak lóugrásokban. De JPEGet menteni sokféleképpen lehet és mind eltérően viselkedhetnek. 
És akkor még nem is próbálkoztunk azzal, hogy a támadásokat egymásra halmozzuk. De hátha valaki kedvet kap hozzá és ír egy olyan programot, ami egyesíti a bejegyzés elején meghivatkozott kolléga munkáját az itt felhozott további részletekkel. Mondjuk egy olyat, ami kijelöli a leglátványosabban támadható byteokat és valid támadó értékintervallumot is ajánl ott ahol nem mindegy mit írunk át mire.




2026/08/31

A felejtés, mint glitch


Biztos jártál már úgy, hogy egy régen látott helyszínre érve azt érezted, hogyha le kellett volna rajzolnod emlékezetből, teljesen másképp helyeztél volna el tárgyakat. Az a fa nem itt volt, annak a sziklának más volt a színe, balról jöttünk, nem jobbról, stb. Mi ez, ha nem egy-két, rég nem használt neuronkapcsolat megszakadása, és az emlékek újra rajzolása a hibás kapcsolat figyelmen kívül hagyásával? Vagyis egy glitch az emlékezetben. 



Ezzel a két képpel dolgozunk, PNG formátumban igyekszünk szanaszét glitchelni, az itt és itt ismertetett módon. Esetleg nézd meg ezt a videót is, a kolléga nagyjából hasonlókat művel és őt is a japán művész inspirálta, mint minket. A 15-20 éve eltűnt városképek, amiknek emlékét agyunkban is lassan kikezdi a felejtés, tökéletes alanyok erre a játékra. 
A bejegyzés végére nagyjából tudni fogjuk, hogy milyen típusú képeket, és milyen módon érdemes megtámadni ahhoz, hogy értelmezhető glitcheket kapjunk.



1. Photoshopban large, medium és smallest mentései az RGB8 PNG filter-swapjére (más filterrel kódoljuk ki, mint amivel bekódoltuk) nem mutatnak különbséget. Mellesleg ezen a fileon, a különböző tömörítéseknél, fileméretben csupán 1-2 % eltérés volt, ellenben mentési időben akár 100% is. Szóval nem érdemes a smallest but slowest tömörítést használni.

Minden filtertípus Averageként kikódolva pont így néz ki.

2. Az viszont meglepett, hogy a program kezeli az alfa csatornát is, a Nap-korongot vágtuk ki a képből. 

A legelső pixelt támadtuk meg, mert a program nem enged menteni támadás nélkül
A filtereket viszont meghagytuk, ahogy az eredeti fileban voltak.

RGBA - összes scanlineja Averagként kibontva, azért ez teljesen mást eredményezett,
mint kettővel fennebb. 

3. RGB16-os PNG-vel nem áll szóba a program, tehát csak a 8 bitesek működnek. De hibaüzenettel lekezeli. 

4. Az Interlaced képeket is megtagadja a program, ügyesen hibaüzenettel.

Innentől csak RGB8 és large mentésű (vegyes filterezésű és olykor normalizált filterezésű) fileokat  támadunk.

5. Pixel támadás mátrixban, vagyis 10*10 pixelenként a teljes kép felületén, filterezést nem bántjuk: 

Az eredmény érdekes, mert sejtetni engedi, hogy a photoshop milyen típusú felületeknek, soroknak milyen filtereket választ leginkább, az ég zömmel Sub filterezésű, a felhő töri ezt meg picit, aztán lefelé, ahogy sűrűsödnek a kábelek Paethre vált,  a házcserepeknél a fene tudja, Average-re tippelnék, mert nem látszik a 10*10-es mintázatban a fehér pixel (amennyiben None lenne ezt várnánk), aztán lefele a ház fala megint Paeth, az aszfalt Average és a csajok megint Paeth. 

Emlékeztetőül ilyen lenne a 10*10-es támadás None-ra normalizált filterű képen. 


A másik képünkön az a nagyon furcsa, hogy az eget nem bántotta, egyetlen pixelt se, erre jelenleg nincs magyarázatunk (még Ps-ben az eredetivel Differenc módban is összenéztük, semmi jele az égben a hibának). Aztán lefele a Paeth, az Average, kicsit megint a Paeth, majd a Sub dominál. 
Gondoltuk sorra megnézzük, hogy ugyanezzel a 10*10-es pixeltámadással elhazudjuk az összes filtert is, mondjuk Average-nek, csak egyetlen filtert hagyunk meg ahogy volt, sorra a None, Sub... és hoppá, ha a Sub filterű scanlineokat békén hagyjuk az összes többi Average, akkor az ég érintetlen marad? Vagy van benne némi átlós textúra?


Nézzük csak meg PS-ben Difference módban az eredetivel és egy durva Curve-t ráhúzva!


Ja, vagy így. Hát ott van a glitch, de mivel minden pixelt 255-re tettünk és az ég eleve nagyon világos, ezért alig látszik a hatás, de ott van. Tehát nemcsak az számít, hogy mennyire homogén zóna scanline-jairól van szó (ami alapján filtert választ a program a soroknak) hanem az is, hogy milyen világos vagy sötét tónust milyen byte-értékkel támadunk az egyes pixelpozíciókon. 

6. Most azt nézzük meg, hogy a három Custom filterünkkel normalizáltan elkódolt képeink hogyan néznének ki, ha a dekódolásukat az 5 valid filter egyikére hazudnánk. Itt már csak a kevésbé zajos képünket teszteljük, hiszen az már világosan látszik, hogy a filterek támadása egyfajta edge-detection szűrőként hatnak. A részletgazdag (nagyfrekvenciás) képek így a filtertámadás során belefulladnak a zajba, és csak a nagyobb egységes felületek maradnak meg.  Mint már várható volt, mindhárom saját elkódolás, None kikódolással egy erős edge detectiont eredményez



Talán a a Custom2 filterünk (ami az RGB színeket külön szomszédaitól veszi) Non-ként interpretálva lehet valamennyire érdekes a színeltolódás miatt, a másik két szűrőnk monokrómabb összhatásban (közelről azért durván színzajos), kb. ugyanez. A Sub és Up filterekkel kikódolás már érdekesebb, nagyon képfüggő lehet, hogy kacat, vagy mestermű lesz belőle.



Bár a Custom1 és Custom3 bemenet se rossz, de a legjobb eredményt itt is a Custom2 bemenetű Sub és Up-ként interpretált képek adták.
Nyilván az Averagetől várjuk a legtöbbet, és nem is csalódunk, mindhármat mutatjuk:

Custom1 filtered  - decoded as Average 

Custom2 filtered  - decoded as Average

Custom3 filtered  - decoded as Average

A Paeth filter meg hozza a szokásost, értelmezhetetlen de pszichedelikus pixel-kristályszerkezet, ami legalább rímel az aminosav kristályaink képeire.



7. Kipróbáltuk a Custom1 (körkörös prediktorunkat is a kikódolásra). Az egyszerű, vegyes filterű, képeink elég semmilyenek lettek, viszont a Custom 1, Custom 2 és Custom 3 elkódolású képek Custom 1 dekódolással már csöppet érdekesebbek:


Továbbra is leginkább a Custom3-nak elkódolt, majd Custom1-ként visszakódolt kép nyújt bármiféle esztétikai élményt, ennél ugyanis, mivel elkódolásnál a pixel RGB színeinek byte értékeit három szomszédjától szedi, a súlyos edge-detection-szerű hatás mellett megfigyelhető egy enyhe pszichedelikus color-shift is.

Körülbelül egyhetes utazásunk végére érve további rengeteg ötletünk is lett, amit egyszer talán érdemes lenne leprogramozni, vagy leprogramoztatni az AI-val. 
Mellesleg az AI szerint ez a teljes projekt, programokkal, szkriptekkel, elemzésekkel, szőröstől-bőröstől pár óra laptophasználat ökológiai lábnyomával ér fel. ennél jóval több számítógéphasználat történt az én kliensoldalamon, legalább 20 óra. Másképpen megközelítve, pár száz palacsintarecept megbeszélése az AI-val ekvivalens öko-lábnyomot eredményez, mint ez a projekt.
További ötletek, saját filterek esetére érdemes lenne kipróbálni azt, hogy az egyes pixel-byteok kiszámolásánál ne csak az aktuális kép már elkódolt bytejaira támaszkodjon, hanem egy másik kép hasonló pozíciójáról is vegyen információkat, például a Red és Green byte értékét vegye az Average szabályai szerint a baloldali és felső pixel átlagából, de a Blue byteot egy másik kép azonos pozíciójú bal és felső pixelátlagából számolja. Ez várhatóan valami olyasmit eredményezne, mintha a két képet valamilyen elcseszett módon egymásra mentettük volna. 

Custom2 to Average + byte attack 1-20

Ugyanakkor van bennünk egy bizonytalanság, hogy ez a módszer valóban glitchnek számít e, a szó szoros és véletlen-kontextusú értelmében, vagy inkább data bending, esetleg egyfajta peremvidéke a hibának és a képfeldolgozásnak? 




2026/08/28

PNG autopsy III

A következőkben a Filterezés támadását tovább gondoljuk és saját filtereket találunk ki. Érdemes az előző bejegyzéssel alapozni, ha nem onnan jöttél. 

Tehát azt már tudni véljük, hogy a PNG 5 filterétől eltérő (más irányokból is építkező) filterek alkalmazásának nincs pragmatikus vonatkozása, de ez nem jelenti azt, hogy nem kísérletezhetünk vele.
Már van olyan eszközünk (köszi Ai, vagy ti mindannyian, akik drágább memória árakkal fizetitek ezt helyettem, vagy az utókornak, akinek ezzel éljük fel a jövőjét), amelyik képes olyan PNG-ket menteni (csak RGB8 semmia alfa és semmi interlace), ahol a scanlineokra kötelezően általunk választott filtert alkalmaz, csak annyit kell hozzáprogramozni, hogy saját algoritmusokat is tudjon kezelni. Ezeknek mondjuk a filter byte-ját 5-6-7 és így tovább, írná bele a képbe, amitől egy normális képnézegető egyből hülyét kap, például a Photoshop, hiszen nem ismert Filtert nem tud használni. De például az Irfan (sőt a windows file explorer nézete) nem esik kétségbe, látszólag az összes nem értelmezhető filterű scanlinet None-nak tekint és megjeleníti. De van olyan eszközünk is, ami adott scanline típus-byteokat el tud hazudni. Az ilyen Custom filterezett képeinknek itt tudunk valid filter-byteot beállítani, ezután már minden képnézegető meg fogja nyitani a képünket a kiválasztott algoritmus szerint, ami természetesen a glitchet fogja okozni.

Három Custom filterrel próbálkoztunk, remélve a szebbnél szebb glitch mintázatokat. Amit ha nem is sikerült elérni, de tapasztalatokat azért szereztünk. Fontos, hogy ezeknél a teszteknél az előző bejegyzésben is említett kis segédprogramunkat használjuk, ami minden scanlinra ráerőlteti ugyanazt a filtert.

Custom1 -- Körkörös prediktor (mind a 8 szomszéd átlaga) - ami körbe minden pixelt figyel, vagyis 4 már elkódoltat a szokásos irányból (balsó, felső irányok), és négy pixelt a jobbra és alul elterülő részről, amit  kikódolásnál azért nem ismerhetünk, mert még nem kódoltuk ki (ha nem világos, tényleg menj vissza az előző posztra). Nyilván emiatt egy ilyen filterrel elkódolt kép nem invertálható (dekódolható) egyszerű szekvenciális dekódolással, de most ez nem is cél, hiszen a Glitch okozására hajtunk, ezért csak ENCODE-ra használjuk.

Custom2 -- RGB-Average (csatornánként MÁSHOVA néző prediktor) - vagyis
- R csatorna <- bal szomszéd R csatornája
- G csatorna <- balsó-fenti szomszéd G csatornája
- B csatorna <- fenti szomszéd B csatornája
Ez az algoritmus elvileg ENCODE-ra és DECODE-ra is használható, hiszen csak valid irányokból veszi az adatot.

Custom3 -- InverseAverage (jobbra / lent szomszédok átlaga) - itt minden hivatkozás jövőbeli, tehát későbbi feldolgozású pixelre mutat, ENCODE-ra tökéletesen használható, de DECODE-ot csak fordított irányban lehetne végrehajtani rajta, tehát ha a jobb alsó pixeltől indulva visszafelé zajlana a dekódolás.

És így néznek ki a Custom Filterekkel elkódolt, de valós Filtereknek (azokkal kikódolt) hazudva:



Emlékeztetésnek és összehasonlításnak (az előző bejegyzésből átemelve),  a valós filterek egymás között elhazudva így néztek ki:

Kis felbontású és JPG-nek mentett nézet, az eredeti jóval gazdagabb.


Az eredmény érdekes, de sajnos nem a reményeink szerint való, azt vártuk volna ugyanis, hogy a merőben eltérő encoder filtereink merőben eltérő hatásokat fognak produkálni, rosszabb esetben annyira összeborzolják a képet, hogy az felismerhetetlenné válik. Ezzel szemben a kikódolásra használt filter hatása a domináns, tehát például egy UP függőlegesen vonalas, egy Average átlósan, stb, és egyáltalán nem felismerhetetlen a kép sem. 

Ezen a ponton végleg el kellett fogadnunk, hogy a végső, meg-glitchet kép zajmintázatát, a glitch geometriáját leginkább nem az határozza meg, hogy eredetileg milyen filterrel volt elkódolva, hanem jellemzően a kikódoló algoritmus. Tehát hiába találunk ki bármilyen irányú, csillag alakú, hatszög, stb. saját-filtert, a végeredmény mégis a kikódoló filter jellegzetességeit fogja mutatni. 

De hogyan lehetne megnézni egy (bármilyen filterezésű) képet a saját filterrel kikódolva, amikor nincs a földön olyan képszerkesztő, amelyik ismerné a mi saját filterünk algoritmusát?  Na erre is írattunk egy python progit a mesterséges intelligenciával, ami bármilyen filterezésű bemeneti képet egy saját filterrel próbál értelmezni. A saját filternek azt választottuk, amelyik a pixel összes (körben mind a 8) szomszédjának átlagával dolgozik, és ugyanúgy, balról jobbra, fentről lefelé járja be a képet. Ilyenkor értelemszerűen az adott pixel kikódolásakor a 8 szomszédból csak négynek (balra és felül található) az értéke ismert, a többi négynek (jobbra és alul található pixeleknek) az értéke még nincs kikódolva. Ez fogja okozni  a glitchet. Ezt egy kis parancssoros pythonnal értük el, ami annyit csinál, hogy bármilyen filterezésű bemeneti képet a mi saját filterünkkel kódol ki, majd az egyszerűség kedvéért sima bmp-nek ment.


Azt vártuk, hogy olyan zaj-katyvaszt kapunk, hogy a fal adja a másikat, ezzel szemben meglepődtünk. Egyrészt igazolódott, hogy mindig a kikódoló filter karakterisztikája lesz a domináns a glitchelt képen. Vagyis közelről megnézve pontszerű (pointilista-szerű) zaj keletkezik, ami nem meglepő hiszen egyes pixelek értéke minden irányból származik, nincs kitüntetett irány. Ugyanakkor az is látszik, hogy az elkódoló filterek is rányomják, bár sokkal csekélyebb mértékben, a kézjegyüket a végleges glitchre. Érdemes megfigyelni, hogy az eredetileg Sub-nak kódolt, majd Customnak kikódolt képen a nagyobb felületek élei dominánsan függőlegesek, míg az Up-nak elkódolt és Customnak kikódoltak esetében vízszintesek. Az Average filterrel elkódolt és Custommal kikódolt képeknél, az összefüggő felületek alsó-jobboldali élei dominánsak. Külön meglepett, hogy a Paeth elkódolás, ami mindig borzalmas kristályszerű szín-glitcheket okozott, itt egyáltalán nem mutatta a szivárványos geometriáit. 

A további 3 kép, amikor az elkódolás során három saját filtert használtunk, külön érdekes. A bejegyzés elején felsoroltuk ezeket a saját filtereket, a C1 az maga a körkörös, amit a kikódolásra is használunk (C1 - C1). Természetesen nem tudja visszaadni az eredeti képet glitchmentesen, hiszen említettük, hogy a 8 szomszédos pixel értékéből, amiből építkezik, 4 értéke nem ismert. Egyfajta edge-detection hatást vélünk felfedezni itt. A C2-C1 esetében az elkódolás során a második saját filterünket próbáljuk kikódolni az első saját filterünkkel, egyszerűsítve, a C2 az RGB értékeinek eltérését három szomszédjától veszi, a pirosat a baltól, a zöldet a bal felsőtől, a kéket pedig a felsőtől.)
A C3-C1 meg hasonló, de itt a C3 egy inverz Average filter, vagyis jobboldali és alsó szomszédaiból építkezik (gyakorlatilag mindkét szomszédja ismeretlen a kikódolás balról és fentről bejárása miatt), ezért látszik úgy, mintha a zajban az edge-detection fordított irányú lenne az Average-C1-hez képest. 

Na így. A programokat, szkipteket elküldöm annak aki kéri, de nem látom értelmét ide felpakolni a blogra, mert valószínű, hogy az elkövetkező 10 évben nem lesz több érdeklődő mint 0.

És végezetül így néz ki a normál RGB8 PNG (vegyes scanline filterrel), Custom 1 filterrel kikódolva:




PNG autopsy II.

Régóta dédelgetett, parkoltatott stb. vágyam, hogy megberheljem a PNG-t, de úgy igazán mélyen.  S bár az AI azt állítja, hogy a PNG-be nem lehet hexeditorban csak úgy belepiszkítani, nekünk régebb mégis sikerült (gondolom az Irfan megengedőbb a sérült CRC-vel).

Kezdjük ezzel. UCNV japán művész, nagyon érdekes munkái vannak, de most csak a PNG-glitchjeire koncentráljunk. Amiről régebb nem találtunk futtatható programot (Rubyhoz még annyira se értünk mint a Pythonhoz), de most a  Claude olyan python-progit ír nekünk, amilyet csak szeretnénk. 

A PNG feldolgozási lánca (hol érdemes megtámadi):

  1. Raw Data (nyers pixelek byte értékei RGB vagy RGBA stb.) — ezt piszkálni valójában BMP glitch, nem PNG-specifikus
  2. Filtered Data — ide lehet nyúlni  - erről fog szólni a bejegyzés
  3. Compressed Data — ide is lehet nyúlni
  4. Formatted PNG (checksummal) — ide NEM tanácsos, mert a sérült CRC miatt érvénytelennek látják a képszerkesztő programok, de  - ilyet csináltunk már hexeditorban és van progi amivel megnyitható.
A nyers megnyitott kép pixeleit, ami mondjuk RGB, RGBA, soronként (ez a scanline) filterezi a képszerkesztő program. RGB8 esetén a pixelek három byteal vannak reprezentálva
<Filter-byte><Pixel1-Red><Pixel1-Green><Pixel1-Blue><Pixel2-Red><Pixel2-Green><Pixel2-Blue>  ... <Pixeln-Red><Pixeln-Green> <Pixeln-Blue> 
RGBA esetén, nyilván 4 byte ír le egy pixelt, RGB16 esetén meg 6 byte. A tovébbiakban RGB8 képekkel dolgozunk, és az Interlace-et is messzire elkerüljük, mert az csak tovább bonyolítaná az egészet.

Az 5 filter típus (amiből választ a képmentő program):

  • None — nincs filter, minden pixel önálló, saját RGB értéket tartalmaz, egy bitcsere csak lokális zajt okoz
  • Sub — az előző (bal oldali) pixel három bytejához viszonyít, és az eltérést tartalmazza → a pixel bytejaiban okozott hiba ezért jobbra "csorog", hiszen a következő pixel bytejai már ebből a sérültből fogja venni az adatot. 
  • Up — a fölötte lévő sorhoz viszonyít, az eltérést tartalmazza → függőlegesen csoroghat a hiba lefelé
  • Average — a Sub és Up átlaga, a balra és fölötte levő szomszédainak átlagára támaszkodik  → átlós, lágy, "üstökös-farok" jellegű, kevésbé "glitches", inkább szép színátmenet
  • Paeth — a legkomplexebb algoritmus → a leglátványosabb, legkiterjedtebb glitch, miközben a kép formája még felismerhető marad 
Ez nagyjából annyit jelent, hogy legtöbbször nem konkrét RGB értékeket tárol a fileban, hanem az adott filter algoritmusa szerint más, szomszédos pixelektől való eltérését, például a Sub esetén az előtte (feldolgozási időben előtte, amúgy balra tőle) levő pixel értékétől való eltérést, Up esetén a fölötte levő pixeltől. Az Average és a Paeth algoritmusai ennél komplexebbek, de a logika ugyanaz. Nagy egybefüggő színfelületek így nagyon sok 0 és más kis értékkel leírhatóak, amik majd jól tömöríthetőek.

A PNG filterezésének logikája az, hogy ha egy irányból bejárjuk a képet, mondjuk bal felső saroktól soronként jobbra, majd lefelé, akkor majd az RGB adat visszanyerésénél is ugyanígy végig tudjuk járni az összes pixelt, ugyanazzal az algoritmussal és mindig valid RGB adatokat találjunk azokon a pozíciókon, amikre támaszkodva vissza kell állítanunk egy pixel értékét. 

Például, a legfelső sor mondjuk Up filterrel kerül elkódolásra. Balról jobbra, fentről lefelé. Az első pixel értéke a felette levő pixeltől való eltérése lenne, de fölötte nincs sor. Ilyenkor a fölötte levő pixel értékét 0-nak veszi a program, így az eltérés gyakorlatilag ugyanaz lesz, mint maga az RGB érték. És így tovább jobbra. A következő sornál, ha történetesen megint Up filterezés van, akkor már tud építkezni a fölötte levő pixelekből. Ugyanez a logika érvényesül a Sub-ra is, csak  vízszintesen. Sőt az Averagnél is, csak itt mind a két, előtte és fölötte levő szomszédját átlagolja, ahol mindig valid (az adott pixel kiszámításánál már visszaállított) adatok vannak. A Paeth esetében szintén, csak itt még bele keveri a bal-felső szomszédot is és nem átlaggal dolgozik. 

Tehát soha nem próbál meg a jobboldalról, vagy alábbi sorokból építkezni, mert amikor vissza kell állítani a képet, mondjuk egy tetszőleges pixelen, akkor mindig csak tőle balra és fölötte találhatóak a már visszaállított értékek, jobbra, és alatta a még kikódolatlan eltéréseket találja, a nemtudni-mihez-viszonyítva. Ezért nincsenek mondjuk körkörös filterek, amik a pixel összes szomszédját használják az algoritmusban, vagy nincsenek olyanok sem, amelyek balról és jobbról is, vagy alulról és felülről is  építkeznének. Mert ezeket egyszerű módon nem is lehetne visszaállítani (bár biztos ennek is meg lehetne találni a matematikáját, de ehhez kicsik vagyunk). 

Minden scanline előtt egy plusz byte jelzi, az adott sor melyik filterrel van képezve (0=None, 1=Sub, 2=Up, 3=Average, 4=Paeth), innen tudja majd a kikódoló program, hogy milyen algoritmust használjon. De egy képszerkesztő programban, felhasználóként, nincs hatásunk arra, hogy melyik sorra milyen filtert használ mentésnél (talán csak nagyon közvetve, amikor a lassúság-minőséget beállítjuk). De az nagyon valószínű, hogy nagy vízszintes hasonló színű felületek ugyanolyan filtert kapnak. Ez is lehetne egy tesztelendő irány, de ragaszkodjunk amennyire lehet az eredeti irányhoz.

A megnyitott kép összes sorát az öt hivatalos és több saját filterrel lehet elmenteni

Mivel minden sor mindenféle filterű lehet, ez nagyon sok változót visz a rendszerbe, ami egyrészt a Glitch-véletlenségének jót tesz, de ha meg akarjuk valamennyire érteni a véletlent, akkor meg pont nem segít. Ezért spéci python-programmal (amit az AI írt nekünk) úgy mentettük el tehát a PNG-ket, hogy minden scanline-ra ugyanazt a filtert erőszakoltuk, majd ezeknek a filtereit szerre elhazudtuk (átállítottuk a scanline elején a filter-byteokat és aszerint kódoltuk ki). Így például egy SUB-nak mentett és SUB-ként megjelenített kép tökéletesen visszaadja a kiindulási képet, de az összes többi filterrel kikódolva a két filter interakciójára jellemző glithet eredményez.


A következő tesztképeket a fenti program 3. pontjánál generáltuk, vagyis benyitottuk szerre az összes None, Sub, Up, Average, Paeth-filterre normalizált - az előbbi programmal generált - képünket és szerre mindegyiknek elhazudtuk a filterét az összes többi lehetséges filterre. Ezért van az, hogy például egy Up-ra normalizált kép Up-ként megnyitva tökéletesen visszaadja az eredetit, de már Average-nek nyitva sérül, és ez mind az ötre igaz:

Kis felbontású és JPG-nek mentett nézet, az eredeti jóval gazdagabb.

Ezzel nagyjából látjuk, hogy milyen hatásra számíthatunk az egyes filterek esetén (ha a PNG minden sora ugyanazzal a filterrel lenne elkódolva). És már az is megsejthető, ami nekünk egyből nem esett le, hogy mindegy mivel volt elkódolva a kép, úgyis a kikódolás / interpretálás filtere fogja rányomni a bélyegét a glitchelt képre. Így a None oszlopban a képek csak zajosak, a Sub oszlopban inkább vízszintes vonalas, Up-nál függőleges struktúrák, Average-nél átlós, Paethnél meg színkristály-zajos. 

Mint az elején láttuk, két helyen érdemes a PNG-t feszegetni, a filterezett adatnál, illetve a tömörített adatnál. Most már érthető, hogy miért van a PNG-glitcheknek ilyen sajátos megjelenése.

Ha a filterezett adatba piszkálunk, az akkor még eléggé pixelspecifikus, konkrét RGB-értéket ugyan nem (a None filtert leszámítva), de pixel-pozíciót, pixel blokkokat, még precízen tudunk támadni x,y koordináta alapján. A filterezett adatfolyamot képmentés során tömörítik (deflate - zlib) ez lesz a compressed data, amit chunkokba szervez, minden chunknak CRC-t számol, ezután már nem tudunk célzottan és közvetlenül támadni egyes pixeleket, vagy kép-zónákat a deflate algoritmus miatt. Elvileg a Compressed-adat támadás után az új IDAT miatt új CRC-t kell számoltatni, hogy a képnéző programok meg tudják jeleníteni. Mivel az Irfan elég megengedő, és mivel régebb Hex-editorban compressed adatot már hajlítgattunk PNG-ben, ezért ezt a vonalat most nem fejlesztjük tovább. Nem kell hozzá semmi, csak egy Hex-editor és szerencsés találat, hogy ne pont az életfontosságú adatba rondítsunk bele. 

A filterezett adatok támadása,
- leginkább pozíciót (x,y koordinátát) lehet támadni. A None filteren kívül, az összes többinél ezek már nem konkrét RGB adatok, hanem valamely szomszédjától való eltérések. 
- de lehet byte mintázatot  (eltérés-mértéket) is támadni, ekkor a képen a támadott pixel koordinátáját egyáltalán nem célozzuk, csak a tárolt értéket cseréljük, bárhol is talál olyat a képen.
- filter-byte támadása, vagyis a scanlinera használt filter típusának elhazudása, ami miatt megnyitáskor nem a megfelelő algoritmussal fogja interpretálni a képnéző. Pl, Sub volt de Average-re változtatjuk, vagy minden sornál random választunk a lehetséges 5-ből, vagyis az összes permutáció kipróbálható. Ezt láttuk fennebb.
- vagy lehetőség van teljesen saját filter-algoritmus létrehozására is, azzal a korláttal, hogy a képnéző programok csak a fenti 5 filtert ismerik és tudják használni. Tehát, ha egy saját algoritmussal filtereztünk, akkor is egy valid filtert kell megnevezzünk a scanline előtt, és a képnéző ezzel fogja visszaalakítani a képet, vagyis ez az eltérés fogja a torzítást vinni a képbe. 

Ezeknek a támadásoknak a végrehajtására az AI írt nekünk egy cukor kis Python programot, ami lehetővé teszi pixel/pixelblokkok értékeinek a megváltoztatását. Illetve byte-mintázatok támadását és filterbyteok meghamisítását is. (Ezeket akár kombinálva.)

1. Pixelpozíció támadása
A következőben a spéci programunkkal létrehozott egységes filterű képeinket felhasználva (hogy az effektusok ne keveredjenek átláthatatlan módon) a 100,85  (bal felső barna folt közepén) pozíciójú pixelt támadjuk meg 10,100,200-as értékkel (R-ben 10-es eltérést, G-ben 100-as eltérést, B-ben 200-as eltérést okozva)
None filternél a 10,100,200 konkrét RGB értéket jelent, nem eltérést. Egyetlen pixelt átszínezett a barna mezőben, szinte nem is látszik.. 

Sub esetén a hiba jobbra végigcsorog.

Up esetén lefele csorog a hiba.

Average esetén átlósan, üstökösen


Paeth esetén meg a pozíciótól jobbra is, lefele is kumulálódik a hiba.

2. Byteok-mintázatok támadása
Ha visszatekintünk a legelső ábrára, az látszik, hogy az Average-filterezett kép az, ami a leglátványosabban támadható (eléggé roncsol, a Sub vagy Up-hoz visszafogott hatásáshoz képest, de nem annyira, mint a Paeth). Ezért az Average-filterre normalizált képünkkel játszunk most tovább. Mivel a képünk sok azonos/nagyon hasonló színű pixelből áll (színpaletta, ez a dolga) és  PNG mentés törekszik a kis értékek halmozására a scanlineban, ezért ha nagyobb byte értékeket (nagyobb eltéréseket reprezentáló) akarunk megtámadni (lecserélni), szinte alig lesz sérülés a képen, mert kevés pixel fog nagyon eltérni a szomszédaitól. A következőben a 2-3-5-7-10 byteértékeket (eltéréseket) cseréljük le egységesen 150-es eltérésre (egységesen 150-et kap az R, G és a B is).  10-től 2 felé nő a roncsolás mértéke.
10 - 150

7-150

5-150

3-150

2-150


A továbbiakban saját szűrőket fogunk kipróbálni.