copying images

299 views
Skip to first unread message

Mark Summerfield

unread,
Jun 9, 2011, 4:47:17 AM6/9/11
to golang-nuts
Hi,

As far as I can see the only way to get a copy of an image is to read
the original twice rather than reading it once and then copying it in
memory.

Copying an image is useful if you want to read the original's pixels'
colors and depending on their values change the copy's pixels' colors.

And in some situations you don't want to work on the original because
the new color may depend on a pixel _and_ its surrounding pixels, so the
original needs to be kept pristine during the processing.

Perhaps a new function is needed?

image.Image.Copy() image.Image
// or
image.Image.Copy() (image.Image, os.Error)

--
Mark Summerfield, Qtrac Ltd, www.qtrac.eu
C++, Python, Qt, PyQt - training and consultancy
"Advanced Qt Programming" - ISBN 0321635906
http://www.qtrac.eu/aqpbook.html

roger peppe

unread,
Jun 9, 2011, 5:31:57 AM6/9/11
to Mark Summerfield, golang-nuts
On 9 June 2011 09:47, Mark Summerfield <li...@qtrac.plus.com> wrote:
> Hi,
>
> As far as I can see the only way to get a copy of an image is to read
> the original twice rather than reading it once and then copying it in
> memory.
>
> Copying an image is useful if you want to read the original's pixels'
> colors and depending on their values change the copy's pixels' colors.
>
> And in some situations you don't want to work on the original because
> the new color may depend on a pixel _and_ its surrounding pixels, so the
> original needs to be kept pristine during the processing.
>
> Perhaps a new function is needed?
>
>    image.Image.Copy() image.Image
>    // or
>    image.Image.Copy() (image.Image, os.Error)

I think this is a good idea. If it was done, it could be
added as part of the Image interface:

type Image interface {
// ColorModel returns the Image's ColorModel.
ColorModel() ColorModel
// Bounds returns the domain for which At can return non-zero color.
// The bounds do not necessarily contain the point (0, 0).
Bounds() Rectangle
// At returns the color of the pixel at (x, y).
// At(Bounds().Min.X, Bounds().Min.Y) returns the upper-left pixel
of the grid.
// At(Bounds().Max.X-1, Bounds().Max.Y-1) returns the lower-right one.
At(x, y int) Color
// Copy returns a copy of the image.
Copy() Image
}

In addition to this, I think it would be useful to be able to
create a new image from an arbitrary ColorModel
(for instance to place a border around an image without
incurring a colour space conversion or enumerating all
possible colour models).

The ColorModel interface could be given a new method:

type ColorModel interface {
Convert(c Color) Color
// NewImage creates a new image of the given width
// and height using the given ColorModel to store pixels.
NewImage(w, h int) Image
}

Then copying an image also could be done like this
(note that this would not work to copy images
without a Set method, such as a ColorImage)

func CopyImage(i image.Image) image.Image {
r := i.Bounds()
ni := i.ColorModel().NewImage(r.Dx(), r.Dy()).(draw.Image)
draw.DrawMask(ni, r, i, r.Min, nil, image.ZP, draw.Src)
return ni
}

[aside: it seems a pity that the image creation functions
take a width and a height rather than a bounds rectangle - there's
no real need that copying a sub-image should require copying
all the pixels of the original]

Rob 'Commander' Pike

unread,
Jun 9, 2011, 6:21:25 AM6/9/11
to roger peppe, Mark Summerfield, golang-nuts
The image stuff is being reworked.

-rob

Nigel Tao

unread,
Jun 10, 2011, 5:03:28 AM6/10/11
to roger peppe, Mark Summerfield, golang-nuts
How about the following additions to the image package:

type Buffered interface {
Image
Set(x, y int, c Color)
}

func New(ColorModel, Rectangle) Buffered

and add to image/draw:

func Copy(dst image.Buffered, r image.Rectangle, src image.Image, sp
image.Point) {
DrawMask(dst, r, src, sp, nil, image.ZP, Src)
}

so that Copy is like Draw except that it's Src instead of Over.

roger peppe

unread,
Jun 10, 2011, 5:14:51 AM6/10/11
to Nigel Tao, Mark Summerfield, golang-nuts
On 10 June 2011 10:03, Nigel Tao <nige...@golang.org> wrote:
> How about the following additions to the image package:
>
> type Buffered interface {
>  Image
>  Set(x, y int, c Color)
> }
>
> func New(ColorModel, Rectangle) Buffered

this won't work if people define colour models
external to the image package (which would be
a nice thing to be able to do - there are some useful
but complex colour models).

