Add SVG image to PdfSignatureAppearance with iText7 - svg

I want to add a SVG image to PdfSignatureAppearance. The method setSignatureGraphic has an ImageData parameter now in iText7. I couldn't find a way to create an imageData from SVG because ImageDataFactory is not supporting this format.
Can you please guide me on how to do that?
Note that with iText5 I was able to add svg after converting it to PDF and import it to a PDFTemplate then create an image after instantiate the PDFTemplate. setSignatureGraphic was accepting com.itextpdf.text.Image as parameter

Your question could be split into 2 more precise and simple ones:
How to process an SVG with iText?
How to create an ImageData instance out of the result of point 1?
As for question 1: one can use SvgConverter class (part of iTextCore's svg module). Unfortunately there are only PDF-related methods there: an SVG could be converted either to Image (class of layout module), or to PdfFormXObject (again PDF-related) or to a PDF file.
// to PDF
SvgConverter.convertToImage(new FileInputStream(sourceFolder + "your_svg.svg"), signer.getDocument()); // the mentioned `signer` is the instance of PdfSigner which you use to sign the document
// to Image
SvgConverter.convertToImage(new FileInputStream(sourceFolder + "your_svg.svg"), new File(destinationFolder + "svgAsPdf.pdf"));
As for question 2, there are several answers:
a) Suppose that you want to use this Image as the PdfSignatureAppearance's graphics data. For now the class doesn't provide a convenient setter, however, you could use some low level methods - either getLayer0 or getLayer2 to get the signature's background or foreground. They are represented by PDfFormXObject, hence you can use Canvas to add your image to them:
Image svg = SvgConverter.convertToImage(new FileInputStream(sourceFolder + "your_svg.svg"), signer.getDocument());
Canvas canvas = new Canvas(appearance.getLayer0(), signer.getDocument());
canvas.add(svg);
canvas.close();
b) Suppose that your goal is to use the rendered bitmap as the PdfSignatureAppearance's graphics data. Then there is a specific iText product - pdfRender - which converts PDF files to images. The following code could be applied:
PdfToImageRenderer.renderPdf(new File(destinationFolder + "svgAsPdf.pdf"), new File(folderForTheResultantImage));
Now you can create an ImageData instance out of the resultant image file (by default a PDF is converted to a series of images with the format "pdfnamePAGE_NUMBER.jpg", but one could customize either the name or the output image format). In your case the PDF consist of just one page (which represents the converted SVG) and its name is "image1.jpg". The rest is obvious:
appearance.setSignatureGraphic(ImageDataFactory.create(destinationFolder + "image1.jpg"));

Related

Converting PDF/SVG to PNG with antialias off using Magick++

I've tried to convert a SVG file to PNG with antialiasing off in Magick++ but I wasn't successful. But I was able to convert the SVG file to PDF with another program and the use the ImageMagick convert command to convert the PDF file to PNG.
How can I use ImageMagick to do it? The command I use for converting PDF to PNG is this:
convert +antialias -interpolate Nearest -filter point -resize 1000x1000 "img.pdf" PNG24:"filter.png"
Is there any way to use Magick++ to do that or better, convert SVG to PNG directly with antialiasing off?
Thanks in advance.
Edit:
The answer given in this post doesn't work for me. Possible because I'm using a colored SVG instead of 1-bit alpha channel. Also I mentioned in my question that I'm also looking for a way to do this in Magick++.
Magick++ has the Magick::Image::textAntiAlias & Magick::Image::strokeAntiAlias methods available, but they would only be useful if your parsing the SVG and rebuilding the image (i.e. roll-your-own SVG engine) one SVG element at a time.
As #ccprog pointed out in the comments; once the decoder utility rasters the vectors, the damage is done & setting the flags would not have an effect on the resulting resize.
Without seeing the SVG, I can only speculate what the problem is. I would suggest setting the document size before reading the SVG content.
For example, read the image at a smaller size than resample up.
Magick::Image img;
img.size(Magick::Geometry(100, 100)); // Decode to a small context
img.read("input.svg");
img.interpolate(Magick::NearestInterpolatePixel);
img.filterType(Magick::PointFilter);
img.resize(Magick::Geometry(600, 600));
img.write("PNG24:output#100x100.png");
Or render at larger size then the finial image.
Magick::Image img;
img.size(Magick::Geometry(1000, 1000)); // Decode to a larger context
img.read("input.svg");
img.interpolate(Magick::NearestInterpolatePixel);
img.filterType(Magick::PointFilter);
img.resize(Magick::Geometry(600, 600));
img.write("PNG24:output#1000x1000.png");
Update from comments
For Postscript (PDF) & True-Type antialiasing, you would set Magick::Image::textAntiAlias (or Magick::Image::antiAlias if using IM6) to false. Just ensure that the density is set to allow any overhead.
Magick::Image img;
img.density(Magick::Point(300));
if (MagickLibVersion < 0x700) {
img.antiAlias(false);
} else {
img.textAntiAlias(false);
}
img.interpolate(Magick::NearestInterpolatePixel);
img.filterType(Magick::PointFilter);
img.read("input.pdf");
img.resize(Magick::Geometry(1000, 1000));
img.write("PNG24:output.png");

