How do I resize a drawing in a processing applet? - resize

I imported the processing language into Java and I drew a simple house.
Like:
rect (75, 175, 350, 175);
// door
rect (225, 275, 50, 75);
// roof
triangle (250, 100, 75, 175, 425, 175);
// windows
rect (125, 200, 50, 50);
rect (325, 200, 50, 50);
I want to be able to resize the image, or scale that image when I change the window size. Right now the window size is just 500 by 500, but if I expand the window it doesn't expand the drawing with it.
I tried using scale(), but for some reason it scaled the image for like a millisecond and then reverted back to the unscaled version. My java teacher told me the draw method in processing refreshes at something like 60 times per second, but I don't see why it would be different from the first time.

If you want your drawing to scale with the window, you're going to need to base all your coordinates off the width and height variables.
For example, let's say I'm drawing a 200x200 circle inside a 200x200 window:
size(200, 200);
ellipse(100, 100, 200, 200);
If I then change the size of the window to 400x400, then I have to change the parameters I'm passing into the ellipse() function:
size(400, 400);
ellipse(200, 200, 400, 400);
This can be annoying (as you're experiencing), so it's better to just base your parameters off the width and height variables. That way whenever your window size changes, Processing does the calculation for you and the drawing scaled with your window.
size(600, 600);
ellipse(width/2, height/2, width, height);
This is just an example, but the process for you would be the same: go through and change every value to be based off the width and height variables instead of hard-coded numbers.
More info can be found here: Using Variables - HappyCoding.io
(full disclosure: I wrote that tutorial, but I think it explains exactly what you're asking about)
Edit: You asked about the scale() method, so I'll explain that below. But if you're trying to base the size of your drawing off the size of your window, then you should use the above approach! But since this is a homework assignment, you're restricted to doing it the way the teacher says. Anyway...
Let's look at a simple program:
size(100, 100);
ellipse(50, 50, 10, 10);
This code simply creates a 100x100 sized window and then draws a small ellipse in the center:
If we wanted to make the circle bigger, we could use the scale() function. You can think of the scale() function as automatically multiplying every parameter you pass into a drawing function (like ellipse() or rect()) by whatever number(s) you pass into the scale() function.
For example, this code multiplies every number by 2:
size(100, 100);
scale(2);
ellipse(50, 50, 10, 10);
The circle is now twice as large, but it's also no longer in the center. That's because we're also multiplying 50,50 (the center of the window) by 2 to get 100,100 (the bottom-right corner of the window). To fix that, we either need to change the 50,50:
size(100, 100);
scale(2);
ellipse(25, 25, 10, 10);
Or we could use the translate() function to move the coordinates before we do the scale:
size(100, 100);
translate(50, 50);
scale(2);
ellipse(0, 0, 10, 10);
Either approach is fine, so it's really up to which one makes more sense to you. Now we have a big centered circle, even though we're still sizing it to 10,10.

Related

How to pixel perfect align text-element

I want my vue Konva Text element to completely fill the given height, like i expect of a rectangle.
This is issue becomes obvious when pairing with text images, (converting svg text to canvas) that properly match the given dimension
<v-text :config={
x: 50,
y: 50,
width: 1000,
height: 60,
fontSize: 60,
fontStyle: 'bold',
fontFamily 'Campton Book'
text: 'WELT'
}
/>
<v-rect
:config="{ x: 50, y: 50, fill: 'black', height: 60, width: 200 }"
/>
Second Part, is there any way to always pixel perfectly align the left side with the border? the x coordinate matches the border
Is this due to font constraints? What am I missing?
I tried to get the height of the text node to fix this positioning but this is the given height passed down as props
Text is defined as having parts above and below the baseline. Above is termed 'ascenders' amd below is 'descenders', which are required for lower case letters like j y g.
Setting the text fontSize to 60 does not say 'whatever the string, make it fill a space 60px high'. Instead it says 'Make text in a 60px font', which makes space for the descenders because they will generally be required.
If you know for sure that the text will be all caps, then a solution is to measure the height used and increase the font size by a computed factor so that the font fills the line height.
To do this you'll need to get the glyph measurements as follows:
const lineHeight = 60; // following your code
// make your text shape here...left out for brevity
const metrics = ctx.measureText('YOUR CAPS TEXT');
capsHeight = Math.abs(metrics.actualBoundingBoxAscent)
fontSize = lineHeight * lineHeight / capsHeight;
If I got that right, your 60px case should give a value around 75. That's based on the convention that ascenders are 80% of the line height. Now you set the font size of your shape to this new value and you should be filling the entire line height.
Regarding the left-alignment, this relies on what the font gurus call the a-b-c widths. The left gap is the a-space, the b is the character width (where the ink falls) and the c-space is the same as the a-space but on the right hand side.
Sadly unless someone else can tell me I am wrong, you don't get a-b-c widths in the canvas TextMetric. There is a workaround which is rather convoluted but viable. You would draw the text in black on an off-screen canvas filled with a transparent background. Then get the canvas pixel data and walk horizontal lines from the left of the canvas inspecting pixels and looking for the first colored pixel. Once you find it you have the measurement to offset the text shape horizontally.

iOS Core Graphics how to optimize incremental drawing of very large image?

I have an app written with RXSwift which processes 500+ days of HealthKit data to draw a chart for the user.
The chart image is drawn incrementally using the code below. Starting with a black screen, previous image is drawn in the graphics context, then a new segment is drawn over this image with certain offset. The combined image is saved and the process repeats around 70+ times. Each time the image is saved, so the user sees the update. The result is a single chart image which the user can export from the app.
Even with autorelease pool, I see spikes of memory usage up to 1Gb, which prevents me from doing other resource intensive processing.
How can I optimize incremental drawing of very large (1440 × 5000 pixels) image?
When image is displayed or saved at 3x scale, it is actually 4320 × 15360.
Is there a better way than trying to draw over an image?
autoreleasepool {
//activeEnergyCanvas is custom data processing class
let newActiveEnergySegment = activeEnergyCanvas.draw(in: CGRect(x: 0, y: 0, width: 1440, height: days * 10), with: energyPalette)
let size = CGSize(width: 1440, height: height)
UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
//draw existing image
self.activeEnergyImage.draw(in: CGRect(origin: CGPoint(x: 0, y: 0),
size: size))
//calculate where to draw smaller image over larger one
let offsetRect = CGRect(origin: CGPoint(x: 0, y: offset * 10),
size: newActiveEnergySegment.size)
newActiveEnergySegment.draw(in: offsetRect)
//get the combined image
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
//assign combined image to be displayed
if let unwrappedImage = newImage {
self.activeEnergyImage = unwrappedImage
}
}
Turns out my mistake was in passing invalid drawing scale (0.0) when creating graphics context, which defaulted to drawing at the device's native screen scale.
In case of iPhone 8 it was 3.0 The result is needing extreme amounts of memory to draw, zoom and export these images. Even if all debug logging prints that image is 1440 pixels wide, the actual canvas ends up being 1440 * 3.0 = 4320.
Passing 1.0 as the drawing scale makes the image more fuzzy, but reduces memory usage to less than 200mb.
// UIGraphicsBeginImageContext() <- also uses #3x scale, even when all display size printouts show
let drawingScale: CGFloat = 1.0
UIGraphicsBeginImageContextWithOptions(size, true, drawingScale)

Is an AlphaMaskFilter correct in this case?

I am trying to use an alppha mask filter to apply a texture to a canvas element but cannot seem to get things to work. I have a base image which is a flat white color and to which I want to apply a color filter at runtime based on a users selection for example:
bitmap = new createjs.Bitmap(image);
bitmap.filters = [
new createjs.ColorFilter(0,0, 0.5, 1, 0, 0, 120, 0)
];
bitmap.cache(0, 0, 500, 500, 2);
I then want to use a second image which is a texture png that will add various shading texture to that first one. Looking over the docs it would seem that I need to use an AlphaMaskFilter but that does not seem to work and nothing is rendered onto the canvas. For example:
//filterImage contains the transparent image which has a shaded texture
var bitmap2 = new createjs.Bitmap(filterImage);
bitmap2.cache(0, 0, 500, 500, 2);
var bitmap = new createjs.Bitmap(image);
bitmap.filters = [
new createjs.ColorFilter(0,0, 0.5, 1, 0, 0, 120, 0),
new createjs.AlphaMaskFilter(bitmap2.cacheCanvas)
];
bitmap.cache(0, 0, 500, 500, 2);
Can someone help point me in the right direction here or if I am trying to do something which is just not possible using that filter.

How do I get the frame of visible content from SKCropNode?

It appears that, in SpriteKit, when I use a mask in a SKCropNode to hide some content, it fails to change the frame calculated by calculateAccumulatedFrame. I'm wondering if there's any way to calculate the visible frame.
A quick example:
import SpriteKit
let par = SKCropNode()
let bigShape = SKShapeNode(rect: CGRect(x: 0, y: 0, width: 100, height: 100))
bigShape.fillColor = UIColor.redColor()
bigShape.strokeColor = UIColor.clearColor()
par.addChild(bigShape)
let smallShape = SKShapeNode(rect: CGRect(x: 0, y: 0, width: 20, height: 20))
smallShape.fillColor = UIColor.greenColor()
smallShape.strokeColor = UIColor.clearColor()
par.maskNode = smallShape
par.calculateAccumulatedFrame() // returns (x=0, y=0, width=100, height=100)
I expected par.calculateAccumulatedFrame() to return (x=0, y=0, width=20, height=20) based on the crop node mask.
I thought maybe I could code the function myself as an extension that basically reimplements calculateAccumulatedFrame with support for checking for SKCropNodes and their masks, but it occurred to me that I would need to consider the alpha of that mask to determine if there's actual content that grows the frame. Sounds difficult.
Is there an easy way to calculate this?

OpenTK OpenGL Drawing text

I am trying to learn how to do OpenGL using OpenTK and I can successfully draw polygons, circles, and triangles so far but my next question is how to draw text? I have looked at the example on their homepage which was in C# and I translated it to VB .NET.
It currently just draws a white rectangle so I was hoping that someone could spot an error in my code or suggest another way to draw text. I will just list my paint event.
Paint event:
GL.Clear(ClearBufferMask.ColorBufferBit)
GL.Clear(ClearBufferMask.DepthBufferBit)
Dim text_bmp As Bitmap
Dim text_texture As Integer
text_bmp = New Bitmap(ClientSize.Width, ClientSize.Height)
text_texture = GL.GenTexture()
GL.BindTexture(TextureTarget.Texture2D, text_texture)
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, All.Linear)
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, All.Linear)
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, text_bmp.Width, text_bmp.Height, 0 _
, PixelFormat.Bgra, PixelType.UnsignedByte, IntPtr.Zero)
Dim gfx As Graphics
gfx = Graphics.FromImage(text_bmp)
gfx.DrawString("TEST", Me.Font, Brushes.Red, 0, 0)
Dim data As Imaging.BitmapData
data = text_bmp.LockBits(New Rectangle(0, 0, text_bmp.Width, text_bmp.Height), Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb)
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, Width, Height, 0, PixelFormat.Bgra, PixelType.UnsignedByte, data.Scan0)
text_bmp.UnlockBits(data)
GL.MatrixMode(MatrixMode.Projection)
GL.LoadIdentity()
GL.Ortho(0, width, Height, 0, -1, 1)
GL.Enable(EnableCap.Texture2D)
GL.Enable(EnableCap.Blend)
GL.BlendFunc(BlendingFactorSrc.One, BlendingFactorDest.OneMinusSrcAlpha)
GL.Begin(BeginMode.Quads)
GL.TexCoord2(0.0F, 1.0F)
GL.Vertex2(0.0F, 0.0F)
GL.TexCoord2(1.0F, 1.0F)
GL.Vertex2(1.0F, 0.0F)
GL.TexCoord2(1.0F, 0.0F)
GL.Vertex2(1.0F, 1.0F)
GL.TexCoord2(0.0F, 0.0F)
GL.Vertex2(0.0F, 1.0F)
GL.End()
GlControl1.SwapBuffers()
You'll get a white rectangle if your card doesn't support NPOT (non-power-of-two) texture sizes. Try testing by setting the bitmap size to e.g. 256x256.
That is an ok method. If you plan to draw lots of text or even a medium amount, that will absolutely destroy performance. What you want to do is look into a program called BMFont:
www.angelcode.com/products/bmfont/‎
What this does is create a texture atlas of text, along with an xml file with the positions, width and height and offsets of every letter. You start off by reading that xml file, and loading each character into a class, with the various values. Then you simply make a function that you pass a string which binds the atlas, than depending on the letters in the string, draws a quad with texture coordinates that vary on the xml data. So you might make a:
for each _char in string
create quad according to xml size
assign texture coordinates relative to xml position
increase position so letters don't draw on top of each other
There are tutorials in other languages on the BMFont website which can be helpful.