summaryrefslogtreecommitdiff
path: root/Build/source/libs/gd/libgd-src/src/gd_crop.c
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/libs/gd/libgd-src/src/gd_crop.c')
-rw-r--r--Build/source/libs/gd/libgd-src/src/gd_crop.c300
1 files changed, 300 insertions, 0 deletions
diff --git a/Build/source/libs/gd/libgd-src/src/gd_crop.c b/Build/source/libs/gd/libgd-src/src/gd_crop.c
new file mode 100644
index 00000000000..05a1dce1701
--- /dev/null
+++ b/Build/source/libs/gd/libgd-src/src/gd_crop.c
@@ -0,0 +1,300 @@
+/**
+ * File: Cropping
+ *
+ * Crop an image
+ *
+ * Some functions to crop images, automatically (auto detection of the border
+ * color), using a given color (with or without tolerance) or using a given
+ * rectangle.
+ *
+ * Example:
+ * (start code)
+ * im2 = gdImageAutoCrop(im, GD_CROP_SIDES);
+ * if (im2) {
+ * gdImageDestroy(im); // unless you need the original image subsequently
+ * // do something with the cropped image
+ * }
+ * gdImageDestroy(im2);
+ * (end code)
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include "gd.h"
+#include "gd_color.h"
+
+static int gdGuessBackgroundColorFromCorners(gdImagePtr im, int *color);
+
+/**
+ * Function: gdImageCrop
+ *
+ * Crop an image to a given rectangle
+ *
+ * Parameters:
+ * src - The image.
+ * crop - The cropping rectangle, see <gdRect>.
+ *
+ * Returns:
+ * The newly created cropped image, or NULL on failure.
+ *
+ * See also:
+ * - <gdImageCropAuto>
+ * - <gdImageCropThreshold>
+ */
+BGD_DECLARE(gdImagePtr) gdImageCrop(gdImagePtr src, const gdRect *crop)
+{
+ gdImagePtr dst;
+ int alphaBlendingFlag;
+
+ if (gdImageTrueColor(src)) {
+ dst = gdImageCreateTrueColor(crop->width, crop->height);
+ } else {
+ dst = gdImageCreate(crop->width, crop->height);
+ }
+ if (!dst) return NULL;
+ alphaBlendingFlag = dst->alphaBlendingFlag;
+ gdImageAlphaBlending(dst, gdEffectReplace);
+ gdImageCopy(dst, src, 0, 0, crop->x, crop->y, crop->width, crop->height);
+ gdImageAlphaBlending(dst, alphaBlendingFlag);
+
+ return dst;
+}
+
+/**
+ * Function: gdImageCropAuto
+ *
+ * Crop an image automatically
+ *
+ * This function detects the cropping area according to the given _mode_.
+ *
+ * Parameters:
+ * im - The image.
+ * mode - The cropping mode, see <gdCropMode>.
+ *
+ * Returns:
+ * The newly created cropped image, or NULL on failure.
+ *
+ * See also:
+ * - <gdImageCrop>
+ * - <gdImageCropThreshold>
+ */
+BGD_DECLARE(gdImagePtr) gdImageCropAuto(gdImagePtr im, const unsigned int mode)
+{
+ const int width = gdImageSX(im);
+ const int height = gdImageSY(im);
+
+ int x,y;
+ int color, match;
+ gdRect crop;
+
+ crop.x = 0;
+ crop.y = 0;
+ crop.width = 0;
+ crop.height = 0;
+
+ switch (mode) {
+ case GD_CROP_TRANSPARENT:
+ color = gdImageGetTransparent(im);
+ break;
+
+ case GD_CROP_BLACK:
+ color = gdImageColorClosestAlpha(im, 0, 0, 0, 0);
+ break;
+
+ case GD_CROP_WHITE:
+ color = gdImageColorClosestAlpha(im, 255, 255, 255, 0);
+ break;
+
+ case GD_CROP_SIDES:
+ gdGuessBackgroundColorFromCorners(im, &color);
+ break;
+
+ case GD_CROP_DEFAULT:
+ default:
+ color = gdImageGetTransparent(im);
+ break;
+ }
+
+ /* TODO: Add gdImageGetRowPtr and works with ptr at the row level
+ * for the true color and palette images
+ * new formats will simply work with ptr
+ */
+ match = 1;
+ for (y = 0; match && y < height; y++) {
+ for (x = 0; match && x < width; x++) {
+ match = (color == gdImageGetPixel(im, x,y));
+ }
+ }
+
+ /* Whole image would be cropped > bye */
+ if (match) {
+ return NULL;
+ }
+
+ crop.y = y - 1;
+
+ match = 1;
+ for (y = height - 1; match && y >= 0; y--) {
+ for (x = 0; match && x < width; x++) {
+ match = (color == gdImageGetPixel(im, x,y));
+ }
+ }
+ crop.height = y - crop.y + 2;
+
+ match = 1;
+ for (x = 0; match && x < width; x++) {
+ for (y = 0; match && y < crop.y + crop.height; y++) {
+ match = (color == gdImageGetPixel(im, x,y));
+ }
+ }
+ crop.x = x - 1;
+
+ match = 1;
+ for (x = width - 1; match && x >= 0; x--) {
+ for (y = 0; match && y < crop.y + crop.height; y++) {
+ match = (color == gdImageGetPixel(im, x,y));
+ }
+ }
+ crop.width = x - crop.x + 2;
+
+ return gdImageCrop(im, &crop);
+}
+
+/**
+ * Function: gdImageCropThreshold
+ *
+ * Crop an image using a given color
+ *
+ * The _threshold_ defines the tolerance to be used while comparing the image
+ * color and the color to crop. The method used to calculate the color
+ * difference is based on the color distance in the RGB(A) cube.
+ *
+ * Parameters:
+ * im - The image.
+ * color - The crop color.
+ * threshold - The crop threshold.
+ *
+ * Returns:
+ * The newly created cropped image, or NULL on failure.
+ *
+ * See also:
+ * - <gdImageCrop>
+ * - <gdImageCropAuto>
+ */
+BGD_DECLARE(gdImagePtr) gdImageCropThreshold(gdImagePtr im, const unsigned int color, const float threshold)
+{
+ const int width = gdImageSX(im);
+ const int height = gdImageSY(im);
+
+ int x,y;
+ int match;
+ gdRect crop;
+
+ crop.x = 0;
+ crop.y = 0;
+ crop.width = 0;
+ crop.height = 0;
+
+ /* Pierre: crop everything sounds bad */
+ if (threshold > 100.0) {
+ return NULL;
+ }
+
+ if (!gdImageTrueColor(im) && color >= gdImageColorsTotal(im)) {
+ return NULL;
+ }
+
+ /* TODO: Add gdImageGetRowPtr and works with ptr at the row level
+ * for the true color and palette images
+ * new formats will simply work with ptr
+ */
+ match = 1;
+ for (y = 0; match && y < height; y++) {
+ for (x = 0; match && x < width; x++) {
+ match = (gdColorMatch(im, color, gdImageGetPixel(im, x,y), threshold)) > 0;
+ }
+ }
+
+ /* Whole image would be cropped > bye */
+ if (match) {
+ return NULL;
+ }
+
+ crop.y = y - 1;
+
+ match = 1;
+ for (y = height - 1; match && y >= 0; y--) {
+ for (x = 0; match && x < width; x++) {
+ match = (gdColorMatch(im, color, gdImageGetPixel(im, x, y), threshold)) > 0;
+ }
+ }
+ crop.height = y - crop.y + 2;
+
+ match = 1;
+ for (x = 0; match && x < width; x++) {
+ for (y = 0; match && y < crop.y + crop.height; y++) {
+ match = (gdColorMatch(im, color, gdImageGetPixel(im, x,y), threshold)) > 0;
+ }
+ }
+ crop.x = x - 1;
+
+ match = 1;
+ for (x = width - 1; match && x >= 0; x--) {
+ for (y = 0; match && y < crop.y + crop.height; y++) {
+ match = (gdColorMatch(im, color, gdImageGetPixel(im, x,y), threshold)) > 0;
+ }
+ }
+ crop.width = x - crop.x + 2;
+
+ return gdImageCrop(im, &crop);
+}
+
+/* This algorithm comes from pnmcrop (http://netpbm.sourceforge.net/)
+ * Three steps:
+ * - if 3 corners are equal.
+ * - if two are equal.
+ * - Last solution: average the colors
+ */
+static int gdGuessBackgroundColorFromCorners(gdImagePtr im, int *color)
+{
+ const int tl = gdImageGetPixel(im, 0, 0);
+ const int tr = gdImageGetPixel(im, gdImageSX(im) - 1, 0);
+ const int bl = gdImageGetPixel(im, 0, gdImageSY(im) -1);
+ const int br = gdImageGetPixel(im, gdImageSX(im) - 1, gdImageSY(im) -1);
+
+ if (tr == bl && tr == br) {
+ *color = tr;
+ return 3;
+ } else if (tl == bl && tl == br) {
+ *color = tl;
+ return 3;
+ } else if (tl == tr && tl == br) {
+ *color = tl;
+ return 3;
+ } else if (tl == tr && tl == bl) {
+ *color = tl;
+ return 3;
+ } else if (tl == tr || tl == bl || tl == br) {
+ *color = tl;
+ return 2;
+ } else if (tr == bl || tr == br) {
+ *color = tr;
+ return 2;
+ } else if (br == bl) {
+ *color = bl;
+ return 2;
+ } else {
+ register int r,b,g,a;
+
+ r = (2 + gdImageRed(im, tl) + gdImageRed(im, tr) + gdImageRed(im, bl) + gdImageRed(im, br)) / 4;
+ g = (2 + gdImageGreen(im, tl) + gdImageGreen(im, tr) + gdImageGreen(im, bl) + gdImageGreen(im, br)) / 4;
+ b = (2 + gdImageBlue(im, tl) + gdImageBlue(im, tr) + gdImageBlue(im, bl) + gdImageBlue(im, br)) / 4;
+ a = (2 + gdImageAlpha(im, tl) + gdImageAlpha(im, tr) + gdImageAlpha(im, bl) + gdImageAlpha(im, br)) / 4;
+ *color = gdImageColorClosestAlpha(im, r, g, b, a);
+ return 0;
+ }
+}