แปลงบิตแมปเป็นอาร์เรย์ไบต์


233

การใช้ C # มีวิธีที่ดีกว่าในการแปลง Windows Bitmapเป็น a byte[]มากกว่าการบันทึกเป็นไฟล์ชั่วคราวและอ่านผลลัพธ์โดยใช้FileStream?

คำตอบ:


418

มีสองวิธี

ImageConverter

public static byte[] ImageToByte(Image img)
{
    ImageConverter converter = new ImageConverter();
    return (byte[])converter.ConvertTo(img, typeof(byte[]));
}

อันนี้สะดวกเพราะมันไม่ต้องการรหัสจำนวนมาก

สตรีมหน่วยความจำ

public static byte[] ImageToByte2(Image img)
{
    using (var stream = new MemoryStream())
    {
        img.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
        return stream.ToArray();
    }
}

อันนี้เทียบเท่ากับสิ่งที่คุณกำลังทำยกเว้นไฟล์จะถูกบันทึกลงในหน่วยความจำแทนที่จะเป็นดิสก์ แม้ว่ารหัสเพิ่มเติมคุณมีตัวเลือกของ ImageFormat และสามารถแก้ไขได้ง่ายระหว่างการบันทึกลงในหน่วยความจำหรือดิสก์

ที่มา: http://www.vcskicks.com/image-to-byte.php


2
นอกจากนี้คุณยังสามารถใช้ bitmap.Lockbits และ Marshal.Copy เพื่อการคัดลอกอย่างรวดเร็วแบบง่าย ๆ โดยไม่ต้องใช้หน่วยความจำระดับกลาง ฯลฯ
deegee

4
โปรดทราบว่าImageConverterวิธีการนี้จะบันทึกภาพเป็น Png ส่งผลให้มีไฟล์จำนวนมาก
skolima

8
คุณไม่จำเป็นต้องปิดสตรีมเมื่อใช้ 'using'
LastTribunal

2
ใครสามารถให้ข้อมูลเพิ่มเติมกับฉันเกี่ยวกับวิธีการจัดโครงสร้างนี้ มันเริ่มต้นด้วย x = 0 และวนรอบทุก ๆ y แล้วจึงเพิ่ม x แล้วเก็บมันแบบนี้: [0,0,1,1,1,1,1,0,0,1,1]?
Raymond Timmermans

1
ImageConverterไม่ใช่. net มาตรฐานที่คุณอาจใช้MemoryStream
Alexandre

95

MemoryStreamจะมีประโยชน์สำหรับการนี้ คุณสามารถใส่ไว้ในวิธีการขยาย:

public static class ImageExtensions
{
    public static byte[] ToByteArray(this Image image, ImageFormat format)
    {
        using(MemoryStream ms = new MemoryStream())
        {
            image.Save(ms, format);
            return ms.ToArray();
        }
    }
}

คุณสามารถใช้มันได้เช่น:

var image = new Bitmap(10, 10);
// Draw your image
byte[] arr = image.ToByteArray(ImageFormat.Bmp);

ฉันไม่เห็นด้วยกับคำตอบของ prestomanifto บางส่วนเกี่ยวกับ ImageConverter ห้ามใช้ ImageConverter ไม่มีอะไรผิดปกติทางเทคนิคกับมัน แต่เพียงความจริงที่ว่ามันใช้มวย / unboxing จากวัตถุบอกฉันว่ามันเป็นรหัสจากที่มืดเก่าของ. NET Framework และไม่เหมาะที่จะใช้กับการประมวลผลภาพ (มันเกินจริงสำหรับการแปลงเป็นไบต์ [] อย่างน้อย) โดยเฉพาะเมื่อคุณพิจารณาสิ่งต่อไปนี้

ฉันดูที่ImageConverterรหัสที่ใช้โดยกรอบงาน. Net และภายในจะใช้รหัสเกือบเหมือนกันกับที่ฉันให้ไว้ข้างต้น มันจะสร้างใหม่MemoryStreamบันทึกBitmapสิ่งที่อยู่ในรูปแบบที่คุณให้ไว้และส่งกลับอาร์เรย์ ข้ามโอเวอร์เฮดแบบพิเศษของการสร้างImageConverterคลาสโดยใช้MemoryStream


น่ารัก นั่นจะทำ! ฉันคิดว่าคุณต้องการกำจัด MemoryStream แม้ว่า - สนใจที่จะอัปเดตหรือไม่
Jeremy McGee

