January 26, 2021, 06:02:49 AM

Author Topic: [bmx] StackPixmapsPrecise & StackPixmapsFast by Medicine Storm [ 1+ years ago ]  (Read 555 times)

Offline BlitzBot

  • Jr. Member
  • **
  • Posts: 1
Title : StackPixmapsPrecise & StackPixmapsFast
Author : Medicine Storm
Posted : 1+ years ago

Description : Use the StackPixmapsPrecise or StackPixmapsFast functions to combine two pixmaps into one as if
the two were drawn one on top of the other. The transparency and color of the top pixmap can
also be modified. Also, the top pixmap can be flipped vertically and horizontally as well as
rotated in increments of 90 degrees. For example, The following 2 lines:

.   pixNew = StackPixmapsPrecise(pixBottom, pixTop, a, r, g, b, x, y, XFlip, YFlip, RotateMultipleOf90)
.   DrawPixmap(pixNew, 0, 0)
   
Will look identical to:

.   DrawPixmap(pixBottom, 0, 0)
.   If YFlip Then pixTop = YFlipPixmap(pixTop)
.   If XFlip Then pixTop = XFlipPixmap(pixTop)
.   SetColor(r, g, b)
.   SetAlpha(a/255)
.   SetRotation(RotateMultipleOf90)
.   DrawPixmap(pixTop, x, y)

The StackPixmapsFast function does the same thing as StackPixmapsPrecise, but it runs about
5 times faster. The more pixels you are processing with it, the faster the performance gains are
between StackPixmapsFast and StackPixmapsPrecise. The only drawback to using StackPixmapsFast is
the color accuracy could be plus or minus 0.2%. That is: there is a 35% chance that the color
will be off by 2 points at most. For example: RGB(128, 128, 126) instead of RGB(128, 128, 128).
For most applications (especially when processing massive images) the 0.2% error is acceptable and,
unless you are a cyborg, unnoticeable.

