Is it certain that UIGraphicsBeginImageContext use CGBitmapContextCreate to create the graphics context? - ios

Does UIGraphicsBeginImageContext use CGBitmapContextCreate to create a graphics context [update: I can't find it in the documentation], so the graphics context is exactly the same either way? I also tried to step into UIGraphicsBeginImageContext but the debugger won't let me step into it.

In the UIKit Function References page of iOS documentation, the following is written about UIGraphicsBeginImageContext:
Creates a bitmap-based graphics context and makes it the current context.
Emphasis added. Following a link to the CGContextRef page, I find this:
A graphics context contains drawing parameters and all device-specific information needed to render the paint on a page to the destination, whether the destination is a window in an application, a bitmap image, a PDF document, or a printer.
Again, emphasis added. This says that (as of now) there are 4 kinds of Core Graphics contexts, each with their own initializers. The only kind that has to do with bitmaps is a bitmap-based CGContextRef, and there is only one documented way to create them (well, technically it comes in two versions). It is very likely that this function is being used. I believe that UIGraphicsBeginImageContext is merely a convenience method. It just sets up a default set of parameters for CGBitmapContextCreate (it takes a lot of parameters) and pushes the created context onto the graphics stack.

Related

Duplicate sub-area within a CGLayer

I use Core Graphics to draw in an UIView, and cache the contents in a CGLayer.
One of its functions needs to duplicate a sub-area of the CGLayer and move it to a new location within the same layer. As a traditional trick, I used to do this by drawing the layer into its own context.
However, the behavior of this trick is "undefined" according to the documentation, and it stops working in iOS 12.
Is there an alternative way to do this efficiently? (I have tried drawing the sub-area into an CGImage then drawing the result image back to the layer. But this method seems sort of slow and not so memory efficient.:()

CIImage and CIFilter implementation specifics

I have a question about the underlying implementation of the Core Image system. I'm adding some CIImages on top of each other. Not that much, about 5 or 6 of them. To save memory and performance, they all have their transparent pixels cropped. They are then drawn at offsets, so I'm using a #"CIAffineTransform" filter to position them.
CIFilter* moveFilter = [CIFilter filterWithName:#"CIAffineTransform"];
My question is: does the moveFilter.outputImage REALLY generate a new image, or does it generate "render settings" that are later on used to draw the actual image?
(If it is the first, that would mean I'm effectively rendering the image twice. It would be a huge flaw in the Core Image API and hard to believe Apple created it this way.)
Filters do not generate anything. outputImage does not generate anything. CIImage does not generate anything. All you are doing is constructing a chain of filters.
Rendering to a bitmap doesn't happen until you explicitly ask for it to happen. You do this in one of two ways:
Call CIContext createCGImage:fromRect:.
Actually draw a CIImage-based UIImage into a graphics context.

In iOS Core Graphics, what is a graphicsContext?

When we do:
CGContextRef ctx = UIGraphicsGetCurrentContext();
what exactly is ctx? Apparently it's a struct. Where is the struct defined? What are its members?
What is a graphics context?
A graphics context refers to the graphic destination. Destination can be a window in an application, a bitmap image, a PDF document, or a printer.
If you want to draw on a view, the view is your graphicsContext or if you wish to draw on an image then that image becomes your graphicsContext.
So, if you wish to make custom drawing using CoreGraphics , you must get the graphic context (destination where you want to put your drawing) . After getting the context , drawing can be done using the CoreGraphics function. Almost all CoreGraphics function has a parameter context. So, each time we call the coregraphics function we first get the current context and pass it as a parameter.
How can you obtain a graphics context?
You can obtain a graphics context by using Quartz graphics context creation functions or by using higher-level functions provided in the Carbon, Cocoa, or Printing frameworks.
For eg:
Quartz provides creation functions for various flavors of Quartz graphics contexts including bitmap images and PDF.
The Cocoa framework provides functions for obtaining window graphics contexts. The Printing framework provides functions that obtain a graphics context appropriate for the destination printer.
What a graphics context contains?
It contains drawing parameters and all device-specific information needed to render the paint to the destination.
Source::
https://developer.apple.com/library/ios/documentation/graphicsimaging/conceptual/drawingwithquartz2d/dq_layers/dq_layers.html
It is a pointer to a struct. The struct is opaque. Just use the functions connected with it.

How does drawRect and CGGraphicsContext work?

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,

iOS " current graphics context" - What is that

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 :)

Resources