This pdf is displayed on my Firefox very well but in a C# program I wrote using itextsharp 5.4.4, I used the GetDrawingImage method of the PdfImageObject and I get a grabled image.
I used itextsharp in the following way:
PdfReader reader = new PdfReader(filename);
PdfReaderContentParser parser = new PdfReaderContentParser(reader);
ImageRenderListener listener = new ImageRenderListener();
parser.ProcessContent(pageNumber, listener);
Where ImageRenderListener is a IRenderListener, which implements the RenderImage method in the following way:
public void RenderImage(ImageRenderInfo renderInfo)
{
PdfImageObject image = renderInfo.GetImage();
PdfObject obj = image.Get(PdfName.FILTER);
PdfName filter = null;
if (obj is PdfName)
{
filter = (PdfName)obj;
}
else if (obj is PdfArray)
{
foreach(var o in (PdfArray)obj)
{
if (o is PdfName)
{
filter = o as PdfName;
break;
}
}
}
if (filter != null)
{
System.Drawing.Image drawingImage = image.GetDrawingImage();
...
...
...
}
The drawing image is stored in the listener and then drawn to the screen etc...
I tried to understand this, I get that the filter is a /CCITTFaxDecode but the streamContentType is somehow a png, could someone enlighten me on this matter?
The reason for this problem is explained in the following video: Ripping your PDF files apart. If you don't want to sit through the complete video, fast forward to minute 24 and watch everything up onto minute 27. Note the conclusion on minute 27: In general, there are no images in PDF. (That's exaggerated, but if you understand the 3 minutes of explanation, you understand what Mark Stephens means.)
If you want the details about why CCITTFaxDecode is changed into PNG, please read chapter 10 of my book.
Related
In the end, my goal is to send a raw image data from the front-end, then split that image into however many pages, and lastly send that pdf back to the front-end for download.
But every time I use the theDoc.addImageFile(), it tells me that the "Image is not in a suitable format". I'm using this as reference: https://www.websupergoo.com/helppdfnet/source/5-abcpdf/doc/1-methods/addimagefile.htm
To troubleshoot, I thought that the image might not be rendering correctly, so I added a File.WriteAllBytes to view the rendered image and it was exactly what I wanted, but still not adding to the PDF. I also tried sending the actual path of a previously rendered image thinking that the new image might not have been fully created yet, but it also gave me the same error. Lastly, I thought PNGs might be problematic and changed to JPG but it did not work.
Here is the code:
[HttpPost]
public IActionResult PrintToPDF(string imageString)
{
// Converts dataUri to bytes
var base64Data = Regex.Match(imageString, #"data:image/(?<type>.+?),(?<data>.+)").Groups["data"].Value;
var binData = Convert.FromBase64String(base64Data);
/* Ultimately will be removed, but used for debugging image */
string path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
string imgName= "Test.jpg";
string filename = Path.Combine(path, imgName);
System.IO.File.WriteAllBytes(filename, binData);
/***********************************************************/
using (Doc theDoc = new Doc())
{
// Using explicit path
theDoc.AddImageFile(#"C:\Users\User\Documents\Test.jpg", 1);
// Using variable
//theDoc.AddImageFile(filename, 1);
// What I really want
//theDoc.AddImageFile(binData , 1);
theDoc.Page = theDoc.AddPage();
theDoc.AddText("Thanks");
Response.Headers.Clear();
Response.Headers.Add("content-disposition", "attachment; filename=test.pdf");
return new FileStreamResult(theDoc.GetStream(), "application/pdf");
}
}
Try something like this (not tested, but cleaned up from my own code):
public int AddImageFile(Doc doc, byte[] data, int insertBeforePageID)
{
int pageid;
using (var img = new XImage())
{
img.SetData(data);
doc.Page = doc.AddPage(insertBeforePageID);
pageid = doc.Page;
doc.AddImage(img);
img.Clear();
}
return pageid;
}
To add a JPEG from a byte array you need Doc.AddImageData instead of Doc.AddImageFile. Note that AddImageFile / AddImageData do not support PNG - for that you would definitely need to use an XImage. The XImage.SetData documentation has the currently supported image formats.
I've an IFormFile image file (from postman as form data), which I convert into byte array. Before converting it into byte array, I want to rotate it into its actual position (if user input image as 90°(right). I'm implementing web api in asp.net core 2.0.
byte[] ImageBytes = Utils.ConvertFileToByteArray(model.Image);
public static byte[] ConvertFileToByteArray(IFormFile file)
{
using (var memoryStream = new MemoryStream())
{
file.CopyTo(memoryStream);
return memoryStream.ToArray();
}
}
Any help, Thanks in advance.
In my project I need to crop and resize the images users upload. And I am using a fantastic library called ImageSharp from Six Labors. You can use its image processor to do the transformation such as Resize, Crop, Skew, Rotate and more!
Install via NuGet
I am actually using their nightly build through MyGet.
Visual Studio -> Tools -> Options -> NuGet Package Manager -> Package Sources
Hit the "Plus" button to add a new package resource
I typed "ImageSharp Nightly" as the name and put "https://www.myget.org/F/sixlabors/api/v3/index.json" as the source url.
On Browse, search "SixLabors.ImageSharp" (In my case I also need "SixLabors.ImageSharp.Drawing" but in your case you might only need to core library. Always refer back to their documentations).
Crop & Resize
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Processing.Transforms;
using SixLabors.Primitives;
using System.IO;
namespace DL.SO.Project.Services.ImageProcessing.ImageSharp
{
public CropAndResizeResult CropAndResize(byte[] originalImage,
int offsetX, int offsetY, int croppedWidth, int croppedHeight,
int finalWidth, int finalHeight) : IImageProcessingService
{
IImageFormat format;
using (var image = Image.Load(originalImage, out format))
{
image.Mutate(x => x
// There is .Rotate() you can call for your case
.Crop(new Rectangle(offsetX, offsetY, croppedWidth, croppedHeight))
.Resize(finalWidth, finalHeight));
using (var output = new MemoryStream())
{
image.Save(output, format);
// This is just my custom class. But see you can easily
// get the processed image byte[] using the ToArray() method.
return new CropAndResizeResult
{
ImageExtension = format.Name,
CroppedImage = output.ToArray()
};
}
}
}
}
Hope this helps you - from a big fan of ImageSharp library!
Magick.NET, The ImageMagick wrapper for .Net Core can be used for many file manipulations, see https://github.com/dlemstra/Magick.NET
byte[] byt = System.IO.File.ReadAllBytes(filePath);
System.IO.MemoryStream ms = new System.IO.MemoryStream(byt);
using (Image img = Image.FromStream(ms))
{
RotateFlipType r = angle == 90 ? RotateFlipType.Rotate90FlipNone : RotateFlipType.Rotate270FlipNone;
img.RotateFlip(r);
img.Save(filePath);
}
Using your existing code you can do the following
I have a HP Scanjet 7000 (duplex & ADF scanner) and a HP Scanjet 5500c (only ADF) and a scanner program I'm developing which uses WIA 2.0 on Windows 7.
The problem is that the code works perfectly on the older scanner model, but on the newer one the code seems to run just fine through the first page, then fail on the second. If I step through the code around the following line;
image = (WIA.ImageFile)wiaCommonDialog.ShowTransfer(item, wiaFormatTIFF, false);
the old scanner stops and waits for another call to be made on the same reference, but the newer one just runs through all it's pages from the feeder in one continuous operation.
I notice if I'm using the default scanning program in Windows 7, the newer one returns a single .tif file which contains all the separate pages. The older one returns separate .jpg files (one for each page).
This indicates to me that the newer scanner is scanning through its whole feeder before it is ready to return a collection of images where the older one returns ONE image between each page scanned.
How can I support this behavior in code? The following is part of the relevant code which works on the older scanner model:
public static List<Image> Scan(string scannerId)
{
List<Image> images = new List<Image>();
List<String> tmp_imageList = new List<String>();
bool hasMorePages = true;
bool useAdf = true;
bool duplex = false;
int pages = 0;
string fileName = null;
string fileName_duplex = null;
WIA.DeviceManager manager = null;
WIA.Device device = null;
WIA.DeviceInfo device_infoHolder = null;
WIA.Item item = null;
WIA.ICommonDialog wiaCommonDialog = null;
manager = new WIA.DeviceManager();
// select the correct scanner using the provided scannerId parameter
foreach (WIA.DeviceInfo info in manager.DeviceInfos)
{
if (info.DeviceID == scannerId)
{
// Find scanner to connect to
device_infoHolder = info;
break;
}
}
while (hasMorePages)
{
wiaCommonDialog = new WIA.CommonDialog();
// Connect to scanner
device = device_infoHolder.Connect();
if (device.Items[1] != null)
{
item = device.Items[1] as WIA.Item;
try
{
if ((useAdf) || (duplex))
SetupADF(device, duplex); //Sets the right properties in WIA
WIA.ImageFile image = null;
WIA.ImageFile image_duplex = null;
// scan image
image = (WIA.ImageFile)wiaCommonDialog.ShowTransfer(item, wiaFormatTIFF, false);
if (duplex)
{
image_duplex = (ImageFile)wiaCommonDialog.ShowTransfer(item, wiaFormatPNG, false);
}
// save (front) image to temp file
fileName = Path.GetTempFileName();
tmp_imageList.Add(fileName);
File.Delete(fileName);
image.SaveFile(fileName);
image = null;
// add file to images list
images.Add(Image.FromFile(fileName));
if (duplex)
{
fileName_duplex = Path.GetTempFileName();
tmp_imageList.Add(fileName_duplex);
File.Delete(fileName_duplex);
image_duplex.SaveFile(fileName_duplex);
image_duplex = null;
// add file_duplex to images list
images.Add(Image.FromFile(fileName_duplex));
}
if (useAdf || duplex)
{
hasMorePages = HasMorePages(device); //Returns true if the feeder has more pages
pages++;
}
}
catch (Exception exc)
{
throw exc;
}
finally
{
wiaCommonDialog = null;
manager = null;
item = null;
device = null;
}
}
}
device = null;
return images;
}
Any help on this issue would be very much appreciated! I can't seem to find a working solution on the web. Just unanswered forum posts from people with the same problem.
we had a very similar problem and various solutions, e.g. by setting certain properties, did not help. The main problem was that the scanner (ADF) retracted all pages on startup, regardless of what was happening in the program code.
The process repeatedly led to errors, since "too much" was made before the next page was scanned. This applies in particular to the fact that another "Connect" was attempted.
For this reason, we have modified the code so that the individual pages can be read in as quickly as possible:
public List<Image> Scan(string deviceID)
{
List<Image> images = new List<Image>();
WIA.ICommonDialog wiaCommonDialog = new WIA.CommonDialog();
WIA.Device device = this.Connect(deviceID);
if (device == null)
return images;
WIA.Item item = device.Items[1] as WIA.Item;
List<WIA.ImageFile> wiaImages = new List<ImageFile>();
try
{
// scan images
do
{
WIA.ImageFile image = (WIA.ImageFile)wiaCommonDialog.ShowTransfer(item, wiaFormatJPEG, false);
wiaImages.Add(image);
} while (true);
}
catch (System.Runtime.InteropServices.COMException ex)
{
if ((uint)ex.ErrorCode != WIA_PROPERTIES.WIA_ERROR_PAPER_EMPTY)
throw ex;
}
catch (Exception ex)
{
throw ex;
}
foreach (WIA.ImageFile image in wiaImages)
this.DoImage(images, image);
return images;
}
I see you're calling a method called SetupADF, which is not shown, that presumably sets some properties on the device object. Have you tried setting WIA_DPS_PAGES (property 3096) and/or WIA_DPS_SCAN_AHEAD_PAGES (property 3094)?
I have a blog post about scanning from an ADF in Silverlight, and I believe a commenter came up against the same issue you're having. Setting WIA_DPS_PAGES to 1 fixed it for him. I ended up modifying my code's SetDeviceProperties method to set WIA_DPS_PAGES to 1 and WIA_DPS_SCAN_AHEAD_PAGES to 0.
After alot of trial and error I stumbled upon a solution which worked for reasons I'm not quite sure of. It seems like the ShowTransfer() method was unable to convert the page to .png or .tiff WHILE scanning. Setting the format to JPEG or BMP actually solved the issue for me:
image = (ImageFile)scanDialog.ShowTransfer(item, wiaFormatJPEG, false);
I think I saw somewhere on the web that this method actually returns BMP regardless of the format specified. Might be that converting the image to png or tiff is too heavy as opposed to using bmp or jpeg.
On a sidenote, I'm setting the property setting: 3088 to 0x005 (adf AND duplex mode).
I want to load images into a Pivot header to substitute the lack of a Gallery control in WP7. I'm trying to populate them from a URL, and want to make sure that the image is not kept in the cache (by setting UriSource = null) to make sure that they don't take too much resources.
There's no way to do this in the XAML itself, can someone give me sample code to handle this from code-behind. my attempts have been unsuccessful. what am I doing wrong here?
public class PhotoGalleryVM
{
public ObservableCollection<BitmapImage> Images
{
get
{
ObservableCollection<BitmapImage> list = new ObservableCollection<BitmapImage>();
foreach (RoomImage r in App.appData.currentChoices.roomImages)
{
BitmapImage img = new BitmapImage(new Uri(Uri.UnescapeDataString(r.largeUri)));
img.UriSource = null;
list.Add(img);
}
return list;
}
}
}
There is an option that enables to ignore image cache:
bitmapImage.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
Read more at msdn
My script fetches xml via httpConnection and saves to persistent store. No problems there.
Then I loop through the saved data to compose a list of image url's to fetch via queue.
Each of these requests calls the httpConnection thread as so
...
public synchronized void run()
{
HttpConnection connection = (HttpConnection)Connector.open("http://www.somedomain.com/image1.jpg");
connection.setRequestMethod("GET");
String contentType = connection.getHeaderField("Content-type");
InputStream responseData = connection.openInputStream();
connection.close();
outputFinal(responseData, contentType);
}
public synchronized void outputFinal(InputStream result, String contentType) throws SAXException, ParserConfigurationException, IOException
{
if(contentType.startsWith("text/"))
{
// bunch of xml save code that works fine
}
else if(contentType.equals("image/png") || contentType.equals("image/jpeg") || contentType.equals("image/gif"))
{
// how to save images here?
}
else
{
//default
}
}
What I can't find any good documentation on is how one would take the response data and save it to an image stored on the device.
Maybe I just overlooked something very obvious. Any help is very appreciated.
Thanks
I tried following this advise and found the same thing I always find when looking up BB specific issues: nothing.
The problem is that every example or post assumes you know everything about the platform.
Here's a simple question: What line of code writes the read output stream to the blackberry device? What path? How do I retrieve it later?
I have this code, which I do not know if it does anything because I don't know where it is supposedly writing to or if that's even what it is doing at all:
** filename is determined on a loop based on the url called.
FileOutputStream fos = null;
try
{
fos = new FileOutputStream( File.FILESYSTEM_PATRIOT, filename );
byte [] buffer = new byte [262144];
int byteRead;
while ((byteRead = result.read (buffer ))!=- 1)
{
fos.write (buffer, 0, byteRead);
}
fos.flush();
fos.close();
}
catch(IOException ieo)
{
}
finally
{
if(fos != null)
{
fos.close();
}
}
The idea is that I have some 600 images pulled from a server. I need to loop the xml and save each image to the device so that when an entity is called, I can pull the associated image - entity_id.png - from the internal storage.
The documentation from RIM does not specify this, nor does it make it easy to begin figuring it out.
This issue does not seem to be addressed on this forum, or others I have searched.
Thanks
You'll need to use the Java FileOutputStream to do the writing. You'll also want to close the connection after reading the data from the InputStream (move outputFinal above your call to close). You can find all kinds of examples regarding FileOutputStream easily.
See here for more. Note that in order to use the FileOutputStream your application must be signed.