SVG में noise texture बनाना
(daniel.do)- जैसे-जैसे वेब illustration सपाट vector से आगे बढ़कर noise texture और lighting·shading इस्तेमाल करने की दिशा में फैल रही है, इसे हल्के और reusable SVG के रूप में लागू करने का तरीका महत्वपूर्ण हो गया है
- मुख्य लक्ष्य है साधारण shapes में texture वाला shadow effect जोड़ना, और उसे Svelte या React component में ले जाकर color और shape बदलकर इस्तेमाल करने योग्य बनाना
- बुनियादी संरचना में
<defs>में shape को एक बार define किया जाता है, फिर<use>से reuse किया जाता है, औरmaskवlinearGradientसे color पर कम निर्भर gradient mask बनाया जाता है - दानेदार texture
<feTurbulence>आधारित SVG filter से बनाया जाता है, और<feComposite>,<feColorMatrix>,<feBlend>को जोड़कर चुने गए fill color के साथ mix किया जाता है - नतीजा इच्छित texture के काफ़ी करीब पहुँचा, लेकिन Safari rendering difference अभी भी मौजूद है, इसलिए browser-वार rendering और अधिक जटिल illustration पर लागू करने के लिए अतिरिक्त adjustment की ज़रूरत है
सिर्फ कोड से SVG में noise texture जोड़ना
- हाल के web design में vector illustration लगातार इस्तेमाल हो रही है, लेकिन साफ-सुथरे flat shapes की तुलना में खुरदुरी दानेदार texture वाली lighting·shading style ज़्यादा नज़र आ रही है
- इस तरह की style को illustration program से SVG के रूप में export किया जा सकता है, लेकिन texture raster के रूप में शामिल हो सकती है या vector का आकार बड़ा हो सकता है
- लक्ष्य है केवल सामान्य SVG spec का उपयोग करके noise वाली textured shadow effect बनाना, और संरचना को component बनाना आसान रहे ऐसा रखना
- reuse के लिए इसे इस तरह बनाया गया है कि shape और color बदलने पर भी वही तरीका काम करे
बुनियादी shape और gradient
- circle या rectangle जैसी SVG basic shapes आसानी से बनाई जा सकती हैं, लेकिन reusable component में fixed-color gradient काफ़ी नहीं होता
- base color के अनुसार बदलने वाला gradient बनाने के लिए mask का उपयोग किया जाता है
- SVG mask काले और सफेद के आधार पर दिखने या छिपने वाले क्षेत्रों को नियंत्रित करता है
- तरीका थोड़ा भ्रमित कर सकता है, लेकिन इसे सरल उदाहरण से शुरू किया जा सकता है
- अगर एक ही circle shape को कई बार इस्तेमाल करना हो, तो
<defs>के अंदर<circle id="shape">define करके<use href="#shape">से reference किया जाता है - यह तरीका दोहराव कम करता है और shape definition को एक जगह रखने वाली DRY संरचना देता है
noise texture बनाने का तरीका
- gradient के ऊपर texture चढ़ाने के लिए SVG filter का उपयोग किया जाता है
- noise generation का काम
<feTurbulence>करता है<feTurbulence>कृत्रिम texture बनाने वाला SVG filter primitive है- मनचाहा एहसास पाने के लिए कई values को adjust करना पड़ता है
- अंतिम filter कई चरणों से गुज़रकर texture को color के साथ blend करता है
<feTurbulence type="fractalNoise" baseFrequency="19.5" numOctaves="10">से noise बनाया जाता है<feComposite>से turbulence result कोSourceAlphaके भीतर composite किया जाता है<feColorMatrix type="luminanceToAlpha">से color variation कम किया जाता है<feBlend mode="color-burn">से original graphic के साथ composite किया जाता है
- filter को अंतिम
<use>element परfilter="url('#noise')"से लागू किया जाता है
अंतिम SVG संरचना
- अंतिम example में
<defs>के अंदर shape, filter, mask और gradient को साथ में define किया गया है - gradient को
linearGradient id="fade"से बनाया गया है0%बिंदु पर काले रंग के साथstop-opacity="0.6"का उपयोग होता है65%और75%बिंदुओं पर सफेद रंग का उपयोग करके opacity को क्रमिक रूप से adjust किया जाता है
- अंतिम shape पर fill color, mask और filter एक साथ लागू होते हैं
fill="hsl(337, 92%, 69%)"mask="url(#gradient)"filter="url('#noise')"
- color जोड़कर और gradient को अधिक सूक्ष्म रूप से adjust करके मनचाहे visual effect के करीब परिणाम हासिल किया जाता है
- पूरा परिणाम Full Demo में देखा जा सकता है, और implementation code repository में प्रकाशित है
परिणाम और सीमाएँ
- अतिरिक्त प्रयोगों के बाद संतोषजनक illustration बनाई गई, लेकिन परिणाम अभी पूरी तरह परिपूर्ण नहीं है
- खासकर Safari में यह दूसरे browsers से अलग render होता है
- संदर्भ के रूप में देखी गई जटिल illustration की तुलना में यह अभी भी सरल है, लेकिन और निखारने पर इसे अधिक स्थितियों में इस्तेमाल किया जा सकता है
- 7 दिसंबर 2023 को जोड़ी गई अतिरिक्त जानकारी के अनुसार, Hacker News पर submit करने के बाद Jimmy Chion की 2021 की CSS-Tricks post Grainy Gradients के बारे में पता चला
- उस लेख में पहुँची हुई technique इस तरीके से मिलती-जुलती लगती है, इसलिए उसे पूरक संदर्भ के रूप में भी देखा जा सकता है
2 टिप्पणियां
उम्मीद के मुताबिक, Safari ने फिर निराश नहीं किया! इसे 2020s का IE कहना भी गलत नहीं होगा।
Hacker News की राय
हाल ही में SVG के साथ काम करते हुए मैं एक drop shadow डालना चाहता था, जो canvas से बनाना मुश्किल था, लेकिन Safari में SVG के अंदर CSS drop shadow काम नहीं करता, इसलिए SVG का native drop shadow filter इस्तेमाल करना पड़ा, और उसका नतीजा भी दूसरे browsers से अलग दिखा
इसका ठोस उदाहरण https://www.einarmagnus.net/pages/logo पर है, जहां JavaScript से Safari detect करके SVG version चालू और CSS version बंद किया गया है
“recursive yin-yang” background https://einarmagnus.net/blog/2020/01/22/finding-the-logo पर है
texture के साथ और experiment करना चाहता हूं, लेकिन Safari में इसका इतना अलग दिखना परेशान करता है। सोचता हूं कि कभी SVG interpretation के तरीके converge होंगे या नहीं
इस विषय पर https://razrfalcon.github.io/notes-on-svg-parsing/ पढ़ने लायक है
SVG library bug reports में “मेरा SVG ठीक से render नहीं हो रहा” जैसा वाक्य अक्सर दिखता है, लेकिन बात यह है कि सही तरह से rendered SVG जैसी कोई चीज़ असल में होती ही नहीं। मतलब यह है कि text, filters, animation जैसी advanced features इस्तेमाल करना शुरू करते ही अलग-अलग renderers में चीज़ें आसानी से टूट जाती हैं
parameters को थोड़ा-सा बदलने भर से scorpion, balance, spruce जैसे काफी अलग design निकल आते हैं, यह बढ़िया है
लेखक जिस term को खोज रहे थे, वह dithering के ज्यादा करीब है। CSS-Tricks का “Grainy Gradients” भी यही technique समझाता है
https://css-tricks.com/grainy-gradients/
CSS से कुछ मिलता-जुलता करने का एक alternative भी है, लेकिन वह पूरी image पर लागू होता है
https://github.com/tomren1/dither-with-css
dithering वह technique है जिसमें smooth high-color-depth image को सीमित colors में quantize करते समय banding कम करने के लिए हर pixel को ऊपर या नीचे की value में से एक probabilistically चुना जाता है। जहां desired color ठीक-ठीक मौजूद हो, वहां यह noise जैसा दिखे, जरूरी नहीं
यहां तो बस uniform noise texture बनता है, और यह असल banding को कम नहीं करता। aesthetic purpose के लिए यह असली dithering से बेहतर दिखता है
हालांकि dithering की तरह यह defects छिपाकर और perceived sharpness बढ़ाकर image quality बेहतर दिखाने का effect दे सकता है
लेखक शायद “flat”, “skeuomorphic”, “italian style” जैसे visual style को बुलाने वाला design term खोज रहे हैं
geometric forms और graininess के combination को देखकर Memphis style याद आता है
इसके बजाय vintage travel poster art याद आता है। उदाहरण: https://www.graphicart-news.com/wp-content/uploads/2012/09/2...
[0] https://en.wikipedia.org/wiki/Stippling
इसे बनाते समय मैंने वह सच में नहीं देखा था, और खुद try करते-करते उसी conclusion पर पहुंचा
याद आता है कि film photographers और filmmakers film grain हटाने की कोशिश करते थे, जबकि digital photographers उसे वापस जोड़ना चाहते दिखते हैं। दूसरे की थाली में घी ज्यादा लगता है
पूरी तरह digital और sterile चीज़ों के बीच, इस page के examples काफी आकर्षक लगते हैं
noise अपने-आप में समस्या नहीं थी; असली सवाल हमेशा यह था कि वह बहुत ज्यादा है या नहीं
क्या कहीं ऐसा मटेरियल है जिसमें यहまとめ किया गया हो कि हर implementation में कौन-सी चीज़ टूटती है? मुझे SVG से अपनी मानसिक सेहत बचाए रखने का तरीका जानना है
हाल ही में मैंने एक जटिल conference poster को SVG में बनाने की गलती कर दी, और अब यह हर browser और program में अलग-अलग render होता है
https://kxygk.github.io/imergination/
बनाते समय मेरा अनुभव यह रहा: SVG को include या link तो किया जा सकता है, लेकिन अगर उसके अंदर फिर कोई दूसरा SVG हो तो वह काम नहीं करता। उदाहरण के लिए poster → diagram → कई plots/maps जैसी structure हो, तो sub-image बदलने पर dynamically update होने वाला SVG practically impossible है
Web browser “security” reasons से embedded/linked images को अपनी मर्ज़ी से display न भी करें। ऊपर वाले link के SVG को अलग tab में खोलने पर यह ठीक से display नहीं होता: https://raw.githubusercontent.com/wiki/kxygk/imergination/ag...
जटिल SVG को PDF में बदलना भी बिना mismatch के handle करना मुश्किल है, और memory भी खत्म हो सकती है। हर SVG-to-PDF converter का result अलग होता है
Inkscape जैसे कई implementations embedded SVG को मनमाने ढंग से raster graphics की तरह treat कर देते थे, और आखिर तक यह pinpoint नहीं कर पाया कि ऐसा कब होता है। PNG में render करते समय Inkscape द्वारा DPI setting को sub-images तक propagate न करने की समस्या भी थी
बढ़िया है। लगता है Inkscape Filters menu के कई effects के ज़रिए इस तरह का noise जोड़ना support करता है। Plain SVG में export करके code देखा तो confirm हुआ कि यह
feTurbulenceइस्तेमाल करता हैतुलना के लिए Affinity Designer 2 का noise fill भी try किया, लेकिन exported SVG में noise base64 JPEG image के रूप में embedded था
Adobe license को justify करना मुश्किल है और InkScape भी मुझे खास suit नहीं करता; ऐसे में इन अजीब quirks को छोड़ दें तो Designer एक perfect alternative था
“ApeFest” website[1] में भी dynamic noise था, इसलिए मैंने CSS देखी। वही event site जिसने attendees की retinas को UV से जला दिया था
असल में यह tiled PNG overlay[2] इस्तेमाल करता है और CSS animation से उसे “random” जैसा हिलाता है। edit: असल में लगता है यह JS से move होता है। काफी low-tech है, लेकिन काम करता है
[1] https://apefest.com/
[2] https://framerusercontent.com/images/rR6HYXBrMmX4cRpXfXUOvpv...
मैं ऐसे SVG filters कई बार इस्तेमाल करना चाहता था, लेकिन समस्या यह है कि engine और zoom scale के हिसाब से presentation काफी बदल जाती है
इसलिए इन्हें केवल उन subtle effects के लिए इस्तेमाल किया जा सकता है जहाँ inaccuracy बहुत मायने नहीं रखती, और अंत में अफसोस के साथ बार-बार raster पर लौटना पड़ता है
साथ ही pixel-level पर काम करने की वजह से
feDisplacementMapजैसी चीज़ें anti-aliasing खराब कर देती हैं, और जिन स्थितियों में इन्हें इस्तेमाल करने का मन होता है उनमें से लगभग आधी को बिगाड़ देती हैंPerlin noise और उसका successor fractal noise realism या organic feel जोड़ने में cost के मुकाबले जबरदस्त असर देते हैं
उदाहरण के लिए Aladdin (1992) में Cave of Wonders से escape वाले scene में इसे बहुत प्रभावी ढंग से इस्तेमाल होते देखा जा सकता है
मुझे नहीं पता यह असल में कैसा दिखना चाहिए, लेकिन मेरे phone पर यह noise के बिना सिर्फ smooth gradient जैसा दिखता है
effect पसंद आया, लेकिन क्या इसे zoom scale से independent बनाने का कोई तरीका है?
इसी से related, लगता है यह randomness भी जोड़ता है; क्या इसमें seed देने का कोई तरीका है? जैसे किसी specific size पर एक correct rendering result define किया जा सके तो अच्छा होगा
seedattribute है, और random function algorithm भी spec में C code की 186 lines में defined है[0], इसलिए theory में अलग-अलग implementations में एक जैसा result आना चाहिएहालांकि code देखने पर इसमें floating-point operations इस्तेमाल होते हैं, और मेरी जानकारी में यह implementation-defined होता है, इसलिए platforms के बीच अलग behavior होने की संभावना दिखती है
[0]: https://drafts.fxtf.org/filter-effects/#elementdef-feturbule...