I'm running this code in the emulator set to iPhone (Retina 4-inch)
-(void)drawRect:(CGRect)rect {
[[UIColor whiteColor]set];
UIRectFill(self.bounds);
UIBezierPath *vertLine = [UIBezierPath bezierPath];
[vertLine moveToPoint:CGPointMake(20.5, 10.0)];
[vertLine addLineToPoint:CGPointMake(20.5, 20.0)];
vertLine.lineWidth = 1.0;
[[UIColor blackColor]set];
[vertLine stroke];
}
I expect to have a one pixel vertical line, but the line the two pixel wide, and solid black.
The solid black color seems to suggest that this is not due to a problem with the alignment of the line on the pixel grid (it would be 50% gray in this case)
What's happening here ?
For UIKit you don't specify pixels but points. Points are then mapped automatically to pixels. Your 1-point-width-line seems to be mapped to two retina-pixels.
See "Points versus Pixels" in http://developer.apple.com/library/ios/#documentation/2DDrawing/Conceptual/DrawingPrintingiOS/GraphicsDrawingOverview/GraphicsDrawingOverview.html
Related
I am creating the "perfect" sprite packer. This is a sprite packer that makes sure the output sprite is compatible with most if not all game engines and animation software. It is a program that merges images into a horizontal sprite sheet.
It converts (if needed) the source frames to BMP in memory
It considers the top-left pixel fully transparent for the entire image (can be configured)
It parses the frames each individually to find the real coordinates rect (where the actual frame starts, ends, its width and height (sometimes images may have a lot of extra transparent pixels).
It determines the frame box, which have the width and height of the frame with the largest width/height so that it is long enough to contain every frame. (For extra compatibility, every frame must have the same dimensions).
Creates output sprite with width of nFrames * wFrameBox
The problem is - anchor alignment. Currently, it tries to align each frame so that its center is on the frame box center.
if((wBox / 2) > (frame->realCoordinates.w / 2))
{
xpos = xBoxOffset + ((wBox / 2) - (frame->realCoordinates.w / 2));
}
else
{
xpos = xBoxOffset + ((frame->realCoordinates.w / 2) - (wBox / 2));
}
When animated, it looks better with it, but there is still this inconsistent horizontal frame position so that a walking animation looks like walking and shaking.
I also tried the following:
store the real x pixel position of the widest frame and use it as a reference point:
xpos = xBoxOffset + (frame->realCoordinates.x - xRef);
It also gives a little better results, showing that this is still not the correct algorithm.
Honestly, I don't know what am I doing.
What will be the correct way to align sprite frames (obtain the appropriate x position for drawing the next frame) given that the output sprite sheet have width of the number of frames multiplied by the width of the widest frame?
Your problem is that you first calculate the center then calculate the size of the required bounding box. That is why your image 'shakes' because in each image that center is different to the original center.
You should use the center of the original bounding box as your origin, then find out the size of each sprite, keeping track of the leftmost, rightmost, topmost and bottommost non transparent pixels. That would give you the bounding box you need to use to avoid the shaking.
The problem is that you will find that most sprites are already done that way, so the original bounding box is actually defined as to the minimum space to paint the whole sprite's sequence covering these non transparent pixels.
The only way to remove unused sprite space is to store the first sprite complete, and then the origin and dimensions of each other sprite, like is done in animated GIF and APNG ( Animated PNG -> https://en.wikipedia.org/wiki/APNG )
How does image resize[Adding and Reducing size of image] works and what happens to the pixels and RGB ?
explain briefly
An RGB image has three channels: red, green, and blue. RGB channels roughly follow the color receptors in the human eye, and are used in computer displays and image scanners.
If the RGB image is 24-bit (the industry standard as of 2005), each channel has 8 bits, for red, green, and blue—in other words, the image is composed of three images (one for each channel), where each image can store discrete pixels with conventional brightness intensities between 0 and 255. If the RGB image is 48-bit (very high color-depth), each channel is made of 16-bit images.
Image interpolation occurs when you resize or distort your image from one pixel grid to another. Image resizing is necessary when you need to increase or decrease the total number of pixels, whereas remapping can occur when you are correcting for lens distortion or rotating an image. Zooming refers to increase the quantity of pixels, so that when you zoom an image, you will see more detail.
So the number of pixels will be reduced which means it will have a less rgb pixels.
I would like to have a gradient which goes from black to transparent (not white). How can I achieve this?
From my attempt below I assume the gradient style color's alpha value is not considered:
gui_Footer.allStyles.apply {
backgroundType = Style.BACKGROUND_GRADIENT_LINEAR_VERTICAL
border = RoundRectBorder.create().topOnlyMode(true).cornerRadius(1f)
backgroundGradientEndColor = ColorUtil.BLACK
backgroundGradientStartColor = ColorUtil.argb(0, 255, 255, 255)
}
Gradients in Codename One ignore the alpha byte. While we could technically add support for alpha gradients it's not something that's planned at this time. You can probably generate such an image by manipulating the RGB data but it would be more efficient to just generate an RGB image of a gradient and draw it scaled.
Notice that this is generally the most efficient approach since the GPU works by drawing textures very efficiently. If an image is a power of 2 (e.g. 256x128 pixels) it can fit perfectly in a texture and it's drawn very fast. Much faster than our builtin gradients.
I'm rendering the font Consolas using freetype2.
I rendered the glyphs using
FT_Load_Glyph(face, glyphIndex, FT_LOAD_DEFAULT);
FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
and converted the bitmap to an ARGB map using a simple loop:
uint32_t* content = ... // ARGB bitmap
for (int py = 0; py < bitmap->rows; py++) {
for (int px = 0; px < bitmap->width; px++) {
uint8_t intensity = bitmap->buffer[py * bitmap->pitch + px];
content[py * bitmap->width + px] = (intensity << 24);
}
}
The result is that my rendered text looks much bolder than when it's rendered from for example notepad:
What could be the reason for this issue?
I'm not a Freetype expert (at all), but if you look at your example bitmap with a magnifying glass you'll see that the Notpad rendering has light blue and pink shades around it. Your rendering is anti-aliased, but all grey.
So I assume that Notepad renders in LCD mode , which really renders three subpixels (corresponding to the RBG rays of the Cathode Ray Display) per pixel and then smears them with the neighbouring pixels.
That also means that vertical hinting takes place along these subpixels and that, for example, the width of the vertical stems in the Notepad rendering is four or five sub-pixels, whereas in your rendering is is alwys at full pixel borders, i.e. six subpixels. This makes your rendering look bold in comparison to Notepad's. (Perhaps you can find font sizes where the effect is reversed: Your rendering looks lighter than Notepad's.)
You could do your rendering also in LCD mode (FT_RENDER_MODE_LCD). You'd render to a bitmap three times as wide and when you copy the text bitmap to your ARGB bitmap, you should take the average value of three adjacent pixels. (This will not give you true LCD rendering, but a lighter greyscale rendering.)
I'm trying to do simple drawing in a subclass of a decorator, similar to what they're doing here...
How can I draw a border with squared corners in wpf?
...except with a single-pixel border thickness instead of the two they're using there. However, no matter what I do, WPF decides it needs to do its 'smoothing' (e.g. instead of rendering a single-pixel line, it renders a two-pixel line with each 'half' about 50% of the opacity.) In other words, it's trying to anti-alias the drawing. I do not want anti-aliased drawing. I want to say if I draw a line from 0,0 to 10,0 that I get a single-pixel-wide line that's exactly 10 pixels long without smoothing.
Now I know WPF does that, but I thought that's specifically why they introduced SnapsToDevicePixels and UseLayoutRounding, both of which I've set to 'True' in the XAML. I'm also making sure that the numbers I'm using are actual integers and not fractional numbers, but still I'm not getting the nice, crisp, one-pixel-wide lines I'm hoping for.
Help!!!
Mark
Aaaaah.... got it! WPF considers a line from 0,0 to 10,0 to literally be on that logical line, not the row of pixels as it is in GDI. To better explain, think of the coordinates in WPF being representative of the lines drawn on a piece of graph paper whereas the pixels are the squares those lines make up (assuming 96 DPI that is. You'd need to adjust accordingly if they are different.)
So... to get the drawing to refer to the pixel locations, we need to shift the drawing from the lines themselves to be the center of the pixels (squares on graph paper) so we shift all drawing by 0.5, 0.5 (again, assuming a DPI of 96)
So if it is a 96 DPI setting, simply adding this in the OnRender method worked like a charm...
drawingContext.PushTransform(new TranslateTransform(.5, .5));
Hope this helps others!
M
Have a look at this article: Draw lines exactly on physical device pixels
UPD
Some valuable quotes from the link:
The reason why the lines appear blurry, is that our points are center
points of the lines not edges. With a pen width of 1 the edges are
drawn excactly between two pixels.
A first approach is to round each point to an integer value (snap to a
logical pixel) an give it an offset of half the pen width. This
ensures, that the edges of the line align with logical pixels.
Fortunately the developers of the milcore (MIL stands for media
integration layer, that's WPFs rendering engine) give us a way to
guide the rendering engine to align a logical coordinate excatly on a
physical device pixels. To achieve this, we need to create a
GuidelineSet
protected override void OnRender(DrawingContext drawingContext)
{
Pen pen = new Pen(Brushes.Black, 1);
Rect rect = new Rect(20,20, 50, 60);
double halfPenWidth = pen.Thickness / 2;
// Create a guidelines set
GuidelineSet guidelines = new GuidelineSet();
guidelines.GuidelinesX.Add(rect.Left + halfPenWidth);
guidelines.GuidelinesX.Add(rect.Right + halfPenWidth);
guidelines.GuidelinesY.Add(rect.Top + halfPenWidth);
guidelines.GuidelinesY.Add(rect.Bottom + halfPenWidth);
drawingContext.PushGuidelineSet(guidelines);
drawingContext.DrawRectangle(null, pen, rect);
drawingContext.Pop();
}