Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SVGDocument new features #1

Open
abu-irrational opened this issue May 7, 2024 · 8 comments
Open

SVGDocument new features #1

abu-irrational opened this issue May 7, 2024 · 8 comments

Comments

@abu-irrational
Copy link

Thanks for svg2b2d, it's well integrated with Blend2d, but I'm thinking about two small things
, currently missing, that could be useful for better positioning or framing a picture on a canvas.

  • Class SVGDocument should provide some methods returning the viewbox() and the boundingbox().

  • The width(), height(), viewbox() and bbox() methods should always return a meaningful
    (computed) result, even if these attributes are not set.
    (* I know boundingbox is not an SVG attribute, but it is useful for sizing the canvas *)

  • Test case 1: tiger.svg
    https://upload.wikimedia.org/wikipedia/commons/f/fd/Ghostscript_Tiger.svg
    has the following header ( ... missing width, height)
    <svg id="svg2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 900 900" version="1.1">

and methods width(), height() returns 100.0 100.0

Therefore, when rendered (doc.draw(..)), nothing is drawn.

  • Test case 2: * moby.svg
    This attched file <mobj.svg>,
    moby
    has the following header
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="392.466022pt" height="110.322899pt" viewBox="0 0 392.466022 110.322899"
preserveAspectRatio="xMidYMid meet">

here width(), height() return 523.288029 , 147.097199
I suppose they are scaled, but the bad thing is that in this 'viewBox' the true picture (moby)
is much more smaller. there's a lot of white/unused space around the picture
Therefore the measurement of the bounding box would be needed to size the canvas better.

@Wiladams
Copy link
Owner

Wiladams commented May 7, 2024

image

I agree with you 110%!!

I ran into the same challenges, and in subsequent work added all that stuff you mentioned.

My main challenge will be in how to best introduce all that new stuff. The structures have changed fundamentally, so probably the best thing is to push the current thing off to its own branch/release, and just copy the new stuff over to main here.

@Wiladams
Copy link
Owner

Wiladams commented May 7, 2024

I'm assuming the highest level simple C interface is still good?

Also, I added the ability to easily scale things at the document level.

@abu-irrational
Copy link
Author

Scaling the whole SVGDocument is a good solution ( I will add also rotations ... affine transformations).

About the 'top' C interface, I think that
loadSVG(filename, blImage)
is useful for quick drawing, but it's too limited.

We need to control where to put the extracted paths, scale them, and maybe redraw them more times

I think that the right top API should be a C-transposition of the SVGDocument class
( but also the C++ class is enough for me )

  • load a SVG-file in a new SVGDocument
    . .. get the width, height, viewbox, bbox ....
    . ... preparare a BLimage and a BLContext .... (...define a coord-system ..)
    .
  • draw the SVGDocument in the BLContext
    . .. (optional..) change the BLContext matrix an draw again ...
    .- destroy the SVGDocument

More in detail:

  • doc.readFromData(..) is very useful, but I fear that mmap is not cross-platform,
    so, maybe you could provide a method like
    doc.readFromFile(..)
    hiding all the mmap stuff ....

  • doc.draw(blCtx) should work on an existing BLContext (currently it requires a new standalone SVGRenderer)
    .. I would completely hide SVGRenderer; maybe this new doc.draw() method could internally allocate an SVGRenderer 'grabbing' the blCtx and its attached BLImage ....
    Yeah, it's quiet intricated .. working on a BLImage that is already under control of another BLContext may be dangerous ...

Let me know if you think they are a right and coherent choice.

@Wiladams
Copy link
Owner

Wiladams commented May 8, 2024

