/******************************************************************* * Resize.c * * ======== * * * * USE: * * Resize newImgWidth newImgHeight printer halftone interp * * * * interp = { repeat, avg } * * dimensions given in pixels * * * * * * DESRIPTION: * * This program takes an image, its original width and height in * * number of pixels, and the desired width and height in number of * * pixels. It will create a new image of the desired width and * * height, using one of the following algorithms: * * * * 1. Repeated pixel * * 2. Weighted averaging * * * * For non-integer scaling, the program will first interpolate to * * enlarge the image, then sample. * * * * * * REVISIONS: * * A JPK 3/5/97 Assuming we get image string * * Pointers ARE used. * * Extract rgb components * * B JPK 3/7/97 Expand by repeated pixel done * * C JPK 3/8/97 Expand by interpolation/avg done * * D JPK 3/8/97 Sampling done * * E JPK 3/10/97 Finally! get_hinfo works! * * F JPK 3/10/97 get_pinfo works. * * get_hinfo assumes linear matrix mapping * * G JPK 3/10/97 CMYK calibration now assumes exp mapping * * RGB to XYZ conversion works * * H JPK 3/11/97 XYZ2CMYK tested. print statements removed * * from get_number. get_number changed to * * return a value. Fixed bug in getting DPI * * values. Problems with pointers and memory * * allocation fixed. * * I JPK 3/11/97 Code complete except for piping info in and * * out. Print statements available for viewing * * results. * * J JPK 3/12/97 Results printed to stdout. Order of * * arguments passed to function changed. * * L JPK 3/12/97 Pipe in image * * M JPK 3/13/97 Runs a little faster...no need to call * * extract_rgb since image piped in directly to * * RGB matrices. Fixed sample ratio to be float * * in both resize routines. Also changed the * * sample increment and position to be floats, * * only to be converted to int before usage * * N JPK 3/14/97 Updated printer calibration: conversion of * * monitor XYZ to amounts of absorption based on * * printer/paper white point's XYZ. Read in * * image width and height from image file. * * Changed arguments to be passed to function. * * Fixed bug with padding. Can use different * * functions for tone reproduction correction * * O JPK 3/14/97 Fixed get_number to account for neg. numbers * * P JPK 3/14/97 Scaling of XYZ for white point and truncation * * Q JPK 3/14/97 New functions for error diffusion * *******************************************************************/ #include#include #include #include #include #define REPEAT 0 #define AVG 1 #define GREY 1 #define COLOR 2 #define PI 3.14159265359 /******************************************************************* * get_number * * ========== * * Takes a string and removes the first number in that string. * * It updates the string so that it is pointing to the first * * position after the number and returns that updated string * * in UpdatedString. Function also returns the number. * *******************************************************************/ float get_number(String, UpdatedString) char *String; char *UpdatedString; { char c; char *IntString, *DecString; char *BeginIntString, *BeginDecString, *BeginString; int Mult, Count; int temp, negative; float Number; /* Initialize variables */ negative = 0; IntString = malloc(sizeof(char) * strlen(String)); DecString = malloc(sizeof(char) * strlen(String)); BeginIntString = IntString; BeginDecString = DecString; Number = 0; /* Remove any commas, white spaces, etc., so that String * points to the first number remaining the line. Since * the number could be less than one and start with a decimal * point, function also checks for decimal points. Number * could also be negative number. */ while ((isdigit(*String) == 0) && (*String != '.') && (*String != '-')) { String++; } /* As long as String has valid numerical values, add * that to IntString (this is the integer part of the * number). */ Count = 0; BeginString = String; while ((isdigit(*String) != 0) || (*String == '-')) { if (*String == '-') { negative = 1; BeginString++; Count--; } Count++; String++; } strncpy(IntString, BeginString, Count); IntString[Count] = '\0'; /* Terminate string */ /* If there is a decimal portion to the number, * put that part of the string into DecString. */ Count = 0; BeginString = String; if (*String == '.') { String++; BeginString++; while (isdigit(*String) != 0) { Count++; String++; } } strncpy(DecString, BeginString, Count); DecString[Count] = '\0'; /* Terminate string */ /* Make UpdatedString point to current position of String */ strcpy(UpdatedString,String); /* Reset pointers for DecString and IntString to point * to the beginning of their respective strings */ DecString = BeginDecString; IntString = BeginIntString; /* Now convert the strings representing the number into * an actual floating point representation */ Number = atoi(IntString); Mult = strlen(DecString); Number = Number + pow(0.10, (float)Mult) * atoi(DecString); if (negative == 1) Number = Number * (-1); /* Free up memory */ free (DecString); free (IntString); return Number; } /******************************************************************* * get_pinfo * * ========= * * Extracts the information needed to transform XYZ to CMYK for * * the particular printer specified. CConv, MConv, YConv, KConv * * are 1D arrays containing 3 elements each. Multiplying the 1D * * array by XYZ produces C, M, Y, or K. * *******************************************************************/ void get_pinfo(FileName, RConv, GConv, BConv, GreyDPI, ColorDPI, WhiteXYZ) char *FileName; float RConv[]; float GConv[]; float BConv[]; int GreyDPI[]; int ColorDPI[]; float WhiteXYZ[]; { FILE *FormatFile; char *TextLine, *LineMarker, *NewLineMarker; int MaxLine, Index, Mode; float Number, Number1, Number2; /* Initialize values */ MaxLine = 200; TextLine = malloc(sizeof(char) * MaxLine); LineMarker = malloc(sizeof(char) * MaxLine); NewLineMarker = malloc(sizeof(char) * MaxLine); /* Open file for reading. Make sure file exists. */ if ((FormatFile = fopen(FileName, "r")) == NULL) { fprintf(stderr,"get_hinfo: can't open %s\n", FileName); exit(1); } /* Get XYZ to printer RGB information */ while((fgets(TextLine, MaxLine, FormatFile) != NULL) && (strstr(TextLine, "#END") == NULL)) { if ((strstr(TextLine,"#BEGIN")) != NULL) { Index = 0; while (Index < 4) { fgets(TextLine, MaxLine, FormatFile); /* LineMarker indicates where = first occurs in TextLine. * If there is no = sign on this line, configuration file * is wrong */ if ((LineMarker = strchr(TextLine,'=')) == NULL) { fprintf(stderr, "Invalid configuration file for %s\n", FileName); exit(1); } /* get_number will continuously return the first number on * the line, and update LineMarker to point to the line position * after the first number has been removed from the line. The * 4th line of numbers that we get correspond to the XYZ values * for the white point. */ Number = get_number(LineMarker, NewLineMarker); if (Index == 3) WhiteXYZ[0] = Number; else RConv[Index] = Number; LineMarker=NewLineMarker; Number = get_number(LineMarker, NewLineMarker); if (Index == 3) WhiteXYZ[1] = Number; else GConv[Index] = Number; LineMarker=NewLineMarker; Number = get_number(LineMarker, NewLineMarker); if (Index == 3) WhiteXYZ[2] = Number; else BConv[Index] = Number; Index++; } } } /* Now get DPI information */ Index = 0; while((fgets(TextLine, MaxLine, FormatFile) != NULL) && (Index < 2)) { /* LineMarker indicates where = first occurs in TextLine. * If there is no = sign on this line, configuration file * is wrong */ if ((LineMarker = strchr(TextLine,'=')) == NULL) { fprintf(stderr, "Invalid configuration file for %s\n", FileName); exit(1); } if (strstr(TextLine,"Grey") != NULL) Mode = GREY; else if (strstr(TextLine,"Color") != NULL) Mode = COLOR; else { fprintf(stderr, "Invalid printer information\n"); exit(1); } /* get_number will continuously return the first number on * the line, and update LineMarker to point to the line position * after the first number has been removed from the line. */ Number1 = get_number(LineMarker, NewLineMarker); LineMarker=NewLineMarker; Number2 = get_number(LineMarker, NewLineMarker); switch (Mode) { case COLOR: { ColorDPI[0] = Number1; ColorDPI[1] = Number2; break; } case GREY: { GreyDPI[0] = Number1; GreyDPI[1] = Number2; break; } } Index++; } fclose(FormatFile); free(TextLine); free(LineMarker); } /******************************************************************* * get_hinfo * * ========= * * Extracts the information needed to transform CMYK to a * * calibrated CMYK for the particular halftone pattern specified. * * The function returns a 1D array, which contains 4 elements: * * The first element corresponds conversions for C, the second * * for M, the third for Y, the last for K. * *******************************************************************/ void get_hinfo(FileName, Conv) char *FileName; float Conv[4]; { FILE *FormatFile; char *TextLine, *LineMarker, *NewLineMarker; int MaxLine, Index; float Number; /* Initialize values */ MaxLine = 200; TextLine = malloc(sizeof(char) * MaxLine); NewLineMarker = malloc(sizeof(char) * MaxLine); /* Open file for reading. Make sure file exists. */ if ((FormatFile = fopen(FileName, "r")) == NULL) { fprintf(stderr, "get_hinfo: can't open %s\n", FileName); exit(1); } while((fgets(TextLine, MaxLine, FormatFile) != NULL) && (strstr(TextLine, "#END") == NULL)) { /* After getting the line #BEGIN, start filling in arrays * with transformation factors */ if ((strstr(TextLine,"#BEGIN")) != NULL) { for (Index = 0; Index < 4; Index++) { fgets(TextLine, MaxLine, FormatFile); /* LineMarker indicates where = first occurs in TextLine. * If there is no = sign on this line, configuration file * is wrong */ if ((LineMarker = strchr(TextLine,'=')) == NULL) { fprintf(stderr, "Invalid configuration file for %s\n", FileName); exit(1); } /* get_number will continuously return the first number on * the line, and update LineMarker to point to the line position * after the first number has been removed from the line. */ Number = get_number(LineMarker, NewLineMarker); Conv[Index] = Number; LineMarker = NewLineMarker; } } } fclose(FormatFile); free(TextLine); free(NewLineMarker); } /******************************************************************* * rgb2xyz * * ======= * * Takes 3 arrays representing R, G, and B and transforms them to * * 3 new arrays representing X, Y, Z. The transformation is based * * on the monitor calibration, since we assume that we want to * * match the printout to what appears on the monitor. We assume * * linear monitor RGB values. Transformation factors are taken * * from the Rendering.m tutorial (= XYZ'*phosphors). * *******************************************************************/ void rgb2xyz(R, G, B, X, Y, Z, ImgH, ImgW) unsigned char R[], G[], B[]; float X[], Y[], Z[]; int ImgH, ImgW; { int Row, Col, Index; float ScaledR, ScaledG, ScaledB; for (Row = 0; Row < ImgH; Row++) { for (Col = 0; Col < ImgW; Col++) { Index = Row * ImgW + Col; /* Because program reads in RGB values that run from 0 to 255, * but all conversion matrices assume RGB values from 0 to 1, * program needs to use scaled RGB values. */ ScaledR = R[Index] / 255.0; ScaledG = G[Index] / 255.0; ScaledB = B[Index] / 255.0; X[Index] = 25.9232 * ScaledR + 36.136 * ScaledG + 22.9809 * ScaledB; Y[Index] = 14.6733 * ScaledR + 69.9554 * ScaledG + 11.458 * ScaledB; Z[Index] = 1.3834 * ScaledR + 12.3235 * ScaledG + 119.3425 * ScaledB; } } } /******************************************************************* * xyz2cmyk * * ======== * * Takes 3 arrays representing X, Y, and Z and transforms them * * into 4 new arrays representing Cyan, Magenta, Yellow, Black. * * Because CMYK is a subtractive space, the program actually * * converts XYZ to printer-specific RGB, then converts that to * * CMYK by the formulae C=1-R, M=1-G, Y=1-B. For now, don't use K.* * The transformation is printer-specific and that information is * * stored in a file based on the printer name. * *******************************************************************/ void xyz2cmyk(X, Y, Z, Cyan, Magenta, Yellow, Black, ImgH, ImgW, Printer, GreyDPI, ColorDPI) float X[], Y[], Z[]; float Cyan[], Magenta[], Yellow[], Black[]; int GreyDPI[], ColorDPI[]; int ImgH, ImgW; char *Printer; { int Row, Col, Index; float RConv[3], GConv[3], BConv[3], WhiteXYZ[3]; float ScaledZ, ScaledX, ScaledY; get_pinfo(Printer, RConv, GConv, BConv, GreyDPI, ColorDPI, WhiteXYZ); /* printouts for testing purposes only */ /* printf("Printer Info\n"); *printf("RConv: %f %f %f, GConv: %f %f %f, BConv: %f %f %f\n",RConv[0],RConv[1],RConv[2],GConv[0],GConv[1],GConv[2],BConv[0],BConv[1],BConv[2]); *printf("DPI: Grey = %d, %d, Color = %d, %d\n", GreyDPI[0], GreyDPI[1], ColorDPI[0], ColorDPI[1]); *printf("Whitepoint: X= %f, Y=%f, Z=%f\n",WhiteXYZ[0], WhiteXYZ[1], WhiteXYZ[2]); */ for (Row = 0; Row < ImgH; Row++) { for (Col = 0; Col < ImgW; Col++) { Index = Row * ImgW + Col; /* Scale XYZ so that white looks white from printer */ ScaledX = X[Index] * (WhiteXYZ[0] / 85.0402); ScaledY = Y[Index] * (WhiteXYZ[1] / 96.0867); ScaledZ = Z[Index] * (WhiteXYZ[2] / 133.0494); Cyan[Index] = (WhiteXYZ[0] - ScaledX) * RConv[0] + (WhiteXYZ[1] - ScaledY) * RConv[1] + (WhiteXYZ[2] - ScaledZ) * RConv[2]; Magenta[Index] = (WhiteXYZ[0] - ScaledX) * GConv[0] + (WhiteXYZ[1] - ScaledY) * GConv[1] + (WhiteXYZ[2] - ScaledZ) * GConv[2]; Yellow[Index] = (WhiteXYZ[0] - ScaledX) * BConv[0] + (WhiteXYZ[1] - ScaledY) * BConv[1] + (WhiteXYZ[2] - ScaledZ) * BConv[2]; Black[Index] = 0x00; if (Cyan[Index] > 1) Cyan[Index] = 1; else if (Cyan[Index] < 0) Cyan[Index] = 0; if (Magenta[Index] > 1) Magenta[Index] = 1; else if (Magenta[Index] < 0) Magenta[Index] = 0; if (Yellow[Index] > 1) Yellow[Index] = 1; else if (Yellow[Index] < 0) Yellow[Index] = 0; /* printf("XYZ: %f %f %f %f \n",X[Index],Y[Index],Z[Index],ScaledZ); *printf("CMY: %f %f %f \n",Cyan[Index],Magenta[Index],Yellow[Index]); */ } } } /******************************************************************* * cmyk_calib * * ========== * * Takes CMYK data and calibrates it based on the halftoning * * pattern being used. Function outputs a new set of CMYK * * data to be output to the printer. Parameters associated with * * the halftone pattern/calibration transformation are stored in * * a file. * *******************************************************************/ void cmyk_calib(C, M, Y, K, NewC, NewM, NewY, NewK, ImgH, ImgW, Halftone) unsigned char NewC[], NewM[], NewY[], NewK[]; float C[], M[], Y[], K[]; int ImgH, ImgW; char *Halftone; { int Row, Col, Index; float Conv[4]; get_hinfo(Halftone, Conv); if (strcmp(Halftone,"errdiffuse") == 0) { for (Row = 0; Row < ImgH; Row++) { for (Col = 0; Col < ImgW; Col++) { Index = Row * ImgW + Col; NewC[Index] = (unsigned char)(255 * asin(C[Index]) * 2 / PI ); NewM[Index] = (unsigned char)(255 * pow(asin(M[Index]) * 2 / PI,-0.7)); NewY[Index] = (unsigned char)(255 * (-0.93199 + Y[Index]) / .1005); NewK[Index] = (unsigned char)(255 * asin(K[Index]) * 2 / PI ); } } } else { for (Row = 0; Row < ImgH; Row++) { for (Col = 0; Col < ImgW; Col++) { Index = Row * ImgW + Col; NewC[Index] = (unsigned char)(255 * pow(C[Index],Conv[0])); NewM[Index] = (unsigned char)(255 * pow(M[Index],Conv[1])); NewY[Index] = (unsigned char)(255 * pow(Y[Index],Conv[2])); NewK[Index] = (unsigned char)(255 * pow(K[Index],Conv[3])); } } } } /******************************************************************* * extract_rgb * * =========== * * Take the image, which is a string of characters--each character * * represents repeated sequence of alpha, red, green, blue. * * Generate 3 one-dimensional arrays, representing the red, green * * and blue components of the image. * *******************************************************************/ void extract_rgb(Img, ImgH, ImgW, ImgR, ImgG, ImgB) int ImgH, ImgW; unsigned char Img[]; unsigned char ImgR[]; unsigned char ImgG[]; unsigned char ImgB[]; { int row, col; for(row=0; row < ImgH; row++) { for(col=0; col < ImgW; col++) { ImgR[row*ImgW + col] = Img[4*row*ImgW + 4*col + 1]; ImgG[row*ImgW + col] = Img[4*row*ImgW + 4*col + 2]; ImgB[row*ImgW + col] = Img[4*row*ImgW + 4*col + 3]; } } } /******************************************************************* * sample * * ====== * * Takes an image and produces a new, smaller image that has * * a width and height that is a multiple of 8 pixels. If the * * desired size of the new, smaller image is not a multiple of 8, * * it is padded with white space. * *******************************************************************/ void sample(Img, ImgH, ImgW, NewImgH, NewImgW, PadH, PadW, NewImg) unsigned char Img[]; unsigned char NewImg[]; int ImgW, ImgH, NewImgH, NewImgW, PadH, PadW; { float SampleIncW, SampleIncH, TrueSampleCol, TrueSampleRow; int Row, Col, SampleCol, SampleRow; int TrueImgW, TrueImgH; /* Used to determine what pixel value in original image * corresponds to given pixel in new, sampled image. */ SampleIncW = ((float)ImgW) / NewImgW; SampleIncH = ((float)ImgH) / NewImgH; /* Actual image size depends on sampled image size + padding needed */ TrueImgW = NewImgW + PadW; TrueImgH = NewImgH + PadH; /* Sample rows and columns */ SampleRow = 0; TrueSampleRow = 0; for (Row = 0; Row < NewImgH; Row++) { /* Make sure that last pixel in column of new image is same * as last pixel in column of original image */ if (Row == (NewImgH - 1)) SampleRow = ImgH - 1; /* Get values from original image except for last pixel in row*/ SampleCol = 0; TrueSampleCol = 0; for (Col = 0; Col < (NewImgW - 1); Col++) { NewImg[Row * TrueImgW + Col] = Img[SampleRow * ImgW + SampleCol]; TrueSampleCol = TrueSampleCol + SampleIncW; SampleCol = floor(TrueSampleCol + 0.5); /* Need to add * 0.5 to simulate * rounding to the * nearest integer */ } /* Make sure that last pixel in row of new image is same * as last pixel in row of original image */ NewImg[Row * TrueImgW + Col] = Img[SampleRow * ImgW + (ImgW - 1)]; /* Pad image with white pixels to make image width a * multiple of 8 pixels */ for (Col = 0; Col < PadW; Col++) { NewImg[Row * TrueImgW + (Col + NewImgW)] = 0xff; } TrueSampleRow = TrueSampleRow + SampleIncH; SampleRow = floor(TrueSampleRow + 0.5); } /* Pad image rows with white pixels to make image height a * multiple of 8 pixels */ for (Row = 0; Row < PadH; Row++) { for (Col = 0; Col < (NewImgW + PadW); Col++) { NewImg[(Row + NewImgH) * TrueImgW + Col] = 0xff; } } } /******************************************************************* * resize_avg * * ========== * * Algorithm to resize image using an averaging algorithm, which * * works by expanding the image and then sampling it: * * 1. Across a given row, interpolate color values for * * pixels. Interpolation is linear. Repeat for rows * * for which pixel values are known. * * 2. Using same interpolation scheme, interpolate values * * across a given column. Repeat for all columns. * * 3. Special case for last pixel in a row/column of the * * original image. Set that last pixel to the last * * pixel in the row/column of the expanded image and * * then interpolate. This will cause some distortion * * since the left and bottom edges of the image will * * be interpolated over more pixels than the rest of * * the expanded image, but hopefully this will not be * * that noticeable to the viewer. * * 4. Call the function sample. * * 5. Notes: * * The upsampling/downsampling process uses * * the closest rational fraction. Some error * * may occur here. * *******************************************************************/ void resize_avg(Img, OrigImgH, OrigImgW, NewImgH, NewImgW, PadH, PadW, NewImg) unsigned char Img[]; unsigned char NewImg[]; int OrigImgW, OrigImgH, NewImgH, NewImgW, PadH, PadW; { int ExpRatioW, ExpRatioH, ExpImgW, ExpImgH; int NumXtraPixelsW, NumXtraPixelsH; float Ratio, ColorIncB, ColorIncT, ColorIncH, ColorT, ColorB; int Row, Col, CountW, CountH; unsigned char TLColor, TRColor; /* Top left, top right colors */ unsigned char BLColor, BRColor; /* Bottom left & right colors */ unsigned char Color; unsigned char *ExpandImg; int i,j; Ratio = ((float) NewImgW)/OrigImgW; ExpRatioW = ceil(Ratio); /* Round ratio up to next greatest integer */ Ratio = ((float) NewImgH)/OrigImgH; ExpRatioH = ceil(Ratio); ExpImgW = ExpRatioW * OrigImgW; ExpImgH = ExpRatioH * OrigImgH; ExpandImg = malloc(sizeof(char) * ExpImgW * ExpImgH); /* Expand image columns and rows */ for(Row=0; Row < (OrigImgH - 1); Row++) { for (Col=0; Col < (OrigImgW - 1); Col++) { /* Get 4 pixel values for colors to interpolate between */ TLColor = Img[Row * OrigImgW + Col]; TRColor = Img[Row * OrigImgW + Col + 1]; BLColor = Img[(Row + 1) * OrigImgW + Col]; BRColor = Img[(Row + 1) * OrigImgW + Col + 1]; /* Calculate the incremental difference to add to each * pixel for the top and bottom. Special case exists * for handling the next-to-last column of the * original image. */ if ((Col == (OrigImgW - 2)) && (ExpRatioW != 1)) { Ratio = (float) 1.5 * ExpRatioW; NumXtraPixelsW = ceil(Ratio); } else { NumXtraPixelsW = ExpRatioW; } ColorIncT = (float) (TRColor - TLColor) / NumXtraPixelsW; ColorIncB = (float) (BRColor - BLColor) / NumXtraPixelsW; for (CountW=0; CountW <= NumXtraPixelsW; CountW++) { /* Interpolate along a column. Special case * for handling the last row. */ if ((Row == (OrigImgH - 2)) && (ExpRatioH != 1)) { Ratio = (float) 1.5 * ExpRatioH; NumXtraPixelsH = ceil(Ratio); } else { NumXtraPixelsH = ExpRatioH; } ColorT = TLColor + CountW * ColorIncT; ColorB = BLColor + CountW * ColorIncB; ColorIncH = (float) (ColorB - ColorT) / NumXtraPixelsH; for (CountH=0; CountH <= NumXtraPixelsH; CountH++) { ExpandImg[(Row * ExpRatioH + CountH) * ExpImgW + (Col * ExpRatioW + CountW)] = (char) (ColorT + CountH * ColorIncH); } } } } /* Call sampling/padding routine */ sample(ExpandImg, ExpImgH, ExpImgW, NewImgH, NewImgW, PadH, PadW, NewImg); /* Free up memory */ free(ExpandImg); } /******************************************************************* * resize_repeat * * ============= * * Algorithm to resize image using "repeat pixel" algorithm, which * * works as follows: * * 1. Since non-integer resizing is allowed, first extract * * out by what amount image needs to be expanded and * * then sampled. * * 2. For expansion: replicate pixel columns by * * ExpRatioW and then replicate rows by ExpRatioH. * * 3. Sampling: Extract out pixels. * * 4. Return the final image as a 1D array * * 5. Notes: * * The upsampling/downsampling process uses * * the closest rational fraction. Some error * * may occur here. * *******************************************************************/ void resize_repeat(Img, OrigImgH, OrigImgW, NewImgH, NewImgW, PadH, PadW, NewImg) unsigned char Img[]; unsigned char NewImg[]; int OrigImgW, OrigImgH, NewImgH, NewImgW, PadH, PadW; { int ExpRatioW, ExpRatioH, ExpImgW, ExpImgH; float Ratio; int Row, Col, RepeatW, RepeatH; unsigned char *ExpandImg; int i,j; Ratio = ((float) NewImgW)/OrigImgW; ExpRatioW = ceil(Ratio); /* Round ratio up to next greatest integer */ Ratio = ((float) NewImgH)/OrigImgH; ExpRatioH = ceil(Ratio); ExpImgW = ExpRatioW * OrigImgW; ExpImgH = ExpRatioH * OrigImgH; ExpandImg = malloc(sizeof(char) * ExpImgW * ExpImgH); /* Expand image columns and rows*/ for(Row=0; Row < OrigImgH; Row++) { for (Col=0; Col < OrigImgW; Col++) { for (RepeatW=0; RepeatW < ExpRatioW; RepeatW++) { for (RepeatH=0; RepeatH < ExpRatioH; RepeatH++) { ExpandImg[(Row * ExpRatioH + RepeatH) * ExpImgW + (Col * ExpRatioW + RepeatW)] = Img[Row * OrigImgW + Col]; } } } } /* Call sampling/padding routine */ sample(ExpandImg, ExpImgH, ExpImgW, NewImgH, NewImgW, PadH, PadW, NewImg); /* Free up memory */ free(ExpandImg); } /******************************************************************* * main * * ==== * * Formats arguments and calls subroutines * *******************************************************************/ main(Argc, Argv) int Argc; char *Argv[]; { int OrigImgH, OrigImgW, NewImgH, NewImgW; int PaddedH, PaddedW, PaddingForH, PaddingForW; char *Printer, *Interp, *Halftone; unsigned char *ImgR, *ImgG, *ImgB; unsigned char *NewImgR, *NewImgG, *NewImgB; unsigned char *NewC, *NewM, *NewY, *NewK; float *Cyan, *Magenta, *Yellow, *Black; float *X, *Y, *Z; int Algorithm, i, j, Index; int GreyDPI[2], ColorDPI[2]; if (Argc != 6) { printf("%d ",Argc); fprintf(stderr, "Wrong number of arguments\n"); exit(1); } /* Assign variables to arguments passed to function */ NewImgW = atoi(Argv[1]); NewImgH = atoi(Argv[2]); Printer = Argv[3]; Halftone = Argv[4]; Interp = Argv[5]; /* Check that arguments for printer, interp are valid. * Are assuming the image sizes are valid */ if ((strcmp(Printer, "ise1600cm") != 0) && (strcmp(Printer, "ise755cm") != 0)) { fprintf(stderr, "Invalid printer name\n"); exit(1); } if (strcmp(Interp,"repeat") == 0) Algorithm = REPEAT; else if (strcmp(Interp, "avg") == 0) Algorithm = AVG; else { fprintf(stderr, "Invalid interpolation algorithm\n"); exit(1); } /* Resized images need to be multiples of 8 for compression/ * halftoning part of process */ PaddingForH = 8 - (NewImgH % 8); PaddingForW = 8 - (NewImgW % 8); if (PaddingForH == 8) PaddingForH = 0; if (PaddingForW == 8) PaddingForW = 0; PaddedH = NewImgH + PaddingForH; PaddedW = NewImgW + PaddingForW; /* Get original image width and height data. This should be the * first 2 integers from the image input file. */ scanf("%d %d %d ", &OrigImgW, &OrigImgH, &i); /* Allocate space for images */ ImgR=malloc(sizeof(char) * OrigImgH * OrigImgW); ImgG=malloc(sizeof(char) * OrigImgH * OrigImgW); ImgB=malloc(sizeof(char) * OrigImgH * OrigImgW); NewImgR=malloc(sizeof(char) * PaddedH * PaddedW); NewImgG=malloc(sizeof(char) * PaddedH * PaddedW); NewImgB=malloc(sizeof(char) * PaddedH * PaddedW); /* Get image data*/ for(i=0; i < OrigImgH; i++) { for(j=0; j < OrigImgW; j++) { getchar(); /* This is the alpha value. Ignore this */ ImgR[i * OrigImgW + j] = getchar(); ImgG[i * OrigImgW + j] = getchar(); ImgB[i * OrigImgW + j] = getchar(); } } /* extract_rgb(Img, OrigImgH, OrigImgW, ImgR, ImgG, ImgB); */ /* Printing for testing purposes only */ /* printf("RGB Image\n"); *for(i=0; i < OrigImgH; i++) * { * for(j=0; j < OrigImgW; j++) *{ * printf("R: %c, G: %c, B: %c\n",ImgR[i * OrigImgW + j], ImgG[i * OrigImgW + j], ImgB[i * OrigImgW + j]); *} *} */ /* Depending on what algorithm is desired, call different * functions for resizing the rgb arrays */ switch(Algorithm) { case 0: { resize_repeat(ImgR, OrigImgH, OrigImgW, NewImgH, NewImgW, PaddingForH, PaddingForW, NewImgR); resize_repeat(ImgG, OrigImgH, OrigImgW, NewImgH, NewImgW, PaddingForH, PaddingForW, NewImgG); resize_repeat(ImgB, OrigImgH, OrigImgW, NewImgH, NewImgW, PaddingForH, PaddingForW, NewImgB); break; } case 1: { resize_avg(ImgR, OrigImgH, OrigImgW, NewImgH, NewImgW, PaddingForH, PaddingForW, NewImgR); resize_avg(ImgG, OrigImgH, OrigImgW, NewImgH, NewImgW, PaddingForH, PaddingForW, NewImgG); resize_avg(ImgB, OrigImgH, OrigImgW, NewImgH, NewImgW, PaddingForH, PaddingForW, NewImgB); break; } } /* Free up memory */ free(ImgR); free(ImgG); free(ImgB); /* Convert RGB values of new image to XYZ values */ X=malloc(sizeof(float) * PaddedH * PaddedW); Y=malloc(sizeof(float) * PaddedH * PaddedW); Z=malloc(sizeof(float) * PaddedH * PaddedW); rgb2xyz(NewImgR, NewImgG, NewImgB, X, Y, Z, PaddedH, PaddedW); free(NewImgR); free(NewImgG); free(NewImgB); /* Convert XYZ values to CMYK for specific printer */ Cyan=malloc(sizeof(float) * PaddedH * PaddedW); Magenta=malloc(sizeof(float) * PaddedH * PaddedW); Yellow=malloc(sizeof(float) * PaddedH * PaddedW); Black=malloc(sizeof(float) * PaddedH * PaddedW); xyz2cmyk(X, Y, Z, Cyan, Magenta, Yellow, Black, PaddedH, PaddedW, Printer, GreyDPI, ColorDPI); free(X); free(Y); free(Z); /* Convert CMYK values to calibrated ones for specific halftone */ NewC=malloc(sizeof(char) * PaddedH * PaddedW); NewM=malloc(sizeof(char) * PaddedH * PaddedW); NewY=malloc(sizeof(char) * PaddedH * PaddedW); NewK=malloc(sizeof(char) * PaddedH * PaddedW); cmyk_calib(Cyan, Magenta, Yellow, Black, NewC, NewM, NewY, NewK, PaddedH, PaddedW, Halftone); free(Cyan); free(Magenta); free(Yellow); free(Black); /* Printing for testing purposes only */ /*Index = 0; *for(i=0; i < PaddedH; i++) * { * for(j=0; j < PaddedW; j++) *{ * Index = i*PaddedW + j; * printf(" %x %x %x %x \n",NewC[Index], NewM[Index], NewY[Index], NewK[Index]); *} * } */ /* Output data to standard output to be used in next part of process */ Index = 0; printf("%d %d\n",PaddedW, PaddedH); for(i=0; i < PaddedH; i++) { for(j=0; j < PaddedW; j++) { Index = i*PaddedW + j; putchar(NewC[Index]); putchar(NewM[Index]); putchar(NewY[Index]); putchar(NewK[Index]); } } /* Free up memory */ free(NewC); free(NewM); free(NewY); free(NewK); }