i know it may be easy but i couldn't able to find a solution for this.
i need to get the next row of bitmap after using all the bitmap of current bitmap
I'm making a stenography program where I'm hiding a text file inside image.
Each character is stored inside 8 different bytes.
so after hiding text inside 1st column i need to get next column and so on.
I'm very weak in this. I tried this for 1st row, but don't know for other rows according to text length.
private void HIDE(){
if (textBox1.Text != "")
{
Bitmap bitmap = (Bitmap)pictureBox1.Image;
int next,width=0;
for (int t = 0; t < textBox1.Text.Length; t++)
{
next = 8 * t;
for (int i = 0; i < 8; i++)
{
if (i * t <= bitmap.Width/8)
{
//hiding code for 1st row
}
else
{
//hiding code for 2nd row
}
}
}
}}
How about this?
private void HIDE(){
if (textBox1.Text != "")
{
Bitmap bitmap = (Bitmap)pictureBox1.Image;
// Starting point for embedding secret
int x0=0, y0=0;
// Error checking, to see if text can fit in image
int imageSize = bitmap.Width * bitmap.Height;
if (imageSize - x0 * bitmap.Width - y0 < 8 * textBox1.Text.Length)
{
// Deal with error
}
// Ready to embed
for (int t = 0; t < textBox1.Text.Length; t++)
{
for (int i = 0; i < 8; i++)
{
// Check if y0 has exceeded image width
// so to wrap around to the new row
if (y0 == bitmap.Width)
{
x0++;
y0=0;
}
// x0, y0 are now the current pixel coordinates
//
// EMBED MESSAGE HERE
//
y0++; // Move to the next pixel for the next bit
}
}
}}
For example, if you have a width of 10, these should be the coordinates for the first two letters of your text:
Letter 1:
(0, 0)
...
(0, 7)
Letter 2:
(0, 8)
(0, 9)
(1, 0)
...
IMPORTANT NOTE: It looks like you don't hide the length of the text and the decoding process won't know how many pixels to read to retrieve the message.
If you have dealt with it somewhere else, or the decoder always knows the length, that's fine. Otherwise, you want to use a set number of pixels at a fixed location (usually the first 32), to encode in binary the length of your text. For example,
int secretLength = 8 * textBox1.Text.Length;
string binary = Convert.ToString(secretLength, 2);
For the text "Hello World", binary will be 00000000000000000000000001011000. Now you can embed these in your 32 specific pixels and the actual secret message afterwards. Remember that in this case your image must have at least 8 * TextBox1.Text.Length + 32 number of pixels to accommodate the whole secret.
Using 4 bytes for the length of the text is such an overkill, considering, above all, image size limitations. You can use fewer bytes if you can always guarantee the text size will never exceed a specific length, or a more dynamic approach, like this
Reference: Integer to binary string conversion borrowed from here.
Related
I receive images of the same size but with different amounts of information. Examples below (red borders are mine). The background is always white.
I am trying to detect where the information on the image ends - at what pixel height (and crop accordingly). In other words, find the first non-white pixel from the bottom.
Is there a better way to do this other than extract BitmapData out of Image object and loop through all the pixels?
Just to add a suggestion having looked over your images and your solution (below) and your method is fine but you may be able to improve efficiency.
The more you know about your image the better; you're confident the background is always white (according to your post, the code is a more generic utility but the following suggestion can still work); can you be confident on the furthest point in a non-white pixel will be found if the row is not empty?
For example; in your two pictures the furthest in non-white pixel on a row is about 60px in. If this is universally true for your data then you don't need to scan the whole line of the image, which would make your for loop:
for (int y = bitmap.Height - 1; y >= 0; y--) {
for (int x = 0; x < 60; x++) {
Color color = bitmap.GetPixel(x, y);
if (color.R != backColor.R || color.G != backColor.G || color.B != backColor.B) {
foundContentOnRow = y;
break;
}
}
}
(You could make it a parameter on the function so you can easily control it if needed).
Imagine for example that the first non-white row was 80px down. To find it currently you do 640 x 300 = 192,000 checks. If you could confidently say that you would know a row was blank within 100 pixels (an over-estimate based on the data presented) then this would be 100 * 300 = 30,000 checks per image.
If you always knew that the first 10 pixels of the image were always blank you could shave a little bit more off (say 3000 checks).
Musing on a setup where you knew that the first non-white pixel was between 10 and 60 pixels in (range of 50) you could find it at row 80 in 50 x 300 = 15,000 checks which is a good reduction.
Of course the downside about assumptions is that if things change your assumptions may not be valid, but if the data is going to remain fairly constant then it may be worthwhile, especially if you do this for a lot of images.
I've ended up using the following code to trim the image. Hopefully someone finds this useful.
class Program {
static void Main(string[] args) {
Image full = Image.FromFile("foo.png");
Image cropped = full.TrimOnBottom();
}
}
public static class ImageUtilities {
public static Image TrimOnBottom(this Image image, Color? backgroundColor = null, int margin = 30) {
var bitmap = (Bitmap)image;
int foundContentOnRow = -1;
// handle empty optional parameter
var backColor = backgroundColor ?? Color.White;
// scan the image from the bottom up, left to right
for (int y = bitmap.Height - 1; y >= 0; y--) {
for (int x = 0; x < bitmap.Width; x++) {
Color color = bitmap.GetPixel(x, y);
if (color.R != backColor.R || color.G != backColor.G || color.B != backColor.B) {
foundContentOnRow = y;
break;
}
}
// exit loop if content found
if (foundContentOnRow > -1) {
break;
}
}
if (foundContentOnRow > -1) {
int proposedHeight = foundContentOnRow + margin;
// only trim if proposed height smaller than existing image
if (proposedHeight < bitmap.Height) {
return CropImage(image, bitmap.Width, proposedHeight);
}
}
return image;
}
private static Image CropImage(Image image, int width, int height) {
Rectangle cropArea = new Rectangle(0, 0, width, height);
Bitmap bitmap = new Bitmap(image);
return bitmap.Clone(cropArea, bitmap.PixelFormat);
}
}
I have a tiff Image and I am reading the RGB values of each pixel with following code. the Image Height :16198 width :12900.
But the code is taking much longer time (more than 20 minutes). tried various way like converting it to bitmap, but non of them leads to better performance. any suggestions
using (Tiff tiffreader = Tiff.Open(imgpath, "r"))
{
img.Width = tiffreader.GetField(TiffTag.IMAGEWIDTH)[0].ToInt();
img.Height = tiffreader.GetField(TiffTag.IMAGELENGTH)[0].ToInt();
img.DipX = tiffreader.GetField(TiffTag.XRESOLUTION)[0].ToInt();
img.DipY = tiffreader.GetField(TiffTag.YRESOLUTION)[0].ToInt();
// Reading RGB values
int height = (int)img.Height;
int width = (int)img.Width;
int[] raster = new int[height*width];
var b = tiffreader.ReadRGBAImage(width, height, raster);
img.Pixels = new PColor[height, width];
img.Pixels = Utility.ConvertToRGB(height, width, raster);
}
internal static PColor[,] ConvertToRGB(int height, int width, int[] raster)
{
PColor[,] pcolor = new PColor[height, width];
try
{
for (int i = 0; i < height; ++i)
for (int j = 0; j < width; ++j)
{
int offset = (height - j - 1) * width + i;
PColor color = new PColor();
color.R = Tiff.GetR(raster[offset]);
color.G = Tiff.GetG(raster[offset]);
color.B = Tiff.GetB(raster[offset]);
pcolor[i, j] = color;
}
}
catch(Exception exp)
{
throw exp;
}
return pcolor;
}
It looks like you are doing unnecessary processing of the file. The whole loop that calls ReadScanline seems to be pointless since you just read the whole file later with a call to ReadRGBAImage. I'm not sure what class backs the img variable, but it looks like it has duplicated data in it (The Pixels property and the bytearray variable). I would see if you can refactor your code to remove one of these items.
It would also be good to change your loops to convert to RGB to have i (the height) be the inside loop so that you are accessing the raster array in order (which saves a lot of memory fetches).
Also note that 2-dimensional array access is significantly slower than 1d because of double bounds checking. In my own experience it's actually faster to calculate the offset of a 1d array manually than to use a C# 2d array. It might be worth refactoring Pixels to be 1d.
EDIT: If you can't refactor the code to remove Pixels or bytearray, then I would suggest creating the bytearray variable contents from the contents of raster instead of re-reading the file again.
I have a bitmap and I am wanting to get the colour values from the pixels but only in certain areas of the image. I am wanting to the get the pixels of a image for the full width and only a bit of the height (say height =1) and then I want to move the position to one down and get the same values.
I am using
for (int i = 0; i < 302; i++)
{
Rectangle cloneRect = new Rectangle(0, i, 514, 1);
System.Drawing.Imaging.PixelFormat format = bm.PixelFormat;
Bitmap cloneBitmap = bm.Clone(cloneRect, format);
bitMapList.Add(cloneBitmap);
}
foreach (Bitmap bmp in bitMapList)
{
c = bmp.GetPixel(514, 1);
r = Convert.ToInt16(c.R);
lumi.Add(r);
}
The for statement to create the areas I want on the bitmap and then the foreach to loop through these bitmaps and then get the values. Only problem is I am getting the error message "Parameter must be positive and < Width."
On the line
c = bmp.GetPixel(514, 1);
anyone know why?
Thanks
You need to make sure that the pixel you are getting is inside of the image (which must not be the case). You could wrap this in a call to run a check first something like:
public static Color GetPixelSafe(Bitmap image, int x, int y) {
if (x >= image.Width) x = image.Width - 1;
else if (x < 0) x = 0;
if (y >= image.Height) y = image.Height - 1;
else if (y < 0) y = 0;
return image.GetPixel(x, y);
}
Now, this is not going to fix your processing algorithm itself, but it should at least fix the exception. One other pointer is that if you are going to be processing lots of color values and performance is a concern you should really consider using image.LockBits instead of GetPixel. For more information on that see here: http://msdn.microsoft.com/en-us/library/5ey6h79d(v=vs.110).aspx.
It seems that 514 is bigger then your image actual Width. How did you come up with that number?
I'm hoping someone that's had experience with the RFB protocol will give me an answer.
Following the RFB protocol, I've implemented a 3.3 client, the handshake and all is fine. What I don't understand / having issues with, is the FrameUpdateRequest and FrameUpdate using Raw data.
I've read and implemented the documentation verbatim # contents 6.4.3 and 6.5.1 from http://www.realvnc.com/docs/rfbproto.pdf
It's a bit messy as I've been playing left, right and center with it. But here's what I'm doing:
public int beginNormalOperation()
{
byte[] fbUp = new byte[10];
fbUp[0] = 0003; //Message type, 3= FrameBufferUpdate
fbUp[1] = 0001; //Incremental 0=true, 1=false
fbUp[2] = 0000; //X Position High Byte
fbUp[3] = 0000; //X Position Low Byte
fbUp[4] = 0000; //Y Position High Byte
fbUp[5] = 0000; //Y Position Low Byte
fbUp[6] = INTtoU16(serverSetWidth)[0];
fbUp[7] = INTtoU16(serverSetWidth)[1];
fbUp[8] = INTtoU16(serverSetHeight)[0];
fbUp[9] = INTtoU16(serverSetHeight)[1];
//fbUp[6] = 0000;
//fbUp[7] = 100;
//fbUp[8] = 0000;
//fbUp[9] = 100;
sock.Send(fbUp);
System.Drawing.Image img;
byte[] bufferInfo = new byte[4];
try
{
sock.Receive(bufferInfo);
textBox4.AppendText("\r\n" + Encoding.Default.GetString(bufferInfo));
}
catch (SocketException ex) { MessageBox.Show("" + ex); }
return U16toINT(bufferInfo[2], bufferInfo[3]);
}
The return value is the number of rectangles, because I'm calling this method from a button click, then passing it to:
public void drawImage(int numRectangles)
{
//Now within the class
//int xPos = 0;
//int yPos = 0;
//int fWidth = 0;
//int fHeight = 0;
if (myBmp == null)
{
myBmp = new Bitmap(serverSetWidth, serverSetHeight); //I'm requesting full size, so using server bounds atm
}
for (int i = 0; i < numRectangles; i++)
{
byte[] bufferData = new byte[12];
int headerLen = 0;
if (!gotRectangleHeader)
{
try
{
sock.Receive(bufferData);
}
catch (SocketException ex) { MessageBox.Show("" + ex); }
xPos = U16toINT(bufferData[0], bufferData[1]);
yPos = U16toINT(bufferData[2], bufferData[3]);
fWidth = U16toINT(bufferData[4], bufferData[5]);
fHeight = U16toINT(bufferData[6], bufferData[7]);
//headerLen = 12; //I'm now reading the first 12 bytes first so no need for this
gotRectangleHeader = true;
}
bufferData = new byte[((fWidth * fHeight)*4)];
try
{
sock.Receive(bufferData);
}
catch (SocketException ex) { MessageBox.Show("" + ex); }
//Testing to see where the actual data is ending
//byte[] end = new byte[1000];
//Array.Copy(bufferData, 16125, end, 0, 1000);
//for(int f=0; f<bufferData.Length;f++)
//{
// if (Convert.ToInt32(bufferData[f].ToString()) == 0 &&
// Convert.ToInt32(bufferData[f + 1].ToString()) == 0 &&
// Convert.ToInt32(bufferData[f + 2].ToString()) == 0 &&
// Convert.ToInt32(bufferData[f + 3].ToString()) == 0)
// {
// Array.Copy(bufferData, f-30, end, 0, 500);
// int o = 1;
// }
//}
int curRow = 0;
int curCol = 0;
for (int curBit = 0; curBit < (bufferData.Length - headerLen) / 4; curBit++)
{
int caret = (curBit * 4) + headerLen;
if (curRow == 200)
{
int ss = 4;
}
Color pixCol = System.Drawing.Color.FromArgb(Convert.ToInt32(bufferData[caret+3].ToString()), Convert.ToInt32(bufferData[caret+2].ToString()), Convert.ToInt32(bufferData[caret+1].ToString()), Convert.ToInt32(bufferData[caret].ToString()));
myBmp.SetPixel(curCol, curRow, pixCol);
if (curCol == (fWidth - 1))
{
curRow++;
curCol = 0;
}
else
{
curCol++;
}
}
}
imgForm.Show();
imgForm.updateImg(myBmp);
}
I'm sorry for the code, I've gone through so many permutations messing about it's become a mess.
This is what I'm trying to do and the way I imagine that it should work according to the protocol:
I request a FrameBufferUpdateRequest, incremental is false (1, according to the Doc's), X and Y position set to 0 and width & height both U16 set to 1366 x 768 respectively.
I receive a FrameBufferUpdate with Number of Rectangles
I call drawImage passing Number of Rectangles in.
I assume from the docs, for each rectangle then create a buffer to that rectangles height and width. And set the pixels on a BMP to the rectangles bounds.
The first rectangle always has a header, and within that header the requested width and height. The following rectangle doesn't have any header information. So i'm missing something here. I'm guessing I haven't received all of the first rectangles data even though I have set the sockets buffer size to width*height*bytes.
Sometimes I get say the top 200 pixels or so and full width though a quarter of the right hand screen is shown on the left hand side in my BMP. Sometimes I've had the full screen and that's what I want but mostly I get a slither say 10px of the top of the screen then nothing.
I'm doing something wrong, I know I am. But what??? The documentation isn't great. If someone could hold my hand through the FrameBufferUpdateRequest -> FrameBufferUpdate -> Display Raw Pixel Data!!
Thanks for any input
craig
I suggest you refer to http://tigervnc.org/cgi-bin/rfbproto which I've found to be a much better reference on the protocol. Specifically the sections on framebufferupdaterequest and framebufferupdate
Some other notes:
you have your incremental values swapped. 1 is incremental and 0 is a full request. With incremental set to 1 you are only requesting rectangles that have changed since the last round.
don't assume that framebuffer updates comes synchronously right after you send a framebufferupdate. You really need to read the first byte first to determine what sort of message the server has sent and process the message accordingly.
you should really create your bitmap based on that actual size of each rectangle (i.e. after you read the size of the rectangle you are processing.
you need to take into account the encoding format (you're currently ignoring it). That will determine how large the image data for the rectangle is.
Also, I'm not familiar with how C# Socket.Receive works. Unless it is always guaranteed to block until the buffer is filled, you might need to check how much data was actually read since the servers don't always send the whole framebufferupdate message all at once and even if they do, the messages might get fragmented and not arrive all at once.
I am working on constructing and saving a bitmap, and i have a loop that sets the pixels in the bitmap to their proper values. However it crashes after a short period of ime with an IndexOutOfRange exception at the noted point in the code.
//data is an array of bytes of size (image width * image height) * 2;
Bitmap b = new Bitmap(width, height, PixelFormat.Format32bppArgb);
for (int i = 0; i < data.Length; i += 2)
{
int luminance = ((int)data[i] << 8) | (int)data[i + 1];
Color c = Color.FromArgb(luminance,luminance,luminance,luminance);
int x = i / 2;
int y = x / width;
x %= width;
b.SetPixel(x, y, c);//crashes here when Y is at 513, should only go to 512
}
b.Save(Path.GetFileNameWithoutExtension(fileName) + ".bmp");
I'm stumped as to why this happens.Why does this happen and how can i fix it?
(a note ot all of those that reommend unsafe code: I am going for a working program then a fast one. I'll be sure to write up 3 questions on the subject when i start! ;) )
When Length is odd, then at some point i+1 == Length will be true.
for (int i = 0; i < data.Length; i += 2)
{
int luminance = ((int)data[i] << 8) | (int)data[i + 1];
int x = (i + 1) / 2;
}
I would suggest replacing
//data is an array of bytes of size (image width * image height) * 2;
with
System.Diagnostics.Debug.Assert(data.Length == width * height * 2);
System.Diagnostics.Debug.Assert((data.Length % 2) == 0);
It's hard to tell what might be wrong without knowing what your data actually is. I suspect that it might be organised into rows like a bitmap, but sometimes bitmap format data requires that rows be a multiple of 4 bytes in length (with unused padding at the end, see BMP file format). If this is the case, your y value might become larger than you expect. You may need to take such padding into account.