how to draw transparent rect in pygame - pygame

Can I draw a rect which is transparent inside, but not the outline? It would be better if I could set the outline's width.

If you just want to draw the outline of a rect, you can pass an integer as the fourth (the width) argument to pygame.draw.rect:
pygame.draw.rect(screen, (0, 100, 255), (50, 50, 162, 100), 3) # width = 3
The problem with this approach is that the corners won't look sharp and clean and the outline can't be transparent.
You could also use the gfxdraw module to draw several outlines with a for loop:
def draw_rect_outline(surface, rect, color, width=1):
x, y, w, h = rect
width = max(width, 1) # Draw at least one rect.
width = min(min(width, w//2), h//2) # Don't overdraw.
# This draws several smaller outlines inside the first outline. Invert
# the direction if it should grow outwards.
for i in range(width):
pygame.gfxdraw.rectangle(screen, (x+i, y+i, w-i*2, h-i*2), color)
draw_rect_outline(screen, (250, 50, 162, 100), (0, 100, 255, 155), 9)
That also allows you to pass a color with an alpha channel to make the outline transparent.
It would also be possible to create a transparent surface and draw a rect onto it (you can pass a transparent color here as well):
surf = pygame.Surface((162, 100), pygame.SRCALPHA)
pygame.draw.rect(surf, (0, 100, 255, 155), (0, 0, 162, 100), 21)
If you want a filled, transparent rectangle, just fill the complete surface:
surf.fill((0, 100, 255, 155))

Related

Pygame smooth movement

How can I get a pygame rect to move smoothly? Like if I update the x position by 2 it looks smooth but if I update it by bigger number like 25 it teleports to the position. Also, if possible, can this work for decimals also?
Visual Representation
import pygame
import math
GREEN = (20, 255, 140)
GREY = (210, 210 ,210)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
PURPLE = (255, 0, 255)
BLUE = (0, 0, 255)
BLACK = (0, 0, 0)
class Dot(pygame.sprite.Sprite):
# This class represents a car. It derives from the "Sprite" class in Pygame.
def __init__(self, color, width, height):
# Call the parent class (Sprite) constructor
super().__init__()
# Pass in the color of the car, and its x and y position, width and height.
# Set the background color and set it to be transparent
self.image = pygame.Surface([width, height])
self.image.fill(WHITE)
self.image.set_colorkey(WHITE)
self.color = color
self.width = width
self.height = height
pygame.draw.rect(self.image, self.color, [0, 0, self.width, self.height])
self.rect = self.image.get_rect()
How can I get a pygame rect to move smoothly?
If your rectangle has to move 25px per frame, then the it makes no sens to draw the rectangles at the positions in between. The display is updated once per frame and it make no sens at all to draw the rectangle at the positions in between.
Possibly you have to less frames per second. In that case you have to increase the framerate and you can decrease the movement. Note, the human eye can just process a certain number of images per second. The trick is that you generate enough frames, that the movement appears smooth for the human eye.
pygame.Rect can store integral values only. If you want to operate with a very high framerate and floating accuracy, then you have to store the position of the object in separate floating point attributes. Synchronize the rounded position to the rectangle attribute. Note, you cannot draw on a "half" pixel of the window (at least in pygame).
e.g.:
class Dot(pygame.sprite.Sprite):
# This class represents a car. It derives from the "Sprite" class in Pygame.
def __init__(self, color, x, y, width, height):
# Call the parent class (Sprite) constructor
super().__init__()
# Pass in the color of the car, and its x and y position, width and height.
# Set the background color and set it to be transparent
self.x = x
self.y = y
self.image = pygame.Surface([width, height])
self.image.fill(self.color)
self.rect = self.image.get_rect(center = (round(x), round(y)))
def update(self):
# update position of object (change `self.x`, ``self.y``)
# [...]
# synchronize position to `.rect`
self.rect.center = (round(x), round(y))

PDFlib - setting stroke and fill opacity (transparency)

Is it possible to set value of alpha channel when providing fill and stroke colors in PDFlib?
$p->setlinewidth(20);
$p->setcolor('fill', 'rgb', 1, 0, 0, null);
$p->setcolor('stroke', 'rgb', 0, 1, 0, null);
$p->rect(0, 0, 100, 100);
$p->fill_stroke();
Is it possible to make rectangle's red fill and thick green border to be semi-transparent?
Is it possible to make rectangle's red fill and thick green border to be semi-transparent?
sure, please use GState for this task. You find a complete sample code within the PDFlib cookbook: Transparent Graphics
/* Save the current graphics state. The save/restore of the current
* state is not necessarily required, but it will help you get back to
* a graphics state without any transparency.
*/
$gstate = $p->create_gstate("opacityfill=.5 opacitystroke=.5");
$p->save();
$p->set_gstate($gstate);
$p->setlinewidth(20);
$p->setcolor('fill', 'rgb', 1, 0, 0, null);
$p->setcolor('stroke', 'rgb', 0, 1, 0, null);
$p->rect(0, 0, 100, 100);
$p->fill_stroke();
$p->restore();
For a powerful path generation, you might use the Path object. See PDFlib 9.2 Documentation as well the samples within PDFlib Cookbook - path objects.
page.drawText(WATERMARK.LABEL, {
x: 180,
y: 400,
size: 30,
font: helveticaFont,
color: rgb(220 / 255, 220 / 255, 220 / 255),
rotate: degrees(-315),
opacity: 0.6
})
// add opacity field only

Can't get radial gradient

I'm trying to create elipse with radial gradient fill, but flash makes it filled with solid color (the second one - 0xe9afaf)
var mat:Matrix = new Matrix();
mat.createGradientBox(150, 100, 0, 0, 0);
timeField = new Shape();
timeField.graphics.beginGradientFill(GradientType.RADIAL, [0xd35f57, 0xe9afaf], [1, 1], [0,255],mat);
timeField.graphics.lineStyle(3, 0x561717);
timeField.graphics.drawEllipse(GlobalVariables.globalStage.stageWidth / 2 - 75, -50, 150, 100);
timeField.graphics.endFill();
addChild(timeField);
I have no idea what's wrong.
The position of your matrix's gradient box and your ellipse are off center, so you're seeing the solid part of the gradient after all the color has faded out. You're going to have to offset your gradient box to match the position of the ellipse.
Line 2:
mat.createGradientBox(150, 100, 0, GlobalVariables.globalStage.stageWidth / 2 - 75, -50);
Or you can also make your ellipse at 0, 0 and move the timeField to the center where you want it.
timeField.graphics.drawEllipse(0, 0, 150, 100);
timeField.x = GlobalVariables.globalStage.stageWidth / 2 - 75;
timeField.y = -50;

html5 canvas overlay cutout workaround in safari

I am trying to create an overlay that can highlight certain portions of the page. The best way I've figured out to do this is to use a canvas fit to the page, draw the shapes I need, and draw a rectangle using this trick:
ctx.rect(canvas.width, 0, 0 - canvas.width, canvas.height);
I'm not sure I can explain this well, so it might be best to look at the jsFiddle example here to get an idea of what I am trying to do.
This works perfectly in every browser except Safari. Is there any way to achieve this effect in Safari?
You can try filling the whole canvas first, then use composite mode to knock out the shapes.
Example:
ctx.fillStyle = "rgba(0, 0, 0, 0.5)";
ctx.fillRect(canvas.width, 0, 0 - canvas.width, canvas.height);
// next shape will punch hole in the draw rectangle above
ctx.globalCompositeOperation = 'destination-out';
ctx.fillStyle = "rgba(0, 0, 0, 1)"; // make sure alpha is 100%
ctx.beginPath();
ctx.moveTo(300, 60);
ctx.arc(300, 60, 50, 0, 2 * Math.PI);
ctx.moveTo(500, 160);
ctx.arc(500, 160, 50, 0, 2 * Math.PI);
drawEllipse(ctx, 103, 23, 100, 30)
drawEllipse(ctx, 503, 23, 100, 30)
ctx.fill();
ctx.globalCompositeOperation = 'source-over'; // reset comp. mode
Modifed fiddle here
Alpha (not the color) will determine how much visible the hole will be.
Hope this helps.

Html5 Canvas - Shading an outside area

I need to shade an OUTSIDE area, ie the shapes I draw in the shader are drawn normally, and their inverse is then shaded. Its easiest to explain with an example, and noting the bit that is not working:
// canvasBackground is the actual background
// canvasBackgroundContext is its context
// To make it simple, I will fill it with green
canvasBackgroundContext.fillStyle = "#00FF00";
canvasBackgroundContext.clearRect(0, 0, canvasBackground.width, canvasBackground.height);
// I also have a the shader
// canvasShader and canvasShaderContext with same width and height as canvasBackground
canvasShaderContext.fillStyle = "rgba(0, 0, 0, 0.25)"; // Black but slightly transparent
canvasShaderContext.clearRect(0, 0, canvasShader.width, canvasShader.height);
// Everything so far is great - now the problem
// This is wrong, because when I create the area I want to create clear, it does not work
// because when you draw a shape it does not work like clearRect, as it does not set each pixel to a clear pixel
canvasShaderContext.fillStyle = "rgba(0, 0, 0, 0.0)";
// Create the only non shaded bits in the shader, overlapping rects
canvasShaderContext.fillRect(10, 10, 50, 50);
canvasShaderContext.fillRect(40, 40, 50, 50);
// So when I do this, it should shade the entire background except for the two 50x50 overlapping rects at 10,10 and 40,40
canvasBackgroundContext.drawImage(canvasShaderContext, 0, 0);
I don't want to go to a pixel by pixel basis using getImageData, as that is slow. There must be some way of doing this.
I am not sure I fully understand what you try to achieve, but how about adding a composite mode to this:
canvasShaderContext.fillRect(10, 10, 50, 50);
canvasShaderContext.fillRect(40, 40, 50, 50);
which results in:
/// store old mode whatever that is
var oldMode = canvasShaderContext.globalCompositeOperation;
/// this uses any shape that is drawn next to punch a hole
/// in destination (current context).
canvasShaderContext.globalCompositeOperation = 'destination-out';
/// now draw the holes
canvasShaderContext.fillRect(10, 10, 50, 50);
canvasShaderContext.fillRect(40, 40, 50, 50);
/// set back to old mode
canvasShaderContext.globalCompositeOperation = oldMode;
That will also clear the alpha bits.