<p></p>
<p dir="auto">The <code class="notranslate">BitBlt</code> blending rule <code class="notranslate">Form blendAlphaScaled</code> (<code class="notranslate">34</code>) doesn't blend the colors <code class="notranslate">0x00000000</code> (source; fully transparent) and <code class="notranslate">0xFFFFFFFF</code> (destination; white) correctly. The output is <code class="notranslate">0xFEFEFEFE</code> (slightly transparent white), whereas it should be <code class="notranslate">0xFFFFFFFF</code> (fully opaque white).</p>
<p dir="auto">I think the problem lies in <a href="https://github.com/OpenSmalltalk/opensmalltalk-vm/blob/a45e38820e50ffe19ac61428df88ebcd724e67e8/src/plugins/BitBltPlugin/BitBltPlugin.c#L557">the implementation</a> of <code class="notranslate">BitBltSimulation>>#alphaBlendScaled:with:</code>. When calculating the summand containing the <code class="notranslate">destinationWord</code>, a right bit shift by <code class="notranslate">8</code> is performed to normalize the result after multiplying with <code class="notranslate">unAlpha</code> (semantically a division by <code class="notranslate">256</code>). However, <code class="notranslate">unAlpha</code> is in the range <code class="notranslate">0x00</code> - <code class="notranslate">0xFF</code> and thus a division by <code class="notranslate">0xFF = 255</code> should be used instead. I think that the other bit shifts by <code class="notranslate">8</code> in the function are ok, as they are only used to extract or compose certain bytes and not to (semantically) divide a value by <code class="notranslate">256</code>.</p>
<p dir="auto">This problem causes the described behavior, because the following computation is performed in each channel:<br>
<code class="notranslate">((0xFF * 0xFF) >> 8) + 0x00 = 0xFE01 >> 8 = 0xFE</code><br>
A division by <code class="notranslate">0xFF</code> produces the expected result:<br>
<code class="notranslate">((0xFF * 0xFF) / 0xFF) + 0x00 = 0xFE01 / 0xFF = 0xFF</code></p>
<p dir="auto">Code to reproduce:</p>
<pre class="notranslate"><code class="notranslate">| src dst |
src := (Form extent: 1 @ 1 depth: 1)
    colorAt: 0 @ 0 put: Color black; "transparency is applied with the fillColor:"
    yourself.
dst := (Form extent: 1 @ 1 depth: 32)
    colorAt: 0 @ 0 put: Color white; "16rFFFFFFFF"
    yourself.
dst
    copyBits: (0 @ 0 corner: 1 @ 1)
    from: src
    at: 0 @ 0
    clippingBox: (0 @ 0 corner: 1 @ 1)
    rule: Form blendAlphaScaled
    fillColor: Color transparent. "16r00000000"
(dst pixelValueAt: 0 @ 0) hex "16rFEFEFEFE"
</code></pre>
<p dir="auto">Notes:</p>
<ul dir="auto">
<li>I did not thoroughly test the proposed change, just calculated the result for the described case.</li>
<li>I am no expert in writing high performance code, but a potential improved implementation may not use a division but rather a more optimized combination of <code class="notranslate">+</code>, <code class="notranslate">*</code> and <code class="notranslate">>></code> to increase performance. A quick search on the internet shows some possible alternatives.</li>
<li>I read in the contribution guidelines, that the VM is developed in Smalltalk and the C code is only generated from the Smalltalk code. I did not have the time to set up a VM image and just looked into the C code to find the problem. I hope the problem description still helps.</li>
<li>The described behavior doesn't occur when blending two 32 bit <code class="notranslate">Form</code>s. I think this is due to <code class="notranslate">alphaSourceBlendBits32</code> being called in this case, which is optimized for edge cases with full or zero transparency and handles those correctly (it doesn't call <code class="notranslate">alphaBlendScaledwith</code>).</li>
</ul>

<p style="font-size:small;-webkit-text-size-adjust:none;color:#666;">—<br />Reply to this email directly, <a href="https://github.com/OpenSmalltalk/opensmalltalk-vm/issues/643">view it on GitHub</a>, or <a href="https://github.com/notifications/unsubscribe-auth/AIJPEW6KMESCZKJLXOPURLLVRX2EZANCNFSM52KOMWCQ">unsubscribe</a>.<br />You are receiving this because you are subscribed to this thread.<img src="https://github.com/notifications/beacon/AIJPEW6IG6PB764PGH5JVJDVRX2EZA5CNFSM52KOMWC2YY3PNVWWK3TUL52HS4DFUVEXG43VMWVGG33NNVSW45C7NFSM4THMN2ZQ.gif" height="1" width="1" alt="" /><span style="color: transparent; font-size: 0; display: none; visibility: hidden; overflow: hidden; opacity: 0; width: 0; height: 0; max-width: 0; max-height: 0; mso-hide: all">Message ID: <span><OpenSmalltalk/opensmalltalk-vm/issues/643</span><span>@</span><span>github</span><span>.</span><span>com></span></span></p>
<script type="application/ld+json">[
{
"@context": "http://schema.org",
"@type": "EmailMessage",
"potentialAction": {
"@type": "ViewAction",
"target": "https://github.com/OpenSmalltalk/opensmalltalk-vm/issues/643",
"url": "https://github.com/OpenSmalltalk/opensmalltalk-vm/issues/643",
"name": "View Issue"
},
"description": "View this Issue on GitHub",
"publisher": {
"@type": "Organization",
"name": "GitHub",
"url": "https://github.com"
}
}
]</script>