00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #include <exception>
00034 #include <cstring>
00035 #include <cstdio>
00036
00037
00038 #include "chomp/system/config.h"
00039 #include "chomp/system/textfile.h"
00040 #include "chomp/system/timeused.h"
00041 #include "chomp/system/arg.h"
00042
00043
00044 #include "pngimage.h"
00045
00046
00047
00048
00049
00050
00051
00052
00053 const char *title = "\
00054 PNGSMALL, ver. 0.01, 04/10/08. Copyright (C) 2008 by Pawel Pilarczyk.\n\
00055 This is free software. No warranty. Consult 'license.txt' for details.";
00056
00057
00058
00059
00060 const char *helpinfo = "\
00061 This program reads a given PNG images and writes another PNG image\n\
00062 which is the original one scaled down so that the provided width\n\
00063 and height are not exceeded. The down-scaling factors are limited\n\
00064 to the integer numbers for optimal efficiency. The colors of output\n\
00065 pixels are computed by means of an arithmetic average of the input ones.\n\
00066 Command line arguments:\n\
00067 input.png - the name of the input PNG image file to be down-scaled,\n\
00068 output.png - the name of the output PNG file (rewrites the input if none),\n\
00069 -w width - the maximal allowed width of the output PNG image,\n\
00070 -h height - the maximal allowed height of the output PNG image,\n\
00071 -s scaling - the downscaling factor (overrides max width/height settings),\n\
00072 --quiet - makes the program run quietly, without any output messages,\n\
00073 --help - shows this brief help information on the program's usage.\n\
00074 For more information consult the accompanying documentation (if available)\n\
00075 or ask the program's author at http://www.PawelPilarczyk.com/.";
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088 int pngSmall (const char *inName, const char *outName,
00089 int maxWidth, int maxHeight, int scalingFactor)
00090 {
00091 using chomp::homology::sout;
00092
00093
00094 PngImage inPng (inName);
00095 int inWidth = inPng. width ();
00096 int inHeight = inPng. height ();
00097
00098
00099 if (scalingFactor <= 0)
00100 {
00101 int widthFactor = 0;
00102 if (maxWidth > 0)
00103 {
00104 widthFactor = (inWidth + maxWidth - 1) / maxWidth;
00105 }
00106 int heightFactor = 0;
00107 if (maxHeight > 0)
00108 {
00109 heightFactor = (inHeight + maxHeight - 1) /
00110 maxHeight;
00111 }
00112 scalingFactor = (widthFactor < heightFactor) ?
00113 heightFactor : widthFactor;
00114 if (scalingFactor <= 0)
00115 scalingFactor = 1;
00116 }
00117
00118
00119 if (scalingFactor == 1)
00120 {
00121 using namespace std;
00122 if (!outName || !strcmp (inName, outName))
00123 {
00124 sout << inWidth << " x " << inHeight <<
00125 ": No downscaling necessary. "
00126 "Leaving the file intact.\n";
00127 return 0;
00128 }
00129 sout << inWidth << " x " << inHeight <<
00130 ": No downscaling necessary. "
00131 "Copying the file byte-for-byte.\n";
00132 FILE *inFile = fopen (inName, "rb");
00133 FILE *outFile = fopen (outName, "wb");
00134 int ch = getc (inFile);
00135 while (ch != EOF)
00136 {
00137 putc (ch, outFile);
00138 ch = getc (inFile);
00139 }
00140 fclose (outFile);
00141 fclose (inFile);
00142 return 0;
00143 }
00144
00145
00146 int outWidth = inWidth / scalingFactor;
00147 if (outWidth <= 0)
00148 outWidth = 1;
00149 int outHeight = inHeight / scalingFactor;
00150 if (outHeight <= 0)
00151 outHeight = 1;
00152 PngImage outPng (outWidth, outHeight);
00153
00154
00155 sout << "Downscaling " << inName;
00156 if (outName)
00157 sout << " -> " << outName;
00158 sout << ":\n" << inWidth << " x " << inHeight << " -> " <<
00159 outWidth << " x " << outHeight << " (" << scalingFactor <<
00160 " times smaller).\n";
00161
00162
00163 for (int outX = 0; outX < outWidth; ++ outX)
00164 {
00165 for (int outY = 0; outY < outHeight; ++ outY)
00166 {
00167
00168 int red = 0;
00169 int green = 0;
00170 int blue = 0;
00171
00172
00173 int inX = outX * scalingFactor;
00174 int inY = outY * scalingFactor;
00175 for (int x = 0; x < scalingFactor; ++ x)
00176 {
00177 for (int y = 0; y < scalingFactor; ++ y)
00178 {
00179 int color = inPng. getPixel
00180 (inX + x, inY + y);
00181 red += (color >> 16) & 0xFF;
00182 green += (color >> 8) & 0xFF;
00183 blue += color & 0xFF;
00184 }
00185 }
00186
00187
00188 int n = scalingFactor * scalingFactor;
00189 red = (red + (n >> 1)) / n;
00190 green = (green + (n >> 1)) / n;
00191 blue = (blue + (n >> 1)) / n;
00192
00193
00194 int color = (red << 16) | (green << 8) | blue;
00195 outPng. putPixel (outX, outY, color);
00196 }
00197 }
00198
00199
00200 outPng. save (outName ? outName : inName);
00201 return 0;
00202 }
00203
00204
00205
00206
00207
00208
00209
00210 int main (int argc, char *argv [])
00211 {
00212 using namespace chomp::homology;
00213
00214
00215 char *inName = 0;
00216 char *outName = 0;
00217 int maxWidth = 0;
00218 int maxHeight = 0;
00219 int scalingFactor = 0;
00220
00221
00222 arguments a;
00223 arg (a, 0, inName);
00224 arg (a, 0, outName);
00225 arg (a, "w", maxWidth);
00226 arg (a, "h", maxHeight);
00227 arg (a, "s", scalingFactor);
00228 arghelp (a);
00229
00230 argstreamprepare (a);
00231 int argresult = a. analyze (argc, argv);
00232 argstreamset ();
00233
00234
00235 if (!inName)
00236 argresult = 1;
00237
00238
00239 if (argresult >= 0)
00240 sout << title << '\n';
00241
00242
00243 if (argresult < 0)
00244 {
00245 sout << "Call with '--help' for help.\n";
00246 return 2;
00247 }
00248
00249
00250 if (argresult > 0)
00251 {
00252 sout << helpinfo << '\n';
00253 return 1;
00254 }
00255
00256
00257 try
00258 {
00259
00260 program_time = "Aborted after:";
00261 program_time = 1;
00262
00263
00264 pngSmall (inName, outName, maxWidth, maxHeight,
00265 scalingFactor);
00266
00267
00268 program_time = "Total time used:";
00269
00270
00271 return 0;
00272 }
00273 catch (const char *msg)
00274 {
00275 sout << "ERROR: " << msg << '\n';
00276 return -1;
00277 }
00278 catch (const std::exception &e)
00279 {
00280 sout << "ERROR: " << e. what () << '\n';
00281 return -1;
00282 }
00283 catch (...)
00284 {
00285 sout << "ABORT: An unknown error occurred.\n";
00286 return -1;
00287 }
00288 }
00289