Results 1 to 7 of 7

Thread: [RESOLVED] draw highlights over an image

  1. #1

    Thread Starter
    Still learning kebo's Avatar
    Join Date
    Apr 2004
    Location
    Gardnerville,nv
    Posts
    3,762

    Resolved [RESOLVED] draw highlights over an image

    Hey all,
    I'm working on a pdf embellishment app and am having problems with drawing performance.

    I convert pdf files to images and the image size is rather large (5000x3000). I could solve my problem by reducing the image size, but that is not an option (o how I wish it was) so I have to deal with big images.

    The gist of the app is to draw the pdf image on a control, then draw an overlay image on the control after drawing the pdf image. The overlay image is the exact same size as the pdf image so I can handle panning and zooming fairly easily.

    My issue is when I draw a highlight block (bright yellow over text to highlight... you know). The first obvious way to do this was to draw a simple rectangle using color.yellow with the alpha value set to make the block semi-transparent. This looks bad though. The yellow block looks faded and the text under it also looks faded.

    What I have resorted to is copy the part of the pdf image that the block covers and change the white pixels to yellow. Since the pdf image is guaranteed to be black text on a white background, this works exceptionally well... the text remains black, and the highlight is nice and bright. Unfortunately it takes a while to make this white to yellow conversion and given the size of the images I'm dealing with, the problem gets exponentially worse as the highlight block size increases.

    Here is my code for the conversion...
    VB.net Code:
    1. Private Sub drawHighlight(gr As Graphics, r As Rectangle)
    2.  
    3.         'r is the highlight block rectangle
    4.         If r.Width > 0 AndAlso r.Height > 0 Then
    5.             'create a new image using the block size
    6.             Using img As New Bitmap(r.Width, r.Height)
    7.  
    8.                 RaiseEvent GetHighlightedImage(r, img) '<---this gets the underlying pdf image; img is passed ByRef
    9.                 'iterate the image's pixels
    10.                 For x As Integer = 0 To img.Width - 1
    11.                     For y As Integer = 0 To img.Height - 1
    12.                         'get the color of the pixel
    13.                         Dim c As Color = img.GetPixel(x, y)
    14.  
    15.                         'if the R,G & B are larger than the threshold, then change the pixel to yellow
    16.                         Const BW_THREASHOLD As Integer = 200
    17.                         If c.R > BW_THREASHOLD AndAlso c.G > BW_THREASHOLD AndAlso c.B > BW_THREASHOLD Then
    18.                             img.SetPixel(x, y, Me.BackColor)
    19.                         End If
    20.                     Next
    21.                 Next
    22.                 'finally draw the image on the overlay
    23.                 gr.DrawImage(img, r.Location)
    24.             End Using
    25.         End If
    26.     End Sub
    So is there a way that I can increase performance of this routine (significantly)?

    Thanks for looking... Cheers!
    kevin
    Process control doesn't give you good quality, it gives you consistent quality.
    Good quality comes from consistently doing the right things.

    Vague general questions have vague general answers.
    A $100 donation is required for me to help you if you PM me asking for help. Instructions for donating to one of our local charities will be provided.

    ______________________________
    Last edited by kebo : Now. Reason: superfluous typo's

  2. #2
    Frenzied Member
    Join Date
    May 2014
    Location
    Central Europe
    Posts
    1,388

    Re: draw highlights over an image

    GetPixel/SetPixel is slow. you should rather use lockbits or New Bitmap with the overload where you can provide Scan0 as IntPtr. this gives you access to a bytearray where you can easily loop through and that is much faster. i see two options: one is to lockbits the entire big image and just work on the area you need to. this would also eliminate the drawimage back to the big image. or second option, you keep your drawHighlight function but use New Bitmap(...,Scan0) to create your img var. this would probably involve less code changes.

    option a is better if you have many areas to color but i guess both should give you the desired speed boost.

    here is an example snippet that counts the number of colors in an image:
    Code:
        Private Function CountColors(ByVal InBitmap As Bitmap) As UInt32
            Dim dwPixels(InBitmap.Height * InBitmap.Width - 1) As UInt32
            Dim hPixels As GCHandle = GCHandle.Alloc(dwPixels, GCHandleType.Pinned)
            Dim bmp32Bpp As New Bitmap(InBitmap.Width, InBitmap.Height, InBitmap.Width * 4,
              Imaging.PixelFormat.Format32bppRgb, hPixels.AddrOfPinnedObject)
    
            Using gr As Graphics = Graphics.FromImage(bmp32Bpp)
                gr.DrawImageUnscaledAndClipped(InBitmap, New Rectangle(0, 0, _
                  bmp32Bpp.Width, bmp32Bpp.Height))
            End Using
    
            Dim dwTable(CInt(2 ^ 19) - 1) As Int32
            Dim index As Int32
            Dim bit As Int32
            Dim cDifferentColors As UInt32
            For i = 0 To dwPixels.Length - 1
                index = CInt(dwPixels(i) And &HFFFFFF)
                bit = 1 << (index And &H1F)
                index >>= 5
    
                If (dwTable(index) And bit) = 0 Then
                    cDifferentColors += 1UI
                    dwTable(index) = dwTable(index) Or bit
                End If
            Next
    
            hPixels.Free()
    
            Return cDifferentColors
        End Function
    i'm sure you can find more examples and examples for lockbits on the internet.

  3. #3
    Fanatic Member
    Join Date
    Aug 2004
    Location
    Essex, UK
    Posts
    774

    Re: draw highlights over an image

    Check out fastpix by boops boops:

    http://www.vbforums.com/showthread.p...mies-and-Dudes

    Just add the module to your project and you hardly have to change your code.

  4. #4
    PowerPoster boops boops's Avatar
    Join Date
    Nov 2008
    Location
    Holland/France
    Posts
    3,201

    Re: draw highlights over an image

    For maximum performance, you could use the FastPix with an integer array for the pixels. But I suspect that a simple function like the following would be quick enough for your present purpose and it doesn't require LockBits or FastPix:
    Code:
      Private Function ReplaceColor(img As Image, oldColor As Color, newColor As Color) As Bitmap
          Dim bmp1, bmp2 As New Bitmap(img)
          bmp2.MakeTransparent(oldColor)
          Using g As Graphics = Graphics.FromImage(bmp1)
             g.Clear(newColor)
             g.DrawImage(bmp2, Point.Empty)
          End Using
          Return bmp1
       End Function
    On quick testing. It seems to take only a couple of milliseconds regardless of image size. Of course, it only works if "oldColor" is the exact ARBG colour to be replaced so it can't preserve anti-aliasing of the text; the AA-pixels will still be blended with the original background colour.

    BB

  5. #5

    Thread Starter
    Still learning kebo's Avatar
    Join Date
    Apr 2004
    Location
    Gardnerville,nv
    Posts
    3,762

    Re: draw highlights over an image

    Thanks to all for your feedback...

    @digitalShaman - I saw a bunch of Lockbits examples on the internets, but couldn't decipher exactly how any of them fit my situation. Coding outside of the managed space is something I haven't grasped. I am very comfortable in the nice tidy world of .net and I'm very comfortable manipulating registers and moving electrons around on small micro controllers, but I've never had a need for the "in between" so I've never learned it.

    @paulg4ije - thanks for the link. It's was my ultimate solution. Dead easy drop in replacement for my existing code.

    @BB - FastPix gave me a performance boost of around 5X which meets my criteria of "significant improvement". When I tried simple replacing specific colored pixels (i.e. Black), the text ended up looking stringy. Although I said the pdf files are black and white, nothing is ever black and white.. there is always some gray area. Because of that, I need to compare against a threshold value.

    Thanks again to all of you
    kevin
    Process control doesn't give you good quality, it gives you consistent quality.
    Good quality comes from consistently doing the right things.

    Vague general questions have vague general answers.
    A $100 donation is required for me to help you if you PM me asking for help. Instructions for donating to one of our local charities will be provided.

    ______________________________
    Last edited by kebo : Now. Reason: superfluous typo's

  6. #6
    Frenzied Member
    Join Date
    May 2014
    Location
    Central Europe
    Posts
    1,388

    Re: [RESOLVED] draw highlights over an image

    the is no "in between" and lockbits is part of the managed space. its just that a 24bpp bitmap is effectively an array of bytes, one byte for red, one for green and one for blue and that for each pixel. lockbits/scan0 allows you to directly access the RGB value of each pixel with the performance of a normal array read/write operation. i have not checked but i am sure that fastpix is actually using lockbits/scan0, but it encapsulates this away from you which is fair enough.

    but now comes the clou. i realized that the correct way to do this is not accessing pixels but instead using a color transformation matrix when calling drawimage.
    try this out:
    Code:
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Dim img As New Bitmap("c:\kill\test.jpg")
    
            Dim matrix As New Imaging.ColorMatrix(
                        New Single()() {New Single() {1, 0, 0, 0, 0},
                                        New Single() {0, 1, 0, 0, 0},
                                        New Single() {0, 0, 0, 0, 0},
                                        New Single() {0, 0, 0, 1, 0},
                                        New Single() {0, 0, 0, 0, 1}
                                       })
    
            Dim Attributes As New Imaging.ImageAttributes
            Attributes.SetColorMatrix(matrix)
    
            Using g As Graphics = PictureBox1.CreateGraphics
                g.DrawImage(img, New Rectangle(0, 0, PictureBox1.Width, PictureBox1.Height), 0, 0, img.Width, img.Height, GraphicsUnit.Pixel, Attributes)
            End Using
        End Sub
    Last edited by digitalShaman; Feb 24th, 2017 at 11:06 AM.

  7. #7
    PowerPoster boops boops's Avatar
    Join Date
    Nov 2008
    Location
    Holland/France
    Posts
    3,201

    Re: draw highlights over an image

    Quote Originally Posted by kebo View Post
    When I tried simple replacing specific colored pixels (i.e. Black), the text ended up looking stringy. Although I said the pdf files are black and white, nothing is ever black and white.. there is always some gray area. Because of that, I need to compare against a threshold value.
    kevin
    To get goed results, you would have to convert the greyness of the pixels to transparency. Otherwise they will still be blended with the original white background and will show up as white against the new yellow background.

    As an alternative, it might be worth trying with only the black pixels, and blur the result a little bit to give an impression of anti-aliasing. Here's a quick and dirty way of blurring which takes only a few lines of code. Draw the black pixels onto a yellow background, scaling the whole thing down a bit (e.g. 1/2 or 2/3 linear); then scale the result back up again. Use Graphics.DrawImage with InterpolationMode.HighQualityBilinear for scaling in both directions. Finally paint the black pixels again at the correct scale.

    BB

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width