locked
Why does InkCollector shrink collected bitmap image of strokes? RRS feed

  • Question

  •  

    I'm trying to write a simple Tablet PC app in VB6 with the COM Automation
    library inkobj.dll to draw over a bitmap and save a bitmap image of the ink strokes.

     

    I am using an InkCollector attached to a window (e.g. a PictureBox) to
    collect a bitmap image of the doodles made over the window..
    I am then using InkCollector.Ink.Save(IPF_GIF) to generate a GIF
    bitmap that I save to a file.
    Because I want a bitmap that covers the entire PictureBox, I start by
    adding a diagonal ink stroke from the upper left of the window to the
    lower right.
    This forces the InkRectangle to the size I want.
    I compute the Ink Coordinates for this by calling Ink.Renderer with
    the DC of the attached window,
    then I call Ink.CreateStrokes and this works properly if I save the
    GIF file.
    The display also looks correct, with a diagonal line from UL to LR.
    If I now doodle on the window, this works and displays correctly.
    So far so good.

    The problem comes if I now call Ink.Save(IPF_GIF) to save the Ink.
    Now, the diagonal stroke I created looks ok, but the doodles are
    shrunk to the upper left of the GIF file.
    Why are my pen doodles not scaling properly as they appeared during
    the drawing process. Why is Ink.Save moving the doodles, but keeping
    my diagonal stroke intact?
    Is there some special scaling parameters I must set in InkCollector to
    save the ink image the way it is being displaying?

    Also, I've noticed that penstrokes moved from inside to outside the
    PictureBox are also being picked up. How do I capture Ink strokes.made
    only within the attached window?
    Do I need to do something in addition to setting the InkCollector.hWnd
    to the attached window's handle?

    I would think that using InkCollector this way would be
    straightforward, but there is obviously something I am not
    understanding here.

    In fact, the simple InkCollector sample in the Tablet PC API exhibits the same behavior - capturing ink strokes beyond the actual form's window.

     

    Thanks for any help / advice!

    Monday, December 10, 2007 12:51 AM

Answers

  • >>Do I have to convert Picture1.Width and Picture1.Height to ink coordinates first somehow?

     

    Yes, you have to convert those coordinates to inkspace, by using the Renderer.PixelToInkSpace API.

     

    Thanks!

    Tuesday, December 11, 2007 11:11 PM

