2

I'm writing a shell script to concatenate some images, and I'm using the vips command-line because it has low memory requirements (and I intend to work with extremely large images).

However, if one image is RGB and the other is RGBA, it fails:

$ vips insert foo3.png foo4.png foo.png 64 0 --expand --background '0 0 0 0'
insert: images must have the same number of bands, or one must be single-band

$ file foo?.png
foo3.png: PNG image data, 1 x 1, 8-bit/color RGB, non-interlaced
foo4.png: PNG image data, 1 x 1, 8-bit/color RGBA, non-interlaced

How can I convert the input image to RGBA when using vips? I've been searching through the documentation, but I can't find it.

I'm also willing to use nip2 tool, which also uses libvips. I'm not willing to use ImageMagick (or similar tools) because the script will end up working with images as large as 20k×20k pixels, which take several gigabytes of RAM, more than I have now.

Denilson Sá Maia
  • 47,466
  • 33
  • 109
  • 111
  • 1
    I presume you are aware of ImageMagick's `stream` function that may be useful here... http://www.imagemagick.org/script/stream.php – Mark Setchell Sep 02 '15 at 08:42

3 Answers3

3

On recent vips versions:

vips bandjoin_const source.png dest.png 255

255 for opaque, 0 for transparent.

Denilson Sá Maia
  • 47,466
  • 33
  • 109
  • 111
2

I'd write the whole thing in Python with pyvips. For example:

#!/usr/bin/python3

import sys 
import pyvips

if len(sys.argv) < 3:
    print("usage: join outfile in1 in2 in3 ...")
    sys.exit(1)

def imopen(filename):
    im = pyvips.Image.new_from_file(filename, access="sequential")
    if not im.hasalpha():
        im = im.addalpha()

    return im

images = [imopen(filename) for filename in sys.argv[2:]]
image = images[0]
for tile in images[1:]:
    image = image.join(tile, "horizontal", expand=True)

image.write_to_file(sys.argv[1])

I would use TIFF rather than PNG if possible -- PNG is extremely slow.

jcupitt
  • 10,213
  • 2
  • 23
  • 39
  • What if there are images that are BW? I'm just starting out with pyvips and it's completely not obvious and frustrating, even when looking at docs. I'm just trying to generate a text on a **transparent** background. I don't care that there are only two bands after I addalpha() to the text() output, why not just autoconvert them to the highest number of bands? – int_ua Aug 24 '20 at 02:49
  • 1
    You have a mix of RGB and mono images? You could add `im = im.colourspace('srgb')` just after the `new_from_file` to move everything to RGB. – jcupitt Aug 24 '20 at 09:55
  • 1
    It's not always possible to convert to the highest number of bands automatically. What if you have a mixture of CIELAB and RGB? Or hyperspectral and CMYK? libvips leaves conversion to a common space to the user, other than obvious things like converting both to a common numerical format. – jcupitt Aug 24 '20 at 10:01
0

Not the best solution, but as a workaround, if the input images are small enough:

convert "foo3.png" "png32:tmp.png"
vips insert tmp.png foo4.png foo.png 64 0 --expand --background '0 0 0 0'

Essentially, I'm using ImageMagick to convert to a temporary RGBA file, and then using vips on that file. It only works for small files.

Denilson Sá Maia
  • 47,466
  • 33
  • 109
  • 111