How to render / display multiframe dicom images in vtk?

I am using gdcm ImageReader to read multiframe dicom file. It reads multiframe correctly but I am unable to display the multiframe dicom file.
I am using vtkImageViewer to display single frame image,
vtkImageViewer viewer = new vtkImageViewer();
vtkDICOMImageReader reader = new vtkDICOMImageReader();
reader.SetInputfile(..\\inputFile);
viewer.SetInput(reader.GetOutput());
It displays single frame images correctly but does not display multiframe images.
Anybody knows how to display multiframe dicom files???
I would advise you to use vtkImageViewer2 instead of vtkImageViewer in this context. The former has a method, SetSlice, where, according to the documentation:
'Each call to SetSlice() changes the image data (slice) displayed AND changes the depth of the displayed slice in the 3D scene'
Example**:
vtkSmartPointer<vtkImageViewer2> imageViewer = vtkSmartPointer<vtkImageViewer2>::New();
imageViewer->SetSlice(5); //Specify the index/slice in image data
** Assumes you have set the input connection/data, example in c++ language.

how to draw shapes in a PDF using NodeJS

I have some existing PDF files and what I want is to highlight some content by overlaying circles or straight lines. I've looked at some NodeJS PDF libraries but couldn't find a solution (some libraries allow creating a PDF from scratch and draw into it; other libraries can modify existing PDFs, but do not support drawing).
A (Linux / OSX) command line solution (e.g. using ImageMagick or some other library) would be perfectly fine, too.
Edit I've since found out that with Image/GraphicsMagick I can in fact do sth. like gm convert -draw "rectangle 20,20 150,100" xxx.pdf[7] xxx2.pdf, but this (1) either draws on all pages or else only on a single one, but then the resulting PDF will only contain that page; (2) the output PDF will contain a bitmap image where I would prefer a PDF with text content.
Edit I've just found HummusJS which is a NodeJS library to manipulate PDF files via declarative JSON objects. Unfortunately, apart from the scrace documentation, the unwieldy API (see below), the tests fail consistently and across the board with Unable to create PDF file, make sure that output file target is available.
completely OT not sure what it is that makes people think such utterly obfuscated APIs are better than simple ones:
var settings = {modifiedFilePath:'./output/BasicJPGImagesTestPageModified.pdf'}
var pdfWriter = hummus.createWriterToModify('./TestMaterials/BasicJPGImagesTest.PDF',settings);
var pageModifier = new hummus.PDFPageModifier(pdfWriter,0);
pageModifier.startContext().getContext().writeText('Test Text', ...
...
var copyingContext = inPDFWriter.createPDFCopyingContextForModifiedFile();
var thirdPageID = copyingContext.getSourceDocumentParser().getPageObjectID(2);
var thirdPageObject = copyingContext.getSourceDocumentParser().parsePage(2).getDictionary().toJSObject();
var objectsContext = inPDFWriter.getObjectsContext();
objectsContext.startModifiedIndirectObject(thirdPageID);
var modifiedPageObject = inPDFWriter.getObjectsContext().startDictionary();
A couple of helpers with HummusJS, to assist with what you are trying to do:
Adding content to existing pages - https://github.com/galkahana/HummusJS/wiki/Modification#adding-content-to-existing-pages
Draw shapes - https://github.com/galkahana/HummusJS/wiki/Show-primitives
using both, this is how to add a circle at 'centerx,centery' with 'radius' and border width of 1, to the first page of 'myFile.pdf'. The end result, in this case will be placed in 'modifiedCopy.pdf':
var pdfWriter = hummus.createWriterToModify(
'myfile.pdf',
{modifiedFilePath:'modifiedCopy.pdf'});
var pageModifier = new hummus.PDFPageModifier(pdfWriter,0);
var cxt = pageModifier.startContext().getContext();
cxt.drawCircle(
centerX,
centerY,
radius,
{
type:stroke,
width:1,
color:'black'
});
pageModifier.endContext().writePage();
pdfWriter.end();
General documentation - https://github.com/galkahana/HummusJS/wiki
If the tests fail, check that an "output" folder exists next to the script being executed, and that there are permissions to write there.

How to convert selected pdf page with gm

I am converting different images and pdf files with "gm" module for nodejs. Image types go successfully but when I want to convert PDF to image have problems. I need to covert only one selected page from pdf file to jpg/png. If I pass whole pdf file to "gm" it saves to image only first page, but I cannot find the way to save another page.
gm(file).toBuffer(format.toUpperCase(),
function (err, buffer) {
// so in buffer now we have converted image
}
Thank you.
You can use gm.selectFrame like this
gm(file).selectFrame(0).toBuffer() // To get first page
gm(file).selectFrame(1).toBuffer() // To get second page
// for only first pdf page use:
gm(file, 'pdf.pdf[0]').toBuffer(...)
// for only second pdf page use:
gm(file, 'pdf.pdf[1]').toBuffer(...)
There is spindrift for manipulating pdf (includes image conversion).
You can define your pdf using (You don't have you use all of the commands):
var pdf = spindrift('in.pdf')
.pages(7, 24)
.page(1)
.even()
.odd()
.rotate(90)
.compress()
.uncompress()
.crop(100, 100, 300, 200) // left, bottom, right, top
Later on convert to image:
// Use the 'index' property of an image element to extract an image:
pdf.extractImageStream(0)
If you have to use gm, you can do what #Ben Fortune suggested in his comment and split the pdf first.

How can BonsaiJS load external SVG files?

I am learning to work with BonsaiJS and would like to import an external SVG image on the stage.
At http://docs.bonsaijs.org/overview/Path.html I learnt that there are three ways to create a new Path() sending SVG paths, path commands or path points as arguments, but for more complex SVG files this is too much of a hassle to make this work.
At How Can I Animate my SVG files with a JS Library - Is Bonsai Ideal for this? I read one can use the new Bitmap() method, but SVG's are turned into... bitmaps.
Am I missing something? Thanks in advance!
At the time it seems impossible for BonsaiJS to load external SVG's like it is possible to load external bitmap images. The BonsaiJS docs (http://docs.bonsaijs.org/overview/Path.html) do provide three methods to manually handle paths from an SVG file separately.
Path nodes
If your SVG contains <path> nodes (tags), get the value of the d attribute and apply the fill manually:
SVG
<path id="pathId" fill="#ff6600" d="M54.651,316.878c9.098,19.302,3.208,46.085,11.193,67.117 c0.687,2.48-4.441-0.06-2.581,5.486c9.171,20.188,10.61,52.755,17.331,79.04l-1.88-0.961c1.652,5.139,7.946,8.864,10.469,13.37">
BonsaiJS
var myShape1 = new Path("M54.651,316.878c9.098,19.302,3.208,46.085,11.193,67.117 c0.687,2.48-4.441-0.06-2.581,5.486c9.171,20.188,10.61,52.755,17.331,79.04l-1.88-0.961c1.652,5.139,7.946,8.864,10.469,13.37");
myShape1.fill('#ff6600');
Polygon nodes
If your SVG ie. contains <polygon> nodes, get the string value of the points attribute, split this string into an array and turn all string elements into floats. Again also apply the fill manually:
SVG
<polygon id="polygonId" fill="#FFFFFF" points="76.5,253.5 94.5,165.5 108.5,125.5 128.5,93.5 164.5,66.5 195.891,44.719 254.5,36.5 299.656,36.5 348.5,41.5 414,66 459,102 488,150.5 505.5,218.5 508,331.5 508,390 504.5,424.5 480,463.5 450,509.5 378,554.5 300,566 226,556.5 168,535.5 109.5,476 87,419.5 76.5,339.5 "/>
BonsaiJS
var points = "76.5,253.5 94.5,165.5 108.5,125.5 128.5,93.5 164.5,66.5 195.891,44.719 254.5,36.5 299.656,36.5 348.5,41.5 414,66 459,102 488,150.5 505.5,218.5 508,331.5 508,390 504.5,424.5 480,463.5 450,509.5 378,554.5 300,566 226,556.5 168,535.5 109.5,476 87,419.5 76.5,339.5";
points = points.split(/[\s,]+/).map(function(point) {
return parseFloat(point);
});
var myShape2 = new Path(points).fill('#ffffff');
Then...
After defining all parts, one can create a group and add all parts to 'reconstruct' the original SVG image, ie.:
var myGroup = new Group().addTo(stage);
myShape1.addTo(myGroup);
myShape2.addTo(myGroup);
At http://docs.bonsaijs.org/overview/Path.html I learnt that there are three ways to create a new Path() sending SVG paths, path commands or path points as arguments, but for more complex SVG files this is too much of a hassle to make this work.
Yes, Bonsai let you import SVG (like) Paths.
At How Can I Animate my SVG files with a JS Library - Is Bonsai Ideal for this? I read one can use the new Bitmap() method, but SVG's are turned into... bitmaps.
Bonsai doesn't let you import SVGs in general. Only paths. Which means that Bonsai doesn't give you API for accessing the inner nodes of your SVG file.
Using the Bitmap API is not a way of importing your SVG. The SVG file is treated as any regular image format. It depends on the platform and renderer whether it is going to be rastered or not. It can be compared with using DOM's HTMLImageElement.

Resources