All replies

  • Hi hogwell,

     

    >> Now, the diagonal stroke I created looks ok, but the doodles are shrunk to the upper left of the GIF file.
    I do not see this happening on my computer with a little test program I wrote. Which version of the operating system are you runng - and which version of InkObj.dll are you referencing? Can you include the code to reproduce the problem?

     

    >>Also, I've noticed that penstrokes moved from inside to outside the PictureBox are also being picked up.

    This is by design. We preserve, by default, the full information of the ink that the user has collected. This is very important for example if you want to perform handwriting recognition on the ink.

     

    If you want to clip the ink to the visible area, just call the Clip() method on the Ink object and pass in the rectangle of your visible area.

     

    Thanks!

    Tuesday, December 11, 2007 5:23 AM
  • Thanks, Stefan

     

    I'll try to work up a simple sample to demonstrate the shrinkage of collected ink.

    I think there is something about the default transfer of ink over a window that involves some kind of scaling when the strokes are rendered to a GIF bitmap. I'm certainly not calling any of the mapping functions explicitly and I was expecting the saved bitmap to look just like the auto-redrawn inkstrokes during the collection process.

     

    I wish there was an SDK sample somewhere that let a user scribble on a bmp file, for example, then save the merged strokes with it back to another bmp (or GIF) file. Seems like it should be simple.

     

    The SDK I'm using is recently downloaded from the MSDN library - VB6 shows it as "Microsoft Tablet PC Type Library, v1.0" in the references.

     

    I also appreciate your comment about the collected ink outside the attached window.

    The documentation lead me to believe that setting the hwnd to a window or control would collect ink only within that window.

    I also saw that the default for Clip was (0,0,0,0), which was supposed to clip ink outside the window dimensions, so I did not think I had to also call it explicitly with actual window coordinates for the attached hwnd. But I will try that.

     

    Tuesday, December 11, 2007 8:40 PM
  • >>I wish there was an SDK sample somewhere that let a user scribble on a bmp file, for example, then save the merged strokes with it back to another bmp

     

    There is sample that does exactly this attached to this blog post:

    http://blogs.msdn.com/swick/archive/2007/12/02/tabletpc-development-gotchas-part5-rendering-ink-and-image-to-a-bitmap.aspx

     

    It's in C# though, not VB6, but the same concept applies in both environments. FYI: In VB6 (or in any other native language) you don't have to use the workaround described in that post.

     

    Thanks!

    Tuesday, December 11, 2007 9:00 PM
  • Thanks for the link Stefan.

     

    I've definitely perused your blog site and this technique was one of my early attempts, taken from this page:

     

        myInkCollector.Renderer.Draw Me.hDC, myInkCollector.Ink.Strokes
        
        Dim SavedGIF() As Byte
        SavedGIF = myInkCollector.Ink.Save(IPF_GIF)
        Open "C:\TEST.GIF" For Binary As #1
        Put #1, , SavedGIF
        Close #1

    What this gave me is a small GIF sized to the extent of where the actual ink was drawn - not a GIF sized to the attached InkCollector window.

     

    That is where I came up with the idea of drawing an (invisible) stroke from UL to LR to force the GIF to match the window.

     

    I've now determined that part of my problem is that my diagonal line might not be correct and is too long - causing the "shrinkage" of the drawn ink. I'll have to track this down.

     

    Now I just need to figure out how to call Ink.Clip to eliminate any stray ink outside the PictureBox control boundaries.

    Do I have to convert Picture1.Width and Picture1.Height to ink coordinates first somehow?

    Or can I just call clip with (0,0,0,0)?

     

    Tuesday, December 11, 2007 10:26 PM
  • >>Do I have to convert Picture1.Width and Picture1.Height to ink coordinates first somehow?

     

    Yes, you have to convert those coordinates to inkspace, by using the Renderer.PixelToInkSpace API.

     

    Thanks!

    Tuesday, December 11, 2007 11:11 PM
  • Follow up self post:

    I've now determined that calling Ink.Clip 0,0,0,0 does not work, despite what the documentation says.

    However, calling Ink.Clip with the ink coordinates of the window *does* work and I now have what I wanted working.

    Wednesday, December 12, 2007 12:16 AM
  • Can you please point me to the piece of documentation that you think is incorrect?

     

    I think you might be confusing the InkCollector.SetInputWindowRectangle method (http://msdn2.microsoft.com/en-us/library/ms820357.aspx) with the Ink.Clip method (http://msdn2.microsoft.com/en-us/library/aa510955.aspx).

     

    Thanks!

    Wednesday, December 12, 2007 1:16 AM
  • You're right - I was confusing Clip and SetInputWindowRectangle

     

    Perhaps the reason for my confusion is that the docs lead me to believe that the default behavior of SetInputWindowRectangle would restrict ink input to the InkCollector's attached window.

     

    Here's some specific examples of how the documentation is confusing/incomplete/inaccurate::

     

    > SetWindowInputRectangle Method

    > Sets the window rectangle, in pixels, within which ink is drawn.

     

    This doesn't tell me much other than the units (pixels). Are these screen coordinates, window coordinates, client coordinates, etc? Does this restrict where Ink is drawn only (e.g. with AutoRedraw=True)? or where it's collected?

    What does this method actually do? Why would I call it?

     

    > windowRectangle

    > [in] The rectangle, in window coordinates, on which ink is drawn.

     

    So, would this be (0,0,width height} or {Window.Left, Window.Top, left+width, top+height}?

     

    > By default, the window input rectangle is set to {0,0,0,0}. This default rectangle maps to the size of the entire window.

     

    But if the default input rectangle is confined to the window, why are ink strokes gathered outside the window? There is no explanation or mention of this behavior, which you indicated is "by design".

     

    > This Visual Basic 6.0 example shows how to call SetWindowInputRectangle to set the input area to the screen.

    >        Option Explicit
    > Dim theInkCollector As InkCollector
    >
    > Private Sub Form_Load()
    >   Dim theInkRect As New InkRectangle
    >    theInkRect.SetRectangle 0, 0, 0, 0

    >    Set theInkCollector = New InkCollector
    >    theInkCollector.hWnd = Me.hWnd
    >    theInkCollector.SetWindowInputRectangle theInkRect
    >
    >    theInkCollector.Enabled = True
    > End Sub
    "...set the input area to the screen" Why does this set the input area to the entire screen? The description above indicated it would set the input area to the window (i.e. the dimensions of the Form in this example)?  Which is it?
    Also, this example is so sparse, and is just the default behavior, so it's redundant anyway. How about an example showing how an actual non-zero InkRectangle would be constructed to limit input to a window or portion of a window within an application?
     
    I hope this clarifies my confusion for you... :-)
     
    Thanks again, Stefan, for your help!
     
    Wednesday, December 12, 2007 5:58 PM
  • Hey Do you have this issues fixed? If so can you let me know!
    Thursday, December 5, 2013 9:24 PM