diff -Nru libbsb-0.0.7/AUTHORS libbsb-0.0.8.1/AUTHORS --- libbsb-0.0.7/AUTHORS 2015-01-16 15:25:19.000000000 +0000 +++ libbsb-0.0.8.1/AUTHORS 2016-03-19 21:41:15.000000000 +0000 @@ -5,3 +5,5 @@ Contributers ------------ Stefan Petersen + Michal Krombholz + Tom Gray (geotransform polynomial reengineering) diff -Nru libbsb-0.0.7/bootstrap.sh libbsb-0.0.8.1/bootstrap.sh --- libbsb-0.0.7/bootstrap.sh 1970-01-01 00:00:00.000000000 +0000 +++ libbsb-0.0.8.1/bootstrap.sh 2016-03-19 21:41:15.000000000 +0000 @@ -0,0 +1,13 @@ +#!/bin/sh +# +# $Id: bootstrap.sh,v 1.2 2004/07/07 18:19:20 stuart_hc Exp $ + +# remove generated files (avoids clashes between versions of autotools) +rm -f depcomp missing install-sh mkinstalldirs +rm -f aclocal.m4 configure Makefile.in config.guess ltmain.sh config.sub +rm -rf autom4te.cache + +set -x +aclocal +automake --foreign --copy --add-missing +autoconf diff -Nru libbsb-0.0.7/bsb2png.c libbsb-0.0.8.1/bsb2png.c --- libbsb-0.0.7/bsb2png.c 2015-01-16 15:25:19.000000000 +0000 +++ libbsb-0.0.8.1/bsb2png.c 2016-03-19 21:41:15.000000000 +0000 @@ -19,7 +19,7 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - * $Id: bsb2png.c,v 1.5 2004/11/03 13:29:39 stuart_hc Exp $ + * $Id: bsb2png.c,v 1.7 2007/02/05 17:08:18 mikrom Exp $ * */ diff -Nru libbsb-0.0.7/bsb2ppm.c libbsb-0.0.8.1/bsb2ppm.c --- libbsb-0.0.7/bsb2ppm.c 2015-01-16 15:25:19.000000000 +0000 +++ libbsb-0.0.8.1/bsb2ppm.c 2016-03-19 21:41:15.000000000 +0000 @@ -19,7 +19,7 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - * $Id: bsb2ppm.c,v 1.10 2004/08/13 18:37:46 stuart_hc Exp $ + * $Id: bsb2ppm.c,v 1.11 2007/02/05 17:11:56 mikrom Exp $ * */ @@ -69,8 +69,7 @@ /* Read rows from bsb file and write rows to PPM */ for (y = 0; y < image.height; y++) { - bsb_seek_to_row(&image, y); - bsb_read_row(&image, buf); + bsb_read_row_at(&image, y, buf); /* Each pixel is a triplet of Red,Green,Blue samples */ for (x = 0; x < image.width; x++) diff -Nru libbsb-0.0.7/bsbfix.c libbsb-0.0.8.1/bsbfix.c --- libbsb-0.0.7/bsbfix.c 2015-01-16 15:25:19.000000000 +0000 +++ libbsb-0.0.8.1/bsbfix.c 2016-03-19 21:41:15.000000000 +0000 @@ -18,7 +18,7 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - * $Id: bsbfix.c,v 1.12 2004/11/03 13:29:39 stuart_hc Exp $ + * $Id: bsbfix.c,v 1.13 2007/02/05 17:11:15 mikrom Exp $ * */ @@ -64,8 +64,9 @@ extern int main (int argc, char *argv[]) { BSBImage image; - int i, arg_idx, *index, delete_only = 0; + int32_t i, arg_idx, *index, delete_only = 0; uint8_t *buf; + int height; arg_idx = 1; // points to the first non-option arg if (argc > 1 && (argv[1][0] == '-' && argv[1][1] == 'd')) @@ -83,31 +84,35 @@ } if (! bsb_open_header(argv[arg_idx], &image)) + { + fprintf(stderr, "Failed to open %s\n", argv[arg_idx] ); exit(1); + } buf = (uint8_t *)malloc(image.width); if (! buf) exit(1); - index = (int *)malloc((image.height + 1) * sizeof(int)); - + index = (int32_t *)malloc((image.height + 1) * sizeof(int)); /* Read rows from bsb file */ for (i = 0; i < image.height; i++) { index[i] = ftell(image.pFile); - bsb_read_row(&image, buf); - } free(buf); /* record start-of-index-table file position in the index table */ index[image.height] = ftell(image.pFile); + + /* remember for later as we are closing the BSB file */ + height = image.height; + bsb_close(&image); /* delete index table by truncating file */ - if (truncate(argv[arg_idx], index[image.height]) != 0) + if (truncate(argv[arg_idx], index[height]) != 0) { perror(argv[arg_idx]); exit(1); @@ -127,7 +132,7 @@ exit(1); } - bsb_write_index(image.pFile, image.height, index); + bsb_write_index(image.pFile, height, index); free(index); return 0; diff -Nru libbsb-0.0.7/bsb.h libbsb-0.0.8.1/bsb.h --- libbsb-0.0.7/bsb.h 2015-01-16 15:25:19.000000000 +0000 +++ libbsb-0.0.8.1/bsb.h 2016-03-19 21:41:15.000000000 +0000 @@ -1,3 +1,5 @@ +#ifndef BSB_INCLUDED +#define BSB_INCLUDED /* * bsb.h - libbsb types and functions * @@ -17,12 +19,14 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - * $Id: bsb.h,v 1.12 2004/08/13 18:37:46 stuart_hc Exp $ + * $Id: bsb.h,v 1.14 2007/02/18 06:12:50 mikrom Exp $ * */ +#include + #ifdef HAVE_INTTYPES_H -#include + #include #else // not ISO C99 - use best guess instead typedef unsigned char uint8_t; @@ -30,26 +34,95 @@ typedef unsigned int uint32_t; #endif +#define BSB_MAX_REFS 200 +#define BSB_MAX_PLYS 20 +#define BSB_MAX_AFTS 20 + typedef struct BSBImage { - FILE *pFile; - char depth; - char num_colors; - float version; - int width; - int height; - double xresolution; - double yresolution; - uint8_t red[256]; - uint8_t green[256]; - uint8_t blue[256]; + char name[200]; + char projection[50]; + char datum[50]; + char depth; + float version; + int width; + int height; + double xresolution; + double yresolution; + double scale; + /* usually 'scale given at latitude' with mercator projection */ + double projectionparam; + + uint8_t red[256]; + uint8_t green[256]; + uint8_t blue[256]; + char num_colors; + + /* geo reference points */ + struct REF + { + int id; + int x; + int y; + double lon; + double lat; + } ref[BSB_MAX_REFS]; + int num_refs; + + /* chart border points */ + struct PLY + { + int id; + double lat; + double lon; + } ply[BSB_MAX_PLYS]; + int num_plys; + + /* geotransforms from/to lat/lon & X,Y are polynomials */ + + /* wpx,wpy - world to pixel */ + double wpx[BSB_MAX_AFTS]; + int num_wpxs; + int wpx_level; + double wpy[BSB_MAX_AFTS]; + int num_wpys; + int wpy_level; + /* pwx,pwy - pixel to world */ + double pwx[BSB_MAX_AFTS]; + int num_pwxs; + int pwx_level; + double pwy[BSB_MAX_AFTS]; + int num_pwys; + int pwy_level; + /* phase change for charts crossing 180 longitude */ + double cph; + + /* private: */ + FILE* pFile; + uint32_t* row_index; + unsigned char* rbuf; } BSBImage; +#ifdef __cplusplus +extern "C" { +#endif + /* See comments in bsb_io.c for documentation on these functions */ + extern int bsb_get_header_size(FILE *fp); extern int bsb_open_header(char *filename, BSBImage *p); extern int bsb_seek_to_row(BSBImage *p, int row); extern int bsb_read_row(BSBImage *p, uint8_t *buf); +extern int bsb_read_row_at(BSBImage *p, int row, uint8_t *buf); +extern int bsb_read_row_part(BSBImage *p, int row, uint8_t *buf, int xoffset, int len); +extern int bsb_LLtoXY(BSBImage *p, double lon, double lat, int* x, int* y); +extern int bsb_XYtoLL(BSBImage *p, int x, int y, double* lon, double* lat); extern int bsb_compress_row(BSBImage *p, int row, const uint8_t *pixel, uint8_t *buf); extern int bsb_write_index(FILE *fp, int height, int index[]); extern int bsb_close(BSBImage *p); + +#ifdef __cplusplus +} +#endif + +#endif /* BSB_INCLUDED */ diff -Nru libbsb-0.0.7/bsb_io.c libbsb-0.0.8.1/bsb_io.c --- libbsb-0.0.7/bsb_io.c 2015-01-16 15:25:19.000000000 +0000 +++ libbsb-0.0.8.1/bsb_io.c 2016-03-19 21:41:15.000000000 +0000 @@ -1,25 +1,25 @@ /* - * bsb_io.c - implementation of libbsb reading and writing - * - * Copyright (C) 2000 Stuart Cunningham - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * $Id: bsb_io.c,v 1.20 2004/12/22 13:04:53 stuart_hc Exp $ - * - */ +* bsb_io.c - implementation of libbsb reading and writing +* +* Copyright (C) 2000 Stuart Cunningham +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* This library 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* $Id: bsb_io.c,v 1.22 2007/02/18 06:12:50 mikrom Exp $ +* +*/ #include #include @@ -27,394 +27,821 @@ #include #ifdef _WIN32 -#define DIR_SEPARATOR '\\' + #define DIR_SEPARATOR '\\' #else -#define DIR_SEPARATOR '/' + #define DIR_SEPARATOR '/' #endif /* MSVC doesn't supply a strcasecmp(), so use the MSVC workalike */ #ifdef _MSC_VER -#define strcasecmp(s1, s2) stricmp(s1, s2) + #define strcasecmp(s1, s2) stricmp(s1, s2) #endif -/* bsb_ntohl - portable ntohl */ +/** + * bsb_ntohl - portable ntohl + */ static uint32_t bsb_ntohl(uint32_t netlong) { - static const uint32_t testvalue = 0x12345678; - uint8_t *p = (uint8_t *)&testvalue; + static const uint32_t testvalue = 0x12345678; + uint8_t *p = (uint8_t *)&testvalue; - if (p[0] == 0x12 && p[3] == 0x78) // big endian? - return netlong; + if (p[0] == 0x12 && p[3] == 0x78) /* big endian? */ + return netlong; - // for little endian swap bytes - return ( (netlong & 0xff000000) >> 24 - | (netlong & 0x00ff0000) >> 8 - | (netlong & 0x0000ff00) << 8 - | (netlong & 0x000000ff) << 24 ); -} - -/* Copies the next newline-delimited line from *pp into line as a NUL */ -/* terminated string and increments the pp pointer to point to the start */ -/* of the next line. */ -/* Removes \r characters from the line (if any). */ + /* for little endian swap bytes */ + return( (netlong & 0xff000000) >> 24 + | (netlong & 0x00ff0000) >> 8 + | (netlong & 0x0000ff00) << 8 + | (netlong & 0x000000ff) << 24 ); +} + +/** + * Copies the next newline-delimited line from *pp into line as a NUL + * terminated string and increments the pp pointer to point to the start + * of the next line. + * Removes \r characters from the line (if any). + * + * @param pp pointer to pointer of the the start + * @param len size of line buffer + * @param line the buffer to read the line to + * + * @return 0 is no NL or line did not fit in the buffer; 1 on success + */ static int next_line(char **pp, int len, char *line) { - char *p = *pp; - char *q = line; - - while (*p != '\0') - { - /* Don't overflow destination buffer */ - if (q - line > len) - return 0; /* line didn't fit in buffer */ + char *p = *pp; + char *q = line; - if (*p == '\r') - { - p++; - continue; - } - if (*p == '\n') - { - *q = '\0'; - p++; - *pp = p; - return 1; - } - *q++ = *p++; - } - return 0; /* didn't find \n line terminator */ + while (*p != '\0') + { + /* Don't overflow destination buffer */ + if (q - line > len) + return 0; /* line didn't fit in buffer */ + + if (*p == '\r') + { + p++; + continue; + } + if (*p == '\n') + { + p++; + if ( *p == ' ' ) // line continues so glue it together + { + while ( *p == ' ' ) p++; + if( *(q-1) != ',' ) + *q++ = ','; /* join them with the comma */ + } + else /* it is trully the end */ + { + *q = '\0'; + *pp = p; + return 1; + } + } + *q++ = *p++; + } + return 0; /* didn't find \n line terminator */ } -extern int bsb_get_header_size(FILE *fp) +/** + * reads the string until comma or max chars + * + * @param from source to read from + * @param to destination to put the chars into + * @param max numer of chars (sizeo of to) + */ +static void readStrUntilComma( const char* from, char* to, const unsigned max ) { - int text_size = 0, c; - - /* scan for end-of-text marker and record size of text section */ - while ( (c = fgetc(fp)) != -1 ) - { - if (c == 0x1a) /* Control-Z */ - break; - text_size++; - } - return text_size; + unsigned i = 0; + while ( from[i] && from[i] != ',' && i < max-1 ) + { + to[i]=from[i]; + i++; + } + /* terminate string */ + to[i] = 0; } -/* return 0 on failure */ -extern int bsb_open_header(char *filename, BSBImage *p) +/** + * reads the comma-separated list of numbers from string + * + * @param pc pointer to first character on list + * @param list[] array of double values to read into + * @param count number of parameters to read (length of list[] + * + * @return count of read numbers + */ +static +int readNumberList( char* pc, double list[], int count ) { - int text_size = 0, c, depth; - char *p_ext, *pt, *text_buf, line[1024]; - - p->pFile = NULL; - - /* Look for an extension (if any) to test for '.NO1' files */ - /* which must be treated specially since they are obfuscated */ - if ( (p_ext = strrchr(filename, '.')) != NULL && - (p_ext > strrchr(filename, DIR_SEPARATOR)) && - (strcasecmp(p_ext, ".NO1") == 0) ) - { - FILE *inputFile; - - if (! (inputFile = fopen(filename, "rb"))) - { - perror(filename); - return 0; - } - - /* Open temporary file to store unobfuscated file */ - if (! (p->pFile = tmpfile())) - { - perror("tmpfile()"); - return 0; - } - - /* .NO1 files are obfuscated using ROT-9 */ - while ((c = fgetc(inputFile)) != EOF) - { - int r = (c - 9) & 0xFF; - fputc(r, p->pFile); - } - fflush(p->pFile); - fseek(p->pFile, 0, SEEK_SET); - } - else - { - /* Normal unobfuscated BSB/NOS files can be opened straight away */ - if (! (p->pFile = fopen(filename, "rb"))) - { - perror(filename); - return 0; - } - } + int i = 0; + while ( *pc && i < count ) + { + while ( *pc && *pc != ',' ) pc++; + if ( *pc ) + { + pc++; + if ( *pc ) sscanf( pc, "%lf", &list[i++] ); + } + } + return i; +} - if ((text_size = bsb_get_header_size(p->pFile)) == 0) - return 0; +/** + * internal function - reads the raster row index + * + * @param p pointer to BSBImage to update + */ +static +int bsb_read_row_index( BSBImage* p ) +{ + /* Read start-of-index offset */ + if (fseek(p->pFile, -4, SEEK_END) == -1) + return 0; + uint32_t st; + if (fread(&st, 4, 1, p->pFile) != 1) + return 0; + uint32_t start_of_index = bsb_ntohl(st); + /* Read start-of-rows offset */ + if (fseek(p->pFile, start_of_index, SEEK_SET) == -1) + return 0; + /* allocate one more for last row ending */ + p->row_index = (uint32_t*)malloc( (p->height+1)*4 ); + if ( !p->row_index ) + return 0; + if (fread(p->row_index, p->height*4, 1, p->pFile) != 1) + return 0; + /* remember end of last row, which is start of the index */ + p->row_index[p->height] = start_of_index; + /* convert endiannes */ + int i; + for ( i = 0; i < p->height; i++ ) + p->row_index[i] = bsb_ntohl(p->row_index[i]); + /* convert endiannes */ + int max_row_size = 0; + for ( i = 0; i < p->height; i++ ) + { + int row_size = p->row_index[i+1]-p->row_index[i]; + max_row_size = max_row_size < row_size ? row_size : max_row_size; + } + p->rbuf = (unsigned char*)malloc( max_row_size ); + return p->rbuf != 0; +} - /* allocate space & read in the entire text header */ - text_buf = (char *)malloc(text_size + 1); - if (text_buf == NULL) - { - fprintf(stderr, - "malloc(%d) failed for text header - BSB file possibly corrupt", - text_size + 1); - return 0; - } +/** + * computes the BSB header size of the BSB (KAP) file (text part preceding the image) + * + * @return the size of the BSB header + * + */ +extern int bsb_get_header_size(FILE *fp) +{ + int text_size = 0, c; - fseek(p->pFile, 0, SEEK_SET); - if (fread(text_buf, text_size, 1, p->pFile) != 1) - return 0; - text_buf[text_size] = '\0'; + /* scan for end-of-text marker and record size of text section */ + while ( (c = fgetc(fp)) != -1 ) + { + if (c == 0x1a) /* Control-Z */ + break; + text_size++; + } + return text_size; +} - pt = text_buf; - p->num_colors = 0; - p->version = -1.0; - p->width = -1; - p->height = -1; - while ( next_line(&pt, sizeof(line), line) ) - { - char *s; - int index, r, g, b, ifm_depth; - float ver; +/** + * opens the BSB (KAP or NO1) file and and populated the BSBImage structure + * also reads the row index + * + * @param filename full path to the file to open + * @param p pointer to the BSBImage structure + * + * @return 0 on failure + */ +extern int bsb_open_header(char *filename, BSBImage *p) +{ + int text_size = 0, c, depth; + char *p_ext, *pt, *text_buf, line[1024]; - if (sscanf(line, "RGB/%d,%d,%d,%d", &index, &r, &g, &b) == 4) - { - if ((unsigned)index < sizeof(p->red)) - { - if (index > 0) - { - p->red[index-1] = r; - p->green[index-1] = g; - p->blue[index-1] = b; - p->num_colors++; - } - } - } - if ( (s = strstr(line, "RA=")) ) - { - int x0, y0; + /* zerofill entire BSB structure - not very strict + as we would want some 0.0l and 0.0f but this works just the same */ + memset( p, 0, sizeof(*p) ); + + /* Look for an extension (if any) to test for '.NO1' files + which must be treated specially since they are obfuscated */ + if ( (p_ext = strrchr(filename, '.')) != NULL && + (p_ext > strrchr(filename, DIR_SEPARATOR)) && + (strcasecmp(p_ext, ".NO1") == 0) ) + { + FILE *inputFile; + + if (! (inputFile = fopen(filename, "rb"))) + { + perror(filename); + return 0; + } + + /* Open temporary file to store unobfuscated file */ + if (! (p->pFile = tmpfile())) + { + perror("tmpfile()"); + return 0; + } + + /* .NO1 files are obfuscated using ROT-9 */ + while ((c = fgetc(inputFile)) != EOF) + { + int r = (c - 9) & 0xFF; + fputc(r, p->pFile); + } + fflush(p->pFile); + fseek(p->pFile, 0, SEEK_SET); + } + else + { + /* Normal unobfuscated BSB/NOS files can be opened straight away */ + if (! (p->pFile = fopen(filename, "rb"))) + { + perror(filename); + return 0; + } + } + + if ((text_size = bsb_get_header_size(p->pFile)) == 0) + return 0; + + /* allocate space & read in the entire text header */ + text_buf = (char *)malloc(text_size + 1); + if (text_buf == NULL) + { + fprintf(stderr, + "malloc(%d) failed for text header - BSB file possibly corrupt", + text_size + 1); + return 0; + } + + fseek(p->pFile, 0, SEEK_SET); + if (fread(text_buf, text_size, 1, p->pFile) != 1) + return 0; + text_buf[text_size] = '\0'; + + pt = text_buf; + p->num_colors = 0; + p->num_refs = 0; + p->num_plys = 0; + p->num_wpxs = 0; + p->num_wpys = 0; + p->num_pwxs = 0; + p->num_pwys = 0; + p->version = -1.0; + p->width = -1; + p->height = -1; + while ( next_line(&pt, sizeof(line), line) ) + { + char *s; + int idx, r, g, b, ifm_depth; + + if (sscanf(line, "RGB/%d,%d,%d,%d", &idx, &r, &g, &b) == 4) + { + if ((unsigned)idx < sizeof(p->red)/sizeof(p->red[0])) + { + if (idx > 0) + { + p->red[idx-1] = r; + p->green[idx-1] = g; + p->blue[idx-1] = b; + p->num_colors++; + } + } + } + if (sscanf(line, "REF/%d,%d,%d,%lf,%lf", + &p->ref[p->num_refs].id, + &p->ref[p->num_refs].x, + &p->ref[p->num_refs].y, + &p->ref[p->num_refs].lat, + &p->ref[p->num_refs].lon) == 5) + { + if ( p->num_refs < BSB_MAX_REFS -1 ) + { + p->num_refs++; + } + else + { + printf("too many reference points (REF)\n"); + } + } + if (sscanf(line, "PLY/%d,%lf,%lf", + &p->ply[p->num_plys].id, + &p->ply[p->num_plys].lat, + &p->ply[p->num_plys].lon) == 3) + { + if ( p->num_plys < BSB_MAX_PLYS -1 ) + { + p->num_plys++; + } + else + { + printf("too many border points (PLY)\n"); + } + + } + if (sscanf(line, "WPX/%d,", &p->wpx_level )==1) + { + p->num_wpxs = readNumberList( line, p->wpx, sizeof(p->wpx)/sizeof(p->wpx[0]) ); + } + if (sscanf(line, "WPY/%d,", &p->wpy_level )==1) + { + p->num_wpys = readNumberList( line, p->wpy, sizeof(p->wpy)/sizeof(p->wpy[0]) ); + } + if (sscanf(line, "PWX/%d,", &p->pwx_level )==1) + { + p->num_pwxs = readNumberList( line, p->pwx, sizeof(p->pwx)/sizeof(p->pwx[0]) ); + } + if (sscanf(line, "PWY/%d,", &p->pwy_level )==1) + { + p->num_pwys = readNumberList( line, p->pwy, sizeof(p->pwy)/sizeof(p->pwy[0]) ); + } + if ( (s = strstr(line, "NA=")) ) + { + readStrUntilComma( s+3, p->name, sizeof(p->name) ); + } + if ( strstr(line,"KNP/") == line ) + { + if ( (s = strstr(line, "PR=")) ) + { + readStrUntilComma( s+3, p->projection, sizeof(p->projection) ); + } + if ( (s = strstr(line, "GD=")) ) + { + readStrUntilComma( s+3, p->datum, sizeof(p->datum) ); + } + if ( (s = strstr(line, "SC=")) ) + { + sscanf( s+3, "%lf", &p->scale ); + } + if ( (s = strstr(line, "PP=")) ) + { + sscanf( s+3, "%lf", &p->projectionparam ); + } + + } + if ( (s = strstr(line, "RA=")) ) + { + int x0, y0; + /* Attempt to read old-style NOS (4 parameter) version of RA= */ + /* then fall back to newer 2-argument version */ + if ((sscanf(s,"RA=%d,%d,%d,%d",&x0,&y0,&p->width,&p->height)!=4) && + (sscanf(s,"RA=%d,%d", &p->width, &p->height) != 2)) + { + fprintf(stderr, "failed to read width,height from RA=\n"); + return 0; + } + } + if ( (s = strstr(line, "DX=")) ) + { + if ( sscanf(s, "DX=%lf", &p->xresolution) != 1 ) + { + fprintf(stderr, "failed to read xresolution\n"); + return 0; + } + } + if ( (s = strstr(line, "DY=")) ) + { + if ( sscanf(s, "DY=%lf", &p->yresolution) != 1 ) + { + fprintf(stderr, "failed to read xresolution\n"); + return 0; + } + } + if (sscanf(line, "IFM/%d", &ifm_depth) == 1) + { + p->depth = ifm_depth; + } + if (sscanf(line, "VER/%f", &p->version) == 1) + { + } + if (sscanf(line, "CPH/%lf", &p->cph) == 1) + { + } + + } + if (p->width == -1 || p->height == -1) + { + fprintf(stderr, "Error: Could not read RA=,\n"); + return 0; + } + /* done with the header */ + free(text_buf); + + /* Attempt to read depth from binary section, but first skip until NULL */ + while( fgetc(p->pFile) > 0 ); + + /* Test depth from bitstream */ + depth = fgetc(p->pFile); + if (depth != p->depth) + { + fprintf(stderr, + "Warning: depth from IFM tag (%d) != depth from bitstream (%d)\n", + p->depth, depth); + } + long pos = ftell(p->pFile); + if ( !bsb_read_row_index(p) ) + { + /* printf("Could not read row index\n"); */ + /* restore file position so it starts at the first row again */ + /* TODO: provide a function to recreate the index */ + fseek(p->pFile, pos, SEEK_SET); + } + else + { + /* position at the first row - it is safer to use index if exists */ + bsb_seek_to_row(p, 0); + } + return 1; +} - /* Attempt to read old-style NOS (4 parameter) version of RA= */ - /* then fall back to newer 2-argument version */ - if ((sscanf(s,"RA=%d,%d,%d,%d",&x0,&y0,&p->width,&p->height)!=4) && - (sscanf(s,"RA=%d,%d", &p->width, &p->height) != 2)) - { - fprintf(stderr, "failed to read width,height from RA=\n"); - return 0; - } - } - if ( (s = strstr(line, "DX=")) ) - { - if ( sscanf(s, "DX=%lf", &p->xresolution) != 1 ) - { - fprintf(stderr, "failed to read xresolution\n"); - return 0; - } - } - if ( (s = strstr(line, "DY=")) ) - { - if ( sscanf(s, "DY=%lf", &p->yresolution) != 1 ) - { - fprintf(stderr, "failed to read xresolution\n"); - return 0; - } - } - if (sscanf(line, "IFM/%d", &ifm_depth) == 1) - { - p->depth = ifm_depth; - } - if (sscanf(line, "VER/%f", &ver) == 1) - { - p->version = ver; - } - } - if (p->width == -1 || p->height == -1) - { - fprintf(stderr, "Error: Could not read RA=,\n"); - return 0; - } - /* Attempt to read depth from binary section */ - c = fgetc(p->pFile); /* discard */ - c = fgetc(p->pFile); /* discard NUL */ +/** + * generic polynomial to convert georeferenced lat/lon to char's x/y + * + * @param coeff list of polynomial coefficients + * @param lon longitute or x + * @param lat latitude or y + * + * @return coordinate corresponding to the coeff list + */ +static double polytrans( double* coeff, double lon, double lat ) +{ + double ret = coeff[0] + coeff[1]*lon + coeff[2]*lat; + ret += coeff[3]*lon*lon; + ret += coeff[4]*lon*lat; + ret += coeff[5]*lat*lat; + ret += coeff[6]*lon*lon*lon; + ret += coeff[7]*lon*lon*lat; + ret += coeff[8]*lon*lat*lat; + ret += coeff[9]*lat*lat*lat; + ret += coeff[10]*lat*lat*lat*lat; + ret += coeff[11]*lat*lat*lat*lat*lat; + return ret; +} - /* Test depth from bitstream */ - depth = fgetc(p->pFile); - if (depth != p->depth) - fprintf(stderr, "Warning: depth from IFM tag (%d) != depth from bitstream (%d)\n", p->depth, depth); +/** + * converts Lon/Lat to chart's X/Y + * + * @param p pointer to a BSBImage structure + * @param lon longitude (-180.0 to 180.0) + * @param lat latitude (-180.0 to 180.0) + * @param x output chart X coordinate + * @param y output chart Y coordinate + * + * @return 1 on success and 0 on error + */ +extern int bsb_LLtoXY(BSBImage *p, double lon, double lat, int* x, int* y) +{ + /* change longitude phase (CPH) */ + lon = (lon < 0) ? lon + p->cph : lon - p->cph; + double xd = polytrans( p->wpx, lon, lat ); + double yd = polytrans( p->wpy, lon, lat ); + *x = (int)(xd + 0.5); + *y = (int)(yd + 0.5); + return 1; +} - free(text_buf); - return 1; +/** + * converts chart's X/Y to Lon/Lat + * + * @param p pointer to a BSBImage structure + * @param x chart X coordinate + * @param y chart Y coordinate + * @param lon output longitude (-180.0 to 180.0) + * @param lat output latitude (-180.0 to 180.0) + * + * @return 1 on success and 0 on error + */ +extern int bsb_XYtoLL(BSBImage *p, int x, int y, double* lonout, double* latout) +{ + double lon = polytrans( p->pwx, x, y ); + lon = (lon < 0) ? lon + p->cph : lon - p->cph; + *lonout = lon; + *latout = polytrans( p->pwy, x, y ); + return 1; } -/* bsb_seek_to_row(BSBImage *p, int row) + +/** + * Seeks the file to the given row so read_row can start reading. + * Uses the index table at the end of the BSB file to quickly jump to a row. * - * p - pointer to a BSBImage - * row - row to seek to starting from row 0 (BSB row 1) + * @param p pointer to a BSBImage + * @param row row to seek to starting from row 0 (BSB row 1) * - * Returns 1 on success and 0 on error + * @returns 1 on success and 0 on error * - * Uses the index table at the end of the BSB file to quickly jump to a row. */ extern int bsb_seek_to_row(BSBImage *p, int row) { - int st, start_of_index, start_of_rows; - - /* Read start-of-index offset */ - if (fseek(p->pFile, -4, SEEK_END) == -1) - return 0; - if (fread(&st, 4, 1, p->pFile) != 1) - return 0; - start_of_index = bsb_ntohl(st); - - /* Read start-of-rows offset */ - if (fseek(p->pFile, row*4 + start_of_index, SEEK_SET) == -1) - return 0; - if (fread(&st, 4, 1, p->pFile) != 1) - return 0; - start_of_rows = bsb_ntohl(st); + int st, start_of_index, start_of_rows; - /* seek to row offset */ - if (fseek(p->pFile, start_of_rows, SEEK_SET) == -1) - return 0; - return 1; + /* in case we did not cahced the index, read it here */ + if ( !p->row_index ) + { + /* Read start-of-index offset */ + if (fseek(p->pFile, -4, SEEK_END) == -1) + return 0; + if (fread(&st, 4, 1, p->pFile) != 1) + return 0; + start_of_index = bsb_ntohl(st); + /* Read start-of-rows offset */ + if (fseek(p->pFile, row*4 + start_of_index, SEEK_SET) == -1) + return 0; + if (fread(&st, 4, 1, p->pFile) != 1) + return 0; + start_of_rows = bsb_ntohl(st); + } + else + { + start_of_rows = p->row_index[row]; + } + + /* seek to row offset */ + if (fseek(p->pFile, start_of_rows, SEEK_SET) == -1) + return 0; + else + return 1; } /* Table used for computing multiplier in bsb_read_row() */ -static char mul_mask[8] = { 0, 63, 31, 15, 7, 3, 1, 0 }; +static char mul_mask[8] = { 0, 63, 31, 15, 7, 3, 1, 0}; -/* bsb_read_row(BSBImage *p, int row, uint8_t *buf) +/** + * Read currently seek-to row. Can continue to read more rows. * - * p - pointer to a BSBImage containing file pointer at the start of a row + * @param p pointer to a BSBImage containing file pointer at the start of a row * this occurs after bsb_open_header() or bsb_seek_to_row() - * buf - output buffer for uncompressed pixel data + * @oaram buf output buffer for uncompressed pixel data * - * Returns 1 on success and 0 on error + * @returns 1 on success and 0 on error */ extern int bsb_read_row(BSBImage *p, uint8_t *buf) { - int c, i, multiplier, row_num = 0; - int pixel = 1, written = 0; - - /* The row number is stored in the low 7 bits of each byte. */ - /* The 8th bit indicates if row number is continued in the next byte. */ - do { - c = fgetc(p->pFile); - row_num = ((row_num & 0x7f) << 7) + c; - } while (c >= 0x80); - - /* Rows are terminated by '\0'. Note that rows can contain a '\0' */ - /* as part of the run-length data, so '\0' does not delimit rows. */ - /* (This occurs when multiplier is a multiple of 128 - 1) */ - while ((c = fgetc(p->pFile)) != '\0') - { - if (c == EOF) - { - fprintf(stderr, "Warning: EOF reading row %d\n", row_num); - return 0; - } - - pixel = (c & 0x7f) >> (7 - p->depth); - multiplier = c & mul_mask[(int)p->depth]; + int c, multiplier, row_num = 0; + int pixel = 1, written = 0; - while (c >= 0x80) - { - c = fgetc(p->pFile); - multiplier = (multiplier << 7) + (c & 0x7f); - } - multiplier++; - - if (multiplier > p->width) /* limit impact of corrupt BSB data */ - multiplier = p->width; + /* The row number is stored in the low 7 bits of each byte. */ + /* The 8th bit indicates if row number is continued in the next byte. */ + do + { + c = fgetc(p->pFile); + row_num = ((row_num & 0x7f) << 7) + c; + } while (c >= 0x80); + + /* Rows are terminated by '\0'. Note that rows can contain a '\0' */ + /* as part of the run-length data, so '\0' does not delimit rows. */ + /* (This occurs when multiplier is a multiple of 128 - 1) */ + while ((c = fgetc(p->pFile)) != '\0') + { + if (c == EOF) + { + fprintf(stderr, "Warning: EOF reading row %d\n", row_num); + return 0; + } + + pixel = (c & 0x7f) >> (7 - p->depth); + multiplier = c & mul_mask[(int)p->depth]; + + while (c >= 0x80) + { + c = fgetc(p->pFile); + multiplier = (multiplier << 7) + (c & 0x7f); + } + multiplier++; + /* limit impact of corrupt BSB data */ + /* For the lower depths, the "grain" of the multiplyer is */ + /* course, so don't write past the width of the buffer. */ + if ( written + multiplier > p->width ) + { + multiplier = p->width - written; + } + memset( buf+written, pixel-1, multiplier ); + written += multiplier; + } + + if (written < p->width) + { + int short_fall = p->width - written; + + /* It seems valid BSB rows sometimes don't include pixel data for */ + /* the very last pixel or two. Perhaps the decoder is supposed */ + /* to merely repeat the last pixel until the width is reached. */ + /* A value of 8 was chosen as a guess since the intended behaviour */ + /* of a BSB reader in this situation is not known. */ + if (short_fall < 8) + { + /* Repeat the last pixel value for small short falls */ + while (written < p->width) + buf[written++] = pixel - 1; + } + else + { + fprintf(stderr, "Warning: Short row for row %d written=%d width=%d\n", row_num, written, p->width); + return 0; + } + } + return 1; +} - for (i = 0; i < multiplier; i++) - { - /* For the lower depths, the "grain" of the multiplyer is */ - /* course, so don't write past the width of the buffer. */ - if (written < p->width) - buf[written++] = pixel - 1; /* BSB color idx starts at 1 */ - } - } +/** + * Seeks-to and reads given row. + * This is performance improved version but it requires that row index is present. + * + * @param p pointer to a BSBImage containing file pointer at the start of a row + * this occurs after bsb_open_header() or bsb_seek_to_row() + * @param buf output buffer for uncompressed pixel data + * + * @returns 1 on success and 0 on error + */ +extern int bsb_read_row_at(BSBImage *p, int row, uint8_t *buf) +{ + return bsb_read_row_part(p, row, buf, 0, p->width); +} - if (written < p->width) +/** + * Seeks-to and reads part of a row. + * This is performance improved version but it requires that row index is present. + * + * @param p pointer to a BSBImage containing file pointer at the start of a row + * this occurs after bsb_open_header() or bsb_seek_to_row() + * @param buf output buffer for uncompressed pixel data + * + * @param xoffset X offset in a row to start reading from + * @param len number of points to read (length of buf) + * + * @returns 1 on success and 0 on error + */ +extern int bsb_read_row_part(BSBImage *p, int row, uint8_t *buf, int xoffset, int buflen) +{ + /* trying to read outside of image? */ + if( row >= p->height ) + return 0; + if( xoffset >= p->width ) + return 0; + int len = buflen; + if( xoffset+len > p->width ) { - int short_fall = p->width - written; - - /* It seems valid BSB rows sometimes don't include pixel data for */ - /* the very last pixel or two. Perhaps the decoder is supposed */ - /* to merely repeat the last pixel until the width is reached. */ - /* A value of 8 was chosen as a guess since the intended behaviour */ - /* of a BSB reader in this situation is not known. */ - if (short_fall < 8) - { - /* Repeat the last pixel value for small short falls */ - while (written < p->width) - buf[written++] = pixel - 1; - } - else - { - fprintf(stderr, "Warning: Short row for row %d written=%d width=%d\n", row_num, written, p->width); - return 0; - } + len = p->width-xoffset; } - return 1; + + /* if we failed to read row index use old routine */ + if ( !p->rbuf || !p->row_index || !p->row_index[row] ) + { + bsb_seek_to_row( p, row ); + return bsb_read_row( p, buf ); + } + + if ( fseek( p->pFile, p->row_index[row], SEEK_SET ) == -1 ) + return 0; + + int size = p->row_index[row+1]-p->row_index[row]; + unsigned char* rbuf = p->rbuf; + /* read compressed row in one step */ + if ( fread( rbuf, size, 1, p->pFile ) != 1 ) + { + return 0; + } + + /* uncompress the row */ + + /* The row number is stored in the low 7 bits of each byte. */ + /* The 8th bit indicates if row number is continued in the next byte. */ + + int cidx = 0; + int c, row_num = 0; + do + { + c = rbuf[cidx++]; + row_num = ((row_num & 0x7f) << 7) + c; + } while (c >= 0x80); + + int multiplier, pixel = 1, rowx = 0, bufidx = 0; + int maxWidth = xoffset + len; + + /* Rows are terminated by '\0'. Note that rows can contain a '\0' */ + /* as part of the run-length data, so '\0' does not delimit rows. */ + /* (This occurs when multiplier is a multiple of 128 - 1) */ + while ((c = rbuf[cidx++]) != '\0' && bufidx < len) + { + pixel = (c & 0x7f) >> (7 - p->depth); + multiplier = c & mul_mask[(int)p->depth]; + + while (c >= 0x80) + { + c = rbuf[cidx++]; + multiplier = (multiplier << 7) + (c & 0x7f); + } + multiplier++; + + /* limit impact of corrupt BSB data */ + if (multiplier > maxWidth) + multiplier = maxWidth-rowx; + + /* For the lower depths, the "grain" of the multiplyer is */ + /* course, so don't write past the width of the buffer. */ + if (rowx + multiplier > maxWidth) + { + multiplier = maxWidth-rowx; + } + if( rowx+multiplier > xoffset ) + { + int step = rowx >= xoffset ? multiplier : multiplier-(xoffset-rowx); + if( bufidx+step > len ) step = len-bufidx; + memset(buf+bufidx, pixel-1, step); + bufidx += step; + } + rowx += multiplier; + } + + /* It seems valid BSB rows sometimes don't include pixel data for */ + /* the very last pixel or two. Perhaps the decoder is supposed */ + /* to merely repeat the last pixel until the width is reached. */ + /* A value of 8 was chosen as a guess since the intended behaviour */ + /* of a BSB reader in this situation is not known. */ + /* Repeat the last pixel value for small short falls */ + if(bufidx < buflen) + memset(buf+bufidx, pixel - 1, buflen-bufidx); + return 1; } -extern int bsb_write_index(FILE *fp, int height, int index[]) +/** + * Writes the row index to BSB file + * + * @param fp pointer to opened file to write the index to + * @param height number of rows (the height of the raster/length of index[]) + * @param idx row index table to write + * + * @returns 1 on success and 0 on error + */ +extern int bsb_write_index(FILE *fp, int height, int idx[]) { - int j; + int j; - /* Write index table */ - for (j = 0; j < height + 1; j++) - { - /* Indices must be written as big-endian */ - if ((fputc(index[j] >> 24, fp)) == EOF) return 0; - if ((fputc((index[j] & 0x00ff0000) >> 16, fp)) == EOF) return 0; - if ((fputc((index[j] & 0x0000ff00) >> 8, fp)) == EOF) return 0; - if ((fputc(index[j] & 0x000000ff, fp)) == EOF) return 0; - } - return 1; + /* Write index table */ + for (j = 0; j < height + 1; j++) + { + /* Indices must be written as big-endian */ + if ((fputc(idx[j] >> 24, fp)) == EOF) return 0; + if ((fputc((idx[j] & 0x00ff0000) >> 16, fp)) == EOF) return 0; + if ((fputc((idx[j] & 0x0000ff00) >> 8, fp)) == EOF) return 0; + if ((fputc(idx[j] & 0x000000ff, fp)) == EOF) return 0; + } + return 1; } -/* Convert an integer into the variable length encoded form used for row +/** + * Convert an integer into the variable length encoded form used for row * numbers in the BSB bitstream. + * @param row row number to store + * @param p pointer to the place to store it + * + * @return number of bytes used to store it */ static int bsb_store_integer(int row, uint8_t *p) { - int req_bytes, i, c; + int req_bytes, i, c; - /* Using 32 bit integers, row numbers are stored in one to four bytes. */ - /* This limits row numbers to 2^28 - 1 (= 268,435,455). */ - /* Calculate required bytes to store integer using a table instead of */ - /* expensive calls to get log base 2. */ - - req_bytes = 1; - if (row > 2097151) /* 2^(7*3) - 1 */ - req_bytes = 4; - else if (row > 16383) /* 2^(7*2) - 1 */ - req_bytes = 3; - else if (row > 127) /* 2^(7*1) - 1 */ - req_bytes = 2; - - for (i = req_bytes - 1; i >= 0; i--) - { - c = (row >> i * 7) & 0x7f; - - if (i > 0) - c |= 0x80; /* set sentinel high bit */ - - *p++ = c; - } - return req_bytes; + /* Using 32 bit integers, row numbers are stored in one to four bytes. */ + /* This limits row numbers to 2^28 - 1 (= 268,435,455). */ + /* Calculate required bytes to store integer using a table instead of */ + /* expensive calls to get log base 2. */ + + req_bytes = 1; + if (row > 2097151) /* 2^(7*3) - 1 */ + req_bytes = 4; + else if (row > 16383) /* 2^(7*2) - 1 */ + req_bytes = 3; + else if (row > 127) /* 2^(7*1) - 1 */ + req_bytes = 2; + + for (i = req_bytes - 1; i >= 0; i--) + { + c = (row >> i * 7) & 0x7f; + + if (i > 0) + c |= 0x80; /* set sentinel high bit */ + + *p++ = c; + } + return req_bytes; } -/* bsb_compress_row(BSBImage *p, int row, uint8_t *aPixel, uint8_t *buf) +/** + * Compress one row of image and store it * - * p - pointer to a BSBImage for the width & depth values - * row - row number stating at 0 (row 0 will be stored as BSB row 1) - * aPixel - array of uncompressed pixels - * buf - output buffer for compressed bitstream + * @param p - pointer to a BSBImage for the width & depth values + * @param row - row number stating at 0 (row 0 will be stored as BSB row 1) + * @param aPixel - array of uncompressed pixels + * @param buf - output buffer for compressed bitstream * - * Returns length of encoded bitstream + * @returns length of encoded bitstream * * Use a simple run length encoding, storing the run length in the * sentinel bits where possible. Lower depth images have more room @@ -422,87 +849,107 @@ */ extern int bsb_compress_row(BSBImage *p, int row, const uint8_t *aPixel, uint8_t *buf) { - int width = p->width, depth = p->depth; - int run_length, sentinel_bits, max_sentinel_rep, sentinel_mask; - int ibuf, ipixel; - uint8_t last_pix, shifted_pix; - - /* Write the row number (add 1 since BSB rows number from 1 not 0) */ - ibuf = 0; - ibuf = bsb_store_integer(row+1, buf); - - - sentinel_bits = 7 - depth; /* number of sentinel bits available */ - sentinel_mask = ((1 << depth) - 1) << (7 - depth); - max_sentinel_rep = 1 << sentinel_bits; /* max run length that fits */ - /* in sentinel bits */ - - ipixel = 0; - while ( ipixel < width ) - { - last_pix = aPixel[ipixel]; - ipixel++; - - /* Count length of pixel 'run' - run length cannot be greater than width */ - run_length = 0; - while ( (ipixel < width) && (aPixel[ipixel] == last_pix) ) - { - ipixel++; - run_length++; - } - ipixel--; - - /* BSB colormap never uses index 0, so add 1 to pixel index before use */ - shifted_pix = (last_pix + 1) << sentinel_bits; - - if ( run_length < max_sentinel_rep ) - { - if ( run_length == 0 ) - { - if ( (shifted_pix & 0xff) == 0 ) - shifted_pix = sentinel_mask; - } - buf[ibuf++] = shifted_pix | run_length; - } - else - { - int i, rc_bytes, rc_bits; - int rc = run_length / 2; - - rc_bits = 1; - while (rc > 0) - { - rc = rc / 2; - rc_bits++; - } - - rc_bytes = (int)(rc_bits / 7); - if ( rc_bits - rc_bytes * 7 > sentinel_bits ) - rc_bytes++; - - for ( i = rc_bytes; i > 0; i-- ) - { - buf[ibuf + i] = run_length & 0x7f; - run_length = run_length >> 7; - } - - buf[ibuf] = shifted_pix | run_length; - - for ( i = 0; i < rc_bytes; i++ ) - buf[ibuf + i] |= 0x80; - - ibuf++; - ibuf = ibuf + rc_bytes; - } - ipixel++; - } - buf[ibuf] = 0; /* terminate row with zero */ - return ibuf + 1; + int width = p->width, depth = p->depth; + int run_length, sentinel_bits, max_sentinel_rep, sentinel_mask; + int ibuf, ipixel; + uint8_t last_pix, shifted_pix; + + /* Write the row number (add 1 since BSB rows number from 1 not 0) */ + ibuf = 0; + ibuf = bsb_store_integer(row+1, buf); + + + sentinel_bits = 7 - depth; /* number of sentinel bits available */ + sentinel_mask = ((1 << depth) - 1) << (7 - depth); + max_sentinel_rep = 1 << sentinel_bits; /* max run length that fits */ + /* in sentinel bits */ + + ipixel = 0; + while ( ipixel < width ) + { + last_pix = aPixel[ipixel]; + ipixel++; + + /* Count length of pixel 'run' - run length cannot be greater than width */ + run_length = 0; + while ( (ipixel < width) && (aPixel[ipixel] == last_pix) ) + { + ipixel++; + run_length++; + } + ipixel--; + + /* BSB colormap never uses index 0, so add 1 to pixel index before use */ + shifted_pix = (last_pix + 1) << sentinel_bits; + + if ( run_length < max_sentinel_rep ) + { + if ( run_length == 0 ) + { + if ( (shifted_pix & 0xff) == 0 ) + shifted_pix = sentinel_mask; + } + buf[ibuf++] = shifted_pix | run_length; + } + else + { + int i, rc_bytes, rc_bits; + int rc = run_length / 2; + + rc_bits = 1; + while (rc > 0) + { + rc = rc / 2; + rc_bits++; + } + + rc_bytes = (int)(rc_bits / 7); + if ( rc_bits - rc_bytes * 7 > sentinel_bits ) + rc_bytes++; + + for ( i = rc_bytes; i > 0; i-- ) + { + buf[ibuf + i] = run_length & 0x7f; + run_length = run_length >> 7; + } + + buf[ibuf] = shifted_pix | run_length; + + for ( i = 0; i < rc_bytes; i++ ) + buf[ibuf + i] |= 0x80; + + ibuf++; + ibuf = ibuf + rc_bytes; + } + ipixel++; + } + buf[ibuf] = 0; /* terminate row with zero */ + return ibuf + 1; } +/** + * Close the BSB file and release all the memory. + * Zeros all the files of the structure. + * + * @param p pointer to BSBImage structure to close + * + * @retrun 1 on success; 0 on failure (the structure was not opened) + */ extern int bsb_close(BSBImage *p) { - fclose(p->pFile); - - return 1; + if (p->pFile) + { + fclose(p->pFile); + free(p->row_index); + free(p->rbuf); + p->pFile = 0; + p->row_index = 0; + p->rbuf = 0; + return 1; + } + else + { + return 0; + } } + diff -Nru libbsb-0.0.7/bsbview.cpp libbsb-0.0.8.1/bsbview.cpp --- libbsb-0.0.7/bsbview.cpp 1970-01-01 00:00:00.000000000 +0000 +++ libbsb-0.0.8.1/bsbview.cpp 2016-03-19 21:41:15.000000000 +0000 @@ -0,0 +1,76 @@ +/* +* bsbview.cpp - implementation of BSB marine chart viewer +* +* Copyright (C) 2006 Michal Krombholz +* +* This software is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* This software 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* $Id: bsbview.cpp,v 1.1 2007/02/06 16:05:25 mikrom Exp $ +* +*/ + +#include +#include + +#include + +// +// Create and display a BSBWidget. +// +int main( int argc, char **argv ) +{ + QApplication a( argc, argv ); + BSBWidget bsbw(0,"BSBView"); + a.setMainWidget( &bsbw ); + bsbw.setCaption("QCharts Viewer"); + char *startchart = 0; + // startchar = (char*)"australia4c.kap"; + + //extern char *optarg; + extern int optind, optopt; + bool test = false; + bool verbose = false; + bool quit = false; + int c; + while ((c = getopt(argc, argv, ":tvq")) != -1) { + switch (c) { + case 't': test = true; break; + case 'v': verbose = true; break; + case 'q': quit = true; break; + default : printf("ignoring option %c\n", optopt); break; + } + } + // see if there is any file name + for ( ; optind < argc; optind++) { + startchart = argv[optind]; + } + if( startchart ) + { + bsbw.setChartFile(startchart); + if(test) + { + bsbw.testGeoTransform(verbose); + } + } + else + { + bsbw.selectChartFile(); + } + if( !quit ) + { + bsbw.show(); + a.exec(); + } +} diff -Nru libbsb-0.0.7/bsbview_src/BSBMainWindow.cpp libbsb-0.0.8.1/bsbview_src/BSBMainWindow.cpp --- libbsb-0.0.7/bsbview_src/BSBMainWindow.cpp 1970-01-01 00:00:00.000000000 +0000 +++ libbsb-0.0.8.1/bsbview_src/BSBMainWindow.cpp 2016-03-19 21:41:15.000000000 +0000 @@ -0,0 +1,51 @@ +/* +* BSBMainWindow.cpp - implementation of BSBView for qchart - a marine BSB chart viewer +* +* Copyright (C) 2006-2007 Michal Krombholz +* +* This software is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* This software 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* $Id: BSBMainWindow.cpp,v 1.1 2007/02/18 07:50:31 mikrom Exp $ + * +*/ + +#include +#include +#include +#include +#include +#include + +#include "BSBScrollArea.h" +#include "BSBMainWindow.h" + +BSBMainWindow::BSBMainWindow(QWidget* parent) + : QMainWindow(parent), bsbsa(0) +{ + bsbsa = new BSBScrollArea(this); + setCentralWidget(bsbsa); + connect( bsbsa, SIGNAL(chartChanged()), this, SLOT(chartChanged()) ); +} + +void BSBMainWindow::setChartFile(const char* filename) +{ + if( bsbsa ) + bsbsa->setChartFile(filename); +} + +void BSBMainWindow::chartChanged() +{ + setWindowTitle( bsbsa->chartName() ); +} diff -Nru libbsb-0.0.7/bsbview_src/BSBMainWindow.h libbsb-0.0.8.1/bsbview_src/BSBMainWindow.h --- libbsb-0.0.7/bsbview_src/BSBMainWindow.h 1970-01-01 00:00:00.000000000 +0000 +++ libbsb-0.0.8.1/bsbview_src/BSBMainWindow.h 2016-03-19 21:41:15.000000000 +0000 @@ -0,0 +1,41 @@ +#ifndef BSBMainWindow_INCLUDED +#define BSBMainWindow_INCLUDED +/* +* BSBMainWindow.cpp - implementation of BSBView for qchart - a marine BSB chart viewer +* +* Copyright (C) 2006-2007 Michal Krombholz +* +* This software is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* This software 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* $Id: BSBMainWindow.h,v 1.1 2007/02/18 07:50:31 mikrom Exp $ + * +*/ + +#include + +#include "BSBScrollArea.h" + +class BSBMainWindow : public QMainWindow { + Q_OBJECT +public: + BSBMainWindow(QWidget* parent = 0); + void setChartFile(const char* filename); +private slots: + void chartChanged(); +private: + BSBScrollArea* bsbsa; +}; + +#endif // BSBMainWindow_INCLUDED diff -Nru libbsb-0.0.7/bsbview_src/BSBScrollArea.cpp libbsb-0.0.8.1/bsbview_src/BSBScrollArea.cpp --- libbsb-0.0.7/bsbview_src/BSBScrollArea.cpp 1970-01-01 00:00:00.000000000 +0000 +++ libbsb-0.0.8.1/bsbview_src/BSBScrollArea.cpp 2016-03-19 21:41:15.000000000 +0000 @@ -0,0 +1,451 @@ +/* +* BSBScrollArea.cpp - implementation of BSBView for qchart - a marine BSB chart viewer +* +* Copyright (C) 2006-2007 Michal Krombholz +* +* This software is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* This software 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* $Id: BSBScrollArea.cpp,v 1.1 2007/02/18 07:50:31 mikrom Exp $ + * +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include "BSBWidget.h" +#include "BSBScrollArea.h" + +BSBScrollArea::BSBScrollArea(QWidget* parent) + : QScrollArea(parent), + bsbw(0), bsb(0), bsbFileName(0), + mseDown(false), + lastOpenDir(QDir::homePath()+"/BSB_ROOT") +{ +// horizontalScrollBar()->setSingleStep(1); +// verticalScrollBar()->setSingleStep(1); +} + +/** + * Scrolls the chart relative to current position (by dx/dy offset) + * @param dx + * @param dy + */ +void BSBScrollArea::scrollBy(int dx, int dy) +{ + verticalScrollBar()->setValue(verticalScrollBar()->value() + dy); + horizontalScrollBar()->setValue(horizontalScrollBar()->value() + dx); +} + +/** + * Scrolls the chart to the absolute x/y position + * @param x + * @param y + */ +void BSBScrollArea::scrollTo(int x, int y) +{ + verticalScrollBar()->setValue(y); + horizontalScrollBar()->setValue(x); +} + +/** + * Returns current content offset + * @return QPoint with content offset + */ +QPoint BSBScrollArea::viewportOffset() +{ + return QPoint( horizontalScrollBar()->value(), verticalScrollBar()->value() ); +} + +/** + * Sets the chart + * @param filename full path to the char KAP file + * @return true if successfull + */ +bool BSBScrollArea::setChartFile(const char* filename) +{ + bool success = true; + BSBImage* b = new BSBImage(); + if ( bsb_open_header((char*)filename, b) ) + { + delete bsb; + bsb = b; + printf("Opened: %s\n",filename); + bsbw = new BSBWidget(this); + bsbw->setChart(bsb); + bsbw->setZoom(-2); + setWidget(bsbw); + setWidgetResizable( true ); + centerChart(); + free(bsbFileName); + bsbFileName = strdup(filename); + emit chartChanged(); + + } + else + { + delete b; + printf("Failed to open %s\n",filename); + success = false; + } + return success; +} + +/** + * Sets zoom for the view + * if xcenter/ycenter are specified, they become center of the chart otherwise the center is maintained + */ +void BSBScrollArea::setZoomAutoScroll(int zoom, int xcenter, int ycenter) +{ + int xc,yc; + if( xcenter < 0 ) + { + xcenter = viewport()->width()/2; + } + if( ycenter < 0 ) + { + ycenter = viewport()->height()/2; + } + bsbw->screenToChart(xcenter+horizontalScrollBar()->value(), + ycenter+verticalScrollBar()->value(), + &xc, &yc); + bsbw->setZoom( zoom ); + int xs,ys; + bsbw->chartToScreen(xc,yc,&xs,&ys); + scrollTo(xs-viewport()->width()/2,ys-viewport()->height()/2); +} + +/** + * Handles key events for the widget. + */ +void BSBScrollArea::keyPressEvent( QKeyEvent *e ) +{ + int dx = 0; + int dy = 0; + switch ( e->key() ) + { + case Qt::Key_Up: dy = -1; break; + case Qt::Key_Down: dy = 1; break; + case Qt::Key_Left: dx = -1; break; + case Qt::Key_Right: dx = 1; break; + } + if( dx || dy ) + { + int shift = (e->modifiers() & Qt::ControlModifier) ? 3 : 1; + scrollBy( dx*viewport()->height()*shift/4, dy+viewport()->width()*shift/4 ); + return; + } + switch ( e->key() ) + { + case Qt::Key_Plus: + case Qt::Key_Z: + zoomIn(); + break; + case Qt::Key_Minus: + case Qt::Key_X: + zoomOut(); + break; + case Qt::Key_C: + centerChart(); + break; + case Qt::Key_N: + zoomNorm(); + break; + case Qt::Key_R: + toggleDisplayRefs(); + break; + case Qt::Key_B: + toggleDisplayBorder(); + break; + case Qt::Key_I: + chartInfo(); + break; + case Qt::Key_O: + openChart(); + break; + case Qt::Key_F: + /*todo full screen*/; break; + default: return; + } +} + + +/** + * Creats context popup menu + */ +QMenu* BSBScrollArea::createPopupMenu () +{ + QMenu* pm = new QMenu(this); + pm->addAction(tr("Zoom In"),this,SLOT(zoomIn()),tr("Z")); + pm->addAction(tr("Zoom Out"),this,SLOT(zoomOut()),tr("X")); + pm->addAction(tr("Zoom Normal (1:1)"),this,SLOT(zoomNorm()),tr("N")); + pm->addAction(tr("Center"),this,SLOT(centerChart()),tr("C")); + pm->addSeparator(); + pm->addAction(tr("Display Chart Refs"),this,SLOT(toggleDisplayRefs()),tr("R")); + pm->addAction(tr("Display Chart Border"),this,SLOT(toggleDisplayBorder()),tr("B")); + pm->addSeparator(); + pm->addAction(tr("Open chart"),this,SLOT(openChart()),tr("O")); + pm->addAction(tr("Chart Info"),this,SLOT(chartInfo()),tr("I")); + return pm; +} + +/** + * Handles context menu event + */ +void BSBScrollArea::contextMenuEvent ( QContextMenuEvent * e ) +{ +// just do nothing so default contex menu handling is supressed +} + +/** + * Handles mouse press events for the widget. + */ +void BSBScrollArea::mousePressEvent( QMouseEvent *e ) +{ + msedwntme.start(); + msedwnpos = e->pos(); + switch ( e->button() ) + { + case Qt::LeftButton : { + //cursor.setShape( Qt::SizeAllCursor ); + //setCursor( cursor ); + mseDown = true; + break; + } + case Qt::RightButton : { + break; + } + default: + break; + } +} + + +/** + * Handles mouse release events for the connect widget. + * The code is smart on right click: + * - if it was a short click and mouse did not move much then it's a popup menu + * - if the time was longer and mouse move then it is a gesture + */ +void BSBScrollArea::mouseReleaseEvent( QMouseEvent *e ) +{ + //cursor.setShape( Qt::CrossCursor ); + //setCursor( cursor ); + QPoint mseuppos = e->pos(); + switch ( e->button() ) + { + case Qt::LeftButton : + if ( mseDown ) + { + mseDown = false; + int dx = - (mseuppos.x()-msedwnpos.x()); + int dy = - (mseuppos.y()-msedwnpos.y()); + scrollBy( dx, dy ); + } + break; + case Qt::RightButton : { + QPoint d = msedwnpos - mseuppos; + int adx = d.x() > 0 ? d.x() : -d.x(); + int ady = d.y() > 0 ? d.y() : -d.y(); + if ( msedwntme.elapsed() < 300 /* ms */ && adx < 10 && ady < 10 ) + { + contextMenu( QPoint(e->x(),e->y()) ); + } + else /* its a gesture - up (zoom in) or down (zoom out) */ + { + QPoint p = msedwnpos/*+QPoint(d.x()/2, d.y()/2)*/+viewportOffset(); + int xc,yc; + bsbw->screenToChart(p.x(), p.y(), &xc, &yc); + int newzoom = bsbw->getZoom(); + newzoom = (d.y()>0) ? newzoom+1 : newzoom-1; + bsbw->setZoom( newzoom ); + int x,y; + bsbw->chartToScreen(xc, yc, &x, &y); + scrollTo(QPoint(x, y)-centerViewportOffset()); + } + break; + } + default: + break; + } +} + +/** + * Handles mouse move events for the widget. + */ +void BSBScrollArea::mouseMoveEvent( QMouseEvent *e ) +{ + if ( mseDown ) + { + QPoint d = msedwnpos-e->pos(); + scrollBy(d.x(), d.y()); + msedwnpos = e->pos(); + } +} + +/** + * Handles mouse double click press events for the connect widget. + * Here execute ZOOM IN action at the click point. + */ +void BSBScrollArea::mouseDoubleClickEvent ( QMouseEvent * e ) +{ + // compute new chart coord in e->xy + QPoint ofs = viewportOffset() + e->pos(); + int xc, yc; + bsbw->screenToChart( ofs.x(), ofs.y(), &xc, &yc ); + bsbw->setZoom( bsbw->getZoom()+1 ); + // compute back and scroll to new pos + int x,y; + bsbw->chartToScreen( xc, yc, &x, &y ); + x -= e->x(); + y -= e->y(); + scrollTo(x, y); +} + + +/** + * Handles mouse double click press events for the connect widget. + * Here execute ZOOM IN action at the click point. + */ +void BSBScrollArea::wheelEvent( QWheelEvent * e ) +{ + // compute new chart coord in e->xy + QPoint ofs = viewportOffset() + e->pos(); + int xc, yc; + bsbw->screenToChart( ofs.x(), ofs.y(), &xc, &yc ); + bsbw->setZoom( bsbw->getZoom() + (e->delta() > 0 ? 1 : -1) ); + // compute back and scroll to new pos + int x,y; + bsbw->chartToScreen( xc, yc, &x, &y ); + x -= e->x(); + y -= e->y(); + scrollTo(x, y); +} + +/** + * Open dialog and let the user select the chart file + */ +void BSBScrollArea::openChart() +{ + QFileDialog fd(this,"Open BSB(KAP) chart file",lastOpenDir,"BSB Charts (*.KAP)"); + if( fd.exec() == QDialog::Accepted ) + { + QStringList qfn = fd.selectedFiles(); + setChartFile( qfn.first().toAscii( ) ); + lastOpenDir=fd.directory().absolutePath(); + } +} + +/** + * Slot to zoom in + */ +void BSBScrollArea::zoomIn() +{ + setZoomAutoScroll( bsbw->getZoom()+1 ); +} + +/** + * Slot to zoom out + */ +void BSBScrollArea::zoomOut() +{ + setZoomAutoScroll( bsbw->getZoom()-1 ); +} + +/** + * Slot to set normal zoom + */ +void BSBScrollArea::zoomNorm() +{ + setZoomAutoScroll( 0 ); +} + +/** + * Slot to set normal zoom + */ +void BSBScrollArea::toggleDisplayRefs() +{ + bsbw->setDisplayRefs( !bsbw->getDisplayRefs() ); +} + +/** + * Slot to center the chart + */ +void BSBScrollArea::toggleDisplayBorder() +{ + bsbw->setDisplayBorder( !bsbw->getDisplayBorder() ); +} + +/** + * Slot to center the chart + */ +void BSBScrollArea::centerChart() +{ + QSize zs = bsbw->getZoomedSize(); + int vx = viewport()->width()/2; + int vy = viewport()->height()/2; + scrollTo(zs.width()/2-vx,zs.height()/2-vy); +} + +/** + * Slot to show chart infor + */ +void BSBScrollArea::chartInfo() +{ + char txt[1000]; + sprintf(txt, + "%s
" + "%s
" + "version : %f
" + "%s/%s
" + "scale : %.0f at %.3f lat
" + "res x/y : %.3f/%.3f
" + "# refs : %d
" + "# borders : %d
" + "# geocoef : %d/%d/%d/%d %d/%d/%d/%d
" + "cph : %f
" + , + bsbFileName, + bsb->name, bsb->version, + bsb->projection, bsb->datum, + bsb->scale, bsb->projectionparam, + bsb->xresolution, bsb->yresolution, + bsb->num_refs, bsb->num_plys, + bsb->num_wpxs, bsb->num_wpys, bsb->num_pwxs, bsb->num_pwys, + bsb->wpx_level, bsb->wpy_level, bsb->pwx_level, bsb->pwy_level, bsb->cph ); + QMessageBox::information(this, "About This Chart", txt, QMessageBox::Ok); +} + + +/** + * Slot to popup contex menu + */ +void BSBScrollArea::contextMenu(QPoint pos) +{ + char s[100]; + QPoint pv = pos + viewportOffset(); + bsbw->screenToLLStr( pv.x(), pv.y(), s ); + QMenu* pm = createPopupMenu(); + pm->addSeparator(); + pm->addAction(s); + if( pm ) + { + pm->exec(mapToGlobal(pos)); + } +} diff -Nru libbsb-0.0.7/bsbview_src/BSBScrollArea.h libbsb-0.0.8.1/bsbview_src/BSBScrollArea.h --- libbsb-0.0.7/bsbview_src/BSBScrollArea.h 1970-01-01 00:00:00.000000000 +0000 +++ libbsb-0.0.8.1/bsbview_src/BSBScrollArea.h 2016-03-19 21:41:15.000000000 +0000 @@ -0,0 +1,82 @@ +#ifndef BSBScrollArea_INCLUDED +#define BSBScrollArea_INCLUDED +/* +* BSBMainWindow.cpp - implementation of BSBView for qchart - a marine BSB chart viewer +* +* Copyright (C) 2006-2007 Michal Krombholz +* +* This software is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* This software 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* $Id: BSBScrollArea.h,v 1.1 2007/02/18 07:56:56 mikrom Exp $ + * +*/ + +#include +#include +#include +#include "BSBWidget.h" +#include "bsb.h" + +class BSBScrollArea : public QScrollArea { + Q_OBJECT +public: + BSBScrollArea(QWidget* parent = 0); + + bool setChartFile(const char* filename); + const char* chartName() const { return bsb ? bsb->name : ""; } + + void setZoomAutoScroll(int zoom, int xcenter = -1, int ycenter = -1 ); + void scrollBy( int dx, int dy ); + void scrollTo( int x, int y ); + void scrollTo( QPoint p ) { scrollTo( p.x(), p.y() ); } + void scrollCenterTo( int x, int y ) { scrollTo( QPoint(x,y)+centerViewportOffset() ); } + QPoint centerViewportOffset() { return QPoint( viewport()->width()/2, viewport()->height()/2 ); } + QPoint viewportOffset(); +signals: + void chartChanged(); +protected: + virtual void keyPressEvent( QKeyEvent * ); + virtual void mousePressEvent( QMouseEvent * ); + virtual void mouseReleaseEvent( QMouseEvent * ); + virtual void mouseDoubleClickEvent( QMouseEvent * ); + virtual void mouseMoveEvent( QMouseEvent * ); + virtual void contextMenuEvent( QContextMenuEvent * ); + virtual void wheelEvent( QWheelEvent * ); + virtual QMenu* createPopupMenu(); + +private slots: + void openChart(); + void zoomIn(); + void zoomOut(); + void zoomNorm(); + void toggleDisplayRefs(); + void toggleDisplayBorder(); + void centerChart(); + void chartInfo(); + void contextMenu(QPoint pos); + +private: + BSBWidget* bsbw; + BSBImage* bsb; + char* bsbFileName; + + bool mseDown; // TRUE if mouse button down + QPoint msedwnpos; + QTime msedwntme; + + QString lastOpenDir; +}; + +#endif // BSBScrollArea_INCLUDED diff -Nru libbsb-0.0.7/bsbview_src/bsbview.pro libbsb-0.0.8.1/bsbview_src/bsbview.pro --- libbsb-0.0.7/bsbview_src/bsbview.pro 1970-01-01 00:00:00.000000000 +0000 +++ libbsb-0.0.8.1/bsbview_src/bsbview.pro 2016-03-19 21:41:15.000000000 +0000 @@ -0,0 +1,12 @@ +###################################################################### +# Automatically generated by qmake (1.07a) Sat Nov 18 10:14:15 2006 +###################################################################### + +TEMPLATE = app +INCLUDEPATH += . .. +INCLUDEPATH += c:/msys/1.0/local/include + +# Input +HEADERS += BSBWidget.h BSBMainWindow.h BSBScrollArea.h +SOURCES += BSBWidget.cpp BSBMainWindow.cpp BSBScrollArea.cpp main.cpp +LIBS += -lbsb -L.. -L/local/lib diff -Nru libbsb-0.0.7/bsbview_src/BSBWidget.cpp libbsb-0.0.8.1/bsbview_src/BSBWidget.cpp --- libbsb-0.0.7/bsbview_src/BSBWidget.cpp 1970-01-01 00:00:00.000000000 +0000 +++ libbsb-0.0.8.1/bsbview_src/BSBWidget.cpp 2016-03-19 21:41:15.000000000 +0000 @@ -0,0 +1,396 @@ +/* +* BSBWidget.cpp - implementation of BSBWidget for qchart - a marine BSB chart viewer +* +* Copyright (C) 2006 Michal Krombholz +* +* This software is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* This software 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* $Id: BSBWidget.cpp,v 1.1 2007/02/18 07:50:31 mikrom Exp $ +* +*/ + +#include +#include +#include + +#include +#include +#include + +#include "BSBWidget.h" + +/** + * Constructs a BSBWidget. + */ +BSBWidget::BSBWidget( QWidget *parent ) + : QWidget( parent ), + m_bsb(0), m_zoom(0), + display_border(false), + display_refs(false) +{ +} + +/** + * Destructs a BSBWidget. + */ +BSBWidget::~BSBWidget() +{ +} + +/** + * Sets current raster chart to view + * + * @param filename full path to the BSB file name to open + */ +void +BSBWidget::setChart(BSBImage* bsb) +{ + m_bsb = bsb; + setZoom(2); +} + +/** + * Given current zoom level return image size + */ +QSize BSBWidget::getZoomedSize() +{ + if( m_bsb ) + { + if( m_zoom >= 0 ) + return QSize( m_bsb->width*(m_zoom+1), m_bsb->height*(m_zoom+1) ); + else // if( m_zoom < 0 ) + return QSize( -m_bsb->width/(m_zoom-1), -m_bsb->height/(m_zoom-1) ); + } + else + return QSize(640,400); +} + +/** + * Sets zoom level + * + * @param zoom level of zoom + */ +void BSBWidget::setZoom(int zoom) +{ + if ( zoom > MAXZOOM ) zoom = MAXZOOM; + if ( zoom < MINZOOM ) zoom = MINZOOM; + if( m_zoom != zoom ) + { + m_zoom = zoom; + setMinimumSize(getZoomedSize()); + } +} + +/** + * Converts screen x,y to chart xc,yc + * + * @param xs screen (viewport) X coordinate + * @param ys screen (viewport) Y coordinate + * @param xc output chart X coordinate + * @param yc output chart Y coordinate + */ +void BSBWidget::screenToChart(int xs, int ys, int* xc, int* yc) +{ + int zoom = getZoom(); + if( zoom < 0 ) + { + zoom --; + zoom = -zoom; + *xc=xs*zoom; + *yc=ys*zoom; + } + else + { + zoom ++; + *xc=xs/zoom; + *yc=ys/zoom; + } + //printf("s2c %d %d %d %d\n", xs, ys, *xc, *yc ); +} + + +/** + * Converts chart xc, yc to screen x,y + * + * @param xc chart X coordinate + * @param yc chart Y coordinate + * @param xs output screen (viewport) X coordinate + * @param ys output screen (viewport) Y coordinate + */ +void BSBWidget::chartToScreen(int xc, int yc, int* xs, int* ys) +{ + int zoom = getZoom(); + if( zoom < 0 ) + { + zoom --; + zoom = -zoom; + *xs=xc/zoom; + *ys=yc/zoom; + } + else + { + zoom ++; + *xs=xc*zoom; + *ys=yc*zoom; + } + //printf("c2s %d %d %d %d\n" , xc, yc, *xs, *ys ); +} + +/** + * Converts screen x,y to chart Lat/Lon and formats for output + * + * @param x screen (viewport) X coordinate + * @param y screen (viewport) Y coordinate + * @param s output text buffer + */ +void BSBWidget::screenToLLStr(int x, int y, char* s) +{ + double lat,lon; + int xc,yc; + screenToChart(x, y, &xc, &yc); + if( bsb_XYtoLL( m_bsb, xc, yc, &lon, &lat) ) + { + char sn = 'N'; + if( lat < 0 ) + { + sn = 'S'; + lat = -lat; + } + char ew = 'E'; + if( lon < 0 ) + { + ew = 'W'; + lon = -lon; + + } + sprintf(s, "Lat %7.3f%c Lon %7.3f%c", lat,sn,lon,ew); + } + else + { + strcpy(s, "Lat ? Lon ?"); + } +} + +/** + * Creates a single tile (part of image) of given coordinates and zoom. + * Uses smooth (and slow) algorithm for scaling. + * + * @param xc chart offset that tile should include + * @param yc chart offset that tile should include + * @param zoom level of zoom of tile + * @return pointer to QImage of tile + */ + QImage* BSBWidget::makeTileSmooth(int xc, int yc, int zoom, const int TILESIZEX, const int TILESIZEY) +{ + //printf("mts %d %d %d %08x\n", xc, yc, zoom, tileID(xc,yc,zoom) ); + QImage img( TILESIZEX*zoom, TILESIZEY*zoom, QImage::Format_Indexed8 ); + if( img.isNull() ) + { + printf("QImage isNull: (x,y,w,h,z)=%d,%d,%d,%d,%d\n", xc, yc, TILESIZEX, TILESIZEY, zoom); + return 0; + } + img.setNumColors( m_bsb->num_colors ); + for ( int col = 0; col < m_bsb->num_colors; col++ ) + { + img.setColor( col, qRgb( m_bsb->red[col], m_bsb->green[col], m_bsb->blue[col] ) ); + } + //img.fill(0); + int xo = xc/*(xc/TILESIZEX)*TILESIZEY*/; + int yo = yc/*(yc/TILESIZEY)*TILESIZEY*/; + if( xo >= m_bsb->width ) printf("xo=%d width=%d\n", xo, m_bsb->width ); + for ( int y = 0; y < img.height(); y++ ) + { + uchar* ppix = img.scanLine(y); + if( yo+y < m_bsb->height ) + { + // tile goes over the chart on the right + bsb_read_row_part( m_bsb, yo+y, ppix, xo, TILESIZEX*zoom ); + } + else // tile goes over the chart on the bottom + memcpy(ppix, img.scanLine(y-1), img.width()); + //memset( ppix, 0, img.width() ); + } + return new QImage(img.scaled(TILESIZEX,TILESIZEY, + Qt::IgnoreAspectRatio, + Qt::SmoothTransformation)); +} + + +/** + * Creates a single tile (part of image) of given coordinates and zoom. + * Uses quick (subsample) algorithm for scaling. + * + * @param xo widget offset that tile should include + * @param yo widget offset that tile should include + * @param zoom level of zoom of tile + * @param TILESIZEX x size of tile + * @param TILESIZEY y size of tile + * @return pointer to QImage of tile + */ +QImage* BSBWidget::makeTileQuick(int xo, int yo, int zoom, const int TILESIZEX, const int TILESIZEY) +{ + //printf("mt %d %d %d\n", xc, yc, zoom ); + if( zoom < 0 ) + { + // zoom of 0 means 1:1 + // negative zoom --> shrink it by subsampling + zoom--; + zoom = -zoom; + int xc = xo*zoom; + int yc = yo*zoom; + QImage img( TILESIZEX, TILESIZEY, QImage::Format_Indexed8 ); + if( img.isNull() ) + { + printf("QImage isNull: (x,y,w,h,z)=%d,%d,%d,%d,%d\n", xc, yc, TILESIZEX, TILESIZEY, zoom); + return 0; + } + img.fill(0); + img.setNumColors( m_bsb->num_colors ); + for ( int col = 0; col < m_bsb->num_colors; col++ ) + { + img.setColor( col, qRgb( m_bsb->red[col], m_bsb->green[col], m_bsb->blue[col] ) ); + } + int xs = TILESIZEX*zoom; + uint8_t* row = new uint8_t[xs]; + memset( row, 0, xs ); + for ( int y = 0; y < TILESIZEY; y++ ) + { + int yy = yc+y*zoom; + if( yy < m_bsb->height ) + bsb_read_row_part( m_bsb, yy, row, xc, xs ); + else + memset( row, 0, xs ); + uchar* ppix = img.scanLine(y); + for ( int x = 0; x < TILESIZEX; x++ ) + { + int xx = x*zoom; + int col = row && xx >=0 && xx < m_bsb->width ? row[xx] : 0; + *ppix++ = col; + } + } + delete[] row; + return new QImage(img); + } + else // enlarge + { + // zoom of 0 means 1:1 + zoom ++; + int xc = xo/zoom; + int yc = yo/zoom; + int tw = TILESIZEX/zoom; + tw = tw < 1 ? 1 : tw; + int th = TILESIZEY/zoom; + th = th < 1 ? 1 : th; + QImage img( tw, th, QImage::Format_Indexed8 ); + if( img.isNull() ) + { + printf("QImage isNull: (x,y,w,h,z)=%d,%d,%d,%d,%d\n", xc, yc, TILESIZEX, TILESIZEY, zoom); + return 0; + } + img.fill(0); + img.setNumColors( m_bsb->num_colors ); + for ( int col = 0; col < m_bsb->num_colors; col++ ) + { + img.setColor( col, qRgb( m_bsb->red[col], m_bsb->green[col], m_bsb->blue[col] ) ); + } + for ( int y = 0; y < TILESIZEY/zoom; y++ ) + { + uchar* ppix = img.scanLine(y); + int yy = yc+y; + if( yy < m_bsb->height ) + bsb_read_row_part( m_bsb, yy, ppix, xc, img.width() ); + else + memset(ppix,0, img.width()); + } + // scale it up + return new QImage(img.scaled(TILESIZEX,TILESIZEY, + Qt::IgnoreAspectRatio, + Qt::FastTransformation)); + } +} + +/** + * Handles paint events for the connect widget. + */ +void BSBWidget::paintEvent(QPaintEvent* pe) +{ + QRect r = pe->rect(); + int cx = r.left(); + int cy = r.top(); + int cw = r.width(); + int ch = r.height(); + QPainter p( this ); + + //printf("dc %d %d %d %d\n", cx, cy, cw, ch ); + // do we have anything to draw? + if ( m_bsb ) + { + QImage* img = makeTileQuick( cx, cy, m_zoom, cw, ch ); + if( img ) + { + p.drawImage( cx, cy, *img ); + delete img; + } + if ( display_refs ) + { + for ( int r = 0; r < m_bsb->num_refs; r++ ) + { + const int size = 10; + + int xc, yc, x, y; + chartToScreen(m_bsb->ref[r].x, m_bsb->ref[r].y, &x, &y); + //printf( "(%f,%f) -> (%d,%d) -> (%d,%d)\n", + // m_bsb->ref[r].lon, m_bsb->ref[r].lat, xc, yc, x, y ); + if ( x >= cx && x < cx+cw && y >= cy && y < cy+ch ) + { + p.setPen(QColor(64,255,64)); + p.drawRect( x-size/2, y-size/2, size, size ); + } + + bsb_LLtoXY( m_bsb, m_bsb->ref[r].lon, m_bsb->ref[r].lat, &xc, &yc ); + chartToScreen(xc, yc, &x, &y); + //printf( "(%f,%f) -> (%d,%d) -> (%d,%d)\n", + // m_bsb->ref[r].lon, m_bsb->ref[r].lat, xc, yc, x, y ); + if ( x >= cx && x < cx+cw && y >= cy && y < cy+ch ) + { + p.setPen(QColor(255,64,64)); + p.drawRect( x-size/2, y-size/2, size, size ); + } + } + } + if ( display_border ) + { + p.setPen(QColor(255,64,64)); + QPolygon pg(m_bsb->num_plys); + for ( int r = 0; r < m_bsb->num_plys; r++ ) + { + int xc, yc, x, y; + bsb_LLtoXY( m_bsb, m_bsb->ply[r].lon, m_bsb->ply[r].lat, &xc, &yc ); + chartToScreen(xc, yc, &x, &y); + pg.setPoint(r, x, y); + } + p.drawPolygon(pg); + } + } + else + { + QFont font( "Helvetica", 12 ); + p.setFont( font ); + QFontMetrics fm = p.fontMetrics(); + //p.drawText( 10, 10+fm.ascent(), bsbFileName ); + p.drawText( 10, 10+2*fm.ascent(), "The chart did not load!"); + } + //printf("dce\n"); +} diff -Nru libbsb-0.0.7/bsbview_src/BSBWidget.h libbsb-0.0.8.1/bsbview_src/BSBWidget.h --- libbsb-0.0.7/bsbview_src/BSBWidget.h 1970-01-01 00:00:00.000000000 +0000 +++ libbsb-0.0.8.1/bsbview_src/BSBWidget.h 2016-03-19 21:41:15.000000000 +0000 @@ -0,0 +1,81 @@ +#ifndef BSBWidget_INCLUDED +#define BSBWidget_INCLUDED +/* +* BSBWidget.h - declaration of BSBWidget for qchart - a marine BSB chart viewer +* +* Copyright (C) 2006 Michal Krombholz +* +* This software is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* This software 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* $Id: BSBWidget.h,v 1.1 2007/02/18 07:56:56 mikrom Exp $ +* +*/ + +#include +#include +#include +#include + +// +// BSBWidget - draws BSB image +// +class BSBWidget : public QWidget +{ + Q_OBJECT + + public: + BSBWidget( QWidget *parent=0 ); + ~BSBWidget(); + + void setChart(BSBImage* bsb); + void setZoom(int zoom); + int getZoom() { return m_zoom; } + QSize getZoomedSize(); + + void screenToChart(int xs,int ys,int* xc, int* yc); + void chartToScreen(int xc,int yc,int* xs, int* ys); + void screenToLLStr(int x, int y, char* s); + + void setDisplayRefs(bool on) { display_refs = on; update(); } + bool getDisplayRefs() { return display_refs; } + void setDisplayBorder(bool on) { display_border = on; update(); } + bool getDisplayBorder() { return display_border; } + + + enum + { + MAXZOOM = 10, + MINZOOM = -10 + }; + +protected: + enum + { + MAXCOLORS = 256 + }; + + virtual void paintEvent( QPaintEvent * ); + + QImage* makeTileQuick(int xc, int yc, int zoom, const int TILESIZEX = 200,const int TILESIZEY = 200); + QImage* makeTileSmooth(int xc, int yc, int zoom, const int TILESIZEX = 200,const int TILESIZEY = 200); + +private: + BSBImage* m_bsb; + int m_zoom; + bool display_border; + bool display_refs; +}; + +#endif // #ifndef BSBWidget_INCLUDED diff -Nru libbsb-0.0.7/bsbview_src/main.cpp libbsb-0.0.8.1/bsbview_src/main.cpp --- libbsb-0.0.7/bsbview_src/main.cpp 1970-01-01 00:00:00.000000000 +0000 +++ libbsb-0.0.8.1/bsbview_src/main.cpp 2016-03-19 21:41:15.000000000 +0000 @@ -0,0 +1,70 @@ +/* +* main.cpp - implementation of main() for qchart a marine BSB chart viewer +* Copyright (C) 2006 Michal Krombholz +* +* This software is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* This software 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* $Id: main.cpp,v 1.1 2007/02/18 07:50:31 mikrom Exp $ +* +*/ + +#include + +#include +#include + +// +// Create and display a BSBWidget. +// +int main( int argc, char **argv ) +{ + QApplication a( argc, argv ); + + BSBMainWindow *mw = new BSBMainWindow(); + + //bsbsa.setCaption("QCharts Viewer"); + char *startchart = (char*)"/home/m/BSB_ROOT/World.KAP"; + //char *startchart = (char*)"d:\\home\\BSB_ROOT\\World.KAP"; + + //extern char *optarg; + extern int optind, optopt; + bool test = false; + bool verbose = false; + bool quit = false; + int c; + while ((c = getopt(argc, argv, ":tvq")) != -1) { + switch (c) { + case 't': test = true; break; + case 'v': verbose = true; break; + case 'q': quit = true; break; + default : printf("ignoring option %c\n", optopt); break; + } + } + // see if there is any file name + for ( ; optind < argc; optind++) { + startchart = argv[optind]; + } + if( startchart ) + { + mw->setChartFile(startchart); + } + if( !quit ) + { + mw->resize(640,480); + mw->show(); + a.connect( &a, SIGNAL(lastWindowClosed()), &a, SLOT(quit()) ); + return a.exec(); + } + } diff -Nru libbsb-0.0.7/BSBWidget.cpp libbsb-0.0.8.1/BSBWidget.cpp --- libbsb-0.0.7/BSBWidget.cpp 1970-01-01 00:00:00.000000000 +0000 +++ libbsb-0.0.8.1/BSBWidget.cpp 2016-03-19 21:41:15.000000000 +0000 @@ -0,0 +1,738 @@ +/* +* BSBWidget.cpp - implementation of BSBWidget for qchart - a marine BSB chart viewer +* +* Copyright (C) 2006 Michal Krombholz +* +* This software is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* This software 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* $Id: BSBWidget.cpp,v 1.1 2007/02/06 16:05:25 mikrom Exp $ +* +*/ + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// set preload to 1 if you want the entire chart to be preloaded (faster) +// note: this takes gobs of memory as chart rasters can be tens MB +#define PRELOAD 0 + +#include "BSBWidget.h" + +/** + * Constructs a BSBWidget. + */ +BSBWidget::BSBWidget( QWidget *parent, const char *name ) +: QWidget( parent, name, WNorthWestGravity|WNoAutoErase ), + mseDown(false), + bsbFileName(""), + bsbLoaded(false), + bsbBuf(0), + xc_ofs(0), + yc_ofs(0), + zoom(1), + display_border(false), + display_refs(false) +{ + cursor.setShape( Qt::CrossCursor ); + setCursor( cursor ); +} + +/** + * Destructs a BSBWidget. + */ +BSBWidget::~BSBWidget() +{ +} + +/** + * Sets current raster chart to view + * + * @param filename full path to the BSB file name to open + */ +void +BSBWidget::setChartFile(const char* filename) +{ + if ( bsbLoaded ) + { + bsb_close( &bsb ); + bsbLoaded = false; + free((void*)bsbFileName); + } + bsbFileName = strdup(filename); + if ( bsb_open_header((char*)filename, &bsb) ) + { + for ( int i=0; i 0 ) + { + prg = y*100/bsb.height; + prog.setProgress( prg ); + } + qApp->processEvents(); + { + //bsb_read_row(&bsb, bsbBuf+y*bsb.width); + bsb_read_row_at(&bsb, y, bsbBuf+y*bsb.width); + } + } +#else + bsbBuf = new uint8_t[bsb.width]; +#endif + zoomToFitChart(); + } +} + +/** + * test the Geo Transform using BSB reference points + * + * @param verbose set to true for point-by-point print + */ +void +BSBWidget::testGeoTransform(bool verbose) +{ + if ( bsbLoaded ) + { + printf("%s: NA=%s PR=%s GD=%s\nrefs=%d plys=%d wpx=%d/%d wpy=%d/%d pwx=%d/%d pwy=%d/%d cph=%f ", + bsbFileName, + bsb.name, bsb.projection, bsb.datum, + bsb.num_refs, bsb.num_plys, + bsb.num_wpxs, bsb.wpx_level, bsb.num_wpys, bsb.wpy_level, + bsb.num_pwxs, bsb.pwx_level, bsb.num_pwys, bsb.pwy_level, + bsb.cph + ); + if ( verbose ) printf("\n"); + int maxXerr = 0; + int maxYerr = 0; + double maxLatErr = 0; + double maxLonErr = 0; + for ( int r = 0; r < bsb.num_refs; r++ ) + { + int xc, yc; + bsb_LLtoXY( &bsb, bsb.ref[r].lon, bsb.ref[r].lat, &xc, &yc ); + int xerr = abs(bsb.ref[r].x-xc); + int yerr = abs(bsb.ref[r].y-yc); + if ( maxXerr < xerr ) maxXerr = xerr; + if ( maxYerr < yerr ) maxYerr = yerr; + double lat, lon; + bsb_XYtoLL( &bsb, bsb.ref[r].x, bsb.ref[r].y, &lon, &lat ); + double latErr = fabs(bsb.ref[r].lat-lat); + double lonErr = fabs(bsb.ref[r].lon-lon); + if ( maxLonErr < lonErr ) maxLonErr = lonErr; + if ( maxLatErr < latErr ) maxLatErr = latErr; + if ( verbose ) + { + printf("Ref#%3d (%8.3f,%8.3f} {%5d,%5d} --> ", + r+1, bsb.ref[r].lon, bsb.ref[r].lat, bsb.ref[r].x, bsb.ref[r].y ); + printf("{%5d,%5d} err {%3d,%3d} ", xc, yc, bsb.ref[r].x - xc, bsb.ref[r].y - yc ); + printf("{%8.3f,%8.3f} err {%8.3f,%8.3f} ", lon, lat, bsb.ref[r].lon - lon, bsb.ref[r].lat - lat ); + printf("\n"); + } + } + printf("err xy=%d/%d ll=%f/%f\n", maxXerr, maxYerr, maxLonErr, maxLatErr ); + } +} + +/* + * Open dialog and let the user to select the chart file + */ +void +BSBWidget::selectChartFile() +{ + QFileDialog fd; + fd.addFilter("BSB Charts (*.KAP)"); + fd.setCaption("Select BSB chart file"); + fd.setDir("~/BSB_ROOT"); + if( fd.exec() == QDialog::Accepted ) + { + QString qfn = fd.selectedFile(); + setChartFile( qfn.ascii() ); + } +} + +/** + * Adjust the zoom to fit the chart in the current window + */ +void +BSBWidget::zoomToFitChart() +{ + int w = width(); + int h = height(); + int wc = bsb.width; + int hc = bsb.height; + int zw = (wc+w/2)/w; + int zh = (hc+h/2)/h; + zoom = zw > zh ? zw : zh; + if ( zoom < 1 ) zoom = 1; + if ( zoom > MAXZOOM ) zoom = MAXZOOM; +} + +/** + * Returns the pointer to memory buffer with given image row. + * If no preload is selected than the buffer if always the same + * but the function reads the specified row into it first. + * + * @param row row number to get the pointer to + */ +uint8_t* BSBWidget::getRow(int row) +{ + uint8_t* p = 0; + if ( row >=0 && row < bsb.height ) + { +#if PRELOAD + p = bsbBuf+row*bsb.width; +#else + //if( bsb_seek_to_row(&bsb, row) ) + { + bsb_read_row_at(&bsb, row, bsbBuf); + p = bsbBuf; + } +#endif + } + return p; +} + +/** + * Converts screen x,y to chart xc,yc + * + * @param x screen X coordinate + * @param y screen Y coordinate + * @param xc output chart X coordinate + * @param yc output chart Y coordinate + */ +void BSBWidget::screenToChart(int x, int y, int* xc, int* yc) +{ + // relative to origin of the screen and zoomed + int xz=x*zoom; + int yz=y*zoom; + // absolute to the origin in chart's units + *xc = xc_ofs+xz; + *yc = yc_ofs+yz; +} + +/** + * Converts screen x,y to chart Lat/Lon and formats for output + * + * @param x screen X coordinate + * @param y screen Y coordinate + * @param s output text buffer + */ +void BSBWidget::screenToLLStr(int x, int y, char* s) +{ + double lat,lon; + int xc,yc; + screenToChart(x, y, &xc, &yc); + if( bsb_XYtoLL(&bsb, xc, yc, &lon, &lat) ) + { + char sn = 'N'; + if( lat < 0 ) + { + sn = 'S'; + lat = -lat; + } + char ew = 'E'; + if( lon < 0 ) + { + ew = 'W'; + lon = -lon; + + } + sprintf(s, "Lat %7.3f%c Lon %7.3f%c", lat,sn,lon,ew); + } + else + { + strcpy(s, "Lat ? Lon ?"); + } +} + +/** + * Converts chart xc, yc to screen x,y + * + * @param xc chart X coordinate + * @param yc chart Y coordinate + * @param x output screen X coordinate + * @param y output screen Y coordinate + */ +void BSBWidget::chartToScreen(int xc, int yc, int* x, int* y) +{ + // relative to the chart's display offset + xc -= xc_ofs; + yc -= yc_ofs; + *x = xc / zoom; + *y = yc / zoom; +} + +/** + * Handles paint events for the connect widget. + */ +void BSBWidget::paintEvent( QPaintEvent * ) +{ + QPainter paint( this ); + // do we have anything to print? + if ( bsbLoaded ) + { + int ws = width(); + int hs = height(); + QImage img( ws, hs, 8 ); + img.setNumColors( bsb.num_colors ); + for ( int col = 0; col < bsb.num_colors; col++ ) + { + img.setColor( col, qRgb( bsb.red[col], bsb.green[col], bsb.blue[col] ) ); + } + +#if 0 /* keep max of chart visible - limit the chart offset */ + // chart visible width & height + int wz = ws*zoom; + int hz = hs*zoom; + // correct chart center + if ( x_cent - wz/2 < 0 ) + x_cent = wz < bsb.width ? wz/2 : bsb.width/2; + if ( x_cent + wz/2 > bsb.width ) + x_cent = wz < bsb.width ? bsb.width-wz/2 : bsb.width/2; + if ( y_cent - hz/2 < 0 ) + y_cent = hz < bsb.height ? hz/2 : bsb.height/2; + if ( y_cent + hz/2 > bsb.height ) + y_cent = hz < bsb.width ? bsb.height-hz/2 : bsb.height/2; +#endif + // chart unit offsets + int xo = xc_ofs; + int yo = yc_ofs; +#define FILTER 0 /* simple average filter for filtering down */ +#if FILTER + // screen offsets and coordinates + for ( int y = 0; y < hs; y++ ) + { + for ( int x = 0; x < ws; x++ ) + { + int r = 0, g = 0, b = 0; + int yy = yo+y*zoom; + for ( int yc = yy ; yc < yy+zoom; yc ++ ) + { + uint8_t* row = getRow(yc); + for ( int xc = xo+x*zoom; row && (xc < xo+x*zoom+zoom); xc ++ ) + { + int c = xc >=0 && xc < bsb.width ? row[xc] : 0; + r += bsb.red[c]; + g += bsb.green[c]; + b += bsb.blue[c]; + } + } + img.setPixel( x, y, QColor(r/zoom,g/zoom,b/zoom).pixel() ); + } + } +#else + // screen offsets and coordinates + for ( int y = 0; y < hs; y++ ) + { + int yc = yo+y*zoom; + uint8_t* row = getRow(yc); + uchar* ppix = img.scanLine(y); + for ( int x = 0; x < ws; x++ ) + { + int xc = xo+x*zoom; +//#define HORFILTER +#ifdef HORFILTER + int col = 0; + for ( int i = 0; i < zoom; i++, xc++ ) + col += row && xc >=0 && xc < bsb.width ? row[xc] : 0; + col /= zoom; +#else + int col = row && xc >=0 && xc < bsb.width ? row[xc] : 0; +#endif + *ppix++ = col; + //img.setPixel( x, y, col ); + } + } +#endif + paint.drawImage( 0, 0, img ); + if ( display_refs ) + { + for ( int r = 0; r < bsb.num_refs; r++ ) + { + const int size = 10; + + int xc, yc; + int x,y; + chartToScreen( bsb.ref[r].x, bsb.ref[r].y, &x, &y ); + //printf( "(%f,%f) -> (%d,%d) -> (%d,%d)\n", + // bsb.ref[r].lon, bsb.ref[r].lat, xc, yc, x, y ); + if ( x >= 0 && x < width() && y >= 0 && y < height() ) + { + paint.setPen(QColor(64,255,64)); + paint.drawRect( x-size/2, y-size/2, size, size ); + } + + bsb_LLtoXY( &bsb, bsb.ref[r].lon, bsb.ref[r].lat, &xc, &yc ); + chartToScreen( xc, yc, &x, &y ); + //printf( "(%f,%f) -> (%d,%d) -> (%d,%d)\n", + // bsb.ref[r].lon, bsb.ref[r].lat, xc, yc, x, y ); + if ( x >= 0 && x < width() && y >= 0 && y < height() ) + { + paint.setPen(QColor(255,64,64)); + paint.drawRect( x-size/2, y-size/2, size, size ); + } + } + } + if ( display_border ) + { + paint.setPen(QColor(255,64,64)); + QPointArray pa(bsb.num_plys); + for ( int r = 0; r < bsb.num_plys; r++ ) + { + int xc, yc; + bsb_LLtoXY( &bsb, bsb.ply[r].lon, bsb.ply[r].lat, &xc, &yc ); + int x,y; + chartToScreen( xc, yc, &x, &y ); + pa.setPoint(r,x,y); + } + paint.drawPolygon(pa); + } + + } + else + { + QFont font( "Helvetica", 12 ); + paint.setFont( font ); + QFontMetrics fm = paint.fontMetrics(); + paint.drawText( 10, 10+fm.ascent(), bsbFileName ); + paint.drawText( 10, 10+2*fm.ascent(), "The chart did not load!"); + } +} + +// +// Handles mouse press events for the connect widget. +// +void BSBWidget::mousePressEvent( QMouseEvent *e ) +{ + msedwntme.start(); + msedwnpos = e->pos(); + x_dwn = xc_ofs; + y_dwn = yc_ofs; + switch ( e->button() ) + { + case Qt::LeftButton : { + cursor.setShape( Qt::SizeAllCursor ); + setCursor( cursor ); + mseDown = TRUE; + break; + } + case Qt::RightButton : { + break; + } + default: + break; + } +} + +/** + * Handles mouse double click press events for the connect widget. + * Here execute ZOOM IN action at the click point. + */ +void BSBWidget::mouseDoubleClickEvent ( QMouseEvent * e ) +{ + doAction(A_ZOOMIN, e->x(), e->y() ); +} + +/** + * Show context menu at given point. + * + * @param p clicked point to show the menu at + */ +void +BSBWidget::doContextMenu( QPoint p ) +{ + char s[100]; + screenToLLStr( p.x(), p.y(), s ); + + QPopupMenu pup(this); + pup.setCheckable(true); + pup.setCaption("Actions"); + pup.insertItem("Zoom In",A_ZOOMIN); + pup.insertItem("Zoom Out",A_ZOOMOUT); + pup.insertItem("Full zoom",A_ZOOMMAX); + pup.insertItem("Show all",A_ZOOMMIN); + pup.insertItem("Center",A_CENTER); + pup.insertSeparator(); + pup.insertItem("Open chart",A_OPEN); + pup.insertItem("Chart info",A_CHARTINFO); + pup.insertItem("Display border",A_DISPBORDER); + pup.setItemChecked(A_DISPBORDER, display_border); + pup.insertItem("Display refs",A_DISPREFS); + pup.setItemChecked(A_DISPREFS, display_refs); + pup.insertSeparator(); + pup.insertItem("Toggle Full Screen",A_FULLSCREEN); + pup.insertItem("About",A_ABOUT); + pup.insertItem("Exit",A_EXIT); + pup.insertSeparator(); + pup.insertItem(s); + + doAction((Action)pup.exec(mapToGlobal(p)),p.x(),p.y()); +} + +/** + * Handles main UI actions. + * + * @param action the action to perform + * @param par1 first parameter (action specific) + * @param par2 second parameter (action specific) + */ +void BSBWidget::doAction(enum Action action, int par1, int par2) +{ + int xc,yc; + screenToChart( par1, par2, &xc, &yc ); + bool applyShift = false; + + switch ( action ) + { + case A_ZOOMIN: + { + zoom/=2; + if (zoom<1) zoom=1; + applyShift = true; + break; + } + case A_ZOOMOUT: + { + zoom*=2; + if (zoom>MAXZOOM) zoom=MAXZOOM; + applyShift = true; + break; + } + case A_ZOOMMAX: + { + zoom=1; + applyShift = true; + break; + } + case A_ZOOMMIN: + zoomToFitChart(); /* continue to CENTER */ + case A_CENTER: + { + xc = bsb.width/2; + yc = bsb.height/2; + applyShift = true; + break; + } + case A_FULLSCREEN: + if ( isFullScreen() ) + showNormal(); + else + showFullScreen(); + break; + case A_OPEN: + selectChartFile(); + update(); + break; + case A_ABOUT: + QMessageBox::information(this, + "About QCharts", + "QCharts written by Michal Krombholz (C)2006" + "

