%% options copyright owner = Dirk Krause copyright year = 2018-xxxx SPDX-License-Identifier: BSD-3-Clause %% header /** @file dk4bifap.h Bitmap image file handling with application support. */ #ifndef DK4CONF_H_INCLUDED #if DK4_BUILDING_DKTOOLS4 #include "dk4conf.h" #else #include #endif #endif #ifndef DK4APP_H_INCLUDED #if DK4_BUILDING_DKTOOLS4 #include "dk4app.h" #else #include #endif #endif #ifndef DK4BIF_H_INCLUDED #if DK4_BUILDING_DKTOOLS4 #include "dk4bif.h" #else #include #endif #endif #ifdef __cplusplus extern "C" { #endif /** Open bitmap image file by name. @param fn Input file name. @param honly Flag: Read image header only. @param pcsctx Color space conversion context, may be NULL. @param app Application structure for diagnostics, may be NULL. @return Valid pointer to bitmap image file on success, NULL on error. */ dk4_bif_t * dk4bif_open_app( dkChar const *fn, int honly, dk4_cs_conv_ctx_t const *pcsctx, dk4_app_t *app ); /** Open bitmap image file by opened FILE. @param fipo File, opened for binary reading. @param fn File name containing the bitmap image. Provide a dummy file name here when processing stdin. @param ty Image file type (PNG, JPEG or TIFF). @param honly Flag: Read image header only. @param pcsctx Color space conversion context, may be NULL. @param app Application structure for diagnostics, may be NULL. @return Valid pointer to bitmap image file on success, NULL on error. */ dk4_bif_t * dk4bif_open_file_app( FILE *fipo, dkChar const *fn, int ty, int honly, dk4_cs_conv_ctx_t const *pcsctx, dk4_app_t *app ); /** Find bitmap image file type for file name based on suffix. @param fn File name to find type for. @param app Application structure for diagnostics, may be NULL. */ int dk4bif_type_for_suffix_app( dkChar const *fn, dk4_app_t *app ); /** Issue warning about aspect ratio change. @param bif Bitmap image file containing data about old resolution. @param xres New x resolution. @param yres New y resolution. @param app Application structure for diagnostics, may be NULL. */ void dk4bif_warn_aspect_ratio_change( dk4_bif_t *bif, double xres, double yres, dk4_app_t *app ); /** Set image resolution. @param bif Bitmap image file. @param xres New x resolution. @param yres New y resolution. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ int dk4bif_set_res_app( dk4_bif_t *bif, double xres, double yres, dk4_app_t *app ); #ifdef __cplusplus } #endif /* vim: set ai sw=4 ts=4 : */ %% module #include "dk4conf.h" #if DK4_HAVE_MATH_H #ifndef MATH_H_INCLUDED #if DK4_ON_WINDOWS #ifndef _USE_MATH_DEFINES #define _USE_MATH_DEFINES 1 #endif #endif #include #define MATH_H_INCLUDED 1 #endif #endif #ifndef DK4MEM_H_INCLUDED #include "dk4mem.h" #endif #ifndef DK4BIFAP_H_INCLUDED #include "dk4bifap.h" #endif #ifndef BIF_H_INCLUDED #include "bif.h" #endif #ifndef DK4MAODD_H_INCLUDED #include "dk4maodd.h" #endif #ifndef DK4MAODDBL_H_INCLUDED #include "dk4maoddbl.h" #endif #ifndef DK4MATH_H_INCLUDED #include "dk4math.h" #endif #if DK4_HAVE_ASSERT_H #ifndef ASSERT_H_INCLUDED #include #define ASSERT_H_INCLUDED 1 #endif #endif $!trace-include /** File name dummy to use when processing standard input. */ static const dkChar dk4bifap_def_fn[] = { dkT("") }; /** File name of string table for localizted texts. */ static const dkChar dk4bifap_str[] = { dkT("dk4bif.str") }; /** Default texts for diagnostic messages if localized texts are not found. */ static const dkChar * const dk4bifap_kw[] = { $!string-table macro=dkT # # 0 File suffix doest not indicate a known image type # File suffix does not inidicate a known image type! # # 1 Failed to open image # Failed to open image! # # 2 Syntax error, file probably damaged! # Syntax error, file probably damaged! # # 3 Failed to open file for reading! # Failed to open and/or read file! # # 4 File type not supported! # File type not supported! # # 5 Invalid arguments provided to function call, probably bug! # Invalid arguments provided to function call, probably bug! # # 6-7 Unusual maxval ... may result in color distorsion! # Unusual maxval !\n\tMay result in color distorsion! # # 8-12 # Aspect ratio changed!\n\tChanging resolution from / to / dpi.\n\tThis will probably result in an image distorsion. # # # $!end }; /** Report error using one text fragment. @param app Application structure. @param si Index of text fragment in dk4bifap_kw or list of localized texts. */ static void dk4bifap_error_1( dk4_app_t *app, size_t si ) { const dkChar * const *msg = dk4bifap_kw; /* Localized texs */ size_t sz_msg; /* Size of msg array */ sz_msg = dk4app_string_table_size(dk4bifap_kw); msg = dk4app_string_table(app, dk4bifap_str, dk4bifap_kw); dk4app_log_1(app, msg, sz_msg, DK4_LL_ERROR, si); } /** Report errors from attempt to open a bitmap image file. @param fn File name to read. @param erp Error report containing error information. @param app Application structure for diagnostics, may be NULL. */ static void dk4bif_error_open_app( dkChar const *fn, dk4_er_t *erp, dk4_app_t *app ) { dkChar const *oldsourcefile; /* Previous source file name to save */ dk4_um_t oldsourceline; /* Previous source line no to save */ oldsourcefile = dk4app_get_log_source_file(app); oldsourceline = dk4app_get_log_source_line(app); if (NULL == fn) { fn = dk4bifap_def_fn; } dk4app_set_log_source_file(app, fn); dk4app_set_log_source_line(app, 0UL); dk4bifap_error_1(app, 1); switch (erp->ec) { case DK4_E_MEMORY_ALLOCATION_FAILED : { dk4app_log_base1(app, DK4_LL_ERROR, 90); } break; case DK4_E_SYNTAX : { dk4bifap_error_1(app, 2); } break; case DK4_E_MATH_OVERFLOW : { dk4app_log_base1(app, DK4_LL_ERROR, 82); } break; case DK4_E_NOT_FOUND : { dk4bifap_error_1(app, 0); } break; case DK4_E_READ_FAILED : { dk4bifap_error_1(app, 3); } break; case DK4_E_NOT_SUPPORTED : { dk4bifap_error_1(app, 4); } break; case DK4_E_INVALID_ARGUMENTS : { dk4bifap_error_1(app, 5); } break; } dk4app_set_log_source_file(app, oldsourcefile); dk4app_set_log_source_line(app, oldsourceline); } /** Check whether the bitmap image file is NetPBM type and has an unusual maxval, report unusual maxval. @param bif Bitmap image file to check. @param app Application structure for diagnostics, may be NULL. */ static void dk4bifap_check_netpbm_maxval( dk4_bif_t *bif, dk4_app_t *app ) { dkChar buf[16*sizeof(dk4_um_t)]; /* Buffer */ dkChar const * const *msg = dk4bifap_kw; /* Localized */ dkChar const *oldsourcefile; /* Previous src file */ dk4_bif_netpbm_per_frame_t *npfd; /* Per-frame data */ dk4_bif_frame_t *frptr; /* Current frame */ dkChar const *fn = NULL; /* File name */ dk4_um_t oldsourceline; /* Previous src line */ size_t sz_msg; /* Size of msg array */ int res; /* Operation result */ dk4_px_t bdspec; /* Maximum value for bpc */ dk4_px_t bdmaxv; /* Maxval */ $? "+ dk4bifap_check_netpbm_maxval" #if DK4_USE_ASSERT assert(NULL != bif); assert(NULL != app); #endif if ((NULL != bif) && (NULL != app)) { switch (bif->imgtype) { case DK4_BIF_TYPE_NETPBM : { dk4sto_it_reset(bif->i_frames); do { frptr = (dk4_bif_frame_t *)dk4sto_it_next(bif->i_frames); if (NULL != frptr) { npfd = (dk4_bif_netpbm_per_frame_t *)(frptr->tsdata); bdspec = dk4pxbit_get_max(npfd->bpc); bdmaxv = npfd->maxval; if (bdspec != bdmaxv) { fn = bif->filename; res = dk4ma_write_decimal_unsigned( buf, DK4_SIZEOF(buf,dkChar), bdmaxv, 0, NULL ); if (0 != res) { oldsourcefile = dk4app_get_log_source_file(app); oldsourceline = dk4app_get_log_source_line(app); dk4app_set_log_source_file(app, fn); dk4app_set_log_source_line(app, (dk4_um_t)0UL); sz_msg = dk4app_string_table_size(dk4bifap_kw); msg = dk4app_string_table( app, dk4bifap_str, dk4bifap_kw ); dk4app_log_3( app, msg, sz_msg, DK4_LL_WARNING, 6, 7, buf ); dk4app_set_log_source_file(app, oldsourcefile); dk4app_set_log_source_line(app, oldsourceline); } } } } while (NULL != frptr); dk4sto_it_reset(bif->i_frames); } break; } } $? "- dk4bifap_check_netpbm_maxval" } dk4_bif_t * dk4bif_open_app( dkChar const *fn, int honly, dk4_cs_conv_ctx_t const *pcsctx, dk4_app_t *app ) { dk4_er_t er; /* Error report */ dk4_bif_t *back = NULL; /* Function result */ $? "+ dk4bif_open_app \"%!ds\"", TR_STR(fn) #if DK4_USE_ASSERT assert(NULL != fn); #endif dk4error_init(&er); back = dk4bif_open(fn, honly, pcsctx, &er); if ((NULL == back) && (NULL != app)) { $? "! failed to open bif" dk4bif_error_open_app(fn, &er, app); } if (NULL != back) { $? ". going to check maxval" dk4bifap_check_netpbm_maxval(back, app); } $? "- dk4bif_open_app %d", TR_IPTR(back) return back; } dk4_bif_t * dk4bif_open_file_app( FILE *fipo, dkChar const *fn, int ty, int honly, dk4_cs_conv_ctx_t const *pcsctx, dk4_app_t *app ) { dk4_er_t er; dk4_bif_t *back = NULL; $? "+ dk4bif_open_file_app %d", TR_IPTR(fipo) #if DK4_USE_ASSERT assert(NULL != fipo); #endif dk4error_init(&er); back = dk4bif_open_file(fipo, fn, ty, honly, pcsctx, &er); if ((NULL == back) && (NULL != app)) { $? "! failed to open bif" dk4bif_error_open_app(fn, &er, app); } if (NULL != back) { $? ". going to check maxval" dk4bifap_check_netpbm_maxval(back, app); } $? "- dk4bif_open_file_app %d", TR_IPTR(back) return back; } int dk4bif_type_for_suffix_app( dkChar const *fn, dk4_app_t *app ) { const dkChar *oldsourcefile = NULL; /* Previous source file name */ dk4_um_t oldsourceline = 0UL; /* Previous source line no */ int back = -1; $? "+ dk4bif_type_for_suffix_app" #if DK4_USE_ASSERT assert(NULL != fn); #endif if (NULL != fn) { back = dk4bif_type_for_suffix(fn); if ((0 > back) && (NULL != app)) { oldsourcefile = dk4app_get_log_source_file(app); oldsourceline = dk4app_get_log_source_line(app); dk4app_set_log_source_file(app, fn); dk4app_set_log_source_line(app, 0UL); /* ##### ERROR: Not a known bitmap image file type */ dk4app_set_log_source_file(app, oldsourcefile); dk4app_set_log_source_line(app, oldsourceline); } } $? "- dk4bif_type_for_suffix_app %d", back return back; } void dk4bif_warn_aspect_ratio_change( dk4_bif_t *bif, double xres, double yres, dk4_app_t *app ) { dkChar b1[64]; dkChar b2[64]; dkChar b3[64]; dkChar b4[64]; const dkChar *p[16]; const dkChar * const *msg = dk4bifap_kw; $? "+ dk4bif_warn_aspect_ratio_change" #if DK4_USE_ASSERT assert(NULL != bif); #endif dk4ma_write_double(b1, 64, bif->cf->res_x, 0, 1, NULL); dk4ma_write_double(b2, 64, bif->cf->res_y, 0, 1, NULL); dk4ma_write_double(b3, 64, xres, 0, 1, NULL); dk4ma_write_double(b4, 64, yres, 0, 1, NULL); /* WARNING: Resolution setting changes aspect ratio */ msg = dk4app_string_table(app, dk4bifap_str, dk4bifap_kw); p[0] = msg[8]; p[1] = b1; p[2] = msg[9]; p[3] = b2; p[4] = msg[10]; p[5] = b3; p[6] = msg[11]; p[7] = b4; p[8] = msg[12]; dk4app_log_msg(app, DK4_LL_WARNING, p, 9); $? "- dk4bif_warn_aspect_ratio_change" } int dk4bif_set_res_app( dk4_bif_t *bif, double xres, double yres, dk4_app_t *app ) { double qo; /* Quotient of old resolutions */ double qn; /* Quotient of new resolutions */ int back = 0; $? "+ dk4bif_set_res_app %lg %lg", xres, yres #if DK4_USE_ASSERT assert(NULL != bif); assert(0.0 < xres); assert(0.0 < yres); #endif if ((NULL != bif) && (0.0 < xres) && (0.0 < yres)) { $? ". args ok" if (NULL != bif->cf) { $? ". have bif" if ((0.0 < bif->cf->res_x) && (0.0 < bif->cf->res_y)) { $? ". res old=%lg/%lg", bif->cf->res_x, bif->cf->res_y qo = bif->cf->res_y / bif->cf->res_x; qn = yres / xres; if ((0 != dk4ma_is_finite(qo)) && (0 != dk4ma_is_finite(qn))) { if (DK4_BIF_EPSILON_ASPECT <= fabs(qn - qo)) { $? ". diff" dk4bif_warn_aspect_ratio_change( bif, xres, yres, app ); } } } bif->cf->res_x = xres; bif->cf->res_y = yres; back = 1; } } else { /* ERROR: Invalid arguments */ } $? "- dk4bif_set_res_app %d", back return back; } /* vim: set ai sw=4 ts=4 : */