Browse Source

Reviewed ImageDraw() and ImageResizeCanvas()

Added security checks in case provided image to functions hasn't been properly loaded... just to avoid program crashes.
Ray 6 years ago
parent
commit
2433f30b4b
1 changed files with 123 additions and 32 deletions
  1. 123 32
      src/textures.c

+ 123 - 32
src/textures.c

@@ -408,7 +408,11 @@ Texture2D LoadTextureFromImage(Image image)
 {
 {
     Texture2D texture = { 0 };
     Texture2D texture = { 0 };
 
 
-    texture.id = rlLoadTexture(image.data, image.width, image.height, image.format, image.mipmaps);
+    if ((image.data != NULL) && (image.width != 0) && (image.height != 0))
+    {
+        texture.id = rlLoadTexture(image.data, image.width, image.height, image.format, image.mipmaps);
+    }
+    else TraceLog(LOG_WARNING, "Texture could not be loaded from Image");
 
 
     texture.width = image.width;
     texture.width = image.width;
     texture.height = image.height;
     texture.height = image.height;
@@ -888,6 +892,9 @@ Image ImageCopy(Image image)
 // NOTE: It could be useful on OpenGL ES 2.0 (RPI, HTML5)
 // NOTE: It could be useful on OpenGL ES 2.0 (RPI, HTML5)
 void ImageToPOT(Image *image, Color fillColor)
 void ImageToPOT(Image *image, Color fillColor)
 {
 {
+    // Security check to avoid program crash
+    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
+
     Color *pixels = GetImageData(*image);   // Get pixels data
     Color *pixels = GetImageData(*image);   // Get pixels data
 
 
     // Calculate next power-of-two values
     // Calculate next power-of-two values
@@ -931,6 +938,9 @@ void ImageToPOT(Image *image, Color fillColor)
 // Convert image data to desired format
 // Convert image data to desired format
 void ImageFormat(Image *image, int newFormat)
 void ImageFormat(Image *image, int newFormat)
 {
 {
+    // Security check to avoid program crash
+    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
+
     if ((newFormat != 0) && (image->format != newFormat))
     if ((newFormat != 0) && (image->format != newFormat))
     {
     {
         if ((image->format < COMPRESSED_DXT1_RGB) && (newFormat < COMPRESSED_DXT1_RGB))
         if ((image->format < COMPRESSED_DXT1_RGB) && (newFormat < COMPRESSED_DXT1_RGB))
@@ -1153,6 +1163,9 @@ void ImageAlphaMask(Image *image, Image alphaMask)
 // NOTE: Threshold defines the alpha limit, 0.0f to 1.0f
 // NOTE: Threshold defines the alpha limit, 0.0f to 1.0f
 void ImageAlphaClear(Image *image, Color color, float threshold)
 void ImageAlphaClear(Image *image, Color color, float threshold)
 {
 {
+    // Security check to avoid program crash
+    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
+
     Color *pixels = GetImageData(*image);
     Color *pixels = GetImageData(*image);
 
 
     for (int i = 0; i < image->width*image->height; i++) if (pixels[i].a <= (unsigned char)(threshold*255.0f)) pixels[i] = color;
     for (int i = 0; i < image->width*image->height; i++) if (pixels[i].a <= (unsigned char)(threshold*255.0f)) pixels[i] = color;
@@ -1168,6 +1181,9 @@ void ImageAlphaClear(Image *image, Color color, float threshold)
 // Premultiply alpha channel
 // Premultiply alpha channel
 void ImageAlphaPremultiply(Image *image)
 void ImageAlphaPremultiply(Image *image)
 {
 {
+    // Security check to avoid program crash
+    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
+
     float alpha = 0.0f;
     float alpha = 0.0f;
     Color *pixels = GetImageData(*image);
     Color *pixels = GetImageData(*image);
 
 
@@ -1274,6 +1290,9 @@ TextureCubemap LoadTextureCubemap(Image image, int layoutType)
 // NOTE: Security checks are performed in case rectangle goes out of bounds
 // NOTE: Security checks are performed in case rectangle goes out of bounds
 void ImageCrop(Image *image, Rectangle crop)
 void ImageCrop(Image *image, Rectangle crop)
 {
 {
+    // Security check to avoid program crash
+    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
+
     // Security checks to make sure cropping rectangle is inside margins
     // Security checks to make sure cropping rectangle is inside margins
     if ((crop.x + crop.width) > image->width)
     if ((crop.x + crop.width) > image->width)
     {
     {
@@ -1323,6 +1342,9 @@ void ImageCrop(Image *image, Rectangle crop)
 // Crop image depending on alpha value
 // Crop image depending on alpha value
 void ImageAlphaCrop(Image *image, float threshold)
 void ImageAlphaCrop(Image *image, float threshold)
 {
 {
+    // Security check to avoid program crash
+    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
+
     Color *pixels = GetImageData(*image);
     Color *pixels = GetImageData(*image);
 
 
     int xMin = 65536;   // Define a big enough number
     int xMin = 65536;   // Define a big enough number
@@ -1358,6 +1380,9 @@ void ImageAlphaCrop(Image *image, float threshold)
 // STBIR_DEFAULT_FILTER_DOWNSAMPLE  STBIR_FILTER_MITCHELL   (high-quality Catmull-Rom)
 // STBIR_DEFAULT_FILTER_DOWNSAMPLE  STBIR_FILTER_MITCHELL   (high-quality Catmull-Rom)
 void ImageResize(Image *image, int newWidth, int newHeight)
 void ImageResize(Image *image, int newWidth, int newHeight)
 {
 {
+    // Security check to avoid program crash
+    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
+
     // Get data as Color pixels array to work with it
     // Get data as Color pixels array to work with it
     Color *pixels = GetImageData(*image);
     Color *pixels = GetImageData(*image);
     Color *output = (Color *)RL_MALLOC(newWidth*newHeight*sizeof(Color));
     Color *output = (Color *)RL_MALLOC(newWidth*newHeight*sizeof(Color));
@@ -1379,6 +1404,9 @@ void ImageResize(Image *image, int newWidth, int newHeight)
 // Resize and image to new size using Nearest-Neighbor scaling algorithm
 // Resize and image to new size using Nearest-Neighbor scaling algorithm
 void ImageResizeNN(Image *image,int newWidth,int newHeight)
 void ImageResizeNN(Image *image,int newWidth,int newHeight)
 {
 {
+    // Security check to avoid program crash
+    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
+
     Color *pixels = GetImageData(*image);
     Color *pixels = GetImageData(*image);
     Color *output = (Color *)RL_MALLOC(newWidth*newHeight*sizeof(Color));
     Color *output = (Color *)RL_MALLOC(newWidth*newHeight*sizeof(Color));
 
 
@@ -1411,18 +1439,42 @@ void ImageResizeNN(Image *image,int newWidth,int newHeight)
 
 
 // Resize canvas and fill with color
 // Resize canvas and fill with color
 // NOTE: Resize offset is relative to the top-left corner of the original image
 // NOTE: Resize offset is relative to the top-left corner of the original image
-void ImageResizeCanvas(Image *image, int newWidth,int newHeight, int offsetX, int offsetY, Color color)
+void ImageResizeCanvas(Image *image, int newWidth, int newHeight, int offsetX, int offsetY, Color color)
 {
 {
-    // TODO: Review different scaling situations
+    // Security check to avoid program crash
+    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
 
 
     if ((newWidth != image->width) || (newHeight != image->height))
     if ((newWidth != image->width) || (newHeight != image->height))
     {
     {
+        // Support offsets out of canvas new size -> original image is cropped
+        if (offsetX < 0)
+        {
+            ImageCrop(image, (Rectangle) { -offsetX, 0, image->width + offsetX, image->height });
+            offsetX = 0;
+        }
+        else if (offsetX > (newWidth - image->width))
+        {
+            ImageCrop(image, (Rectangle) { 0, 0, image->width - (offsetX - (newWidth - image->width)), image->height });
+            offsetX = newWidth - image->width;
+        }
+
+        if (offsetY < 0)
+        {
+            ImageCrop(image, (Rectangle) { 0, -offsetY, image->width, image->height + offsetY });
+            offsetY = 0;
+        }
+        else if (offsetY > (newHeight - image->height))
+        {
+            ImageCrop(image, (Rectangle) { 0, 0, image->width, image->height - (offsetY - (newHeight - image->height)) });
+            offsetY = newHeight - image->height;
+        }
+
         if ((newWidth > image->width) && (newHeight > image->height))
         if ((newWidth > image->width) && (newHeight > image->height))
         {
         {
             Image imTemp = GenImageColor(newWidth, newHeight, color);
             Image imTemp = GenImageColor(newWidth, newHeight, color);
 
 
             Rectangle srcRec = { 0.0f, 0.0f, (float)image->width, (float)image->height };
             Rectangle srcRec = { 0.0f, 0.0f, (float)image->width, (float)image->height };
-            Rectangle dstRec = { (float)offsetX, (float)offsetY, (float)srcRec.width, (float)srcRec.height };
+            Rectangle dstRec = { (float)offsetX, (float)offsetY, srcRec.width, srcRec.height };
 
 
             ImageDraw(&imTemp, *image, srcRec, dstRec);
             ImageDraw(&imTemp, *image, srcRec, dstRec);
             ImageFormat(&imTemp, image->format);
             ImageFormat(&imTemp, image->format);
@@ -1431,7 +1483,7 @@ void ImageResizeCanvas(Image *image, int newWidth,int newHeight, int offsetX, in
         }
         }
         else if ((newWidth < image->width) && (newHeight < image->height))
         else if ((newWidth < image->width) && (newHeight < image->height))
         {
         {
-            Rectangle crop = { (float)offsetX, (float)offsetY, newWidth, newHeight };
+            Rectangle crop = { (float)offsetX, (float)offsetY, (float)newWidth, (float)newHeight };
             ImageCrop(image, crop);
             ImageCrop(image, crop);
         }
         }
         else    // One side is bigger and the other is smaller
         else    // One side is bigger and the other is smaller
@@ -1439,13 +1491,12 @@ void ImageResizeCanvas(Image *image, int newWidth,int newHeight, int offsetX, in
             Image imTemp = GenImageColor(newWidth, newHeight, color);
             Image imTemp = GenImageColor(newWidth, newHeight, color);
 
 
             Rectangle srcRec = { 0.0f, 0.0f, (float)image->width, (float)image->height };
             Rectangle srcRec = { 0.0f, 0.0f, (float)image->width, (float)image->height };
-            Rectangle dstRec = { (float)offsetX, (float)offsetY, (float)newWidth, (float)newHeight };
+            Rectangle dstRec = { (float)offsetX, (float)offsetY, (float)image->width, (float)image->height };
 
 
             if (newWidth < image->width)
             if (newWidth < image->width)
             {
             {
                 srcRec.x = offsetX;
                 srcRec.x = offsetX;
                 srcRec.width = newWidth;
                 srcRec.width = newWidth;
-
                 dstRec.x = 0.0f;
                 dstRec.x = 0.0f;
             }
             }
 
 
@@ -1453,11 +1504,9 @@ void ImageResizeCanvas(Image *image, int newWidth,int newHeight, int offsetX, in
             {
             {
                 srcRec.y = offsetY;
                 srcRec.y = offsetY;
                 srcRec.height = newHeight;
                 srcRec.height = newHeight;
-
                 dstRec.y = 0.0f;
                 dstRec.y = 0.0f;
             }
             }
 
 
-            // TODO: ImageDraw() could be buggy?
             ImageDraw(&imTemp, *image, srcRec, dstRec);
             ImageDraw(&imTemp, *image, srcRec, dstRec);
             ImageFormat(&imTemp, image->format);
             ImageFormat(&imTemp, image->format);
             UnloadImage(*image);
             UnloadImage(*image);
@@ -1472,6 +1521,9 @@ void ImageResizeCanvas(Image *image, int newWidth,int newHeight, int offsetX, in
 // NOTE 3: Mipmaps format is the same as base image
 // NOTE 3: Mipmaps format is the same as base image
 void ImageMipmaps(Image *image)
 void ImageMipmaps(Image *image)
 {
 {
+    // Security check to avoid program crash
+    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
+
     int mipCount = 1;                   // Required mipmap levels count (including base level)
     int mipCount = 1;                   // Required mipmap levels count (including base level)
     int mipWidth = image->width;        // Base image width
     int mipWidth = image->width;        // Base image width
     int mipHeight = image->height;      // Base image height
     int mipHeight = image->height;      // Base image height
@@ -1546,6 +1598,9 @@ void ImageMipmaps(Image *image)
 // dithered data is stored in the LSB part of the unsigned short
 // dithered data is stored in the LSB part of the unsigned short
 void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp)
 void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp)
 {
 {
+    // Security check to avoid program crash
+    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
+
     if (image->format >= COMPRESSED_DXT1_RGB)
     if (image->format >= COMPRESSED_DXT1_RGB)
     {
     {
         TraceLog(LOG_WARNING, "Compressed data formats can not be dithered");
         TraceLog(LOG_WARNING, "Compressed data formats can not be dithered");
@@ -1702,10 +1757,11 @@ Color *ImageExtractPalette(Image image, int maxPaletteSize, int *extractCount)
 }
 }
 
 
 // Draw an image (source) within an image (destination)
 // Draw an image (source) within an image (destination)
-// TODO: Feel this function could be simplified...
 void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec)
 void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec)
 {
 {
-    bool cropRequired = false;
+    // Security check to avoid program crash
+    if ((dst->data == NULL) || (dst->width == 0) || (dst->height == 0) ||
+        (src.data == NULL) || (src.width == 0) || (src.height == 0)) return;
 
 
     // Security checks to avoid size and rectangle issues (out of bounds)
     // Security checks to avoid size and rectangle issues (out of bounds)
     // Check that srcRec is inside src image
     // Check that srcRec is inside src image
@@ -1727,45 +1783,50 @@ void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec)
     Image srcCopy = ImageCopy(src);     // Make a copy of source image to work with it
     Image srcCopy = ImageCopy(src);     // Make a copy of source image to work with it
     ImageCrop(&srcCopy, srcRec);        // Crop source image to desired source rectangle
     ImageCrop(&srcCopy, srcRec);        // Crop source image to desired source rectangle
 
 
-    // Check that dstRec is inside dst image
-    // TODO: Allow negative position within destination with cropping
-    if (dstRec.x < 0) dstRec.x = 0;
-    if (dstRec.y < 0) dstRec.y = 0;
-
     // Scale source image in case destination rec size is different than source rec size
     // Scale source image in case destination rec size is different than source rec size
-    if ((dstRec.width != srcRec.width) || (dstRec.height != srcRec.height)) ImageResize(&srcCopy, (int)dstRec.width, (int)dstRec.height);
-
+    if (((int)dstRec.width != (int)srcRec.width) || ((int)dstRec.height != (int)srcRec.height))
+    {
+        ImageResize(&srcCopy, (int)dstRec.width, (int)dstRec.height);
+    }
+    
+    // Check that dstRec is inside dst image
+    // Allow negative position within destination with cropping
+    if (dstRec.x < 0)
+    {
+        ImageCrop(&srcCopy, (Rectangle) { -dstRec.x, 0, dstRec.width + dstRec.x, dstRec.height });
+        dstRec.width = dstRec.width + dstRec.x;
+        dstRec.x = 0;
+    }
+    
     if ((dstRec.x + dstRec.width) > dst->width)
     if ((dstRec.x + dstRec.width) > dst->width)
     {
     {
+        ImageCrop(&srcCopy, (Rectangle) { 0, 0, dst->width - dstRec.x, dstRec.height });
         dstRec.width = dst->width - dstRec.x;
         dstRec.width = dst->width - dstRec.x;
-        TraceLog(LOG_WARNING, "Destination rectangle width out of bounds, rescaled width: %i", dstRec.width);
-        cropRequired = true;
     }
     }
 
 
-    if ((dstRec.y + dstRec.height) > dst->height)
+    if (dstRec.y < 0)
     {
     {
-        dstRec.height = dst->height - dstRec.y;
-        TraceLog(LOG_WARNING, "Destination rectangle height out of bounds, rescaled height: %i", dstRec.height);
-        cropRequired = true;
+        ImageCrop(&srcCopy, (Rectangle) { 0, -dstRec.y, dstRec.width, dstRec.height + dstRec.y });
+        dstRec.height = dstRec.height + dstRec.y;
+        dstRec.y = 0;
     }
     }
-
-    if (cropRequired)
+    
+    if (dstRec.y > (dst->height - dstRec.height))
     {
     {
-        // Crop destination rectangle if out of bounds
-        Rectangle crop = { 0, 0, dstRec.width, dstRec.height };
-        ImageCrop(&srcCopy, crop);
+        ImageCrop(&srcCopy, (Rectangle) { 0, 0, dstRec.width, dst->height - dstRec.y });
+        dstRec.height = dst->height - dstRec.y;
     }
     }
 
 
     // Get image data as Color pixels array to work with it
     // Get image data as Color pixels array to work with it
     Color *dstPixels = GetImageData(*dst);
     Color *dstPixels = GetImageData(*dst);
     Color *srcPixels = GetImageData(srcCopy);
     Color *srcPixels = GetImageData(srcCopy);
 
 
-    UnloadImage(srcCopy);       // Source copy not required any more...
+    UnloadImage(srcCopy);       // Source copy not required any more
 
 
     Vector4 fsrc, fdst, fout;   // float based versions of pixel data
     Vector4 fsrc, fdst, fout;   // float based versions of pixel data
 
 
     // Blit pixels, copy source image into destination
     // Blit pixels, copy source image into destination
-    // TODO: Probably out-of-bounds blitting could be considered here instead of so much cropping...
+    // TODO: Maybe out-of-bounds blitting could be considered here instead of so much cropping
     for (int j = (int)dstRec.y; j < (int)(dstRec.y + dstRec.height); j++)
     for (int j = (int)dstRec.y; j < (int)(dstRec.y + dstRec.height); j++)
     {
     {
         for (int i = (int)dstRec.x; i < (int)(dstRec.x + dstRec.width); i++)
         for (int i = (int)dstRec.x; i < (int)(dstRec.x + dstRec.width); i++)
@@ -1799,7 +1860,7 @@ void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec)
         }
         }
     }
     }
 
 
-    UnloadImage(*dst);  // NOTE: Only dst->data is unloaded
+    UnloadImage(*dst);
 
 
     *dst = LoadImageEx(dstPixels, (int)dst->width, (int)dst->height);
     *dst = LoadImageEx(dstPixels, (int)dst->width, (int)dst->height);
     ImageFormat(dst, dst->format);
     ImageFormat(dst, dst->format);
@@ -1900,6 +1961,9 @@ Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Co
 // Draw rectangle within an image
 // Draw rectangle within an image
 void ImageDrawRectangle(Image *dst, Rectangle rec, Color color)
 void ImageDrawRectangle(Image *dst, Rectangle rec, Color color)
 {
 {
+    // Security check to avoid program crash
+    if ((dst->data == NULL) || (dst->width == 0) || (dst->height == 0)) return;
+
     Image imRec = GenImageColor((int)rec.width, (int)rec.height, color);
     Image imRec = GenImageColor((int)rec.width, (int)rec.height, color);
     ImageDraw(dst, imRec, (Rectangle){ 0, 0, rec.width, rec.height }, rec);
     ImageDraw(dst, imRec, (Rectangle){ 0, 0, rec.width, rec.height }, rec);
     UnloadImage(imRec);
     UnloadImage(imRec);
@@ -1937,6 +2001,9 @@ void ImageDrawTextEx(Image *dst, Vector2 position, Font font, const char *text,
 // Flip image vertically
 // Flip image vertically
 void ImageFlipVertical(Image *image)
 void ImageFlipVertical(Image *image)
 {
 {
+    // Security check to avoid program crash
+    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
+
     Color *srcPixels = GetImageData(*image);
     Color *srcPixels = GetImageData(*image);
     Color *dstPixels = (Color *)RL_MALLOC(image->width*image->height*sizeof(Color));
     Color *dstPixels = (Color *)RL_MALLOC(image->width*image->height*sizeof(Color));
 
 
@@ -1961,6 +2028,9 @@ void ImageFlipVertical(Image *image)
 // Flip image horizontally
 // Flip image horizontally
 void ImageFlipHorizontal(Image *image)
 void ImageFlipHorizontal(Image *image)
 {
 {
+    // Security check to avoid program crash
+    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
+
     Color *srcPixels = GetImageData(*image);
     Color *srcPixels = GetImageData(*image);
     Color *dstPixels = (Color *)RL_MALLOC(image->width*image->height*sizeof(Color));
     Color *dstPixels = (Color *)RL_MALLOC(image->width*image->height*sizeof(Color));
 
 
@@ -1985,6 +2055,9 @@ void ImageFlipHorizontal(Image *image)
 // Rotate image clockwise 90deg
 // Rotate image clockwise 90deg
 void ImageRotateCW(Image *image)
 void ImageRotateCW(Image *image)
 {
 {
+    // Security check to avoid program crash
+    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
+
     Color *srcPixels = GetImageData(*image);
     Color *srcPixels = GetImageData(*image);
     Color *rotPixels = (Color *)RL_MALLOC(image->width*image->height*sizeof(Color));
     Color *rotPixels = (Color *)RL_MALLOC(image->width*image->height*sizeof(Color));
 
 
@@ -2011,6 +2084,9 @@ void ImageRotateCW(Image *image)
 // Rotate image counter-clockwise 90deg
 // Rotate image counter-clockwise 90deg
 void ImageRotateCCW(Image *image)
 void ImageRotateCCW(Image *image)
 {
 {
+    // Security check to avoid program crash
+    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
+
     Color *srcPixels = GetImageData(*image);
     Color *srcPixels = GetImageData(*image);
     Color *rotPixels = (Color *)RL_MALLOC(image->width*image->height*sizeof(Color));
     Color *rotPixels = (Color *)RL_MALLOC(image->width*image->height*sizeof(Color));
 
 
@@ -2037,6 +2113,9 @@ void ImageRotateCCW(Image *image)
 // Modify image color: tint
 // Modify image color: tint
 void ImageColorTint(Image *image, Color color)
 void ImageColorTint(Image *image, Color color)
 {
 {
+    // Security check to avoid program crash
+    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
+
     Color *pixels = GetImageData(*image);
     Color *pixels = GetImageData(*image);
 
 
     float cR = (float)color.r/255;
     float cR = (float)color.r/255;
@@ -2072,6 +2151,9 @@ void ImageColorTint(Image *image, Color color)
 // Modify image color: invert
 // Modify image color: invert
 void ImageColorInvert(Image *image)
 void ImageColorInvert(Image *image)
 {
 {
+    // Security check to avoid program crash
+    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
+
     Color *pixels = GetImageData(*image);
     Color *pixels = GetImageData(*image);
 
 
     for (int y = 0; y < image->height; y++)
     for (int y = 0; y < image->height; y++)
@@ -2102,6 +2184,9 @@ void ImageColorGrayscale(Image *image)
 // NOTE: Contrast values between -100 and 100
 // NOTE: Contrast values between -100 and 100
 void ImageColorContrast(Image *image, float contrast)
 void ImageColorContrast(Image *image, float contrast)
 {
 {
+    // Security check to avoid program crash
+    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
+
     if (contrast < -100) contrast = -100;
     if (contrast < -100) contrast = -100;
     if (contrast > 100) contrast = 100;
     if (contrast > 100) contrast = 100;
 
 
@@ -2156,6 +2241,9 @@ void ImageColorContrast(Image *image, float contrast)
 // NOTE: Brightness values between -255 and 255
 // NOTE: Brightness values between -255 and 255
 void ImageColorBrightness(Image *image, int brightness)
 void ImageColorBrightness(Image *image, int brightness)
 {
 {
+    // Security check to avoid program crash
+    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
+
     if (brightness < -255) brightness = -255;
     if (brightness < -255) brightness = -255;
     if (brightness > 255) brightness = 255;
     if (brightness > 255) brightness = 255;
 
 
@@ -2195,6 +2283,9 @@ void ImageColorBrightness(Image *image, int brightness)
 // Modify image color: replace color
 // Modify image color: replace color
 void ImageColorReplace(Image *image, Color color, Color replace)
 void ImageColorReplace(Image *image, Color color, Color replace)
 {
 {
+    // Security check to avoid program crash
+    if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
+
     Color *pixels = GetImageData(*image);
     Color *pixels = GetImageData(*image);
 
 
     for (int y = 0; y < image->height; y++)
     for (int y = 0; y < image->height; y++)