image (noninlineshape) from Word to clipboard to file - c#

I have a Word document (referred to as "doc" in the code below) with a bunch of .jpg images. Some of them have text wrapped around them (= Shapes), some of them don't (= InlineShapes). I am able to save the InlineShapes like so:
InlineShape ils = doc.InlineShapes[1];
ils.Select();
application.Selection.Copy();
IDataObject data = Clipboard.GetDataObject();
if (data.GetDataPresent(DataFormats.Bitmap)) {
Image image = (Image)data.GetData(DataFormats.Bitmap, true);
image.Save("c:\\image.jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
}
But if I try to get the other ones by replacing the first two lines with these –
Shape s = doc.Shapes[1];
s.Select();
– it won't work. And if I check the formats with "data.GetFormats()" I notice that Bitmap isn't listed, which explains why it doesn't work. Instead it lists the "Office Drawing Shape Format". I suppose that I should try to convert the Shape to a InlineShape somehow, but I haven't been able to make it work. When I try to do it like this –
s.ConvertToInlineShape();
– I get an "invalid parameter" exception.

OK, the problem seems to have been that I tried to convert it at the wrong time. If I loop through all Shapes and convert them before trying to do anything else it works fine.
int number = doc.InlineShapes.Count;
MessageBox.Show(number.ToString()); // 0 to begin with
foreach (Microsoft.Office.Interop.Word.Shape s in doc.Shapes) {
MessageBox.Show(s.Type.ToString());
if (s.Type.ToString() == "msoTextBox") {
MessageBox.Show(s.TextFrame.TextRange.Text);
} else if (s.Type.ToString() == "msoPicture") {
s.ConvertToInlineShape();
}
}
number = doc.InlineShapes.Count;
MessageBox.Show(number.ToString()); // Now it's 1 as it should be
InlineShape ils = doc.InlineShapes[1];
ils.Select();
application.Selection.Copy();
IDataObject data = Clipboard.GetDataObject();
if (data.GetDataPresent(DataFormats.Bitmap)) {
Image image = (Image)data.GetData(DataFormats.Bitmap, true);
image.Save("c:\\image.jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
}

Related

c# Novacode.Picture to System.Drawing.Image

I'm reading in a .docx file using the Novacode API, and am unable to create or display any images within the file to a WinForm app due to not being able to convert from a Novacode Picture (pic) or Image to a system image. I've noticed that there's very little info inside the pic itself, with no way to get any pixel data that I can see. So I have been unable to utilize any of the usual conversion ideas.
I've also looked up how Word saves images inside the files as well as Novacode source for any hints and I've come up with nothing.
My question then is is there a way to convert a Novacode Picture to a system one, or should I use something different to gather the image data like OpenXML? If so, would Novacode and OpenXML conflict in any way?
There's also this answer that might be another place to start.
Any help is much appreciated.
Okay. This is what I ended up doing. Thanks to gattsbr for the advice. This only works if you can grab all the images in order, and have descending names for all the images.
using System.IO.Compression; // Had to add an assembly for this
using Novacode;
// Have to specify to remove ambiguous error from Novacode
Dictionary<string, System.Drawing.Image> images = new Dictionary<string, System.Drawing.Image>();
void LoadTree()
{
// In case of previous exception
if(File.Exists("Images.zip")) { File.Delete("Images.zip"); }
// Allow the file to be open while parsing
using(FileStream stream = File.Open("Images.docx", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
using(DocX doc = DocX.Load(stream))
{
// Work rest of document
// Still parse here to get the names of the images
// Might have to drag and drop images into the file, rather than insert through Word
foreach(Picture pic in doc.Pictures)
{
string name = pic.Description;
if(null == name) { continue; }
name = name.Substring(name.LastIndexOf("\\") + 1);
name = name.Substring(0, name.Length - 4);
images[name] = null;
}
// Save while still open
doc.SaveAs("Images.zip");
}
}
// Use temp zip directory to extract images
using(ZipArchive zip = ZipFile.OpenRead("Images.zip"))
{
// Gather all image names, in order
// They're retrieved from the bottom up, so reverse
string[] keys = images.Keys.OrderByDescending(o => o).Reverse().ToArray();
for(int i = 1; ; i++)
{
// Also had to add an assembly for ZipArchiveEntry
ZipArchiveEntry entry = zip.GetEntry(String.Format("word/media/image{0}.png", i));
if(null == entry) { break; }
Stream stream = entry.Open();
images[keys[i - 1]] = new Bitmap(stream);
}
}
// Remove temp directory
File.Delete("Images.zip");
}

LEADTOOLS adding QRBarcode to an existing image

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.

Losing image quality in c# using Image class (reduces amount of colors)

I have a c# program that opens a .tif image and later offers the option to save it. However, there is always a drop in quality when saving the image.
(EDIT:I passed some parameters while saving the image so that the quality is at 100 % and there is no compression, but the number of actual unique colors go from 254 to 16, even though the image properties show 8bpp)
(EDIT2: The image in question is a grayscale image at 8 bits per pixel - 256 colors/shades of gray - This doesn't happen with a 24 bits per pixel color image that I tested where all the colors are retained. I am starting to think that the image class may only support 16 shades of gray)
How do I avoid this?
Here's the code for opening the image:
public Image imageImport()
{
Stream myStream = null;
OpenFileDialog openTifDialog = new OpenFileDialog();
openTifDialog.Title = "Open Desired Image";
openTifDialog.InitialDirectory = #"c:\";
openTifDialog.Filter = "Tiff only (*.tif)|*.tif";
openTifDialog.FilterIndex = 1;
openTifDialog.RestoreDirectory = true;
if (openTifDialog.ShowDialog() == DialogResult.OK)
{
try
{
if ((myStream = openTifDialog.OpenFile()) != null)
{
using (myStream)
{
String tifFileName= openTifDialog.FileName;
imgLocation = tifFileName;
Bitmap tifFile = new Bitmap(tifFileName);
return tifFile;
}
}
}
catch (Exception ex)
{
MessageBox.Show("Error: Could not read file from disk. Original error: " + ex.Message);
}
}
return null;
}
This is the way I save the image:
private void saveImage(Image img)
{
SaveFileDialog sf = new SaveFileDialog();
sf.Title = "Select File Location";
sf.Filter = " bmp (*.bmp)|*.bmp|jpeg (*.jpg)|*.jpg|tiff (*.tif)|*.tif";
sf.FilterIndex = 4;
sf.RestoreDirectory = true;
sf.ShowDialog();
// If the file name is not an empty string open it for saving.
if (sf.FileName != "")
{
// Saves the Image via a FileStream created by the OpenFile method.
System.IO.FileStream fs =
(System.IO.FileStream)sf.OpenFile();
// Saves the Image in the appropriate ImageFormat based upon the
// File type selected in the dialog box.
// NOTE that the FilterIndex property is one-based.
switch (sf.FilterIndex)
{
case 1:
img.Save(fs,
System.Drawing.Imaging.ImageFormat.Bmp);
break;
case 2:
img.Save(fs,
System.Drawing.Imaging.ImageFormat.Jpeg);
break;
case 3://EDITED -STILL DOES NOT RESOLVE THE ISSUE
ImageCodecInfo codecInfo = ImageClass.GetEncoderInfo(ImageFormat.Tiff);
EncoderParameters parameters = new EncoderParameters(2);
parameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality,100L);
parameters.Param[1] = new EncoderParameter(System.Drawing.Imaging.Encoder.Compression, (long)EncoderValue.CompressionNone);
img.Save(fs,codecInfo, parameters);
break;
}
fs.Close();
}
}
Even if I don't resize or change the image in any ways, I experience a loss in quality. any advice?
System.Drawing has poor support for 8-bit images. When converting from 24 or 32-bit images to 8-bit; it'll always use a fixed default color palette. That default color palette only contains 16 shades of grey, the other entries are various colors.
Do you have the same problem when saving as '.bmp'? If yes, then the conversion to the 8-bit format already happened earlier, you'll have to figure out where your program does that and fix the issue there.
If it's only the tiff encoder that converts to 8-bit, you'll have to do the 8-bit conversion in a separate step first. Create an 8-bit image, fill Image.Palette with a gray-scale palette, and then copy the bitmap data over.
But System.Drawing has poor support for 8-bit images, and several methods (e.g. SetPixel) will just throw InvalidOperationException when dealing with such images. You will probably have to use unsafe code (with LockBits etc.) to copy the bitmap data. If I were you, I'd look if there are alternative graphics libraries you could use.
I had issues with using the .NET libraries to find good balances of image quality and size. I gave up rolling my own and tried out a few imaging libraries. I found http://imageresizing.net/ to produce consistently good results, much better than I was able to do.
Just throwing that out there as a plan B in case the roll your own method doesn't wind up working well on a consistent basis for you.
Image.Save by default uses a quality setting of 75%. You could try using one of the other overloads of the method that allows you to specify quality setting parameters. See this question.
Only one suggestion really....when loading the Image you use new Bitmap(fileName)... Rather than using Bitmap have you considered using
Image tiffImage = Image.FromFile(tiffFileName, true);
The true tells it to use "embedded color management", and using Image instead of Bitmap avoids any image casting that might be occurring behind the scenes.

pdf to image issues

am trying to convert pdftoimage using the below link
http://threebit.net/mail-archive/itext-questions/msg00436.html
but i get this error how to get this code to work ?
"The type or namespace name 'PdfDecoder' could not be found"
am looking for open source .
this ghostscript dint work on server ,
http://www.codeproject.com/KB/webforms/aspnetpdfviewer.aspx
help me.
you Can try this.....
pdfDoc = (Acrobat.CAcroPDDoc)
Microsoft.VisualBasic.Interaction.CreateObject("Ac roExch.PDDoc", "");
int ret = pdfDoc.Open(inputFile);
if (ret == 0)
{
throw new FileNotFoundException();
}
// Get the number of pages (to be used later if you wanted to store that information)
int pageCount = pdfDoc.GetNumPages();
// Get the first page
pdfPage = (Acrobat.CAcroPDPage)pdfDoc.AcquirePage(0);
pdfPoint = (Acrobat.CAcroPoint)pdfPage.GetSize();
pdfRect = (Acrobat.CAcroRect)
Microsoft.VisualBasic.Interaction.CreateObject("Ac roExch.Rect", "");
pdfRect.Left = 0;
pdfRect.right = pdfPoint.x;
pdfRect.Top = 0;
pdfRect.bottom = pdfPoint.y;
// Render to clipboard, scaled by 100 percent (ie. original size)
// Even though we want a smaller image, better for us to scale in .NET
// than Acrobat as it would greek out small text
pdfPage.CopyToClipboard(pdfRect, 0, 0, 100);
IDataObject clipboardData = Clipboard.GetDataObject();
if (clipboardData.GetDataPresent(DataFormats.Bitmap))
{
Bitmap pdfBitmap =
(Bitmap)clipboardData.GetData(DataFormats.Bitmap);
}
pls take a look at this link For more info
you can try this one also
SautinSoft.PdfFocus f = new SautinSoft.PdfFocus();
f.ConvertPdfToImage(#"c:\sample.pdf", #"c:\pages\",
SautinSoft.PdfFocus.eImageFormat.Jpeg, 200);
pls go through this link for more info

C# How can I test a file is a jpeg?

Using C# how can I test a file is a jpeg? Should I check for a .jpg extension?
Thanks
Several options:
You can check for the file extension:
static bool HasJpegExtension(string filename)
{
// add other possible extensions here
return Path.GetExtension(filename).Equals(".jpg", StringComparison.InvariantCultureIgnoreCase)
|| Path.GetExtension(filename).Equals(".jpeg", StringComparison.InvariantCultureIgnoreCase);
}
or check for the correct magic number in the header of the file:
static bool HasJpegHeader(string filename)
{
using (BinaryReader br = new BinaryReader(File.Open(filename, FileMode.Open, FileAccess.Read)))
{
UInt16 soi = br.ReadUInt16(); // Start of Image (SOI) marker (FFD8)
UInt16 marker = br.ReadUInt16(); // JFIF marker (FFE0) or EXIF marker(FFE1)
return soi == 0xd8ff && (marker & 0xe0ff) == 0xe0ff;
}
}
Another option would be to load the image and check for the correct type. However, this is less efficient (unless you are going to load the image anyway) but will probably give you the most reliable result (Be aware of the additional cost of loading and decompression as well as possible exception handling):
static bool IsJpegImage(string filename)
{
try
{
using (System.Drawing.Image img = System.Drawing.Image.FromFile(filename))
{
// Two image formats can be compared using the Equals method
// See http://msdn.microsoft.com/en-us/library/system.drawing.imaging.imageformat.aspx
//
return img.RawFormat.Equals(System.Drawing.Imaging.ImageFormat.Jpeg);
}
}
catch (OutOfMemoryException)
{
// Image.FromFile throws an OutOfMemoryException
// if the file does not have a valid image format or
// GDI+ does not support the pixel format of the file.
//
return false;
}
}
Open the file as a stream and look for the magic number for JPEG.
JPEG image files begin with FF D8 and
end with FF D9. JPEG/JFIF files
contain the ASCII code for 'JFIF' (4A
46 49 46) as a null terminated string.
JPEG/Exif files contain the ASCII code
for 'Exif' (45 78 69 66) also as a
null terminated string
OMG, So many of these code examples are wrong, wrong wrong.
EXIF files have a marker of 0xff*e1*, JFIF files have a marker of 0xff*e0*. So all code that relies on 0xffe0 to detect a JPEG file will miss all EXIF files.
Here's a version that will detect both, and can easily be altered to return only for JFIF or only for EXIF. (Useful when trying to recover your iPhone pictures, for example).
public static bool HasJpegHeader(string filename)
{
try
{
// 0000000: ffd8 ffe0 0010 4a46 4946 0001 0101 0048 ......JFIF.....H
// 0000000: ffd8 ffe1 14f8 4578 6966 0000 4d4d 002a ......Exif..MM.*
using (BinaryReader br = new BinaryReader(File.Open(filename, FileMode.Open, FileAccess.ReadWrite)))
{
UInt16 soi = br.ReadUInt16(); // Start of Image (SOI) marker (FFD8)
UInt16 marker = br.ReadUInt16(); // JFIF marker (FFE0) EXIF marker (FFE1)
UInt16 markerSize = br.ReadUInt16(); // size of marker data (incl. marker)
UInt32 four = br.ReadUInt32(); // JFIF 0x4649464a or Exif 0x66697845
Boolean isJpeg = soi == 0xd8ff && (marker & 0xe0ff) == 0xe0ff;
Boolean isExif = isJpeg && four == 0x66697845;
Boolean isJfif = isJpeg && four == 0x4649464a;
if (isJpeg)
{
if (isExif)
Console.WriteLine("EXIF: {0}", filename);
else if (isJfif)
Console.WriteLine("JFIF: {0}", filename);
else
Console.WriteLine("JPEG: {0}", filename);
}
return isJpeg;
return isJfif;
return isExif;
}
}
catch
{
return false;
}
}
You could try loading the file into an Image and then check the format
Image img = Image.FromFile(filePath);
bool isBitmap = img.RawFormat.Equals(ImageFormat.Jpeg);
Alternatively you could open the file and check the header to get the type
You could find documentation on the jpeg file format, specifically the header information. Then try to read this information from the file and compare it to the expected jpeg header bytes.
Read the header bytes. This article contains info on several common image formats, including JPEG:
Using Image File Headers To Verify Image Format
JPEG Header Information
Once you have the extension you could use a regular expression to validate it.
^.*\.(jpg|JPG)$
This will loop through each file in the current directory and will output if any found files with JPG or JPEG extension are Jpeg images.
foreach (FileInfo f in new DirectoryInfo(".").GetFiles())
{
if (f.Extension.ToUpperInvariant() == ".JPG"
|| f.Extension.ToUpperInvariant() == ".JPEG")
{
Image image = Image.FromFile(f.FullName);
if (image.RawFormat == ImageFormat.Jpeg)
{
Console.WriteLine(f.FullName + " is a Jpeg image");
}
}
}
Depending on the context in which you're looking at this file, you need to remember that you can't open the file until the user tells you to open it.
(The link is to a Raymond Chen blog entry.)
The code here:
http://mark.michaelis.net/Blog/RetrievingMetaDataFromJPEGFilesUsingC.aspx
Shows you how to get the Meta Data. I guess that would throw an exception if your image wasn't a valid JPEG.
Checking the file extension is not enough as the filename might be lying.
A quick and dirty way is to try and load the image using the Image class and catching any exceptions:
Image image = Image.FromFile(#"c:\temp\test.jpg");
This isn't ideal as you could get any kind of exception, such as OutOfMemoryException, FileNotFoundException, etc. etc.
The most thorough way is to treat the file as binary and ensure the header matches the JPG format. I'm sure it's described somewhere.
The best way would to try and create an image from it using the Drawing.Bitmap (string) constructor and see if it fails to do so or throws an exception. The problem with some of the answers are this: firstly, the extension is purely arbitrary, it could be jpg, jpeg, jpe, bob, tim, whatever. Secondly, just using the header isn't enough to be 100% sure. It can definitely determine that a file isn't a jpeg but can't guarantee that a file is a jpeg, an arbitrary binary file could have the same byte sequence at the start.
Just take the media type of file and verify:
private bool isJpeg()
{
string p = currFile.Headers.ContentType.MediaType;
return p.ToLower().Equals("image/jpeg") || p.ToLower().Equals("image/pjpeg") || p.ToLower().Equals("image/png");
}
after check extention of file read first four byte of image and two last byte of image like this, do it for two last byte for value 255 , 217
for other file can do it
Validate image from file in C#
http://www.garykessler.net/library/file_sigs.html
// after check extention of file
byte[] ValidFileSignture = new byte[] { 255, 216, 255, 224 };
byte[] bufferforCheck = new byte[ValidFileSignture.Length];
Stream _inputStream = file.InputStream;
byte[] bufferforCheck1 = new byte[] { 255, 216, 255, 224 };
_inputStream.Read(bufferforCheck, 0, ValidFileSignture.Length);
if (!Enumerable.SequenceEqual(bufferforCheck, ValidFileSignture))
{
//file OK
}
System.Web.MimeMapping.GetMimeMapping(filename).StartsWith("image/");
MimeMapping.GetMimeMapping produces these results:
file.jpg: image/jpeg
file.gif: image/gif
file.jpeg: image/jpeg
file.png: image/png
file.bmp: image/bmp
file.tiff: image/tiff
file.svg: application/octet-stream
You can use the Path.GetExtension Method.

Categories