These functions were designed for Project Utumno (http://utumno.medicinestorm.com) If you like these
functions or use this code, please, all I ask is that you visit Utumno.MedicineStorm.com and tell
me what you think.


Code :
Code: BlitzMax
  1. 'p_pixBottom: TPixmap imitating the pixmap drawn first, behind the top pixmap
  2. 'p_pixTop: TPixmap imitating the pixmap drawn second, on top of the first pixmap
  3. 'p_intAlpha: Optional. Value between 0 and 255 indicating transparency in addition to any transparency already in the image. Imitates SetAlpha(a/255) command. Only effects the top pixmap.
  4. 'p_intStainRed, p_intStainGreen, and p_intStainBlue: Optional. values between 0 and 255 indicating the colorization to be added to the image. Imitates SetColor(r, g, b) command. Only effects the top pixmap.
  5. 'p_intHorizontalOffset and p_intVerticalOffset: Optional. Shifts the top pixmap horizontally and vertically relative to the bottom pixmap. Negative values can be specified. Any areas of the top pixmap that are beyond the width or height of the bottom pixmap will be clipped off.
  6. 'p_blnFlipVertical and p_blnMirrorHorizontal: Optional. If "True", the image will be flipped about the X-axis and Y-axis, respectivly. Imitates XFlipPixmap() and YFlipPixmap() commands. only efects the top pixmap.
  7. 'p_intRotaiton: Optional. Values of 90, 180, or 270 will rotate the image by 90 degrees, 180 degrees, and 270 degrees, respectivly. Imitates SetRotation() command. Value must be a multiple of 90. Only effects the top pixmap.
  8. Function StackPixmapsPrecise:TPixmap(p_pixBottom:TPixmap, p_pixTop:TPixmap, p_intAlpha:Int = 255, p_intStainRed:Int = 255, p_intStainGreen:Int = 255, p_intStainBlue:Int = 255, p_intHorizontalOffset:Int = 0, p_intVerticalOffset:Int = 0, p_blnFlipVertical:Byte = False, p_blnMirrorHorizontal:Byte = False, p_intRotation:Int = 0)
  9.         'Initialize variables
  10.         Local intLoopX:Int, intLoopY:Int
  11.         Local intOffsetX:Int, intOffsetY:Int, fltAlphaRatio:Float, fltInverseAlphaRatio:Float
  12.  
  13.         Local intTopPixel:Int, fltTopRed:Float, fltTopGreen:Float, fltTopBlue:Float, fltTopAlpha:Float
  14.         Local intBottomPixel:Int, fltBottomRed:Float, fltBottomGreen:Float,     fltBottomBlue:Float, fltBottomAlpha:Float
  15.         Local intCompositePixel:Int, intCompositeRed:Int, intCompositeGreen:Int, intCompositeBlue:Int, intCompositeAlpha:Int
  16.  
  17.         Local intFMR:Int = FMRIndex(p_blnFlipVertical, p_blnMirrorHorizontal, p_intRotation)
  18.         Local intMaxX:Int = p_pixTop.Width - 1
  19.         Local intMaxY:Int = p_pixTop.Height - 1
  20.         Local intBoundsWidth:Int = p_pixBottom.Width
  21.         Local intBoundsHeight:Int = p_pixBottom.Height
  22.         Local pixComposite:TPixmap = p_pixBottom.Copy()
  23.  
  24.         'Loop through each pixel
  25.         For intLoopX = 0 To intMaxX
  26.                 For intLoopY = 0 To intMaxY
  27.  
  28.                         'calculate offset location for later reference
  29.                         intOffsetX = intLoopX + p_intHorizontalOffset
  30.                         intOffsetY = intLoopY + p_intVerticalOffset
  31.  
  32.                         'skip this pixel if it lies outside the boundaries of the bottom pixmap
  33.                         If intOffsetX < intBoundsWidth And intOffsetY < intBoundsHeight And intOffsetX >= 0 And intOffsetY >= 0
  34.  
  35.                                 'Get the top pixel at the current location, taking into account flip, mirror and rotation
  36.                                 Select intFMR
  37.                                         Case 0
  38.                                                 intTopPixel = p_pixTop.ReadPixel(intLoopX, intLoopY)
  39.  
  40.                                         Case 1
  41.                                                 intTopPixel = p_pixTop.ReadPixel(intMaxX - intLoopX, intLoopY)
  42.  
  43.                                         Case 2
  44.                                                 intTopPixel = p_pixTop.ReadPixel(intLoopX, intMaxY - intLoopY)
  45.  
  46.                                         Case 3
  47.                                                 intTopPixel = p_pixTop.ReadPixel(intMaxX - intLoopX, intMaxY - intLoopY)
  48.  
  49.                                         Case 4
  50.                                                 intTopPixel = p_pixTop.ReadPixel(intLoopY, intMaxX - intLoopX)
  51.  
  52.                                         Case 5
  53.                                                 intTopPixel = p_pixTop.ReadPixel(intMaxY - intLoopY, intLoopX)
  54.  
  55.                                         Case 6
  56.                                                 intTopPixel = p_pixTop.ReadPixel(intMaxY - intLoopY, intMaxX - intLoopX)
  57.  
  58.                                         Default '7
  59.                                                 intTopPixel = p_pixTop.ReadPixel(intLoopY, intLoopX)
  60.                                 EndSelect
  61.  
  62.                                 'Split pixel into Alpha channel
  63.                                 fltTopAlpha = (intTopPixel Shr 24) & $FF
  64.  
  65.                                 'if no alpha or stain modifications are being done and the top pixel is totally opaque, there is no need to composite pixels
  66.                                 If (Int(fltTopAlpha) & p_intStainRed & p_intStainGreen & p_intStainBlue & p_intAlpha) = 255
  67.                                         intCompositePixel = intTopPixel
  68.                                 Else
  69.                                         'Split pixel into Red, Green, and Blue channels
  70.                                         fltTopRed = (intTopPixel Shr 16) & $FF
  71.                                         fltTopGreen = (intTopPixel Shr 8) & $FF
  72.                                         fltTopBlue = intTopPixel & $FF
  73.  
  74.                                         'add color stain and alpha modification
  75.                                         If p_intAlpha < 255 Then fltTopAlpha = (fltTopAlpha * p_intAlpha) / 255
  76.                                         If p_intStainRed < 255 Then fltTopRed = (fltTopRed * p_intStainRed) / 255
  77.                                         If p_intStainGreen < 255 Then fltTopGreen = (fltTopGreen * p_intStainGreen) / 255
  78.                                         If p_intStainBlue < 255 Then fltTopBlue = (fltTopBlue * p_intStainBlue) / 255
  79.  
  80.                                         'Get the bottom pixel at the offset location
  81.                                         intBottomPixel = p_pixBottom.ReadPixel(intOffsetX, intOffsetY)
  82.  
  83.                                         'Split pixel into Alpha channel
  84.                                         fltBottomAlpha = (intBottomPixel Shr 24) & $FF
  85.  
  86.                                         'if bottom pixel is totally transparent, there is no need to composite pixels
  87.                                         If fltBottomAlpha = 0
  88.                                                 intCompositePixel = (Int(fltTopAlpha) Shl 24) | (Int(fltTopRed) Shl 16) | (Int(fltTopGreen) Shl 8) | Int(fltTopBlue)
  89.                                         Else
  90.                                                 'precalculate alpha ratios
  91.                                                 fltAlphaRatio = fltTopAlpha / 255
  92.                                                 fltInverseAlphaRatio = 1 - fltAlphaRatio
  93.  
  94.                                                 'Split pixel into Red, Green, and Blue channels
  95.                                                 fltBottomRed = (intBottomPixel Shr 16) & $FF
  96.                                                 fltBottomGreen = (intBottomPixel Shr 8) & $FF
  97.                                                 fltBottomBlue = intBottomPixel & $FF
  98.  
  99.                                                 'Perform alpha-composite
  100.                                                 intCompositeRed = (fltInverseAlphaRatio * fltBottomRed) + (fltAlphaRatio * fltTopRed)
  101.                                                 intCompositeGreen = (fltInverseAlphaRatio * fltBottomGreen) + (fltAlphaRatio * fltTopGreen )
  102.                                                 intCompositeBlue = (fltInverseAlphaRatio * fltBottomBlue) + (fltAlphaRatio * fltTopBlue)
  103.                                                 intCompositeAlpha = (fltInverseAlphaRatio * fltBottomAlpha) + fltTopAlpha
  104.  
  105.                                                 'combine all channels back into a pixel
  106.                                                 intCompositePixel = (intCompositeAlpha Shl 24) | (intCompositeRed Shl 16) | (intCompositeGreen Shl 8) | intCompositeBlue
  107.                                         EndIf
  108.                                 EndIf
  109.                                
  110.                                 'write the pixel to the pixmap at the offset location
  111.                                 pixComposite.WritePixel(intOffsetX, intOffsetY, intCompositePixel)
  112.                         EndIf
  113.                 Next
  114.         Next
  115.         Return pixComposite
  116. EndFunction
  117.  
  118. 'StackPixmapsFast is much faster than StackPixmapsPrecise, but color values may be off by 0.2% at most.
  119. 'p_pixBottom: TPixmap imitating the pixmap drawn first, behind the top pixmap
  120. 'p_pixTop: TPixmap imitating the pixmap drawn second, on top of the first pixmap
  121. 'p_intAlpha: Optional. Value between 0 and 255 indicating transparency in addition to any transparency already in the image. Imitates SetAlpha(a/255) command. Only effects the top pixmap.
  122. 'p_intStainRed, p_intStainGreen, and p_intStainBlue: Optional. values between 0 and 255 indicating the colorization to be added to the image. Imitates SetColor(r, g, b) command. Only effects the top pixmap.
  123. 'p_intHorizontalOffset and p_intVerticalOffset: Optional. Shifts the top pixmap horizontally and vertically relative to the bottom pixmap. Negative values can be specified. Any areas of the top pixmap that are beyond the width or height of the bottom pixmap will be clipped off.
  124. 'p_blnFlipVertical and p_blnMirrorHorizontal: Optional. If "True", the image will be flipped about the X-axis and Y-axis, respectivly. Imitates XFlipPixmap() and YFlipPixmap() commands. only efects the top pixmap.
  125. 'p_intRotaiton: Optional. Values of 90, 180, or 270 will rotate the image by 90 degrees, 180 degrees, and 270 degrees, respectivly. Imitates SetRotation() command. Value must be a multiple of 90. Only effects the top pixmap.
  126. Function StackPixmapsFast:TPixmap(p_pixBottom:TPixmap, p_pixTop:TPixmap, p_intAlpha:Int = 255, p_intStainRed:Int = 255, p_intStainGreen:Int = 255, p_intStainBlue:Int = 255, p_intHorizontalOffset:Int = 0, p_intVerticalOffset:Int = 0, p_blnFlipVertical:Byte = False, p_blnMirrorHorizontal:Byte = False, p_intRotation:Int = 0)
  127.         'Initialize variables
  128.         Local intLoopX:Int, intLoopY:Int
  129.         Local intOffsetX:Int, intOffsetY:Int, intInverseAlphaRatio:Int
  130.        
  131.         Local intTopPixel:Int, intTopRed:Int, intTopGreen:Int, intTopBlue:Int, intTopAlpha:Int
  132.         Local intBottomPixel:Int, intBottomRed:Int, intBottomGreen:Int, intBottomBlue:Int, intBottomAlpha:Int
  133.         Local intCompositePixel:Int, intCompositeRed:Int, intCompositeGreen:Int, intCompositeBlue:Int, intCompositeAlpha:Int
  134.        
  135.         Local intFMR:Int = FMRIndex(p_blnFlipVertical, p_blnMirrorHorizontal, p_intRotation)
  136.         Local intMaxX:Int = p_pixTop.Width - 1
  137.         Local intMaxY:Int = p_pixTop.Height - 1
  138.         Local intBoundsWidth:Int = p_pixBottom.Width
  139.         Local intBoundsHeight:Int = p_pixBottom.Height
  140.         Local pixComposite:TPixmap = p_pixBottom.Copy()
  141.  
  142.         'Loop through each pixel
  143.         For intLoopX = 0 To intMaxX
  144.                 For intLoopY = 0 To intMaxY
  145.  
  146.                         'calculate offset location for later reference
  147.                         intOffsetX = intLoopX + p_intHorizontalOffset
  148.                         intOffsetY = intLoopY + p_intVerticalOffset
  149.  
  150.                         'skip this pixel if it lies outside the boundaries of the bottom pixmap
  151.                         If intOffsetX < intBoundsWidth And intOffsetY < intBoundsHeight And intOffsetX >= 0 And intOffsetY >= 0
  152.  
  153.                                 'Get the top pixel at the current location, taking into account flip, mirror and rotation
  154.                                 Select intFMR
  155.                                         Case 0
  156.                                                 intTopPixel = p_pixTop.ReadPixel(intLoopX, intLoopY)
  157.  
  158.                                         Case 1
  159.                                                 intTopPixel = p_pixTop.ReadPixel(intMaxX - intLoopX, intLoopY)
  160.  
  161.                                         Case 2
  162.                                                 intTopPixel = p_pixTop.ReadPixel(intLoopX, intMaxY - intLoopY)
  163.  
  164.                                         Case 3
  165.                                                 intTopPixel = p_pixTop.ReadPixel(intMaxX - intLoopX, intMaxY - intLoopY)
  166.  
  167.                                         Case 4
  168.                                                 intTopPixel = p_pixTop.ReadPixel(intLoopY, intMaxX - intLoopX)
  169.  
  170.                                         Case 5
  171.                                                 intTopPixel = p_pixTop.ReadPixel(intMaxY - intLoopY, intLoopX)
  172.  
  173.                                         Case 6
  174.                                                 intTopPixel = p_pixTop.ReadPixel(intMaxY - intLoopY, intMaxX - intLoopX)
  175.  
  176.                                         Default '7
  177.                                                 intTopPixel = p_pixTop.ReadPixel(intLoopY, intLoopX)
  178.                                 EndSelect
  179.  
  180.                                 'Split pixel into Alpha channel
  181.                                 intTopAlpha = (intTopPixel Shr 24) & $FF
  182.  
  183.                                 'if no alpha or stain modifications are being done and the top pixel is totally opaque, there is no need to composite pixels
  184.                                 If (intTopAlpha & p_intStainRed & p_intStainGreen & p_intStainBlue & p_intAlpha) = 255
  185.                                         pixComposite.WritePixel(intOffsetX, intOffsetY, intTopPixel)
  186.                                 Else
  187.                                         'Split pixel into Red, Green, and Blue channels
  188.                                         intTopRed = ((intTopPixel Shr 16) & $FF)
  189.                                         intTopGreen = ((intTopPixel Shr 8) & $FF)
  190.                                         intTopBlue = (intTopPixel & $FF)
  191.  
  192.                                         'add color stain and alpha modification
  193.                                         If p_intAlpha < 255 Then intTopAlpha = (intTopAlpha * (p_intAlpha + 1)) Shr 8
  194.                                         If p_intStainRed < 255 Then intTopRed = (intTopRed * (p_intStainRed + 1)) Shr 8
  195.                                         If p_intStainGreen < 255 Then intTopGreen = (intTopGreen * (p_intStainGreen + 1)) Shr 8
  196.                                         If p_intStainBlue < 255 Then intTopBlue = (intTopBlue * (p_intStainBlue + 1)) Shr 8
  197.  
  198.                                         'Get the bottom pixel at the offset location
  199.                                         intBottomPixel = p_pixBottom.ReadPixel(intOffsetX, intOffsetY)
  200.  
  201.                                         'Split pixel into Alpha channel
  202.                                         intBottomAlpha = (intBottomPixel Shr 24) & $FF
  203.  
  204.                                         'if bottom pixel is totally transparent, there is no need to composite pixels
  205.                                         If intBottomAlpha = 0
  206.                                                 pixComposite.WritePixel(intOffsetX, intOffsetY, (intTopAlpha Shl 24) | (intTopRed Shl 16) | (intTopGreen Shl 8) | intTopBlue)
  207.                                         Else
  208.                                                 'precalculate alpha ratios
  209.                                                 intInverseAlphaRatio = (intTopAlpha ~ $FF)
  210.  
  211.                                                 'Split pixel into Red, Green, and Blue channels
  212.                                                 intBottomRed = ((intBottomPixel Shr 16) & $FF) + 1
  213.                                                 intBottomGreen = ((intBottomPixel Shr 8) & $FF) + 1
  214.                                                 intBottomBlue = (intBottomPixel & $FF) + 1
  215.  
  216.                                                 'Perform alpha-composite
  217.                                                 intCompositeRed = ((intInverseAlphaRatio * intBottomRed) + (intTopAlpha * intTopRed)) Shr 8
  218.                                                 intCompositeGreen = ((intInverseAlphaRatio * intBottomGreen) + (intTopAlpha * intTopGreen)) Shr 8
  219.                                                 intCompositeBlue = ((intInverseAlphaRatio * intBottomBlue) + (intTopAlpha * intTopBlue)) Shr 8
  220.                                                 intCompositeAlpha = (intInverseAlphaRatio * intBottomAlpha) + intTopAlpha
  221.  
  222.                                                 'combine all channels back into a pixel and write it to the composite pixmap
  223.                                                 pixComposite.WritePixel(intOffsetX, intOffsetY, (intCompositeAlpha Shl 24) | (intCompositeRed Shl 16) | (intCompositeGreen Shl 8) | intCompositeBlue)
  224.                                         EndIf
  225.                                 EndIf
  226.                         EndIf
  227.                 Next
  228.         Next
  229.         Return pixComposite
  230. EndFunction
  231.  
  232. 'Since some combinations of XFlip, YFlip and Rotation are equivalent, this function returns the index for the simplest combination of the three for faster processing.
  233. 'p_blnFlipVertical: If "True", indicates a flip about the X-axis.
  234. 'p_blnMirrorHorizontal: If "True", indicates a flip about the Y-axis.
  235. 'p_intRotation: Indicates a rotation by the specified amount in degrees. Angle must be 0, 90, 180 or 270. Any other angles default to 270 degrees.
  236. Function FMRIndex:Int(p_blnFlipVertical:Byte = False, p_blnMirrorHorizontal:Byte = False, p_intRotation:Int = 0)
  237.         If p_blnFlipVertical
  238.                 If p_blnMirrorHorizontal
  239.                         Select p_intRotation
  240.                                 Case 0
  241.                                         'Flip + Mirror = Rotate 180 Degrees
  242.                                         Return 3
  243.  
  244.                                 Case 90
  245.                                         'Flip + Mirror + Rotate 90 degrees = Rotate 270 degrees
  246.                                         Return 5
  247.  
  248.                                 Case 180
  249.                                         'Flip + Mirror + Rotate 180 degrees = Nothing
  250.                                         Return 0
  251.  
  252.                                 Default '270
  253.                                         'Flip + Mirror + Rotate 270 degrees = Rotate 90 degrees
  254.                                         Return 4
  255.                         EndSelect
  256.                 Else
  257.                         Select p_intRotation
  258.                                 Case 0
  259.                                         'Flip = Mirror + Rotate 180 Degrees
  260.                                         Return 2
  261.  
  262.                                 Case 90
  263.                                         'Flip + Rotate 90 degrees = Mirror + Rotate 270 degrees
  264.                                         Return 7
  265.  
  266.                                 Case 180
  267.                                         'Flip + Rotate 180 degrees = Mirror
  268.                                         Return 1
  269.  
  270.                                 Default '270
  271.                                         'Flip + Rotate 270 degrees = Mirror + Rotate 90 degrees
  272.                                         Return 6
  273.                         EndSelect
  274.                 EndIf
  275.         Else
  276.                 If p_blnMirrorHorizontal
  277.                         Select p_intRotation
  278.                                 Case 0
  279.                                         'Mirror = Flip + Rotate 180 degrees
  280.                                         Return 1
  281.  
  282.                                 Case 90
  283.                                         'Mirror + Rotate 90 Degrees = Flip + Rotate 270 degrees
  284.                                         Return 6
  285.  
  286.                                 Case 180
  287.                                         'Mirror + Rotate 180 Degrees = Flip
  288.                                         Return 2
  289.  
  290.                                 Default '270
  291.                                         'Mirror + Rotate 270 Degrees = Flip + Rotate 90 degrees
  292.                                         Return 7
  293.                         EndSelect
  294.                 Else
  295.                         Select p_intRotation
  296.                                 Case 0
  297.                                         'Nothing = Flip + Mirror + Rotate 180 degrees
  298.                                         Return 0
  299.  
  300.                                 Case 90
  301.                                         'Rotate 90 Degrees = Flip + Mirror + Rotate 270 degrees
  302.                                         Return 4
  303.  
  304.                                 Case 180
  305.                                         'Rotate 180 Degrees = Flip + Mirror
  306.                                         Return 3
  307.  
  308.                                 Default '270
  309.                                         'Rotate 270 Degrees = Flip + Mirror + Rotate 90 degrees
  310.                                         Return 5
  311.                         EndSelect
  312.                 EndIf
  313.         EndIf
  314. EndFunction


Comments : none...

 

SimplePortal 2.3.6 © 2008-2014, SimplePortal