+// Returns a smaller image composed of the specified crop area from the larger area.
+// If the specified area is larger than is in the original, returns NULL.
+EG_IMAGE * egCropImage(IN EG_IMAGE *Image, IN UINTN StartX, IN UINTN StartY, IN UINTN Width, IN UINTN Height) {
+ EG_IMAGE *NewImage = NULL;
+ UINTN x, y;
+
+ if (((StartX + Width) > Image->Width) || ((StartY + Height) > Image->Height))
+ return NULL;
+
+ NewImage = egCreateImage(Width, Height, Image->HasAlpha);
+ if (NewImage == NULL)
+ return NULL;
+
+ for (y = 0; y < Height; y++) {
+ for (x = 0; x < Width; x++) {
+ NewImage->PixelData[y * NewImage->Width + x] = Image->PixelData[(y + StartY) * Image->Width + x + StartX];
+ }
+ }
+ return NewImage;
+} // EG_IMAGE * egCropImage()
+
+// The following function implements a bilinear image scaling algorithm, based on
+// code presented at http://tech-algorithm.com/articles/bilinear-image-scaling/.
+// Resize an image; returns pointer to resized image if successful, NULL otherwise.
+// Calling function is responsible for freeing allocated memory.
+// NOTE: x_ratio, y_ratio, x_diff, and y_diff should really be float values;
+// however, I've found that my 32-bit Mac Mini has a buggy EFI (or buggy CPU?), which
+// causes this function to hang on float-to-UINT8 conversions on some (but not all!)
+// float values. Therefore, this function uses integer arithmetic but multiplies
+// all values by FP_MULTIPLIER to achieve something resembling the sort of precision
+// needed for good results.
+EG_IMAGE * egScaleImage(IN EG_IMAGE *Image, IN UINTN NewWidth, IN UINTN NewHeight) {
+ EG_IMAGE *NewImage = NULL;
+ EG_PIXEL a, b, c, d;
+ UINTN x, y, Index ;
+ UINTN i, j;
+ UINTN Offset = 0;
+ UINTN x_ratio, y_ratio, x_diff, y_diff;
+
+ if ((Image == NULL) || (Image->Height == 0) || (Image->Width == 0) || (NewWidth == 0) || (NewHeight == 0))
+ return NULL;
+
+ if ((Image->Width == NewWidth) && (Image->Height == NewHeight))
+ return (egCopyImage(Image));
+
+ NewImage = egCreateImage(NewWidth, NewHeight, Image->HasAlpha);
+ if (NewImage == NULL)
+ return NULL;
+
+ x_ratio = ((Image->Width - 1) * FP_MULTIPLIER) / NewWidth;
+ y_ratio = ((Image->Height - 1) * FP_MULTIPLIER) / NewHeight;
+
+ for (i = 0; i < NewHeight; i++) {
+ for (j = 0; j < NewWidth; j++) {
+ x = (j * (Image->Width - 1)) / NewWidth;
+ y = (i * (Image->Height - 1)) / NewHeight;
+ x_diff = (x_ratio * j) - x * FP_MULTIPLIER;
+ y_diff = (y_ratio * i) - y * FP_MULTIPLIER;
+ Index = ((y * Image->Width) + x);
+ a = Image->PixelData[Index];
+ b = Image->PixelData[Index + 1];
+ c = Image->PixelData[Index + Image->Width];
+ d = Image->PixelData[Index + Image->Width + 1];
+
+ // blue element
+ NewImage->PixelData[Offset].b = ((a.b) * (FP_MULTIPLIER - x_diff) * (FP_MULTIPLIER - y_diff) +
+ (b.b) * (x_diff) * (FP_MULTIPLIER - y_diff) +
+ (c.b) * (y_diff) * (FP_MULTIPLIER - x_diff) +
+ (d.b) * (x_diff * y_diff)) / (FP_MULTIPLIER * FP_MULTIPLIER);
+
+ // green element
+ NewImage->PixelData[Offset].g = ((a.g) * (FP_MULTIPLIER - x_diff) * (FP_MULTIPLIER - y_diff) +
+ (b.g) * (x_diff) * (FP_MULTIPLIER - y_diff) +
+ (c.g) * (y_diff) * (FP_MULTIPLIER - x_diff) +
+ (d.g) * (x_diff * y_diff)) / (FP_MULTIPLIER * FP_MULTIPLIER);
+
+ // red element
+ NewImage->PixelData[Offset].r = ((a.r) * (FP_MULTIPLIER - x_diff) * (FP_MULTIPLIER - y_diff) +
+ (b.r) * (x_diff) * (FP_MULTIPLIER - y_diff) +
+ (c.r) * (y_diff) * (FP_MULTIPLIER - x_diff) +
+ (d.r) * (x_diff * y_diff)) / (FP_MULTIPLIER * FP_MULTIPLIER);
+
+ // alpha element
+ NewImage->PixelData[Offset++].a = ((a.a) * (FP_MULTIPLIER - x_diff) * (FP_MULTIPLIER - y_diff) +
+ (b.a) * (x_diff) * (FP_MULTIPLIER - y_diff) +
+ (c.a) * (y_diff) * (FP_MULTIPLIER - x_diff) +
+ (d.a) * (x_diff * y_diff)) / (FP_MULTIPLIER * FP_MULTIPLIER);
+ } // for (j...)
+ } // for (i...)
+ return NewImage;
+} // EG_IMAGE * egScaleImage()
+