I was having trouble editing or removing keywords from a photograph. The following works to replace the keywords successfully:
...
string s_keywords = "tag1;tag2;tag3";
PropertyItem item_keyword = (PropertyItem)FormatterServices.GetUninitializedObject(typeof(PropertyItem));
item_keyword.Id = 0x9c9e; // XPKeywords
item_keyword.Type = 1;
item_keyword.Value = System.Text.Encoding.Unicode.GetBytes(s_keywords + "\0");
item_keyword.Len = item_keyword.Value.Length;
image.SetPropertyItem(item_keyword);
...
Note that my experiments show that image.RemovePropertyItem(0x9c9e); seems to have no effect on the saved image. Instead use the above code with s_keywords = "";
Don't do it this way: The following code works to remove the keywords, but results in the jpeg being re-encoded and loosing some quality (the image file goes from about 4MB to < 2MB and I can see some slight visual differences):
...
Image image_copy = new Bitmap(image);
foreach (var pi in image.PropertyItems)
{
if (pi.Id != 0x9c9e) image_copy.SetPropertyItem(pi);
}
image.Dispose();
image = (Image)image_copy.Clone();
...
I'm was having similar issues with setting the XPTitle - setting the propertyItem 0x9c9b seemed to have no effect in the saved image, instead I had to open the file as a BitmapFrame, extract the BitmapMetadata and use the Title property, then build a new jpeg using JpegBitmapEncoder - thus re-encoding and loosing image quality.
...
BitmapFrame bf_title = BitmapFrame.Create(new Uri(tmp_file, UriKind.Relative));
BitmapMetadata bmd_title = (BitmapMetadata)bf_title.Metadata.Clone();
bmd_title.Title = new_title;
BitmapFrame bf_new = BitmapFrame.Create(bf_title, bf_title.Thumbnail, bmd_title, bf_title.ColorContexts);
JpegBitmapEncoder je = new JpegBitmapEncoder();
je.Frames.Add(bf_new);
FileStream fs = new FileStream(tmp_file, FileMode.Create);
je.Save(fs);
fs.Close();
...
See my answer below for the correct way to change the title.
This was driving me crazy, I hope this can help someone else...
Note that the above keywords code now works perfectly.
I'm answering this because I could not find sample code to do this when I searched - so hopefully someone else will find this useful.
To change the title use the following code. The problem was that there are two tags that affect how windows shows the title - one of which (0x010e) takes priority over the XPTitle (0xc9b) tag...
...
string new_value = "New title for the image";
PropertyItem item_title = (PropertyItem)FormatterServices.GetUninitializedObject(typeof(PropertyItem));
item_title.Id = 0x9c9b; // XPTitle 0x9c9b
item_title.Type = 1;
item_title.Value = System.Text.Encoding.Unicode.GetBytes(new_value + "\0");
item_title.Len = item_title.Value.Length;
image.SetPropertyItem(item_title);
PropertyItem item_title2 = (PropertyItem)FormatterServices.GetUninitializedObject(typeof(PropertyItem));
item_title2.Id = 0x010e; // ImageDescription 0x010e
item_title2.Type = 2;
item_title2.Value = System.Text.Encoding.UTF8.GetBytes(new_value + "\0");
item_title2.Len = item_title2.Value.Length;
image.SetPropertyItem(item_title2);
image.Save("new_filename.jpg", ImageFormat.Jpeg)
image.Dispose();
...
Note - Another potential issue, you need to save the image to a new location. You can then dispose of the image and copy it into the original location if desired.
Related
I have a following exception on my report:
I think i tried every possible way to fix it, I even changed the way I load that image to load it from base64 string:
var bytes = Convert.FromBase64String(#"base64string");
using (var ms = new MemoryStream(bytes))
{
pbLogo.Value = Image.FromStream(ms);
}
The problem is that it's non deterministic - sometimes it will work and sometines and will only appear from time to time, without any way to always reproduce it.
Edit - this is a designer code:
// pbLogo
//
this.pbLogo = new Telerik.Reporting.PictureBox()
this.pbLogo.Location = new Telerik.Reporting.Drawing.PointU(Telerik.Reporting.Drawing.Unit.Inch(0D), Telerik.Reporting.Drawing.Unit.Inch(3.9418537198798731E-05D));
this.pbLogo.MimeType = "";
this.pbLogo.Name = "pbLogo";
this.pbLogo.Size = new Telerik.Reporting.Drawing.SizeU(Telerik.Reporting.Drawing.Unit.Pixel(185D), Telerik.Reporting.Drawing.Unit.Pixel(42D));
this.pbLogo.Sizing = Telerik.Reporting.Drawing.ImageSizeMode.ScaleProportional;
this.pbLogo.Style.BackgroundImage.MimeType = "image/jpeg";
this.pbLogo.Style.BackgroundImage.Repeat = Telerik.Reporting.Drawing.BackgroundRepeat.NoRepeat;
this.pbLogo.Value = "";
I need to convert a JPG image to PNG and change its white background to transparent instead. I am using ImageMagick.NET and I have found the following ImageMagick command that is supposed to do what I am trying to achieve:
convert image.jpg -fuzz XX% -transparent white result.png
I have tried converting this to c# but all I am getting is a png image with a white background. My code snippet:
using (var img = new MagickImage("image.jpg"))
{
img.Format = MagickFormat.Png;
img.BackgroundColor = MagickColors.White;
img.ColorFuzz = new Percentage(10);
img.BackgroundColor = MagickColors.None;
img.Write("image.png");
}
Any kind of help will be greatly appreciated. Thank you!!
This is a late response as it took me a while to find an answer myself, but this seems to work for me quite well. Look at where the Background property is assigned the Transparent value.
using (var magicImage = new MagickImage())
{
var magicReadSettings = new MagickReadSettings
{
Format = MagickFormat.Svg,
ColorSpace = ColorSpace.Transparent,
BackgroundColor = MagickColors.Transparent,
// increasing the Density here makes a larger and sharper output to PNG
Density = new Density(950, DensityUnit.PixelsPerInch)
};
magicImage.Read("someimage.svg", magicReadSettings);
magicImage.Format = MagickFormat.Png;
magicImage.Write("someimage.png");
}
In my case, I wanted to send this to UWP Image element, so instead of Write(), I did the following after the steps above:
// Create byte array that contains a png file
byte[] imageData = magicImage.ToByteArray();
using (InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream())
{
using (DataWriter writer = new DataWriter(stream.GetOutputStreamAt(0)))
{
writer.WriteBytes(imageData);
await writer.StoreAsync();
}
await bitmapImage.SetSourceAsync(stream);
}
return bitMapImage; // new BitMapImage() was scoped before all of this
Then on the UWP Image element, simply use:
imageElement.Source = bitMapImage;
Most of the arguments on the command line are either properties or method on the MagickImage class. Your command would translate to this:
using (var img = new MagickImage("image.jpg"))
{
// -fuzz XX%
img.ColorFuzz = new Percentage(10);
// -transparent white
img.Transparent(MagickColors.White);
img.Write("image.png");
}
I am trying to conceptualize a way to get base64 image onto an already rendered PDF in iText. The goal is to have the PDF save to disk then reopen to apply the "signature" in the right spot.
I haven't had any success with finding other examples online so I'm asking Stack.
My app uses .net c#.
Any advice on how to get started?
As #mkl mentioned the question is a confusing, especially the title - usually base64 and signature do not go together. Guessing you want to place a base64 image from web on the PDF as a pseudo signature?!?!
A quick working example to get you started:
static void Main(string[] args)
{
string currentDir = AppDomain.CurrentDomain.BaseDirectory;
// 'INPUT' => already rendered pdf in iText
PdfReader reader = new PdfReader(INPUT);
string outputFile = Path.Combine(currentDir, OUTPUT);
using (var stream = new FileStream(outputFile, FileMode.Create))
{
using (PdfStamper stamper = new PdfStamper(reader, stream))
{
AcroFields form = stamper.AcroFields;
var fldPosition = form.GetFieldPositions("lname")[0];
Rectangle rectangle = fldPosition.position;
string base64Image = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==";
Regex regex = new Regex(#"^data:image/(?<mediaType>[^;]+);base64,(?<data>.*)");
Match match = regex.Match(base64Image);
Image image = Image.GetInstance(
Convert.FromBase64String(match.Groups["data"].Value)
);
// best fit if image bigger than form field
if (image.Height > rectangle.Height || image.Width > rectangle.Width)
{
image.ScaleAbsolute(rectangle);
}
// form field top left - change parameters as needed to set different position
image.SetAbsolutePosition(rectangle.Left + 2, rectangle.Top - 2);
stamper.GetOverContent(fldPosition.page).AddImage(image);
}
}
}
If you're not working with a PDF form template, (AcroFields in code snippet) explicitly set the absolute position and scale the image as needed.
My current code writes a qr code but it over writes my file with just the qr code. I am not sure how to adjust the size of the qr code to be placed in one corner of the document rather than taking up the whole page. Also not sure if the RasterImage.Create means that it creates a new file with just the qr and discard my original file?
Code: - Convert PDF to Bmp to add QR then saving back to PDF
public void PDFFileExample()
{
RasterCodecs codecs1 = new RasterCodecs();
codecs1.Options.Pdf.InitialPath = #"C:\LEADTOOLS 18\Bin\Dotnet4\Win32";
codecs1.Dispose();
RasterCodecs codecs2 = new RasterCodecs();
codecs2.ThrowExceptionsOnInvalidImages = true;
System.Diagnostics.Debug.Assert(codecs2.Options.Pdf.InitialPath == #"C:\LEADTOOLS 18\Bin\Dotnet4\Win32");
string pdfFile = #"C:\QRCodeTesting\bottomRight.pdf";
string destFileName1 = #"C:\QRCodeTesting\bottomRightOutputTemp.pdf";
string destFileName2 = #"C:\QRCodeTesting\bottomRightOutput.bmp";
RasterCodecs codecs = new RasterCodecs();
if (codecs.Options.Pdf.IsEngineInstalled)
{
// Resulting image pixel depth.
codecs.Options.Pdf.Load.DisplayDepth = 24;
codecs.Options.Pdf.Load.GraphicsAlpha = 4;
codecs.Options.Pdf.Load.Password = "";
// Type of font anti-aliasing to use.
codecs.Options.Pdf.Load.TextAlpha = 1;
codecs.Options.Pdf.Load.UseLibFonts = true;
// Horizontal,vertical display resolution in dots per inch.
codecs.Options.RasterizeDocument.Load.XResolution = 150;
codecs.Options.RasterizeDocument.Load.YResolution = 150;
using (RasterImage image = codecs.Load(pdfFile, 0, CodecsLoadByteOrder.BgrOrGray, 1, 1))
{
// Set the PDF version to be v1.4
codecs.Options.Pdf.Save.Version = CodecsRasterPdfVersion.V14;
try
{
// Save the image back as PDF
codecs.Save(image, destFileName1, RasterImageFormat.RasPdf, 24);
}
catch (RasterException ex)
{
if (ex.Code == RasterExceptionCode.FileFormat)
MessageBox.Show(string.Format("Image in file {0} is loaded", destFileName1));
else
{
MessageBox.Show(string.Format("Could not load the file {0}.{1}{2}", destFileName1, Environment.NewLine, ex.Message));
}
}
}
// And load it back before saving it as BMP
using (RasterImage image = codecs.Load(destFileName1))
{
codecs.Save(image, destFileName2, RasterImageFormat.Bmp, image.BitsPerPixel);
writeQRTag(destFileName2);
}
}
else
{
MessageBox.Show("PDF Engine is not found!");
}
// Clean up
codecs.Dispose();
}
QRCode writing Method
private void writeQRTag(string imageFileName)
{
BarcodeEngine engine = new BarcodeEngine();
// Create the image to write the barcodes to
int resolution = 300;
using (RasterImage image = RasterImage.Create((int)(8.5 * resolution), (int)(11.0 * resolution), 1, resolution, RasterColor.FromKnownColor(RasterKnownColor.Red)))
{
// Write two QR barcodes
WriteQRCode(engine.Writer, image, QRBarcodeSymbolModel.Model1AutoSize, "QR Data 1", true);
// Save the image
using (RasterCodecs codecs = new RasterCodecs())
{
codecs.Save(image, imageFileName, RasterImageFormat.CcittGroup4, 1);
}
}
}
This is Maen from LEADTOOLS support.
I checked your code and noticed the following:
1) When you call RasterImage.Create() method, it will create a new RasterImage object that contains an empty red image, which you subsequently pass to the writeQRTag() function then save using the given file name.
When you save it, the red color is replaced by black because the file format you used only supports black and white. Since you're using a new image, the old image is lost (overwritten).
If you want to write the barcode on the image from the original file, you should NOT create a new image. Instead, you need to use the image you already loaded using codecs.Load() and write the barcode on it.
2) The code performs multiple load and save operations. Normally, you don't need to do that unless your application needs the different file formats (PDF, BMP and TIFF).
3) You create different instances of our RasterCodecs object but actually use only one of them. There's no need for 3 of the 4 RasterCodecs objects in the code.
If you still face problems with the code that uses our toolkit, you can send us the details in an email to support#leadtools.com and we will try to help you.
This is a part of a code that will saved image to database
Bitmap TempImage = new Bitmap(#cwd + "\\Final.jpg", true);
pictureBox.Image = new Bitmap(TempImage);//pictureBox.Image = Image.FromFile(imgName[0]);
TempImage.Dispose();
string name = textBox1.Text + ".jpg";
MemoryStream mstr = new MemoryStream();
pictureBox.Image.Save(mstr, pictureBox.Image.RawFormat);
byte[] arrImage = mstr.GetBuffer();
then the program halts at pictureBox.Image.Save(mstr, pictureBox.Image.RawFormat); saying ArgumentNullException was unhandled, Value cannot be null.
Parameter name: encoder
what would be wrong?
Going to take a WAG and say that you shouldn't dispose of things you might be messing with later on.
using( Bitmap TempImage = new Bitmap(#cwd + "\\Final.jpg", true))
{
pictureBox.Image = TempImage // why do => new Bitmap(TempImage); here?
string name = textBox1.Text + ".jpg";
MemoryStream mstr = new MemoryStream();
pictureBox.Image.Save(mstr, pictureBox.Image.RawFormat);
byte[] arrImage = mstr.GetBuffer();
}
// after this point, you'd better not be using pictureBox either!
Also, not sure why you are creating two Bitmaps... or using a "pictureBox" in order to save the image... Quite frankly, the more I look at this code the more I boggle. Perhaps you should ask a question such as
I am attempting to foo an image so that I may bar. How do I do this?
and skip this bit of code altogether.
The implementation of Save() will call FindEncoder() on the format you pass in as the second parameter (pictureBox.Image.RawFormat), and that is returning null.
simply use
pictureBox1.Image =
Bitmap.FromFile(#"C:\Users\Public\Pictures\Sample Pictures\Desert.jpg");