I am compressing a pdf containing a number of images. The below code I got while browsing for the PDF compression. It works fine for RBG format images but in case of CMYK format the images appears with inverted colours (as a negative). Somehow I was able to convert the inverted colours but the image colour got faded.
Please suggest how should I proceed. Thanks in advance.
{
PdfReader.unethicalreading = true;
string pdfFile = #"C:\TestPdf.pdf";
PdfReader reader = new PdfReader(pdfFile);
long quality = 50L;
int n = reader.XrefSize;
for (int i = 0; i < n; i++)
{
PdfObject obj = reader.GetPdfObject(i);
if (obj == null || !obj.IsStream()) { continue; }
PdfDictionary dict = (PdfDictionary)PdfReader.GetPdfObject(obj);
PdfObject pdfcolorspace = dict.Get(PdfName.COLORSPACE);
PdfName subType = (PdfName)PdfReader.GetPdfObject(dict.Get(PdfName.SUBTYPE));
if (!PdfName.IMAGE.Equals(subType)) { continue; }
PRStream stream = (PRStream)obj;
try
{
PdfImageObject image = new PdfImageObject(stream);
PdfName filter = (PdfName)image.Get(PdfName.FILTER);
if ( PdfName.JBIG2DECODE.Equals(filter) || PdfName.JPXDECODE.Equals(filter) || PdfName.CCITTFAXDECODE.Equals(filter) || PdfName.FLATEDECODE.Equals(filter))
continue;
System.Drawing.Image img = image.GetDrawingImage();
if (img == null) continue;
var ll = image.GetImageBytesType();
int width = img.Width;
int height = img.Height;
using (System.Drawing.Bitmap dotnetImg = new System.Drawing.Bitmap(img))
{
System.Drawing.Imaging.ImageCodecInfo codec = System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders()[1];
System.Drawing.Imaging.EncoderParameters eParams = new System.Drawing.Imaging.EncoderParameters(1);
eParams.Param[0] = new System.Drawing.Imaging.EncoderParameter( System.Drawing.Imaging.Encoder.Quality, quality);
using (MemoryStream msImg = new MemoryStream())
{
dotnetImg.Save(msImg, codec, eParams);
msImg.Position = 0;
stream.Clear();
if (pdfcolorspace == PdfName.DEVICECMYK)
{
img.Save(msImg, ImageFormat.Jpeg);
stream.Put(PdfName.COLORSPACE, PdfName.DEVICECMYK);
}
else
{
stream.Put(PdfName.COLORSPACE, PdfName.DEVICERGB);
}
stream.SetData( msImg.ToArray(), true, PdfStream.BEST_COMPRESSION);
stream.Put(PdfName.TYPE, PdfName.XOBJECT);
stream.Put(PdfName.SUBTYPE, PdfName.IMAGE);
stream.Put(PdfName.FILTER, PdfName.DCTDECODE);
stream.Put(PdfName.WIDTH, new PdfNumber(width));
stream.Put(PdfName.HEIGHT, new PdfNumber(height));
stream.Put(PdfName.BITSPERCOMPONENT, new PdfNumber(8));
}
}
}
catch (Exception ex)
{
}
finally
{
reader.RemoveUnusedObjects();
}
}
PdfStamper stamper = new PdfStamper(reader, new FileStream(#"C:\Compress.pdf", FileMode.Create), PdfWriter.VERSION_1_5);
stamper.FormFlattening = false;
stamper.SetFullCompression();
stamper.Close();
reader.Close();
}
Related
I have inserted the image in the pdf using itextsharp as shown below and I tried all the possible solutions to extract it with using the coordinates.
String pathin = pdf.src;
String pathout = "C:\\....";
string signedFile = System.IO.Path.GetTempFileName();
PdfReader reader = new PdfReader(pathin);
FileStream fs = new FileStream(pathout, FileMode.Create);
PdfStamper stamper = new PdfStamper(reader, fs);
PdfContentByte cb = stamper.GetOverContent(1);
iTextSharp.text.Image image1 = iTextSharp.text.Image.GetInstance(imageFileName);
image1.RotationDegrees = 270f;
image1.Alignment = Element.ALIGN_TOP;
image1.SetAbsolutePosition(0,0);
image1.ScalePercent(50f, 50f);
cb.AddImage(image1);
stamper.Close();
fs.Close();
Console.Read();
pdf.src = pathout;
Is there any way to use itextsharp to extract image from position (0,0)?
pseudo-code:
implement IEventListener
parse the page you are interested in, CanvasProcessor takes an IEventListener implementation in its constructor, every time it finishes rendering text, an image, or a path, it will notify the IEventListener
IEventListener has a method called eventOccurred(IEventData data, EventType type). One of the types will be responsible for images
cast IEventData to ImageRenderInfo
derive the coordinates from the ImageRenderInfo object
if the coordinates happen to contain Point(0, 0) then (temporarily) store the image in a variable of your IEventListener
code sample (java, iText7)
disclaimer: the following code does not handle rotation
class MyImageSeek implements IEventListener{
private int pageNr = 0;
private Map<Integer, Map<Rectangle, BufferedImage>> images = new HashMap<>();
public MyImageSeek(PdfDocument pdfDocument){
PdfCanvasProcessor canvasProcessor = new PdfCanvasProcessor(this);
for(int i=1;i<=pdfDocument.getNumberOfPages();i++) {
images.put(i, new HashMap<Rectangle, BufferedImage>());
pageNr = i;
canvasProcessor.processPageContent(pdfDocument.getPage(i));
}
}
#Override
public void eventOccurred(IEventData data, EventType type) {
if(type != EventType.RENDER_IMAGE)
return;
ImageRenderInfo imageRenderInfo = (ImageRenderInfo) data;
int x = (int) imageRenderInfo.getStartPoint().get(0);
int y = (int) imageRenderInfo.getStartPoint().get(1);
int w = (int) imageRenderInfo.getImageCtm().get(Matrix.I11);
int h = (int) imageRenderInfo.getImageCtm().get(Matrix.I22);
try {
images.get(pageNr).put(new Rectangle(x,y,w,h), imageRenderInfo.getImage().getBufferedImage());
} catch (IOException e) {}
}
#Override
public Set<EventType> getSupportedEvents() {
return null;
}
public Map<Rectangle, BufferedImage> getImages(int pageNr){
return images.get(pageNr);
}
}
and this is the main method to call this class
PdfDocument pdfDocument = new PdfDocument(new PdfReader(new File("C:\\Users\\me\\lookAtMe.pdf")));
MyImageSeek meeseek = new MyImageSeek(pdfDocument);
for(Map.Entry<Rectangle, BufferedImage> en : meeseek.getImages(1).entrySet())
System.out.println(en.getKey() + "\t" + en.getValue());
I am using itextsharp for extracting content from PDF using c# as follow
public static string GetTextFromAllPages(String pdfPath)
{
PdfReader reader = new PdfReader(pdfPath);
StringWriter output = new StringWriter();
for (int i = 1; i <= reader.NumberOfPages; i++)
output.WriteLine(PdfTextExtractor.GetTextFromPage(reader, i, new SimpleTextExtractionStrategy()));
return output.ToString();
}
Now change I want in this code whenever there are images in PDF it should include an image tag (<img>) in the content.
I tried with the extracting images alone and I am able to do it but not sure how to merge these two codes together to make extracted content consist with img tag also .
Extraction code of image as follow :
private static List<System.Drawing.Image> ExtractImages(String PDFSourcePath)
{
//string res = GetTextFromAllPages(PDFSourcePath);
//File.WriteAllText(#"d:\blobfile\blobfileresult.txt", res);
List<System.Drawing.Image> ImgList = new List<System.Drawing.Image>();
iTextSharp.text.pdf.RandomAccessFileOrArray RAFObj = null;
iTextSharp.text.pdf.PdfReader PDFReaderObj = null;
iTextSharp.text.pdf.PdfObject PDFObj = null;
iTextSharp.text.pdf.PdfStream PDFStremObj = null;
try
{
RAFObj = new iTextSharp.text.pdf.RandomAccessFileOrArray(PDFSourcePath);
PDFReaderObj = new iTextSharp.text.pdf.PdfReader(RAFObj, null);
if (PDFReaderObj.IsOpenedWithFullPermissions)
{
Console.WriteLine("this is a test");
}
for (int i = 0; i <= PDFReaderObj.XrefSize - 1; i++)
{
PDFObj = PDFReaderObj.GetPdfObject(i);
if ((PDFObj != null) && PDFObj.IsStream())
{
PDFStremObj = (iTextSharp.text.pdf.PdfStream)PDFObj;
iTextSharp.text.pdf.PdfObject subtype = PDFStremObj.Get(iTextSharp.text.pdf.PdfName.SUBTYPE);
if ((subtype != null) && subtype.ToString() == iTextSharp.text.pdf.PdfName.IMAGE.ToString())
// if ((subtype != null) && subtype.ToString() == iTextSharp.text.pdf.PdfName.CCITTFAXDECODE.ToString())
{
byte[] bytes = iTextSharp.text.pdf.PdfReader.GetStreamBytesRaw((iTextSharp.text.pdf.PRStream)PDFStremObj);
if ((bytes != null))
{
try
{
System.IO.MemoryStream MS = new System.IO.MemoryStream(bytes);
MS.Position = 0;
System.Drawing.Image ImgPDF = System.Drawing.Image.FromStream(MS);
ImgList.Add(ImgPDF);
}
catch (Exception e)
{
Console.WriteLine("Exception in extract: " + e);
}
}
}
}
}
PDFReaderObj.Close();
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
return ImgList;
}
I would like create TIF, PNG, JPG and BMP like black and white images via
https://magick.codeplex.com.
What I found if I do like in my code I can generate only TIF black and why images but not images of other types.
Any clue how to fix it?
MagickReadSettings readSettings = new MagickReadSettings()
{
UseMonochrome = true
};
using (MagickImage image = new MagickImage(fileInfo.FullName, readSettings))
{
image.AddProfile(ColorProfile.SRGB);
if (Properties.Settings.Default.ImageFileExtentionToConvert.ToLower().Contains("tif"))
{
image.CompressionMethod = CompressionMethod.Group4;
image.ColorSpace = ColorSpace.Gray;
image.Format = MagickFormat.Tif;
}
else if (Properties.Settings.Default.ImageFileExtentionToConvert.ToLower().Contains("png"))
{
// image.ColorSpace = ColorSpace.Gray;
image.Settings.SetDefine(MagickFormat.Png, "compression-strategy", "0");
image.Settings.SetDefine(MagickFormat.Png, "compression-filter", "0");
image.Format = MagickFormat.Png;
}
else if (Properties.Settings.Default.ImageFileExtentionToConvert.ToLower().Contains("jpg"))
{
image.Settings.SetDefine(MagickFormat.Jpg, "compression-strategy", "0");
image.Settings.SetDefine(MagickFormat.Jpg, "compression-filter", "0");
image.Format = MagickFormat.Jpg;
}
else
{
image.CompressionMethod = CompressionMethod.NoCompression;
image.Format = MagickFormat.Bmp;
}
image.Write(newFileName);
}
I found the answer here https://magick.codeplex.com/discussions/637181
using (MagickImage image = new MagickImage(pathToTiffFile))
{
image.Threshold(60); // 60 is OK
image.Depth = 1;
image.Write(pathToOutputFile);
}
i am trying to show the barcode in asp.net page. already download the zen barcode render with sample code. i tried the sample it is working fine with me. once i try in my code barcode label is showing empty. i checked with sample code and mine i did not find any difference , only data transfer is the different. this is what i tried.
<barcode:BarcodeLabel ID="BarcodeLabel1" runat="server" BarcodeEncoding="Code39NC" LabelVerticalAlign="Bottom" Text="12345"></barcode:BarcodeLabel>
if (!IsPostBack)
{
List<string> symbologyDataSource = new List<string>(
Enum.GetNames(typeof(BarcodeSymbology)));
symbologyDataSource.Remove("Unknown");
barcodeSymbology.DataSource = symbologyDataSource;
barcodeSymbology.DataBind();
}
this is the function
BarcodeSymbology symbology = BarcodeSymbology.Unknown;
if (barcodeSymbology.SelectedIndex != 0)
{
symbology = (BarcodeSymbology)1;
}
symbology = (BarcodeSymbology)1;
string text = hidID.Value.ToString();
string scaleText = "1";
int scale;
if (!int.TryParse(scaleText, out scale))
{
if (symbology == BarcodeSymbology.CodeQr)
{
scale = 3;
}
else
{
scale = 1;
}
}
else if (scale < 1)
{
scale = 1;
}
if (!string.IsNullOrEmpty(text) && symbology != BarcodeSymbology.Unknown)
{
barcodeRender.BarcodeEncoding = symbology;
barcodeRender.Scale = 1;
barcodeRender.Text = text;
}
symbology is set as Code39NC from the dropdown. scale is 1 and text is coming from other form the value is passing as well. still the bacodelable is showing only value not the barcode picture.
Here are two code samples using ZXing to create a (QR) barcode as both an image and as a base64 encoded string. Both of these options can be used with an <img /> tag to embed the barcode in the page.
This is not an ASP.NET control. It is a library that creates barcodes from text.
// First Text to QR Code as an image
public byte[] ToQRAsGif(string content)
{
var barcodeWriter = new BarcodeWriter
{
Format = BarcodeFormat.QR_CODE,
Options = new EncodingOptions
{
Height = this._h,
Width = this._w,
Margin = 2
}
};
using (var bitmap = barcodeWriter.Write(content))
using (var stream = new MemoryStream())
{
bitmap.Save(stream, ImageFormat.Gif);
stream.Position = 0;
return stream.GetBuffer();
}
}
// From Text to QR Code as base64 string
public string ToQRAsBase64String(string content)
{
var barcodeWriter = new BarcodeWriter
{
Format = BarcodeFormat.QR_CODE,
Options = new EncodingOptions
{
Height = _h,
Width = _w,
Margin = 2
}
};
using (var bitmap = barcodeWriter.Write(content))
using (var stream = new MemoryStream())
{
bitmap.Save(stream, ImageFormat.Gif);
return String.Format("data:image/gif;base64,{0}", Convert.ToBase64String(stream.ToArray()));
}
}
Hope this helps! Happy coding.
UPDATE: Here is the link to their product page on codeplex: https://zxingnet.codeplex.com/
I see in my code I'm not passing the re-scaled image into the InputStream, I'm passing in the original file-base. Is it possible to pass in newImage in some way as its of a different type?
I'm using MVC2 .NET 3.5
Here's the controller for uploading:
[HttpPost]
public ActionResult ImageUpload(HttpPostedFileBase fileBase, PhotoViewModel photoViewModel)
{
if (photoViewModel.Button == "Upload")
{
photoViewModel.ImageValid = "Valid";
ImageService imageService = new ImageService();
if (fileBase != null && fileBase.ContentLength > 0 && fileBase.ContentLength <= 2097152 && fileBase.ContentType.Contains("image/"))
{
Path.GetExtension(fileBase.ContentType);
var extension = Path.GetExtension(fileBase.FileName);
if (extension.ToLower() != ".jpg" && extension.ToLower() != ".gif") // only allow these types
{
photoViewModel.ImageValid = "Not Valid";
ModelState.AddModelError("Photo", "Wrong Image Type");
return View(photoViewModel);
}
EncoderParameters encodingParameters = new EncoderParameters(1);
encodingParameters.Param[0] = new EncoderParameter(Encoder.Quality, 100L); // Set the JPG Quality percentage
ImageCodecInfo jpgEncoder = imageService.GetEncoderInfo("image/jpeg");
var uploadedimage = Image.FromStream(fileBase.InputStream, true, true);
Bitmap originalImage = new Bitmap(uploadedimage);
Bitmap newImage = new Bitmap(originalImage, 274, 354);
Graphics g = Graphics.FromImage(newImage);
g.InterpolationMode = InterpolationMode.HighQualityBilinear;
g.DrawImage(originalImage, 0, 0, newImage.Width, newImage.Height);
var streamLarge = new MemoryStream();
newImage.Save(streamLarge, jpgEncoder, encodingParameters);
var fileExtension = Path.GetExtension(extension);
string newname;
if (photoViewModel.photoURL != null)
{
newname = photoViewModel.photoURL;
}
else
{
newname = Guid.NewGuid() + fileExtension;
}
//changed this up now, so it stores the image in db as apposed to physical path
photoViewModel.photo = newname;
photoViewModel.ContentType = fileBase.ContentType;
Int32 length = fileBase.ContentLength;
byte[] tempImage = new byte[length];
fileBase.InputStream.Read(tempImage, 0, length);
photoViewModel.ImageData = tempImage;
TempImageUpload tempImageUpload = new TempImageUpload();
tempImageUpload.TempImageData = tempImage;
tempImageUpload.ContentType = photoViewModel.ContentType;
photoViewModel.TempImageId = _service.InsertImageDataBlob(tempImageUpload);
originalImage.Dispose();
streamLarge.Dispose();
return View(photoViewModel);
}
if (fileBase != null)
{
if (fileBase.ContentLength > 0) ModelState.AddModelError("Photo", "Image size too small");
if (fileBase.ContentLength <= 2097152) ModelState.AddModelError("Photo", "Image size too big");
if (fileBase.ContentType.Contains("image/")) ModelState.AddModelError("Photo", "Wrong Image Type");
}
else ModelState.AddModelError("Photo", "Please upload a image");
if (!ModelState.IsValid)
{
photoViewModel.ImageValid = "Not Valid";
return View(photoViewModel);
}
}
return View(photoViewModel);
}
Here's my repository class:
public int InsertImageDataBlob(TempImageUpload tempImageUpload)
{
int ReturnedPhotoId;
try
{
var phototempdata = new Photo
{
ImageData = tempImageUpload.TempImageData,
contentType = tempImageUpload.ContentType,
dateUploaded = DateTime.Now
};
_db.Photos.InsertOnSubmit(phototempdata);
Save();
ReturnedPhotoId = phototempdata.id;
return ReturnedPhotoId;
}
catch (Exception ex)
{
//ErrorLogging;
}
return 0;
}
And image data field (image type) in the database gets populated with data.
probably it works..or not :-P ....my changes in your code for the bypassing/rescaling issue (check my comments in your code):
[HttpPost]
public ActionResult ImageUpload(HttpPostedFileBase fileBase, PhotoViewModel photoViewModel)
{
if (photoViewModel.Button == "Upload")
{
photoViewModel.ImageValid = "Valid";
ImageService imageService = new ImageService();
if (fileBase != null && fileBase.ContentLength > 0 && fileBase.ContentLength <= 2097152 && fileBase.ContentType.Contains("image/"))
{
Path.GetExtension(fileBase.ContentType);
var extension = Path.GetExtension(fileBase.FileName);
if (extension.ToLower() != ".jpg" && extension.ToLower() != ".gif") // only allow these types
{
photoViewModel.ImageValid = "Not Valid";
ModelState.AddModelError("Photo", "Wrong Image Type");
return View(photoViewModel);
}
EncoderParameters encodingParameters = new EncoderParameters(1);
encodingParameters.Param[0] = new EncoderParameter(Encoder.Quality, 100L); // Set the JPG Quality percentage
ImageCodecInfo jpgEncoder = imageService.GetEncoderInfo("image/jpeg");
var uploadedimage = Image.FromStream(fileBase.InputStream, true, true);
Bitmap originalImage = new Bitmap(uploadedimage);
Bitmap newImage = new Bitmap(originalImage, 274, 354);
Graphics g = Graphics.FromImage(newImage);
g.InterpolationMode = InterpolationMode.HighQualityBilinear;
// change from originalImage to newImage
g.DrawImage(newImage, 0, 0, newImage.Width, newImage.Height);
var streamLarge = new MemoryStream();
newImage.Save(streamLarge, jpgEncoder, encodingParameters);
var fileExtension = Path.GetExtension(extension);
string newname;
if (photoViewModel.photoURL != null)
{
newname = photoViewModel.photoURL;
}
else
{
newname = Guid.NewGuid() + fileExtension;
}
//changed this up now, so it stores the image in db as apposed to physical path
photoViewModel.photo = newname;
photoViewModel.ContentType = fileBase.ContentType;
// using the memoryStream streamLarge
// old code: Int32 length = fileBase.ContentLength;
byte[] tempImage = new byte[streamLarge.Length];
// replace fileBase.InputStream with streamLarge
streamLarge.Read(tempImage, 0, length);
photoViewModel.ImageData = tempImage;
TempImageUpload tempImageUpload = new TempImageUpload();
tempImageUpload.TempImageData = tempImage;
tempImageUpload.ContentType = photoViewModel.ContentType;
photoViewModel.TempImageId = _service.InsertImageDataBlob(tempImageUpload);
originalImage.Dispose();
streamLarge.Dispose();
return View(photoViewModel);
}
if (fileBase != null)
{
if (fileBase.ContentLength > 0) ModelState.AddModelError("Photo", "Image size too small");
if (fileBase.ContentLength <= 2097152) ModelState.AddModelError("Photo", "Image size too big");
if (fileBase.ContentType.Contains("image/")) ModelState.AddModelError("Photo", "Wrong Image Type");
}
else ModelState.AddModelError("Photo", "Please upload a image");
if (!ModelState.IsValid)
{
photoViewModel.ImageValid = "Not Valid";
return View(photoViewModel);
}
}
return View(photoViewModel);
}
I actually got it to work with this code:
photoViewModel.photo = newname;
photoViewModel.ContentType = fileBase.ContentType;
streamLarge.Position = 0;
byte[] tempImage = new byte[streamLarge.Length + 1];
streamLarge.Read(tempImage, 0, tempImage.Length);
photoViewModel.ImageData = tempImage;