Автор Тема: Программа сборки PNG из множества нумерованных BMP  (Прочитано 7589 раз)

Оффлайн keremet

  • Global Moderator
  • ROOT
  • *****
  • Сообщений: 463
  • Репутация: +237/-0
    • Просмотр профиля
    • OpenSolaris
/*
Применяется в РИА "Деловая литература" и "ГИС-Киров" для формирования большой картинки карты из множества мелких
 * 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;
}