You are viewing a plain text version of this content. The canonical link for it is here.
Posted to batik-users@xmlgraphics.apache.org by Steve Lamont <sp...@ncmir.ucsd.edu> on 2005/03/21 20:15:17 UTC

Adding a BufferedImage to an SVG document?

I want to insert an BufferedImage, which only exists in memory and not
in an external file, into an SVG document for display and
manipulation.  I don't want or need to ever write the resulting
document out.

Can someone be so kind as to give me a leg up on this?  I've looked at
SVGImageElement and it's ilk but haven't the slightest clue as to how
to stuff a BufferedImage or anything similar into them.

This seems like it should be a simple, straightforward thing but
either I'm too dense to figure it out or it's hidden in some obscure
corner of the documentation.

Thanks.

							spl

---------------------------------------------------------------------
To unsubscribe, e-mail: batik-users-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: batik-users-help@xmlgraphics.apache.org


Re: Adding a BufferedImage to an SVG document?

Posted by Steve Lamont <sp...@ncmir.ucsd.edu>.
> > Why, for instance, is a `StrokingTextPainter' so radically different
> > than a 'StrokeShapePainter'?  
>
>     Because text can change color in the middle, and it also needs
> to support being reordered to handle bi-directional text (like
> Arabic or Hebrew).

In reading this, I'm reminded of one of my favor "cookies" from the
Unix `fortune' program:

  Speaking as someone who has delved into the intricacies of PL/I, I
  am sure that only Real Men could have written such a
  machine-hogging, cycle-grabbing, all-encompassing monster.  Allocate
  an array and free the middle third?  Sure!  Why not?  Multiply a
  character string times a bit string and assign the result to a float
  decimal?  Go ahead!  Free a controlled variable procedure parameter
  and reallocate it before passing it back?  Overlay three different
  types of variable on the same memory location?  Anything you say!
  Write a recursive macro?  Well, no, but Real Men use rescan.  How
  could a language so obviously designed and written by Real Men not
  be intended for Real Man use?

It might be helpful to provide some "convenience methods" for those
cases where one wants to apply a change to a simple string that
doesn't require translating the middle three characters to Navajo and
printing them backwards on clay tablets in Cuneiform. :-)

Anyhow, I got it working, so many thanks for that (and bearing with my
rants).
  
>     Well this basic approach is the one used by the JDK for complex
> text so it's not like we invented it. . . .

Don't get me started on the Rococo perversity of the JDK. . .

I'm reminded here of the flyer that I saw being handed out at SIGGRAPH
back in the late 1980s (I think Boston in 1989), the text of which I
reproduce here:

  The X Window System:
  
          A mistake carried out to perfection.
          A moment of convenience, a lifetime of regret.
          Dissatisfaction guaranteed.
          Don't get frustrated without it.
          Even your dog won't like it.
          Flaky and built to stay that way.
          Complex non-solutions to simple non-problems.
          Flawed beyond belief.
          Form follows malfunction.
          Garbage at your fingertips.
          If we raise our standards, we'll let you know.
          Ignorance is our most important resource.
          It could be worse, but it will take time.
          It could happen to you.
          Japan's secret weapon.
          Let it get in YOUR way.
          Live the nightmare.
          More than enough rope.
          Never had it, never will.
          Next day service in a nanosecond world.
          No hardware is safe.
          Power tools for power fools.
          Power tools for power losers.
          Putting new limits on productivity.
          Simplicity made complex.
          The bleeding edge of technology.
          The cutting edge of obsolescence.
          The art of incompetence.
          The defacto substandard.
          The first fully modular software disaster.
          The joke that kills.
          The problem for your problem.
          There's got to be a better way.
          Warn your friends about it.
          You'd better sit down.
          You'll envy the dead.
  
Yes, I'm joking.  Mostly.

Now back to your regularly scheduled programming.

							spl

---------------------------------------------------------------------
To unsubscribe, e-mail: batik-users-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: batik-users-help@xmlgraphics.apache.org


Re: Adding a BufferedImage to an SVG document?

Posted by Thomas DeWeese <Th...@Kodak.com>.
Hi Steve,

    I warned you that text was tricky ;)

Steve Lamont wrote:
>>    Text is quite tricky.  You need to manipulate the TextPaintInfo
>>object that is attached to the AttributedString associated with the
>>TextNode.  The tricky bit is that all of the tspan's are built into
>>the one AttributedString so if you have 'complex' text you would have
>>to track down the proper TextPaintInfo to update.
> 
> Do you mean `AttributedCharacterIterator'?  I see no AttributedString'
> in a `TextNode'.

   The AttributedCharacterIterator comes from the AttributedString
built in the TextBridge.

> Is there a reason why all of this is so darned Byzantine?

    Because Text is _extremely_ complex. The text handling
portion of Batik is by far the most complex part.

