GIMP: Add padding to multiple images - gimp

I scanned a couple pages and edited them a little so the look neat.
But as I wanted to reprint them I noticed that I cropped the border from these images so that the printer won't print the whole content.
I have a Brother printer which has Linux drivers but somehow the scaling option does not work.
So I thought to scale the PDF (in which I have converted these scans) but the printer driver scales them back to fit the page. (If I disable the scale-to-fit option it becomes garbage)
So I thought that I could do some script-fu to resize these images with a couple of lines and add some padding for the printer. But I have no clue how to do this.
Here's my first attempt:
(define (resize-image filename-in filename-out )
(let* ((image (car (gimp-file-load RUN-NONINTERACTIVE filename-in "")))
(drawable (car (gimp-image-active-drawable image)))
)
(gimp-image-resize image 2728 3819 124 173)
(gimp-file-save RUN-NONINTERACTIVE image drawable filename-out "")
)
)
This does not work. The image simply remains unchanged.
My page is A4 with 2480x3472, so I thought to add 10% to the width so it becomes 2728x3819 and set the offset to 5% so the content is centered (with offset values 124 and 173).

Wnen you resize the image you are just extending the canvas but not the layer. And gimp-file-save only saves the active "drawable" (layer in your case), so you just save the same image. What you have to do is either:
add a white layer at the bottom of the layer stack
flatten the image
save the result
or
remove the layer's alpha channel (assuming the background paint color is white)
extend the layer to cover the canvas (the extension will be filled with white): gimp-layer-resize-to-image-size
save the result

Related

how to select and manipulate a portion of text inside a text layer using python-fu

I wrote a gimp python plugin to create an image, add a text layer, and write some text into it. Similar to this one.
I want to apply a different formatting to a portion of this text but I can't find the function to do it when I browse Filters > Script-Fu > Console > Browser.
This gif illustrates what I want. It was done manually:
Very complicated. You can get the info in the "parasite" attached to the text layer:
data=layer.parasite_find('gimp-text-layer').data
So for instance, for an image like this:
Data looks like this:
(markup "<markup>SO<span font=\"URW Bookman L Bold\">ME</span> <span size=\"15728\">TE</span>XT</markup>")
(font "Bungee")
(font-size 80)
(font-size-unit pixels)
(antialias yes)
(language "en")
(base-direction ltr)
(color (color-rgb 0 0 0))
(justify fill)
(box-mode dynamic)
(box-unit pixels)
(hinting yes)
Markup is possibly related to Cairo (which is the library used by Gimp to draw text and curves). However,
The parasite is only available once the image has been saved to disk
I have never checked what happens if you update the parasite.
Edited:
It seems creating or updating the parasite doesn't work and Gimp seems to ignored the parasite. It only considers it when loading the file, and when the file is saved, it generates a new parasite from the actual layer contents.
It may be easier for you to format several individual text layers side-by-side. To align them to the same baseline: if you use pdb.gimp_text_get_extents_fontname() with a character that has a flat bottom (I typically use "X") the "ascent" is the distance of the baseline from the top of the layer (round character such as "O" can extent slightly under the baseline).

How can I make a text box background color NOT transparent in Gimp?

I often need to add text to an image. To do this, I use the Text Tool. When I click on the image, I can start filling in the text. However, the box that the text is in always shows up as transparent. There are times where this is good, but many times I want black text on a white box. How can I set the color of the box the text is inside?
You can just bucket fill the layer (no selection) after putting the bucket tool in Behind mode. But this makes the text layer no longer a text layer (text and font information is lost).
So a better solution is to add a layer under the text later and bucket-fill, with two options:
Make a layer the right size (when you create the layer it takes by default the side of the active layer) and bucket-fill the whole layer
Make an image-size layer, make a rectangle selection and bucket-fill the selection
Note that bucket-filling the text layer (or a layer which is the exact same size) usually won't look good because the boundaries of the layer come from the font geometry (so you can stack/abut layers) and there is a lot more space on top and bottom than on the sides.

