/*******************************************************************
* 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);
}