I'm trying to copy an image to the windows clipboard but windows keeps removing my alpha. This is may latest attempt where i manually create the buffer and copy the BGRA values to the buffer, however still when i read the values later alpha is set to 255. If i copy my image from Paint.NET I get an InteropBitmap with the exact same values but alpha is set correct, so it should be possible. If i save my image to a PNG-file instead of the clipboard alpha is also correct.
var buffer = new byte[width * height * 4];
for (var x = 0; x < width; x++)
{
for (var y = 0; y < height; y++)
{
var pixel = surface[x, y];
var i = (y * width + x) * 4;
buffer[i + 0] = pixel.B;
buffer[i + 1] = pixel.G;
buffer[i + 2] = pixel.R;
buffer[i + 3] = pixel.A;
}
}
Clipboard.Clear();
Clipboard.SetImage(InteropBitmap.Create(
bounds.Width, bounds.Height,
96, 96,
PixelFormats.Bgra32,
null,
buffer,
width * 4));
Related
I am trying to extract images using the PDFsharp library. As mentioned in the sample program, the library does not support the extraction of the non-JPEG images, therefore, I am trying to do it myself.
I found a non-working sample program for the same purpose. I am using the following code to extract a 400 x 400 PNG image embedded in a PDF file (the image was first inserted in a MS Word file, which was saved as a PDF file then).
PDF File Link:
https://drive.google.com/open?id=1aB-SrMB3eu00BywliOBC8AW0JqRa0Hbd
EXTRACTION CODE:
static void ExportAsPngImage(PdfDictionary image, ref int count)
{
int width = image.Elements.GetInteger(PdfSharp.Pdf.Advanced.PdfImage.Keys.Width);
int height = image.Elements.GetInteger(PdfSharp.Pdf.Advanced.PdfImage.Keys.Height);
System.Drawing.Imaging.PixelFormat pixelFormat = System.Drawing.Imaging.PixelFormat.Format8bppIndexed;
byte[] original_byte_boundary = image.Stream.UnfilteredValue;
byte[] result_byte_boundary = null;
//Image data in BMP files always starts at a DWORD boundary, in PDF it starts at a BYTE boundary.
//You must copy the image data line by line and start each line at the DWORD boundary.
byte[, ,] copy_dword_boundary = new byte[3, height, width];
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
if (x <= width && (x + (y * width) != original_byte_boundary.Length))
// while not at end of line, take orignale array
{
copy_dword_boundary[0, y, x] = original_byte_boundary[3*x + (y * width)];
copy_dword_boundary[1, y, x] = original_byte_boundary[3*x + (y * width) + 1];
copy_dword_boundary[2, y, x] = original_byte_boundary[3*x + (y * width) + 2];
}
else //fill new array with ending 0
{
copy_dword_boundary[0, y, x] = 0;
copy_dword_boundary[1, y, x] = 0;
copy_dword_boundary[2, y, x] = 0;
}
}
}
result_byte_boundary = new byte[3 * width * height];
int counter = 0;
int n_width = copy_dword_boundary.GetLength(2);
int n_height = copy_dword_boundary.GetLength(1);
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{ //put 3dim array back in 1dim array
result_byte_boundary[counter] = copy_dword_boundary[0, x, y];
result_byte_boundary[counter + 1] = copy_dword_boundary[1, x, y];
result_byte_boundary[counter + 2] = copy_dword_boundary[2, x, y];
//counter++;
counter = counter + 3;
}
}
Bitmap bmp = new Bitmap(width, height, pixelFormat);
System.Drawing.Imaging.BitmapData bmd = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.WriteOnly, bmp.PixelFormat);
System.Runtime.InteropServices.Marshal.Copy(result_byte_boundary, 0, bmd.Scan0, result_byte_boundary.Length);
bmp.UnlockBits(bmd);
using (FileStream fs = new FileStream(#"D:\TestPdf\" + String.Format("Image{0}.png", count), FileMode.Create, FileAccess.Write))
{
bmp.Save(fs, ImageFormat.Png);
count++;
}
}
PROBLEM:
Whatever PixelFormat format I choose, the saved PNG image does not look correct.
Original PNG IMAGE (Bit Depth-32):
Result of PixelFormat = Format24bppRgb
You can get the pixelformat from the PDF file. Since you did not include the PDF in your post, I cannot tell you which format would be correct.
PDF files do not contain PNG images, instead images use a special PDF image format which is somewhat similar to the BMP files used by Windows, but without any headers in the binary data. Instead the "header" information can be found with the properties of the Image object. See the PDF Reference for further details.
I have a 32bit .tif file which is displayed in the image below by first ImageJ, and secondly my program. As you can guess, the way ImageJ displays the picture is correct.
I am converting the file to a Bitmap like this:
private Bitmap TiffToBmp()
{
Bitmap bmp;
int width;
int height;
float[] scanline32Bit;
float[] buffer;
using (Tiff original = Tiff.Open(file, "r"))
{
width = original.GetField(TiffTag.IMAGEWIDTH)[0].ToInt();
height = original.GetField(TiffTag.IMAGELENGTH)[0].ToInt();
byte[] scanline = new byte[original.ScanlineSize()];
scanline32Bit = new float[original.ScanlineSize() / 4];
buffer = new float[width * height];
for (int i = 0; i < height; i++) //loading the data into a buffer
{
original.ReadScanline(scanline, i);
Buffer.BlockCopy(scanline, 0, scanline32Bit, 0, scanline.Length);
for (int j = 0; j < width; j++)
{
buffer[i * width + j] = scanline32Bit[j];
}
}
}
bmp = new Bitmap(width, height);
BitmapData data = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, bmp.PixelFormat);
byte[] bytes = new byte[data.Height * data.Stride];
for (int y = 0; y < data.Height; y++) //creating Bitmap from buffer
{
for (int x = 0; x < data.Stride; x += 4)
{
bytes[y * data.Stride + x] = (byte)buffer[(y * data.Stride + x) / 4];
bytes[y * data.Stride + x + 1] = (byte)buffer[(y * data.Stride + x) / 4];
bytes[y * data.Stride + x + 2] = (byte)buffer[(y * data.Stride + x) / 4];
bytes[y * data.Stride + x + 3] = 255;
}
}
Marshal.Copy(bytes, 0, data.Scan0, bytes.Length);
bmp.UnlockBits(data);
return bmp;
}
Using a RGBA Bitmap might seem a bit naive but it's necessary in further steps of the program. Also worth mentioning: XnView displays the file similar to mine, just the negative (from white to black instead of black to white). When opening the file it notices me that it converts the image to RGB with 8bits per channel (the same thing I'm doing) and falsely claims the .tif is 16bit instead of 32bit.
Has someone an idea of what I am doing wrong?
It seems to me that the error comes purely from some kind of misuse of structs or wrongly converting between them (from float to byte and so on).
I am using BitMiracle.LibTiff.Classic from the the .NET version of original libtiff library
edit: after some research I found out that original.ReadScanline(scanline, i) returns seemingly weird values and converts them via Buffer.BlockCopy(...) to the stripes appearing in the image. For example the 4 bytes (read from scanline) of the pixel (x = 0, y = 0) are 0, 0, 200, 6, the corresponding 8bit pixel value (read from scanline32Bit) turns out to be 110. Of Pixel (x = width, y = 0) the 4 bytes are 0, 128, 111, 68 and the 8bit value displayed is 958 corresponding to 190. So now I think there's something wrong with one of those steps but I actually have no idea what's going on.
Assuming you don't mind using existing code, there is this: https://www.codeproject.com/Articles/8279/ImageConverter-Converts-images-to-a-specific-image
The author (not me, BTW) provides both the C# source and an executable. I used the executable to convert a TIF (created using paint.net) to a BMP, so I presume the source will be useful to you. I was able to open the author's solution using VS 2017 (VS upgraded both the solution and project to work in the current VS environment). The conversion is based on the System.Drawing.Imaging.ImageFormat class
The following routine is to sharpen an 8 bit indexed grayscale only.
This code seems to have no effect on the input image. That is, what is going in, the same is coming out.
If I increase the value of strength the image seems to be getting darker, but, never filtered.
What could be possibly going wrong?
I am using the following kernel,
double[,] _numericalKernel = new double[,]
{ { -1, -1, -1, },
{ -1, 9, -1, },
{ -1, -1, -1, }, };
The following is my source code for sharpening,
public static Bitmap NonfftSharpen(Bitmap image, double[,] mask, double strength)
{
Bitmap bitmap = (Bitmap)image.Clone();
if (bitmap != null)
{
int width = bitmap.Width;
int height = bitmap.Height;
if (mask.GetLength(0) != mask.GetLength(1))
{
throw new Exception("_numericalKernel dimensions must be same");
}
// Create sharpening filter.
int filterSize = mask.GetLength(0);
double[,] filter = (double[,])mask.Clone();
int channels = sizeof(byte);
double bias = 1.0 - strength;
double factor = strength / 16.0;
int halfOfFilerSize = filterSize / 2;
byte[,] result = new byte[bitmap.Width, bitmap.Height];
// Lock image bits for read/write.
BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, width, height),
ImageLockMode.ReadWrite,
PixelFormat.Format8bppIndexed);
// Declare an array to hold the bytes of the bitmap.
int memorySize = bitmapData.Stride * height;
byte[] memory = new byte[memorySize];
// Copy the RGB values into the local array.
Marshal.Copy(bitmapData.Scan0, memory, 0, memorySize);
int rgb;
// Fill the color array with the new sharpened color values.
for (int y = halfOfFilerSize; y < height - halfOfFilerSize; y++)
{
for (int x = halfOfFilerSize; x < width - halfOfFilerSize; x++)
{
for (int filterY = 0; filterY < filterSize; filterY++)
{
double grayShade = 0.0;
for (int filterX = 0; filterX < filterSize; filterX++)
{
int imageX = (x - halfOfFilerSize + filterX + width) % width;
int imageY = (y - halfOfFilerSize + filterY + height) % height;
rgb = imageY * bitmapData.Stride + channels * imageX;
grayShade += memory[rgb + 0] * filter[filterX, filterY];
}
rgb = y * bitmapData.Stride + channels * x;
int b = Math.Min(Math.Max((int)(factor * grayShade + (bias * memory[rgb + 0])), 0), 255);
result[x, y] = (byte)b;
}
}
}
// Update the image with the sharpened pixels.
for (int x = halfOfFilerSize; x < width - halfOfFilerSize; x++)
{
for (int y = halfOfFilerSize; y < height - halfOfFilerSize; y++)
{
rgb = y * bitmapData.Stride + channels * x;
memory[rgb + 0] = result[x, y];
}
}
// Copy the RGB values back to the bitmap.
Marshal.Copy(memory, 0, bitmapData.Scan0, memorySize);
// Release image bits.
bitmap.UnlockBits(bitmapData);
return bitmap;
}
else
{
throw new Exception("input image can't be null");
}
}
I've changed your function a bit to make it work.
Take care that the strength parameter has no effect in my function. You can play with the bias and factor values to get different results in brightness and so on.
public static Bitmap NonfftSharpen(Bitmap image, double[,] mask, double strength)
{
Bitmap bitmap = (Bitmap)image.Clone();
if (bitmap != null)
{
int width = bitmap.Width;
int height = bitmap.Height;
if (mask.GetLength(0) != mask.GetLength(1))
{
throw new Exception("_numericalKernel dimensions must be same");
}
// Create sharpening filter.
int filterSize = mask.GetLength(0);
double[,] filter = (double[,])mask.Clone();
int channels = sizeof(byte);
double bias = 0.0; // 1.0 - strength;
double factor = 1.0; // strength / 16.0;
byte[,] result = new byte[bitmap.Width, bitmap.Height];
// Lock image bits for read/write.
BitmapData bitmapData = bitmap.LockBits(new System.Drawing.Rectangle(0, 0, width, height),
ImageLockMode.ReadWrite,
System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
// Declare an array to hold the bytes of the bitmap.
int memorySize = bitmapData.Stride * height;
byte[] memory = new byte[memorySize];
// Copy the RGB values into the local array.
Marshal.Copy(bitmapData.Scan0, memory, 0, memorySize);
int pixel;
// Fill the color array with the new sharpened color values.
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
double grayShade = 0.0;
for (int filterY = 0; filterY < filterSize; filterY++)
{
for (int filterX = 0; filterX < filterSize; filterX++)
{
int imageX = (x - filterSize / 2 + filterX + width) % width;
int imageY = (y - filterSize / 2 + filterY + height) % height;
pixel = imageY * bitmapData.Stride + channels * imageX;
grayShade += memory[pixel] * filter[filterX, filterY];
}
int newPixel = Math.Min(Math.Max((int)(factor * grayShade + bias), 0), 255);
result[x, y] = (byte)newPixel;
}
}
}
// Update the image with the sharpened pixels.
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
pixel = y * bitmapData.Stride + channels * x;
memory[pixel] = result[x, y];
}
}
// Copy the values back to the bitmap.
Marshal.Copy(memory, 0, bitmapData.Scan0, memorySize);
// Release image bits.
bitmap.UnlockBits(bitmapData);
return bitmap;
}
else
{
throw new Exception("input image can't be null");
}
}
I hope this gets you going :)
Regards
How do I go about setting a Bitmap with a Color of the pixels. I created a program with LockBits and it is very fast but now I need to set a PictureBox with that image I ran through the LockBits I do not want to use SetPixels My current code is:
Bitmap imageFile = new Bitmap(bmpPath);
BitmapData imageData = imageFile.LockBits(new Rectangle(0, 0, imageFile.Width, imageFile.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
IntPtr Pointer = imageData.Scan0;
int ArraySize = Math.Abs(imageData.Stride) * imageFile.Height;
byte[] PixelArray = new byte[ArraySize];
Marshal.Copy(Pointer, PixelArray, 0, ArraySize);
int PixelAmount = 4; //ArGb
Color ArGBformat;
Bitmap RenderedImage = new Bitmap(imageFile.Width, imageFile.Height);
byte NewAlpha;
byte NewRed;
byte NewGreen;
byte NewBlue;
unsafe
{
for (int y = 0; y < imageData.Height; y++)
{
byte* row = (byte*)imageData.Scan0 + (y * imageData.Stride);
for (int x = 0; x < imageData.Width; x++)
{
int offSet = x * PixelAmount;
// read pixels
byte blue = row[offSet];
byte green = row[offSet + 1];
byte red = row[offSet + 2];
byte alpha = row[offSet + 3];
//Manipulates pixels
NewAlpha = Convert.ToByte(Math.Abs(alpha - _Alpha));
NewRed = Convert.ToByte(Math.Abs(red - _Red));
NewBlue = Convert.ToByte(Math.Abs(blue - _Blue));
NewGreen = Convert.ToByte(Math.Abs(green - _Green));
ArGBformat = Color.FromArgb(NewAlpha, NewRed, NewGreen, NewBlue);
RenderedImage.SetPixel(x, y, ArGBformat); //Slow and want something else
}
}
}
I would like to set my PictureBox1 to the pixels that get ran through the program.
Found the answer. I needed to set the pixels back.
//Sets image
row[offSet] = NewBlue;
row[offSet + 1] = NewGreen;
row[offSet + 2] = NewRed;
row[offSet + 3] = NewAlpha;
The idea is building a windows form application in Visual Studio 2010 using C#.
The program will run a series of operation when the user hit a button.
Is it possible to use a image to show the progress instead of using a progress bar?
So the idea is that the image will start of being invisible, and as the program progress, the image become more and more visible.
0% - invisible
50% - half transparent
100% - visible
I know you can toggle the PictureBox to be visible or not (PictureBox.Visible = true or false;), but is there a way to make it in between?
Any idea is appreciate.
Manipulating images in winforms is slow, so do this as little as possible:
public Bitmap ImageFade( Bitmap sourceBitmap, byte Transparency)
{
BitmapData sourceData = sourceBitmap.LockBits(new Rectangle(0, 0,
sourceBitmap.Width, sourceBitmap.Height),
ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
byte[] pixelBuffer = new byte[sourceData.Stride * sourceData.Height];
byte[] resultBuffer = new byte[sourceData.Stride * sourceData.Height];
Marshal.Copy(sourceData.Scan0, pixelBuffer, 0, pixelBuffer.Length);
sourceBitmap.UnlockBits(sourceData);
byte blue = 0;
byte green = 0;
byte red = 0;
byte a = 0;
int byteOffset = 0;
for (int offsetY = 0; offsetY <
sourceBitmap.Height; offsetY++)
{
for (int offsetX = 0; offsetX <
sourceBitmap.Width; offsetX++)
{
blue = 0;
green = 0;
red = 0;
a = 0;
byteOffset = offsetY *
sourceData.Stride +
offsetX * 4;
blue += pixelBuffer[byteOffset];
green += pixelBuffer[byteOffset + 1];
red += pixelBuffer[byteOffset + 2];
a += Transparency;//pixelBuffer[byteOffset + 3];
resultBuffer[byteOffset] = blue;
resultBuffer[byteOffset + 1] = green;
resultBuffer[byteOffset + 2] = red;
resultBuffer[byteOffset + 3] = a;
}
}
Bitmap resultBitmap = new Bitmap(sourceBitmap.Width, sourceBitmap.Height);
BitmapData resultData = resultBitmap.LockBits(new Rectangle(0, 0,
resultBitmap.Width, resultBitmap.Height),
ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
Marshal.Copy(resultBuffer, 0, resultData.Scan0, resultBuffer.Length);
resultBitmap.UnlockBits(resultData);
return resultBitmap;
}
I note another answer uses SetPixel. Avoid using that function if possible. It's much faster to edit the underlying bytestream, which is still slow since it's not hardware accelerated, but it's the best of several not-great options
This function can potentially be further optimized, but I leave that as an exercise for the reader
You could always adjust the alpha component of your image:
void SetImageProgress(float percent, Bitmap img)
{
int alpha = (int)(percent / 100.0f * 255.0f);
alpha &= 0xff;
for(int x = 0; x < img.Width; x++)
{
for(int y = 0; y < img.Height; y++)
{
Color c = img.GetPixel(x, y);
c = Color.FromArgb(alpha, c.R, c.G, c.B);
img.SetPixel(x, y, c);
}
}
}