Holiday Paintable Canvas Challenge

Create your best holiday image in the paintable canvas and share it here.

Example:
I was able to create a Santa Clause in the paintable canvas by simply tracing an image using the techniques outlined in this tutorial:
Paintable Canvas Hacks Post #1

Result:

Repaint Event Code:

from java.awt import BasicStroke
from java.awt.geom import Arc2D, GeneralPath

graphics = event.graphics
graphics.stroke = BasicStroke(2)
graphics.color = system.gui.color('red')

# Scale graphics to actual component size
dX = (event.width-1)/230.0
dY = (event.height-1)/275.0
graphics.scale(dX,dY)

###################
# Paint Red HAT
###################
hat = GeneralPath()

# Top of hat
hat.append(Arc2D.Double(20, 5, 185, 180, 360, 178, Arc2D.OPEN), True)

# Top of hat brim
hat.append(Arc2D.Double(-60, 75, 330, 230, 121, -59, Arc2D.OPEN), True)

# Right of hat brim
hat.append(Arc2D.Double(117, 69, 70, 76, 30, -60, Arc2D.OPEN), True)

# Beard Border
hat.append(Arc2D.Double(121, 105, 64, 62, 30, -40, Arc2D.OPEN), True)

# Top of ball on hat
hat.append(Arc2D.Double(171, 138, 53, 52, 114, -34, Arc2D.OPEN), True)

# Hat tail 
hat.append(Arc2D.Double(-39, -20, 245, 257, 348, 18, Arc2D.OPEN), True)

hat.closePath()
graphics.fill(hat)

###################
# Paint White Hat Brim
###################
graphics.color = system.gui.color(245, 245, 235)
hatBrim = GeneralPath()

# Top of hat brim
hatBrim.append(Arc2D.Double(-60, 75, 330, 230, 62, 59, Arc2D.OPEN), True)

# Left of hat brim
hatBrim.append(Arc2D.Double(12, 80, 70, 61, 144, 65, Arc2D.OPEN), True)

# Bottom of hat brim
hatBrim.append(Arc2D.Double(-60, 110, 320, 230, 121, -61, Arc2D.OPEN), True)

# Right of hat brim
hatBrim.append(Arc2D.Double(117, 69, 70, 76, 330, 60, Arc2D.OPEN), True)

hatBrim.closePath()
graphics.fill(hatBrim)

###################
# Paint White Hat Ball
###################

graphics.color = system.gui.color(245, 245, 235)
graphics.fillOval(171, 138, 53, 52)

###################
# Paint White Beard
###################
beard = GeneralPath()
graphics.color = system.gui.color(235, 240, 245)

# Beard Shapes starting at the left and moving clockwise
beard.append(Arc2D.Double(10, 115, 64, 62, 145, 50, Arc2D.OPEN), True)
beard.append(Arc2D.Double(4, 146, 58, 53, 142, 102, Arc2D.OPEN), True)
beard.append(Arc2D.Double(16, 182, 58, 53, 152, 118, Arc2D.OPEN), True)
beard.append(Arc2D.Double(46, 208, 50, 53, 183, 108, Arc2D.OPEN), True)
beard.append(Arc2D.Double(75, 216, 50, 54, 214, 108, Arc2D.OPEN), True) # Bottom of beard
beard.append(Arc2D.Double(108, 208, 50, 53, 240, 121, Arc2D.OPEN), True)
beard.append(Arc2D.Double(128, 182, 58, 53, 273, 118, Arc2D.OPEN), True)
beard.append(Arc2D.Double(134, 146, 58, 53, 309, 99, Arc2D.OPEN), True)
beard.append(Arc2D.Double(121, 105, 64, 62, 330, 50, Arc2D.OPEN), True)

# Bottom of hat brim
beard.append(Arc2D.Double(-60, 110, 320, 230, 60, 61, Arc2D.OPEN), True)

beard.closePath()
graphics.fill(beard)

###################
# Paint Face
###################
face = GeneralPath()
graphics.color = system.gui.color(255, 224, 189)

# Right cheek
face.append(Arc2D.Double(33, 75, 130, 150, 330, 55, Arc2D.OPEN), True)

# Bottom of hat brim
face.append(Arc2D.Double(-60, 110, 320, 230, 65, 50, Arc2D.OPEN), True)

# left cheek
face.append(Arc2D.Double(33, 75, 130, 150, 155, 55, Arc2D.OPEN), True)


face.closePath()
graphics.fill(face)

###################
# Paint Mouth
###################

graphics.color = system.gui.color('pink')
graphics.fillOval(79, 150, 38, 41)

