Module ops

An assortment of useful image operations.

Most image resize logic comes courtesy of Jorge L Rodriguez (@VinoBS), via Sean Barrett's stb.

The Bytes type—specified below—may be any object that implements ByteReader, including strings.

Various routines build upon the Accelerate framework, Project Ne10, DirectXMath, and XMath.


(The comments that follow were adapted from stb_image_resize.h.)

Written with emphasis on usability, portability, and efficiency. (No SIMD or threads, so it's easily outperformed by libs that use those.) Only scaling and translation is supported, no rotations or shears. By default, the API downsamples with Mitchell filter, upsamples with cubic interpolation.

QUICKSTART

output_pixels = impack.ops.resize_custom(input_pixels, in_w, in_h,
                         out_w, out_h, num_channels)
output_pixels = impack.ops.resize_custom(input_pixels, in_w, in_h,
                         out_w, out_h, num_channels, { datatype = "FLOAT" })
output_pixels = impack.ops.resize_custom(input_pixels, in_w, in_h,
                         out_w, out_h, num_channels, { has_alpha = alpha_chan, space = "SRGB" })
output_pixels = impack.ops.resize_custom(input_pixels, in_w, in_h,
                         out_w, out_h, num_channels, {
                              has_alpha = alpha_chan, space = "SRGB",
                              wrap = "CLAMP" -- or "WRAP", "REFLECT", "ZERO"
                          })

Additional documentation:

SRGB & FLOATING POINT REPRESENTATION

The sRGB functions presume IEEE floating point.

ALPHA CHANNEL

Most of the resizing functions provide the ability to control how the alpha channel of an image is processed. The important things to know about this:

1. The best mathematically-behaved version of alpha to use is called "premultiplied alpha", in which the other color channels have had the alpha value multiplied in. If you use premultiplied alpha, linear filtering (such as image resampling done by this library, or performed in texture units on GPUs) does the "right thing". While premultiplied alpha is standard in the movie CGI industry, it is still uncommon in the videogame / real-time world.

If you linearly filter non-premultiplied alpha, strange effects occur. (For example, the average of 1% opaque bright green and 99% opaque black produces 50% transparent dark green when non-premultiplied, whereas premultiplied it produces 50% transparent near-black. The former introduces green energy that doesn't exist in the source image.)

2. Artists should not edit premultiplied-alpha images; artists want non-premultiplied alpha images. Thus, art tools generally output non-premultiplied alpha images.

3. You will get best results in most cases by converting images to premultiplied alpha before processing them mathematically.

4. If you pass the flag "ALPHA_PREMULTIPLIED", the resizer does not do anything special for the alpha channel; it is resampled identically to other channels. This produces the correct results for premultiplied-alpha images, but produces less-than-ideal results for non-premultiplied-alpha images.

5. If you do not pass the flag "ALPHA_PREMULTIPLIED", then the resizer weights the contribution of input pixels based on their alpha values, or, equivalently, it multiplies the alpha value into the color channels, resamples, then divides by the resultant alpha value. Input pixels which have alpha = 0 do not contribute at all to output pixels unless all of the input pixels affecting that output pixel have alpha = 0, in which case the result for that pixel is the same as it would be without "ALPHA_PREMULTIPLIED". However, this is only true for input images in integer formats. For input images in float format, input pixels with alpha = 0 have no effect, and output pixels which have alpha = 0 will be 0 in all channels. (For float images, you can manually achieve the same result by adding a tiny epsilon value to the alpha channel of every image, and then subtracting or clamping it at the end.)

6. You can separately control whether the alpha channel is interpreted as linear or affected by the colorspace. By default it is linear; you almost never want to apply the colorspace. (For example, graphics hardware does not apply sRGB conversion to the alpha channel.)

ADDITIONAL CONTRIBUTORS

Sean Barrett: API design, optimizations


From stb's project page:

This software is dual-licensed to the public domain and under the following license: you are granted a perpetual, irrevocable license to copy, modify, publish, and distribute this file as you see fit.


From NE10's license:

Copyright 2012-15 ARM Limited and Contributors. All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  • Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

  • Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

  • Neither the name of ARM Limited nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY ARM LIMITED AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ARM LIMITED AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

See: BSD-3-Clause for template


Functions

box_filter (input, input_w, input_h, kernel_w, kernel_h, opts)
Given some image data, find the results of applying a box filter to it.

On iPhone and capable Android devices, this will use a NEON-optimized routine when both kernel dimensions are between 2 and 127, inclusive. Mac and tvOS use an Accelerate framework routine.

Parameters:

  • input Bytes Input image, in RGBA form.
  • input_w uint Width of input...
  • input_h uint ...and height.
  • kernel_w uint Width of kernel, from 1 to input_w... (The Accelerate technique will adjust this, if necessary.)
  • kernel_h uint ...and height, from 1 to input_h. (Ditto.)
  • opts optional table

    Filter options, which include:

    • in_stride: Bytes per row on input image (w * 4 by default, the minimum)...
    • out_stride: ...and on output image (again, defaults to w * 4).
    • as_userdata: Affects how the image data is returned.

Returns:

    Bytes On success, output of the box filter, in RGBA form.

    If opts.as_userdata was true, the data is returned as a userdata that implements ByteReader, rather than being converted to a more friendly string. Under some circumstances, this might be worth doing for performance reasons.

Or

  1. nil, indicating an error.
  2. string Error message.
floats_to_unorm8s (input, w, h, opts)
Converts an image from to floating-point to normalized unsigned 8-bit form, i.e. floats in [0, 1] are remapped to [0, 255].

Parameters:

  • input Bytes Input image, in floating-point form.
  • w uint Width of input...
  • h uint ...and height.
  • opts optional table Conversion options. At the moment, the only option is channels, describing the number of channels per pixel (by default 4, in keeping with RGBA).

Returns:

    Bytes On success, the converted result, in normalized unsigned 8-bit form.

Or

  1. nil, indicating an error.
  2. string Error message.

See also:

resize_custom (input, iw, ih, ow, oh, nchannels, opts)
Generalized variant of resize_rgb and resize_rgba.

Parameters:

  • input Bytes Input image, in nchannels-per-pixel form, according to datatype.
  • iw uint Input image width...
  • ih uint ...and height.
  • ow uint Output image width...
  • oh uint ...and height.
  • nchannels uint Number of color channels.
  • opts optional table

    Resize options. These include all the options from box_filter, though the strides default to w * nchannels * bytes_per_component(datatype).

    Additionally, the following are available:

    • flags: May be a string or array of strings, consisting of entries from ResizeFlags. If unsure what these mean, leaving them blank will probably do the right thing.
    • has_alpha: If true, the image has an alpha channel. This may be an integer between 1 and nchannels, inclusive, indicating which channel to treat as alpha. Otherwise, the index is assumed to be nchannels. (No alpha is the default.)
    • datatype: May be one of the DataType entries (a string), indicating the component data type. Defaults to "UINT8".
    • wrap: May be one of the EdgeMode entries (a string), indicating the edge-sampling behavior. Defaults to "CLAMP".
    • hwrap: If present, an EdgeMode entry (that overrides wrap) describing horizontal behavior...
    • vwrap: ...likewise, for vertical edge-sampling.
    • filter: May be one of the Filter entries (a string), indicating the color filtering behavior. Naturally, "DEFAULT" is the default.
    • hfilter: If present, a Filter entry (that overrides filter) describing horizontal behavior...
    • vfilter: ...likewise, for vertical filtering.
    • space: May be one of the ColorSpace entries (a string), describing how colors are understood. By default, "LINEAR".

Returns:

    Bytes On success, as per box_filter; will match input in form.

Or

  1. nil, indicating an error.
  2. string Error message.
resize_region (input, iw, ih, ow, oh, nchannels, s0, t0, s1, t1, opts)
Variant of resize_custom that allows you to specify the image source tile using texture coordinates, i.e. (s0, t0) and (s1, t1) are the top-left and bottom-right corner (uv addressing style: [0, 1] × [0, 1]) of a region of the input image to use.

Parameters:

  • input Bytes As per resize_custom.
  • iw uint Input image width...
  • ih uint ...and height.
  • ow uint Output image width...
  • oh uint ...and height.
  • nchannels uint Number of color channels.
  • s0 number Upper-left coordinate, u-component...
  • t0 number ...and v-component.
  • s1 number Bottom-right coordinate, u-component...
  • t1 number ...and v-component.
  • opts optional table As per resize_custom.

Returns:

    Bytes On success, as per box_filter; will match input in form.

Or

  1. nil, indicating an error.
  2. string Error message.
resize_rgb (input, iw, ih, ow, oh, nchannels, opts)
Given some image data, find the results of performing a resize, using the default filter.

Parameters:

  • input Bytes Input image, in RGB form.
  • iw uint Input image width...
  • ih uint ...and height.
  • ow uint Output image width...
  • oh uint ...and height.
  • nchannels uint Number of color channels.
  • opts optional table Resize options, as per box_filter (although strides default to w * 3, instead).

Returns:

    Bytes On success, as per box_filter; output will be in RGB form.

Or

  1. nil, indicating an error.
  2. string Error message.
resize_rgba (input, iw, ih, ow, oh, opts)
Given some image data, find the results of performing a resize, using bilinear filtering.

Parameters:

  • input Bytes Input image, in RGBA form.
  • iw uint Input image width...
  • ih uint ...and height.
  • ow uint Output image width...
  • oh uint ...and height.
  • opts optional table Resize options, as per box_filter.

Returns:

    Bytes On success, as per box_filter; output will be in RGBA form.

Or

  1. nil, indicating an error.
  2. string Error message.
resize_subpixel (input, iw, ih, ow, oh, nchannels, xscale, yscale, xoff, yoff, opts)
Variant of resize_custom that takes an explicit scale for subpixel correctness.

Parameters:

  • input Bytes As per resize_custom.
  • iw uint Input image width...
  • ih uint ...and height.
  • ow uint Output image width...
  • oh uint ...and height.
  • nchannels uint Number of color channels.
  • xscale number Scale factor along x-axis... (For some sense of the numbers, resize_region could be emulated by setting this to (ow / iw) / (s1 - s0)...)
  • yscale number ...and y-axis. (...this to (oh / ih) / (t1 - t0)...)
  • xoff number Offset along x-axis, to upper-left corner... (...this to s0 * ow / (s1 - s0)...)
  • yoff number ...and y-axis. (...and this to t0 * oh / (t1 - t0).)
  • opts optional table As per resize_custom.

Returns:

    Bytes On success, as per box_filter; will match input in form.

Or

  1. nil, indicating an error.
  2. string Error message.
rotate (input, w, h, angle, opts)
Given some image data, find the results of performing rotation.

Any non-trivial rotation will leave gaps. Unwritten pixels will be transparent.

Parameters:

  • input Bytes Input image, in RGBA form.
  • w uint Width of input...
  • h uint ...and height.
  • angle number Rotation angle, in radians.
  • opts optional table Rotate options, as per box_filter.

Returns:

  1. Bytes On success, as per box_filter.
  2. uint Width, after rotation...
  3. uint ...and height.

Or

  1. nil, indicating an error.
  2. string Error message.
unorm8s_to_floats (input, w, h, opts)
Converts an image from normalized unsigned 8-bit to floating-point form, i.e. unsigned bytes in [0, 255] are remapped to [0, 1].

Parameters:

  • input Bytes Input image, in RGBA form (or according to channels).
  • w uint Width of input...
  • h uint ...and height.
  • opts optional table Conversion options. At the moment, the only option is channels, describing the number of channels per pixel (by default 4, in keeping with RGBA).

Returns:

    Bytes On success, the converted result, in floating-point form.

Or

  1. nil, indicating an error.
  2. string Error message.

See also:

Tables

DataType
Data representations in the resize APIs.

Fields:

  • UINT8 Components are 8-bit unsigned integers, i.e. 0 to 255 (typical for images)...
  • UINT16 ...are 16-bit unsigned integers...
  • UINT32 ...or are 32-bit unsigned integers.
  • FLOAT Components are single-precision (32-bit) floating point numbers.
EdgeMode
How resizes handle sampling outside the image.

Fields:

  • CLAMP Samples are clamped to the nearest edge value, e.g. position 0 snaps to 1 and n + 1 to n.
  • REFLECT Samples reflect back across the image, e.g. position n + 3 maps to n - 3.
  • WRAP Samples wrap around to the other side of the image, e.g. position n + 1 maps to 1.
  • ZERO Samples are read back as values of 0.
Filter
How pixels are filtered during resizes.

Fields:

  • DEFAULT Use the appropriate default filter for an operation, cf. the summary above.
  • BOX A trapezoid with one-pixel-wide ramps; same result as box for integer scale ratios.
  • TRIANGLE On upsampling, produces same results as bilinear texture filtering.
  • CUBICBSPLINE The cubic B-spline (aka Mitchell-Netrevali with B = 1, C = 0). Gaussian-esque.
  • CATMULLROM An interpolating cubic spline.
  • MITCHELL Mitchell-Netrevali filter with B = C = ⅓.
ColorSpace
How to interpret colors.

Fields:

  • LINEAR Colors map linearly from [0, 255] to [0, 1].
  • SRGB Colors follow an sRGB gamma ramp.
ResizeFlags
Optional flags to apply to resize operation.

Fields:

  • ALPHA_PREMULTIPLIED Set this flag if your texture has premultiplied alpha. Otherwise, alpha-weighted resampling will be used (effectively premultiplying, resampling, then unpremultiplying).
  • ALPHA_USES_COLORSPACE The specified alpha channel should be handled as gamma-corrected value even when doing sRGB operations.
generated by LDoc 1.4.6 Last updated 2018-09-03 18:10:24