Remove color cast using libvips

I have sRGB images with color casts. To remove it manually I usually use Photoshop Level Adjustments. Photoshop also have tools for that: Auto Contrast or even better Auto Tone which also takes shadows, midtones & highlights into account.
If I remove the cast manually I adjust each of the RGB channels individually so that the darkest pixels are set to pure black and the lightest to pure white and then redistribute all other values (spreading the histogram). This is a simple approach but shows good results for my images.
In my node.js app I'm using sharp for image processing which uses libvips as its processing engine. I tried to remove the cast with .normalize() but this command works on all channels together and not individual for each of the RGB channels. So it doesn't work for me.
I also asked this question on the sharp project page. I tested the suggestion from lovell to try it with hist_local but the results are not useable for me.
Now I would like to find out how this could be done using the native libvips. I've played around with nip2 GUI and different commands but could not figure out how it could be achieved:
Histogram > Equalise Histogram > Global => Picture looks over saturated
Image > Levels > Scale to 0 - 255 => Channels ar not all spreading from 0 - 255 (I don't understand exactly what this command does?)
Thanks for every hint!
Addition
Here is a example with pictures from Photoshop to show what I want.
The source image is a picture of a frame from a film negative.
Image before processing
Step1 Invert image
Image after inversion
Step2 using Auto tone in Photoshop (works the same way as my description above about manually remove the color cast)
Image after Auto Tone
This last picture is ok for me.
nip2 has a menu item for this.
Load your image and mark a region on it containing the area you'd like to be neutral. It can be any lightness, it doesn't need to be white.
Use File / Open to get the file dialog and you should see the image loaded in your workspace as a thumbnail.
Doubleclick on the thumbnail to open an image view window.
In the view window, zoom and pan to the right spot. The user guide (press F1) has a section on image navigation.
Hold down CTRL and click and drag down and right to mark a rectangular region.
Back in the main window, click Toolkits / Tasks / Capture / White balance. You should see something like:
You can drag an resize your region to change the neutral point. Use the colour picker to set what white means. You can make other whites with (for example) Colour / New / Colour from CCT and link them together.
Click Colour / New / Colour from CCT to make a colour picker from CCT (correlated colour temperature) -- the temperature in Kelvin of that white.
Set it to something interesting, like 4800 for warm white.
Click on the formula for A5.white to edit it, and enter the cell of your CCT widget (A7 in this case).
Now you can drag the region to adjust the pixels to set the neutral from, and drag the CCT slider to set the temperature.
It can be annoying to find things in the toolkit menu. There's a thing for searching toolkits: in the main window, click View / Toolkit browser. You can enter something like "white" and it'll show related toolkit entries.
Here's another answer, but using pyvips and responding to the previous comments. I didn't want to delete the first answer as it still seemed useful.
This version finds the image histogram, searches for thresholds which will select 0.5% and 99.5% of pixels in each image band, then rescales the image so that those pixel values become 0 and 255.
import sys
import pyvips
# trim off this percentage of pixels from the top and bottom
trim_percent = 0.5
def percent(hist, percentage):
"""From a histogram, find the threshold above which lie
#percentage of pixels."""
# normalised cumulative histogram
norm = hist.hist_cum().hist_norm()
# column and row profile over percentage
c, r = (norm > norm.width * percentage / 100).profile()
return r.avg()
image = pyvips.Image.new_from_file(sys.argv[1])
# photographic negative
image = image.invert()
# find image histogram, split to set of separate bands
bands = image.hist_find().bandsplit()
# for each band, the low and high thresholds
low = [percent(band, trim_percent) for band in bands]
high = [percent(band, 100 - trim_percent) for band in bands]
# rescale image
scale = [255.0 / (h - l) for h, l in zip(high, low)]
image = (image - low) * scale
image.write_to_file(sys.argv[2])
It seems to give roughly similar results to the PS button. If I run:
$ ./autolevel.py ~/pics/before.jpg x.jpg
I see:
In the meantime I've found the Simplest Color Balance Algorithm which exactly describes the problem with color casts and there you can also find a C source code.
It is exactly the same solution as John describes in his second answer but as a small piece of c-code.
I'm now trying to use it as C/C++ addon with N-API under node.js.

How to add transparent border OpenCV copymakeborder

I have 26 PNG files, each with an image of a letter of the alphabet. They've all been fully cropped to the letter shape with the result that when I insert them into an image, letters with tails all 'sit on the line'
Each letter is in black, with a transparent background. Each PNG has different dimensions, because of the differing letter shapes
I thought I'd remediate this by adding a transparent border of a different size depending on the source file, to make common datum for all the letters, so that 'a' for example would have some transparent space at the bottom.
I've coded up the calculcation for each letter, but I have two issues:
1) Even before applying the operation, I can't seem to read the file in and write it to a new unchanged file in OpenCV. The transparency in the image is replaced with black.
2) While I can add a colour border, I can't seem to add a transparent border.
Original Image:
Read in, and written out:
Apparenly with a blue border, but maximum transparancy:
I have a feeling that if I can sort out the first problem, the second might fall in line. Here is my code:
img = cv2.imread(file)
img_with_border = cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, value=[-255,0,0,255])
#img_with_border = img
cv2.imwrite(newfile, img_with_border, [cv2.IMWRITE_JPEG_QUALITY, 100])
I'd appreciate some help on what is going on here with transparancy. Is OpenCV the right tool to use?
Thanks,
Jeff.
To load a PNG image with 4 channels in OpenCV, use im = cv2.imread(file, cv2.IMREAD_UNCHANGED). You will obtain a BGRA image.
To change the alpha value, you have to change the fourth channel of the image. This means that to create your transparent border you have to pass a value (B, G, R, 0) and not [-255, 0, 0, 255]. (What is that -255 by the way ?). B, G and R can be 0, it doesn't matter.
Also, make sure you write to a PNG image to keep the transparency. You seem to be writing your result as JPEG.

