[ENH]Translucent images in 8 and 16 bit screen resolution

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

[ENH]Translucent images in 8 and 16 bit screen resolution

karl-8
Images with alpha translucency will now keep the translucency in 8 and
16 bit screen resolution. (Rotated forms will not, that has to do with
WarpBlt internals I don't really understand yet.) It would be nice if
people could play with this enhancement and report any issues.
Karl

'From OLPC2.0 of ''24 October 2006'' [latest update: #1141] on 15 December 2006 at 3:09:23 pm'!

!Canvas methodsFor: 'drawing-images' stamp: 'kfr 12/15/2006 14:54'!
translucentImage: aForm at: aPoint sourceRect: sourceRect
        "Draw a translucent image using the best available way of representing translucency.
        Note: This will be fixed in the future."
        self shadowColor ifNotNil:[
                ^self stencil: aForm at: aPoint sourceRect: sourceRect color: self shadowColor].
        (self depth < 32 and:[aForm depth > 16])
                ifTrue:[^self image: aForm at: aPoint sourceRect: sourceRect rule: 34].
        (self depth < 32 or:[aForm isTranslucent not])
                ifTrue:[^self paintImage: aForm at: aPoint sourceRect: sourceRect].
        self image: aForm
                at: aPoint
                sourceRect: sourceRect
                rule: Form blend! !



Reply | Threaded
Open this post in threaded view
|

Re: [ENH]Translucent images in 8 and 16 bit screen resolution

Andreas.Raab
karl wrote:
> Images with alpha translucency will now keep the translucency in 8 and
> 16 bit screen resolution. (Rotated forms will not, that has to do with
> WarpBlt internals I don't really understand yet.) It would be nice if
> people could play with this enhancement and report any issues.

Sorry to say that but the proposed fix is incorrect. Form>>blend (the
operator used by #translucentImage:at:) computes the blend of source and
destination color using:

    srcAlpha*srcColor + (1-srcAlpha)*dstColor

while rule 34 computes it based on the following formula:

    srcColor + (1-srcAlpha)*dstColor

In other words, rule 34 assumes that the input is premultiplied, i.e.,
the color components for each pixel are in the range of (0..alpha). The
difference can be seen in the following:

        "Go to 32 bpp for the demonstration"
        Display newDepth: 32.
        World color: Color red.

        "Create a regular alpha (0-255 saturated) form"
        formA := Form extent: 200@200 depth: 32.
        formA fillColor: (Color white alpha: 0.5).
        formA displayAt: 0@0. "shows as white"

        "Convert formA to pre-multiplied"
        formB := Form extent: formA extent depth: 32.
        formA displayOn: formB at: 0@0 rule: Form blend.
        formB displayAt: 200@0. "shows as gray since it's premultiplied"

        "Show the both forms using Form>>blend"
        formA displayOn: Display at: 0@200 rule: Form blend.
        formB displayOn: Display at: 200@200 rule: Form blend.

        "Show the both forms using rule 34"
        formA displayOn: Display at: 0@400 rule: 34.
        formB displayOn: Display at: 200@400 rule: 34.

Notice how Form>>blend is the correct combination rule for blending a
50% white with the red background for the regular form and rule 34 is
the correct combination rule for the pre-multiplied blend. But neither
is correct for the "other" form. In other words, you can't mix the two;
you need to know whether to expect pre-multiplied alpha or not, and
#translucentImage:at: does NOT expect pre-multiplied alpha.

The way to fix that is by either converting the input form into
pre-multiplied form first (as shown in the above) the cost of which is
the obvious memory hit or by writing other custom BitBlt methods just
like for rule 34 (only for using the regular Form>>blend operator).

Cheers,
   - Andreas

Reply | Threaded
Open this post in threaded view
|

Re: [ENH]Translucent images in 8 and 16 bit screen resolution

karl-8
Andreas Raab skrev:

> karl wrote:
>> Images with alpha translucency will now keep the translucency in 8
>> and 16 bit screen resolution. (Rotated forms will not, that has to do
>> with WarpBlt internals I don't really understand yet.) It would be
>> nice if people could play with this enhancement and report any issues.
>
> Sorry to say that but the proposed fix is incorrect. Form>>blend (the
> operator used by #translucentImage:at:) computes the blend of source
> and destination color using:
>
>    srcAlpha*srcColor + (1-srcAlpha)*dstColor
>
> while rule 34 computes it based on the following formula:
>
>    srcColor + (1-srcAlpha)*dstColor
>
> In other words, rule 34 assumes that the input is premultiplied, i.e.,
> the color components for each pixel are in the range of (0..alpha).
> The difference can be seen in the following:
>
>     "Go to 32 bpp for the demonstration"
>     Display newDepth: 32.
>     World color: Color red.
>
>     "Create a regular alpha (0-255 saturated) form"
>     formA := Form extent: 200@200 depth: 32.
>     formA fillColor: (Color white alpha: 0.5).
>     formA displayAt: 0@0. "shows as white"
>
>     "Convert formA to pre-multiplied"
>     formB := Form extent: formA extent depth: 32.
>     formA displayOn: formB at: 0@0 rule: Form blend.
>     formB displayAt: 200@0. "shows as gray since it's premultiplied"
>
>     "Show the both forms using Form>>blend"
>     formA displayOn: Display at: 0@200 rule: Form blend.
>     formB displayOn: Display at: 200@200 rule: Form blend.
>
>     "Show the both forms using rule 34"
>     formA displayOn: Display at: 0@400 rule: 34.
>     formB displayOn: Display at: 200@400 rule: 34.
>
> Notice how Form>>blend is the correct combination rule for blending a
> 50% white with the red background for the regular form and rule 34 is
> the correct combination rule for the pre-multiplied blend. But neither
> is correct for the "other" form. In other words, you can't mix the
> two; you need to know whether to expect pre-multiplied alpha or not,
> and #translucentImage:at: does NOT expect pre-multiplied alpha.
>
> The way to fix that is by either converting the input form into
> pre-multiplied form first (as shown in the above) the cost of which is
> the obvious memory hit or by writing other custom BitBlt methods just
> like for rule 34 (only for using the regular Form>>blend operator).
>
> Cheers,
>   - Andreas
>
>
I knew it was to easy ;-)
I'll see if I can manage to hack together a new Form>> blend rule...
Karl

Reply | Threaded
Open this post in threaded view
|

[ENH]Translucent images in 8 and 16 bit screen resolution version 2

karl-8
In reply to this post by Andreas.Raab
Andreas Raab skrev:
> karl wrote:
>> Images with alpha translucency will now keep the translucency in 8
>> and 16 bit screen resolution. (Rotated forms will not, that has to do
>> with WarpBlt internals I don't really understand yet.) It would be
>> nice if people could play with this enhancement and report any issues.
> The way to fix that is by either converting the input form into
> pre-multiplied form first (as shown in the above) the cost of which is
> the obvious memory hit or by writing other custom BitBlt methods just
> like for rule 34 (only for using the regular Form>>blend operator).
Here is a version which pre-multiply the forms and results with colors
are much better :-)

In the first version I  was testing using a black circle which blurred
to transparent so I did not catch obvious color errors.

I have also added a enhancement to preserve translucency when a morph is
rotated, this works only in 32 bit screen resolution for the time being.

Karl

'From OLPC2.0 of ''24 October 2006'' [latest update: #1141] on 17 December 2006 at 11:42:34 pm'!
"Change Set: FormTranslucency
Date: 17 December 2006
Author: Karl Ramberg

Project to make translucency work in different screen resolutions and with rotated morphs "!


!Canvas methodsFor: 'drawing-images' stamp: 'kfr 12/17/2006 23:35'!
translucentImage: aForm at: aPoint sourceRect: sourceRect
        "Draw a translucent image using the best available way of representing translucency.
        Note: This will be fixed in the future."
        | multipliedForm |
        self shadowColor ifNotNil:[
                ^self stencil: aForm at: aPoint sourceRect: sourceRect color: self shadowColor].
        ((self depth < 32 and:[aForm depth = 32]) and:[self depth > 4])
                ifTrue:[
    "Convert aForm to pre-multiplied"
    multipliedForm := Form extent: aForm extent depth: 32.
    aForm displayOn: multipliedForm at: 0@0 rule: Form blend.
    ^self image: multipliedForm at: aPoint sourceRect: sourceRect rule: 34].
        (self depth < 32 or:[aForm isTranslucent not])
                ifTrue:[^self paintImage: aForm at: aPoint sourceRect: sourceRect].
        self image: aForm
                at: aPoint
                sourceRect: sourceRect
                rule: Form blend! !


!FormCanvas methodsFor: 'drawing-support' stamp: 'kfr 12/17/2006 23:39'!
transformBy: aDisplayTransform clippingTo: aClipRect during: aBlock smoothing: cellSize

        "Note: This method has been originally copied from TransformationMorph."
        | innerRect patchRect sourceQuad warp start subCanvas |
        (aDisplayTransform isPureTranslation) ifTrue:[
                ^aBlock value: (self copyOffset: aDisplayTransform offset negated truncated
                                                        clipRect: aClipRect)
        ].
        "Prepare an appropriate warp from patch to innerRect"
        innerRect _ aClipRect.
        patchRect _ (aDisplayTransform globalBoundsToLocal: innerRect) truncated.
        sourceQuad _ (aDisplayTransform sourceQuadFor: innerRect)
                                        collect: [:p | p - patchRect topLeft].
        warp _ self warpFrom: sourceQuad toRect: innerRect.
        warp cellSize: cellSize.

        "Render the submorphs visible in the clipping rectangle, as patchForm"
        start _ (self depth = 1 and: [self isShadowDrawing not])
                "If this is true B&W, then we need a first pass for erasure."
                ifTrue: [1] ifFalse: [2].
        start to: 2 do:
                [:i | "If i=1 we first make a shadow and erase it for opaque whites in B&W"
                subCanvas _ self class extent: patchRect extent depth: self depth.
                i=1 ifTrue: [subCanvas shadowColor: Color black.
                                        warp combinationRule: Form erase]
                        ifFalse: [self isShadowDrawing ifTrue:
                                        [subCanvas shadowColor: self shadowColor].
                                        (self depth = 32) ifTrue:[warp combinationRule: 34]
                                        ifFalse:[warp combinationRule: Form paint]].
                subCanvas translateBy: patchRect topLeft negated
                        during:[:offsetCanvas| aBlock value: offsetCanvas].
                warp sourceForm: subCanvas form; warpBits.
                warp sourceForm: nil.  subCanvas _ nil "release space for next loop"]
! !