What I'm After:
I'm trying to create an extra 1/4 inch of white space to be appended to the TOP of the image during the scanning process.
Using the Kofax Image Controls Toolkit is it possible within one of the following events to add extra white space to the top of the image when scanning?
_PageStart
_PageEnd
_PageAnnotate
_PageDone
Most of the properties available are read only... I know I can set the scan size in the beginning to say 14 inches and when scanning an 11 inch document I will get my extra 3 inches at the bottom of the image. I want to achieve the same principle but at the top of the document and only about a quarter of an inch tall.
So in all the research I did trying to make this possible I came to the conclusion it is in fact not possible...
The only drawbacks about this method were the speed issues after the fact. It did end up slowing down things a good bit.. Hope this helps someone else! Upvote if it helps you please. ;)
What I ended up doing is not using the _PageAnnotate event raised by the Kofax Image Controls and in turn I ended up turning off that event by setting .hDCCreate = false on the Kofax Scan control. Not creating a DC when scanning speeds up the process a little bit not bogging down the processor with all the uncompressing and compressing of the image.
Instead of using the built in Kofax Image Controls event _PageAnnotate I used the _PageDone event and from there used native c# objects/functions to achieve what I was after. Below is the code I ended up with.
if (!Imaging.AnnotateImage(sImageFileName, "This is my annotation..."))
{
Debug.WriteLine("Scan Error! Could not annotate the image.");
}
The code for the class I made called 'Imaging.cs'...
static class Imaging
{
public static bool AnnotateImage(string sFilePath, string sText)
{
try
{
// Get an ImageCodecInfo object that represents the TIFF codec.
ImageCodecInfo myImageCodecInfo = GetEncoderInfo("image/tiff");
Encoder myEncoder = Encoder.Compression;
EncoderParameters myEncoderParameters = new EncoderParameters(1);
EncoderParameter myEncoderParameter = new EncoderParameter(myEncoder, (long)EncoderValue.CompressionCCITT4);
myEncoderParameters.Param[0] = myEncoderParameter;
//Create some global variables
Point pointPosition = new Point(0, 0);
PointF pPos = new PointF((float)pointPosition.X, (float)pointPosition.Y);
Bitmap newBmp;
Graphics g;
Font fNewFont;
SizeF sizeTextSize;
Rectangle rectTextSize;
//Set inital width and height variables
int iW;
int iH;
int iAnnotationH = 44;
using(Image iSource = Image.FromFile(sFilePath))
{
iW = iSource.Width;
iH = iSource.Height;
//Increase the height of the image
iH += iAnnotationH;
//Create the new bitmap object
newBmp = new Bitmap(iW, iH);
newBmp.SetResolution(200.0F, 200.0F);
g = Graphics.FromImage(newBmp);
g.Clear(Color.White);
g.DrawImageUnscaled(iSource, 0, iAnnotationH, iW, iH);
//Create the font object to draw the annotation text
fNewFont = new Font("Verdana", 12);
//Get the size of the area to be drawn then convert it to a rect
sizeTextSize = g.MeasureString(sText, fNewFont);
rectTextSize = new Rectangle(pointPosition.X, pointPosition.Y, (int)sizeTextSize.Width, (int)sizeTextSize.Height);
//Draw a white rect
g.FillRectangle(Brushes.White, rectTextSize);
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
g.DrawString(sText, fNewFont, Brushes.Black, pPos);
}
//Save the changed image
newBmp.Save(sFilePath, myImageCodecInfo, myEncoderParameters);
}
catch
{
return false;
}
return true;
}
static ImageCodecInfo GetEncoderInfo(String mimeType)
{
int j;
ImageCodecInfo[] encoders;
encoders = ImageCodecInfo.GetImageEncoders();
for (j = 0; j < encoders.Length; ++j)
{
if (encoders[j].MimeType == mimeType)
return encoders[j];
}
return null;
}
}
Related
In .net application when the image is processed & merged with another image then its colours are affected.
Image image ---------> Uploaded image
Bitmap xy = new Bitmap(image, image.Width, image.Height); -----> Conversion into Bitmap to perform various operations like resize or merge with another image.
So the “image” object has few “PropertyItems” and when we convert image to Bitmap type of object then these “PropertyItems” array is empty, which means these “PropertyItems” were not moved in this conversion.
Now after this image is moved into Bitmap object for merging with another image, then “PropertyItems” array is empty
Due to loss of these propertyitems, color of the image is changed.
For merging, I'm using below code
public string MergeImages(List<BlockPositionDetailsWithSize> blockPositionDetailsWithSize, int layoutWidth, int layoutHeight)
{
var bitmap = new Bitmap(layoutWidth-75, layoutHeight);
float width = 0, height = 0;
using (var g = Graphics.FromImage(bitmap))
{
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.SmoothingMode = SmoothingMode.HighQuality;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.CompositingQuality = CompositingQuality.HighQuality;
var bitmapImg = blockPositionDetailsWithSize.Where(b => b.BlockId.Contains("fImageBlock")).FirstOrDefault();
// This loop is placing two images in graphic object
foreach (var block in blockPositionDetailsWithSize)
{
width = block.Width;
height = block.Height;
g.DrawImage(block.BlockImage, block.PosX, block.PosY, block.Width, block.Height);
}
}
ImageCodecInfo jpgEncoder = GetEncoder(ImageFormat.Jpeg); // change image format
System.IO.MemoryStream ms = new System.IO.MemoryStream();
bitmap.SetResolution(288, 288);
System.Drawing.Imaging.Encoder imgEncoder = System.Drawing.Imaging.Encoder.Quality;
EncoderParameters imgEncoderParameters = new EncoderParameters(1);
EncoderParameter imgEncoderParameter = new EncoderParameter(imgEncoder, 95L); //A quality level of 0 corresponds to the greatest compression, and a quality level of 100 corresponds to the least compression.
imgEncoderParameters.Param[0] = imgEncoderParameter;
bitmap.Save(ms, jpgEncoder, imgEncoderParameters);
byte[] byteImage = ms.ToArray();
string base64String = string.Empty;
base64String = Convert.ToBase64String(byteImage); ////Get Base64
return base64String;
}
Image's color quality can be maintained by following code
foreach (System.Drawing.Imaging.PropertyItem item in bitmapImg.BlockImage.PropertyItems)
{
try
{
bitmap.SetPropertyItem(item);
}
catch
{
}
}
Now the issue is I cannot apply one image's property item on the final image(produced after merging). Because when I apply one image's property items onto another image then the second image's color quality is affected but if I don't apply then the first Image's color quality is affected.
So I am looking for the way to merge two images without loosing of any it's property items.
For my current WPF appliaction I have to down scale some System.Drawing.Image ( objects which I load from PNG files (some of them with transparent background). I've tried multiple approaches for the resizing of the images and all of them worked fine in terms of having a smaller image afterwards. But unfortunately they all make the images loose their transparency.
My last try was to use ImageResizer an external library to get the job done as I expected it to handle that problem easily, but I still have the same issue: Original image is displayed with transparent background; Resized image displayed is displayed with black background.
Here's my code for the usage of the ImageResizer library:
ImageResizer.Instructions inst = new ImageResizer.Instructions("width=" + newWidth.ToString() + ";height=" + newHeight.ToString() + ";format=png;mode=max");
ImageResizer.ImageJob job = new ImageResizer.ImageJob(originalImage, typeof(System.Drawing.Bitmap), inst);
job.Build();
return job.Result as System.Drawing.Image;
These are my other two approaches, which also basically deliver the same result (Image resized: yet; Transparency preserved: Nope):
return originalImage.GetThumbnailImage(newWidth, newHeight, null, IntPtr.Zero); // Transparency gets lost
return new System.Drawing.Bitmap(originalImage, new System.Drawing.Size(newWidth, newHeight)); // Transparency gets lost
Any ideas on what I have to do in order preserve the transparency while resizing?
Regards
Ralf
ImageResizer always preserves transparency.
You're losing transparency during the encoding (or display) of the image, which happens after you've taken control away from ImageResizer. Instead of passing in typeof(System.Drawing.Bitmap), pass in an output path or output stream.
var i = new Instructions(){ Width = newWidth,Height = newHeight, OutputFormat= OutputFormat.Png, Mode= FitMode.Max};
new ImageJob(originalImage, "output.png", i).Build();
ImageResizer can't control how an image is encoded if you take a raw Bitmap from it instead.
You didn't specific how you're using the results, which is very important. If you are not writing them to disk or a stream, but are instead displaying them, then you're looking for the problem in the wrong place. It's likely that the code responsible for compositing the results onto the display surface is failing to treat the image as a 32-bit image, and is instead ignoring the alpha channel.
Even though you're using WPF, you're working with System.Drawing.Image objects, so you can do this:
public static Bitmap ResizeImage(Image imgToResize, int newHeight)
{
int sourceWidth = imgToResize.Width;
int sourceHeight = imgToResize.Height;
float nPercentH = ((float)newHeight / (float)sourceHeight);
int destWidth = Math.Max((int)Math.Round(sourceWidth * nPercentH), 1); // Just in case;
int destHeight = newHeight;
Bitmap b = new Bitmap(destWidth, destHeight);
using (Graphics g = Graphics.FromImage((Image)b))
{
g.SmoothingMode = SmoothingMode.HighQuality;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.DrawImage(imgToResize, 0, 0, destWidth, destHeight);
}
return b;
}
Afterwards, be sure to save it with the PNG encoder:
public static System.Drawing.Imaging.ImageCodecInfo GetEncoder(System.Drawing.Imaging.ImageFormat format)
{
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
foreach (ImageCodecInfo codec in codecs)
{
if (codec.FormatID == format.Guid)
{
return codec;
}
}
return null;
}
and then
codec = GetEncoder(ImageFormat.Png);
newBitmap.Save(newFile, codec, null);
(Note I'm using the standard .Net class libraries rather than a 3rd party library; hope that's OK.)
Update
Incidentally, since you are working in WPF, why not use WPF's image manipulation?
public static class BitmapHelper
{
public static void SaveToPng(this BitmapSource bitmap, string fileName)
{
var encoder = new PngBitmapEncoder();
SaveUsingEncoder(bitmap, fileName, encoder);
}
public static void SaveUsingEncoder(this BitmapSource bitmap, string fileName, BitmapEncoder encoder)
{
BitmapFrame frame = BitmapFrame.Create(bitmap);
encoder.Frames.Add(frame);
using (var stream = File.Create(fileName))
{
encoder.Save(stream);
}
}
public static void ImageLoadResizeAndSave(string inFile, string outFile, int newPixelHeight)
{
BitmapImage image = new BitmapImage();
image.BeginInit();
image.UriSource = new Uri(inFile);
image.EndInit();
var newImage = BitmapHelper.ResizeImageToHeight(image, newPixelHeight);
BitmapHelper.SaveToPng(newImage, outFile);
}
/// <summary>
/// Resize the image to have the selected height, keeping the width proportionate.
/// </summary>
/// <param name="imgToResize"></param>
/// <param name="newHeight"></param>
/// <returns></returns>
public static BitmapSource ResizeImageToHeight(BitmapSource imgToResize, int newPixelHeight)
{
double sourceWidth = imgToResize.PixelWidth;
double sourceHeight = imgToResize.PixelHeight;
var nPercentH = ((double)newPixelHeight / sourceHeight);
double destWidth = Math.Max((int)Math.Round(sourceWidth * nPercentH), 1); // Just in case;
double destHeight = newPixelHeight;
var bitmap = new TransformedBitmap(imgToResize, new ScaleTransform(destWidth / imgToResize.PixelWidth, destHeight / imgToResize.PixelHeight));
return bitmap;
}
}
Maybe you're losing transparencies converting images in the older format to WPF format?
I have been using iTextSharp for creating a report. My report has many images which are of varying sizes. Each image renders in different size eventhough I scale them. I found many solutions but none helped.
My code:
PdfPCell InnerCell;
iTextSharp.text.Image logo = iTextSharp.text.Image.GetInstance(Server.MapPath(#"images\Logo.png"));
logo.ScaleToFit(80f, 80f);
InnerCell.FixedHeight = 80f;
InnerCell = new PdfPCell(logo);
I tried adding the image to the chunk but the image positions itself to the top. Since being a dynamic report I can't specify the x and y values in chunk
InnerCell = new PdfPCell(new Phrase(new Chunk(logo, 0, 0)));
I even tried this but I can't get a fixed size.
ScaleToFit(w,h) will scale an image proportionately based on the larger of the width/height of the source image. When scaling multiple images, unless the ratio of the dimensions are all the same you will end up with different sizes. This is by design.
Using ScaleToFit(80,80):
If your source is a square that's 100x100 you'll get a square that's 80x80
If your source is a rectangle that's 200x100 you'll get a rectangle that's 80x40
If your source is a rectangle that's 100x200 you'll get a rectangle that's 40x80
Whatever comes out, measure the width and height and at least one will be one of the dimensions that you specified.
I created a sample program that created random sized images and it gave me the expected output shown in the image (w=80,h=80,h=80,h=80,w=80)
private void test() {
//Output the file to the desktop
var testFile = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "Test.pdf");
//Standard PDF creation here, nothing special
using (var fs = new FileStream(testFile, FileMode.Create, FileAccess.Write, FileShare.None)) {
using (var doc = new Document()) {
using (var writer = PdfWriter.GetInstance(doc, fs)) {
doc.Open();
//Create a random number generator to create some random dimensions and colors
var r = new Random();
//Placeholders for the loop
int w, h;
Color c;
iTextSharp.text.Image img;
//Create 5 images
for (var i = 0; i < 5; i++) {
//Create some random dimensions
w = r.Next(25, 500);
h = r.Next(25, 500);
//Create a random color
c = Color.FromArgb(r.Next(256), r.Next(256), r.Next(256));
//Create a random image
img = iTextSharp.text.Image.GetInstance(createSampleImage(w, h, c));
//Scale the image
img.ScaleToFit(80f, 80f);
//Add it to our document
doc.Add(img);
}
doc.Close();
}
}
}
}
/// <summary>
/// Create a single solid color image using the supplied dimensions and color
/// </summary>
private static Byte[] createSampleImage(int width, int height, System.Drawing.Color color) {
using (var bmp = new System.Drawing.Bitmap(width, height)) {
using (var g = Graphics.FromImage(bmp)) {
g.Clear(color);
}
using (var ms = new MemoryStream()) {
bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
return ms.ToArray();
}
}
}
I think what you're looking for is the ability to scale an image proportionately but also have the image "be that size" which would mean filling in the rest of the pixels with clear or possibly white pixels. See this post for a solution to that.
I've got to following function which is called to change the resolution of an image. I want to do this so uploaded image with for example 300dpi will be modified to 72dpi (for web). This question is related to another question here on SO where i'm working on.
I'm creation an extension method for this to be able to use this function on more places in my application, instead of only when uploading new files. (See above mentioned question)
public static byte[] SetDpiTo72(this byte[] imageToFit, string mimeType, Size newSize)
{
using (MemoryStream memoryStream = new MemoryStream(), newMemoryStream = new MemoryStream())
{
memoryStream.Write(imageToFit, 0, imageToFit.Length);
var originalImage = new Bitmap(memoryStream);
using (var canvas = Graphics.FromImage(originalImage))
{
canvas.SmoothingMode = SmoothingMode.AntiAlias;
canvas.InterpolationMode = InterpolationMode.HighQualityBicubic;
canvas.PixelOffsetMode = PixelOffsetMode.HighQuality;
canvas.DrawImage((Image)originalImage,0,0, newSize.Width, newSize.Height);
newBitmap.SetResolution(72, 72);
newBitmap.Save(newMemoryStream, ImageFunctions.GetEncoderInfo(mimeType), null);
}
return newMemoryStream.ToArray();
}
}
The mentioned extension methode is being called in a function similar to the situation below;
if (newSize.Width > originalImage.Width && newSize.Height > originalImage.Height)
{
newSize.Width = originalImage.Width;
newSize.Height = originalImage.Height;
uploadedFileBuffer = uploadedFileBuffer.SetDpiTo72(uploadedFile.ContentType, newSize);
return CreateFile(newSize, uploadedFile, uploadedFileBuffer);
}
The bytearray coming in is the file as an bytearray. It already has the correct size, but I want to change the resolution to 72dpi. However after exectution and saving the image the resolution is still the originale entered resolution, which is 300dpi. How can I do this?
UPDATE AFTER SEVERAL ANSWERS:
public static byte[] SetDpiTo72(this byte[] imageToFit, string mimeType, Size newSize)
{
using (MemoryStream memoryStream = new MemoryStream(), newMemoryStream = new MemoryStream())
{
memoryStream.Write(imageToFit, 0, imageToFit.Length);
var originalImage = new Bitmap(memoryStream);
using (var canvas = Graphics.FromImage(originalImage))
{
canvas.SmoothingMode = SmoothingMode.AntiAlias;
canvas.InterpolationMode = InterpolationMode.HighQualityBicubic;
canvas.PixelOffsetMode = PixelOffsetMode.HighQuality;
canvas.DrawImage((Image)originalImage,0,0, newSize.Width, newSize.Height);
originalImage.SetResolution(72, 72);
var epQuality = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 75);
var epParameters = new EncoderParameters(1);
epParameters.Param[0] = epQuality;
Image newimg = Image.FromStream(memoryStream);
//Getting an GDI+ exception after the execution of this line.
newimg.Save("C:\\test1234.jpg", ImageFunctions.GetEncoderInfo(mimeType), epParameters);
originalImage.Save("test.jpg", ImageFormat.Jpeg);
//This line give me an Argumentexception - Parameter is not valid.
//originalImage.Save(newMemoryStream, ImageFunctions.GetEncoderInfo(mimeType), epParameters);
//newMemoryStream.Close();
}
return newMemoryStream.ToArray();
}
}
The stackstrace which comes with the exception is telling me the following;
at System.Drawing.Image.Save(String filename, ImageCodecInfo encoder, EncoderParameters encoderParams)
at Extensions.ByteArrayExtensions.SetDpiTo72(Byte[] imageToFit, String mimeType, Size newSize) in C:\Website\Project\Extensions\ByteArrayExtensions.cs:line 356
at CMS.Presentation.FileFunctions.CreateFullsizeImage(HttpPostedFileBase uploadedFile, Size newSize, Byte[] uploadedFileBuffer) in C:\Website\Project\CMS.Presentation\FileFunctions.cs:line 197
at CMS.Presentation.FileFunctions.CreateFile(HttpPostedFileBase uploadedFile, INodeService nodeservice, Guid userId, Node parentNode) in C:\Website\Project\CMS.Presentation\FileFunctions.cs:line 53
In the mean time I've also developed another function (see below) resizing just a bitmap. And this seem to work correctly. I can't use this function with my current implementation though because it returns just an Bitmap. Or should i change everything to work with bitmaps?
private static Bitmap ResizeImage(Image image, int width, int height)
{
var frameCount = image.GetFrameCount(new FrameDimension(image.FrameDimensionsList[0]));
var newDimensions = ImageFunctions.GenerateImageDimensions(image.Width, image.Height, width, height);
Bitmap resizedImage;
if (frameCount > 1)
{
//we have a animated GIF
resizedImage = ResizeAnimatedGifImage(image, width, height);
}
else
{
resizedImage = (Bitmap)image.GetThumbnailImage(newDimensions.Width, newDimensions.Height, null, IntPtr.Zero);
}
resizedImage.SetResolution(72,72);
return resizedImage;
}
Ok, I tried it only on files on harddrive, but it should work with streams too.
Bitmap bitmap = new Bitmap(loadFrom);
Bitmap newBitmap = new Bitmap(bitmap);
newBitmap.SetResolution(72, 72);
newBitmap.Save(saveTo);
Took me a while, but I finally found the problem!
The problem lied in the ResizeImage function I used. In the 'GetThumbnailImage' to be specific. I ran into another problem with blurry images, which was explainable because GetThumbnailImage would stretch up the created ThumbNail to the desired size. And the resolution off the thumbnail never changes.
private static Bitmap ResizeImage(Image image, int width, int height)
{
var frameCount = image.GetFrameCount(new FrameDimension(image.FrameDimensionsList[0]));
var newDimensions = ImageFunctions.GenerateImageDimensions(image.Width, image.Height, width, height);
Bitmap resizedImage;
if (frameCount > 1)
{
//we have a animated GIF
resizedImage = ResizeAnimatedGifImage(image, width, height);
}
else
{
resizedImage = (Bitmap)image.GetThumbnailImage(newDimensions.Width, newDimensions.Height, null, IntPtr.Zero);
}
resizedImage.SetResolution(72,72);
return resizedImage;
}
By modifying the function above to the function below I was able to solve the problem using Graphics.DrawImage to redraw the new image before rendering it. Also the GenerateImageDimensions was slightly modified. This taken together the problem was solved.
private static Bitmap ResizeImage(Image image, int width, int height)
{
var frameCount = image.GetFrameCount(new FrameDimension(image.FrameDimensionsList[0]));
var newDimensions = ImageFunctions.GenerateImageDimensions(image.Width, image.Height, width, height);
var resizedImage = new Bitmap(newDimensions.Width, newDimensions.Height);
if (frameCount > 1)
{
//we have a animated GIF
resizedImage = ResizeAnimatedGifImage(image, width, height);
}
else
{
//we have a normal image
using (var gfx = Graphics.FromImage(resizedImage))
{
gfx.SmoothingMode = SmoothingMode.HighQuality;
gfx.InterpolationMode = InterpolationMode.HighQualityBicubic;
gfx.PixelOffsetMode = PixelOffsetMode.HighQuality;
var targRectangle = new Rectangle(0, 0, newDimensions.Width, newDimensions.Height);
var srcRectangle = new Rectangle(0, 0, image.Width, image.Height);
gfx.DrawImage(image, targRectangle, srcRectangle, GraphicsUnit.Pixel);
}
}
return resizedImage;
}
By "changing the resolution", do you actually mean you want to reduce the number of pixels in the image by 72/300? I.e. change a 4000x3000 image to 960x720?
If so, I can't see where your code actually does that. The overload of DrawImage() you're using does this:
Draws the specified image, using its original physical size, at the location specified by a coordinate pair.
Which is exactly what is happening.
Try one of the other overloads such as this one:
Draws the specified Image at the specified location and with the specified size.
for example:
// Create image.
Image newImage = Image.FromFile("SampImag.jpg");
// Create coordinates for upper-left corner of image and for size of image.
int x = 0;
int y = 0;
int width = 450;
int height = 150;
// Draw image to screen.
e.Graphics.DrawImage(newImage, x, y, width, height);
EDIT: per the comments, I understand the OP wants to reduce file size without reducing pixel count. Therefore the files must be recompressed.
I've borrowed some sample code from here:
ImageCodecInfo iciJpegCodec = null;
// This will specify the image quality to the encoder. Change the value of 75 from 0 to 100, where 100 is best quality, but highest file size.
EncoderParameter epQuality = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 75);
// Get all image codecs that are available
ImageCodecInfo[] iciCodecs = ImageCodecInfo.GetImageEncoders();
// Store the quality parameter in the list of encoder parameters
EncoderParameters epParameters = new EncoderParameters(1);
epParameters.Param[0] = epQuality;
// Loop through all the image codecs
for (int i = 0; i < iciCodecs.Length; i++)
{
// Until the one that we are interested in is found, which is image/jpeg
if (iciCodecs[i].MimeType == "image/jpeg")
{
iciJpegCodec = iciCodecs[i];
break;
}
}
// Create a new Image object from the current file
Image newImage = Image.FromFile(strFile);
// Get the file information again, this time we want to find out the extension
FileInfo fiPicture = new FileInfo(strFile);
// Save the new file at the selected path with the specified encoder parameters, and reuse the same file name
newImage.Save(outputPath + "\\" + fiPicture.Name, iciJpegCodec, epParameters);
Rob, I believe that issue with your code is at saving the image - the actual digital image data would be certain number of dots/pixels i.e. (m x n) and setting resolution at bitmap wouldn't/shouldn't change the number dots (and hence physical byte size of image). The resolution information will be stored in the image header (to be used by programs while printing/editing images) - what happens if you store the new bitmap to file instead of mem stream
newBitmap.Save("c:\test.png", ImageFormat.Png);
Check dpi for above file from file -> properties -> summary (advanced). It should be 72 dpi.
Whats going on is i need to draw a black rectangle over the image. I have to load a tif and then show a blackbox over it. I was helped with some code but i continously got the error: A Graphics object cannot be created from an image that has an indexed pixel format.
So i had to read it in to bit format, but when i display the box it resizes the box wierd. And completly displays the the picture box in all black nothing of the original image. if someone could help me where i'm going wrong that would be awesome.
Bitmap original = (Bitmap)System.Drawing.Image.FromFile(coveted, true);
Bitmap newImage = new Bitmap(original.Width, original.Height);
pictureBox1.Image = newImage;
using (Graphics g = Graphics.FromImage(pictureBox1.Image))
{
using (SolidBrush brush = new SolidBrush(Color.Black))
{
g.FillRectangle(brush, new Rectangle(x1value, y1value, x3value, y3value));
}
}
I'm not sure how I can make this clearer. Whats happening is I have a tif in a unsupported format. So I have to change it to a Bitmap so I can actually draw a rectangle on it. Then I need to display this redacted image (the original with the redaction) in a picturebox. Whats going on with the code above, is once it's completed, all it displays is a blackbox with no original image.
I believe i ran something about using a Bitmap from stream and then closing the stream. Anybody familiar with this?
Thanks to all the help from STO members!! heres the correct code for redacting images if you encounter the error "A Graphics object cannot be created from an image that has an indexed pixel format.".
if you're given the redacted starting points (obviously you have to make the Regex work to your situation):
//Regex for pulling points from a file
string x1 = x1 = Regex.Match(l, #"\r\n(\d+)\r\n(\d+)").Groups[2].Value;
string y1 = y1 = Regex.Match(l, #"\r\n(\d+)\r\n(\d+)\r\n(\d+)").Groups[3].Value;
string x2 = x2 = Regex.Match(l, #"\r\n(\d+)\r\n(\d+)\r\n(\d+)\r\n(\d+)").Groups[4].Value;
string y2 = y2 = Regex.Match(l, #"\r\n(\d+)\r\n(\d+)\r\n(\d+)\r\n(\d+)\r\n(\d+)").Groups[5].Value;
string x3 = x3 = Regex.Match(l, #"\r\n(\d+)\r\n(\d+)\r\n(\d+)\r\n(\d+)\r\n(\d+)\r\n(\d+)").Groups[6].Value;
string y3 = y3 = Regex.Match(l, #"\r\n(\d+)\r\n(\d+)\r\n(\d+)\r\n(\d+)\r\n(\d+)\r\n(\d+)\r\n(\d+)").Groups[7].Value;
{
//convert string to int for redacted points
int x1value = Convert.ToInt32(x1);
int y1value = Convert.ToInt32(y1);
int x3value = Convert.ToInt32(x3);
int y3value = Convert.ToInt32(y3);
{
//BEGIN Workaround for indexed pixels
Bitmap original = (Bitmap)System.Drawing.Image.FromFile(YOURFILE, true);
Bitmap newImage = new Bitmap(original);
pictureBox1.Image = newImage; //END Workaround for indexed pixels
using (Graphics g = Graphics.FromImage(pictureBox1.Image)) //start redaction
{
using (SolidBrush brush = new SolidBrush(Color.Black))
{
g.DrawImageUnscaled(newImage, 0,0);
g.FillRectangle(brush, new Rectangle(x1value, y1value, x3value, y3value));
}
} //End Redaction
pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage; //Resized to fit into a static picturebox
}
}
Instead of
Bitmap newImage = new Bitmap(original.Width, original.Height);
you want
Bitmap newImage = new Bitmap(original);
This will make your newImage start with the contents of original.
The difference will be that you will end up with newImage.PixelFormat == PixelFormat.Format32bppArgb, while I'm assuming original.PixelFormat == PixelFormat.Format1bppIndexed.
With PixelFormat.Format32bppArgb, you can create a Graphics object; you cannot with PixelFormat.Format1bppIndexed.
This should work for you:
original = (Bitmap)System.Drawing.Image.FromFile(coveted, true);
using (Graphics g = Graphics.FromImage(original))
{
using (SolidBrush brush = new SolidBrush(Color.Black))
{
g.FillRectangle(brush, new Rectangle(x1value, y1value, x3value, y3value));
}
}
pictureBox1.Image = original;
You aren't drawing the original image on the newImage.
To do so :
g.DrawImageUnscaled(original, 0, 0);
Also, I would do it as follows, I think it works better drawing in RAM, and then showing it to screen. Perhaps I'm wrong though.
using (Graphics g = Graphics.FromImage(newImage))
{
g.DrawImageUnscaled(original, 0, 0);
using (SolidBrush brush = new SolidBrush(Color.Black))
{
g.FillRectangle(brush, new Rectangle(x1value, y1value, x3value, y3value));
}
}
pictureBox1.Image = newImage;
I haven't tested the code above.. good luck though.