I want to read a pbm (portable bitmap format) image having depth one bit per pixel and store that data in a file, so I can perform some operation on bits.
I think in C# the smallest data that can be read is 1 byte so how can I read a bit?
You can't read a bit directly. But you can read a byte and then get the bits from that byte. Or, better yet, read a bunch of bytes into an array and then create a BitArray.
Or ... is this "portable bitmap format" supported directly by the Bitmap class? Bitmap does support a 1 bit per pixel format. It might be as simple as calling the Bitmap constructor to load from a file or a stream.
More information on your problem will get you a better answer.
Related
I am trying to convert YUV420 frames to Bitmap or Image. I am reading these frames from an MP4 video in C# using the AVBlocks library. So, after creating an input and output socket using AVBlocks classes, I then pull each frame from the video with a YUV420 color format and UncompressedVideo stream type. I basically do this by calling Transcoder.Pull(int outputIndex, MediaSample outputData) and then the MediaBuffer that's part of the outputData has the data in an array of bytes. So I am trying to convert these bytes to a Bitmap or Image so that I can eventually show each frame into a PictureBox in the Winforms application.
What I've tried:
I have tried using a MemoryStream, as shown below, but I get an unhandled ArgumentException saying that the parameter is not valid. I tried using ImageConverter() as well to convert to an Image, but I get the same exception. Then, I converted the byte array from YUV to RGB format and gave the updated array as a parameter to the MemoryStream, but again no luck. I also tried changing the color format of the output socket from YUV420 to a BGR format, but it resulted in the same issue as above. The code that tries to convert to a bitmap using MemoryStream:
while (transcoder.Pull(out inputIndex, yuvFrame))
{
buffer = (MediaBuffer) yuvFrame.Buffer.Clone();
Bitmap b;
byte[] temp = new byte[buffer.DataSize];
Array.Copy(buffer.Start, buffer.DataOffset, temp, 0, buffer.DataSize);
var ms = new MemoryStream(temp);
b = new Bitmap(ms);
}
The aforementioned exception is thrown in the last line of the code. I'm not sure if it's the color format or the stream type, or something else that's causing the problem. If someone wants to see more of the code (setting up input & output sockets etc), let me know. For reference, the link to the example I've been following from AVBlocks is this and the link to MediaBuffer class is this.
The Bitmap(MemoryStream ms) constructor expects the bytes from an actual file, like a png, jpeg, bmp or gif. If I'm reading this correctly, you don't have that; you only have pure RGB triplets data. That isn't enough, because it lacks all information about the image's width, height, colour depth etc.
You will need to actually construct an image object from the RGB data. This isn't really trivial; it means you need to make a new image object with the correct dimensions and colour format, then access its backing bytes array, and write your data into it. The actual code for creating an image out of a byte array can be found in this answer.
Note that you'll have to take into account the actual stride in the resulting data you get; the amount of bytes on each line of the image. Images are saved per line, and those lines are usually padded to a multiple of 4 bytes. This obviously messes up a lot if you don't take it into account.
If your data is completely compact, then the stride to give to the BuildImage function I linked to will just be your image width multiplied by the amount of bytes per pixel (should be 3 for 24bpp RGB), but if not, you'll have to pad it to the next multiple of 4.
First, this question is NOT about "how to save a Bitmap as a jpeg on your disk?"
I can't find (or think of) a way of converting a Bitmap with Jpeg compression, but keep it as a Bitmap object. MSDN clearly shows how to save a Bitmap as a JPEG, but what I'm looking for is how to apply the encoding/compression to the Bitmap object, so I can still pass it around, in my code, without referencing the file.
One of the reasons behind that would be a helper class that handles bitmap, but shouldn't be aware of the persistency method used.
All images are bitmaps when loaded into program memory. Specific compressions are typically utilized when writing to disk, and decompressing when reading from disk.
If you're worried about the in-memory footprint of an image you could zip-compress the bytes and pass the byte array around internally. Zipping would be good for lossless compression of an image. Don't forget that many image compressions have different levels of losiness (sp?) In other words, the compression throws away data to store the image in the smallest number of bytes possible.
De/compression is also a performance tradeoff in that you're trading memory footprint for processing time. And in any case, unless you get really fancy, the image does need to be a bitmap if you need to manipulate it in any way.
Here is an answer for a somewhat similar question which you might find interesting.
Bitmap does not support encoded in-memory storage. It is always unencoded (see the PixelFormat enum). Problably you need to write your own wrapper class/abstraction, or give up on that idea.
var stream = new MemoryStream()
Bitmap.Save(Stream, ImageFormat)
Does it what you need?
I'm working on some university project and got stuck with memory issue.
I load a bitmap which takes about 1,5GB on HDD with code below:
Bitmap bmp = new Bitmap(pathToFile);
The issue is that the newly created Bitmap object uses about 3,5GB of RAM which is something I can't understand (that's really BIG wrapper :E). I need to get to the pixel array, and the use of Bitmap class is really helpful (I use LockBits() method later, and process the array byte per byte) but in this case it's total blocker. So here is my question:
Is there any easy way to extract the pixel array without lending additional 2gb?
I'm using c# just to extract the needed array, which is later processed in c++ - maybe I can extract all needed data in c++ (but conversion issue appears here - I'm concentrating on 24bgr format)?
PS: I need to keep the whole bitmap in memory so splitting it into parts is no solution.
PS2: Just to clarify some issues: I know the difference between file extension and file format. The loaded file is uncompressed bitmap 3 bytes per pixel of size ~1.42GB (16k x 32k pixels), so why Bitmap object is more than two times bigger? Any decompressing issues and converting into other format aren't taking place.
Consider using Memory Mapped Files to access your HUGE data :).
An example focused on what you need can be found here: http://visualstudiomagazine.com/articles/2010/06/23/memory-mapped-files.aspx
It's in managed code but you might as well use it from equivalent native code.
Let me know if you need more details.
You can use this solution , Work with bitmaps faster in C#
http://www.codeproject.com/Tips/240428/Work-with-bitmap-faster-with-Csharp
Or you can use memory mapped files
http://visualstudiomagazine.com/articles/2010/06/23/memory-mapped-files.aspx
You can stop memory caching.
Instead of
Bitmap bmp = new Bitmap(pathToFile);
Use
var bmp = (Bitmap)Image.FromStream(sourceFileStream, false, false);
see https://stackoverflow.com/a/47424918/887092
What's the difference between File.WriteAllBytes and FileStream.Write/WriteBytes? I have a bitmap object that and I want to create a new bmp/jpg/png on disk. I think I read somewhere that WriteAllBytes uses FileStream.Write underneath?
WriteAllBytes is just a convinience method, that wraps the underlying Stream operations. (Create a file, write to stream, close stream, etc). Use it if it fits your needs. If you need more control on the underlying operations, fallback to using a Streamor similar.
It is all about using the right abstraction for the task.
Use WriteAllBytes to just save all the bytes, use Write if you need to watch the progress.
You're on the wrong track with this. Saving a bitmap object requires Image.Save(). That's a method that knows how to use an image encoder to convert a bitmap into the bytes that another program (or yours) can load back. There are several image encoders, you can select the one you want with the Save() overload that lets you pick the ImageFormat. The BMP format is the native Windows format, it is uncompressed. The PNG format is nice, it is a compressed lossless format. The JPEG format is a compressed lossy format, good for photos. File size is big to small in order.
You should use WriteAllBytes if you want to save a bitmap.
I'm loading a Bitmap from a jpg file. If the image is not 24bit RGB, I'd like to convert it. The conversion should be fairly fast. The images I'm loading are up to huge (9000*9000 pixel with a compressed size of 40-50MB). How can this be done?
Btw: I don't want to use any external libraries if possible. But if you know of an open source utility class performing the most common imaging tasks, I'd be happy to hear about it. Thanks in advance.
The jpeg should start with 0xFF 0xD8. After that you will find various fields in the format:
Field identifier 2 bytes
Field length, excluding field identifier. 2 bytes.
Variable data.
Parse through the fields. The identifier you will be looking for is 0xFF 0xC0. This is called SOF0, and contains height, width, bit depth, etc. 0xFF 0xC0 will be followed by two bytes for the field length. Immediately following that will be a single byte showing the bit depth, which will usually be 8. Then there will be two bytes for height, two for width, and a single byte for the number of components; this will usually be 1 (for greyscale) or 3. (for color)
This isn't something I've tried myself, but I think you might need to acccess the picture's EXIF information as a start.
Check out Scott Hanselman's blog-entry on accessing EXIF information from pictures.
Standard .NET System.Drawing namespace should have all that you need,
but it probably won't be very efficient. It'll load the whole thing into RAM, uncompress it, convert it (probably by making a copy) and then re-compress and save it. If you aim for high performance, I'm afraid you might need to look into C/C++ libraries and make .NET wrappers for them.
As far as I know jpg is always 24 bpp. The only thing that could change would be that it's CMY(K?) rather then RGB. That information would be stored in the header. Unfortunately I don't have any means of creating a CMYK image to test whether loading into a Bitmap will convert it automatically.
The following line will read the file into memory:
Bitmap image = Image.FromFile(fileName);
image.PixelFormat will tell you the image format. However, I can't test what the file load does with files other than 24bpp RGB jpgs. I can only recommend that you try it out.