नमस्कार दोस्तों, आज आइए इमेज रॉ बाइट्स के साथ खेलते हैं। मैं जो करने जा रहा हूं वह है, छवि के कच्चे पिक्सेल बाइट्स में हेरफेर करना, और कुछ मूर्खतापूर्ण बनाना, यह करने के लिए मज़ेदार चीज़ है। इस लेख में कुछ सिद्धांत के साथ-साथ व्यावहारिक कार्यान्वयन भी शामिल है, तो चलिए…
जैसा कि हम जानते हैं कि एक छवि एक साथ पिक्सेल के समूह से बनती है, पिक्सेल कुछ और नहीं बल्कि RGB (लाल, हरा, नीला) या RGBA (लाल, हरा, नीला) का संयोजन है। अल्फ़ा) प्रत्येक 1 बाइट लें।
जिन छवियों को हम पीएनजी या जेपीजी जैसे एक्सटेंशन के साथ देखते हैं, वे छवि के संपीड़ित प्रारूप हैं, पीएनजी दोषरहित है कि पीएनजी पिक्सेल खोए बिना संपीड़ित करने के लिए DEFLATE जैसे एल्गोरिदम का उपयोग करता है और जेपीजी हानिपूर्ण संपीड़न है जो यह करेगा कुछ पिक्सेल खो जाने से छवि गुणवत्ता में कुछ हानि होगी, यदि हम छवि को संपीड़न के बिना देखना चाहते हैं तो हमें छवि को BMP (बिटमैप छवि फ़ाइल) में परिवर्तित करना होगा या कुछ अन्य भी हैं प्रारूपों में, यदि हम इसे परिवर्तित करते हैं तो हमें असंपीड़ित छवि प्राप्त होती है। लेकिन हमें इसकी आवश्यकता नहीं है, हम उन कच्चे बाइट्स को निकालेंगे और उनके साथ खेलेंगे और हम उन्हें फिर से पीएनजी या जेपीजी में बदल देंगे।
सबसे पहले, क्लाइंट को छवियां अपलोड करने के लिए सेट करें, मैं इसके लिए एक सरल प्रतिक्रिया एप्लिकेशन सेट करूंगा
import axios from "axios"; import { useState } from "react"; import "./App.css"; function App() { const [img, setImg] = useState(null); const [pending, setPending] = useState(false); const handleImg = (e) => { setImg(e.target.files[0]); }; const handleSubmit = async (e) => { e.preventDefault(); if (!img) return; const formData = new FormData(); formData.append("img", img); try { setPending(true); const response = await axios.post("http://localhost:4000/img", formData); console.log(response.data); } catch (error) { console.log("Error uploading image:", error); } finally { setPending(false); } }; return (); } export default App;
तो यह सरल कोड है, छवियों को अपलोड करने के लिए, मुख्य भाग सर्वर साइड पर है।
अब छवि बाइट्स की मैन्युअल रूप से गणना करें और सर्वर-साइड कोड से जांच करें।
मैंने नीचे दी गई छवि चुनी है।
छवि मेरे पिछले लेख थंबनेल से है। तो यह एक पीएनजी फ़ाइल है, यदि हम प्रॉपर्टी सेक्शन में जाते हैं, तो हम छवि की चौड़ाई और ऊंचाई देख सकते हैं। इसके लिए चौड़ाई और ऊंचाई 722 x 407 है जो 293854 पिक्सल के बराबर है, साथ ही यह बाइट्स की कुल संख्या नहीं है, यह सिर्फ पिक्सल की कुल संख्या है। जैसा कि हम जानते हैं कि प्रत्येक पिक्सेल या तो 3 या 4 बाइट्स, RGB या RGBA है। इसलिए यदि उपरोक्त छवि आरजीबी है तो कुल बाइट्स 722 x 407 x 3 = 881562 होंगे या यदि छवि में अल्फा चैनल है, तो कुल बाइट्स 722 x 407 x 4 = 1175416 होंगे।
आइए सर्वर साइड पर कुछ बात करते हैं, मैं नोड जेएस का उपयोग कर रहा हूं।
मल्टीफ़ॉर्म डेटा को पार्स करने के लिए मल्टर नामक एक लाइब्रेरी है।
app.post("/img", upload.single("img"), async (req, res) => { const arr = req.file.buffer console.log(arr.length) //output: 30929 res.send("success") });
हम छवि बाइट्स को बफ़र सरणी में संग्रहीत करते हैं, यदि हम बफ़र सरणी की लंबाई लेते हैं तो उत्तर 30929 है, सरणी में इतने सारे बाइट्स हैं, लेकिन प्रतीक्षा करें बाइट्स की कुल संख्या 1175416 होनी चाहिए, है ना? यहां क्या होता है कि मल्टर कुछ संपीड़न या कुछ भी नहीं करता है, यह बस उपयोगकर्ता से छवि प्राप्त करता है और इसे बफर में संग्रहीत करता है, इसलिए हमने पीएनजी फ़ाइल अपलोड की है, जो बफर आप देख रहे हैं वह उसी आकार का है पीएनजी छवि का आकार.
अब संपीड़ित छवि बाइट में बाइट्स बदलें।
app.post("/img", upload.single("img"), async (req, res) => { const arr = req.file.buffer; console.log("multer " arr.length); fs.writeFile("output.png", arr, (err) => { console.log(err); }); res.send("successfull"); });
मैंने मौजूदा छवि के साथ एक नई छवि बनाने के लिए एफएस का उपयोग किया। तो अब यदि हम प्रथम-बाइट arr[0] = 231 बदलते हैं, तो छवि नहीं खुलेगी।
क्योंकि पहले कुछ बाइट्स मेटाडेटा के लिए आरक्षित हैं, इसलिए यदि हम उन मेटाडेटा को बदलते हैं, और फिर छवि दूषित हो सकती है।
तो आइए 500वें बाइट पर जाएं। arr[500] = 123, फिर छवि लिखें। लेकिन अब, छवि टूट गई है, हमें सीधे संपीड़ित छवि बाइट्स में हेरफेर नहीं करना चाहिए क्योंकि यह संपीड़न एल्गोरिदम एन्कोडेड डेटा को बदल सकता है।
हमें छवि से कच्चे बाइट्स की आवश्यकता है, और फिर हम स्वतंत्र रूप से बाइट्स में हेरफेर कर सकते हैं, और उसके लिए, हम एक sharp लाइब्रेरी का उपयोग कर सकते हैं।
एनपीएम इंस्टाल शार्प
शार्प स्थापित करें, अब मैं उन तर्कों को संभालने के लिए एक अलग फ़ाइल बनाऊंगा,
sharp.js
export async function convert(buffer) { try { const data = await sharp(buffer).metadata(); console.log(data) }catch(err){ console.log(err) } }
यह एक एसिंक फ़ंक्शन है, अब हमारे द्वारा अपलोड किए गए पीएनजी से मेटाडेटा प्राप्त करें।
{ format: 'png', size: 30929, width: 722, height: 407, space: 'srgb', channels: 4, depth: 'uchar', density: 72, isProgressive: false, hasProfile: false, hasAlpha: true }
यह छवि से मेटाडेटा है, जैसा कि हम अंतिम डेटा देख सकते हैं hasAlpha: true इसलिए इसमें अल्फा चैनल है, इसलिए प्रत्येक पिक्सेल 4 बाइट्स है।
अब छवि से कच्चे बाइट्स प्राप्त करें।
const rawBytes = await sharp(buffer) .raw() .toBuffer({ resolveWithObject: true }); console.log(rawBytes.data.length) //1175416
अब हम देख सकते हैं कि सरणी की लंबाई हमारी गणना के बराबर है। तो इस छवि में 1175416 बाइट्स हैं। अब हम स्वतंत्र हैं.. किसी भी बाइट्स को बदलने के लिए, अब मेटाडेटा बफर में संग्रहीत नहीं है, बफर में केवल छवि के कच्चे बाइट्स हैं।
आइए केवल एक पिक्सेल को लाल में बदलें।
rawBytes.data[0] = 225; //red rawBytes.data[1] = 10; //green rawBytes.data[2] = 10; //blue rawBytes.data[3] = Math.floor(0.8 * 255); //alpha
जैसा कि हम कर सकते हैं एक पिक्सेल को लाल रंग में बदल दिया जाता है, हमें पिक्सेल परिवर्तन देखने के लिए छवि पर ज़ूम इन करना होगा।
अब छवि को विभाजित करें और रंग बदलें, ऊपर का आधा हिस्सा पीला है और निचला आधा हरा है
const div = rawBytes.data.length / 2; for (let i = 0; iहम लूप को 4 गुना बढ़ा रहे हैं क्योंकि हम प्रत्येक पुनरावृत्ति पर एक पिक्सेल बदल रहे हैं। अब आउटपुट इस तरह होगा।
हम इस छवि में पारदर्शिता देख सकते हैं क्योंकि अल्फा चैनल 0.8 पर सेट है
छवि लिखने के लिए मैं बताना भूल गया, नई छवि लिखने के लिए हमें fs की आवश्यकता नहीं है, हम शार्प का ही उपयोग कर सकते हैं।
await sharp(rawBytes.data, { raw: { width: data.width, height: data.height, channels: data.channels, }, }) .png() .toFile("demo.png");हम उसी मेटाडेटा के साथ नई छवि तैयार कर रहे हैं।
यहां पूरा सर्वर साइड कोड है,
//index.js import express from "express"; import dotenv from "dotenv"; import multer from "multer"; import cors from "cors"; import { convert } from "./sharp.js"; const app = express(); dotenv.config(); app.use(cors({ origin: "http://localhost:5173" })); const storage = multer.memoryStorage(); const upload = multer(); app.post("/img", upload.single("img"), async (req, res) => { const arr = req.file.buffer; await convert(arr); res.send("successful"); }); app.listen(process.env.PORT, () => { console.log("server started"); });//sharp.js import sharp from "sharp"; export async function convert(buffer) { try { const data = await sharp(buffer).metadata(); console.log(data); //raw data const rawBytes = await sharp(buffer) .raw() .toBuffer({ resolveWithObject: true }); console.log(rawBytes.data.length); const div = rawBytes.data.length / 2; for (let i = 0; iतो यह बात है, हमने बस उन पिक्सेल के साथ खेला। और अंत में यह लेख थंबनेल लूप में इस एक पंक्ति के साथ बनाया गया है।
rawBytes.data[i] = Math.floor(Math.random()*256)मैंने बस प्रत्येक बाइट को यादृच्छिक रूप से बदल दिया है?
पूरे कोड के लिए मेरा रेपो देखें: पिक्सेल-बाइट-हेरफेर
यदि कोई गलती हो तो कृपया टिप्पणी करें
धन्यवाद!!!
अस्वीकरण: उपलब्ध कराए गए सभी संसाधन आंशिक रूप से इंटरनेट से हैं। यदि आपके कॉपीराइट या अन्य अधिकारों और हितों का कोई उल्लंघन होता है, तो कृपया विस्तृत कारण बताएं और कॉपीराइट या अधिकारों और हितों का प्रमाण प्रदान करें और फिर इसे ईमेल पर भेजें: [email protected] हम इसे आपके लिए यथाशीघ्र संभालेंगे।
Copyright© 2022 湘ICP备2022001581号-3