छवि रूपांतरण के लिए बाइट सरणी


101

मैं एक बाइट सरणी को एक छवि में बदलना चाहता हूं।

यह मेरा डेटाबेस कोड है जहां से मुझे बाइट सरणी मिलती है:

public void Get_Finger_print()
{
    try
    {
        using (SqlConnection thisConnection = new SqlConnection(@"Data Source=" + System.Environment.MachineName + "\\SQLEXPRESS;Initial Catalog=Image_Scanning;Integrated Security=SSPI "))
        {
            thisConnection.Open();
            string query = "select pic from Image_tbl";// where Name='" + name + "'";
            SqlCommand cmd = new SqlCommand(query, thisConnection);
            byte[] image =(byte[]) cmd.ExecuteScalar();
            Image newImage = byteArrayToImage(image);
            Picture.Image = newImage;
            //return image;
        }
    }
    catch (Exception) { }
    //return null;
}

मेरा रूपांतरण कोड:

public Image byteArrayToImage(byte[] byteArrayIn)
{
    try
    {
        MemoryStream ms = new MemoryStream(byteArrayIn,0,byteArrayIn.Length);
        ms.Write(byteArrayIn, 0, byteArrayIn.Length);
        returnImage = Image.FromStream(ms,true);//Exception occurs here
    }
    catch { }
    return returnImage;
}

जब मैं एक टिप्पणी के साथ लाइन पर पहुंचता हूं, तो निम्न अपवाद होता है: Parameter is not valid.

जो भी इस अपवाद का कारण बन रहा है, उसे मैं कैसे ठीक कर सकता हूं?


क्या आपने जाँच की है कि आपकी क्वेरी में छवि बाइट्स मान्य हैं? आप सत्यापित करने के लिए एक File.WriteAllBytes ("myimage.jpg", byteArrayIn) कर सकते हैं।
होल्स्टेब्रो

जवाबों:


110

आप अपनी मेमोरी स्ट्रीम को दो बार लिख रहे हैं, साथ ही आप उपयोग के बाद स्ट्रीम को डिस्पोज़ नहीं कर रहे हैं। आप छवि डीकोडर को एम्बेडेड रंग सुधार लागू करने के लिए भी कह रहे हैं।

इसके बजाय यह प्रयास करें:

using (var ms = new MemoryStream(byteArrayIn))
{
    return Image.FromStream(ms);
}

नई MemoryStream (byteArrayIn, गलत): आप यह भी स्पष्ट रूप से प्रारंभ करने के बाद स्मृति धारा गैर लिखने योग्य बना सकता है
Holstebroe

28
यह छवि के लिए MSDN में एक विनिर्देश का उल्लंघन करता है। Stream (), जहाँ यह कहता है कि "आपको छवि के जीवनकाल के लिए स्ट्रीम को खुला रखना चाहिए।" यह भी देखें stackoverflow.com/questions/3290060/...
RenniePet

81

शायद मुझे कुछ याद आ रहा है, लेकिन मेरे लिए यह एक-लाइनर एक बाइट सरणी के साथ ठीक काम करता है जिसमें एक JPEG फ़ाइल की छवि होती है।

Image x = (Bitmap)((new ImageConverter()).ConvertFrom(jpegByteArray));

संपादित करें:

इस उत्तर के एक अद्यतन संस्करण के लिए यहां देखें: बाइट सरणी में छवि कैसे बदलें


AAAh धन्यवाद, अंत में एक अच्छा जवाब। मेमोरी स्ट्रीम के साथ इतने सारे उत्तर क्यों, इससे मुझे इतनी समस्या होती है। आपका बहुत बहुत धन्यवाद !
जूलियन 50

अच्छा उत्तर! इसका उपयोग एक अलग फ़ंक्शन में किया जा सकता है जबकि
मेमोरीस्ट्रीम

20
public Image byteArrayToImage(byte[] bytesArr)
{
    using (MemoryStream memstr = new MemoryStream(bytesArr))
    {
        Image img = Image.FromStream(memstr);
        return img;
    }
}

हालांकि यह आम तौर पर एक अच्छा विचार नहीं है, मैंने मेमोरी स्ट्रीम से पहले GC.Collect () डाला। मैं स्मृति से बाहर चल रहा था जब मैंने मेमोरी में बायटियर के रूप में कई बड़ी ग्राफिक फ़ाइलों को लोड किया और फिर देखने के दौरान उन्हें छवियों में बदल दिया।
कायट

9

मैं यह नोट करना चाहूंगा कि @ isaias-b द्वारा प्रदान समाधान में एक बग है।

