in reply to Tk:Photo -data with binary data?

Tk805 will probably support binary data for the -data option.

Replies are listed 'Best First'.
Re^2: Tk:Photo -data with binary data?
by BrowserUk (Patriarch) on Dec 13, 2006 at 11:31 UTC

    That's really good to know. Thanks.

    I would have raised this as bug report but it was never clear whether the 'bug' was just my misinterpretation of the docs--plenty of other people assumed that 'binary data' meant base64 encoded binary data--, a deliberate omission, or a limitation of the underlying Tk libraries.

    If you have any influence with those that will implement this?

    What would be *really nice*, would be the possibility to (alternatively) pass the address of a buffer from which Tk would update the underlying windows bits when instructed.

    In an ideal world, it would be possible to use a graphics (painting) tool, (like GD) to create and/or modify images and a presentation tool (like Tk) to display them; with having to go through multiple copy operations and format conversions to pass data between them.

    Presumably, all Tk::Photo does with the data passed is convert it into the format required by the underlying OS window primitives (eg. Bitmap for windows), and then pass the converted data on to the OS for display. Tk::Photo makes use of several packages (Tk::Png, Tk::Jpeg etc.) to do the conversion.

    GD uses an internal format of it's own making (the GD(1) format). I'm wondering about the possibility of adding a Tk::GD package to the suite?

    If (a to be written) Tk::GD package could accept an address, and the authors of GD/bgd could be pursuaded to expose the address of their internal buffers, then once the connection was made, you could use GD to modify the image and simple force an update to the Tk::Photo widget to have it read the bits directly out of the GD buffer. That would save several copy and convert steps along the way.

    The current situation of either:

      1. Draw with GD (in it's gd format).
      2. Export (copy and convert) the data into (say) Png format.
      3. Convert that to base64.
      4. Pass that to the Tk::Photo widget, which converts it back from base64 to Png.
      5. Passes that to Tk::Png, which converts it to whatever format the underlying windowing system requries.(eg. BITMAP on windows).
      6. Then throws those bits into the device context in the OS windowing system

    • Using a Tk::Canvas object with all it's hit testing, scaling and other potential, which is great if you need those facilities, but horribly slow for your basic pixel painting applications (eg. Tk Mandelbrot Fractal).

    makes using Tk for graphical applications (rather than window/dialog building purposes for which it is really quite nice), a PITA.


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      Tcl/Tk lifted the restriction to only base64-encoded data for gif images recently. This means it is just a question of porting the Tcl/Tk changes to the Perl/Tk source code (I am currently maintaining a set of patches against Tk-804.027, so this could maybe also go into the patchset).

      As for the Tk::GD thing, I think this should be possible. Tk has various image types (Bitmap, Pixmap, Photo). And for Photo, there are various handlers for different image formats (gif, jpeg, png ...). It seems that Tk::GD should be implemented as another image type. You can look at tixGeneric/tixImgXpm.c or generic/tkImgPhoto.c in the Perl/Tk sources to see how to do this.

        Here's a patch against Tk804.027 which adds binary data support, but for GIF only. The patch includes additional tests in the t/photo.t file.

        I found that the internal Tk image handling code is already binary-ready, at least for the GIF format. Unfortunately Perl/Tk converts every string into a utf8-flagged string, which means that the data has again to be converted back to bytes before handing to the image handling code, which consumes space and time. It seems to be non-trivial to avoid these unnecessary conversions.

        --- t/photo.t (revision 1365) +++ t/photo.t (revision 1367) @@ -14,7 +14,7 @@ $numFormats++ unless $@; my $mw = MainWindow->new(); $mw->geometry('+100+100'); -plan tests => (2*(7 * $numFormats) + 2); +plan tests => (2*(7 * $numFormats) + 2 + 2); my @files = (); @@ -81,6 +81,38 @@ foreach my $leaf('Tk.xbm','Xcamel.gif') } $row += 3; } + +# Extra tests +my $col = 0; +$mw->Label(-text => "Extra tests")->grid(-row => $row++, -column => $ +col); +my $file = Tk->findINC('Xcamel.gif'); +my $data = do { open my $fh, $file or die $!; local $/; <$fh> }; + +if ($Tk::VERSION <= 804.027) + { + skip("Binary GIF data not supported",1,1); + } +else + { + my $image = $mw->Photo(-data => $data); + ok(defined $image, 1, "Read binary GIF data"); + $mw->Label(-background => 'white', -image => $image)->grid(-row => +$row, -column => $col); + $mw->update; + } +$col++; + +if (!eval { require MIME::Base64; 1 }) + { + skip("Need MIME::Base64 module",1,1); + } +else + { + my $image = $mw->Photo(-data => MIME::Base64::encode_base64($data)) +; + ok(defined $image, 1, "Read base64 encoded GIF data"); + $mw->Label(-background => 'white', -image => $image)->grid(-row => +$row, -column => $col); + $mw->update; + } +$col++; $mw->after(2500,[destroy => $mw]); MainLoop; --- objGlue.c (revision 1365) +++ objGlue.c (revision 1367) @@ -584,7 +584,17 @@ Tcl_GetByteArrayFromObj(Tcl_Obj * objPtr /* FIXME: presumably should downgrade from UTF-8, what frees it ? */ - return (unsigned char *) Tcl_GetStringFromObj (objPtr, lengthPtr); + /* SRT: Is this correct? */ + sv_utf8_downgrade(objPtr, 0); + if (lengthPtr) + { + return (unsigned char *) SvPV(objPtr, *lengthPtr); + } + else + { + return (unsigned char *) SvPV(objPtr, PL_na); + } +/* return (unsigned char *) Tcl_GetStringFromObj (objPtr, lengthPtr); + */ }