###################
# Paint Eyebrows
###################
graphics.color = system.gui.color(225, 230, 235)

rightEyeBrow = GeneralPath()
rightEyeBrow.moveTo(137, 113)
rightEyeBrow.lineTo(138, 122)
rightEyeBrow.lineTo(114, 111)
rightEyeBrow.closePath()
graphics.fill(rightEyeBrow)

leftEyeBrow = GeneralPath()
leftEyeBrow.moveTo(57, 115)
leftEyeBrow.lineTo(56, 122)
leftEyeBrow.lineTo(80, 112)
leftEyeBrow.closePath()
graphics.fill(leftEyeBrow)

###################
# Paint Mustash
###################
LeftStash = GeneralPath()
LeftStash.append(Arc2D.Double(61, 145, 75, 64, 114, 50, Arc2D.OPEN), True)
LeftStash.append(Arc2D.Double(28, 141, 36, 41, 349, -164, Arc2D.OPEN), True)
LeftStash.append(Arc2D.Double(28, 128, 70, 70, 185, 174, Arc2D.OPEN), True)
LeftStash.closePath()
graphics.fill(LeftStash)

RightStash = GeneralPath()
RightStash.append(Arc2D.Double(98, 128, 70, 70, 185, 174, Arc2D.OPEN), True)
RightStash.append(Arc2D.Double(133, 141, 36, 41, 1, -166, Arc2D.OPEN), True)
RightStash.append(Arc2D.Double(61, 145, 75, 64, 16, 50, Arc2D.OPEN), True)
RightStash.closePath()
graphics.fill(RightStash)

###################
# Paint Nose
###################

graphics.color = system.gui.color(225, 150, 150)
graphics.fillOval(82, 140, 31, 22)

###################
# Draw Santa outline and facial details over filled shapes
###################
graphics.stroke = BasicStroke(2)
graphics.color = system.gui.color('black')

# Top of hat
graphics.drawArc(20, 5, 185, 180, 360, 178)

# Top of hat brim
graphics.drawArc(-60, 75, 330, 230, 62, 59)

# Bottom of hat brim
graphics.drawArc(-60, 110, 320, 230, 60, 61)

# Left of hat brim
graphics.drawArc(12, 80, 70, 61, 144, 65)

# Right of hat brim
graphics.drawArc(117, 69, 70, 76, 330, 60)

# Crease between hat tail and hat
graphics.drawArc(95, 40, 86, 106, 10, 24)
graphics.drawArc(95, 40, 86, 106, 40, 24)

# Hat tail
graphics.drawArc(-39, -19, 245, 257, 348, 18)

# Ball on end of hat tail
graphics.drawArc(171, 138, 53, 52, 245, 238)

# Beard counterclockwise
graphics.drawArc(121, 105, 64, 62, 330, 50)
graphics.drawArc(134, 146, 58, 53, 309, 99)
graphics.drawArc(128, 182, 58, 53, 273, 118)
graphics.drawArc(108, 208, 50, 53, 240, 121)
graphics.drawArc(75, 216, 50, 54, 214, 108) # Bottom of beard
graphics.drawArc(46, 208, 50, 53, 183, 108)
graphics.drawArc(16, 182, 58, 53, 152, 118)
graphics.drawArc(4, 146, 58, 53, 142, 102)
graphics.drawArc(10, 115, 64, 62, 145, 50)

# Left Cheek
graphics.drawArc(33, 75, 130, 150, 155, 45)

# Right Cheek
graphics.drawArc(33, 75, 130, 150, 340, 45)

# Nose
graphics.drawOval(82, 140, 31, 22)

# left and right  eyes
graphics.fillOval(59, 121, 24, 24)
graphics.fillOval(113, 121, 24, 24)

# left and right pupils
graphics.color = system.gui.color('white')
graphics.fillOval(68, 126, 11, 11)
graphics.fillOval(117, 126, 11, 11)

# Left Eyebrow
graphics.color = system.gui.color('black')
graphics.drawLine(57, 115, 56, 122)
graphics.drawLine(56, 122, 80, 112)

# Right Eyebrow
graphics.color = system.gui.color('black')
graphics.drawLine(137, 113, 138, 122)
graphics.drawLine(138, 122, 114, 111)

# Right stash
graphics.drawArc(61, 145, 75, 64, 16, 50)
graphics.drawArc(133, 141, 36, 41, 195, 166)
graphics.drawArc(98, 128, 70, 70, 185, 174)