> Why, for instance, is a `StrokingTextPainter' so radically different
> than a 'StrokeShapePainter'?  

    Because text can change color in the middle, and it also needs
to support being reordered to handle bi-directional text (like
Arabic or Hebrew).

> In the `StrokeShapePainter' there's a `setPaint()' method that allows 
> one to set the color of the object, whereas in the `StrokingTextPainter' 
> no such method exists and one has to go through extraordinary 
> contortions to get at the `TextPaintInfo' for each individual 
> *character* in a text string in order to set color:

    This is because unlike a shape in the worst case every character
can have a different color.  They all share one StrokingTextPainter
so it can do bidi reordering.  In most cases you don't need to modify
the text paint info for every character you only need to do it for
runs.  All the characters in a run share a single TextPaintInfo,
so modifying the TPI on the first character in the run will update
all the characters in the run.

    The ACI has methods to find the end of a "run" so you can
quickly update an entire string.

>     private void updateTextNodeColor( Color rgb, TextNode text_node )
>     {
> 
> 	AttributedCharacterIterator aci =
> 	    text_node.getAttributedCharacterIterator();
> 
> 	for( char c = aci.first();
> 	     c != CharacterIterator.DONE;
> 	     c = aci.next() ) {
> 
> 	    TextPaintInfo tpi =
> 		( TextPaintInfo ) aci.getAttribute( TextNode.PAINT_INFO );
> 	    
> 	    if ( tpi.fillPaint != null )
> 		tpi.fillPaint = rgb;
> 	    if ( tpi.strokePaint != null )
> 		tpi.strokePaint = rgb;
> 
> 	}
> 
>     }
> 
> It took me most of a day to figure out that you had to slog through
> each character, one by one, in order to get all the characters in the
> same string the same color.

    I'm as sure as I can be that you only need to do this for the
first character in a Run

> I beg your pardon but that's just bizarre.

    Well this basic approach is the one used by the JDK for complex
text so it's not like we invented it.  We did extend it because we
need to do things like under/overline & strikethrough with fill/stroke
as well as stuff like text on a path.  However the concept of
per char attributes that control rendering is a common one for
text rendering systems that need to deal with realities like
bidi text, vertical languages, mid string font/color changes, etc.

> Oh, one minor point.  In `TextPaintInfo', the method name
> `equivilent()' should be `equivalent()'.  I know in computing that
> spelling doesn't necessarily have to be correct, but still. . .

   Thanks I'll fix this and deprecate the misspelling.

---------------------------------------------------------------------
To unsubscribe, e-mail: batik-users-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: batik-users-help@xmlgraphics.apache.org


Re: Adding a BufferedImage to an SVG document?

Posted by Steve Lamont <sp...@ncmir.ucsd.edu>.
>     Text is quite tricky.  You need to manipulate the TextPaintInfo
> object that is attached to the AttributedString associated with the
> TextNode.  The tricky bit is that all of the tspan's are built into
> the one AttributedString so if you have 'complex' text you would have
> to track down the proper TextPaintInfo to update.

Do you mean `AttributedCharacterIterator'?  I see no AttributedString'
in a `TextNode'.

Is there a reason why all of this is so darned Byzantine?

Why, for instance, is a `StrokingTextPainter' so radically different
than a 'StrokeShapePainter'?  In the `StrokeShapePainter' there's a
`setPaint()' method that allows one to set the color of the object,
whereas in the `StrokingTextPainter' no such method exists and one has
to go through extraordinary contortions to get at the `TextPaintInfo'
for each individual *character* in a text string in order to set
color:

    private void updateTextNodeColor( Color rgb, TextNode text_node )

    {

	AttributedCharacterIterator aci =
	    text_node.getAttributedCharacterIterator();

	for( char c = aci.first();
	     c != CharacterIterator.DONE;
	     c = aci.next() ) {

	    TextPaintInfo tpi =
		( TextPaintInfo ) aci.getAttribute( TextNode.PAINT_INFO );
	    
	    if ( tpi.fillPaint != null )
		tpi.fillPaint = rgb;
	    if ( tpi.strokePaint != null )
		tpi.strokePaint = rgb;

	}

    }

It took me most of a day to figure out that you had to slog through
each character, one by one, in order to get all the characters in the
same string the same color.

I beg your pardon but that's just bizarre.

Oh, one minor point.  In `TextPaintInfo', the method name
`equivilent()' should be `equivalent()'.  I know in computing that
spelling doesn't necessarily have to be correct, but still. . .

							spl

---------------------------------------------------------------------
To unsubscribe, e-mail: batik-users-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: batik-users-help@xmlgraphics.apache.org


Re: Adding a BufferedImage to an SVG document?

Posted by Thomas DeWeese <Th...@Kodak.com>.
Steve Lamont wrote:

