How do I efficiently add text and drawn boxes on a PDF using ImageMagick? - pdf

I'm trying to use ImageMagic to open a PDF, draw a couple of boxes with text labels on the PDF, and then resave it as a PDF. This has been deceptively difficult for me to figure out how to do, but I got something working per this previous question: imageMagick: How do I draw on one page of a pdf but keep the whole pdf?
My test files, which were 3 pages, were processed fine. However, when it went to QA, and it was tried with large files (some 30-50 pages, which will be normal use for this script) it kept timing out with messages like this:
timeout [300000 ms] expired while executing [c:\IM\magick.exe -density 300 -compress ZIP c:\tempWorking\138.pdf[0-1] ( c:\tempWorking\138.pdf[2] -fill rgba(255, 214, 214, 0.7) -stroke #000f55 -draw rectangle 2145,742,3245,907 -fill #000 -stroke #000 -font Arial -pointsize 10 -draw text 2167,885 'Box 1: Test' -fill rgba(255, 214, 214, 0.7) -stroke #000f55 -draw rectangle 2145,896,3245,1061 -fill #000 -stroke #000 -font Arial -pointsize 10 -draw text 2167,1039 'Box 2: Test 2' -fill rgba(255, 214, 214, 0.7) -stroke #000f55 -draw rectangle 2145,1023,3245,1188 -fill #000 -stroke #000 -font Arial -pointsize 10 -draw text 2167,1166 'Box 2: Test 2' ) c:\tempWorking\138.pdf[3-18] c:\esigImgs\62\preview.pdf]
To break down that impenetrable wall of text, my script wrote out a command similar to this:
c:\IM\magick.exe
-density 300
-compress ZIP
c:\tempWorking\138.pdf[0-1]
(
c:\tempWorking\138.pdf[2]
-fill rgba(255, 214, 214, 0.7)
-stroke #000f55
-draw rectangle 2145,742,3245,907
-fill #000
-stroke #000
-font Arial
-pointsize 10
-draw text 2167,885 'Box 1: Test'
-fill rgba(255, 214, 214, 0.7)
-stroke #000f55
-draw rectangle 2145,896,3245,1061
-fill #000
-stroke #000
-font Arial
-pointsize 10
-draw text 2167,1039 'Box 2: Test 2'
-fill rgba(255, 214, 214, 0.7)
-stroke #000f55
-draw rectangle 2145,1023,3245,1188
-fill #000
-stroke #000
-font Arial
-pointsize 10
-draw text 2167,1166 'Box 2: Test 2'
)
c:\tempWorking\138.pdf[3-18]
c:\esigImgs\62\preview.pdf
So we're taking some pages that are not altered, adding a page that is altered, then adding more pages that are not altered. Production use of this will usually involve far more boxes and text being written to several pages.
I extended the timeout to 300s just to see what would happen. Originally the timeout was set at 60 seconds, and I would really like it to take far less. This was running on an AWS instance. When I tested it locally it completed in around 60 seconds with the same file, but had mostly locked my cpu for that entire time.
What am I doing wrong and how can I approach making this process more efficient?

In comments you asked how to add vector info quickly to a source PDF via Image Magic appending data, I replied, it is best to use annotation by over stamping one PDF onto another, and there are many different cross platform methods even using shell script as a rect and text pdf as the stamp.
However, it seems from the question your need is even simpler than that.
As an example to add text and boxes you could use cpdf, the advantage is the values can be easily set as variables for different situations. here I am using just page 1 (-range 1) but that same entry can be applied to a range of pages.
cpdf -add-rectangle "200 100" -pos-center "180 200" -color "red" -range 1 -outline earth.pdf AND -pos-center "180 210" -midline -font Helvetica -font-size 20 -add-text "Hello World!" -color "white" -opacity 1.0 -range 1 AND -pos-center "180 190" -midline -font Helvetica -font-size 20 -add-text "Hello USA!" -color "1.0 1.0 0.0" -opacity 1.0 -range 1 -o out.pdf
For more complex possibilities like multi line stamps there is a powerfully small cross platform tool at https://pdfcpu.io/core/stamp#examples

Related

Gray matpotlib figure face color turns black when saving the figure as .eps

I am using the following code to get this:
1
However, when saved as .eps, the face color of the figure turns from gray ( what I want) to black. See this:
2
Any reason why?
dim = np.arange(1, 32, 1)
fig, ax = plt.subplots(figsize=(7,9))
heatmap = ax.imshow(h.T, cmap=plt.cm.get_cmap('Blues', 4), clim=[1,144])
cbaxes = fig.add_axes([.8, .35, .04, .3])
cbar = fig.colorbar(heatmap, ticks = [1, 36, 72, 108, 144], label = 'Number of valid records per day', cax = cbaxes)
ax.set_ylabel("Days", fontsize=15)
ax.set_xlabel("Months", fontsize=15)
ax.set_title("Number of valid records per day", fontsize=20)
ax.set_yticks(range(0,31))
ax.set_yticklabels(dim, ha='center', minor=False, fontsize=12)
ax.set_xticks(range(0,13,1))
ax.set_xticklabels(ylabel[7:20], rotation = 45, ha = 'right')
ax.set_facecolor('gray')
cbar.set_label('Number of valid records')
ax.xaxis.set_minor_locator(MultipleLocator(0.5))
ax.yaxis.set_minor_locator(MultipleLocator(0.5))
ax.tick_params(axis='y', which='major', pad=10)
ax.grid(which = 'minor', color = 'w')
fig.show()
plt.savefig("drive/My Drive/fig.eps")
Your problem is probably caused by your 'gray' colour actually being black with transparency (which is the a channel in rgba), i.e. the rgba color (0,0,0,.5), which is black with a 50% transparency. If you ran your code interactively, you should have gotten a message:
"The PostScript backend does not support transparency; partially
transparent artists will be rendered opaque."
.eps (Postscript in the message refers to encapsulated postscript) doesn't support transparency, I imagine under the hood when your figure is being saved as .eps it simply takes the color channels i.e. the rgb values, which is equivalent to setting alpha to 1.
You can either:
Rasterize your figure/axes before saving as .eps using fig.set_rasterized(True)/ax.set_rasterized(True),
Save in a different format which supports transparency (.pdf, .png etc.)
Choose a color/cmap(colormap) which does not include transparency.
To expand #3 for your specific option, if it's the case that missing values aren't plotted and we're seeing the axes facecolor, you can try explicitly specifying an rgb color ax.set_facecolor(.5,.5,.5) instead of ax.set_facecolor('grey').

Can't draw 1px line

createjs.Shape() with graphics setStrokeStyle(1) draws a 2px line instead of 1px. If you screenshot the JSfiddle output below, you will seee that the line is 2px tall.
http://jsfiddle.net/7fbr9yan/
How do I draw a 1px line?
The line that you draw in going in between two lines of pixels, so it's coloring both sides of it in grey instead of black.
change your code to
line.graphics.moveTo(20,74.5).setStrokeStyle(2).beginStroke("#000").lineTo(280,74.5);
in order to draw over only one line of pixels.

how to reduce the size of 3D pie Graph

i need to decrease the size of 3D pie Graph .i have changed $Radius=100 into $Radius=50 in pChart.class but not happening the size of graph .i am following the link
http://pchart.sourceforge.net/documentation.php?topic=exemple11
This should do:
// Pie chart with radius of 100
$picture->drawPieGraph($DataSet->GetData(), $DataSet->GetDataDescription(), 150, 150, 100, PIE_PERCENTAGE);
// Pie chart with radius of 50
$picture->drawPieGraph($DataSet->GetData(), $DataSet->GetDataDescription(), 150, 150, 50, PIE_PERCENTAGE);

OpenGL glBlendFuncSeparate

I need some help with OpenGL textures masking. I have it working but need to find some other blending function parameters to work in other way.
Now I have:
//Background
...code...
glBlendFunc(GL_ONE, GL_ZERO);
...code
//Mask
...code...
glBlendFuncSeparate(GL_ZERO, GL_ONE, GL_DST_COLOR, GL_ZERO);
...code...
//Foreground
...code
glBlendFunc(GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA);
...code
Now it sets foreground's opacity to 0 (fills with background texture) where mask is transparent. I need it to react to mask's colors. I mean something like setting foregrounds opacity depending on mask's color. For example if mask is black (0.0,0.0,0.0) then the opacity of that place in foreground is 0 (is filled with background), and if mask is white (1.0,1.0,1.0) then the opacity of foreground is 1 (not filled with background). It can be in reverse consequence (white = opacity 0, black = opacity 1). I just need it to work depending on color.
My current result's visualization bellow.
Background:
Mask (circle is transparent):
Foreground:
Result:
And I want it to work like this:
Background:
Mask (circle is white, background is black):
Foreground:
Result:
So that later it could be used like this:
Background:
Mask (circle is white, background is black):
Foreground:
Result:
Attempt with #Gigi solution:
Perhaps this is what you want:
1) Clear the destination image:
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
2) Draw the background, masking out the alpha channel:
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
3) Draw the "masking overlay", masking out the color channels:
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
4) Draw the foreground, enabling blending:
glEnable(GL_BLEND);
glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
glBlendFuncSeparate(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA, GL_ONE, GL_ZERO);
Note: The overlay image must have the alpha channel specified.

matplotlib: how to hide grey border around the plot

I'd like to save figurecanvas as bitmap and don't need grey border around the plot in it. How can I hide this?
I believe that savefig will not include the gray border by default. However, .bmp is not support by savefig; use .png instead.
import pylab
f = pylab.figure()
ax = f.add_axes([0.1, 0.1, 0.8, 0.8])
ax.plot([1,2,3],[4,5,6])
f.savefig('image.png')
Output:
(source: stevetjoa.com)
I found it: subplots_adjust.