Method: Magick::Image#wet_floor

Defined in:
ext/RMagick/rmimage.cpp

#wet_floor(initial = 0.5, rate = 1.0) ⇒ Magick::Image

Creates a “wet floor” reflection. The reflection is an inverted copy of the image that changes from partially transparent to entirely transparent. By default only the bottom third of the image appears in the reflection.

Returns a new image.

Parameters:

  • initial (Numeric) (defaults to: 0.5)

    A value between 0.0 and 1.0 that specifies the initial percentage of transparency. Higher values cause the top of the reflection to be more transparent, lower values less transparent. The default is 0.5, which means that the top of the reflection is 50% transparent.

  • rate (Numeric) (defaults to: 1.0)

    A non-negative value that specifies how rapidly the reflection transitions from the initial level of transparency to entirely transparent. The default value is 1.0, which means that the transition occurs in 1/3 the image height. Values greater than 1.0 speed up the transition (the reflection will have fewer rows), values lower than 1.0 slow down the transition (the reflection will have more rows). A value of 0.0 means that the level of transparency will not change.

Returns:

See Also:



15637
15638
15639
15640
15641
15642
15643
15644
15645
15646
15647
15648
15649
15650
15651
15652
15653
15654
15655
15656
15657
15658
15659
15660
15661
15662
15663
15664
15665
15666
15667
15668
15669
15670
15671
15672
15673
15674
15675
15676
15677
15678
15679
15680
15681
15682
15683
15684
15685
15686
15687
15688
15689
15690
15691
15692
15693
15694
15695
15696
15697
15698
15699
15700
15701
15702
15703
15704
15705
15706
15707
15708
15709
15710
15711
15712
15713
15714
15715
15716
15717
15718
15719
15720
15721
15722
15723
15724
15725
15726
15727
15728
15729
15730
15731
15732
15733
15734
15735
15736
15737
15738
15739
15740
15741
15742
15743
15744
15745
15746
15747
15748
15749
15750
15751
15752
15753
15754
15755
15756
15757
15758
15759
15760
15761
15762
15763
15764
15765
15766
15767
15768
15769
15770
15771
15772
15773
15774
15775
15776
15777
15778
15779
15780
15781
15782
15783
15784
15785
15786
15787
15788
15789
15790
15791
15792
15793
15794
15795
15796
15797
15798
15799
15800
15801
15802
# File 'ext/RMagick/rmimage.cpp', line 15637

