Converting TIFF to PDF results in Insufficient Data For Image - pdf

I have a utility that converts batches of TIFF images to PDFs using the PDFSharp library. The following code performs the actual conversion. When I open the resulting PDF files in Acrobat Reader, I receive an error message for certain ones stating "Insufficient Data for Image." Others are fine.
What could be causing this? Is there anything I'm missing in the code that could prevent this?
Public Shared Function ConvertImageToPDF(ByVal img As Image) As Byte()
Using ms As New MemoryStream()
Using pdf As New PdfDocument()
Dim pageCount = GetPageCount(img)
For index = 0 To (pageCount - 1)
Dim page = New PdfPage()
Using sourceImage = GetPage(img, index)
Using pageImage = XImage.FromGdiPlusImage(sourceImage)
page.Width = pageImage.PointWidth
page.Height = pageImage.PointHeight
pdf.Pages.Add(page)
Using xgr = XGraphics.FromPdfPage(pdf.Pages(index))
xgr.DrawImage(pageImage, 0, 0)
End Using
End Using
End Using
Next
pdf.Save(ms, False)
pdf.Close()
End Using
Return ms.ToArray()
End Using
End Function
Public Shared Function GetPageCount(ByVal img As Image) As Integer
If (img Is Nothing) Then
Return -1
End If
Return img.GetFrameCount(FrameDimension.Page)
End Function
Public Shared Function GetPage(ByVal img As Image, ByVal pageNumber As Integer) As Image
img.SelectActiveFrame(FrameDimension.Page, pageNumber)
Dim ms = New MemoryStream()
img.Save(ms, ImageFormat.Tiff)
Return Image.FromStream(ms)
End Function
UPDATE:
If I run the same code over the same TIFF files, then the PDF files that were corrupt before are now OK, and ones that were OK before are now corrupt.
UPDATE 2:
After reviewing this connect issue (https://connect.microsoft.com/VisualStudio/feedback/details/584681/system-drawing-image-flags-has-different-value-in-vista-and-windows-7) and the community comment on this MSDN page (http://msdn.microsoft.com/en-us/library/system.drawing.image.save.aspx), it appears the issue is related to an operating system level bug in Windows 7. Can anyone confirm this or offer a workaround?

As stated in my update, after reviewing this connect issue (https://connect.microsoft.com/VisualStudio/feedback/details/584681/system-drawing-image-flags-has-different-value-in-vista-and-windows-7) and the community comment on this MSDN page (http://msdn.microsoft.com/en-us/library/system.drawing.image.save.aspx), it appears the issue is related to an operating system level bug in Windows 7.
This is supported by the comment from PDFsharpTeam.
In addition, when the images are read in Windows XP, the flags property on the image object is set to 77888. On Win7, it is set to 77840. After reviewing the MSDN documentation for the flags property (http://msdn.microsoft.com/en-us/library/system.drawing.image.flags.aspx), the difference is that WinXP flagged the image as a grayscale image (which mine are), but Win7 flagged it as an RGB image. This appears to be a symptom of the problem, but I don't know enough about image formats and color spaces to speak with authority on this.
UPDATE (2014-06-13):
After continuing to experience this problem, I researched a bit further and found a post on the PDFSharp forums mentioning this issue and linking to another post with a fix.
http://forum.pdfsharp.net/viewtopic.php?f=2&t=2729
http://forum.pdfsharp.net/viewtopic.php?p=5967#p5967
Basically, there are two methods in the PdfImage.FaxEncode.cs file that need to be updated.
In both the CountOneBits() and CountZeroBits() methods, replace the following code:
return found + hits;
with
found += hits;
if (found >= bitsLeft)
return bitsLeft;
return found;

Related

Deployment of Outlook Add-in - no resources / images

I am trying to deploy an Add-in I wrote, but it has trouble finding associated resources - that is, images for the ribbon.
My GetImage-function is this:
Dim path As String = AppDomain.CurrentDomain.BaseDirectory
System.Windows.Forms.MessageBox.Show(path)
path = path.Substring(0, path.LastIndexOf("\bin")) + "\Resources\" + imageName
Return New Drawing.Bitmap(path)
The reason it fails seems to be that AppDomain.CurrentDomain.BaseDirectory is C:\Users\MZE\AppData\Local\Apps\2.0\4RZKJG5Q.XVT\72NBJ1XY.1QH\andsoon. So for some reason on publishing the images are not rolled out as resources. I added them via the project properties add resources dialog in Visual Studio.
I have also tried setting build to resources and copy to out in the image properties in Visual Studio.
I would appreciate any hints.
Make sure the images you add to your project are in the Resources section of your solution.
Check the project folder structure for your images.
Try the following revised procedure for your GetImage function. Use IntelliSense to navigate to your images under My.Resources.``resourceName. You shouldn't need to reference a path for the images.
Public Function GetImage(control As Office.IRibbonControl) As System.Drawing.Bitmap
Try
Select Case control.Id
Case "btnYourButton1"
Return My.Resources.Image1
Case "btnYourButton2"
Return My.Resources.Image2
Case "btnYourButton3"
Return My.Resources.Image3
Case Else
Return Nothing
End Select
Catch ex As Exception
Return Nothing
End Try
End Function
Here is the Microsoft reference for the Resources object.

Bringing ToolWindow to Front of Application

Basically, in my code I transform my form into a toolwindow in the load event:
Dim lStyleEx As Long = win32.WS._EX_TOOLWINDOW
Call SetWindowLong(Handle, win32.GWL.__EXSTYLE, CInt(lStyleEx))
Const swpFlags As Long = _
win32.SWP._FRAMECHANGED Or _
win32.SWP._NOMOVE Or _
win32.SWP._NOSIZE Or _
win32.SWP._NOZORDER
Call SetWindowPos(Handle, CType(0, IntPtr), 0, 0, 0, 0, CType(swpFlags, win32.SetWindowPosFlags))
(I have a class win32 containing enums for all the constants)
Now, I want to bring this toolwindow to the front with the IVsWindowFrame.Show(), but I'm having trouble getting the actual IVsWindowFrame for my form. After trawling the web I found a snippet on the MSDN forums, but after converting to VBA various issues come up, e.g. I don't know how to properly create a new ServiceProvider:
Dim shell As IVsUIShell = DirectCast(ServiceProvider.GetService(GetType(SVsUIShell)), IVsUIShell)
Dim frame As IVsWindowFrame
Dim guid As New Guid(ToolWindow.GuidList.guidToolWindowPersistanceString)
shell.FindToolWindow(CUInt(__VSFINDTOOLWIN.FTW_fForceCreate), guid, frame)
frame.Show()
Sourced from https://social.msdn.microsoft.com/Forums/vstudio/en-US/d6c2b85c-3a48-48f7-a9f6-a68ea4ef0441/how-to-get-access-to-my-toolwindowpane-object-with-an-ivswindowframe-pointer?forum=vsx
Any help with finding the IVsUIShell of a form or an explanation on this code would be greatly appreciated!
I've also tried something as simple as setting the actual form as an IVsWindowFrame:
Dim windowFrame As IVsWindowFrame = CType(Me, IVsWindowFrame)
windowFrame.Show()
but it throws an exception:
type 'RifleSystem.scrSettings' to type 'Microsoft.VisualStudio.Shell.Interop.IVsWindowFrame'.
btw, I'm running 64-bit VS2013 if that helps.
Okay I feel stupid now. There's a property Form.Owner which does exactly what I need in this scenario, and it works perfectly! No need for all this convuluted stuff :D
Here's the link in case anyone is interested:
https://msdn.microsoft.com/en-us/library/system.windows.forms.form.owner%28v=vs.110%29.aspx

Read From Text File in Windows 8 Apps/Windows Phone 8 Apps

If I'm going in the wrong direction, please feel free to give me some guidance!
I'm having trouble understanding the use of streams in the Visual Studio for Windows 8 Apps and Windows 8 Phone Apps environment.
All I want to do is read some text from a file into a string. Here's my simple code that I would use for Visual Studio for Windows Desktop:
Sub ReadFromFileTest()
Dim FilePath As String = "c:\2012\Projects\VBDesktopTest\Test.txt"
Dim ReadString As String
Dim Reader As New System.IO.StreamReader(FilePath)
ReadString = Reader.ReadLine()
Do Until ReadString Is Nothing
OutputListBox.Items.Add(ReadString)
ReadString = Reader.ReadLine()
Loop
Reader.Close()
Reader.Dispose()
End Sub
This same code in Visual Studio for Windows 8 Applications generates an error: "value of type 'string' cannot be converted to 'system.io.stream'". I've looked through the list of constructors for the StreamReader class and I see that StreamReader(file name as string) is not supported in ".NET for Windows Store apps". It seems I need to use the StreamReader(stream) constructor but I can't seem to figure out how to make a make my file into a stream.
My ultimate goal is to create a simple app for Windows Phone 7.1 that looks up and returns information from a list of equipment stored in a text file. I'm starting with Windows 8 so as not to further confuse myself with the phone emulator.
See I have no idea of Vb .net But I am sharing the c# code (function) that serves the purpose for windows phone
private string ReadFile(string filePath)
{
//this verse is loaded for the first time so fill it from the text file
var ResrouceStream = Application.GetResourceStream(new Uri(filePath, UriKind.Relative));
if (ResrouceStream != null)
{
Stream myFileStream = ResrouceStream.Stream;
if (myFileStream.CanRead)
{
StreamReader myStreamReader = new StreamReader(myFileStream);
//read the content here
return myStreamReader.ReadToEnd();
}
}
return "NULL";
}
The answer i took is from this link
Reading files from stream windows phone

Out of memory exception while loading images

I am using the following piece of code to load images as thumbnails to a FlowLayoutPanel control. Unfortunately i get an OutOfMemory exception.
As you already guess the memory leak is found at line
Pedit.Image = System.Drawing.Image.FromStream(fs)
So how could i optimize the following code?
Private Sub LoadImagesCommon(ByVal FlowPanel As FlowLayoutPanel, ByVal fi As FileInfo)
Pedit = New DevExpress.XtraEditors.PictureEdit
Pedit.Width = txtIconsWidth.EditValue
Pedit.Height = Pedit.Width / (4 / 3)
Dim fs As System.IO.FileStream
fs = New System.IO.FileStream(fi.FullName, IO.FileMode.Open, IO.FileAccess.Read)
Pedit.Image = System.Drawing.Image.FromStream(fs)
fs.Close()
fs.Dispose()
Pedit.Properties.SizeMode = DevExpress.XtraEditors.Controls.PictureSizeMode.Zoom
If FlowPanel Is flowR Then
AddHandler Pedit.MouseClick, AddressOf Pedit_MouseClick
AddHandler Pedit.MouseEnter, AddressOf Pedit_MouseEnter
AddHandler Pedit.MouseLeave, AddressOf Pedit_MouseLeave
End If
FlowPanel.Controls.Add(Pedit)
End Sub
Update: The problem occurs while loading a number of images (3264x2448px at 300dpi - each image is about 3Mb's)
Documentation for Image.FromFile (which is related to your FromStream) says that it will throw OutOfMemoryException if the file is not a valid image format or if GDI+ doesn't support the pixel format. Is it possible you're trying to load an unsupported image type?
Also, documentation for Image.FromStream says that you have to keep the stream open for the lifetime of the image, so even if your code loaded the image you'd probably get an error because you're closing the file while the image is still active. See http://msdn.microsoft.com/en-us/library/93z9ee4x.aspx.
Couple of thoughts:
First off, as Jim has stated, when using Image.FromStream the stream should remain open for the lifetime of the Image as remarked on the MSDN page. As such, I would suggest to copy the contents of the file to a MemoryStream, and use the latter to create the Image instance. So you can release the file handle asap.
Secondly, the images you're using are rather big (uncompressed, as they would exist in memory, Width x Height x BytesPerPixel). Assuming the context you use them in might allow for them to be smaller, consider resizing them, and potentially caching the resized versions somewhere for later use.
Lastly, don't forget to Dispose the image and the Stream when they are no longer needed.
You can solve this in a few steps:
to get free from the File-dependency, you have to copy the images. By really drawing it to a new Bitmap, you can't just copy it.
since you want thumbnails, and your source-bitmaps are rather large, combine this with shrinking the images.
I had the same problem. Jim Mischel answer led me to discover loading an innocent .txt file was the culprit. Here's my method in case anyone is interested.
Here's my method:
/// <summary>
/// Loads every image from the folder specified as param.
/// </summary>
/// <param name="pDirectory">Path to the directory from which you want to load images.
/// NOTE: this method will throws exceptions if the argument causes
/// <code>Directory.GetFiles(path)</code> to throw an exception.</param>
/// <returns>An ImageList, if no files are found, it'll be empty (not null).</returns>
public static ImageList InitImageListFromDirectory(string pDirectory)
{
ImageList imageList = new ImageList();
foreach (string f in System.IO.Directory.GetFiles(pDirectory))
{
try
{
Image img = Image.FromFile(f);
imageList.Images.Add(img);
}
catch
{
// Out of Memory Exceptions are thrown in Image.FromFile if you pass in a non-image file.
}
}
return imageList;
}

Filetype check in VB.NET?

I have an image resized program and it works. The problem is when a user selects a non-image file in the file select dialog, it crashes. How can I check for image files?
UPDATE: 2022-04-05
Since it may not be feasible to validate the binary structure of every supported image, the fastest way to check if a file contains an image is to actually load it. If it loads successfully, then it is valid. If it doesn't then it is not.
The code below can be used to check if a file contains a valid image or not. This code is updated to prevent locking the file while the method is called. It also handles resource disposal after the tests (thanks for pointing out this issue user1931470).
Public Function IsValidImage(fileName As String) As Boolean
Dim img As Drawing.Image = Nothing
Dim isValid = False
Try
' Image.FromFile locks the file until the image is disposed.
' This might not be the wanted behaviour so it is preferable to
' open the file stream and read the image from it.
Using stream = New System.IO.FileStream(fileName, IO.FileMode.Open)
img = Drawing.Image.FromStream(stream)
isValid = True
End Using
Catch oome As OutOfMemoryException
' Image.FromStream throws an OutOfMemoryException
' if the file does not have a valid image format.
isValid = False
Finally
' clean up resources
If img IsNot Nothing Then img.Dispose()
End Try
Return isValid
End Function
ORIGINAL ANSWER
⚠️⚠️ WARNING ⚠️⚠️
This code has a bug that causes a high memory consumption when called several times in a program's lifetime.
DO NOT USE THIS CODE!!
Here's the VB.NET equivalent of 0xA3's answer since the OP insisted on a VB version.
Function IsValidImage(filename As String) As Boolean
Try
Dim img As System.Drawing.Image = System.Drawing.Image.FromFile(filename)
Catch generatedExceptionName As 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
End Try
Return True
End Function
You use it as follows:
If IsValidImage("c:\path\to\your\file.ext") Then
'do something
'
Else
'do something else
'
End If
Edit:
I don't recommend you check file extensions. Anyone can save a different file (text document for instance) with a .jpg extension and trick you app into beleiving it is an image.
The best way is to load the image using the function above or to open the first few bytes and check for the JPEG signature.
You can find more information about JPEG files and their headers here:
http://www.fastgraph.com/help/jpeg_header_format.html
http://en.wikipedia.org/wiki/JPEG
A very primitive check is to simply try to load the image. If it is not valid an OutOfMemoryException will be thrown:
static bool IsImageValid(string filename)
{
try
{
System.Drawing.Image img = System.Drawing.Image.FromFile(filename);
}
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;
}
return true;
}
If I understood your question correctly your application it going to load the image anyway. Therefore simply wrapping the load operation in a try/catch block does not mean any additional overhead. For the VB.NET solution of this approach check the answer by #Alex Essilfie.
The ones wondering why Image.FromFile is throwing an OOM on invalid files should read the answer of Hans Passant to the following question:
Is there a reason Image.FromFile throws an OutOfMemoryException for an invalid image format?
Your first line of defense, of course, would be simply to check the file's extension:
Function IsImageFile(ByVal filename As String) As Boolean
Dim ext As String = Path.GetExtension(filename).ToLowerInvariant()
' This supposes your program can deal only with JPG files; '
' you could add other extensions here as necessary. '
Return ext = ".jpg" OrElse ext = ".jpeg"
End Function
Better yet, as SLC suggests in a comment, set your dialog's Filter property:
dialog.Filter = "Image files|*.jpg;*.jpeg"
This isn't a guarantee -- ideally you'd want to check the file itself to verify it's an image, and theoretically you should also be able to load files with anomalous extensions if they are in fact image files (maybe just ask for the user's acknowledgement first) -- but it's an easy start.
The VB and C# answers are great but also contain a "gotcha" if you plan to alter or move the file: the created 'img' object will lock the image file unless the dispose() method is invoked to release it. See below:
VB
Function IsValidImage(filename As String) As Boolean
Try
Dim img As System.Drawing.Image = System.Drawing.Image.FromFile(filename)
img.dispose() ' Removes file-lock of IIS
Catch generatedExceptionName As 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
End Try
Return True
End Function
C#
static bool IsImageValid(string filename)
{
try
{
System.Drawing.Image img = System.Drawing.Image.FromFile(filename);
img.dispose(); // Removes file-lock of IIS
}
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;
}
return true;
}
The most robust way would be to understand the signatures of the files you need to load.
JPEG has a particular header format, for example.
This way your code won't be as easily fooled if you just look at the extension.
163's answer should get you most of the way along these lines.