Some time ago Vitaliy Kaurov asked an interesting question about implementing in Mathematica so called "torn edge" effect in context of conveying a message perfectly formulated by Sjoerd C. de Vries: "There's more of this, but that's not important." As an answer Heike (a Mathematica.StackExchange community member) published an ingenious implementation which deservedly received a huge amount of upvotes. She not only implemented a "torn edge" effect but also provided an option to add a drop-down shadow in order to dramatize the effect. Here is what her function named torn
generates from the "Mandrill"
example image in Mathematica 8.0.4 (it doesn't work correctly in the recent versions due to an incompatible change in image processing functionality):
img = ExampleData[{"TestImage", "Mandrill"}];
torn[img, {{0, 1}, {1, 0}}, "offset" -> {20, 20}, "gaussianBlur" -> 10]
As Vitaliy recently pointed out, with the release of Mathematica 11.2 we've got a "TornFrame"
image effect immediately available via ImageEffect
function:
ImageEffect[img, {"TornFrame", Scaled[1/15], {Right, Bottom}, .05}]
But people at StackExchange quickly noticed that this effect doesn't produce a sufficiently irregular ripped-out edge, what means that the message that the image is truncated and "there is more of this, but that's not important" isn't exactly obvious (as opposed to the implementation provided by Heike). By spelunking the evaluation of ImageEffect
with Trace
I've found a simple hack allowing to generate a "Heike-style" torn edge effect:
tornEdge = Block[{Accumulate = RandomReal[1, Length[#]] &},
ImageEffect[img, {"TornFrame", Scaled[1/15], {Right, Bottom}, .08}]]
Further investigation showed that using new "Frame"
effect we can produce even more irregular torn edge using only documented functionality, but at the cost of sufficiently more lengthy code:
tornEdge2 = Module[{step = 10, if, n = 2 Total[ImageDimensions[img]], k = 0},
if = Interpolation[
Transpose[{Accumulate[Prepend[RandomInteger[{step, 2 step}, n], 0]],
RandomReal[1, n + 1]}],
InterpolationOrder -> 1];
ImageEffect[img, {"Frame", if[++k] &, 15, {Right, Bottom}}]]
Here is a simple approach allowing to obtain a semi-transparent shadow based on the new functionality. In addition I've added an option to add a darkened one-pixel wide boundary to the torned image:
shadowOffset = 10;
shadowBlur = 5;
shadowTone = .5;
boundaryLigntness = .4;
ImageCompose[
SetAlphaChannel[ColorNegate@#, #] &@
Blur[ImageMultiply[
ImagePad[AlphaChannel[
tornEdge], {{shadowOffset, shadowBlur/2}, {shadowBlur/2, shadowOffset}}],
shadowTone], shadowBlur],
ImagePad[ImageMultiply[tornEdge,
ColorNegate@
ImageMultiply[MorphologicalPerimeter@AlphaChannel[tornEdge], boundaryLigntness]], {{0,
shadowOffset + shadowBlur/2}, {shadowOffset + shadowBlur/2, 0}}]]
Any suggestions and comments are welcome!