यदि आपको एक पिक्सेल के रंग के बजाय एक आयताकार क्षेत्र का औसत रंग प्राप्त करने की आवश्यकता है, तो कृपया एक दूसरे से नज़र डालें:
Average जावास्क्रिप्ट - एक छवि के एक निश्चित क्षेत्र से औसत रंग प्राप्त करें
वैसे भी, दोनों एक ही तरह से किए जाते हैं:
Can एक छवि या कैनवास से एक एकल पिक्सेल का रंग / मूल्य प्राप्त करना
एकल पिक्सेल का रंग प्राप्त करने के लिए, आप सबसे पहले उस चित्र को एक कैनवास पर खींचेंगे, जिसे आप पहले ही कर चुके हैं:
const image = document.getElementById('image');
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
const width = image.width;
const height = image.height;
canvas.width = width;
canvas.height = height;
context.drawImage(image, 0, 0, width, height);
और फिर इस तरह एकल पिक्सेल का मूल्य प्राप्त करें:
const data = context.getImageData(X, Y, 1, 1).data;
D एक बार में सभी ImageData प्राप्त करके गति को तेज करना
संपूर्ण छवि के मान प्राप्त करने के लिए आपको इसी CanvasRenderingContext2D.getImageData () का उपयोग करने की आवश्यकता है , जो आप इसके तीसरे और चौथे परिमार्जन को बदलकर करते हैं। उस फ़ंक्शन का हस्ताक्षर है:
ImageData ctx.getImageData(sx, sy, sw, sh);
sx
: आयत के ऊपरी बाएँ कोने का x निर्देशांक जहाँ से ImageData निकाला जाएगा।
sy
: आयत के ऊपरी बाएँ कोने का y निर्देशांक जिसमें से ImageData निकाला जाएगा।
sw
: आयत की चौड़ाई जिससे ImageData निकाला जाएगा।
sh
: आयत की ऊँचाई जिससे ImageData निकाला जाएगा।
आप देख सकते हैं कि यह एक ImageData
वस्तु देता है , जो कुछ भी है । यहां महत्वपूर्ण बात यह है कि उस वस्तु में एक .data
संपत्ति होती है जिसमें हमारे सभी पिक्सेल मूल्य होते हैं।
हालांकि, ध्यान दें कि .data
संपत्ति 1-आयाम है Uint8ClampedArray
, जिसका अर्थ है कि सभी पिक्सेल के घटक समतल हो गए हैं, इसलिए आपको ऐसा कुछ मिल रहा है जो इस तरह दिखता है:
मान लीजिए कि आपकी 2x2 छवि इस प्रकार है:
RED PIXEL | GREEN PIXEL
BLUE PIXEL | TRANSPARENT PIXEL
फिर, आप उन्हें इस तरह मिलेगा:
[ 255, 0, 0, 255, 0, 255, 0, 255, 0, 0, 255, 255, 0, 0, 0, 0 ]
| RED PIXEL | GREEN PIXEL | BLUE PIXEL | TRANSPAERENT PIXEL |
| 1ST PIXEL | 2ND PIXEL | 3RD PIXEL | 4TH PIXEL |
चूंकि कॉलिंग getImageData
एक धीमा ऑपरेशन है, आप इसे केवल एक बार कॉल कर सकते हैं ताकि सभी छवि ( sw
= छवि चौड़ाई, sh
= छवि ऊंचाई) का डेटा प्राप्त किया जा सके ।
फिर, ऊपर के उदाहरण में, आप के घटकों का उपयोग करना चाहते हैं TRANSPARENT PIXEL
, यह है कि, के स्थान पर एक x = 1, y = 1
काल्पनिक छवि के हैं, तो आप अपनी पहली सूचकांक मिलेगा i
अपने में ImageData
के data
रूप में संपत्ति:
const i = (y * imageData.width + x) * 4;
✨ आइए इसे एक्शन में देखें
const solidColor = document.getElementById('solidColor');
const alphaColor = document.getElementById('alphaColor');
const solidWeighted = document.getElementById('solidWeighted');
const solidColorCode = document.getElementById('solidColorCode');
const alphaColorCode = document.getElementById('alphaColorCode');
const solidWeightedCOde = document.getElementById('solidWeightedCode');
const brush = document.getElementById('brush');
const image = document.getElementById('image');
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
const width = image.width;
const height = image.height;
const BRUSH_SIZE = brush.offsetWidth;
const BRUSH_CENTER = BRUSH_SIZE / 2;
const MIN_X = image.offsetLeft + 4;
const MAX_X = MIN_X + width - 1;
const MIN_Y = image.offsetTop + 4;
const MAX_Y = MIN_Y + height - 1;
canvas.width = width;
canvas.height = height;
context.drawImage(image, 0, 0, width, height);
const imageDataData = context.getImageData(0, 0, width, height).data;
function sampleColor(clientX, clientY) {
if (clientX < MIN_X || clientX > MAX_X || clientY < MIN_Y || clientY > MAX_Y) {
requestAnimationFrame(() => {
brush.style.transform = `translate(${ clientX }px, ${ clientY }px)`;
solidColorCode.innerText = solidColor.style.background = 'rgb(0, 0, 0)';
alphaColorCode.innerText = alphaColor.style.background = 'rgba(0, 0, 0, 0.00)';
solidWeightedCode.innerText = solidWeighted.style.background = 'rgb(0, 0, 0)';
});
return;
}
const imageX = clientX - MIN_X;
const imageY = clientY - MIN_Y;
const i = (imageY * width + imageX) * 4;
const R = imageDataData[i];
const G = imageDataData[i + 1];
const B = imageDataData[i + 2];
const A = imageDataData[i + 3] / 255;
const iA = 1 - A;
const wR = (R * A + 255 * iA) | 0;
const wG = (G * A + 255 * iA) | 0;
const wB = (B * A + 255 * iA) | 0;
requestAnimationFrame(() => {
brush.style.transform = `translate(${ clientX }px, ${ clientY }px)`;
solidColorCode.innerText = solidColor.style.background
= `rgb(${ R }, ${ G }, ${ B })`;
alphaColorCode.innerText = alphaColor.style.background
= `rgba(${ R }, ${ G }, ${ B }, ${ A.toFixed(2) })`;
solidWeightedCode.innerText = solidWeighted.style.background
= `rgb(${ wR }, ${ wG }, ${ wB })`;
});
}
document.onmousemove = (e) => sampleColor(e.clientX, e.clientY);
sampleColor(MIN_X, MIN_Y);
body {
margin: 0;
height: 100vh;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
cursor: none;
font-family: monospace;
overflow: hidden;
}
#image {
border: 4px solid white;
border-radius: 2px;
box-shadow: 0 0 32px 0 rgba(0, 0, 0, .25);
width: 150px;
box-sizing: border-box;
}
#brush {
position: absolute;
top: 0;
left: 0;
pointer-events: none;
width: 1px;
height: 1px;
mix-blend-mode: exclusion;
border-radius: 100%;
}
#brush::before,
#brush::after {
content: '';
position: absolute;
background: magenta;
}
#brush::before {
top: -16px;
left: 0;
height: 33px;
width: 100%;
}
#brush::after {
left: -16px;
top: 0;
width: 33px;
height: 100%;
}
#samples {
position: relative;
list-style: none;
padding: 0;
width: 250px;
}
#samples::before {
content: '';
position: absolute;
top: 0;
left: 27px;
width: 2px;
height: 100%;
background: black;
border-radius: 1px;
}
#samples > li {
position: relative;
display: flex;
flex-direction: column;
justify-content: center;
padding-left: 56px;
}
#samples > li + li {
margin-top: 8px;
}
.sample {
position: absolute;
top: 50%;
left: 16px;
transform: translate(0, -50%);
display: block;
width: 24px;
height: 24px;
border-radius: 100%;
box-shadow: 0 0 16px 4px rgba(0, 0, 0, .25);
margin-right: 8px;
}
.sampleLabel {
font-weight: bold;
margin-bottom: 8px;
}
.sampleCode {
}
<img id="image" src="data:image/gif;base64,R0lGODlhSwBLAPEAACMfIO0cJAAAAAAAACH/C0ltYWdlTWFnaWNrDWdhbW1hPTAuNDU0NTUAIf4jUmVzaXplZCBvbiBodHRwczovL2V6Z2lmLmNvbS9yZXNpemUAIfkEBQAAAgAsAAAAAEsASwAAAv+Uj6mb4A+QY7TaKxvch+MPKpC0eeUUptdomOzJqnLUvnFcl7J6Pzn9I+l2IdfII8DZiCnYsYdK4qRTptAZwQKRVK71CusOgx2nFRrlhMu+33o2NEalC6S9zQvfi3Mlnm9WxeQ396F2+HcQsMjYGEBRVbhy5yOp6OgIeVIHpEnZyYCZ6cklKBJX+Kgg2riqKoayOWl2+VrLmtDqBptIOjZ6K4qAeSrL8PcmHExsgMs2dpyIxPpKvdhM/YxaTMW2PGr9GP76BN3VHTMurh7eoU14jsc+P845Vn6OTb/P/I68iYOfwGv+JOmRNHBfsV5ujA1LqM4eKDoNvXyDqItTxYX/DC9irKBlIhkKGPtFw1JDiMeS7CqWqySPZcKGHH/JHGgIpb6bCl1O0LmT57yCOqoI5UcU0YKjPXmFjMm0ZQ4NIVdGBdZRi9WrjLxJNMY1Yr4dYeuNxWApl1ALHb+KDHrTV1owlriedJgSr4Cybu/9dFiWYAagsqAGVkkzaZTAuqD9ywKWMUG9dCO3u2zWpVzIhpW122utZlrHnTN+Bq2Mqrlnqh8CQ+0Mrq3Kc++q7eo6dlB3rLuh3abPVbbbI2mxBdhWdsZhid8cr0oy9F08q0k5FXSadiyL1mF5z51a8VsQOp3/LlodkBfzmzWf2bOrtfzr48k/1hupDaLa9rUbO+zlwndfaOCURAXRNaCBqBT2BncJakWfTzSYkmCEFr60RX0V8sKaHOltCBJ1tAAFYhHaVVbig3jxp0IBADs=" >
<div id="brush"></div>
<ul id="samples">
<li>
<span class="sample" id="solidColor"></span>
<div class="sampleLabel">solidColor</div>
<div class="sampleCode" id="solidColorCode">rgb(0, 0, 0)</div>
</li>
<li>
<span class="sample" id="alphaColor"></span>
<div class="sampleLabel">alphaColor</div>
<div class="sampleCode" id="alphaColorCode">rgba(0, 0, 0, 0.00)</div>
</li>
<li>
<span class="sample" id="solidWeighted"></span>
<div class="sampleLabel">solidWeighted (with white)</div>
<div class="sampleCode" id="solidWeightedCode">rgb(0, 0, 0)</div>
</li>
</ul>
⚠️ ध्यान दें कि मैं एक छोटे डेटा यूआरआई का उपयोग कर रहा हूं Cross-Origin
यदि मैं एक बाहरी छवि या एक उत्तर को शामिल करता हूं, तो अगर मैं एक लंबे डेटा यूआरआई का उपयोग करने की कोशिश करता हूं तो यह एक बड़ा सवाल है।
🕵️ ये रंग अजीब लगते हैं, नहीं?
यदि आप तारांकन आकृति की सीमाओं के चारों ओर कर्सर ले जाते हैं, तो आप देखेंगे कि कभी-कभी avgSolidColor
लाल होता है, लेकिन आप जिस पिक्सेल का नमूना ले रहे हैं वह सफेद दिखता है। ऐसा इसलिए है क्योंकि भले ही R
उस पिक्सेल के लिए घटक अधिक हो, अल्फा चैनल कम है, इसलिए रंग वास्तव में लाल रंग की लगभग पारदर्शी छाया है, लेकिन avgSolidColor
उस पर ध्यान नहीं देता है।
दूसरी ओर, avgAlphaColor
गुलाबी दिखता है। खैर, यह वास्तव में सच नहीं है, यह सिर्फ गुलाबी दिखता है क्योंकि हम अब अल्फा चैनल का उपयोग कर रहे हैं, जो इसे अर्ध-पारदर्शी बनाता है और हमें पृष्ठ की पृष्ठभूमि को देखने की अनुमति देता है, जो इस मामले में सफेद है।
🎨 अल्फा-भारित रंग
फिर, हम इसे ठीक करने के लिए क्या कर सकते हैं? ठीक है, यह पता चलता है कि हमें अपने नए नमूने के घटकों की गणना करने के लिए अल्फा चैनल और इसके व्युत्क्रम को भार के रूप में उपयोग करने की आवश्यकता है, इस मामले में इसे सफेद के साथ विलय कर दिया जाता है, क्योंकि यह वह रंग है जिसे हम पृष्ठभूमि के रूप में उपयोग करते हैं।
इसका मतलब है कि यदि कोई पिक्सेल है R, G, B, A
, जहां A
अंतराल में है [0, 1]
, तो हम अल्फा चैनल के व्युत्क्रम की गणना करेंगे iA
, और भारित नमूने के घटक निम्नानुसार होंगे:
const iA = 1 - A;
const wR = (R * A + 255 * iA) | 0;
const wG = (G * A + 255 * iA) | 0;
const wB = (B * A + 255 * iA) | 0;
ध्यान दें कि एक पिक्सेल कितना पारदर्शी है ( A
0 के करीब), हल्का रंग।