@@ -168,10 +168,22 @@ static mp_float_t float_subscr(mp_obj_t o, int i) {
168168}
169169
170170//| class ChannelScale:
171- //| """A weight object to use with mix()"""
171+ //| """A weight object to use with mix() that scales each channel independently
172+ //|
173+ //| This is useful for global contrast and brightness adjustment on a
174+ //| per-component basis. For instance, to cut red contrast in half (while keeping the minimum value
175+ //| as black or 0.0),
176+ //|
177+ //| .. code-block:: python
178+ //|
179+ //| reduce_red_contrast = bitmapfilter.ChannelScale(0.5, 1, 1)
180+ //| """
172181//|
173182//| def __init__(self, r: float, g: float, b: float) -> None:
174- //| """The parameters each give a scale to apply to the respective image component"""
183+ //| """Construct a ChannelScale object
184+ //|
185+ //| The ``r`` parameter gives the scale factor for the red channel of
186+ //| pixels, and so forth."""
175187//|
176188static const mp_obj_namedtuple_type_t bitmapfilter_channel_scale_type = {
177189 NAMEDTUPLE_TYPE_BASE_AND_SLOTS (MP_QSTR_ChannelScale ),
@@ -183,16 +195,28 @@ static const mp_obj_namedtuple_type_t bitmapfilter_channel_scale_type = {
183195 },
184196};
185197//| class ChannelScaleOffset:
186- //| """A weight object to use with mix()"""
198+ //| """A weight object to use with mix() that scales and offsets each channel independently
199+ //|
200+ //| The ``r``, ``g``, and ``b`` parameters give a scale factor for each color
201+ //| component, while the ``r_add`, ``g_add`` and ``b_add`` give offset values
202+ //| added to each component.
203+ //|
204+ //| This is useful for global contrast and brightness adjustment on a
205+ //| per-component basis. For instance, to cut red contrast in half while adjusting the
206+ //| brightness so that the middle value is still 0.5:
207+ //|
208+ //| .. code-block:: python
209+ //|
210+ //| reduce_red_contrast = bitmapfilter.ChannelScaleOffset(
211+ //| 0.5, 0.25,
212+ //| 1, 0,
213+ //| 1, 0)
214+ //| """
187215//|
188216//| def __init__(
189217//| self, r: float, r_add: float, g: float, g_add: float, b: float, b_add: float
190218//| ) -> None:
191- //| """Scale and offset each channel independently.
192- //|
193- //| The ``r``, ``g``, and ``b`` parameters each give a scale to apply
194- //| to the respective image component, while the ``r_add``,
195- //| ``g_add``, and ``b_add`` parameters give an offset value to add."""
219+ //| """Construct a ChannelScaleOffset object"""
196220//|
197221static const mp_obj_namedtuple_type_t bitmapfilter_channel_scale_offset_type = {
198222 NAMEDTUPLE_TYPE_BASE_AND_SLOTS (MP_QSTR_ChannelScaleOffset ),
@@ -208,7 +232,32 @@ static const mp_obj_namedtuple_type_t bitmapfilter_channel_scale_offset_type = {
208232};
209233
210234//| class ChannelMixer:
211- //| """A weight object to use with mix()"""
235+ //| """A weight object to use with mix() that mixes different channels together
236+ //|
237+ //| The parameters with names like ``rb`` give the fraction of
238+ //| each channel to mix into every other channel. For instance,
239+ //| ``rb`` gives the fraction of blue to mix into red, and ``gg``
240+ //| gives the fraction of green to mix into green.
241+ //|
242+ //| Conversion to sepia is an example where a ChannelMixer is appropriate,
243+ //| because the sepia conversion is defined as mixing a certain fraction of R,
244+ //| G, and B input values into each output value:
245+ //|
246+ //| .. code-block:: python
247+ //|
248+ //| sepia_weights = bitmapfilter.ChannelMixer(
249+ //| .393, .769, .189,
250+ //| .349, .686, .168,
251+ //| .272, .534, .131)
252+ //|
253+ //| def sepia(bitmap):
254+ //| \"""Convert the bitmap to sepia\"""
255+ //| bitmapfilter.mix(bitmap, sepia_weights)
256+ //| mix_into_red = ChannelMixer(
257+ //| 0.5, 0.25, 0.25,
258+ //| 0, 1, 0,
259+ //| 0, 1, 0)
260+ //| """
212261//|
213262//| def __init__(
214263//| self,
@@ -222,12 +271,7 @@ static const mp_obj_namedtuple_type_t bitmapfilter_channel_scale_offset_type = {
222271//| bg: float,
223272//| bb: float,
224273//| ) -> None:
225- //| """Perform a mixing operation where each channel can receive a fraction of every other channel.
226- //|
227- //| The parameters with names like ``rb`` give the fraction of
228- //| each channel to mix into every other channel. For instance,
229- //| ``rb`` gives the fraction of blue to mix into red, and ``gg``
230- //| gives the fraction of green to mix into green."""
274+ //| """Construct a ChannelMixer object"""
231275//|
232276static const mp_obj_namedtuple_type_t bitmapfilter_channel_mixer_type = {
233277 NAMEDTUPLE_TYPE_BASE_AND_SLOTS (MP_QSTR_ChannelMixer ),
@@ -246,7 +290,23 @@ static const mp_obj_namedtuple_type_t bitmapfilter_channel_mixer_type = {
246290};
247291
248292//| class ChannelMixerOffset:
249- //| """A weight object to use with mix()"""
293+ //| """A weight object to use with mix() that mixes different channels together, plus an offset value
294+ //|
295+ //| The parameters with names like ``rb`` give the fraction of
296+ //| each channel to mix into every other channel. For instance,
297+ //| ``rb`` gives the fraction of blue to mix into red, and ``gg``
298+ //| gives the fraction of green to mix into green. The ``r_add``, ``g_add``
299+ //| and ``b_add`` parameters give offsets applied to each component.
300+ //|
301+ //| For instance, to perform sepia conversion but also increase the overall brightness by 10%:
302+ //|
303+ //| .. code-block:: python
304+ //|
305+ //| sepia_weights_brighten = bitmapfilter.ChannelMixerOffset(
306+ //| .393, .769, .189, .1
307+ //| .349, .686, .168, .1
308+ //| .272, .534, .131, .1)
309+ //| """
250310//|
251311//| def __init__(
252312//| self,
@@ -263,13 +323,7 @@ static const mp_obj_namedtuple_type_t bitmapfilter_channel_mixer_type = {
263323//| bb: float,
264324//| b_add: float,
265325//| ) -> None:
266- //| """Perform a mixing operation where each channel can receive a fraction of every other channel, plus an offset value.
267- //|
268- //| The parameters with names like ``rb`` give the fraction of
269- //| each channel to mix into every other channel. For instance,
270- //| ``rb`` gives the fraction of blue to mix into red, and ``gg``
271- //| gives the fraction of green to mix into green. The ``_add``
272- //| parameters give an offset value to add to the channel."""
326+ //| """Construct a ChannelMixerOffset object"""
273327//|
274328static const mp_obj_namedtuple_type_t bitmapfilter_channel_mixer_offset_type = {
275329 NAMEDTUPLE_TYPE_BASE_AND_SLOTS (MP_QSTR_ChannelMixerOffset ),
@@ -304,42 +358,17 @@ static const mp_obj_namedtuple_type_t bitmapfilter_channel_mixer_offset_type = {
304358//| The ``bitmap``, which must be in RGB565_SWAPPED format, is modified
305359//| according to the ``weights``.
306360//|
307- //| If ``weights`` is a `ChannelScale`
308- //| object, then each channel is scaled independently: The
309- //| numbers are the red, green, and blue channel scales.
310- //|
311- //| If ``weights`` is a `ChannelScaleOffset`
312- //| object, then each channel is scaled and offset independently:
313- //| The first two numbers are applied to the red channel: scale and
314- //| offset. The second two number are applied to the green channel,
315- //| and the last two numbers to the blue channel.
316- //|
317- //| If ``weights`` is a `ChannelMixer`
318- //| object, then channels are mixed. The first three
319- //| numbers are the fraction of red, green and blue input channels
320- //| mixed into the red output channel. The next 3 numbers are for
321- //| green, and the final 3 are for blue.
361+ //| The ``weights`` must be one of the above types: `ChannelScale`,
362+ //| `ChannelScaleOffset`, `ChannelMixer`, or `ChannelMixerOffset`. For the
363+ //| effect of each different kind of weights object, see the type
364+ //| documentation.
322365//|
323- //| If ``weights`` `ChannelMixerOffset`
324- //| object, then channels are mixed with an offset.
325- //| Every fourth value is the offset value.
366+ //| After computation, any out of range values are clamped to the greatest or
367+ //| smallest valid value.
326368//|
327369//| ``mask`` is another image to use as a pixel level mask for the operation.
328370//| The mask should be an image the same size as the image being operated on.
329371//| Only pixels set to a non-zero value in the mask are modified.
330- //|
331- //| For example, to perform a sepia conversion on an input image,
332- //|
333- //| .. code-block:: python
334- //|
335- //| sepia_weights = bitmapfilter.ChannelMixer(
336- //| .393, .769, .189,
337- //| .349, .686, .168,
338- //| .272, .534, .131)
339- //|
340- //| def sepia(bitmap):
341- //| \"""Convert the bitmap to sepia\"""
342- //| bitmapfilter.mix(bitmap, sepia_weights)
343372//| """
344373//|
345374STATIC mp_obj_t bitmapfilter_mix (size_t n_args , const mp_obj_t * pos_args , mp_map_t * kw_args ) {
@@ -398,7 +427,7 @@ STATIC mp_obj_t bitmapfilter_mix(size_t n_args, const mp_obj_t *pos_args, mp_map
398427MP_DEFINE_CONST_FUN_OBJ_KW (bitmapfilter_mix_obj , 0 , bitmapfilter_mix );
399428
400429//| def solarize(bitmap, threshold: float = 0.5, mask: displayio.Bitmap | None = None):
401- //| """Creat a "solarization" effect on an image
430+ //| """Create a "solarization" effect on an image
402431//|
403432//| This filter inverts pixels with brightness values above ``threshold``, while leaving
404433//| lower brightness pixels alone.
0 commit comments