diff --git a/src/Tk/tkImaging.c b/src/Tk/tkImaging.c index 1ebf8985d5f..2edcca49288 100644 --- a/src/Tk/tkImaging.c +++ b/src/Tk/tkImaging.c @@ -239,14 +239,14 @@ TkImaging_Init(Tcl_Interp *interp) { #define TKINTER_PKG "tkinter" +/** + * Load function `func_name` from `lib_handle`. + * Set Python exception if we can't find `func_name` in `lib_handle`. + * + * @return Function pointer or NULL if not present, with Python exception set. + */ FARPROC _dfunc(HMODULE lib_handle, const char *func_name) { - /* - * Load function `func_name` from `lib_handle`. - * Set Python exception if we can't find `func_name` in `lib_handle`. - * Returns function pointer or NULL if not present. - */ - FARPROC func = GetProcAddress(lib_handle, func_name); if (func == NULL) { PyErr_Format(PyExc_RuntimeError, "Cannot load function %s", func_name); @@ -254,14 +254,14 @@ _dfunc(HMODULE lib_handle, const char *func_name) { return func; } +/** + * Try to fill Tcl global vars with function pointers. + * + * @return 0 for no functions found, 1 for all functions found, + * -1 for some but not all functions found. + */ int get_tcl(HMODULE hMod) { - /* - * Try to fill Tcl global vars with function pointers. Return 0 for no - * functions found, 1 for all functions found, -1 for some but not all - * functions found. - */ - if ((TCL_CREATE_COMMAND = (Tcl_CreateCommand_t)GetProcAddress(hMod, "Tcl_CreateCommand")) == NULL) { return 0; /* Maybe not Tcl module */ @@ -272,14 +272,14 @@ get_tcl(HMODULE hMod) { : 1; } +/** + * Try to fill Tk global vars with function pointers. + * + * @return 0 for no functions found, 1 for all functions found, + * -1 for some but not all functions found. + */ int get_tk(HMODULE hMod) { - /* - * Try to fill Tk global vars with function pointers. Return 0 for no - * functions found, 1 for all functions found, -1 for some but not all - * functions found. - */ - FARPROC func = GetProcAddress(hMod, "Tk_PhotoPutBlock"); if (func == NULL) { /* Maybe not Tk module */ return 0; @@ -295,13 +295,13 @@ get_tk(HMODULE hMod) { return 1; } +/** + * Load Tcl and Tk functions by searching all modules in current process. + * + * @return 0 for success, non-zero for failure, with Python exception set. + */ int load_tkinter_funcs(void) { - /* - * Load Tcl and Tk functions by searching all modules in current process. - * Return 0 for success, non-zero for failure. - */ - HMODULE *hMods = NULL; HANDLE hProcess; DWORD cbNeeded; @@ -373,14 +373,14 @@ load_tkinter_funcs(void) { #include +/** + * Load function `func_name` from `lib_handle`. + * Set Python exception if we can't find `func_name` in `lib_handle`. + * + * @return Function pointer or NULL if not present, with Python exception set. + */ void * _dfunc(void *lib_handle, const char *func_name) { - /* - * Load function `func_name` from `lib_handle`. - * Set Python exception if we can't find `func_name` in `lib_handle`. - * Returns function pointer or NULL if not present. - */ - void *func; /* Reset errors. */ dlerror(); @@ -392,13 +392,13 @@ _dfunc(void *lib_handle, const char *func_name) { return func; } +/** + * Fill global function pointers from dynamic library. + * + * @return 1 if any pointer is NULL, 0 otherwise. + */ int _func_loader(void *lib) { - /* - * Fill global function pointers from dynamic lib. - * Return 1 if any pointer is NULL, 0 otherwise. - */ - if ((TCL_CREATE_COMMAND = (Tcl_CreateCommand_t)_dfunc(lib, "Tcl_CreateCommand")) == NULL) { return 1; @@ -420,13 +420,13 @@ _func_loader(void *lib) { ); } +/** + * Load tkinter global functions from tkinter compiled module. + * + * @return 0 for success, non-zero for failure, with Python exception set. + */ int load_tkinter_funcs(void) { - /* - * Load tkinter global funcs from tkinter compiled module. - * Return 0 for success, non-zero for failure. - */ - int ret = -1; void *main_program, *tkinter_lib; char *tkinter_libname; diff --git a/src/_avif.c b/src/_avif.c index b6599196755..da0cf1cf429 100644 --- a/src/_avif.c +++ b/src/_avif.c @@ -85,11 +85,15 @@ irot_imir_to_exif_orientation(const avifImage *image) { return 1; // Default orientation ("top-left", no-op). } +/** + * Map EXIF orientation to irot and imir boxes. + * + * EXIF orientations are defined in JEITA CP-3451C section 4.6.4.A Orientation. + * irot and imir boxes are defined in HEIF ISO/IEC 28002-12:2021 sections 6.5.10 + * and 6.5.12. + */ static void exif_orientation_to_irot_imir(avifImage *image, int orientation) { - // Mapping from Exif orientation as defined in JEITA CP-3451C section 4.6.4.A - // Orientation to irot and imir boxes as defined in HEIF ISO/IEC 28002-12:2021 - // sections 6.5.10 and 6.5.12. switch (orientation) { case 2: // The 0th row is at the visual top of the image, and the 0th column is // the visual right-hand side. diff --git a/src/_imaging.c b/src/_imaging.c index fa42332a815..869f4a8783d 100644 --- a/src/_imaging.c +++ b/src/_imaging.c @@ -408,15 +408,21 @@ getbands(const ModeID mode) { #define TYPE_FLOAT32 (0x300 | sizeof(FLOAT32)) #define TYPE_DOUBLE (0x400 | sizeof(double)) +/** + * Allocates and returns a C array of the items in the Python sequence arg. + * The sequence's length is checked against the length parameter. + * + * @param arg The Python sequence to convert + * @param length The required number of items. + * @param wrong_length Error message to emit in exception if the sequence length does + * not match. + * @param type Type specifier (one of the TYPE_* constants above) + * + * @return A pointer to the allocated C array, or NULL on error. The caller is + * responsible for freeing the memory. + */ static void * getlist_impl(PyObject *arg, Py_ssize_t length, const char *wrong_length, int type) { - /* - allocates and returns a c array of the items in the Python sequence arg. - - the size of the returned array is in length - - all of the arg items must be numeric items of the type specified in type - - sequence length is checked against the length parameter - - caller is responsible for freeing the memory - */ - Py_ssize_t i, n; int itemp; double dtemp; @@ -2104,9 +2110,13 @@ _reduce(ImagingObject *self, PyObject *args) { return PyImagingNew(imOut); } +/** + * Convert the given RGB/RGBX image to RGBA in-place. + * + * @return None on success, with Python exception set on failure. + */ static PyObject * im_setalpha(ImagingObject *self, PyObject *args) { - /* attempt to modify the mode of an image in place */ Imaging im = self->image; if (im->mode != IMAGING_MODE_RGB && im->mode != IMAGING_MODE_RGBX) { return ImagingError_ModeError(); @@ -2846,10 +2856,18 @@ textwidth(ImagingFontObject *self, const unsigned char *text) { return xsize; } +/** + * Convert the given Python string to a C Latin-1 string + * suitable for basic text rendering. + * + * @param encoded_string The Python string to convert. Can be a Unicode or bytes object. + * @param text Pointer to an unsigned char pointer that will be set to the allocated C + * string. The caller is responsible for freeing the memory with `free`. + * @return Void, but a Python exception will be set if an error occurs (e.g., memory + * allocation failure). `text` will not have been set in this case. + */ void _font_text_asBytes(PyObject *encoded_string, unsigned char **text) { - /* Allocates *text, returns a 'new reference'. Caller is required to free */ - PyObject *bytes = NULL; Py_ssize_t len = 0; char *buffer; @@ -2875,8 +2893,6 @@ _font_text_asBytes(PyObject *encoded_string, unsigned char **text) { if (bytes) { Py_DECREF(bytes); } - - return; } static PyObject * diff --git a/src/encode.c b/src/encode.c index 6e5b6a7e943..2eb74088155 100644 --- a/src/encode.c +++ b/src/encode.c @@ -115,14 +115,21 @@ _encode_cleanup(ImagingEncoderObject *encoder, PyObject *args) { Py_RETURN_NONE; } +/** + * Encode to a Python bytes object allocated by this method. + * + * Python arguments: + * - bufsize (int, optional): The size of the buffer to use for encoding. + * + * @return A tuple containing the number of bytes written, an error code if any, and the + * encoded bytes object. NULL if an error occurred, with a Python exception set. + */ static PyObject * _encode(ImagingEncoderObject *encoder, PyObject *args) { PyObject *buf; PyObject *result; int bytes_consumed; - /* Encode to a Python string (allocated by this method) */ - Py_ssize_t bufsize = 16384; if (!PyArg_ParseTuple(args, "|n", &bufsize)) { @@ -168,14 +175,24 @@ _encode_to_pyfd(ImagingEncoderObject *encoder, PyObject *args) { return result; } +/** + * Encode to a file descriptor. + * + * Python arguments: + * - fh (int): The open writable binary file descriptor to write the encoded data to. + * - bufsize (int, optional): The size of the buffer to use for encoding. + * Default is 16384. + * + * @return The error code from the encoder after encoding. + * The caller must ensure this is zero; otherwise encoding had failed. + * Returns NULL if an error occurred, with a Python exception set. + */ static PyObject * _encode_to_file(ImagingEncoderObject *encoder, PyObject *args) { UINT8 *buf; int bytes_consumed; ImagingSectionCookie cookie; - /* Encode to a file handle */ - Py_ssize_t fh; Py_ssize_t bufsize = 16384; diff --git a/src/libImaging/Convert.c b/src/libImaging/Convert.c index b2b7ff26a22..a833a2d7781 100644 --- a/src/libImaging/Convert.c +++ b/src/libImaging/Convert.c @@ -1062,6 +1062,17 @@ pa2ycbcr(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) { ImagingConvertRGB2YCbCr(out, out, xsize); } +/** + * Map palette image to L, RGB, RGBA, or CMYK. + * + * @param imOut The output image. + * Must be NULL or have the same size as imIn and the same mode as `mode`. + * @param imIn The input palette image. + * @param mode The desired output mode. + * @return The converted image, or NULL on error. + * FIXME: there's no way of knowing if Imaging2Dirty did the the conversion + * or if it returned the same image. This should be fixed. + */ static Imaging frompalette(Imaging imOut, Imaging imIn, const ModeID mode) { ImagingSectionCookie cookie; @@ -1069,8 +1080,6 @@ frompalette(Imaging imOut, Imaging imIn, const ModeID mode) { int y; void (*convert)(UINT8 *, const UINT8 *, int, ImagingPalette); - /* Map palette image to L, RGB, RGBA, or CMYK */ - if (!imIn->palette) { return (Imaging)ImagingError_ValueError("no palette"); } @@ -1332,13 +1341,15 @@ topalette( return imOut; } +/** + * Map L or RGB to dithered 1 image + */ static Imaging tobilevel(Imaging imOut, Imaging imIn) { ImagingSectionCookie cookie; int x, y; int *errors; - /* Map L or RGB to dithered 1 image */ if (imIn->mode != IMAGING_MODE_L && imIn->mode != IMAGING_MODE_RGB) { return (Imaging)ImagingError_ValueError("conversion not supported"); } diff --git a/src/libImaging/Effects.c b/src/libImaging/Effects.c index c05c5764e44..428e6038e8e 100644 --- a/src/libImaging/Effects.c +++ b/src/libImaging/Effects.c @@ -19,10 +19,20 @@ #include +/** + * Generate a grayscale Mandelbrot set covering the given extent. + * Allocates a new image of the given size and returns it. + * + * @param xsize Width of the output image in pixels. + * @param ysize Height of the output image in pixels. + * @param extent Array of four doubles specifying the extent of the Mandelbrot set to + * generate: [xmin, ymin, xmax, ymax]. + * @param quality Maximum number of iterations for each pixel. Must be >= 2. + * @return A new grayscale image containing the Mandelbrot set, + * or NULL with a Python error set if an error occurred. + */ Imaging ImagingEffectMandelbrot(int xsize, int ysize, double extent[4], int quality) { - /* Generate a Mandelbrot set covering the given extent */ - Imaging im; int x, y, k; double width, height; @@ -71,10 +81,18 @@ ImagingEffectMandelbrot(int xsize, int ysize, double extent[4], int quality) { return im; } +/** + * Generate Gaussian noise centered around 128 with the given standard deviation. + * Allocates a new grayscale image of the given size and returns it. + * + * @param xsize Width of the output image in pixels. + * @param ysize Height of the output image in pixels. + * @param sigma Standard deviation of the Gaussian noise. + * @return A new grayscale image containing the Gaussian noise, + * or NULL with a Python error set if an error occurred. + */ Imaging ImagingEffectNoise(int xsize, int ysize, float sigma) { - /* Generate Gaussian noise centered around 128 */ - Imaging imOut; int x, y; int nextok; @@ -113,10 +131,17 @@ ImagingEffectNoise(int xsize, int ysize, float sigma) { return imOut; } +/** + * Randomly spread pixels in an image into a new image, + * with a maximum distance of `distance` pixels. + * + * @param imIn Input image. + * @param distance Maximum distance to spread pixels. + * @return A new image with pixels randomly spread, + * or NULL with a Python error set if an error occurred. + */ Imaging ImagingEffectSpread(Imaging imIn, int distance) { - /* Randomly spread pixels in an image */ - Imaging imOut; int x, y; diff --git a/src/libImaging/GetBBox.c b/src/libImaging/GetBBox.c index 1952cd9ccb4..bc69424f901 100644 --- a/src/libImaging/GetBBox.c +++ b/src/libImaging/GetBBox.c @@ -18,10 +18,19 @@ #include "Imaging.h" +/** + * Get the bounding box for any non-zero data in the image. + * + * @param im The image to analyze. + * @param bbox An array of four integers to store the bounding box coordinates: + * [left, top, right, bottom]. + * Must have been allocated as such by the caller. + * @param alpha_only If non-zero, only consider the alpha channel for bounding box + * calculation. + * @return 1 if a bounding box was found, 0 if the image is empty (no non-zero pixels). + */ int ImagingGetBBox(Imaging im, int bbox[4], int alpha_only) { - /* Get the bounding box for any non-zero data in the image.*/ - int xsize = im->xsize, ysize = im->ysize; /* Initialize bounding box to max values */ @@ -139,10 +148,20 @@ ImagingGetBBox(Imaging im, int bbox[4], int alpha_only) { return 1; /* ok */ } +/** + * Get projection arrays for non-zero data in the image. + * Projection arrays indicate the rows and columns in the image + * with non-zero data. + * + * @param im The image to analyze. + * @param xproj Projection array for columns. + * Must be of size `im->xsize`, allocated by the caller. + * @param yproj Projection array for rows. + * Must be of size `im->ysize`, allocated by the caller. + * @return Always 1. + */ int ImagingGetProjection(Imaging im, UINT8 *xproj, UINT8 *yproj) { - /* Get projection arrays for non-zero data in the image.*/ - int x, y; int has_data; diff --git a/src/libImaging/Palette.c b/src/libImaging/Palette.c index b2dacf656b5..d6cafcdd88b 100644 --- a/src/libImaging/Palette.c +++ b/src/libImaging/Palette.c @@ -20,10 +20,14 @@ #include +/** + * Create a palette object in the given mode. + * + * @param mode The mode of the palette (RGB/RGBA/CMYK). + * @return A new palette object, or NULL on error with a Python exception set. + */ ImagingPalette ImagingPaletteNew(const ModeID mode) { - /* Create a palette object */ - int i; ImagingPalette palette; @@ -47,10 +51,13 @@ ImagingPaletteNew(const ModeID mode) { return palette; } +/** + * Create a standard "browser" palette object in RGB mode. + * + * @return A new palette object, or NULL on error with a Python exception set. + */ ImagingPalette ImagingPaletteNewBrowser(void) { - /* Create a standard "browser" palette object */ - int i, r, g, b; ImagingPalette palette; @@ -80,10 +87,14 @@ ImagingPaletteNewBrowser(void) { return palette; } +/** + * Duplicate a palette object. + * + * @param palette The palette to duplicate. + * @return A new palette object, or NULL on error with a Python exception set. + */ ImagingPalette ImagingPaletteDuplicate(ImagingPalette palette) { - /* Duplicate palette descriptor */ - ImagingPalette new_palette; if (!palette) { @@ -103,10 +114,14 @@ ImagingPaletteDuplicate(ImagingPalette palette) { return new_palette; } +/** + * Destroy a palette object. + * + * @param palette The palette to destroy; may be NULL. + * @return Infallible. The passed-in palette pointer is invalid after this call. + */ void ImagingPaletteDelete(ImagingPalette palette) { - /* Destroy palette object */ - if (palette) { if (palette->cache) { free(palette->cache); diff --git a/src/libImaging/Point.c b/src/libImaging/Point.c index 9cb9fbbca7d..64ea4c1e7dd 100644 --- a/src/libImaging/Point.c +++ b/src/libImaging/Point.c @@ -127,10 +127,17 @@ im_point_32_8(Imaging imOut, Imaging imIn, im_point_context *context) { } } +/** + * Apply a lookup table to an image. + * + * @param imIn The input image. + * @param mode The output mode. + * @param table The lookup table. No bounds checking is done for the table; + * the caller must ensure that the table is valid for the image and mode. + * @return A new output image, or NULL on error with a Python exception set. + */ Imaging ImagingPoint(Imaging imIn, ModeID mode, const void *table) { - /* lookup table transform */ - ImagingSectionCookie cookie; Imaging imOut; im_point_context context; @@ -208,10 +215,17 @@ ImagingPoint(Imaging imIn, ModeID mode, const void *table) { ); } +/** + * Transform each pixel of the image with the given scale and offset. + * This can be read as a "multiply and add" operation. + * + * @param imIn The input image. + * @param scale The scale factor. + * @param offset The offset. + * @return A new output image, or NULL on error with a Python exception set. + */ Imaging ImagingPointTransform(Imaging imIn, double scale, double offset) { - /* scale/offset transform */ - ImagingSectionCookie cookie; Imaging imOut; int x, y; diff --git a/src/libImaging/codec_fd.c b/src/libImaging/codec_fd.c index 2e792a85adf..8883ec59d6a 100644 --- a/src/libImaging/codec_fd.c +++ b/src/libImaging/codec_fd.c @@ -1,11 +1,16 @@ #include #include "Imaging.h" +/** + * Read from a Python file-like object into `dest`. + * + * @param fd Python file-like object with a `read` method + * @param dest Caller-allocated buffer to read into; must be at least `bytes` long + * @param bytes Number of bytes to read + * @return Number of bytes read; or -1 on error, and a Python exception set. + */ Py_ssize_t _imaging_read_pyFd(PyObject *fd, char *dest, Py_ssize_t bytes) { - /* dest should be a buffer bytes long, returns length of read - -1 on error */ - PyObject *result; char *buffer; Py_ssize_t length;