OK I seem to have found the cause just by sheer luck and its nothing wrong with that particular method, it's further back up the call stack.
Earlier I resize the image and as part of that method I return the resized object as follows. I have inserted two calls to the above method and a direct save to a file.
// At this point the new bitmap has no MimeType
// Need to output to memory stream
using (var m = new MemoryStream())
{
dst.Save(m, format);
var img = Image.FromStream(m);
//TEST
img.Save("C:\\test.jpg");
var bytes = PhotoEditor.ConvertImageToByteArray(img);
return img;
}
It appears that the memory stream that the object was created on has to be open at the time the object is saved. I am not sure why this is. Is anyone able to enlighten me and how I can get around this.
I only return from a stream because after using the resize code similar to this the destination file has an unknown mime type (img.RawFormat.Guid) and Id like the Mime type to be correct on all image objects as it makes it hard write generic handling code otherwise.
EDIT
This didn't come up in my initial search but here's the answer from Jon Skeet
This is a very brute force method, but it gets the job done. Code to produce the gradients was borrowed from here.
from PIL import Image, ImageDraw
def channel(i, c, size, startFill, stopFill):
"""calculate the value of a single color channel for a single pixel"""
return startFill[c] + int((i * 1.0 / size) * (stopFill[c] - startFill[c]))
def color(i, size, startFill, stopFill):
"""calculate the RGB value of a single pixel"""
return tuple([channel(i, c, size, startFill, stopFill) for c in range(3)])
def round_corner(radius):
"""Draw a round corner"""
corner = Image.new('RGBA', (radius, radius), (0, 0, 0, 0))
draw = ImageDraw.Draw(corner)
draw.pieslice((0, 0, radius * 2, radius * 2), 180, 270, fill="blue")
return corner
def apply_grad_to_corner(corner, gradient, backwards = False, topBottom = False):
width, height = corner.size
widthIter = range(width)
if backwards:
widthIter.reverse()
for i in xrange(height):
gradPos = 0
for j in widthIter:
if topBottom:
pos = (i,j)
else:
pos = (j,i)
pix = corner.getpixel(pos)
gradPos+=1
if pix[3] != 0:
corner.putpixel(pos,gradient[gradPos])
return corner
def round_rectangle(size, radius, startFill, stopFill, runTopBottom = False):
"""Draw a rounded rectangle"""
width, height = size
rectangle = Image.new('RGBA', size)
if runTopBottom:
si = height
else:
si = width
gradient = [ color(i, width, startFill, stopFill) for i in xrange(si) ]
if runTopBottom:
modGrad = []
for i in xrange(height):
modGrad += [gradient[i]] * width
rectangle.putdata(modGrad)
else:
rectangle.putdata(gradient*height)
origCorner = round_corner(radius)
# upper left
corner = origCorner
apply_grad_to_corner(corner,gradient,False,runTopBottom)
rectangle.paste(corner, (0, 0))
# lower left
if runTopBottom:
gradient.reverse()
backwards = True
else:
backwards = False
corner = origCorner.rotate(90)
apply_grad_to_corner(corner,gradient,backwards,runTopBottom)
rectangle.paste(corner, (0, height - radius))
# lower right
if not runTopBottom:
gradient.reverse()
corner = origCorner.rotate(180)
apply_grad_to_corner(corner,gradient,True,runTopBottom)
rectangle.paste(corner, (width - radius, height - radius))
# upper right
if runTopBottom:
gradient.reverse()
backwards = False
else:
backwards = True
corner = origCorner.rotate(270)
apply_grad_to_corner(corner,gradient,backwards,runTopBottom)
rectangle.paste(corner, (width - radius, 0))
return rectangle
img = round_rectangle((200, 200), 70, (255,0,0), (0,255,0), True)
img.save("test.png", 'PNG')
Running from left to right (runTopBottom = False):
Running from top to bottom (runTopBottom = True):
Best Answer
Have you tried using a combination of CreateRoundRectRegion and then FillRgn to fill the non-rectangular area?
This the example given in the docs for CreateRoundRectRegion:
In general, when you want to do something with non-rectangular areas you have to start looking into regions.