Anti-aliasing in the awesome window manager - awesome-wm

Ok so basically, can we somehow get anti-aliasing in the awesome window manager?
The fonts look amazing and everything but it would be really nice to have anti-aliasing applied to regular widgets in awesome. Anti-aliased round-cornered titlebars would be amazing. Also the other shapes applied to widgets like gears.shape.rounded_rect or gears.shape.circle. Or all of the others that have rounded anything.
Is it even possible? I searched for cairo and anti aliasing and I barely found anything and even the people that said something said that it's really hard or just not possible to get really good anti aliasing in cairo.
Also, I looked through an old copy of the awesome-wm repository and at some point I found this in the draw.c file:
draw_rectangle_gradient(draw_context_t *ctx, area_t geometry, float line_width, bool filled,
vector_t gradient_vector, const color_t *pcolor,
const color_t *pcolor_center, const color_t *pcolor_end)
{
cairo_pattern_t *pat;
cairo_set_antialias(ctx->cr, CAIRO_ANTIALIAS_NONE);
cairo_set_line_width(ctx->cr, line_width);
cairo_set_miter_limit(ctx->cr, 10.0);
cairo_set_line_join(ctx->cr, CAIRO_LINE_JOIN_MITER);
Now in the current repository I was not able to find anything like this, so my question is "can we users do something to make the rounded shapes in awesome be anti-aliased?"
EDIT: If there is not an easy way, could you direct me into what the changes required would be to make this work?

Anti-aliased round-cornered titlebars would be amazing
Non-rectangular windows are done in X11 with the SHAPE extension. This extension only allows "this pixel is in the window" or "this pixel is outside of the window". Thus, no anti-aliasing is possible here.
https://www.x.org/releases/X11R7.7/doc/xextproto/shape.html
However, when you have a compositing manager running, one can add an alpha channel to a window. This allows things to be e.g. 50% translucent. Thus, with this, an alpha channel is possible.
So, in AwesomeWM, you could do a outside-rounded border around a client by setting border width to zero and instead adding a titlebar on each side of the client that contains some "real transparency".
A cheap example that does not actually do rounded corners, but shows transparency:
local my_widget = wibox.widget.base.make_widget()
local cairo = require("lgi").cairo
function my_widget:draw(_, cr, width, height)
cr:set_operator(cairo.Operator.SOURCE)
cr:set_source(gears.color.create_linear_pattern{
from = { 0, 0 },
to = { width, 0 },
stops = {
{ 0, "#f000" },
{ 1, "#0f0f" },
},
})
cr:paint()
end
awful.titlebar(c, { position = "bottom" }):set_widget(my_widget)
In this way, one could do a titlebar that draws a rounded corner in an anti-aliased way. However, this would require doing things in multiple pieces, because we need to create each titlebar separately.
Also, this can only do a rounded corner on the outside. On the inside (i.e. towards the actual client content), AwesomeWM only provides access to the shape extension. However, we would have to draw something on the actual client window to have an antialiased rounded corner. This is currently not possible.
(I hope this paragraph can be understood. Somehow I feel like it is hard to describe/understand.)
Also the other shapes applied to widgets like gears.shape.rounded_rect or gears.shape.circle.
Well... I'm not sure why you think that there is no antialiasing here.
local w = wibox{ x = 10, y = 10, height = 300, width = 300 }
w:setup {
widget = wibox.container.background,
bg = '#f00',
{
widget = wibox.container.background,
shape = gears.shape.circle,
bg = '#0f0',
}
}
w.visible = true
A zoom into the resulting image clearly shows antialiasing:
Or all of the others that have rounded anything.
This is actually not specific to the shape, but to the thing that applies the shape. For example wibox.container.background (which "draws directly" and thus can do antialiasing) versus awful.client.shape (which uses the X11 shape extension and thus cannot do antialiasing).

Related

Transparent QGraphicsWebview over QGLWidget leads to super imposed images

I have a transparent QGraphicsWebview inside a QGraphicsView with the following settings:
The QGraphicsView is the high level widget, and is shown in full screen mode
The graphics view uses a QGLWidget as its view port (to use opengl-es)
Alpha channel and double buffering are enabled in this QGLWidget
Transparency is achieved by graphicsView->setStyleSheet("background:transparent")
Following attributes are set for QGraphicsView and QGraphicsWebview
WA_TranslucentBackground = true
WA_NoSystemBackground = true
WA_OpaquePaintEvent = false
The QPalette::Base and QPalette::Window brushes of webview and webview->page() are set to Qt::transparent
At the beginning, the transparency works fine. But as the screen get updated (when I scroll), it looks like the new bitmap is blended on top of the existing one to get a superimposed picture. After about 5-6 screen updates, this blending causes the colors to accumulate and form an opaque rectangle (with a corrupted image). Following images show first, second and final stages of the problem.
How do I tell qt/opengl to stop blending and just draw the new image to the frame buffer?
I tried calling fillRect(boundRect(), Qt::transparent) from overridden Webview::paint and GraphicsView::paintEvent; but it didn't work except for making the updates slower.
I am new to Qt and OpenGl, so I might be missing some basic flags or settings.
I tried all the methods mentioned above. They did not work for me. I then debugged into qtbase code and found that setting the Opacity level make the top browser layer transparent.
this->setOpacity(0.1);
this pointer points to the QGraphicsWebView object.
With this method, the whole front browser contents including background will be transparent. To separate header, paragraph and background and to specify different transparent levels for them, I will have to dig into webkit code a little further to figure out the problem. But for now, setOpacity() did the trick and is good enough for what I am doing.
It turns out the problem is graphicsView->setStyleSheet("background:transparent");. Who would have guessed?!
Yeah, the line that I thought made transparency work was actually causing troubles with transparency. The application works fine without that line (or if you change it to background:none)
In short, steps to get a transparent QGraphicsWebview using QGLWidget:
Set the Base palettes of QGraphicsWebview, QWebpage and the outer QGraphicsView to Qt::transparent
scene->setBackgroundBrush(QBrush(Qt::transparent));
You should also make sure that html body background is set to transparent values:
html, body {
background-color: rgba(127, 127, 0, 0.5);
}

crop an image into a circle rmagick + rails

I am a newbie to RoR and for a feature we need to resize and crop images into circular/oval shaped images. I am using Carrierwave gem to upload them and rmagick(2.1.2) to modify the images on rails 4.1 platform.
On top of that, we need to dynamically mask the images with some color(saved in the modal, every image would have different color based on certain parametes.) before rendering them.
For the first part, I am trying this:
def crop_large
manipulate! do |source|
source = source.resize_to_fill(450,450).quantize(256,Magick::GRAYColorspace).contrast(true)
canvas = Magick::Image.new 450,450
gc = Magick::Draw.new
gc.fill "black"
gc.circle 225,225,5,225
gc.draw canvas
mask = canvas.blur_image(0,1).negate
mask.matte = false
source.matte = true
source.composite!(mask, Magick::CenterGravity, Magick::MultiplyCompositeOp)
end
end
But this leaves black borders and I don't know how to get rid of them. Any clues on how should I fix this?
Also, I don't know how to get the 2nd part done.
Sounds like you are having styling issues, fix it with css by adding a class or two,
it will be much easier.

Scaling Google Maps API v3 MarkerIcons up

I'm displaying a map with many MarkerIcons, all based on the same png but scaled to various sizes.
The base size is 64 x 64 and if I am scaling down, things work as expected.
If I am scaling up, the icons are cropped. I made a trivial JSFiddle that illustrates the issue - this is the code to scale icon. My understanding is the first size is the actual size of the source image in pixels, next two positions are the origin and anchor which I don't care about for the moment and the final size is the scaled size in pixels.
var icon_scaled = new google.maps.MarkerImage(
img-filename,
new google.maps.Size(64, 64),
null,
null,
new google.maps.Size(scaled_size, scaled_size)
);
In the examples I found, you can omit the first size and let the browser calculate it. That works on Chrome but fails on Firefox with an error message like:
Error: IndexSizeError: Index or size is negative or
greater than the allowed amount
Fiddle here: http://jsfiddle.net/y8E54/
How can I do this on both browsers without any errors?
BTW: I know MarkerIcon is deprecated - my experiments replacing it using 'icon' as per the docs and specifying 'size' and 'scaledSize' lead to the same kinds of issues.
I had the same problem and after some research and a simple workaround, I was able to fix this headache.
Here is what I did.
It seems that you need to set both the "size" & "scaleSize" attributes for this to work in FF. But then, there was one other thing which bugged me. When I set the "size" attribute to the original size of the icon, the icon scaled but cropped abruptly without showing the full icon - probably because of the size limitation.
So, I set of the "size" attribute to the max limit of the scaled img (which was 64 in my case) and it worked like a charm.
cObject.setIcon({
url: cObjects[y].getIcon().url,
scaledSize: new google.maps.Size(icoSize, icoSize-1),
size:new google.maps.Size(64, 64)
});

Trying to zoom image based on mouse origin, yet my math is slightly off

I'm working on a full screen image viewer, I'll temporarily open a dev URL here:
http://www.jungledragon.org/apps/jd3/image/704/great_grey_owl.html/zoom
This viewer is responsive and scales to your browser width/height. One of its key features is being able to zoom in and out of the image using your mouse wheel. Rather than a center-based zoom, the idea is to zoom based on origin, meaning the coordinates of your mouse, allowing you to zoom into specific areas of the image.
How to reproduce the issue
If you open the above URL and have a quick play with your mouse wheel, it may appear to be working correctly. However, the math I am using is slightly off. Here is how you can reproduce the issue:
Open the above URL
Hover your mouse over the left eye of the Owl
Zoom one step using your mouse wheel, it should zoom exactly into the eye
Position your mouse on the owl's beak
Zoom one more step using your mouse wheel
You should now notice that the second zoom step did not go into the Owl's beak exactly, it seems to be slightly off, both horizontally and vertically. I'm thinking this is a result of bad math.
How it works
Here is the javascript that handles it all:
http://www.jungledragon.org/apps/jd3/js/jd3-slideshow.js
I am capturing the mousewheel event. Based upon its direction, I am increasing or decreasing the zoom level. The actual zooming is nothing more than applying a CSS class that scales the image using a CSS3 transform:
&.grow1 { #include jd-scale(1); }
&.grow2 { #include jd-scale(1.5); }
&.grow3 { #include jd-scale(2.0); }
&.grow4 { #include jd-scale(2.5); }
&.grow5 { #include jd-scale(3.0); }
Note: the above is a call to a SASS mixin that translates into the right vendor prefixes for transform:scale.
The above accomplishes the basic zooming without issues. To make origin-based zooming possible, however, a few more steps are needed. Upon doing the actual zooming, I first set the origin of the zoom in javascript, using transform-origin. Here is my helper function for setting it:
function zoomOrigin(selector, originStr) {
selector.css({'-webkit-transform-origin': originStr});
selector.css({'-moz-transform-origin': originStr});
selector.css({'-ms-transform-origin': originStr});
selector.css({'-o-transform-origin': originStr});
selector.css({'transform-origin': originStr});
}
The heart of this question is about calculating the correct origin. There are two things worthy to mention in calculating this value:
The absolute coordinates (meaning the X and Y) are relative to the image, not relative to the page
The calculation of the origin should take into account that the image has grown/shrunk based on the current zoom state
The origin calculation happens in realtime, based on the mousemove event. Here is the method that does so, with irrelevant parts removed:
$("#image-container img").mousemove(function(e) {
// user has moved their mouse. in case of zooming or panning, this means that the
// origin (center point) of those interactions need to be recalculated
// calculate the mouse offset within the zoomable object (which is different than the page-level offset)
// this relies on the parent of the element having position:relative set
var parentOffset = $(this).offset();
zoomOriginX = e.pageX - parentOffset.left;
zoomOriginY = e.pageY - parentOffset.top;
// recalculate the width and height of the image given the current zoom level
width = $(this).outerWidth() + (1 + ((zoomLevelCurrent - 1)*0.5) * $(this).outerWidth());
height = $(this).outerHeight() + (1 + ((zoomLevelCurrent - 1)*0.5) * $(this).outerHeight());
// calculate origin percentages based on zoomed width and height
// the zoom methods rely on these variables to be set
zoomOriginPercX = (zoomOriginX / width * 100);
zoomOriginPercY = (zoomOriginY / height * 100);
});
The main purpose of this method is to correctly set the global variables zoomOriginPercX and zoomOriginPercY, which are used to set the origin (percentage) prior to zooming.
From a math perspective, my idea was to simply calculate the zoomed width of the image, and to use the offset X and Y to come to a reliable origin percentage. As the problem statement shows, I am quite close to a correct calculation, yet something is off.
Although the zooming currently works well, I want it to be perfect. It would make for quite a powerful image viewer that is really easy to implement, also for others.
Desired Effect
To start answering your question I think it's worth first clarifying the desired effect. Essentially you're looking for the same effect you'd get if you pinched to zoom on an iPhone - the 'origin' of the pinch stays exactly the same, and everything around it stretches. You can imagine pinning some stretchy fabric at the origin, and pulling the corners.
Problem
This is working fine for you if you don't move the mouse between zooms, but if you do, the origin appears to move. The cause of the problem is exactly that - you are changing the origin of the transform every time you move the mouse. Of course you do need to do this, but you are calculating the origin based on the original (100% zoomed) position of the image. The actual origin needs to be somewhere between the origin of the first zoom and the new mouse position.
In other words, CSS is just doing one transform. If you set the origin to x,y then zoom to zoom level 2, this will give the same result as if you set the origin to x2,y2, zoom to level 1, then move to x,y, and go to level 2.
Solutions
I presume you could solve the issue in several ways:
Calculate a scaling factor for the 'new' origin on each zoom
this is likely a function of zoom level, mouse position and previous origin
Calculate and apply a translation each time the origin is moved
again will depend on the current origin, zoom level and mouse position
Find another way to 'stack' transforms on top of one another.
One way to do this may be to dynamically generate a new containing div each time you and apply a scale transform to that similar to the accepted solution in this question.
Unfortunately I don't have the time to go further than this, but hopefully it points you in the right direction?

resize images with canvas - css overflow issue

I'm working on a JavaScript image resizing feature which rely on the IE only DXImageTransform addon.
Wanting to address modern browsers as well, I gave a shot to canvas, with pretty good results.
However, I face an issue in my resize function, which is the following:
function Resize(oObj, flMultiplier)
{
var canvas = document.getElementById('canvas');
var canvasContext = canvas.getContext('2d');
oObj.style.visibility = 'hidden';
canvasContext.clearRect(0,0,canvas.width,canvas.height); // clear canvas
canvasContext.fillStyle = 'rgba(0,0,0,0.4)';
canvasContext.scale(flMultiplier,flMultiplier);
canvasContext.drawImage(oObj, 0, 0);
}
If my image becomes bigger than the canvas item, then one will see only a portion of the image, which is bad.
I tried to tweak the canvas size at runtime, but if affects the display of the resized image.
So I ended up declaring a big canvas element, which is pretty OK, except that the css overflow of my web page is adjusted on my biggest element, and not on my resized image, which is a pain.
So I guess there are two ways to solve my problem:
Try to exclude the big canvas element from the overflow scheme
Try to update the canvas element size when resizing (I may have missed something there)
I haven't tried that myself, but perhaps you can create a canvas element out of the Dom, with document.createElement. It could be of arbitrary size without disturbing the display.
Now, I lack context (why do you resize images this way instead of using width and height attributes, among other questions) so maybe I am missing the point.

Resources