>>>Can someone be so kind as to give me a leg up on this?  I've looked at
>>>SVGImageElement and it's ilk but haven't the slightest clue as to how
>>>to stuff a BufferedImage or anything similar into them.
>>
>>    You can't because not surprisingly SVG as a document format
>>doesn't handle this concept. . . .
> 
> Then what's the point of the SVGImageElement object?

    This is for the SVG 'image' element, which get's it's
content from a URI.

>>                        . . . You can just stuff a buffered image
>>into a GVT RasterImageNode however it will have no peer in the
>>SVG and there are some cases where it may 'go away' because the
>>graphics tree is rebuilt from the SVG.
> 
> Ah.  This is what I'm already doing and that's exactly the problem I'm
> having.

    I wouldn't expect this problem for simple scale/translate.
Unless you are manipulating the viewBox to scale/translate.

> I'd like to either work at the SVG level or the GVT level.  GVT is
> fine with me if I can figure out how to change colors of the vector
> elements but that seems also to be a dead end.  Or am I again missing
> some subtlety of the TextPainter object and its relatives?  There
> seems to be no method to manipulate text color.

    Text is quite tricky.  You need to manipulate the TextPaintInfo
object that is attached to the AttributedString associated with the
TextNode.  The tricky bit is that all of the tspan's are built into
the one AttributedString so if you have 'complex' text you would have
to track down the proper TextPaintInfo to update.

    The best solution I can think of for this problem would be
to create a custom element.  You could have a subclass of the
UserAgent that knows about the 'images' to display in this document.
Then your Bridge could look up the BufferedImage from the
UserImage and stick it on the RasterImageNode.  This would
allow you to manipulate stuff at the SVG level.

    There are some fairly simple examples in batik.extension.svg.
You might be able to mostly use/copy the existing SVGImage stuff
and just shortcut the URI stuff.

---------------------------------------------------------------------
To unsubscribe, e-mail: batik-users-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: batik-users-help@xmlgraphics.apache.org


Re: Adding a BufferedImage to an SVG document?

Posted by Steve Lamont <sp...@ncmir.ucsd.edu>.
>     You mention 'manipulate' in this case you probably need this
> to exist on the SVG side.  You can do this by encoding the
> Image into a JPEG or PNG and base64 encoding it and including
> that data as a 'data:' protocol on an image xlink:href.  However
> the entire image will have to be encoded and then decoded to
> make this work.

By manipulate, I mean simple scaling and translation.  Nothing exotic.

The application on which I'm working just draws the SVG polylines on
top of the image.

> > Can someone be so kind as to give me a leg up on this?  I've looked at
> > SVGImageElement and it's ilk but haven't the slightest clue as to how
> > to stuff a BufferedImage or anything similar into them.
>
>     You can't because not surprisingly SVG as a document format
> doesn't handle this concept. . . .

Then what's the point of the SVGImageElement object?

>                         . . . You can just stuff a buffered image
> into a GVT RasterImageNode however it will have no peer in the
> SVG and there are some cases where it may 'go away' because the
> graphics tree is rebuilt from the SVG.

Ah.  This is what I'm already doing and that's exactly the problem I'm
having.

I'd like to either work at the SVG level or the GVT level.  GVT is
fine with me if I can figure out how to change colors of the vector
elements but that seems also to be a dead end.  Or am I again missing
some subtlety of the TextPainter object and its relatives?  There
seems to be no method to manipulate text color.

							spl

---------------------------------------------------------------------
To unsubscribe, e-mail: batik-users-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: batik-users-help@xmlgraphics.apache.org


Re: Adding a BufferedImage to an SVG document?

Posted by Thomas DeWeese <Th...@Kodak.com>.
Steve Lamont wrote:
> I want to insert an BufferedImage, which only exists in memory and not
> in an external file, into an SVG document for display and
> manipulation.  I don't want or need to ever write the resulting
> document out.

    You mention 'manipulate' in this case you probably need this
to exist on the SVG side.  You can do this by encoding the
Image into a JPEG or PNG and base64 encoding it and including
that data as a 'data:' protocol on an image xlink:href.  However
the entire image will have to be encoded and then decoded to
make this work.

> Can someone be so kind as to give me a leg up on this?  I've looked at
> SVGImageElement and it's ilk but haven't the slightest clue as to how
> to stuff a BufferedImage or anything similar into them.

    You can't because not surprisingly SVG as a document format
doesn't handle this concept.  You can just stuff a buffered image
into a GVT RasterImageNode however it will have no peer in the
SVG and there are some cases where it may 'go away' because the
graphics tree is rebuilt from the SVG.

> This seems like it should be a simple, straightforward thing but
> either I'm too dense to figure it out or it's hidden in some obscure
> corner of the documentation.

---------------------------------------------------------------------
To unsubscribe, e-mail: batik-users-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: batik-users-help@xmlgraphics.apache.org