वह समाधान मान लेता है कि strideपंक्ति की लंबाई के बराबर है। लेकिन यह हमेशा सच नहीं होता है। GDI द्वारा निष्पादित मेमोरी संरेखण के कारण, स्ट्राइड अधिक हो सकता है फिर पंक्ति की लंबाई। इस पर ध्यान दिया जाना चाहिए। अन्यथा अवैध रूप से स्थानांतरित की गई छवि उत्पन्न हो जाएगी। प्रत्येक पंक्ति में पैडिंग बाइट्स की अनदेखी की जाएगी।

स्ट्राइड पिक्सल की एक पंक्ति (एक स्कैन लाइन) की चौड़ाई है, जो चार-बाइट की सीमा तक गोल है।

निश्चित कोड:

using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;

public static class ImageExtensions
{
    public static Image ImageFromRawBgraArray(this byte[] arr, int width, int height, PixelFormat pixelFormat)
    {
        var output = new Bitmap(width, height, pixelFormat);
        var rect = new Rectangle(0, 0, width, height);
        var bmpData = output.LockBits(rect, ImageLockMode.ReadWrite, output.PixelFormat);

        // Row-by-row copy
        var arrRowLength = width * Image.GetPixelFormatSize(output.PixelFormat) / 8;
        var ptr = bmpData.Scan0;
        for (var i = 0; i < height; i++)
        {
            Marshal.Copy(arr, i * arrRowLength, ptr, arrRowLength);
            ptr += bmpData.Stride;
        }

        output.UnlockBits(bmpData);
        return output;
    }
}

यह वर्णन करने के लिए कि यह किस ओर ले जा सकता है, चलो PixelFormat.Format24bppRgbढाल छवि बनाएँ 101x101:

var width = 101;
var height = 101;
var gradient = new byte[width * height * 3 /* bytes per pixel */];
for (int i = 0, pixel = 0; i < gradient.Length; i++, pixel = i / 3)
{
    var x = pixel % height;
    var y = (pixel - x) / width;
    gradient[i] = (byte)((x / (double)(width - 1) + y / (double)(height - 1)) / 2d * 255);
}

यदि हम द्वारा इंगित की गई पते के अनुसार संपूर्ण सरणी की प्रतिलिपि बनाएँगे bmpData.Scan0, तो हमें निम्नलिखित छवि मिलेगी। इमेज शिफ्टिंग क्योंकि इमेज का हिस्सा पैडिंग बाइट्स को लिखा गया था, जिसे नजरअंदाज कर दिया गया था। यही कारण है कि अंतिम पंक्ति अपूर्ण है:

नजरअंदाज कर दिया

लेकिन अगर हम bmpData.Strideमूल्य के अनुसार पंक्ति-दर-पंक्ति स्थानांतरण गंतव्य सूचक की प्रतिलिपि बनाएंगे, तो वैध imaged उत्पन्न हो जाएगा:

खाते में लिया गया

स्ट्राइड भी नकारात्मक हो सकता है:

यदि स्ट्राइड सकारात्मक है, तो बिटमैप टॉप-डाउन है। यदि स्ट्राइड नकारात्मक है, तो बिटमैप नीचे-ऊपर है।

लेकिन मैंने ऐसी छवियों के साथ काम नहीं किया और यह मेरे नोट से परे है।

संबंधित उत्तर: सी # - आरजीबी बफर सी ++ से अलग बिटमैप से


6

सभी प्रस्तुत उत्तर मान लेते हैं कि बाइट सरणी में एक ज्ञात फ़ाइल प्रारूप प्रतिनिधित्व में डेटा होता है, जैसे: gif, png या jpg। लेकिन मुझे हाल ही में एक समस्या को हल करने की कोशिश की गई थी byte[], जिसमें रेखीयकृत बीजीआरए जानकारी, Imageवस्तुओं में कुशलता से शामिल थी । निम्नलिखित कोड एक Bitmapवस्तु का उपयोग करके इसे हल करता है ।

using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
public static class Extensions
{
    public static Image ImageFromRawBgraArray(
        this byte[] arr, int width, int height)
    {
        var output = new Bitmap(width, height);
        var rect = new Rectangle(0, 0, width, height);
        var bmpData = output.LockBits(rect, 
            ImageLockMode.ReadWrite, output.PixelFormat);
        var ptr = bmpData.Scan0;
        Marshal.Copy(arr, 0, ptr, arr.Length);
        output.UnlockBits(bmpData);
        return output;
    }
}

