libvips / lua-vips

Lua binding for the libvips image processing library
MIT License
127 stars 10 forks source link

How to put a simple text watermark on an image? #30

Closed GildedHonour closed 5 years ago

GildedHonour commented 5 years ago

How do I create and put a text watermark on an image in a simple way?

I'll have to use composite. But how presicely?

Also, no need to write a result to a disk.

jcupitt commented 5 years ago

Hello @GildedHonour,

ruby-vips has a watermark example:

https://github.com/libvips/ruby-vips/blob/master/example/watermark.rb

You can run it like this:

$ ./watermark.rb ~/pics/IMG_2603.jpg x.jpg "Hello <i>World</i>"

To make eg.:

x

I'll make a Lua version tomorrow, though it should be easy to translate.

jcupitt commented 5 years ago

I added a lua version of that watermark example here:

https://github.com/libvips/lua-vips/blob/master/example/watermark.lua

There's an array example too, showing how to make vips images into arrays of pixel values.

GildedHonour commented 5 years ago

Thanks

GildedHonour commented 5 years ago

Apart from that, but related:

I'm writing an nginx module.

Maybe you know if there's a way to send an output image -- with watermark -- to nginx without having to save it to as a file first? That is, I'd send im as a binary stream to nginx. Perhaps, by transforming im to binary stream first somehow.

https://github.com/libvips/lua-vips/blob/master/example/watermark.lua#L32

GildedHonour commented 5 years ago

Namely, I'd need something similar to this:

    local f = io.open("some_image.jpg", "rb")
    local content = f:read("*all")
    f:close()

   -- 'content' now contains binary data  which can be sent to nginx

I need to transform im from https://github.com/libvips/lua-vips/blob/master/example/watermark.lua#L32 to the same content data type, without having to save im on a disk

jcupitt commented 5 years ago

Yes, you can do eg.:

local vips = require "vips"

local f = io.open(arg[1], "rb")
local content = f:read("*all")

local im = vips.Image.new_from_buffer(content, "", {access = "sequential"})

-- brighten 20%
im = (im * 1.2):cast("uchar")

-- print as mime jpg
local buffer = im:write_to_buffer(".jpg", {Q = 90})
print("Content-length: " .. #buffer)
print("Content-type: image/jpeg")
print("")
print(buffer)

See:

https://github.com/libvips/lua-vips#image--vipsimagenew_from_bufferstring--string_options-options

https://github.com/libvips/lua-vips#string--imagewrite_to_buffersuffix--options

jcupitt commented 5 years ago

Kleis has made an image proxy with openresty, luajit, lua-vips, nginx etc., it might be a useful reference:

https://github.com/weserv/images

GildedHonour commented 5 years ago

Thanks

jcupitt commented 5 years ago

I added that to the examples/ dir.

I added access = "sequential" too, it give a nice speedup and drop in memuse.

GildedHonour commented 5 years ago

Is there a way to put a watermark if an image is binary data comming from nginx as a response?

request --> nginx --> retrieve image file, send binary data back --> Lua script is on the way, put watermark on it --> response to a client

A Lua script would receive image as binary data, from nginx, before it reaches a client, then put watermark on it -- on the fly -- and send it to a client. A client would receive it as a normal image/file with watermark.

GildedHonour commented 5 years ago

local img = vips.Image.new_from_NNNN(binary_data_from_nginx_as_response_to_client)

And one difficulty might be is that nginx sends data in chunks. I've read about this. In what occassions presicely - I don't know yet, I haven't dug into that.

jcupitt commented 5 years ago

Sure, though you'll need to make sure you have the complete image before you set the watermark script going.

Something like:

  1. Request
  2. nginx
  3. Retrieve image file, post binary data back
  4. Wait for all parts of binary image to arrive
  5. Run watermark script to make new binary image
  6. Post watermarked binary to client
GildedHonour commented 5 years ago

Would I use "new_from_memory()" or "new_from_buffer()" in the step 4 to create an image?

And if in a separate case I needed to request an image from internet using an HTTP client and also put a watermark on an image on the fly, which function would I use?

jcupitt commented 5 years ago

The _memory functions work with images stored as simple arrays in memory, so a big ffi buffer with RGBRGBRGBRGB etc in. Theuy are handy if you want to send a simple array on to another image processing library without having to decode and recode.

The _buffer functions work with big strings containing formatted jpg, tiff etc. images. They are more useful for something like a web proxy.

So for 3 and 5, use the _buffer variants.