I have a question concerning the current graphics state and the Graphics State Stack in PostScript.
In my code I now have a Stack which represents the current graphics state.
When I initialise my interpreter it creates a new GraphicsState object and adds it to the 'gsstack'.
My Current Graphics State is implemented as: 'gsstack'.Peek() which always returns the topmost graphics state.
with the gsave operator I create a clone of the current graphics state and push that on the 'gsstack', so I have a new topmost graphics state on the stack (and this means I have a new Current Graphics State object).
Now with the grestore I read this from http://www.tailrecursive.org/postscript/operators.html#grestore
"Sets the current graphics state to the topmost graphics state on graphics state stack and pops that state off the stack. "
How does that grestore work, because my current graphics state is already the topmost graphics state... should I just pop it off the stack?
Or is my implementation wrong?
When I initialise my interpreter should I create a new Current Graphics State object, but not add it to the 'gsstack' and only push it to the 'gsstack' when the gsave operator is called?
Thanks in advance
Yes, grestore simply pops the graphics stack.
Just like the dictionary stack should always have systemdict and userdict (at least) at the bottom, there should always be at least one graphics state on the graphics stack. So grestore should throw an error if it finds only one state on the stack (just like end should throw an error if it finds only the permanent dictionaries (systemdict and userdict for Level-1, adding statusdict and globaldict for Level-2)).
But you may want to implement the graphics stack differently from the other stacks, because it's also affected by save and restore. restore should pop all states more recent than the last save. If the graphics stack is implemented as a linked-list of arrays or dictionaries, then restore will do its part without any extra hassle.
from the PLRM, 3ed:
– grestore –
resets the current graphics state from the one on the top of the graphics state stack
and pops the graphics state stack, restoring the graphics state in effect at the time
of the matching gsave operation. This operator provides a simple way to undo
complicated transformations and other graphics state modifications without having
to reestablish all graphics state parameters individually.
If the topmost graphics state on the stack was saved with save rather than gsave
(that is, if there has been no gsave operation since the most recent unmatched
save), grestore restores that topmost graphics state without popping it from the
stack. If there is no unmatched save (which can happen only during an unencapsulated
job) and the graphics state stack is empty, grestore has no effect.
You may want to ignore save and restore at first, and just focus on gsave and grestore (and the rest of the graphics functionality). save and restore get very complicated. I've redesigned my interpreter several times to try to get them to work right.
Related
This is more of a general design question than a specific question about a piece of code. Let me do an outline:
Imagine a canvas with a poly line consisting of 3 or more points. Each of those points has a circle object as draggable handle. The user can move the drag handle, the action updates a react context containing only those 3 coordinates. The new context triggers a redraw of the canvas, updating the poly line and the drag handle with new coordinates, while performing things like “snap to axis” and “snap to closest other vector” checks while dragging occurs.
I only use functional components (React.FC) and state is shared where needed using hooks.
I use requestAnimationFrame() on the drag handler to debounce updates as close as possible to the maximum refresh rate of the client. The goal is to stay at 60fps.
Questions:
Does a re-render of a component attached to a stage in react-konva always trigger a redraw of everything on the actual canvas or does react-konva keep track?
Would it be advisable to use vanilla Konva instead of react-konva abstraction in this case, to avoid excessive redraw, while only using the react context to persist state once a drag action ended?
Is there a more efficient way to handle this use case I currently am not aware of?
When you re-render a component it will trigger an internal update inside react-konva.
react-konva will update props of Konva nodes. It is trying to work smart, so if you re-rendered a component, but no props changed - Konva nodes will be not updated (and no canvas draws).
Any change of props will trigger layer (or stage) redraw.
You can use vanilla Konva instead of react-konva if you want to have full control and if you want to skip some react reconciler work. But it may be hard on large components.
Also, it is better to avoid using React.Context for frequent updates. Updating the context may trigger a lot of re-renders of components. So it is better to use plain state (or even mobx) for faster updates.
I am working with some library. I need to edit some context. And I have a reference to that context.
I find out before I implement my code, in that library called CGContextClipToRect. I need to cancel that clipping. How can I do it?
You can't directly undo a clipping:
This function sets the specified graphics context’s clipping region to the area which intersects both the current clipping path and the specified rectangle.
You can only clip to smaller rectangles. Once some area has been removed, you can't get it back.
However, you can save and restore the entire graphics state which includes the clip region. Before clipping, you can call CGContextSaveGState() and later call CGContextRestoreGState(). This will reset many parameters (see the docs for the full list), but will leave the path (i.e. what has been drawn).
I am working with some stuff in Core Graphic's and I am looking for some additional clarification regarding a couple of topics.
drawRect:
I have an understanding of this and know it is where all of the drawing aspect's of a UIView goes, but am just unclear as to what is happening behind the scene's. What happen's when I create a UIView and fill out drawRect then set another object's UIView to be that custom view? When is drawRect being called?
CGGraphicsContext:
I know what the purpose of this is and understand the concept, but I can't see exactly how it is working.
For example:
CGContextSaveGState(context);
CGContextAddRect(context, rect);
CGContextClip(context);
CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0);
CGContextRestoreGState(context);
The code above is in my app and work's correctly. The thing that confuses me is how it is working. The idea of saving/restoring a context makes sense, but it appears like I am literally saving a context, using that exact same context to make change's, then restoring the same context once again. It just seem's like I am saving a context and then writing on top of that context, only to restore it. How is it getting saved to a point where when you restore it, it is a different instance of the context than what was just used to make changes? You use the same reference of the variable context in every situation.
Lastly I would appreciate any resource's for practice project's or example's on using Core Graphics. I am looking to improve my skill in the matter since I obviously don't have much at the current time.
What happen's when I create a UIView and fill out drawRect then set another object's UIView to be that custom view? When is drawRect being called?
Adding a view to a 'live' view graph marks the view's frame as in need of display. The main run loop then creates and coalesces invalid rects and soon returns to invoke drawing. It does not draw immediately upon invalidation. This is a good thing because resizing, for example, would result in significant overdrawing -- redundant work which would kill many apps' drawing performance. When drawing, a context is created to render to -- which ultimately outputs to its destination.
Graphics Contexts are abstractions which are free to work optimally for their destination -- a destination could be a device/screen, bitmap, PDF, etc.. However, a context handle (CGContextRef) itself refers to a destination and holds a set of parameters regarding its state (these parameters are all documented here). These parameter sets operate like stacks: Push = CGContextSaveGState, Pop = CGContextRestoreGState. Although the context pointer isn't changing, the stack of parameter sets is changing.
As far as resources, see Programming with Quartz. It's 8 years old now, and was originally written for OS X -- but that ultimately doesn't matter a whole lot because the fundamentals of the drawing system and APIs really haven't evolved significantly since then -- And that is what you intend to focus on. The APIs have been extended, so it would be good to review which APIs were introduced since 10.4 and see what problems they solve, but it's secretly a good thing for you because it helps maintain focus on the fundamental operation of the drawing system. Note that some functionalities were excluded from iOS (e.g. often due to floating point performance and memory constraints, I figure), so every example may not be usable on iOS, but I know of no better guide.
Tip: Your drawing code can be easily reused on OS X and iOS if you use Quartz rather than AppKit/UIKit. Plus, the Quartz APIs have a lower update frequency (i.e. the APIs tend to be longer lived).
-drawRect: gets called at some point after you (e.g. your view controller) have called the view's method -setNeedsDisplay or -setNeedsDisplayInRect:.
Saving the graphics state pushes the current graphics state onto a stack. The graphics state contains fill and stroke setting, the current transformation matrix etc. See Apple's documentation for details.
The Quartz 2D Programming Guide doesn't contain many examples but is otherwise quite thorough.
With quartz/ core graphics the context is literally a set of current parameters to use to draw the next drawing command on top of the previous drawing.
Saving the state let's you save all those parameters for later drawing commands that will reuse them.
Then you can set up a different set of parameters for some drawing commands.
Restoring the state gets you back to where you were.
I recommend the book
Programming with Quartz
2D and PDF Graphics in Mac OS X
Though a bit dated in some ways, it will really teach you how quartz / core graphics really flows.
Ok this is a very very deep topic to talk about. I'll explain a few things to my understanding & try to keep it simple. If I'm mistaken I hope someone can correct me out.
first of all there is concept of onscreen drawing and offscreen drawing. On screen drawing is taken place in GPU where offscreen drawing is taken place in CPU to draw things and then its given to GPU to display on the screen. Thats where drawRect() comes in to place (drawrect is only 1 way of doing the offscreen drawings btw). This is why in the drawRect template method (you will see when you make a subclass of UIView) there is a comment by Apple telling
"Only override drawRect: if you perform custom drawing. An empty implementation adversely affects performance during animation"
The reason is whenever there is drawRect method, the iOS would have to ask the CPU to takecare of the drawing which takes place in drawRect and hand it over to the GPU. (Dont get the idea that this is a bad thing :) ). So this is what happens in drawRect in an abstract level.
Now to the question of why save & restore same context over and over. Have you tried to read the description of the method in apple doc about save/restore context ? If you have, you'd notice that it shows all the graphical states which would be affected by this. Ok how does this help ?
Consider something like this. Lets say you're drawing on a rectangle where you have to limit this next part of the drawing on the right half of it and use shadows and antialiasing, etc. You can save your context before drawing the right side and set whatever properties you want and once you finish that, you can simply restore the context and you can continue with all the settings you had before without explicitly setting them again. It's a good practice as well when you do complex drawings as otherwise it would have weird outcomes you might not expect. something like this below
- drawRect()
{
CGContextSaveGState(context);
drawLeftPart(); // - 1
drawRightPart(); // - 2
someOtherDrawing(); // - 3
CGContextRestoreGState(context);
}
- drawLeftPart()
{
CGContextSaveGState(context);
// do your drawing
CGContextRestoreGState(context);
}
- drawRightPart()
{
CGContextSaveGState(context);
// do your drawing
CGContextRestoreGState(context);
}
- someOtherDrawing()
{
CGContextSaveGState(context);
// do your drawing
CGContextRestoreGState(context);
}
Now what ever properties you set in part 1 wont affect drawing of part 2 & 3 so forth.
Hope this helps,
I have been trying so much but have no solution find out yet. I have to implement the painting and erasing on iOS so I successfully implemented the painting logic using UIBezierPath. The problem is that for erasing, I implemented the same logic as for painting by using kCGBlendModeClear but the problem is that I cant redraw on the erased area and this is because in each pass in drawRect i have to stroke both the painting and erasing paths. So is there anyway that we can subtract erasing path from drawing path to get the resultant path and then stroke it. I am very new to Core Graphics and looking forward for your reply and comments. Or any other logic to implement the same. I can't use eraser as background color because my background is textured.
You don't need to stroke the path every time, in fact doing so is a huge performance hit. I guarantee if you try it on an iPad 3 you will be met with a nearly unresponsive screen after a few strokes. You only need to add and stroke the path once. After that, it will be stored as pixel data. So don't keep track of your strokes, just add them, stroke them, and get rid of them. Also look into using a CGLayer (you can draw to that outside the main loop, and only render it to your rect in the main loop so it saves lots of time).
These are the steps that I use, and I am doing the exact same thing (I use a CGPath instead of UIBezierPath, but the idea is the same):
1) In touches began, store the touch point and set the context to either erase or draw, depending on what the user has selected.
2) In touches moved, if the point is a certain arbitrary distance away from the last point, then move to the last point (CGContextMoveToPoint) and draw a line to the new point (CGContextAddLineToPoint) in my CGLayer. Calculate the rectangle that was changed (i.e. contains the two points) and call setNeedsDisplayInRect: with that rectangle.
3) In drawRect render the CGLayer into the current window context ( UIGraphicsGetCurrentContext() ).
On an iPad 3 (the one that everyone has the most trouble with due to its enormous pixel count) this process takes between 0.05 ms and 0.15ms per render (depending on how fast you swipe). There is one caveat though, if you don't take the proper precautions, the entire frame rectangle will be redrawn even if you only use setNeedsDisplayInRect: My hacky way to combat this (thanks to the dev forums) is described in my self answered question here, Otherwise, if your view takes a long time to draw the entire frame (mine took an unacceptable 150 ms) you will get a short stutter under certain conditions while the view buffer gets recreated.
EDIT With the new info from your comments, it seems that the answer to this question will benefit you -> Use a CoreGraphic Stroke as Alpha Mask in iPhone App
Hai here is the code for making painting, erasing, undo, redo, saving as picture. you can check sample code and implement this on your project.
Here
When I draw lines and shapes etc I get the " current graphics context" in iOS.
What exactly though is " current graphics context" - I'm looking for the 30,000 foot description.
Right now I just copy and paste UI code, not exactly sure what it's doing.
A graphics context is the place where information about the drawing state is stored. This includes fill color, stroke color, line width, line pattern, winding rule, mask, current path, transparency layers, transform, text transform, etc. When using CoreGraphics calls, you specify the context to use to every single function. This means you can use multiple contexts at once, though typically you only use one. At the UIKit layer, there is the concept of a "current" graphics context, which is a graphics context that's used by all UIKit-level drawing calls (such as -[UIColor set] or UIBezierPath drawing). The current context is stored in a stack of contexts, so you can create a new context for some drawing, then when you finish with it the previous context is restored. Typically you get a context for free inside of -[UIView drawRect:] inside of CALayer display-related methods, but not otherwise.
It used to be that the "current" context was an application-wide global state, and therefore was not safe to touch outside of the main thread. As of iOS 4.0 (I believe), this became a thread-local state and UIKit-level drawing methods became safe to use on background threads.
The OS needs a place to save information, such as drawing state, which you don't want to specify in every single CG drawing command, such as in which bitmap or view to draw, the scale or other transform to use, the last color you specified, etc.
The context tells each CG call where to find all this "stuff" for your current drawing call. Give a different context to the exact same drawing call, and that call might draw to a different bitmap in a completely different view, with a different color, different scale, etc.
Basically it is a class in a platform (iOS, Android, JavaME and many others) that provides access to all the drawing/display capabilities provided for that platform. It varies a bit for different platforms of course, but this is the 30,000 foot description :)