diff --git a/src/libImaging/Point.c b/src/libImaging/Point.c index 8f6d47c770f..55a1c0bbe81 100644 --- a/src/libImaging/Point.c +++ b/src/libImaging/Point.c @@ -25,30 +25,45 @@ typedef struct { const void *table; } im_point_context; +// Note: all point handlers must fill the entirety of `imOut`, +// as it is allocated dirty by `ImagingPoint`. + +/** + * Contract: imIn is read-only and imOut must be a distinct image. + */ static void im_point_8_8(Imaging imOut, Imaging imIn, im_point_context *context) { - int x, y; /* 8-bit source, 8-bit destination */ UINT8 *table = (UINT8 *)context->table; - for (y = 0; y < imIn->ysize; y++) { - UINT8 *in = imIn->image8[y]; - UINT8 *out = imOut->image8[y]; - for (x = 0; x < imIn->xsize; x++) { + // Invariant over the loop. + int xsize = imIn->xsize, ysize = imIn->ysize; + for (int y = 0; y < ysize; y++) { + // restrict safe: imIn is read-only, imOut is a fresh allocation. + UINT8 *restrict in = imIn->image8[y]; + UINT8 *restrict out = imOut->image8[y]; + for (int x = 0; x < xsize; x++) { out[x] = table[in[x]]; } } } +/** + * Contract: imIn is read-only and imOut must be a distinct image. + */ static void im_point_2x8_2x8(Imaging imOut, Imaging imIn, im_point_context *context) { - int x, y; /* 2x8-bit source, 2x8-bit destination */ UINT8 *table = (UINT8 *)context->table; - for (y = 0; y < imIn->ysize; y++) { - UINT8 *in = (UINT8 *)imIn->image[y]; - UINT8 *out = (UINT8 *)imOut->image[y]; - for (x = 0; x < imIn->xsize; x++) { + // Invariant over the loop. + int xsize = imIn->xsize, ysize = imIn->ysize; + for (int y = 0; y < ysize; y++) { + // restrict safe: imIn is read-only, imOut is a fresh allocation. + UINT8 *restrict in = (UINT8 *)imIn->image[y]; + UINT8 *restrict out = (UINT8 *)imOut->image[y]; + for (int x = 0; x < xsize; x++) { out[0] = table[in[0]]; + out[1] = 0; + out[2] = 0; out[3] = table[in[3] + 256]; in += 4; out += 4; @@ -56,33 +71,44 @@ im_point_2x8_2x8(Imaging imOut, Imaging imIn, im_point_context *context) { } } +/** + * Contract: imIn is read-only and imOut must be a distinct image. + */ static void im_point_3x8_3x8(Imaging imOut, Imaging imIn, im_point_context *context) { - int x, y; /* 3x8-bit source, 3x8-bit destination */ UINT8 *table = (UINT8 *)context->table; - for (y = 0; y < imIn->ysize; y++) { - UINT8 *in = (UINT8 *)imIn->image[y]; - UINT8 *out = (UINT8 *)imOut->image[y]; - for (x = 0; x < imIn->xsize; x++) { + // Invariant over the loop. + int xsize = imIn->xsize, ysize = imIn->ysize; + for (int y = 0; y < ysize; y++) { + // restrict safe: imIn is read-only, imOut is a fresh allocation. + UINT8 *restrict in = (UINT8 *)imIn->image[y]; + UINT8 *restrict out = (UINT8 *)imOut->image[y]; + for (int x = 0; x < xsize; x++) { out[0] = table[in[0]]; out[1] = table[in[1] + 256]; out[2] = table[in[2] + 512]; + out[3] = 0; in += 4; out += 4; } } } +/** + * Contract: imIn is read-only and imOut must be a distinct image. + */ static void im_point_4x8_4x8(Imaging imOut, Imaging imIn, im_point_context *context) { - int x, y; /* 4x8-bit source, 4x8-bit destination */ UINT8 *table = (UINT8 *)context->table; - for (y = 0; y < imIn->ysize; y++) { - UINT8 *in = (UINT8 *)imIn->image[y]; - UINT8 *out = (UINT8 *)imOut->image[y]; - for (x = 0; x < imIn->xsize; x++) { + // Invariant over the loop. + int xsize = imIn->xsize, ysize = imIn->ysize; + for (int y = 0; y < ysize; y++) { + // restrict safe: imIn is read-only, imOut is a fresh allocation. + UINT8 *restrict in = (UINT8 *)imIn->image[y]; + UINT8 *restrict out = (UINT8 *)imOut->image[y]; + for (int x = 0; x < xsize; x++) { out[0] = table[in[0]]; out[1] = table[in[1] + 256]; out[2] = table[in[2] + 512]; @@ -93,29 +119,39 @@ im_point_4x8_4x8(Imaging imOut, Imaging imIn, im_point_context *context) { } } +/** + * Contract: imIn is read-only and imOut must be a distinct image. + */ static void im_point_8_32(Imaging imOut, Imaging imIn, im_point_context *context) { - int x, y; /* 8-bit source, 32-bit destination */ char *table = (char *)context->table; - for (y = 0; y < imIn->ysize; y++) { - UINT8 *in = imIn->image8[y]; - INT32 *out = imOut->image32[y]; - for (x = 0; x < imIn->xsize; x++) { + // Invariant over the loop. + int xsize = imIn->xsize, ysize = imIn->ysize; + for (int y = 0; y < ysize; y++) { + // restrict safe: imIn is read-only, imOut is a fresh allocation. + UINT8 *restrict in = imIn->image8[y]; + INT32 *restrict out = imOut->image32[y]; + for (int x = 0; x < xsize; x++) { memcpy(out + x, table + in[x] * sizeof(INT32), sizeof(INT32)); } } } +/** + * Contract: imIn is read-only and imOut must be a distinct image. + */ static void im_point_32_8(Imaging imOut, Imaging imIn, im_point_context *context) { - int x, y; /* 32-bit source, 8-bit destination */ UINT8 *table = (UINT8 *)context->table; - for (y = 0; y < imIn->ysize; y++) { - INT32 *in = imIn->image32[y]; - UINT8 *out = imOut->image8[y]; - for (x = 0; x < imIn->xsize; x++) { + // Invariant over the loop. + int xsize = imIn->xsize, ysize = imIn->ysize; + for (int y = 0; y < ysize; y++) { + // restrict safe: imIn is read-only, imOut is a fresh allocation. + INT32 *restrict in = imIn->image32[y]; + UINT8 *restrict out = imOut->image8[y]; + for (int x = 0; x < xsize; x++) { int v = in[x]; if (v < 0) { v = 0; @@ -134,7 +170,6 @@ ImagingPoint(Imaging imIn, ModeID mode, const void *table) { ImagingSectionCookie cookie; Imaging imOut; im_point_context context; - void (*point)(Imaging imIn, Imaging imOut, im_point_context *context); if (!imIn) { return (Imaging)ImagingError_ModeError(); @@ -152,46 +187,42 @@ ImagingPoint(Imaging imIn, ModeID mode, const void *table) { goto mode_mismatch; } - imOut = ImagingNew(mode, imIn->xsize, imIn->ysize); + imOut = ImagingNewDirty(mode, imIn->xsize, imIn->ysize); if (!imOut) { return NULL; } - /* find appropriate handler */ + ImagingCopyPalette(imOut, imIn); + + ImagingSectionEnter(&cookie); + context.table = table; + if (imIn->type == IMAGING_TYPE_UINT8) { if (imIn->bands == imOut->bands && imIn->type == imOut->type) { switch (imIn->bands) { case 1: - point = im_point_8_8; + im_point_8_8(imOut, imIn, &context); break; case 2: - point = im_point_2x8_2x8; + im_point_2x8_2x8(imOut, imIn, &context); break; case 3: - point = im_point_3x8_3x8; + im_point_3x8_3x8(imOut, imIn, &context); break; case 4: - point = im_point_4x8_4x8; + im_point_4x8_4x8(imOut, imIn, &context); break; default: /* this cannot really happen */ - point = im_point_8_8; + im_point_8_8(imOut, imIn, &context); break; } } else { - point = im_point_8_32; + im_point_8_32(imOut, imIn, &context); } } else { - point = im_point_32_8; + im_point_32_8(imOut, imIn, &context); } - - ImagingCopyPalette(imOut, imIn); - - ImagingSectionEnter(&cookie); - - context.table = table; - point(imOut, imIn, &context); - ImagingSectionLeave(&cookie); return imOut; @@ -202,20 +233,28 @@ ImagingPoint(Imaging imIn, ModeID mode, const void *table) { ); } +/** + * Apply an affine (scale/offset) transform to every pixel of imIn, + * returning a newly allocated result. + * + * Contract: imIn is read-only. + */ Imaging ImagingPointTransform(Imaging imIn, double scale, double offset) { /* scale/offset transform */ ImagingSectionCookie cookie; Imaging imOut; - int x, y; if (!imIn || (imIn->mode != IMAGING_MODE_I && imIn->mode != IMAGING_MODE_I_16 && imIn->mode != IMAGING_MODE_F)) { return (Imaging)ImagingError_ModeError(); } - imOut = ImagingNew(imIn->mode, imIn->xsize, imIn->ysize); + // Invariant over the loops. + int xsize = imIn->xsize, ysize = imIn->ysize; + + imOut = ImagingNewDirty(imIn->mode, xsize, ysize); if (!imOut) { return NULL; } @@ -223,11 +262,12 @@ ImagingPointTransform(Imaging imIn, double scale, double offset) { switch (imIn->type) { case IMAGING_TYPE_INT32: ImagingSectionEnter(&cookie); - for (y = 0; y < imIn->ysize; y++) { - INT32 *in = imIn->image32[y]; - INT32 *out = imOut->image32[y]; + for (int y = 0; y < ysize; y++) { + // restrict safe: imIn is read-only, imOut is a fresh allocation. + INT32 *restrict in = imIn->image32[y]; + INT32 *restrict out = imOut->image32[y]; /* FIXME: add clipping? */ - for (x = 0; x < imIn->xsize; x++) { + for (int x = 0; x < xsize; x++) { out[x] = in[x] * scale + offset; } } @@ -235,10 +275,11 @@ ImagingPointTransform(Imaging imIn, double scale, double offset) { break; case IMAGING_TYPE_FLOAT32: ImagingSectionEnter(&cookie); - for (y = 0; y < imIn->ysize; y++) { - FLOAT32 *in = (FLOAT32 *)imIn->image32[y]; - FLOAT32 *out = (FLOAT32 *)imOut->image32[y]; - for (x = 0; x < imIn->xsize; x++) { + for (int y = 0; y < ysize; y++) { + // restrict safe: imIn is read-only, imOut is a fresh allocation. + FLOAT32 *restrict in = (FLOAT32 *)imIn->image32[y]; + FLOAT32 *restrict out = (FLOAT32 *)imOut->image32[y]; + for (int x = 0; x < xsize; x++) { out[x] = in[x] * scale + offset; } } @@ -247,11 +288,12 @@ ImagingPointTransform(Imaging imIn, double scale, double offset) { case IMAGING_TYPE_SPECIAL: if (imIn->mode == IMAGING_MODE_I_16) { ImagingSectionEnter(&cookie); - for (y = 0; y < imIn->ysize; y++) { - char *in = (char *)imIn->image[y]; - char *out = (char *)imOut->image[y]; + for (int y = 0; y < ysize; y++) { + // restrict safe: imIn is read-only, imOut is a fresh allocation. + char *restrict in = imIn->image[y]; + char *restrict out = imOut->image[y]; /* FIXME: add clipping? */ - for (x = 0; x < imIn->xsize; x++) { + for (int x = 0; x < xsize; x++) { UINT16 v; memcpy(&v, in + x * sizeof(v), sizeof(v)); v = v * scale + offset;