ฉันได้อัปเดตคำตอบของฉันพร้อมกับการสนทนาเกี่ยวกับสาเหตุที่ไม่ควรใช้ ImageConverter ตามคำตอบที่คุณเลือกรวมถึงการเพิ่มการกำจัดทิ้ง
Christopher Currens

ใช้วิธีการขยายอย่างดีฉันชอบมัน!
Dude Pascalou

3
+1 สำหรับการดู ImageConverter และรายงานผลการวิจัยของคุณ แต่ฉันไม่คิดว่าสิ่งที่คุณค้นพบรับประกันคำว่า "อย่าใช้ ImageConverter" แน่นอนมันให้บริการที่มีประโยชน์ไปในทางอื่นเช่นจากไบต์ไปยังรูปภาพตัวอย่างเช่นการตั้งค่าความละเอียดของภาพ (dpi) และ "ค่าใช้จ่ายเพิ่มเติมในการสร้างคลาส ImageConverter" นั้นอาจน้อยมากและจำเป็นต้องทำเพียงครั้งเดียวโดยไม่คำนึงถึงจำนวนครั้งที่คุณใช้งาน
RenniePet

1
ฉันพบว่า ImageConverter มีประโยชน์เช่นกันในการกำหนดประเภทของภาพโดยอัตโนมัติ - ตัวอย่างเช่นหากคุณมีอาร์เรย์ของรูปภาพ แต่ไม่ทราบรูปแบบคุณสามารถลองอ่านส่วนหัวและรับคำแนะนำจากที่นั่น แต่ ดี ... ใช้ (Image img = (ภาพ) myImgConverter.ConvertFrom (byteImage)) จากนั้นตรวจสอบ img.PixelFormat ฯลฯ ง่ายกว่า .. - แน่นอนขึ้นอยู่กับสิ่งที่คุณต้องการทำ
สวัสดี _

45

คุณสามารถเพียงแค่ Marshal.Copy ข้อมูลบิตแมป ไม่มีหน่วยความจำตัวกลางและอื่น ๆ และคัดลอกหน่วยความจำอย่างรวดเร็ว สิ่งนี้ควรใช้กับบิตแมปทั้งแบบ 24 บิตและ 32 บิต

public static byte[] BitmapToByteArray(Bitmap bitmap)
{

    BitmapData bmpdata = null;

    try
    {
        bmpdata = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat);
        int numbytes = bmpdata.Stride * bitmap.Height;
        byte[] bytedata = new byte[numbytes];
        IntPtr ptr = bmpdata.Scan0;

        Marshal.Copy(ptr, bytedata, 0, numbytes);

        return bytedata;
    }
    finally
    {
        if (bmpdata != null)
            bitmap.UnlockBits(bmpdata);
    }

}

.


1
สวัสดีฉันใช้วิธีนี้ แต่ฉันไม่สามารถแปลงอาร์เรย์ไบต์นี้กลับเป็นภาพได้อีก บิตแมปบิตแมป 1 = บิตแมปใหม่ (ใหม่ MemoryStream (อาร์เรย์)); มันจะโยนข้อยกเว้นของพารามิเตอร์ที่ไม่ถูกต้อง มีอะไรผิดพลาดหรือเปล่า?
Howard

1
สวัสดีส่วนความเห็นมีขนาดเล็กเกินไปสำหรับฉันที่จะโพสต์รหัสสะอาดสมบูรณ์ วิธีที่ง่ายที่สุดคือการตรึงอาร์เรย์: GCHandle handle = GCHandle.Alloc (bufferarray, GCHandleType.Pinned); รับตัวชี้ไปยังอาร์เรย์ IntPtr iptr = Marshal.UnsafeAddrOfPinnedArrayElement (bufferarray, 0); จากนั้นสร้างบิตแมปใหม่โดยใช้ IntPtr: bitmap = บิตแมปใหม่ (ความกว้างความสูง (ความกว้าง * 4), PixelFormat.Format32bppArgb, iptr); แต่คุณจะต้องใช้พารามิเตอร์การสร้างบิตแมปที่เหมาะสมสำหรับรูปแบบบิตแมปของคุณ อย่าลืมล้าง: iptr = IntPtr.Zero; handle.Free ();
deegee

3
บั๊กคืออะไร? โปรแกรมเมอร์หลายคนรวมถึงตัวผมเองกำลังใช้โค้ดนี้อยู่และมันก็ใช้ได้ดี
deegee