the reason i suggested adding a Copy method to image
is that i think it would be nice if at some point in the future
the draw package could work on images in non-local
memory (for example in a graphics card's memory).
we're not far away from being able to do that.

if that is indeed a desirable thing, then we'd probably want the
copy of an image to reside in the same backing store
as the image itself, which a New method based on
the ColorModel wouldn't not be able to do.

Nigel Tao

unread,
Jun 10, 2011, 5:37:23 AM6/10/11
to roger peppe, Mark Summerfield, golang-nuts
On 10 June 2011 19:14, roger peppe <rogp...@gmail.com> wrote:
> this won't work if people define colour models
> external to the image package (which would be
> a nice thing to be able to do - there are some useful
> but complex colour models).

It would if packages could register factory functions for ColorModels,
the way they can currently register decoding funtions for image file
formats.

roger peppe

unread,
Jun 10, 2011, 6:09:50 AM6/10/11
to Nigel Tao, Mark Summerfield, golang-nuts
what do we gain by putting the image creation functions inside
a map[Colormodel] func(...) Image (which is presumably
what we'd have) rather than having them
directly associated with the colour model itself?

Nigel Tao

unread,
Jun 10, 2011, 7:57:43 PM6/10/11
to roger peppe, Mark Summerfield, golang-nuts
On 10 June 2011 20:09, roger peppe <rogp...@gmail.com> wrote:
> what do we gain by putting the image creation functions inside
> a map[Colormodel] func(...) Image (which is presumably
> what we'd have) rather than having them
> directly associated with the colour model itself?

Not every ColorModel needs to have a NewImage(Rectangle) method. For
example, when creating a ycbcr.YCbCr image you usually also want to
specify the chroma subsampling ratio. Also, an image.ColorImage has a
one-off ColorModel that doesn't necessarily need a NewImage method.
How about:

[package image]
type Factory interface {
NewImage(Rectangle) Image
}

that the usual ColorModels (e.g. RGBAColorModel) implement, but it
isn't mandatory for all ColorModels to implement. As an analogy,
io.Reader only has one method, but implementations commonly satisfy
io.Closer, or a flusher interface, etc.


> the reason i suggested adding a Copy method to image
> is that i think it would be nice if at some point in the future
> the draw package could work on images in non-local
> memory (for example in a graphics card's memory).
> we're not far away from being able to do that.

There's two similar-but-different meanings of "copy" here. One is to
"make a copy" as in "make a clone" or "make a duplicate". The other is
"read from here and write to there", like the built-in copy function,
or what draw.Draw does with the Src operator. To be precise, I'd like
to use "duplicate" for the first meaning and "copy" for the second.

Again, a Duplicate method might be nice, but I think it would be
better as a separate interface rather than insisting that all Image
implementations know how to duplicate themselves. You could also have
a generic image.Duplicate function that sniffed for this interface, a
little like io.Copy sniffing for io.ReaderFrom / io.WriterTo.

roger peppe

unread,
Jun 11, 2011, 4:42:13 AM6/11/11
to Nigel Tao, Mark Summerfield, golang-nuts
On 11 June 2011 00:57, Nigel Tao <nige...@golang.org> wrote:
> On 10 June 2011 20:09, roger peppe <rogp...@gmail.com> wrote:
>> what do we gain by putting the image creation functions inside
>> a map[Colormodel] func(...) Image (which is presumably
>> what we'd have) rather than having them
>> directly associated with the colour model itself?
>
> Not every ColorModel needs to have a NewImage(Rectangle) method. For
> example, when creating a ycbcr.YCbCr image you usually also want to
> specify the chroma subsampling ratio. Also, an image.ColorImage has a
> one-off ColorModel that doesn't necessarily need a NewImage method.
> How about:
>
> [package image]
> type Factory interface {
>  NewImage(Rectangle) Image
> }
>
> that the usual ColorModels (e.g. RGBAColorModel) implement, but it
> isn't mandatory for all ColorModels to implement. As an analogy,
> io.Reader only has one method, but implementations commonly satisfy
> io.Closer, or a flusher interface, etc.

This seems OK. As an alternative to this, one could just have NewImage
return nil
when a colour model doesn't support it. I don't mind too much either way.

>> the reason i suggested adding a Copy method to image
>> is that i think it would be nice if at some point in the future
>> the draw package could work on images in non-local
>> memory (for example in a graphics card's memory).
>> we're not far away from being able to do that.
>
> There's two similar-but-different meanings of "copy" here. One is to
> "make a copy" as in "make a clone" or "make a duplicate". The other is
> "read from here and write to there", like the built-in copy function,
> or what draw.Draw does with the Src operator. To be precise, I'd like
> to use "duplicate" for the first meaning and "copy" for the second.
>
> Again, a Duplicate method might be nice, but I think it would be
> better as a separate interface rather than insisting that all Image
> implementations know how to duplicate themselves. You could also have
> a generic image.Duplicate function that sniffed for this interface, a
> little like io.Copy sniffing for io.ReaderFrom / io.WriterTo.

Yes, this seems OK too.

Reply all
Reply to author
Forward
0 new messages