With help from libbsb code by Stuart Cunningham" + "

Use popup menu for commands." + "

Keys:
" + "Z+ zoom in
" + "X- zoom out
" + "C center
" + "A fit to screen
" + "S 1:1 zoom
" + "F toggle full screen
" + "

also use:
" + "- left mouse button for panning (grab the chart)
" + "- right button for mouse gestures:
" + "up to zoom into an area
" + "down to zoom out
" + , QMessageBox::Ok); + break; + case A_CHARTINFO: + { + char txt[1000]; + sprintf(txt, + "%s
" + "%s
" + "version : %f
" + "%s/%s
" + "scale : %.0f at %.3f lat
" + "res x/y : %.3f/%.3f
" + "# refs : %d
" + "# borders : %d
" + "# geocoef : %d/%d/%d/%d %d/%d/%d/%d
" + "cph : %f
" + , + bsbFileName, + bsb.name, bsb.version, + bsb.projection, bsb.datum, + bsb.scale, bsb.projectionparam, + bsb.xresolution, bsb.yresolution, + bsb.num_refs, bsb.num_plys, + bsb.num_wpxs, bsb.num_wpys, bsb.num_pwxs, bsb.num_pwys, + bsb.wpx_level, bsb.wpy_level, bsb.pwx_level, bsb.pwy_level, bsb.cph ); + QMessageBox::information(this, "About This Chart", txt, QMessageBox::Ok); + } + break; + case A_DISPBORDER: + display_border = !display_border; + update(); + break; + case A_DISPREFS: + display_refs = !display_refs; + update(); + break; + case A_EXIT: + QApplication::exit( 0 ); + break; + } + // apply image shift (if any) and redraw the image + if ( applyShift ) + { + xc_ofs = xc-width()*zoom/2; + yc_ofs = yc-height()*zoom/2; + update(); + } +} + +/** + * Handles mouse release events for the connect widget. + * The code is smart on right click: + * - if it was a short click and mouse did not move much then it's a popup menu + * - if the time was longer and mouse move then it is a gesture + */ +void BSBWidget::mouseReleaseEvent( QMouseEvent *e ) +{ + cursor.setShape( Qt::CrossCursor ); + setCursor( cursor ); + QPoint mseuppos = e->pos(); + switch ( e->button() ) + { + case Qt::LeftButton : + if ( mseDown ) + { + mseDown = false; + xc_ofs = x_dwn - (mseuppos.x()-msedwnpos.x())*zoom; + yc_ofs = y_dwn - (mseuppos.y()-msedwnpos.y())*zoom; + update(); + } + break; + case Qt::RightButton : { + int dx = mseuppos.x()-msedwnpos.x(); + int dy = mseuppos.y()-msedwnpos.y(); + int adx = dx > 0 ? dx : -dx; + int ady = dy > 0 ? dy : -dy; + if ( msedwntme.elapsed() < 300 /* ms */ && adx < 10 && ady < 10 ) + { + doContextMenu( msedwnpos ); + } + else /* its a gesture - up (zoom in) or down (zoom out) */ + { + int xc,yc; + screenToChart( mseuppos.x()-dx/2, mseuppos.y()-dy/2, &xc, &yc ); + if ( dy && dx/dy == 0 ) + zoom = (dy>0) ? zoom*2 : zoom/2; + else if ( dx ) + zoom = dx>0 ? (dx*zoom)/width() : zoom*2; + if ( zoom > MAXZOOM ) zoom = MAXZOOM; + if ( zoom < 1 ) zoom = 1; + xc_ofs = xc - width()*zoom/2; + yc_ofs = yc - height()*zoom/2; + update(); + } + } + break; + default: + break; + } +} + +/** + * Handles mouse move events for the widget. + */ +void BSBWidget::mouseMoveEvent( QMouseEvent *e ) +{ + if ( mseDown ) + { + QPoint mseuppos = e->pos(); + xc_ofs = x_dwn - (mseuppos.x()-msedwnpos.x())*zoom; + yc_ofs = y_dwn - (mseuppos.y()-msedwnpos.y())*zoom; + update(); // draw the lines + } +} + +/** + * Handles key events for the widget. + */ +void BSBWidget::keyPressEvent( QKeyEvent *e ) +{ + if ( !(e->state() & Qt::KeyButtonMask) ) + { + Action action; + int x = width()/2; + int y = height()/2; + switch ( e->ascii() ) + { + case '+': + case 'z': + case 'Z': action = A_ZOOMIN; break; + case '-': + case 'x': + case 'X': action = A_ZOOMOUT; break; + case 'c': + case 'C': action = A_CENTER; break; + case 'a': + case 'A': action = A_ZOOMMIN; break; + case 's': + case 'S': action = A_ZOOMMAX; break; + case 'f': + case 'F': action = A_FULLSCREEN; break; + default: return; + } + doAction(action,x,y); + } +} + diff -Nru libbsb-0.0.7/BSBWidget.h libbsb-0.0.8.1/BSBWidget.h --- libbsb-0.0.7/BSBWidget.h 1970-01-01 00:00:00.000000000 +0000 +++ libbsb-0.0.8.1/BSBWidget.h 2016-03-19 21:41:15.000000000 +0000 @@ -0,0 +1,109 @@ +#ifndef BSBWidget_INCLUDED +#define BSBWidget_INCLUDED +/* +* BSBWidget.h - declaration of BSBWidget for qchart - a marine BSB chart viewer +* +* Copyright (C) 2006 Michal Krombholz +* +* This software is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* This software 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* $Id: BSBWidget.h,v 1.1 2007/02/06 16:05:25 mikrom Exp $ +* +*/ + +#include + +#include +#include +#include +#include + +// +// BSBWidget - draws BSB image +// +class BSBWidget : public QWidget +{ +// Q_OBJECT + + public: + BSBWidget( QWidget *parent=0, const char *name=0 ); + ~BSBWidget(); + + void setChartFile(const char* filename); + void selectChartFile(); + void testGeoTransform(bool verbose); + +protected: + enum + { + MAXCOLORS = 256, + MAXZOOM = 256 + }; + + virtual void paintEvent( QPaintEvent * ); + virtual void mousePressEvent( QMouseEvent *); + virtual void mouseReleaseEvent( QMouseEvent *); + virtual void mouseDoubleClickEvent( QMouseEvent *); + virtual void mouseMoveEvent( QMouseEvent *); + virtual void doContextMenu( QPoint p ); + virtual void keyPressEvent( QKeyEvent * ); + + enum Action + { + A_ZOOMIN, + A_ZOOMOUT, + A_ZOOMMAX, + A_ZOOMMIN, + A_CENTER , + A_FULLSCREEN, + A_CHARTINFO, + A_DISPBORDER, + A_DISPREFS, + A_OPEN, + A_EXIT, + A_ABOUT + }; + + void doAction(enum Action action,int par1 = 0, int par2 = 0); + void zoomToFitChart(); + + uint8_t* getRow(int row); + + void screenToChart(int x, int y, int* xc, int* yc); + void chartToScreen(int xc, int yc, int* x, int* y); + void screenToLLStr(int x, int y, char* s); + +private: + QCursor cursor; + bool mseDown; // TRUE if mouse button down + QPoint msedwnpos; + QTime msedwntme; + + const char* bsbFileName; + bool bsbLoaded; + uint8_t* bsbBuf; + BSBImage bsb; + uint colors[MAXCOLORS]; // color array + + int xc_ofs; + int yc_ofs; + int zoom; + int x_dwn; + int y_dwn; + bool display_border; + bool display_refs; +}; + +#endif // #ifndef BSBWidget_INCLUDED diff -Nru libbsb-0.0.7/configure libbsb-0.0.8.1/configure --- libbsb-0.0.7/configure 2015-01-16 15:25:19.000000000 +0000 +++ libbsb-0.0.8.1/configure 2016-03-19 21:41:15.000000000 +0000 @@ -2852,7 +2852,7 @@ *) # override AC_PROG_CC default CFLAGS except when user specified CFLAGS if test x"$orig_cflags" != x"$CFLAGS" ; then - CFLAGS="-g -O2 -W -Wall -Werror" + CFLAGS="-g -O2 -W -Wall" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. diff -Nru libbsb-0.0.7/configure.ac libbsb-0.0.8.1/configure.ac --- libbsb-0.0.7/configure.ac 2015-01-16 15:25:19.000000000 +0000 +++ libbsb-0.0.8.1/configure.ac 2016-03-19 21:41:15.000000000 +0000 @@ -1,13 +1,13 @@ -dnl $Id: configure.ac,v 1.23 2004/12/22 13:11:36 stuart_hc Exp $ +dnl $Id: configure.ac,v 1.25 2007/02/18 07:35:04 mikrom Exp $ dnl dnl Process this file with autoconf to produce a configure script. AC_INIT(bsb2tif.c) -AM_INIT_AUTOMAKE(libbsb, 0.0.7) +AM_INIT_AUTOMAKE(libbsb, 0.0.8) dnl AC_PROG_CC finds CC and defaults CFLAGS (usually -g -O2) orig_cflags=$CFLAGS AC_PROG_CC - +AC_PROG_CXX dnl Default CFLAGS for developer's convenience and avoid ranlib with MSVC use_msvc=no @@ -52,6 +52,28 @@ AC_MSG_WARN([*** PNG conversion tools will not be built ***]) fi +have_qt=no +AC_PATH_X +qtdir=${QTDIR} +if test x"$qtdir" = "x" ; then + dnl Try to locate Qt4 in well-known places + AC_CHECK_FILE([/usr/share/qt4], + [qtdir=/usr/share/qt4], + [qtdir=/usr/lib/qt4]) + export QTDIR=$qtdir + AC_MSG_WARN([QTDIR not set, assuming $qtdir but build will fail if QTDIR env var not set]) +fi +qt_includes=$qtdir/include +export CPPFLAGS="$CPPFLAGS -I$qt_includes" +AC_CHECK_HEADER([QtCore/qglobal.h], [ have_libqt=yes ] ) +AM_CONDITIONAL(HAVE_LIBQT, test x"$have_libqt" = "xyes") +if test x"$have_libqt" = "xyes" ; then + echo "Qt4 seems OK. Including bsbview in the build!" +else + AC_MSG_WARN([*** bsbview will not be built (no QT or QTDIR wrong) ***]) +fi + + dnl Test for valgrind and test which args are needed for memcheck. dnl Using -q --leak-check on valgrind pre-2.2 gives stderr output when dnl no leaks are found so only use --leak-check with recent valgrind. diff -Nru libbsb-0.0.7/debian/changelog libbsb-0.0.8.1/debian/changelog --- libbsb-0.0.7/debian/changelog 2015-01-16 18:20:11.000000000 +0000 +++ libbsb-0.0.8.1/debian/changelog 2018-02-14 00:18:08.000000000 +0000 @@ -1,40 +1,20 @@ -libbsb (0.0.7-0~trusty2) trusty; urgency=low +libbsb (0.0.8.1-0~trusty1) trusty; urgency=low - * 0.0.7 + * v0.0.8 - -- Pavel Kalian Fri, 16 Jan 2015 12:19:40 -0600 -libbsb (0.0.7-0~utopic2) utopic; urgency=low + -- Pavel Kalian Tue, 13 Feb 2018 18:16:24 -0600 +libbsb (0.0.8.1-0~xenial1) xenial; urgency=low - * 0.0.7 + * v0.0.8 - -- Pavel Kalian Fri, 16 Jan 2015 12:19:40 -0600 -libbsb (0.0.7-0~vivid2) vivid; urgency=low + -- Pavel Kalian Tue, 13 Feb 2018 18:16:24 -0600 +libbsb (0.0.8.1-0~artful1) artful; urgency=low - * 0.0.7 + * v0.0.8 - -- Pavel Kalian Fri, 16 Jan 2015 12:19:40 -0600 -libbsb (0.0.7-0~lucid1) lucid; urgency=low + -- Pavel Kalian Tue, 13 Feb 2018 18:16:24 -0600 +libbsb (0.0.8.1-0~bionic1) bionic; urgency=low - * 0.0.7 + * v0.0.8 - -- Pavel Kalian Fri, 16 Jan 2015 12:04:57 -0600 -libbsb (0.0.7-0~precise1) precise; urgency=low - - * 0.0.7 - - -- Pavel Kalian Fri, 16 Jan 2015 12:04:57 -0600 -libbsb (0.0.7-0~trusty1) trusty; urgency=low - - * 0.0.7 - - -- Pavel Kalian Fri, 16 Jan 2015 12:04:57 -0600 -libbsb (0.0.7-0~utopic1) utopic; urgency=low - - * 0.0.7 - - -- Pavel Kalian Fri, 16 Jan 2015 12:04:57 -0600 -libbsb (0.0.7-0~vivid1) vivid; urgency=low - - * 0.0.7 - - -- Pavel Kalian Fri, 16 Jan 2015 12:04:57 -0600 + -- Pavel Kalian Tue, 13 Feb 2018 18:16:24 -0600 diff -Nru libbsb-0.0.7/debian/control libbsb-0.0.8.1/debian/control --- libbsb-0.0.7/debian/control 2015-01-16 18:19:41.000000000 +0000 +++ libbsb-0.0.8.1/debian/control 2018-02-14 00:16:28.000000000 +0000 @@ -5,11 +5,9 @@ Build-Depends: debhelper (>= 8.0.0), libtiff-dev, libpng-dev, cdbs Standards-Version: 3.9.3 Homepage: http://libbsb.sourceforge.net -#Vcs-Git: git://git.debian.org/collab-maint/opencpn.git -#Vcs-Browser: http://git.debian.org/?p=collab-maint/opencpn.git;a=summary Package: libbsb Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} -Description: A portable C library for reading and writing BSB format image files. - Typically used for nautical charts, BSB charts use the .KAP or .CAP extension and store cartographic information in addition to a run-length encoded raster image. libbsb is capable of recovering truncated or otherwise corrupted .KAP files. +Description: Tool to create and convert BSB/KAP charts. + Typically used for nautical charts, BSB charts use the .KAP or .CAP extension and store cartographic information in addition to a run-length encoded raster image. diff -Nru libbsb-0.0.7/debian/copyright libbsb-0.0.8.1/debian/copyright --- libbsb-0.0.7/debian/copyright 2015-01-16 18:19:41.000000000 +0000 +++ libbsb-0.0.8.1/debian/copyright 2018-02-14 00:16:28.000000000 +0000 @@ -1,6 +1,6 @@ Format: http://dep.debian.net/deps/dep5 Upstream-Name: libbsb -Source: +Source: Files: * Copyright: 2004 Stuart Cunningham Binary files /tmp/tmp9jfR8X/iNtLagcTLy/libbsb-0.0.7/doc/arrow.png and /tmp/tmp9jfR8X/jPCqVhVl9C/libbsb-0.0.8.1/doc/arrow.png differ diff -Nru libbsb-0.0.7/doc/bsb_file_format.html libbsb-0.0.8.1/doc/bsb_file_format.html --- libbsb-0.0.7/doc/bsb_file_format.html 1970-01-01 00:00:00.000000000 +0000 +++ libbsb-0.0.8.1/doc/bsb_file_format.html 2016-03-19 21:41:15.000000000 +0000 @@ -0,0 +1,153 @@ + + + + + libbsb - BSB File format + + + + + +