Is there an easy way to cut a slice from an image using Gimp?

Wondering if there is an easy way to remove a rectangular slice across the entire width of an image using Gimp, and have the resulting hole closed up automatically. I hope that makes sense. If I select a slice across an image and do "cut", it leaves a blank "hole" there. I want the new top and bottom of the image to join and fill that hole, reducing the image height by the amount sliced out.
Any easy way to do this?
Here is a method that is quick and often does what you want:
Cut out the middle, leaving a transparent "hole".
Click anywhere to remove the selection (so the hole is not selected).
Click Image > Zealous crop .
This is going to remove the middle part. However, if you also have transparency in other parts of the image (like around the edges) it's going to remove that transparency too.
I believe you're asking to do something like cut out the middle of a page, leaving the header and footer and have the blank space removed with the cut action, effectively joining the header and footer together.
To my knowledge, I don't believe so. Even if you cut, or delete, that space is still part of the image even without content.
But, you would be able to highlight the top or bottom (or left or right) of the remaining space and drag it to align with the other side. It's not ideal for repetitive tasks, but should get you through if you only have to do it a few times.
Install Python and the Python Imaging Library. Back in GIMP, select and cut the full-width areas you don't want to transparent, and export the image to test.png. Then use this Python code (works only if complete lines are transparent; will not work properly if there are 100%-transparent pixels anywhere other than on a full-width row)—
from PIL import Image
i = Image.open("test.png")
b = i.tobytes()
b2 = ''.join(b[n:n+4] for n in xrange(0,len(b),4) if ord(b[n+3]))
newHeight = len(b2)/i.width/4
i2 = Image.frombytes('RGBA',(i.width,newHeight),b2)
i2.save("test.png")
Then re-load test.png and verify that the areas you cut have gone.
In gimp 2.8.1 you can easily create a new image from a selection. So if you select a rectangular than do a copy (Ctrl-C) and a past in a new image
Edit -> Paste as -> new image (or Ctrl-Shift-V).

Resources