[comp.sys.next] Bitmaps from views

combs@sumex-aim.stanford.edu (Dave Combs) (11/22/89)

Gang,
I'm trying to speed up an interactive application by taking various View-
subclass objects and converting them to Bitmaps, which I can then composite
onto a window as I wish.  Can someone explain to me how this is done?
I've tried using "copyPSCodeInside:to:" to put the View data onto a stream
(which is in EPS format, and works fine).  I've then tried to use the
Bitmap function "newFromStream:" to read the data into a bitmap.  However,
this always chokes (quietly) on the second byte read in, and gives me
nothing.  Anybody have any idea what I'm doing wrong?  Is the Bitmap
expecting bitmap-type data from the stream, or is Postscript code okay?
I looked all through the manual, and couldn't find anything.

Thanks,
Dave  (combs@sumex-aim.stanford.edu)

ali@polya.Stanford.EDU (Ali T. Ozer) (11/22/89)

In article <865@shelby.Stanford.EDU> Dave Combs writes:
>I'm trying to speed up an interactive application by taking various 
>View-subclass objects and converting them to Bitmaps, which I can then 
>composite onto a window as I wish.  Can someone explain to me how this is 
>done?

One way to do it is to create a bitmap of the appropriate size, lockfocus
on it, and do your drawing.  I assume you currently have a drawSelf:: method
which draws whatever your view is showing.  To cache the image in a bitmap
without having to change too much code in your subclass of View, you'd do 
something along the lines of...

- drawSelf:(NXRect *)rects :(int)rectCount
{
    if (needsCaching) {
	[cache lockFocus];

        ... do your drawing ...

	[cache unlockFocus];
	needsCaching = NO;
    }

    if (rectCount == 3) {	// Scrolling diagonally; use last two rects
	[cache composite:NX_COPY fromRect:rects+1 toPoint:&(rects+1)->origin];
	[cache composite:NX_COPY fromRect:rects+2 toPoint:&(rects+2)->origin];
    } else {		  	// Just use first rectangle
	[cache composite:NX_COPY toPoint:&rects->origin];
    }

    return self; 
}

Above we're assuming that you have a bitmap (named cache) which is the same
size as the view.  The variable needsCaching specifies whether the image needs 
to be cached in the bitmap or not.  After we cache (if we need to), we go 
ahead and do the actual drawing through compositing.

If you want to print, the above will cause the bitmap to dump its contents
out to the printer; the compositing will be simulated through imaging. 
However, the image will be screen-res.  If you want to get beautiful (300 or
400dpi) image out of the printer, you then need to make sure you check the
value of NXDrawingStatus and if the value is NX_PRINTING simply execute the
PostScript with the focus on the view itself.  

>I've tried using "copyPSCodeInside:to:" to put the View data onto a stream
>(which is in EPS format, and works fine).  I've then tried to use the 
>Bitmap function "newFromStream:" to read the data into a bitmap.  However,
>this always chokes (quietly) on the second byte read in, and gives me 
>nothing.

Bitmap's newFromStream: method tries to read TIFF data from the
stream, not PostScript.  If you wish to create an image in a bitmap
from PostScript, you need to simply lockfocus on the bitmap and
execute the code...

Several of the examples from /NextDeveloper/Examples use bitmaps to
speed drawing up; for instance, BreakApp creates images of tiles &
such in bitmaps and then composites them in; Draw uses caching to
create images of the graphic objects in bitmaps so you can move them
around quickly; and Yap uses code similar to what's above (see YapOutput.m) 
to create its image in a cache and scroll around in it.

Ali

combs@sumex-aim.stanford.edu (Dave Combs) (11/23/89)

Ali,
Thanks for your response regarding Bitmaps.  After I sent my note out,
I realized that I'd left out one crucial piece of information, namely that
the image that I'm trying to place in a bitmap consists of a whole 
hierarchy of views, rather than just a single view.  As I understand it,
doing a lockFocus to an offscreen bitmap works fine in the example you
gave precisely because nothing changes the lockFocus once it's been done
in drawSelf::.  In particular, there is no traversal of the View hierarchy,
(as with the "display" msg, which keeps adjusting the focus as it goes down
a View hierarchy [at least I assume that's what's happening.  Correct?])

To restate the problem for anyone who missed it - to speed up some
interactive drawing operations (for a "link and node editor" I'm developing)
I would like to cache certain images in Bitmaps.  It appears that the
standard "cache to offscreen window, then composite" trick only works
when the image being cached is only a single view, whereas each of my
images is a hierarchy of views.  What's the best way to get these to a 
Bitmap?

Thanks for any advice,
Dave  (combs@sumex-aim.stanford.edu)

ali@polya.Stanford.EDU (Ali T. Ozer) (11/23/89)

In article <867@shelby.Stanford.EDU> Dave Combs writes:
> 		...  After I sent my note out,
>I realized that I'd left out one crucial piece of information, namely that
>the image that I'm trying to place in a bitmap consists of a whole 
>hierarchy of views, rather than just a single view. ...
>To restate the problem for anyone who missed it - to speed up some
>interactive drawing operations (for a "link and node editor" I'm developing)
>I would like to cache certain images in Bitmaps.  It appears that the
>standard "cache to offscreen window, then composite" trick only works
>when the image being cached is only a single view, whereas each of my
>images is a hierarchy of views.  What's the best way to get these to a 
>Bitmap?

Hmm, I see, your problem is somewhat more complicated. How about this, 
then --- go ahead, draw your views into a window using the normal drawing
stuff, then, composite from the window to a bitmap. The drawing
in the window will be done through the view heirarchy, and you won't have
to worry about locking focus on the bitmaps.  

Here's how you composite from a window to a bitmap:

	[bitmap lockFocus];
	PScomposite (srcX, srcY, width, height,    // Of the area in the window
		     [window gState],
		     0.0, 0.0, NX_COPY);
	[bitmap unlockFocus];

The window you draw into can either be on-screen or off-screen.  If it's 
on-screen, you will have some extra work to do as [window gState] will give
you the graphics state of the window, which includes the borders and such.
Thus, you'd need to account for these when specifying srcX, srcY.  Or you can
create a gState for the contentView of the window (once, after the window 
is created), and use that.

To create:

	[[window contentView] allocateGState];

To use:

	PScomposite (srcX, srcY, width, height,    // Of the area in the window
		     [[window contentView] gState],
		     0.0, 0.0, NX_COPY);

Creating an off-screen window might be a better idea; in that case you specify
style:NX_PLAINSTYLE.  This way you won't have any borders or title bars
to worry about and you can just use [window gState] when compositing.

Actually, if all you wanted to do was composite from this cache, you can
even just use this off-screen window as the cache and forget about using a 
bitmap;  after all, a bitmap is just a part of an off-screen window with 
some extra functionality thrown in and some window functionality removed. 
Bitmaps just tend to be more efficient as the appkit uses shared windows
to stick all the bitmaps into.  But if you're just going to use one big
cache bitmap, it won't matter which you use.

Ali