VALUE
Image_wet_floor(int argc, VALUE *argv, VALUE self)
{
    Image *image, *reflection, *flip_image;
#if defined(IMAGEMAGICK_7)
    const Quantum *p;
    Quantum *q;
#else
    const PixelPacket *p;
    PixelPacket *q;
#endif
    RectangleInfo geometry;
    long x, y, max_rows;
    double initial = 0.5;
    double rate = 1.0;
    double opacity, step;
    const char *func;
    ExceptionInfo *exception;

    image = rm_check_destroyed(self);
    switch (argc)
    {
        case 2:
            rate = NUM2DBL(argv[1]);
        case 1:
            initial = NUM2DBL(argv[0]);
        case 0:
            break;
        default:
            rb_raise(rb_eArgError, "wrong number of arguments (%d for 0 to 2)", argc);
            break;
    }


    if (initial < 0.0 || initial > 1.0)
    {
        rb_raise(rb_eArgError, "Initial transparency must be in the range 0.0-1.0 (%g)", initial);
    }
    if (rate < 0.0)
    {
        rb_raise(rb_eArgError, "Transparency change rate must be >= 0.0 (%g)", rate);
    }

#if defined(IMAGEMAGICK_7)
    initial *= QuantumRange;
#else
    initial *= TransparentOpacity;
#endif

    // The number of rows in which to transition from the initial level of
    // transparency to complete transparency. rate == 0.0 -> no change.
    if (rate > 0.0)
    {
        max_rows = (long)((double)image->rows) / (3.0 * rate);
        max_rows = (long)min((unsigned long)max_rows, image->rows);
#if defined(IMAGEMAGICK_7)
        step =  (QuantumRange - initial) / max_rows;
#else
        step =  (TransparentOpacity - initial) / max_rows;
#endif
    }
    else
    {
        max_rows = (long)image->rows;
        step = 0.0;
    }


    exception = AcquireExceptionInfo();
    GVL_STRUCT_TYPE(FlipImage) args_FlipImage = { image, exception };
    flip_image = (Image *)CALL_FUNC_WITHOUT_GVL(GVL_FUNC(FlipImage), &args_FlipImage);
    CHECK_EXCEPTION();


    geometry.x = 0;
    geometry.y = 0;
    geometry.width = image->columns;
    geometry.height = max_rows;
    GVL_STRUCT_TYPE(CropImage) args_CropImage = { flip_image, &geometry, exception };
    reflection = (Image *)CALL_FUNC_WITHOUT_GVL(GVL_FUNC(CropImage), &args_CropImage);
    DestroyImage(flip_image);
    CHECK_EXCEPTION();


#if defined(IMAGEMAGICK_7)
    GVL_STRUCT_TYPE(SetImageStorageClass) args_SetImageStorageClass = { reflection, DirectClass, exception };
    CALL_FUNC_WITHOUT_GVL(GVL_FUNC(SetImageStorageClass), &args_SetImageStorageClass);
    rm_check_exception(exception, reflection, DestroyOnError);
    GVL_STRUCT_TYPE(SetImageAlphaChannel) args_SetImageAlphaChannel = { reflection, ActivateAlphaChannel, exception };
    CALL_FUNC_WITHOUT_GVL(GVL_FUNC(SetImageAlphaChannel), &args_SetImageAlphaChannel);
    rm_check_exception(exception, reflection, DestroyOnError);
#else
    GVL_STRUCT_TYPE(SetImageStorageClass) args_SetImageStorageClass = { reflection, DirectClass };
    CALL_FUNC_WITHOUT_GVL(GVL_FUNC(SetImageStorageClass), &args_SetImageStorageClass);
    rm_check_image_exception(reflection, DestroyOnError);


    reflection->matte = MagickTrue;
#endif
    opacity = initial;

    for (y = 0; y < max_rows; y++)
    {
#if defined(IMAGEMAGICK_7)
        if (opacity > QuantumRange)
        {
            opacity = QuantumRange;
        }
#else
        if (opacity > TransparentOpacity)
        {
            opacity = TransparentOpacity;
        }
#endif

        GVL_STRUCT_TYPE(GetVirtualPixels) args_GetVirtualPixels = { reflection, 0, y, image->columns, 1, exception };
        void *ret = CALL_FUNC_WITHOUT_GVL(GVL_FUNC(GetVirtualPixels), &args_GetVirtualPixels);
        p = reinterpret_cast<decltype(p)>(ret);
        rm_check_exception(exception, reflection, DestroyOnError);
        if (!p)
        {
            func = "AcquireImagePixels";
            goto error;
        }

        q = QueueAuthenticPixels(reflection, 0, y, image->columns, 1, exception);

        rm_check_exception(exception, reflection, DestroyOnError);
        if (!q)
        {
            func = "SetImagePixels";
            goto error;
        }

        for (x = 0; x < (long) image->columns; x++)
        {
            // Never make a pixel *less* transparent than it already is.
#if defined(IMAGEMAGICK_7)
            *q = *p;
            SetPixelAlpha(reflection, min(GetPixelAlpha(image, q), QuantumRange - (Quantum)opacity), q);

            p += GetPixelChannels(reflection);
            q += GetPixelChannels(reflection);
#else
            q[x] = p[x];
            q[x].opacity = max(q[x].opacity, (Quantum)opacity);
#endif
        }

        GVL_STRUCT_TYPE(SyncAuthenticPixels) args_SyncAuthenticPixels = { reflection, exception };
        CALL_FUNC_WITHOUT_GVL(GVL_FUNC(SyncAuthenticPixels), &args_SyncAuthenticPixels);
        rm_check_exception(exception, reflection, DestroyOnError);

        opacity += step;
    }


    DestroyExceptionInfo(exception);
    return rm_image_new(reflection);

    error:
    DestroyExceptionInfo(exception);
    DestroyImage(reflection);
    rb_raise(rb_eRuntimeError, "%s failed on row %lu", func, y);
    return(VALUE)0;
}