const char * UsageLines [] = { "Usage: p6orient", " output width", " output height", " input pivot point #1 across", " input pivot point #1 down", " input pivot point #2 across", " input pivot point #2 down", " output pivot point #1 across", " output pivot point #1 down", " output pivot point #2 across", " output pivot point #2 down", "", "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.", "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.", "December 9, 2025. Newest is at gopher -p users/julianbr sdf.org", }; const int NumUsageLines = sizeof (UsageLines)/sizeof (UsageLines [0] ); #include #include #include 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 < - 0) { 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 > - 0) { 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) { /* Go to left edge */ while (OutputAcross < 0) { 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 > 0) { 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) { if ( InputAcross >= 0 && InputAcross < InputWidth && InputDown >= 0 && InputDown < InputHeight) fwrite ( InputPixels [InputDown] + InputAcross, 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 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; char c; if (argc < 2) { for (i = 0; i < NumUsageLines; i++) printf ("%s\n", UsageLines [i] ); } else if (argc == 11) { ok = 1; if (sscanf (argv [1], "%d%c", & OutputWidth, & c) != 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%c", & OutputHeight, & c) != 1 || OutputHeight < 1) { fprintf (stderr, "***p6orient: Expecting output"); fprintf (stderr, " height,"); fprintf (stderr, " found \"%s\".\n", argv [2] ); ok = 0; } if ( sscanf (argv [3], "%d%c", & InputPoint1Across, & c) != 1 || sscanf (argv [4], "%d%c", & InputPoint1Down, & c) != 1 || sscanf (argv [5], "%d%c", & InputPoint2Across, & c) != 1 || sscanf (argv [6], "%d%c", & InputPoint2Down, & c) != 1 || sscanf (argv [7], "%d%c", & OutputPoint1Across, & c) != 1 || sscanf (argv [8], "%d%c", & OutputPoint1Down, & c) != 1 || sscanf (argv [9], "%d%c", & OutputPoint2Across, & c) != 1 || sscanf (argv [10], "%d%c", & OutputPoint2Down, & c) != 1 ) { fprintf (stderr, "***p6orient: Need 8 numbers: across & down for\n"); fprintf (stderr, "two input points, across & down for two output points.\n"); fprintf (stderr, "Found"); for (i = 3; i < 11; i++) fprintf (stderr, " %s", argv [i] ); fprintf (stderr, "\n"); 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; }