4
@ mini-me - ฉันขอแนะนำให้ค้นหาว่าบิตแมปใดก้าวย่างกับความกว้างบิตแมป นี่ไม่ใช่ข้อผิดพลาดในรหัสของฉันนี่คือวิธีที่ Windows จัดการบิตแมป สาวเท้าอาจรวมถึงข้อมูลเพิ่มเติมในตอนท้ายของแต่ละบรรทัด (ความกว้าง) เพื่อให้แต่ละบรรทัดสิ้นสุดและเริ่มในขอบเขต 32 บิตสำหรับการจัดตำแหน่งหน่วยความจำและประสิทธิภาพ
deegee

3
มันไม่ใช่ข้อผิดพลาด msdn.microsoft.com/en-us/library/…
deegee

16

บันทึกภาพลงใน MemoryStream แล้วคว้าอาร์เรย์ไบต์

http://msdn.microsoft.com/en-us/library/ms142148.aspx

  Byte[] data;

  using (var memoryStream = new MemoryStream())
  {
    image.Save(memoryStream, ImageFormat.Bmp);

    data = memoryStream.ToArray();
  }

ไม่มีวิธีบันทึกบนรูปภาพ
เพรสคอตต์ชา

@PrescottChartier ตัวอย่างข้างต้นสมมติว่าคุณกำลังทำงานจากประเภทที่ได้มาSystem.Drawing.Image (ดู: docs.microsoft.com/en-us/dotnet/api/… )
Chris Baxter

Yup System.Drawing.Image does not existและฉันได้รับ ดังนั้น .. ไม่ไม่ทำงาน :(
เพรสคอตต์ชา

คุณสามารถดูสิ่งที่ฉันพยายามทำที่นี่: stackoverflow.com/questions/55084620/…
Prescott Chartier

10

ใช้ a MemoryStreamแทนFileStreamเช่นนี้

MemoryStream ms = new MemoryStream();
bmp.Save (ms, ImageFormat.Jpeg);
byte[] bmpBytes = ms.ToArray();

คุณอาจต้องการไม่ได้ToArray GetBuffer
vcsjones

GetBuffer ส่งกลับอาร์เรย์ของไบต์ที่ไม่ได้ลงนาม (อาร์เรย์ไบต์)
Jeff Reddy

4
มันอาจมีข้อมูลฟิลเลอร์ที่ไม่ได้เป็นส่วนหนึ่งของภาพ จากเอกสาร: Note that the buffer contains allocated bytes which might be unused. For example, if the string "test" is written into the MemoryStream object, the length of the buffer returned from GetBuffer is 256, not 4, with 252 bytes unused. To obtain only the data in the buffer, use the ToArray method.ดังนั้นตอนนี้อาร์เรย์ไบต์จากGetBufferจะส่งคืนรูปภาพพร้อมไบต์ที่ไม่ได้ใช้ซึ่งอาจส่งผลให้เกิดภาพเสียหาย
vcsjones

1
ดีแล้วที่รู้. ขอบคุณสำหรับความคิดเห็น vcs!
Jeff Reddy

วิธีการนี้จะบันทึกภาพเป็น jpeg ด้วยการตั้งค่าการบีบอัดเริ่มต้นซึ่งจะแนะนำสิ่งที่ใช้ในการบีบอัดซึ่งอาจทำให้ภาพของคุณเสื่อมคุณภาพอย่างเห็นได้ชัด
Richard Ev

8

ลองทำสิ่งต่อไปนี้:

MemoryStream stream = new MemoryStream();
Bitmap bitmap = new Bitmap();
bitmap.Save(stream, ImageFormat.Jpeg);

byte[] byteArray = stream.GetBuffer();

ตรวจสอบให้แน่ใจว่าคุณใช้:

System.Drawing & using System.Drawing.Imaging;

1
วิธีการนี้จะบันทึกภาพเป็น jpeg ด้วยการตั้งค่าการบีบอัดเริ่มต้นซึ่งจะแนะนำสิ่งที่ใช้ในการบีบอัดซึ่งอาจทำให้ภาพของคุณเสื่อมคุณภาพอย่างเห็นได้ชัด
Richard Ev

อีกครั้งไม่มีวิธีการบันทึกบนบิตแมป
เพรสคอตต์ชา

7

ฉันเชื่อว่าคุณทำได้ง่ายๆ

ImageConverter converter = new ImageConverter();
var bytes = (byte[])converter.ConvertTo(img, typeof(byte[]));



-3

ใช้ง่ายมากเพียงแค่ในบรรทัดเดียว:

byte[] imgdata = File.ReadAllBytes(@"C:\download.png");

op กล่าวว่าเขาไม่สนใจตัวเลือกนี้
Mauro Sampietro
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.