This is what I currently do when I drop a file onto my application:

	double startTime = seconds();
	gDoc = SVGDocument::createFromFilename(fde.filenames[i], appFontHandler());

	
	double endTime = seconds();
	printf("== fileDrop: SVGDocument::createFromFilename took %f seconds\n", endTime - startTime);

	auto rootNode = gDoc->documentElement();
	if (rootNode == nullptr)
		continue;
	
	
	if (rootNode != nullptr)
	{
		BLRect r = rootNode->viewport();
		//printf("viewport: %3.0f %3.0f %3.0f %3.0f\n", r.x, r.y, r.w, r.h);

		
		auto objFr = gDoc->sceneFrame();
		//printf("gDoc::sceneFrame: %f,%f %f,%f\n", objFr.x, objFr.y, objFr.w, objFr.h);
		
		gCameraView->resetView();
		gCameraView->clearAll();
		gCameraView->scene(gDoc);

		if (objFr.w > 0 && objFr.h > 0)
			gCameraView->sceneFrame(objFr);

		
		// Only create one window
		return;
	}

@Wiladams
Copy link
Owner

Wiladams commented May 8, 2024

So, in this case, I hide the mmap in the createFromFilename() function, as you suggest.

You can also see how I get the viewport, which might be different from the "sceneFrame".

I then have this SVGCameraView, which handles all the transformation stuff. I can take a general transform, but it has specializations for rotation, pan, and zoom.

in my case, I map mouse scroll wheel to zoom, horizontal scroll (logitech mouse) for rotation, and click/drag to movement.

I put all this into that camera object because it's was getting messing with the bits and pieces all over, and really at the end of the day, you're just trying to create a matrix to apply to the context.

From there, you should be able to draw into an BLContext, without a care in the world. If it's messed up, then that's the caller's fault.

I think I've got all the goodness in hand. Just need to figure out the best way to put it out into the world.

@abu-irrational
Copy link
Author

Hi William, sorry, but I'm not sure I understood the last code snippet.

What is the parameter
appFontHandler
used in createFromFile() method?

I thought createFromFile() should only require a filename, just as createFromData() required just a stream of bytes..

Regarding SVGDocument, from the point of view of integration with Blend2d, I would simplify or hide all those details on the internal XML structure (such as ..getElement() .. ), and expose only the relevant information to 'frame' the drawing in a canvas (BLContext).

Can you just sketch the top interface (*.h)?

Where is the connection with Blend2d and in particulare with BLContext?

@Wiladams
Copy link
Owner

Wiladams commented May 8, 2024

Let me stop right here. I was sharing an internal interface of my current project, which isn't the final interface I would use here.

The appFontHandler is an artifact of how my current project is setup. The previous version did not have any font handling support at all, so, this object showed up. At the very least you need to specify a directory where fonts you want to use live, or something like that. Perhaps it's hidden with an #ifdef.

In my context, the following happens 'per frame'

void onFrame(const FrameCountEvent& fce)
{
//printf("onFrame...\n");

// Start with an initial white background
gAppSurface.setFillStyle(BLRgba32(0xffffffff));
gAppSurface.fillAll();

if (gAnimate)
{
	gDoc->update();
}


if (gCameraView != nullptr)
	gCameraView->draw(&gAppSurface);

gAppSurface.flush();

screenRefresh();

// Save a frame if we're recording
if (gRecorder != nullptr)
	gRecorder->saveFrame();

}

Basically CameraView->draw() is where the action occurs.

	// draw the scene
	virtual void drawSelf(IRenderSVG* ctx)
	{
		ctx->image(getImage(), 0, 0);
		ctx->flush();
	}
	
	void draw(IRenderSVG* ctx) override
	{
		snapshot();
		
		ctx->push();

		ctx->translate(fFrame.x, fFrame.y);
		
		drawSelf(ctx);

		ctx->pop();
	}

But that's layers upon layers.

I'll have to simplify that down to a BLContext thing, instead of IRenderSVG, although that's removing a lot of simplification.

Please don't take these examples as final. I need to think about what the interfaces will really look like, as I have a lot to port over.

@abu-irrational
Copy link
Author

Many thanks William, take your time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants