/*
Применяется в РИА "Деловая литература" и "ГИС-Киров" для формирования большой картинки карты из множества мелких
* pngCombiner is free software; you can redistribute it and/or modify
* it under the terms of version 3 of the GNU General Public License as published by
* the Free Software Foundation
*
* pngCombiner is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
Author: Andrey Sokolov (keremet@solaris.kirov.ru)
Makefile:
all: pngCombiner.c
gcc -std=c99 `pkg-config gtk+-2.0 --cflags` -o pngCombiner pngCombiner.c -lpng `pkg-config gtk+-2.0 --libs`
*/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <gtk/gtk.h>
#define PNG_DEBUG 3
#include <png.h>
void abort_(const char * s, ...)
{
va_list args;
va_start(args, s);
vfprintf(stderr, s, args);
fprintf(stderr, "\n");
va_end(args);
exit(1);
}
void getWidthAndHeight(int *tileWidth, int *tileHeight, int xMin, int yMin){
char buf[100];
sprintf(buf,"%d%d%d%d%d-%d%d%d%d%d.bmp",
xMin/10000, xMin/1000, xMin/100, xMin/10, xMin%10,
yMin/10000, yMin/1000, yMin/100, yMin/10, yMin%10);
GdkPixbuf *pixbuf;
GError *err = NULL;
if(!(pixbuf = gdk_pixbuf_new_from_file(buf, &err)))
abort_("gdk_pixbuf_new error for %s", buf);
*tileWidth = gdk_pixbuf_get_width(pixbuf);
*tileHeight = gdk_pixbuf_get_height(pixbuf);
gdk_pixbuf_unref(pixbuf);
}
void usage(char *progname){
abort_("Usage: %s xMin yMin xMax yMax outfile",progname);
}
int main(int argc, char **argv)
{
if(argc!=1+5)
usage(argv[0]);
int xMin = atoi(argv[1]);
int yMin = atoi(argv[2]);
int xMax = atoi(argv[3]);
int yMax = atoi(argv[4]);
if((xMin<1)||(yMin<1)||(xMax<1)||(yMax<1)||(xMin>xMax)||(yMin>yMax))
usage(argv[0]);
gtk_init(&argc, &argv); //Заменить, так как из-за этого прога требует иксов для запуска. Фунция необходима для начала работы с pixbuf
int tileWidth, tileHeight;
getWidthAndHeight(&tileWidth, &tileHeight, xMin, yMin);
//Открытие выходного файла, поготовка
FILE *fp = fopen(argv[5],"wb");
if(!fp)
abort_("fopen error for %s", argv[5]);
png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png_ptr)
abort_("[write_png_file] png_create_write_struct failed");
png_infop info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr)
abort_("[write_png_file] png_create_info_struct failed");
if (setjmp(png_jmpbuf(png_ptr)))
abort_("[write_png_file] Error during init_io");
png_init_io(png_ptr, fp);
png_set_compression_level(png_ptr,0);//для повышение скорости открытия файла в дальнейшем
// Запись заголовка в файл
if (setjmp(png_jmpbuf(png_ptr)))
abort_("[write_png_file] Error during writing header");
png_set_IHDR(png_ptr, info_ptr, tileWidth*(xMax-xMin+1), tileHeight*(yMax-yMin+1),
8, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
png_write_info(png_ptr, info_ptr);
int imageWidthInTiles = (xMax-xMin+1);
int imageHeightInTiles = (yMax-yMin+1);
float tilesNum =imageWidthInTiles*imageHeightInTiles;
GdkPixbuf* pbout= gdk_pixbuf_new (GDK_COLORSPACE_RGB,
1,
8,
tileWidth*imageWidthInTiles,
tileHeight);
if(!pbout)
abort_("gdk_pixbuf_new error");
for (int j=yMin;j<=yMax;j++){
for (int i=xMin;i<=xMax;i++){
char buf[100];
sprintf(buf,"%d%d%d%d%d-%d%d%d%d%d.bmp",
i/10000, i/1000, i/100, i/10, i%10,
j/10000, j/1000, j/100, j/10, j%10);
printf("%s\t%f\n", buf, (float)( (imageWidthInTiles*(j-yMin)+(i-xMin+1))*100)/tilesNum );
GdkPixbuf *pixbuf;
GError *err = NULL;
if(!(pixbuf = gdk_pixbuf_new_from_file(buf, &err)))
abort_("gdk_pixbuf_new error for %s", buf);
gdk_pixbuf_copy_area(pixbuf,
0, 0,
tileWidth, tileHeight,
pbout,
tileWidth*(i-xMin),
0);
gdk_pixbuf_unref(pixbuf);
}
//Запись строк
if (setjmp(png_jmpbuf(png_ptr)))
abort_("[write_png_file] Error during writing bytes");
int rowstride = gdk_pixbuf_get_rowstride (pbout);
guchar *pixels = gdk_pixbuf_get_pixels (pbout);
for (int y=0;y<tileHeight;y++)
png_write_row(png_ptr, pixels + y * rowstride );
}
gdk_pixbuf_unref(pbout);
//Завершение записи в PNG-файл
if (setjmp(png_jmpbuf(png_ptr)))
abort_("[write_png_file] Error during end of write");
png_write_end(png_ptr, NULL);
fclose(fp);
return 0;
}