# Left Stash
graphics.drawArc(61, 145, 75, 64, 114, 50)
graphics.drawArc(28, 141, 36, 41, 185, 164)
graphics.drawArc(28, 128, 70, 70, 185, 174)

# Mouth
graphics.drawArc(79, 150, 38, 41, 240, 60)

I bet it'd be fun to have a procedurally generated tree with randomly placed lights, tinsel, ornaments?

No nerd sniping, Justin! There's end of year deadlines to think of!

I've made Christmas trees before: :slight_smile: Traced Christmas Tree Example

Traced Christmas Tree

For more fun:
Add a running timer component to the window. Then, put a custom property on the canvas called value and bind it to the value property of the timer to drive animations in the canvas.

Example: (Using the Santa repaint event code above)
Modify the part of the code where the eyes and pupils are drawn, so they change with the timer value:

# left and right  eyes
graphics.fillOval(59, 121, 24, 24)
if event.source.value % 2:
	graphics.fillOval(113, 121, 24, 24)
else:
	graphics.drawLine(113, 132, 133, 132)

# left and right pupils
graphics.color = system.gui.color('white')
graphics.fillOval(68, 126, 11, 11)
if event.source.value % 2:
	graphics.fillOval(117, 126, 11, 11)

Result:
SantaWinking

Thanksgiving Turkey

Repaint Event Script

from java.awt import BasicStroke

graphics = event.graphics
graphics.stroke = BasicStroke(1)

dX = (event.width-1)/225.0
dY = (event.height-1)/225.0
graphics.scale(dX,dY)

bodyColor = system.gui.color(139, 69, 19)		# brown
chestColor = system.gui.color(120, 60, 20)		# darker brown
legColor = system.gui.color(255, 140, 0)		# orange
beakColor = system.gui.color(255, 165, 0)		# lighter orange
black = system.gui.color('black')
white = system.gui.color('white')

tailColors = [
	system.gui.color(160, 82, 45),				# sienna
	system.gui.color(205, 92, 92),				# indian red
	system.gui.color(222, 184, 135),			# tan
	system.gui.color(210, 105, 30),				# chocolate
	system.gui.color(184, 134, 11),				# dark gold
	bodyColor									# brown
	]

# Draw tail feathers behind the body
baseX = 38
baseY = 80
diameter = 130
arcSpan = 25
overlap = 5
totalArc = (arcSpan - overlap) * len(tailColors) 
for iteration in xrange(1, 3):
	startAngle = 208 + (totalArc * iteration)
	for index, color in enumerate(tailColors):
		graphics.color = color
		graphics.fillArc(baseX, baseY, diameter, diameter, startAngle + (index * (arcSpan - overlap)), arcSpan)


##################### 
# Neck & Head
#####################
# Neck
graphics.color = bodyColor
graphics.fillRoundRect(95, 80, 20, 30, 10, 10)
graphics.color = black
graphics.drawRoundRect(95, 80, 20, 30, 10, 10)

# Head
graphics.color = bodyColor
graphics.fillOval(90, 55, 30, 30)
graphics.color = black
graphics.drawArc(90, 55, 30, 30, 0, 231)

##################### 
# Face
##################### 

# Eye
graphics.color = white
graphics.fillOval(100, 63, 10, 10)

# Pupil
graphics.color = black
graphics.fillOval(104, 67, 4, 4)

# Beak
graphics.color = beakColor
beakX = [118, 135, 118]
beakY = [70, 78, 86]
graphics.fillPolygon(beakX, beakY, 3)
graphics.color = black
graphics.drawPolygon(beakX, beakY, 3)

# Wattle
graphics.color = system.gui.color(200, 0, 0)
graphics.fillOval(112, 75, 8, 15)

# Body
graphics.color = black
graphics.drawArc(75, 90, 60, 70, 110, 320)
graphics.color = bodyColor
graphics.fillOval(75, 90, 60, 70)

# Chest
graphics.color = chestColor
graphics.fillOval(75, 105, 60, 45)

# Feet & Legs
graphics.stroke = BasicStroke(3)
graphics.color = legColor

# Legs
graphics.drawLine(95, 155, 95, 185)
graphics.drawLine(115, 155, 115, 185)

# Left Foot
graphics.drawLine(95, 185, 85, 190)
graphics.drawLine(95, 185, 105, 190)
graphics.drawLine(95, 180, 95, 190)

# Right Foot
graphics.drawLine(115, 185, 105, 190)
graphics.drawLine(115, 185, 125, 190)
graphics.drawLine(115, 180, 115, 190)

You forgot the potatoes and the gravy.

