const char * UsageLines [] = { "Usage: p6orient (output width) (output height)", " (pivot point #1) (pivot point #2)", "Shifts, rotates, and resizes input image so that", " the two input pivots are positioned as", " specified on the output image.", "Output is cropped or padded (with gray) as needed", " to reach specified output dimensions.", "Reads P6 PPM image from standard input,", " writes PPM image to standard output.", "Each pivot point is of the form:", " (input across),(input down)=(output across),(output down)", " where the leftmost pixels are (- width/2) across,", " and the topmost pixels are (- height/2) down.", "For example, 0,0=0,0 matches the center of the input image", " with the center of the output image.", "Pixels are moved, repeated, or skipped to produce output", " image. No recalculating of pixel values is done.", "With appropriate choice of pivot points, p6orient can be", " used to pad, crop, or resize an image.", "For example: 0,0=0,0 0,1=0,1", " will keep the center as the center and not resize,", " if the supplied output dimensions are smaller than the input", " it will crop, and,", " if the supplied output dimensions are larger than the input", " it will pad.", "November 24, 2011. Newest is at gopher -p users/julianbr sdf.org", }; const int NumUsageLines = sizeof (UsageLines)/sizeof (UsageLines [0] ); #include <stdlib.h> #include <stdio.h> #include <string.h> void OrientImage ( char (* * InputPixels) [3], int InputWidth, int InputHeight, int OutputWidth, int OutputHeight, int InputPoint1Across, int InputPoint1Down, int OutputPoint1Across, int OutputPoint1Down, int InputPoint2Across, int InputPoint2Down, int OutputPoint2Across, int OutputPoint2Down) { char PaddingPixel [] = {200, 200, 200}; int InputAcross, InputDown, OutputAcross, OutputDown; long int InputAcrossRemainder, InputDownRemainder; long int OutputDotOutput, OutputDotInput, OutputCrossInput; OutputDotOutput = (OutputPoint2Across - OutputPoint1Across) *(OutputPoint2Across - OutputPoint1Across) + (OutputPoint2Down - OutputPoint1Down) *(OutputPoint2Down - OutputPoint1Down); OutputDotInput = (OutputPoint2Across - OutputPoint1Across) *(InputPoint2Across - InputPoint1Across) + (OutputPoint2Down - OutputPoint1Down) *(InputPoint2Down - InputPoint1Down); OutputCrossInput = (OutputPoint2Down - OutputPoint1Down) *(InputPoint2Across - InputPoint1Across) - (OutputPoint2Across - OutputPoint1Across) *(InputPoint2Down - InputPoint1Down); printf ("P6\n"); printf ("%d", OutputWidth); printf (" %d\n", OutputHeight); printf ("255\n"); /* Start at pivot point 1 */ OutputAcross = OutputPoint1Across; OutputDown = OutputPoint1Down; InputAcross = InputPoint1Across; InputAcrossRemainder = OutputDotOutput/2; InputDown = InputPoint1Down; InputDownRemainder = OutputDotOutput/2; /* Go to top edge */ while (OutputDown < - OutputHeight/2) { InputAcrossRemainder += OutputCrossInput; while (InputAcrossRemainder < 0) { InputAcrossRemainder += OutputDotOutput; InputAcross--; } while (InputAcrossRemainder >= OutputDotOutput) { InputAcrossRemainder -= OutputDotOutput; InputAcross++; } InputDownRemainder += OutputDotInput; while (InputDownRemainder < 0) { InputDownRemainder += OutputDotOutput; InputDown--; } while (InputDownRemainder >= OutputDotOutput) { InputDownRemainder -= OutputDotOutput; InputDown++; } OutputDown++; } while (OutputDown > - OutputHeight/2) { InputAcrossRemainder -= OutputCrossInput; while (InputAcrossRemainder < 0) { InputAcrossRemainder += OutputDotOutput; InputAcross--; } while (InputAcrossRemainder >= OutputDotOutput) { InputAcrossRemainder -= OutputDotOutput; InputAcross++; } InputDownRemainder -= OutputDotInput; while (InputDownRemainder < 0) { InputDownRemainder += OutputDotOutput; InputDown--; } while (InputDownRemainder >= OutputDotOutput) { InputDownRemainder -= OutputDotOutput; InputDown++; } OutputDown--; } while (OutputDown < OutputHeight - OutputHeight/2) { /* Go to left edge */ while (OutputAcross < - OutputWidth/2) { InputAcrossRemainder += OutputDotInput; while (InputAcrossRemainder < 0) { InputAcrossRemainder += OutputDotOutput; InputAcross--; } while (InputAcrossRemainder >= OutputDotOutput) { InputAcrossRemainder -= OutputDotOutput; InputAcross++; } InputDownRemainder -= OutputCrossInput; while (InputDownRemainder < 0) { InputDownRemainder += OutputDotOutput; InputDown--; } while (InputDownRemainder >= OutputDotOutput) { InputDownRemainder -= OutputDotOutput; InputDown++; } OutputAcross++; } while (OutputAcross > - OutputWidth/2) { InputAcrossRemainder -= OutputDotInput; while (InputAcrossRemainder < 0) { InputAcrossRemainder += OutputDotOutput; InputAcross--; } while (InputAcrossRemainder >= OutputDotOutput) { InputAcrossRemainder -= OutputDotOutput; InputAcross++; } InputDownRemainder += OutputCrossInput; while (InputDownRemainder < 0) { InputDownRemainder += OutputDotOutput; InputDown--; } while (InputDownRemainder >= OutputDotOutput) { InputDownRemainder -= OutputDotOutput; InputDown++; } OutputAcross--; } while (OutputAcross < OutputWidth - OutputWidth/2) { if ( InputAcross >= - InputWidth/2 && InputAcross < InputWidth - InputWidth/2 && InputDown >= - InputHeight/2 && InputDown < InputHeight - InputHeight/2) fwrite ( InputPixels [InputDown + InputHeight/2] + InputAcross + InputWidth/2, sizeof (InputPixels [0] [0] ), 1, stdout); else { fwrite ( PaddingPixel, sizeof (InputPixels [0] [0] ), 1, stdout); } InputAcrossRemainder += OutputDotInput; while (InputAcrossRemainder < 0) { InputAcrossRemainder += OutputDotOutput; InputAcross--; } while (InputAcrossRemainder >= OutputDotOutput) { InputAcrossRemainder -= OutputDotOutput; InputAcross++; } InputDownRemainder -= OutputCrossInput; while (InputDownRemainder < 0) { InputDownRemainder += OutputDotOutput; InputDown--; } while (InputDownRemainder >= OutputDotOutput) { InputDownRemainder -= OutputDotOutput; InputDown++; } OutputAcross++; } InputAcrossRemainder += OutputCrossInput; while (InputAcrossRemainder < 0) { InputAcrossRemainder += OutputDotOutput; InputAcross--; } while (InputAcrossRemainder >= OutputDotOutput) { InputAcrossRemainder -= OutputDotOutput; InputAcross++; } InputDownRemainder += OutputDotInput; while (InputDownRemainder < 0) { InputDownRemainder += OutputDotOutput; InputDown--; } while (InputDownRemainder >= OutputDotOutput) { InputDownRemainder -= OutputDotOutput; InputDown++; } OutputDown++; } } int ReadImage ( char (* * * PixelsPtr) [3], int * WidthPtr, int * HeightPtr) { int i, j, maxval; PixelsPtr [0] = NULL; if (getchar () != 'P' || getchar () != '6' || getchar () != '\n' || scanf ("%d", WidthPtr) < 1 || scanf ("%d", HeightPtr) < 1 || scanf ("%d", & maxval) < 1 || WidthPtr [0] < 1 || HeightPtr [0] < 1 || maxval != 255 || getchar () != '\n') { fprintf (stderr, "***p6orient: Improper input type, not"); fprintf (stderr, " P6 ppm image with maxval=255.\n"); return 0; } PixelsPtr [0] = malloc (HeightPtr [0]*sizeof (PixelsPtr [0] [0] ) ); if (PixelsPtr [0] == NULL) { fprintf (stderr, "***p6orient: Not enough memory.\n"); return 0; } for (i = 0; i < HeightPtr [0]; i++) PixelsPtr [0] [i] = NULL; for (i = 0; i < HeightPtr [0]; i++) { PixelsPtr [0] [i] = malloc ( WidthPtr [0]*sizeof (PixelsPtr [0] [0] [0] ) ); if (PixelsPtr [0] [i] == NULL) { fprintf (stderr, "***p6orient: Not enough memory.\n"); return 0; } } for (i = 0; i < HeightPtr [0]; i++) { for (j = 0; j < WidthPtr [0]; j++) memset (PixelsPtr [0] [i] [j], '.', sizeof (PixelsPtr [0] [0] [0] ) ); } for (i = 0; i < HeightPtr [0]; i++) { for (j = 0; j < WidthPtr [0]; j++) { if (fread (PixelsPtr [0] [i] [j], sizeof (PixelsPtr [0] [0] [0] ), 1, stdin) < 1) { fprintf (stderr, "***p6orient: Premature"); fprintf (stderr, " end of input image"); fprintf (stderr, " data.\n"); return 1; /* proceed anyway */ } } } if (getchar () != EOF) fprintf (stderr, "***p6orient: Improper extra input data.\n"); return 1; } void ClosePixels ( char (* * Pixels) [3], unsigned int height) { unsigned int i; if (Pixels != NULL) { for (i = 0; i < height; i++) { if (Pixels [i] != NULL) free (Pixels [i] ); } free (Pixels); } } int ReadPivotPoint ( char * point, int * InputAcrossPtr, int * InputDownPtr, int * OutputAcrossPtr, int * OutputDownPtr) { char * ptr; int negative; ptr = point; negative = 0; if (ptr [0] == '-') { negative = 1; ptr++; } InputAcrossPtr [0] = 0; while (ptr [0] >= '0' && ptr [0] <= '9') { InputAcrossPtr [0] = 10*InputAcrossPtr [0] + (ptr [0] - '0'); ptr++; } if (negative) InputAcrossPtr [0] = - InputAcrossPtr [0]; if (ptr [0] != ',') { fprintf (stderr, "***p6orient: Expecting comma, found"); fprintf (stderr, " improper character: \"%s\".\n", point); return 0; } ptr++; negative = 0; if (ptr [0] == '-') { negative = 1; ptr++; } InputDownPtr [0] = 0; while (ptr [0] >= '0' && ptr [0] <= '9') { InputDownPtr [0] = 10*InputDownPtr [0] + (ptr [0] - '0'); ptr++; } if (negative) InputDownPtr [0] = - InputDownPtr [0]; if (ptr [0] != '=') { fprintf (stderr, "***p6orient: Expecting =, found improper"); fprintf (stderr, " character: \"%s\".\n", point); return 0; } ptr++; negative = 0; if (ptr [0] == '-') { negative = 1; ptr++; } OutputAcrossPtr [0] = 0; while (ptr [0] >= '0' && ptr [0] <= '9') { OutputAcrossPtr [0] = 10*OutputAcrossPtr [0] + (ptr [0] - '0'); ptr++; } if (negative) OutputAcrossPtr [0] = - OutputAcrossPtr [0]; if (ptr [0] != ',') { fprintf (stderr, "***p6orient: Expecting comma, found"); fprintf (stderr, " improper character: \"%s\".\n", point); return 0; } ptr++; negative = 0; if (ptr [0] == '-') { negative = 1; ptr++; } OutputDownPtr [0] = 0; while (ptr [0] >= '0' && ptr [0] <= '9') { OutputDownPtr [0] = 10*OutputDownPtr [0] + (ptr [0] - '0'); ptr++; } if (negative) OutputDownPtr [0] = - OutputDownPtr [0]; if (ptr [0] != '\0') { fprintf (stderr, "***p6orient: Improper character(s) at"); fprintf (stderr, " end: \"%s\".\n", point); return 0; } return 1; } int main (int argc, char * argv [] ) { char (* * InputPixels) [3]; int InputWidth, InputHeight, OutputWidth, OutputHeight; int InputPoint1Across, InputPoint1Down; int InputPoint2Across, InputPoint2Down; int OutputPoint1Across, OutputPoint1Down; int OutputPoint2Across, OutputPoint2Down; int i, ok; if (argc < 2) { for (i = 0; i < NumUsageLines; i++) printf ("%s\n", UsageLines [i] ); } else if (argc == 5) { ok = 1; if (sscanf (argv [1], "%d", & OutputWidth) != 1 || OutputWidth < 1) { fprintf (stderr, "***p6orient: Expecting output"); fprintf (stderr, " width,"); fprintf (stderr, " found \"%s\".\n", argv [1] ); ok = 0; } if (sscanf (argv [2], "%d", & OutputHeight) != 1 || OutputHeight < 1) { fprintf (stderr, "***p6orient: Expecting output"); fprintf (stderr, " height,"); fprintf (stderr, " found \"%s\".\n", argv [2] ); } if (!ReadPivotPoint ( argv [3], & InputPoint1Across, & InputPoint1Down, & OutputPoint1Across, & OutputPoint1Down) ) ok = 0; if (!ReadPivotPoint ( argv [4], & InputPoint2Across, & InputPoint2Down, & OutputPoint2Across, & OutputPoint2Down) ) ok = 0; if (ok) { if (OutputPoint1Across == OutputPoint2Across && OutputPoint1Down == OutputPoint2Down) { fprintf (stderr, "***p6orient: Both pivot"); fprintf (stderr, " points are at same"); fprintf (stderr, " output location:"); fprintf (stderr, " %d,", OutputPoint1Across); fprintf (stderr, "%d\n", OutputPoint1Down); ok = 0; } } if (ok) { if (ReadImage ( & InputPixels, & InputWidth, & InputHeight) ) { OrientImage ( InputPixels, InputWidth, InputHeight, OutputWidth, OutputHeight, InputPoint1Across, InputPoint1Down, OutputPoint1Across, OutputPoint1Down, InputPoint2Across, InputPoint2Down, OutputPoint2Across, OutputPoint2Down ); ClosePixels (InputPixels, InputHeight); } else ClosePixels (InputPixels, InputHeight); } } else { fprintf (stderr, "Usage: p6orient"); fprintf (stderr, " (output width)"); fprintf (stderr, " (output height)"); fprintf (stderr, " (pivot point #1)"); fprintf (stderr, " (pivot point #2)\n"); } return 0; }