The BSB file format

+

+A nautical chart set in BSB format consists of several files: main .BSB file and one or more .KAP files. A main BSB file contains chart set meta-data information (chart description, function, enumeration of .KAP files. Note that NOAA BSB charts are meant to be exact equivalent of paper charts, so they contain the same number of sub-charts (paper pages). The .BSB file is unusual in that it contains both ASCII text and binary data concatenated together and structured as follows: + +

    +
  • Text header in DOS text format (CR-LF line-endings) terminated by <Control-Z><NUL> +
  • Binary section consisting of: +
      +
    • One or more rows of run-length compressed raster data +
    • An index table consisting of 32-bit integers storing file offsets to each image row +
    +
+ +

Text Header

+

+Although described as proprietary by NOAA, much of the information in the ASCII text header is self explanatory. Each line begins with a 3 character token followed by a slash "/". The remainder of the line depends upon the token, but in general consists of a list of comma separated values. If the list of values is too long for 80 columns, the values for the token are continued on the next line by prefixing the new line with 4 spaces. Comments are indicated with a leading "!". + +

+    ! An example BSB text header
+    VER/3.0
+    BSB/NA=Australia 3000000
+        NU=,RA=625,480,DU=50
+    KNP/SC=3000000,GD=,PR=LAMBERT CONFORMAL CONIC,PP=145.0
+        PI=0.0,SP=Unknown,0,SK=0.0
+        UN=METRES,SD=,DX=6000.0,DY=6000.0
+    OST/1
+    IFM/3
+    RGB/1,199,231,252
+    RGB/2,174,234,84
+    RGB/3,255,254,206
+    RGB/4,226,65,6
+    DTM/0.0,0.0
+
+ +

+The text header is terminated with a <Control-Z><NUL> sequence (ASCII characters 26 and 0). + +Each line starts with a tag terminated by a '/'. The tags are usually 3 letters. The lines are terminated with the NL character. However, logical lines can continue when next line starts with spaces. + +Tags: +

    +
  • VER - Version number of BSB format e.g. 1, 2.0, 3.0, 3.07, 4.0 +
  • BSB    (or NOS for older GEO/NOS or GEO/NO1 files) +
      +
    • RA=width,height - width and height of raster image data in pixels +
    • NA=Name given to the BSB chart (can represent more than one .KAP) +
    • NU=Number of chart (especially when more than one chart is grouped or tiled together) +
    • DU=Drawing Units in pixels/inch (same as DPI resolution) e.g. 50, 150, 175, 254, 300 +
    +
  • OST - Offset STrip image lines (number of image rows per entry in the index table) e.g. 1 +
  • IFM - Depth of the colormap (bits per pixel). BSB supports 1 through 7 (2 through 127 max colors). +
  • RGB - Color definitions for the raster colormap of the form index,red,green,blue (index starts at 0, index 0 is not used in BSB). Note, there are more than one coloring schemes for different lighting conditions: DAY, DSK (dusk), NGT (night), GRY (gray), PRC (?), PRG (?). +
  • KNP +
      +
    • SC=Scale e.g. 25000 +
    • GD=Geodetic Datum e.g. NAD83, WGS84 +
    • PR=Projection e.g. LAMBERT CONFORMAL CONIC, MERCATOR +
    • PP=Projection Parameter (value depends upon Projection) e.g. 135.0 +
    • PI=? e.g. 0.0, 0.033333, 0.083333, 2.0 +
    • SP=? +
    • SK=Skew angle? e.g. 0.0 +
    • TA=? e.g. 90 +
    • UN=Units (for DX, DY and others) e.g. METRES, FATHOMS +
    • SD=Sounding Datum e.g. MEAN LOWER LOW WATER, HHWLT +
    • DX=distance (approx.) covered by one pixel in X direction +
    • DY=distance (approx.) covered by one pixel in Y direction +
    +
  • KNQ +
      +
    • P1=...,P2=... +
    • P3=...,P4=... +
    • P5=...,P6=... +
    +
  • CED - ? (appears to be optional for many applications) +
  • REF - Registration reference points (at least 3 points). The form is index, x raster coord, y raster coord, latitude, longitude +
  • PLY - Chart area (border) definition. List of points in clockwise order. Form is index, lattitude, longitude. +
  • WPX,WPY World-to-Pixel X/Y geotransformation to convert World coordinates (lat/lon) to accordingly X or Y of the raster. See explanation of geotransform below. +
  • PWX,PWY Pixel-to-World X/Y geotransformation to convert chart pixel coordinates coordinates (X/Y) to accordingly longitude or latitude of the raster. See explanation of geotransform below. +
  • ERR Exact meaning unknown - always thesame number of entries as REF points and always with 4 numbers. Possibly an error data for geotransformation of REF points. +
  • DTM - ? (appears to be optional for many applications) +
+ +

Geotransformation

+The WPX,WPY,PWX,PWY tags define coeffitients of a polynomial used to convert x,y of chart to latitude/longitude and vice versa. The tags specify order of the polynomial (first number) and then list corresponding coefitients. The polynomial has a general form of : + +
+    coeff[0] + coeff[1]*lon + coeff[2]*lat +
+    coeff[3]*lon*lon +
+    coeff[4]*lon*lat +
+    coeff[5]*lat*lat +
+    coeff[6]*lon*lon*lon +
+    coeff[7]*lon*lon*lat +
+    coeff[8]*lon*lat*lat +
+    coeff[9]*lat*lat*lat +
+    coeff[10]*lat*lat*lat*lat +
+    coeff[11]*lat*lat*lat*lat*lat
+
+where: +
    +
  • coeff is the list of coeffitiens as read from appropriate tag (not specified coordinates are zero) +
  • lon/lat are input coordinates (can be really lon/lat or x/y of raster) +
  • returns transformed coordinate according to supplied coeffs +
+Note: the same polynomial, just with different coeffitients (as read from tags) is used for all transformations. See bsb_LLtoXY/bsb_XYtoLL functions for use example. + +

Binary Section

+

+The first byte after the <Control-Z><NUL> sequence is a single byte storing the depth of the image, duplicating the information from the IFM token. +

+Next are one or more rows of run-length encoded raster data terminated by <NUL> characters. Each row, when decompressed, represents one horizontal line of the image. +

+Rows start with one or more bytes representing the row number. The storage of the row number finishes when the byte is less than 128. Row numbering starts at 1 rather than 0. +

+The next byte will indicate the color of a pixel using a colormap index. The nature of the bitstream packing limits the color depth to 7 bits. Therefore bytes of value greater than 127 as used to indicate that the next byte stores the 'run' length in addition to storing the colormap index. + + +

Authors/Contributors

+

+The libbsb library and this web page was written by Stuart Cunningham with GIS related advice from Anuradha Suraparaju. Additional improvements made by Michal Krombholz. The big thanks go to Tom Gray for researching polynomial form of geotransfomration. Feedback is welcome. +

+Copyright (©) 2000-2007 Stuart Cunningham. + +

+SourceForge.net Logo +Valid HTML 4.01! +Valid CSS! + + diff -Nru libbsb-0.0.7/doc/contact.html libbsb-0.0.8.1/doc/contact.html --- libbsb-0.0.7/doc/contact.html 1970-01-01 00:00:00.000000000 +0000 +++ libbsb-0.0.8.1/doc/contact.html 2016-03-19 21:41:15.000000000 +0000 @@ -0,0 +1,36 @@ + + + + + + + Contact libbsb developers + + + + + + + + +
+

+The preferred way to contact the developers of libbsb is via the SourceForge forums. If you believe you have found a bug in libbsb please submit a bug report. +

+If you would like to contribute to libbsb, use the Developers forum. If your contribution includes a patch, submit your patch to the patch tracker. Patches in "diff -Naru" format against the current CVS state are preferred. +

+The libbsb library and documentation were written by Stuart Cunningham with help from Anuradha Suraparaju. Feedback is welcome. +

+ + +

+ SourceForge.net Logo + Valid HTML 4.01! + + + diff -Nru libbsb-0.0.7/doc/examples.html libbsb-0.0.8.1/doc/examples.html --- libbsb-0.0.7/doc/examples.html 1970-01-01 00:00:00.000000000 +0000 +++ libbsb-0.0.8.1/doc/examples.html 2016-03-19 21:41:15.000000000 +0000 @@ -0,0 +1,63 @@ + + + + + + + Example files and usage + + + + +

Example usage of conversion utilities

+The following conversion utilities are available with libbsb. For Win32 the programs are available after unzipping the file package, for all other platforms the programs are built from source (see README for building instructions). + +
convert from BSBconvert to BSB +
TIFFbsb2tiftif2bsb +
PPMbsb2ppmppm2bsb +
PNGbsb2png(not implemented) +
+ +

TIFF conversion

+

+To convert a BSB chart file to a TIFF image file: +

bsb2tif australia4c.kap australia4c.tif
+

+To convert a TIFF image to a BSB chart you need a template file containing all the cartographic information for the image. The template file is merely the ASCII text lines at the start of a BSB file, and for the conversion to work it must contain the correct image width and height in the BSB/ section (RA=width,height). +

+In this example I used the original BSB file as the template: +

tif2bsb australia4c.kap edited.tif new.kap
+

+Conversion to and from GeoTIFF files is planned but currently not implemented. + +

PPM conversion

+

+Usage of bsb2ppm and ppm2bsb is similar to the TIFF utilities. +

bsb2ppm australia4c.kap australia4c.ppm
+
ppm2bsb australia4c.kap edited.ppm new.kap
+ +

PNG conversion

+

+Convert a BSB file to a PNG file: +

bsb2png australia4c.kap australia4c.png
+

+Conversion from PNG back to BSB is currently not implemented. + +

Example BSB files

+ + + +

+ SourceForge.net Logo + Valid HTML 4.01! + + + diff -Nru libbsb-0.0.7/doc/index.html libbsb-0.0.8.1/doc/index.html --- libbsb-0.0.7/doc/index.html 1970-01-01 00:00:00.000000000 +0000 +++ libbsb-0.0.8.1/doc/index.html 2016-03-19 21:41:15.000000000 +0000 @@ -0,0 +1,88 @@ + + + + + + + libbsb - Read, Write and Convert BSB charts + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + +
arrowHome
arrowProject Page
arrowDownload
arrowBSB file format
arrowExamples
arrowContact us
+
+ + + + + +
+

+ libbsb is a portable C library for reading and writing BSB format image files. Typically used for nautical charts, BSB charts use the .KAP or .CAP extension and store cartographic information in addition to a run-length encoded raster image. libbsb is capable of recovering truncated or otherwise corrupted .KAP files. The library is released under the terms of the LGPL. +

+ A number of utilities to convert and work with BSB charts are included in the libbsb package. Sample files and instructions on using these tools are available on the Examples page. +

    +
  • bsb2tif - convert BSB image to TIFF format +
  • bsb2ppm - convert BSB image to PPM format +
  • bsb2png - convert BSB image to PNG format +
  • tif2bsb - convert TIFF image to BSB image +
  • ppm2bsb - convert PPM image to BSB image +
  • bsbfix - fix the index table in a BSB file +
+

+ The source code for the libbsb library and utility programs can be downloaded or browsed online directly from the CVS repository. +

+ The BSB file format stores raster image data in a run-length encoded binary form along with ASCII text describing the projection, datum and other information necessary for GIS applications. Used initially for nautical charts and marine charts by NOAA and the Canadian Hydrographic Service, it is increasingly being used for GIS raster maps in general. +

+ The libbsb library and the BSB file format description were written due to the lack of information and utilities supporting this format. At the time libbsb was first written, November 2000, the only GNU/Linux software library the author could find which could read BSB files was Hugo. However, the code for reading BSB files was distributed as a binary-only module and limited to the i386 platform. +

+ If you have a query or wish to contribute to libbsb please get in touch. +

+
+ + +

+ SourceForge.net Logo + Valid HTML 4.01! + + + diff -Nru libbsb-0.0.7/ImageMagick-5.5.7-bsb.patch libbsb-0.0.8.1/ImageMagick-5.5.7-bsb.patch --- libbsb-0.0.7/ImageMagick-5.5.7-bsb.patch 1970-01-01 00:00:00.000000000 +0000 +++ libbsb-0.0.8.1/ImageMagick-5.5.7-bsb.patch 2016-03-19 21:41:15.000000000 +0000 @@ -0,0 +1,430 @@ +diff -Nru ImageMagick-5.5.7/coders/Makefile.am ImageMagick-5.5.7-new/coders/Makefile.am +--- ImageMagick-5.5.7/coders/Makefile.am 2003-05-12 21:00:59.000000000 +0100 ++++ ImageMagick-5.5.7-new/coders/Makefile.am 2004-01-19 13:23:12.000000000 +0000 +@@ -43,7 +43,7 @@ + endif + + MAGICK_CODER_SRCS = \ +- art.c avi.c avs.c bmp.c caption.c clipboard.c cmyk.c cut.c dcm.c \ ++ art.c avi.c avs.c bmp.c bsb.c caption.c clipboard.c cmyk.c cut.c dcm.c \ + dib.c dps.c dpx.c emf.c ept.c fax.c fits.c fpx.c gif.c gradient.c \ + gray.c histogram.c html.c icon.c jbig.c jp2.c jpeg.c label.c \ + magick.c map.c mat.c matte.c meta.c miff.c mono.c mpc.c mpeg.c \ +@@ -87,7 +87,7 @@ + + # Modules which are to be built + pkg_LTLIBRARIES = \ +- art.la avi.la avs.la bmp.la caption.la cmyk.la cut.la dcm.la dib.la dps.la \ ++ art.la avi.la avs.la bmp.la bsb.la caption.la cmyk.la cut.la dcm.la dib.la dps.la \ + dpx.la ept.la fax.la fits.la fpx.la gif.la gradient.la gray.la \ + histogram.la html.la icon.la jbig.la jp2.la jpeg.la label.la \ + magick.la map.la mat.la matte.la meta.la miff.la mono.la mpc.la mpeg.la \ +@@ -126,6 +126,11 @@ + bmp_la_LDFLAGS = $(MODULECOMMONFLAGS) + bmp_la_LIBADD = $(LIBMAGICK) + ++# BSB module ++bsb_la_SOURCES = bsb.c ++bsb_la_LDFLAGS = $(MODULECOMMONFLAGS) ++bsb_la_LIBADD = $(LIBMAGICK) ++ + # CAPTION module + caption_la_SOURCES = caption.c + caption_la_LDFLAGS = $(MODULECOMMONFLAGS) +diff -Nru ImageMagick-5.5.7/coders/bsb.c ImageMagick-5.5.7-new/coders/bsb.c +--- ImageMagick-5.5.7/coders/bsb.c 1970-01-01 01:00:00.000000000 +0100 ++++ ImageMagick-5.5.7-new/coders/bsb.c 2004-03-09 11:06:04.000000000 +0000 +@@ -0,0 +1,382 @@ ++/* ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++% % ++% % ++% % ++% BBBB SSSSS BBBB % ++% B B SS B B % ++% BBBB SSS BBBB % ++% B B SS B B % ++% BBBB SSSSS BBBB % ++% % ++% % ++% Read/Write ImageMagick Image Format. % ++% % ++% % ++% Software Design % ++% John Cristy % ++% July 1992 % ++% % ++% % ++% Copyright (C) 2000 ImageMagick Studio, a non-profit organization dedicated % ++% to making software imaging solutions freely available. % ++% % ++% Permission is hereby granted, free of charge, to any person obtaining a % ++% copy of this software and associated documentation files ("ImageMagick"), % ++% to deal in ImageMagick without restriction, including without limitation % ++% the rights to use, copy, modify, merge, publish, distribute, sublicense, % ++% and/or sell copies of ImageMagick, and to permit persons to whom the % ++% ImageMagick is furnished to do so, subject to the following conditions: % ++% % ++% The above copyright notice and this permission notice shall be included in % ++% all copies or substantial portions of ImageMagick. % ++% % ++% The software is provided "as is", without warranty of any kind, express or % ++% implied, including but not limited to the warranties of merchantability, % ++% fitness for a particular purpose and noninfringement. In no event shall % ++% ImageMagick Studio be liable for any claim, damages or other liability, % ++% whether in an action of contract, tort or otherwise, arising from, out of % ++% or in connection with ImageMagick or the use or other dealings in % ++% ImageMagick. % ++% % ++% Except as contained in this notice, the name of the ImageMagick Studio % ++% shall not be used in advertising or otherwise to promote the sale, use or % ++% other dealings in ImageMagick without prior written authorization from the % ++% ImageMagick Studio. % ++% % ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++% ++% ++*/ ++ ++/* ++ Include declarations. ++*/ ++#include "magick/studio.h" ++#include "magick/attribute.h" ++#include "magick/blob.h" ++#include "magick/error.h" ++#include "magick/list.h" ++#include "magick/magick.h" ++#include "magick/monitor.h" ++#include "magick/static.h" ++#include "magick/utility.h" ++ ++/* ++ Forward declarations. ++*/ ++static unsigned int ++ WriteBSBImage(const ImageInfo *,Image *); ++ ++/* ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++% % ++% % ++% % ++% R e a d B S B I m a g e % ++% % ++% % ++% % ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++% ++% Method ReadBSBImage reads a BSB image file and returns it. It ++% allocates the memory necessary for the new Image structure and returns a ++% pointer to the new image. ++% ++% ReadBSBImage was contributed by Stuart Cunningham ++% ++% The format of the ReadBSBImage method is: ++% ++% Image *ReadBSBImage(const ImageInfo *image_info,ExceptionInfo *exception) ++% ++% A description of each parameter follows: ++% ++% o image: Method ReadBSBImage returns a pointer to the image after ++% reading. A null image is returned if there is a memory shortage or ++% if the image cannot be read. ++% ++% o image_info: Specifies a pointer to an ImageInfo structure. ++% ++% o exception: return any errors or warnings in this structure. ++% ++% ++*/ ++ ++#include ++#include ++ ++ ++char mul_mask[8] = { 0, 63, 31, 15, 7, 3, 1, 0 }; ++ ++/* Assumes file pointer is at start of run-length encoded bitstream */ ++void read_row(Image *image, int depth, int width, int row) ++{ ++ int c, row_num = 0; ++ int pixel, multiplier, i, written = 0; ++ IndexPacket *indexes; ++ ++ /* The row number is stored in the low 7 bits of each byte. */ ++ /* The 8th bit indicates if row number is continued in the next byte. */ ++ do { ++ c = ReadBlobByte(image); ++ row_num = ((row_num & 0x7f) << 7) + c; ++ } while (c >= 0x80); ++ ++ SetImagePixels(image,0,row,width,1); ++ indexes=GetIndexes(image); ++ ++ /* Rows are terminated by '\0'. Note that rows can contain a '\0' */ ++ /* as part of the run-length data, so '\0' does not delimit rows. */ ++ /* (This occurs when multiplier is a multiple of 128 - 1) */ ++ while ((c = ReadBlobByte(image)) != '\0') ++ { ++ pixel = (c & 0x7f) >> (7 - depth); ++ multiplier = c & mul_mask[(int)depth]; ++ ++ while (c >= 0x80) ++ { ++ c = ReadBlobByte(image); ++ multiplier = (multiplier << 7) + (c & 0x7f); ++ } ++ multiplier++; ++ ++ for (i = 0; i < multiplier; i++) ++ { ++ /* For the lower depths, the "grain" of the multiplyer is */ ++ /* course, so don't write past the width of the buffer. */ ++ if (written < width) ++ indexes[written++] = pixel - 1; /* BSB color idx starts at 1 */ ++ } ++ } ++ ++ if (written < width) ++ { ++ printf("Short row: Row %d written=%d width=%d\n", row, written, width); ++ /* Resyncronise by scanning for next NUL - not perfect since */ ++ /* NUL can be found within the row's data. */ ++ while ((c = ReadBlobByte(image)) != '\0') ++ { ++ if (c == -1) ++ break; ++ } ++ } ++} ++ ++static Image *ReadBSBImage(const ImageInfo *image_info, ++ ExceptionInfo *exception) ++{ ++ Image ++ *image; ++ ++ unsigned int ++ status; ++ ++ char line[4096], *geometry; ++ int i, num_colors, width, height, depth, table_start, first_row, red, green, blue; ++ ++ /* ++ Open image file. ++ */ ++ image=AllocateImage(image_info); ++ status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); ++ if (status == False) ++ ThrowReaderException(FileOpenWarning,"Unable to open file",image); ++ ++ image->depth=8; ++ if (!AllocateImageColormap(image,256)) ++ ThrowReaderException(ResourceLimitWarning,"Memory allocation failed",image); ++ /* ++ Determine width and height ++ */ ++ depth = 0; ++ num_colors = 0; ++ while ( ReadBlobString(image, line) ) ++ { ++ if ( sscanf(line, "RGB/%d,%d,%d,%d", &i, &red, &green, &blue) == 4 ) ++ { ++ image->colormap[i-1].red = ScaleCharToQuantum(red); ++ image->colormap[i-1].green = ScaleCharToQuantum(green); ++ image->colormap[i-1].blue = ScaleCharToQuantum(blue); ++ num_colors++; ++ } ++ if ( (geometry = strstr(line, "RA=")) ) ++ { ++ sscanf(geometry, "RA=%d,%d", &width, &height); ++ } ++ if (line[0] == 0x1a) /* Control-Z */ ++ { ++ depth = line[2]; ++ break; ++ } ++ } ++ ++ image->columns = width; ++ image->rows = height; ++ image->colors = num_colors; ++ ++ /* Seek to start of first row */ ++ SeekBlob(image, -4, SEEK_END); ++ table_start = ReadBlobMSBLong(image); ++ SeekBlob(image, table_start, SEEK_SET); ++ first_row = ReadBlobMSBLong(image); ++ SeekBlob(image, first_row, SEEK_SET); ++ ++ /* ++ Decompress pixels row by row ++ */ ++ for (i = 0; i < height; i++) ++ { ++ read_row(image, depth, width, i); ++ } ++ ++ SyncImage(image); ++ CloseBlob(image); ++ return(image); ++} ++ ++/* ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++% % ++% % ++% % ++% R e g i s t e r B S B I m a g e % ++% % ++% % ++% % ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++% ++% Method RegisterBSBImage adds attributes for the BSB image format to ++% the list of supported formats. The attributes include the image format ++% tag, a method to read and/or write the format, whether the format ++% supports the saving of more than one frame to the same file or blob, ++% whether the format supports native in-memory I/O, and a brief ++% description of the format. ++% ++% The format of the RegisterBSBImage method is: ++% ++% RegisterBSBImage(void) ++% ++*/ ++ModuleExport void RegisterBSBImage(void) ++{ ++ MagickInfo ++ *entry; ++ ++ entry=SetMagickInfo("KAP"); ++ entry->decoder=(DecoderHandler) ReadBSBImage; ++ entry->encoder=(EncoderHandler) WriteBSBImage; ++ entry->description=AcquireString("BSB chart image format - NOAA/Maptech"); ++ entry->module=AcquireString("KAP"); ++ (void) RegisterMagickInfo(entry); ++} ++ ++/* ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++% % ++% % ++% % ++% U n r e g i s t e r B S B I m a g e % ++% % ++% % ++% % ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++% ++% Method UnregisterBSBImage removes format registrations made by the ++% BSB module from the list of supported formats. ++% ++% The format of the UnregisterBSBImage method is: ++% ++% UnregisterBSBImage(void) ++% ++*/ ++ModuleExport void UnregisterBSBImage(void) ++{ ++ UnregisterMagickInfo("KAP"); ++} ++ ++/* ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++% % ++% % ++% % ++% W r i t e B S B I m a g e % ++% % ++% % ++% % ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++% ++% Method WriteBSBImage writes an image to a file in the Wireless Bitmap ++% (level 0) image format. ++% ++% WriteBSBImage was contributed by Milan Votava . ++% ++% The format of the WriteBSBImage method is: ++% ++% unsigned int WriteBSBImage(const ImageInfo *image_info,Image *image) ++% ++% A description of each parameter follows. ++% ++% o status: Method WriteBSBImage return True if the image is written. ++% False is returned is there is a memory shortage or if the image file ++% fails to write. ++% ++% o image_info: Specifies a pointer to an ImageInfo structure. ++% ++% o image: A pointer to a Image structure. ++% ++% ++*/ ++ ++static void BSBWriteInteger(Image *image,const unsigned int value) ++{ ++ int ++ bits, ++ flag, ++ n; ++ ++ register int ++ i; ++ ++ unsigned char ++ buffer[5], ++ octet; ++ ++ n=1; ++ bits=28; ++ flag=False; ++ for(i=4; i >= 0; i--) ++ { ++ octet=((value >> bits) & 0x7f); ++ if (!flag && octet) ++ { ++ flag=True; ++ n=i+1; ++ } ++ buffer[4-i]=octet | (i && (flag || octet))*(0x01 << 7); ++ bits-=7; ++ } ++ (void) WriteBlob(image,n,(char *) buffer+5-n); ++} ++ ++static unsigned int WriteBSBImage(const ImageInfo *image_info,Image *image) ++{ ++ unsigned int ++ status; ++ ++ /* ++ Open output image file. ++ */ ++ status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception); ++ if (status == False) ++ ThrowWriterException(FileOpenWarning,"Unable to open file",image); ++ TransformRGBImage(image,RGBColorspace); ++ /* ++ Convert image to a bi-level image. ++ */ ++ WriteBlobMSBShort(image,0); ++ BSBWriteInteger(image,image->columns); ++ BSBWriteInteger(image,image->rows); ++ ++ CloseBlob(image); ++ return(True); ++} +diff -Nru ImageMagick-5.5.7/magick/static.c ImageMagick-5.5.7-new/magick/static.c +--- ImageMagick-5.5.7/magick/static.c 2003-11-20 17:15:53.000000000 +0000 ++++ ImageMagick-5.5.7-new/magick/static.c 2004-01-19 13:23:12.000000000 +0000 +@@ -126,6 +126,7 @@ + RegisterAVIImage(); + RegisterAVSImage(); + RegisterBMPImage(); ++ RegisterBSBImage(); + RegisterCAPTIONImage(); + RegisterCLIPBOARDImage(); + RegisterCMYKImage(); diff -Nru libbsb-0.0.7/Makefile.am libbsb-0.0.8.1/Makefile.am --- libbsb-0.0.7/Makefile.am 2015-01-16 15:25:19.000000000 +0000 +++ libbsb-0.0.8.1/Makefile.am 2016-03-19 21:41:15.000000000 +0000 @@ -1,4 +1,4 @@ -# $Id: Makefile.am,v 1.17 2004/12/22 13:01:19 stuart_hc Exp $ +# $Id: Makefile.am,v 1.19 2007/02/18 07:35:04 mikrom Exp $ # EXTRA_DIST = australia4c.kap @@ -14,6 +14,7 @@ INCLUDES = -I$(top_builddir) include_HEADERS = bsb.h + bin_PROGRAMS = bsb2ppm ppm2bsb bsbfix if HAVE_LIBTIFF bin_PROGRAMS += bsb2tif tif2bsb @@ -21,6 +22,14 @@ if HAVE_LIBPNG bin_PROGRAMS += bsb2png endif +if HAVE_LIBQT +bin_PROGRAMS += bsbview +bsbview_SOURCES = +bsbview: + cd bsbview_src;qmake -makefile bsbview.pro + cd bsbview_src;make + cp bsbview_src/bsbview . +endif LDADD = libbsb.a @@ -37,3 +46,4 @@ else libbsb_a_AR = ar crv endif + diff -Nru libbsb-0.0.7/msvc/bsb2ppm.dsp libbsb-0.0.8.1/msvc/bsb2ppm.dsp --- libbsb-0.0.7/msvc/bsb2ppm.dsp 1970-01-01 00:00:00.000000000 +0000 +++ libbsb-0.0.8.1/msvc/bsb2ppm.dsp 2016-03-19 21:41:15.000000000 +0000 @@ -0,0 +1,109 @@ +# Microsoft Developer Studio Project File - Name="bsb2ppm" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=bsb2ppm - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "bsb2ppm.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "bsb2ppm.mak" CFG="bsb2ppm - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "bsb2ppm - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "bsb2ppm - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "bsb2ppm - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c +# ADD BASE RSC /l 0x809 /d "NDEBUG" +# ADD RSC /l 0x809 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "bsb2ppm - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I ".." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE RSC /l 0x809 /d "_DEBUG" +# ADD RSC /l 0x809 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "bsb2ppm - Win32 Release" +# Name "bsb2ppm - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\bsb_io.c +# End Source File +# Begin Source File + +SOURCE=..\bsb2ppm.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\bsb.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff -Nru libbsb-0.0.7/msvc/libbsb.dsw libbsb-0.0.8.1/msvc/libbsb.dsw --- libbsb-0.0.7/msvc/libbsb.dsw 1970-01-01 00:00:00.000000000 +0000 +++ libbsb-0.0.8.1/msvc/libbsb.dsw 2016-03-19 21:41:15.000000000 +0000 @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "bsb2ppm"=.\bsb2ppm.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff -Nru libbsb-0.0.7/NEWS libbsb-0.0.8.1/NEWS --- libbsb-0.0.7/NEWS 2015-01-16 15:25:19.000000000 +0000 +++ libbsb-0.0.8.1/NEWS 2016-03-19 21:41:15.000000000 +0000 @@ -1,3 +1,15 @@ +libbsb-0.1.0 +============ + Fully functional chart viewer bsbview with zooming, panning + and georeference capabilitied. Requires QT3 library. + Extended fiunctionality of libbsb: + - added capability to read 'continued lines' (lines that span NLs) + - added reading of more chart data including reference points, + border points, geotransformation polynomial, projection and more + - added geotransformation routines using polynomial coeffitients + - improved raster read performance by pre-reading the index and + added optimized bsb_read_row_at + libbsb-0.0.7 ============ Fix exploitable buffer overflow when reading carefully crafted .KAP file. diff -Nru libbsb-0.0.7/ppm2bsb.c libbsb-0.0.8.1/ppm2bsb.c --- libbsb-0.0.7/ppm2bsb.c 2015-01-16 15:25:19.000000000 +0000 +++ libbsb-0.0.8.1/ppm2bsb.c 2016-03-19 21:41:15.000000000 +0000 @@ -87,9 +87,25 @@ perror(argv[2]); exit(1); } - fscanf(ppm, "P%d\n", &magic); - fscanf(ppm, "%d %d\n", &image.width, &image.height); - fscanf(ppm, "%d\n", &max_sample); + int res = fscanf(ppm, "P%d\n", &magic); + if (res == EOF ) + { + perror(argv[2]); + exit(1); + } + res = fscanf(ppm, "%d %d\n", &image.width, &image.height); + if (res == EOF ) + { + perror(argv[2]); + exit(1); + } + res = fscanf(ppm, "%d\n", &max_sample); + if (res == EOF ) + { + perror(argv[2]); + exit(1); + } + start_of_raster = ftell(ppm); /* Count unique colors in the PPM file */ diff -Nru libbsb-0.0.7/README libbsb-0.0.8.1/README --- libbsb-0.0.7/README 2015-01-16 15:25:19.000000000 +0000 +++ libbsb-0.0.8.1/README 2016-03-19 21:41:15.000000000 +0000 @@ -13,7 +13,8 @@ and the following conversion programs: bsb2ppm ppm2bsb bsbfix bsb2tif tif2bsb - bsb2png + bsb2png + and BSB viewer bsbview For WIN32 native builds you must install MSYS to be able to run the configure script. MSYS can be downloaded gratis from @@ -33,6 +34,10 @@ For bsb2png you must have libpng installed. libpng - http://www.libpng.org/pub/png/libpng.html + For bsbview you must have lib Qt3 development (libqt3-mt). For windows + you can use the free Qt3/win version. The QTDIR environment must be set + to the root of your Qt3 installation. + Usage ----- @@ -76,9 +81,23 @@ vi australia4c.kap Fix the binary index table in the BSB file: bsbfix australia4c.kap - + + bsbview [-t] [-v] [-q] [] + ------- + This is the BSB chart viewer. + Use mouse right click for pop menu. + The About info shows key shortcuts and mouse use. + Parameters: + -t test geotransformation (converts all reference points + from chart to lat/lon and back and displays relative errors) + -v verbose output for -t + -q quit without displaying the graphics (only with -t) + the file to show (when skipped it will ask you to choose one) + With popup menu you may choose another .KAP file. + Author ------ Send feedback to Stuart Cunningham +For 0.0.8 changes and bsbview send feedback to Michal Krombholz diff -Nru libbsb-0.0.7/TODO libbsb-0.0.8.1/TODO --- libbsb-0.0.7/TODO 1970-01-01 00:00:00.000000000 +0000 +++ libbsb-0.0.8.1/TODO 2016-03-19 21:41:15.000000000 +0000 @@ -0,0 +1,13 @@ +bsbview - graphical viewer +-------------------------- +- add ability to zoom in further than one-to-one pixel by scaling pixels + +Batch processing +---------------- +- add command line options to conversion tools to more easily permit batch + conversions, for example *.KAP or everything in a given directory. This + has been requested by WIN32 users who cannot use a shell to do this. + +GeoTIFF support +--------------- +- add conversion to and from GeoTIFF format which is an open standard