edit: I hope you made functions for these drawings. I'm imagining calls to cook_turkey(), bake_potatoes()...

I make a really good Easter egg, but somebody will have to find it before I'll be willing to give up the recipe:
Easter Egg Challenge

I earnestly spent a while once trying to cheat and find the easter egg just looking at the code and couldn't, so hats off (or I'm particularly blind).

The power of obfuscation :upside_down_face: I knew somebody would take that approach, so I went out of my way to use ambiguous and misleading variable names to conceal it.

Hint: The vast majority of my functions are meticulously commented.

Old Glory

Perfect for Memorial Day, Independence Day, and other patriotic American holidays

Add this code to the paintable canvas's repaint event handler:
Note: The canvas will need to be a size of at least 345 x 182 to see the entire flag

graphics = event.graphics

## The original width and height of this paintable canvas in the designer
#unscaledWidth = ???
#unscaledHeight = ???

## (Optional) Allow the canvas to be resized and scale the flag automatically
#dX = (event.width - 1) / unscaledWidth
#dY = (event.height - 1) / unscaledHeight
#graphics.scale(dX,dY)

# Iterate through the 13 stripes that represent the 13 colonies and paint them
for stripe in xrange(13):
	if stripe % 2: # Alternate red and white
		graphics.color = system.gui.color('white')
	else:
		graphics.color = system.gui.color(179, 25, 66)	# Old glory red
	
	# Proper flag dimensions were calculated using this website (pixels were substituted for inches):
	# https://www.inchcalculator.com/american-flag-size-proportions-calculator/
	stripeHeight = 14
	flagWidth = 345
	graphics.fillRect(0, (stripeHeight * stripe), flagWidth, stripeHeight)

# Create a blue rectangle for the 50 stars
graphics.color = system.gui.color(10, 49, 97)	# Old glory blue
graphics.fillRect(0, 0, 138, 97)

# Define all the points needed to make a single star in the top left corner of the canvas
# When making eyeball adjustments to the star size and shape,
# ...the coordinates are much easier to visualize written like this
# ..instead of already split into the X and Y lists that the fillPolygon method requires
points = [
	(4, 0),	# Top outer point
	(5, 3),	# Upper right inner point
	(8, 3),	# Upper right outer point
	(5, 5),	# Lower right inner point
	(7, 8),	# Bottom right outer point
	(4, 7),	# Bottom inner point
	(1, 8),	# Bottom left outer point
	(2, 5),	# Lower left inner point
	(0, 3),	# Upper left outer point
	(3, 3)]	# Upper left inner point

# Separate the x and y coordinates for the top left star into seperate lists for the fillPolygon method,
# ...and inset the star by an arbitrary margin (This was originally done directly in the points set,
# ...but once the star shape was perfected, these variables were added to make tinkering with the insets easier to do
topMargin = leftMargin = 4
xCoordinates = [coordinateSet[0] + leftMargin for coordinateSet in points]
yCoordinates = [coordinateSet[1] + topMargin for coordinateSet in points]

# Switch to white for the stars
graphics.color = system.gui.color('white')

# These arbitrary spacing parameters were precisely calculated using trial and error
horizontalSpacing = 24	# The space betwenn the left edge of a star and the left edge of its neighboring star to the right
verticalSpacing = 10	# The space between the top edge of a row, and the top edge of the row below it

# The american flag currently has 5 rows of 6 stars and 4 rows of 5 stars for a total 9 rows
for row in xrange(9):
	starCount = 5 if row % 2 else 6		# Alternate between rows of 6 and 5 stars
	starInset = 12 if row % 2 else 0	# Inset the rows of 5, so the stars appear evenly staggared
	
	# Iterate through each star in the given row,
	# ...and calculate a list of X and Y coordinates for each star to pass into the fillPolygon method
	for star in xrange(starCount):
		starSpecificXCoords = [xCoordinate + starInset + (star * horizontalSpacing) for xCoordinate in xCoordinates]
		starSpecificYCoords = [yCoordinate + (row * verticalSpacing) for yCoordinate in yCoordinates]
		
		# https://docs.oracle.com/javase/8/docs/api/java/awt/Graphics.html#fillPolygon-int:A-int:A-int-
		#graphics.fillPolygon(int[] xPoints, int[] yPoints, int numberOfPoints)
		graphics.fillPolygon(starSpecificXCoords, starSpecificYCoords, len(xCoordinates))
		
# Paint a small border around the flag, so it will look complete against white backgrounds.
graphics.color = system.gui.color('black')
graphics.drawRect(0, 0, flagWidth, (13 * stripeHeight))