In my MFC project, I need to read and convert a Monochrome bitmap file into CByteArray. While reading the bitmap file by using 'CFile' class with the mode of 'Read', it seems like it gives more length than its original.
My MFC code:-
CFile ImgFile;
CFileException FileExcep;
CByteArray* pBinaryImage = NULL;
strFilePath.Format("%s", "D:\\Test\\Graphics0.bmp");
if(!ImgFile.Open((LPCTSTR)strFilePath,CFile::modeReadWrite,&FileExcep))
{
return NULL;
}
pBinaryImage = new CByteArray();
pBinaryImage->SetSize(ImgFile.GetLength());
// get the byte array's underlying buffer pointer
LPVOID lpvDest = pBinaryImage->GetData();
// perform a massive copy from the file to byte array
if(lpvDest)
{
ImgFile.Read(lpvDest,pBinaryImage->GetSize());
}
ImgFile.Close();
Note: File length is been set to bytearray obj.
I checked with C# with the following sample:-
Bitmap bmpImage = (Bitmap)Bitmap.FromFile("D:\\Test\\Graphics0.bmp");
ImageConverter ic = new ImageConverter();
byte[] ImgByteArray = (byte[])ic.ConvertTo(bmpImage, typeof(byte[]));
While comparing the size of "pBinaryImage" and "ImgByteArray", its not same and I guess "ImgByteArray" size is the correct one since from this array value, I can get my original bitmap back.
As I noted in comments, by reading the whole file with CFile, you are also reading the bitmap headers, which will be corrupting your data.
Here is an example function, showing how to load a monochrome bitmap from file, wrap it in MFC's CBitmap object, query the dimensions etc. and read the pixel data into an array:
void LoadMonoBmp(LPCTSTR szFilename)
{
// load bitmap from file
HBITMAP hBmp = (HBITMAP)LoadImage(NULL, szFilename, IMAGE_BITMAP, 0, 0,
LR_LOADFROMFILE | LR_MONOCHROME);
// wrap in a CBitmap for convenience
CBitmap *pBmp = CBitmap::FromHandle(hBmp);
// get dimensions etc.
BITMAP pBitMap;
pBmp->GetBitmap(&pBitMap);
// allocate a buffer for the pixel data
unsigned int uBufferSize = pBitMap.bmWidthBytes * pBitMap.bmHeight;
unsigned char *pPixels = new unsigned char[uBufferSize];
// load the pixel data
pBmp->GetBitmapBits(uBufferSize, pPixels);
// ... do something with the data ....
// release pixel data
delete [] pPixels;
pPixels = NULL;
// free the bmp
DeleteObject(hBmp);
}
The BITMAP structure will give you information about the bitmap (MSDN here) and, for a monochrome bitmap, the bits will be packed into the bytes you read. This may be another difference with the C# code, where it is possible that each bit is unpacked into a whole byte. In the MFC version, you will need to interpret this data correctly.
Related
I want to convert an .avi with alpha channel into a .gif.
Firstly, I use
ffmpeg -i source.avi -vf scale=720:-1:flags=lanczos,fps=10 frames/ffout%03d.png
to convert .avi to sequence of .png's with aplha channel.
Then, I use
gm convert -loop 0 frames/ffout*.png output.gif
to collect a .gif.
But it seems that pixels of the output.gif just get stuck when something opaque is rendered on top of the transparent areas.
Here's an example:
As you can see the hearts and explosions do not get derendered.
P.S.
FFMPEG output (collection on .png's) is fine.
I do not use Graphicsmagick but your GIF has image disposal mode 0 (no animation). You should use disposal mode 2 (clear with background) or 3 (restore previous image) both works for your GIF. The disposal is present in gfx extension of each frame in the Packed value.
So if you can try to configure encoder to use disposal = 2 or 3 or write script that direct stream copy your GIF and change the Packed value of gfx extension chunk frame by frame. Similar to this:
GIF Image getting distorted on interlacing
If you need help with the script then take a look at:
How to find where does Image Block start in GIF images?
Decode data bytes of GIF87a raster data stream
When I tried this (C++ script) on your GIF using disposal 2 I got this result:
The disposal is changed in C++ like this:
struct __gfxext
{
BYTE Introducer; /* Extension Introducer (always 21h) */
BYTE Label; /* Graphic Control Label (always F9h) */
BYTE BlockSize; /* Size of remaining fields (always 04h) */
BYTE Packed; /* Method of graphics disposal to use */
WORD DelayTime; /* Hundredths of seconds to wait */
BYTE ColorIndex; /* Transparent Color Index */
BYTE Terminator; /* Block Terminator (always 0) */
__gfxext(){}; __gfxext(__gfxext& a){ *this=a; }; ~__gfxext(){}; __gfxext* operator = (const __gfxext *a) { *this=*a; return this; }; /*__gfxext* operator = (const __gfxext &a) { ...copy... return this; };*/
};
__gfxext p;
p.Packed&=255-(7<<2); // clear old disposal and leave the rest as is
p.Packed|= 2<<2; // set new disposal=2 (the first 2 is disposal , the <<2 just shifts it to the correct position in Packed)
It is a good idea to leave other bits of Packed as are because no one knows what could be encoded in there in time ...
i am doing image steganography and if i type message greater than 3 chars to encrypt there is an exception that Quantization table 0x01 is not defined and is message is less than 3 char i got an encrypted image as i needed .I think this is due to JPEG format (I think while injecting bits in image byte array i hv destroyed the property and attributes of an image ).Help me i am sure its something related to metadata but don`t know much about it.
i am adding code what i am doing
Creating_image()
{
File f=new File(file.getParent()+"/encrypt.jpg");
if(file==null)
{
JOptionPane.showMessageDialog(rootPane, "file null ho gyi encrypt mein");
}
try{
FileInputStream imageInFile = new FileInputStream(file);
byte imageData[] = new byte[(int) file.length()];
imageInFile.read(imageData);
// Converting Image byte array into Base64 String
String imageDataString = Base64.encode(imageData);
// Converting a Base64 String into Image byte array
pixels = Base64.decode(imageDataString);
// Write a image byte array into file system
imageInFile.close();
}
catch(Exception as)
{
JOptionPane.showMessageDialog(rootPane,"Please first select an Image");
}
String msg=jTextArea1.getText();
byte[] bmsg=msg.getBytes();
String as=Base64.encode(bmsg);
bmsg=Base64.decode(as);
int len=msg.length();
byte[] blen=inttobyte(len);
String sd=Base64.encode(blen);
blen=Base64.decode(sd);
pixels=encode(pixels,blen,32);
pixels=encode(pixels,bmsg,64);
try{
// Converting Image byte array into Base64 String
String imageDataString = Base64.encode(pixels);
// Converting a Base64 String into Image byte array
pixels = Base64.decode(imageDataString);
InputStream baisData = new ByteArrayInputStream(pixels,0,pixels.length);
image= ImageIO.read(baisData);
if(image == null)
{
System.out.println("imag is empty");
}
ImageIO.write(image, "jpg", f);
}
catch(Exception s)
{
System.out.println(s.getMessage());
}
}
and thats what encode fxn looks like
byte[] encode(byte [] old,byte[] add,int offset)
{
try{ if(add.length+offset>old.length)
{
JOptionPane.showMessageDialog(rootPane, "File too short");
}
}
catch(Exception d)
{
JOptionPane.showMessageDialog(rootPane, d.getLocalizedMessage());
}
byte no;
for(int i=0;i<add.length;i++)
{
no=add[i];
for(int bit=7;bit>=0;bit--,++offset)
{
int b=(no>>bit)&1;
old[offset]=(byte)((old[offset]&0xfe)|b);
}
}
return old;
}
You are correct in that you have disturbed the file structure. The JPEG format contains highly compressed data to the point none of its bytes represent any pixel values directly. In fact, JPEG doesn't even store the pixel values, but the DCT coefficients of pixel blocks.
Your method of reading the raw bytes of the file would work only for a format like BMP, where the pixels are directly stored in the file. However, you'd still have to skip the first few bytes (header), which contain information like the width and height of the image, number of colour planes and bits per pixel.
If you want to embed your message by modifying the least significant bits of pixels, you have to load the actual pixels in a byte array. Then you can modify the pixels with your encode() method. To save the data to a file, convert the byte array to a BuffferedImage object and use ImageIO.write(). However, you must use a format that does not involve lossy compression, because that can distort the pixel values, thereby destroying your message. Losslessly compressed (or uncompressed) file formats include BMP and PNG, while JPEG is lossy.
If you still want to do JPEG steganography, the process is a bit more involving, but this answer pretty much covers what you need to do. Briefly, you want to borrow the source code of a jpeg encoder because writing one is very complex and requires intricate understanding of the whole format. The encoder will convert the pixels to a bunch of different numbers (lossy step) and store them compactly to a file. Your steganography algorithm should then be injected between these two steps, where you can modify those numbers before saving them to file.
I am using Qt and I am new to Qt. I am getting stream of string data from server in particular port.
I am receiving 1 and 0. each time I receive one line like this
1111110001111111111111111111100000000000011111111111
After getting n number of times I need to create binary image file from the data. 1 for white and 0 for black.
How to do this? I already implement the receiving data but I have no idea how to convert this data to image.
Please help me to find the solution for this problem.
You must know dimensions of your image (for example NxM)
According to dimensions of image, you must parse string what you got (think on how to write correct cycle to get NxM 2D array from 1D array consisting NxM elements).
For holding your image data you can use QImage class. Create QImage object, passing to constructor height and width, use its method to fill image. For setting some color of pixel, you can use QImages method setPixel ( int x, int y, uint index_or_rgb ).
Thats all. Good luck!
You may try doing this way
QImage Image(500,500, QImage::Format_Indexed8);
for(int i=0;i<500/*image_width*/;i++)
{
for(int j=0;j<500/*image_height*/;j++)
{
QRgb value;
if(data[i*j] == 0)/*the data array should contain all the information*/
{
value = qRgb(0,0,0);
Image.setPixel(i,j,qGray(value))
}
else
{
value = qRgb(255,255,255);
Image.setPixel(i,j,qGray(value))
}
}
}
From Qt docs:
"Because QImage is a QPaintDevice subclass, QPainter can be used to draw directly onto images."
So, you can create QImage sized to 500x500
QImage image = QImage(500,500)
and then draw on this image
QPainter p(&image);
p.drawPoint(0,0);
p.drawPoint(0,1);
etc;
Another way is to save your bit stream into array char[] and simply create QImage with format Format_Mono or Format_MonoLSB.
QImage image = QImage(bitData, 500, 500, Format_Mono);
Thanks For help i created image. here My Code
QImage testClass::GetImage(QString rdata, int iw, int ih)
{
QImage *Image=new QImage(iw,ih,QImage::Format_ARGB32);
for(int i=0;i<ih;i++)
{
for(int j=0;j<iw;j++)
{
if(rdata.at((i*iw)+j) == '0')
Image->setPixel(QPoint(j,i),qRgb(0,0,0));
else
Image->setPixel(QPoint(j,i),qRgb(255,255,255));
}
}
return *Image;
}
I need to implement a function that receives a string containing the bytes of an image (received via boost socket connection) and converts the info into an OpenCV cv::Mat.
I also know the width and height of the image and its size in bytes. My function looks like this:
void createImageFromBytes(const std::string& name, std::pair<int,int> dimensions, const std::string& data)
{
int width,height;
width = dimensions.first;
height = dimensions.second;
//convert data to cv::Mat image
std::string filepng = DATA_PATH"/" + name +".png";
imwrite(filepng, image);
}
Which is the best method for doing this? Does OpenCV has a constructor for Mat from a string?
OpenCV Mat has a constructor from vector<byte>, but this is not so intuitive. You need to convert from string to vector this way first:
std::vector<byte> vectordata(data.begin(),data.end());
Then you can create a cv::Mat from the vector:
cv::Mat data_mat(vectordata,true);
You also need to decode the image (check documentation for which types are allowed, png, jpg, depending on the OpenCV version)
cv::Mat image(cv::imdecode(data_mat,1)); //put 0 if you want greyscale
Now you can check if the resulting size of the image is the same as the one you sent:
cout<<"Height: " << image.rows <<" Width: "<<image.cols<<endl;
Easy to trip here as the image may have null characters and any c function handling string will see null as string end
Read the image
cv::Mat image;
image = cv::imread("../test/image.png", CV_LOAD_IMAGE_COLOR);
Convert to Bytes (this is just working code, not checked for leaks)
int dataSize = image.total() * image.elemSize();
//convert to bytes
std::vector<char> vec(dataSize);
memcpy(&vec[0], reinterpret_cast<char *>(image.data), dataSize);
std::string test2(vec.begin(), vec.end());
Test and see if conversion works
//test
cv::Mat data_mat(height,width,CV_8UC3,const_cast<char*>(test2.c_str()));
imwrite("out2.png", data_mat);
If the data in the string is raw pixels (rather than a Jpeg/png etc) you can create the cv::mat directly
// assuming an RGB image in bytes
cv::Mat mat(height,width,CV_8UC3,string.data());
Here is my improved solution of Jav_Rock, the problem is that is not clear to use vector (byte type is not defined in c++, i didn't found that), instead of that, use vector, here is a example code
int func(char * pfile){
string strfile = pfile;
std::vector<unsigned char> vectordata(strfile.begin(),strfile.end());
Mat data_mat(vectordata, true);
Mat graySacleFrame = imdecode(data_mat, 0); //PGM image
...
}
GetDIBits: trying to modify the bitmap, but not sure how to go about it? I tried lpvBits but it crashes out in the comparison in the "pig" area. How should I do this? thx
LPVOID lpvBits=NULL; // pointer to bitmap bits array
BITMAPINFO bi;
ZeroMemory(&bi.bmiHeader, sizeof(BITMAPINFOHEADER));
bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
if (!GetDIBits(dc, m_bmp, 0, 400, lpvBits, &bi, DIB_RGB_COLORS))
AfxMessageBox("1");
char *pig = (char*)lpvBits;
for (int m=0;m<100;m++)
{
if (pig[m] > 100)
{
pig[m] = 250;
}
}
SetDIBits( dc, m_bmp, 0, 400, (void *)pig, &bi, DIB_RGB_COLORS );
http://msdn.microsoft.com/en-us/library/dd144879(v=vs.85).aspx
lpvBits [out]
A pointer to a buffer to receive the bitmap data. If this parameter is NULL, the function passes the dimensions and format of the bitmap to the BITMAPINFO structure pointed to by the lpbi parameter.
example found here:
http://msdn.microsoft.com/en-us/library/dd183402(v=vs.85).aspx
http://msdn.microsoft.com/en-us/library/ms969901.aspx
http://www.codeproject.com/KB/graphics/drawing2bitmap.aspx
http://www.cplusplus.com/forum/general/28469/
Read the documentation for GetDIBits carefully - the lpvBits pointer is not returned to you - you need to allocate enough memory for the bitmap data you want to fetch, and pass it to GetDIBits to fill it in with image data.