I created two rulers - one vertical and one horizontal:
Now in the vertical ruler, is 'size' of the text visually larger(aprox. 5-6 pixels longer).
Why?
Relevant code:
WM_CREATE:
LOGFONT Lf = {0};
Lf.lfHeight = 12;
lstrcpyW(Lf.lfFaceName, L"Arial");
if (!g_pGRI->bHorizontal)
{
Lf.lfEscapement = 900; // <----For vertical ruler!
}
g_pGRI->hfRuler = CreateFontIndirectW(&Lf);
SelectFont(g_pGRI->hdRuler, g_pGRI->hfRuler);
WM_PAINT:
SetTextColor(g_pGRI->hdRuler, g_pGRI->cBorder);
SetBkColor(g_pGRI->hdRuler, g_pGRI->cBackground);
SetTextAlign(g_pGRI->hdRuler, TA_CENTER);
#define INCREMENT 10
WCHAR wText[16] = {0};
if (g_pGRI->bHorizontal)
{
INT ixTicks = RECTWIDTH(g_pGRI->rRuler) / INCREMENT;
for (INT ix = 0; ix < ixTicks + 1; ix++)
{
MoveToEx(g_pGRI->hdRuler, INCREMENT * ix, 0, NULL);
if (ix % INCREMENT == 0)
{
//This is major tick.
LineTo(g_pGRI->hdRuler, INCREMENT * ix, g_pGRI->lMajor);
wsprintfW(wText, L"%d", INCREMENT * ix);
TextOutW(g_pGRI->hdRuler, INCREMENT * ix + 1, g_pGRI->lMajor + 1, wText, CHARACTERCOUNT(wText));
}
else
{
//This is minor tick.
LineTo(g_pGRI->hdRuler, INCREMENT * ix, g_pGRI->lMinor);
}
}
}
else
{
INT iyTicks = RECTHEIGHT(g_pGRI->rRuler) / INCREMENT;
for (INT iy = 0; iy < iyTicks + 1; iy++)
{
MoveToEx(g_pGRI->hdRuler, 0, INCREMENT * iy, NULL);
if (iy % INCREMENT == 0)
{
//This is major tick.
LineTo(g_pGRI->hdRuler, g_pGRI->lMajor, INCREMENT * iy);
wsprintfW(wText, L"%d", INCREMENT * iy);
TextOutW(g_pGRI->hdRuler, g_pGRI->lMajor + 1, INCREMENT * iy + 1, wText, CHARACTERCOUNT(wText));
}
else
{
//This is minor tick.
LineTo(g_pGRI->hdRuler, g_pGRI->lMinor, INCREMENT * iy);
}
}
}
}
Background
There are several different schemes for rasterizing text in a legible way when the text is small relative to the size of a pixel. For example, if the stroke width is supposed to be 1.25 pixels wide, you either have to round it off to a whole number of pixels, use antialiasing, or use subpixel rendering (like ClearType). Rounding is usually controlled by "hints" built into the font by the font designer.
Hinting is the main reason why text width doesn't always scale exactly with the text height. For example, if, because of rounding, the left hump of a lowercase m is a pixel wider than the right one, a hint might tell the renderer to round the width up to make the letter symmetric. The result is that the character is a tad wider relative to its height than the ideal character.
This issue
What's likely happening here is that when GDI renders the string horizontally, each subsequent character may start at a fractional position, which is simulated by antialiasing or subpixel (ClearType) rendering. But, when rendering vertically, it appears that each subsequent character's starting position is rounded up to the next whole pixel, which tends to make the vertical text a couple pixels "longer" than its horizontal counterpart. Effectively, the kerning is always rounded up to the next whole pixel.
It's likely that more effort was put into the common case of horizontal text rendering, making it easier to read (and possibly faster to render). The general case of rendering at any other angle may have been implemented in a simpler manner, working glyph-by-glyph instead of with the entire string.
Things to Try
If you want them to look that same, you'll probably have to make a small compromise in the visual quality of the horizontal labels. Here are a few things I can think of to try:
Render the labels with regular antialiasing instead of ClearType subpixel rendering. (You can do this by setting the lfQuality field in the LOGFONT.) You would then draw the horizontal labels in the normal manner. For the vertical labels, draw them to an offscreen buffer horizontally, rotate it, and then blit the buffer to the screen. This gives you labels that look identical. The reason I suggest regular antialiasing is that it's invariant to the rotation. ClearType rendering had an inherent orientation and thus cannot be rotated without creating fringing. I've used this approach for graph labels with good results.
Render the horizontal labels character by character, rounding the starting point up to the next whole pixel. This should make the horizontal labels look like the vertical ones. Typographically, they won't look as good, but for small labels like this, it's probably less distracting than having the horizontal and vertical labels visually mismatched.
Another answer suggested rendering the horizontal labels with a very small, but non-zero, escapement and orientation, forcing those to go through the same rendering pipeline as the vertical labels. This may be the easiest solution for short labels like yours. If you had to handle longer strings of text, I'd suggest one of the first two methods.
When using lfEscapement, you will often get strange behaviour as it renders text using a fairly different pipeline.
A trick would be to have lfEscapement set for both. One with 900, and one with a very low value (such as 1 or even 10. Once you have both rendering with escapement, you should be good.
If you're still having issues with smoothing, try doing something like this:
BOOL bSmooth;
//Get previous smooth value.
SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &bSmooth, 0);
//Set no smoothing.
SystemParametersInfo(SPI_SETFONTSMOOTHING, 0, NULL, 0);
//Draw text.
//Return smoothing.
SystemParametersInfo(SPI_SETFONTSMOOTHING, bSmooth, NULL, 0);
Related
The code is supposed to fade and copy the window's image to a buffer f, then draw f back onto the window but translated, rotated, and scaled. I am trying to create an effect like a feedback loop when you point a camera plugged into a TV at the TV.
I have tried everything I can think of, logged every variable I could think of, and still it just seems like image(f,0,0) is doing something wrong or unexpected.
What am I missing?
Pic of double image mirror about x-axis:
PGraphics f;
int rect_size;
int midX;
int midY;
void setup(){
size(1000, 1000, P2D);
f = createGraphics(width, height, P2D);
midX = width/2;
midY = height/2;
rect_size = 300;
imageMode(CENTER);
rectMode(CENTER);
smooth();
background(0,0,0);
fill(0,0);
stroke(255,255);
}
void draw(){
fade_and_copy_pixels(f); //fades window pixels and then copies pixels to f
background(0,0,0);//without this the corners dont get repainted.
//transform display window (instead of f)
pushMatrix();
float scaling = 0.90; // x>1 makes image bigger
float rot = 5; //angle in degrees
translate(midX,midY); //makes it so rotations are always around the center
rotate(radians(rot));
scale(scaling);
imageMode(CENTER);
image(f,0,0); //weird double image must have something not working around here
popMatrix();//returns window matrix to normal
int x = mouseX;
int y = mouseY;
rectMode(CENTER);
rect(x,y,rect_size,rect_size);
}
//fades window pixels and then copies pixels to f
void fade_and_copy_pixels(PGraphics f){
loadPixels(); //load windows pixels. dont need because I am only reading pixels?
f.loadPixels(); //loads feedback loops pixels
// Loop through every pixel in window
//it is faster to grab data from pixels[] array, so dont use get and set, use this
for (int i = 0; i < pixels.length; i++) {
//////////////FADE PIXELS in window and COPY to f:///////////////
color p = pixels[i];
//get color values, mask then shift
int r = (p & 0x00FF0000) >> 16;
int g = (p & 0x0000FF00) >> 8;
int b = p & 0x000000FF; //no need for shifting
// reduce value for each color proportional
// between fade_amount between 0-1 for 0 being totallty transparent, and 1 totally none
// min is 0.0039 (when using floor function and 255 as molorModes for colors)
float fade_percent= 0.005; //0.05 = 5%
int r_new = floor(float(r) - (float(r) * fade_percent));
int g_new = floor(float(g) - (float(g) * fade_percent));
int b_new = floor(float(b) - (float(b) * fade_percent));
//maybe later rewrite in a way to save what the difference is and round it differently, like maybe faster at first and slow later,
//round doesn't work because it never first subtracts one to get the ball rolling
//floor has a minimum of always subtracting 1 from each value each time. cant just subtract 1 ever n loops
//keep a list of all the pixel as floats? too much memory?
//ill stick with floor for now
// the lowest percent that will make a difference with floor is 0.0039?... because thats slightly more than 1/255
//shift back and or together
p = 0xFF000000 | (r_new << 16) | (g_new << 8) | b_new; // or-ing all the new hex together back into AARRGGBB
f.pixels[i] = p;
////////pixels now copied
}
f.updatePixels();
}
This is a weird one. But let's start with a simpler MCVE that isolates the problem:
PGraphics f;
void setup() {
size(500, 500, P2D);
f = createGraphics(width, height, P2D);
}
void draw() {
background(0);
rect(mouseX, mouseY, 100, 100);
copyPixels(f);
image(f, 0, 0);
}
void copyPixels(PGraphics f) {
loadPixels();
f.loadPixels();
for (int i = 0; i < pixels.length; i++) {
color p = pixels[i];
f.pixels[i] = p;
}
f.updatePixels();
}
This code exhibits the same problem as your code, without any of the extra logic. I would expect this code to show a rectangle wherever the mouse is, but instead it shows a rectangle at a position reflected over the X axis. If the mouse is on the top of the window, the rectangle is at the bottom of the window, and vice-versa.
I think this is caused by the P2D renderer being OpenGL, which has an inversed Y axis (0 is at the bottom instead of the top). So it seems like when you copy the pixels over, it's going from screen space to OpenGL space... or something. That definitely seems buggy though.
For now, there are two things that seem to fix the problem. First, you could just use the default renderer instead of P2D. That seems to fix the problem.
Or you could get rid of the for loop inside the copyPixels() function and just do f.pixels = pixels; for now. That also seems to fix the problem, but again it feels pretty buggy.
If somebody else (paging George) doesn't come along with a better explanation by tomorrow, I'd file a bug on Processing's GitHub. (I can do that for you if you want.)
Edit: I've filed an issue here, so hopefully we'll hear back from a developer in the next few days.
Edit Two: Looks like a fix has been implemented and should be available in the next release of Processing. If you need it now, you can always build Processing from source.
An easier one, and works like a charm:
add f.beginDraw(); before and f.endDraw(); after using f:
loadPixels(); //load windows pixels. dont need because I am only reading pixels?
f.loadPixels(); //loads feedback loops pixels
// Loop through every pixel in window
//it is faster to grab data from pixels[] array, so dont use get and set, use this
f.beginDraw();
and
f.updatePixels();
f.endDraw();
Processing must know when it's drawing in a buffer and when not.
In this image you can see that works
I'm calculating the number of lines in a rich edit control.
Currently I'm using next code
TEXTMETRIC tm; {
HDC hdc = GetDC(hwndRichEdit);
GetTextMetrics(hdc, &tm);
ReleaseDC(hwndRichEdit, hdc);
}
RECT editRect;
GetClientRect(hwndRichEdit, &editRect);
long int countLines = (editRect.bottom - editRect.top) / (tm.tmHeight + tm.tmExternalLeading);
The code yields out the right number of lines until I start to change the size of the text via mouse wheel + ctr.
Is it possible to get the right text height even if the text is resized with mouse wheel?
N.B. I'm recalculating the number of lines with EN_UPDATE notification.
You can send an EM_GETZOOM message to the control to retrieve the current zoom ratio. Dividing the countLines value by the zoom ratio should yield the correct line count. Use the MulDiv API call to implement the division.
I am trying to store the motion detected from optical flow for frames in a video sequence and then use these stored motion vectors in order to predict the already known frames using just the first frame as a reference. I am currently using two processing sketches - the first sketch draws a motion vector for every pixel grid (each of width and height 10 pixels). This is done for every frame in the video sequence. The vector is only drawn in a grid if there is sufficient motion detected. The second sketch aims to reconstruct the video frames crudely from just the initial frame of the video sequence combined with information about the motion vectors got from the first sketch.
My approach so far is as follows: I am able to determine the size, position and direction of each motion vector drawn in the first sketch from four variables. By creating four arrays (two for the motion vector's x and y coordinate and another two for its length in the x and y direction), every time a motion vector is drawn I can append each of the four variables to the arrays mentioned above. This is done for each pixel grid throughout an entire frame where the vector is drawn and for each frame in the sequence - via for loops. Once the arrays are full, I can then save them to a text file as a list of strings. I then load these strings from the text file into the second sketch, along with the first frame of the video sequence. I load the strings into variables within a while loop in the draw function and convert them back into floats. I increment a variable by one each time the draw function is called - this moves on to the next frame (I used a specific number as a separator in my text-files which appears at the end of every frame - the loop searches for this number and then increments the variable by one, thus breaking the while loop and the draw function is called again for the subsequent frame). For each frame, I can draw 10 by 10 pixel boxes and move then by the parameters got from the text files in the first sketch. My problem is simply this: How do I draw the motion of a particular frame without letting what I've have blitted to the screen in the previous frame affect what will be drawn for the next frame. My only way of getting my 10 by 10 pixel box is by using the get() function which gets pixels that are already drawn to the screen.
Apologies for the length and complexity of my question. Any tips would be very much appreciated! I will add the code for the second sketch. I can also add the first sketch if required, but it's rather long and a lot of it is not my own. Here is the second sketch:
import processing.video.*;
Movie video;
PImage [] naturalMovie = new PImage [0];
String xlengths [];
String ylengths [];
String xpositions [];
String ypositions [];
int a = 0;
int c = 0;
int d = 0;
int p;
int gs = 10;
void setup(){
size(640, 480, JAVA2D);
xlengths = loadStrings("xlengths.txt");
ylengths = loadStrings("ylengths.txt");
xpositions = loadStrings("xpositions.txt");
ypositions = loadStrings("ypositions.txt");
video = new Movie(this, "sample1.mov");
video.play();
rectMode(CENTER);
}
void movieEvent(Movie m) {
m.read();
PImage f = createImage(m.width, m.height, ARGB);
f.set(0, 0, m);
f.resize(width, height);
naturalMovie = (PImage []) append(naturalMovie, f);
println("naturalMovie length: " + naturalMovie.length);
p = naturalMovie.length - 1;
}
void draw() {
if(naturalMovie.length >= p && p > 0){
if (c == 0){
image(naturalMovie[0], 0, 0);
}
d = c;
while (c == d && c < xlengths.length){
float u, v, x0, y0;
u = float(xlengths[a]);
v = float(ylengths[a]);
x0 = float(xpositions[a]);
y0 = float(ypositions[a]);
if (u != 1.0E-19){
//stroke(255,255,255);
//line(x0,y0,x0+u,y0+v);
PImage box;
box = get(int(x0-gs/2), int(y0 - gs/2), gs, gs);
image(box, x0-gs/2 +u, y0 - gs/2 +v, gs, gs);
if (a < xlengths.length - 1){
a += 1;
}
}
else if (u == 1.0E-19){
if (a < xlengths.length - 1){
c += 1;
a += 1;
}
}
}
}
}
Word to the wise: most people aren't going to read that wall of text. Try to "dumb down" your posts so they get to the details right away, without any extra information. You'll also be better off if you post an MCVE instead of only giving us half your code. Note that this does not mean posting your entire project. Instead, start over with a blank sketch and only create the most basic code required to show the problem. Don't include any of your movie logic, and hardcode as much as possible. We should be able to copy and paste your code onto our own machines to run it and see the problem.
All of that being said, I think I understand what you're asking.
How do I draw the motion of a particular frame without letting what I've have blitted to the screen in the previous frame affect what will be drawn for the next frame. My only way of getting my 10 by 10 pixel box is by using the get() function which gets pixels that are already drawn to the screen.
Separate your program into a view and a model. Right now you're using the screen (the view) to store all of your information, which is going to cause you headaches. Instead, store the state of your program into a set of variables (the model). For you, this might just be a bunch of PVector instances.
Let's say I have an ArrayList<PVector> that holds the current position of all of my vectors:
ArrayList<PVector> currentPositions = new ArrayList<PVector>();
void setup() {
size(500, 500);
for (int i = 0; i < 100; i++) {
currentPositions.add(new PVector(random(width), random(height)));
}
}
void draw(){
background(0);
for(PVector vector : currentPositions){
ellipse(vector.x, vector.y, 10, 10);
}
}
Notice that I'm just hardcoding their positions to be random. This is what your MCVE should do as well. And then in the draw() function, I'm simply drawing each vector. This is like drawing a single frame for you.
Now that we have that, we can create a nextFrame() function that moves the vectors based on the ArrayList (our model) and not what's drawn on the screen!
void nextFrame(){
for(PVector vector : currentPositions){
vector.x += random(-2, 2);
vector.y += random(-2, 2);
}
}
Again, I'm just hardcoding a random movement, but you would be reading these from your file. Then we just call the nextFrame() function as the last line in the draw() function:
If you're still having trouble, I highly recommend posting an MCVE similar to mine and posting a new question. Good luck.
I'm trying to flip some animations in LibGDX, but because they are of different width, the animation plays weird. Here's the problem:
(the red dot marks the X/Y coordinate {0,0})
As you can see, when the animation plays "left" when you punch, the feet starts way behind than were it was, but when you punch right, the animations plays fine because the origin of both animations is the left corner, so the transition is smooth.
The only way I think of achieving what I want is to see what animation is playing and adjust the coordinates accordingly.
This is the code:
public static float draw(Batch batch, Animation animation, float animationState,
float delta,
int posX, int posY, boolean flip) {
animationState += delta;
TextureRegion r = animation.getKeyFrame(animationState, true);
float width = r.getRegionWidth() * SCALE;
float height = r.getRegionHeight() * SCALE;
if (flip) {
batch.draw(r, posX + width, posY, -width, height);
} else {
batch.draw(r, posX, posY, width, height);
}
return animationState;
}
Any suggestion is welcome as how to approach this.
Use some other batch.draw option (with other parameters). You can set "origin" parameters. It's like a hot spot...center of the image... So if you i.e. rotate, rotation will be done around that hot spot.
https://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/graphics/g2d/Batch.html
I didn't use it for flipping, but it should work the same way. But if it doesn't then you have to adjust coordinates on your own, make some list with X offset for every frame and add it for flipped images.
Other solution would be to have wider frame images and keep center of the character always match the center of the image. That way your images will be wider then they have to - you'll have some empty space, but for sane number of frame it's acceptable.
This is for the programing language Processing (2.0).
Say I wish to load a not square image (lets use a green circle for the example). If I load this on a black background you can visibly see the white square of the image(aka all parts of image that aren't the green circle). How would I go about efficiently removing them?
It can not think of an efficient way to do it, I will be doing it to hundreds of pictures about 25 times a second(since they will be moving).
Any help would be greatly appreciated, the more efficient the code the better.
As #user3342987 said, you can loop through the image's pixels to see if each pixel is white or not. However, it's worth noting that 255 is white (not 0, which is black). You also shouldn't hardcode the replacement color, as they suggested -- what if the image is moving over a striped background? The best approach is to change all the white pixels into transparent pixels using the image's alpha channel. Also, since you mentioned you would be doing it "about 25 times a second", you shouldn't be doing these checks more than once-- it will be the same every time and would be wasteful. Instead, do it when the images are first loaded, something like this (untested):
PImage[] images;
void setup(){
size(400,400);
images = new PImage[10];
for(int i = 0; i < images.length; i++){
// example filenames
PImage img = loadImage("img" + i + ".jpg");
img.beginDraw();
img.loadPixels();
for(int p = 0; p < img.pixels.length; p++){
//color(255,255,255) is white
if(img.pixels[p] == color(255,255,255)){
img.pixels[p] = color(0,0); // set it to transparent (first number is meaningless)
}
}
img.updatePixels();
img.endDraw();
images[i] = img;
}
}
void draw(){
//draw the images as normal, the white pixels are now transparent
}
So, this will lead to no lag during draw() because you edited out the white pixels in setup(). Whatever you're drawing the images on top of will show through.
It's also worth mentioning that some image filetypes have an alpha channel built in (e.g., the PNG format), so you could also change the white pixels to transparent in some image editor and use those edited files for your sketch. Then your sketch wouldn't have to edit them every time it starts up.
Pixels are stored in the Pixels[] array, you can use a for loop to check to see if the value is 0 (aka white). If it is white load it as the black background.