यह एक समाधान का थोड़ा बदलाव है जो इस साइट पर पोस्ट किया गया था ।


एक संदर्भ के रूप में MSDN: Bitmap (Int32, Int32): "यह कंस्ट्रक्टर Format32bppArgb के PixelFormat एन्यूमरेशन वैल्यू के साथ एक बिटमैप बनाता है।", जिसका अर्थ है बाइट [0] नीला है, बाइट [1] हरा है, बाइट [2] लाल है। , बाइट [3] अल्फा है, बाइट [4] नीला है, और इसी तरह।
ब्रैक

1
आवश्यक "सभी" का उपयोग करके जोड़ने के लिए धन्यवाद। ज्यादातर लोग यह भूल जाते हैं और यह उन सभी को खोजने के लिए एक दर्द है।
केसी बदमाश

6

नीचे के रूप में एक सरल तरीका है, आप FromStreamट्रिक को करने के लिए एक छवि की विधि का उपयोग कर सकते हैं , बस उपयोग करने के लिए याद रखें System.Drawing;

// using image object not file 
public byte[] imageToByteArray(Image imageIn)
{
    MemoryStream ms = new MemoryStream();
    imageIn.Save(ms,System.Drawing.Imaging.ImageFormat.Gif);
    return ms.ToArray();
}

public Image byteArrayToImage(byte[] byteArrayIn)
{
    MemoryStream ms = new MemoryStream(byteArrayIn);
    Image returnImage = Image.FromStream(ms);
    return returnImage;
}

5

कोशिश (अद्यतन)

MemoryStream ms = new MemoryStream(byteArrayIn,0,byteArrayIn.Length);
ms.Position = 0; // this is important
returnImage = Image.FromStream(ms,true);

2
एक ही बाइट सरणी के साथ आरंभीकृत होने के बाद बाइट सरणी को मेमोरी स्ट्रीम में लिखना थोड़ा समझ में आता है। वास्तव में मुझे यकीन नहीं है कि मेमोरीस्ट्रीम कंस्ट्रक्टर में निर्दिष्ट लंबाई से आगे लिखने की अनुमति देता है।
होलस्टेब्रो

2

आपने किसी प्रकार के परिवर्तनशील के रूप में रिटर्नइमेज घोषित नहीं किया है :)

यह मदद करनी चाहिए:

public Image byteArrayToImage(byte[] byteArrayIn)
{
    try
    {
        MemoryStream ms = new MemoryStream(byteArrayIn,0,byteArrayIn.Length);
        ms.Write(byteArrayIn, 0, byteArrayIn.Length);
        Image returnImage = Image.FromStream(ms,true);
    }
    catch { }
    return returnImage;
}

1
एक विचार के रूप में उपयोगी कोड, लेकिन निश्चित रूप से लिखित रूप में काम नहीं करेगा। रिटर्नमैज को कोशिश / कैच सेक्शन के बाहर घोषित करना होगा। इसके अलावा रिटर्नआईजेज को 'कैच' में तत्काल किया जाना है - मैं एक एकल पिक्सेल बिटमैप बनाता हूं: var छवि = नया Bitmap (1, 1); मेमोरीस्ट्रीम स्ट्रीम = नया मेमोरीस्ट्रीम (); image.Save (धारा, ImageFormat.Jpeg); धारा। प्रस्ताव = ०;
रीड



0

अधिकांश समय जब ऐसा होता है तो यह SQL कॉलम में खराब डेटा होता है। यह एक छवि स्तंभ में सम्मिलित करने का उचित तरीका है:

INSERT INTO [TableX] (ImgColumn) VALUES (
(SELECT * FROM OPENROWSET(BULK N'C:\....\Picture 010.png', SINGLE_BLOB) as tempimg))

ज्यादातर लोग इसे गलत तरीके से करते हैं:

INSERT INTO [TableX] (ImgColumn) VALUES ('C:\....\Picture 010.png'))

0

पहले इस पैकेज को स्थापित करें:

स्थापित-पैकेज SixLabors.ImageSharp -Version 1.0.0-beta0007

[SixLabors.ImageSharp] [1] [१]: https://www.nuget.org/packages/SixLabors.ImageSharp

तो नीचे कास्ट बाइट के लिए कोड का उपयोग करें छवि के लिए:

Image<Rgba32> image = Image.Load(byteArray); 

कोड के नीचे ImageFormat का उपयोग करें:

IImageFormat format = Image.DetectFormat(byteArray);

कोड के नीचे म्यूट छवि का उपयोग करें:

image.Mutate(x => x.Resize(new Size(1280, 960)));
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.