-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathresize.c
181 lines (161 loc) · 5.12 KB
/
resize.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
/**
* @file: resize.c
* @author: Billy.Ljm
* @date: 22 June 2015
* @brief: Rescale a 24-bit uncompressed BMP 4.0
*
* >> ./resize 4.0 small.bmp large.bmp
*
* Scales up & down by positive floats.
* No anti-aliasing or interpolation.
* Scales up pixel by pixel & scale down square of pixels by square of pixels.
* As such, actual scaling factor may differ from factor provided.
* Sides of picture may also be deleted when scaling down.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <math.h>
#include "bmp.h"
int main(int argc, char* argv[])
{
float inscale; // scale factor user provided
int scale; // scale factor optimised & stored as integer (for resizing down, actual scale is 1/scale)
bool scaleup; // indicates if image is being resized up or down
char* infile; // in file name
char* outfile; // out file name
FILE* inptr; // in file stream pointer
FILE* outptr; // out file stream pointer
int inpad; // in file padding (includes pixels to ignore)
int outpad; // out file padding
int ignoredpix; // number of pixels ignored when scaling down
BITMAPFILEHEADER inbf; // in file headers
BITMAPINFOHEADER inbi;
BITMAPFILEHEADER outbf; // out file headers
BITMAPINFOHEADER outbi;
RGBTRIPLE inpix; // to read in file RGB pixels
RGBTRIPLE outpix; // to create out file RGB pixels
// ensure proper usage
if (argc != 4){
printf("Usage: ./copy scale_factor infile outfile\n");
return 1;
}
// remember file names
infile = argv[2];
outfile = argv[3];
// optimise scale
inscale = atof(argv[1]);
if(inscale <= 0){
printf("Please provide a non-negative scale factor\n");
return 1;
}
else if(inscale > 1){ // to nearest whole number
scale = (int)round(inscale);
scaleup = true;
}
else{ // to nearest 1/integer
scale = (int)round(1/inscale);
scaleup = false;
}
// open files
inptr = fopen(infile, "r");
if (inptr == NULL){
printf("Could not open %s.\n", infile);
return 2;
}
outptr = fopen(outfile, "w");
if (outptr == NULL){
fclose(inptr);
fprintf(stderr, "Could not create %s.\n", outfile);
return 3;
}
// read infile's headers
fread(&inbf, sizeof(BITMAPFILEHEADER), 1, inptr);
fread(&inbi, sizeof(BITMAPINFOHEADER), 1, inptr);
// ensure infile is (likely) a 24-bit uncompressed BMP 4.0
if (inbf.bfType != 0x4d42 || inbf.bfOffBits != 54 || inbi.biSize != 40 ||
inbi.biBitCount != 24 || inbi.biCompression != 0)
{
fclose(outptr);
fclose(inptr);
fprintf(stderr, "Unsupported file format.\n");
return 4;
}
// write out file's headers
outbf = inbf;
outbi = inbi;
inpad = (4 - (inbi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;
if(scaleup){
outbi.biWidth = inbi.biWidth * scale;
outbi.biHeight = inbi.biHeight * scale;
ignoredpix = 0;
}else{
outbi.biWidth = (int)(inbi.biWidth / scale);
outbi.biHeight = (int)(inbi.biHeight / scale);
ignoredpix = (inbi.biWidth % scale);
}
outpad = (4 - (outbi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;
outbi.biSizeImage = (outbi.biWidth * sizeof(RGBTRIPLE) + outpad) * abs(outbi.biHeight);
outbf.bfSize = inbf.bfSize + outbi.biSizeImage - inbi.biSizeImage;
fwrite(&outbf, sizeof(BITMAPFILEHEADER), 1, outptr);
fwrite(&outbi, sizeof(BITMAPINFOHEADER), 1, outptr);
// scale pixels up
if(scaleup){
for(int i = 0, biHeight = abs(inbi.biHeight); i < biHeight; i++){
for(int j = 0; j < scale; j++){
// scale line laterally
for(int k = 0; k < inbi.biWidth; k++){
fread(&outpix, sizeof(RGBTRIPLE), 1, inptr);
for(int l = 0; l < scale; l++)
fwrite(&outpix, sizeof(RGBTRIPLE), 1, outptr);
}
// insert padding
for(int k = 0; k < outpad; k++)
fputc(0x00, outptr);
// back to start, to scale vertically
if(j < scale - 1)
fseek(inptr, -inbi.biWidth * sizeof(RGBTRIPLE), SEEK_CUR);
}
// move on to in file's next line
fseek(inptr, inpad, SEEK_CUR);
}
}
// scale pixel down
else{
int totred, totgreen, totblue; // total colour values of pixel square
for(int i = 0, biHeight = abs(outbi.biHeight); i < biHeight; i++){
for(int j = 0; j < outbi.biWidth; j++){
// sum color values in pixel square (from top-left to bottom-right)
totred = 0; totgreen = 0; totblue = 0;
for(int k = 0; k < scale; k++){
// sum row in pixel square
for(int l = 0; l < scale; l++){
fread(&inpix, sizeof(RGBTRIPLE), 1, inptr);
totred += inpix.rgbtRed;
totgreen += inpix.rgbtGreen;
totblue += inpix.rgbtBlue;
}
// move to next line in pixel square
if(k != scale - 1)
fseek(inptr, (inbi.biWidth - scale) * sizeof(RGBTRIPLE) + inpad , SEEK_CUR);
}
// write out file pixel
outpix.rgbtRed = totred / (scale * scale);
outpix.rgbtGreen = totgreen / (scale * scale);
outpix.rgbtBlue = totblue / (scale * scale);
fwrite(&outpix, sizeof(RGBTRIPLE), 1, outptr);
// move in file pointer to top-left of next pixel square
if(j != outbi.biWidth - 1)
fseek(inptr, -(scale - 1) * (inbi.biWidth * sizeof(RGBTRIPLE) + inpad), SEEK_CUR);
}
// manage padding
for(int j = 0; j < outpad; j++)
fputc(0x00, outptr);
fseek(inptr, ignoredpix * sizeof(RGBTRIPLE) + inpad, SEEK_CUR);
}
}
// end
fclose(inptr);
fclose(outptr);
return 0;
}