News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

libpng

Started by Biterider, October 10, 2022, 12:22:48 AM

Previous topic - Next topic

Biterider

Hi
Tired of taking a detour with GDI+ to load a PNG, I tried to build a static library (x86/x64) from the original authors of the format http://www.libpng.org/ .
Building the library wasn't that difficult. I used an existing Visual Studio project and changed to project configuration for my purposes.
Creating the include file will still require some work, but one problem I'm facing is that I need to include C runtime stuff, which I don't want.
Has anyone succeeded? Has anyone been able to set up the library?  :rolleyes:

Biterider

fearless

Yeh a lot of libraries make use of C runtime stuff, which is alway a pain to deal with tbh.

Came across this repo a while back that might be useful: https://github.com/Chuyu-Team/VC-LTL5

QuoteVC-LTL is an open source CRT library based on the MS VCRT that reduce program binary size and say goodbye to Microsoft runtime DLLs, such as msvcr120.dll, api-ms-win-crt-time-l1-1-0.dll and other dependencies.

hutch--

I confess I don't see the problem with loading JPG PNG and a few other formats with GDI+. Just bundle it into a reusable library and you are free of external DLLs and libraries.

LiaoMi

Quote from: Biterider on October 10, 2022, 12:22:48 AM
Hi
Tired of taking a detour with GDI+ to load a PNG, I tried to build a static library (x86/x64) from the original authors of the format http://www.libpng.org/ .
Building the library wasn't that difficult. I used an existing Visual Studio project and changed to project configuration for my purposes.
Creating the include file will still require some work, but one problem I'm facing is that I need to include C runtime stuff, which I don't want.
Has anyone succeeded? Has anyone been able to set up the library?  :rolleyes:

Biterider

Hi Biterider,

my results:

Severity Code Description Project File Line Suppression State
Error LNK2001 unresolved external symbol _printf pngtest U:\LIBPNG\libpng-libpng16\projects\vstudio\pngtest\pngtest.obj 1
Error LNK2001 unresolved external symbol _png_image_begin_read_from_file pngtest U:\LIBPNG\libpng-libpng16\projects\vstudio\pngtest\pngtest.obj 1
Error LNK2001 unresolved external symbol _malloc pngtest U:\LIBPNG\libpng-libpng16\projects\vstudio\pngtest\pngtest.obj 1
Error LNK2001 unresolved external symbol _malloc pngtest U:\LIBPNG\libpng-libpng16\projects\vstudio\pngtest\libpng16.lib(pngmem.obj) 1
Error LNK2001 unresolved external symbol _png_image_write_to_file pngtest U:\LIBPNG\libpng-libpng16\projects\vstudio\pngtest\pngtest.obj 1
Error LNK2001 unresolved external symbol _free pngtest U:\LIBPNG\libpng-libpng16\projects\vstudio\pngtest\pngtest.obj 1
Error LNK2001 unresolved external symbol _free pngtest U:\LIBPNG\libpng-libpng16\projects\vstudio\pngtest\libpng16.lib(png.obj) 1
Error LNK2001 unresolved external symbol _free pngtest U:\LIBPNG\libpng-libpng16\projects\vstudio\pngtest\libpng16.lib(pngmem.obj) 1
Error LNK2001 unresolved external symbol _memset pngtest U:\LIBPNG\libpng-libpng16\projects\vstudio\pngtest\libpng16.lib(pngwutil.obj) 1
Error LNK2001 unresolved external symbol _memset pngtest U:\LIBPNG\libpng-libpng16\projects\vstudio\pngtest\libpng16.lib(pngmem.obj) 1
Error LNK2001 unresolved external symbol _memset pngtest U:\LIBPNG\libpng-libpng16\projects\vstudio\pngtest\libpng16.lib(pngset.obj) 1
Error LNK2001 unresolved external symbol _memset pngtest U:\LIBPNG\libpng-libpng16\projects\vstudio\pngtest\libpng16.lib(pngrutil.obj) 1
Error LNK2001 unresolved external symbol _memset pngtest U:\LIBPNG\libpng-libpng16\projects\vstudio\pngtest\libpng16.lib(pngwrite.obj) 1
Error LNK2001 unresolved external symbol _memset pngtest U:\LIBPNG\libpng-libpng16\projects\vstudio\pngtest\pngtest.obj 1
Error LNK2001 unresolved external symbol _memset pngtest U:\LIBPNG\libpng-libpng16\projects\vstudio\pngtest\libpng16.lib(pngread.obj) 1
Error LNK2001 unresolved external symbol _memset pngtest U:\LIBPNG\libpng-libpng16\projects\vstudio\pngtest\libpng16.lib(png.obj) 1
Error LNK2001 unresolved external symbol _memset pngtest U:\LIBPNG\libpng-libpng16\projects\vstudio\pngtest\libpng16.lib(pngrtran.obj) 1
Error LNK2001 unresolved external symbol _memcpy pngtest U:\LIBPNG\libpng-libpng16\projects\vstudio\pngtest\libpng16.lib(pngwrite.obj) 1
Error LNK2001 unresolved external symbol _memcpy pngtest U:\LIBPNG\libpng-libpng16\projects\vstudio\pngtest\libpng16.lib(pngwutil.obj) 1
Error LNK2001 unresolved external symbol _memcpy pngtest U:\LIBPNG\libpng-libpng16\projects\vstudio\pngtest\libpng16.lib(pngread.obj) 1
Error LNK2001 unresolved external symbol _memcpy pngtest U:\LIBPNG\libpng-libpng16\projects\vstudio\pngtest\libpng16.lib(pngmem.obj) 1
Error LNK2001 unresolved external symbol _memcpy pngtest U:\LIBPNG\libpng-libpng16\projects\vstudio\pngtest\libpng16.lib(pngset.obj) 1
Error LNK2001 unresolved external symbol _memcpy pngtest U:\LIBPNG\libpng-libpng16\projects\vstudio\pngtest\libpng16.lib(pngrutil.obj) 1
Error LNK2001 unresolved external symbol _longjmp pngtest U:\LIBPNG\libpng-libpng16\projects\vstudio\pngtest\libpng16.lib(png.obj) 1
Error LNK2001 unresolved external symbol _longjmp pngtest U:\LIBPNG\libpng-libpng16\projects\vstudio\pngtest\libpng16.lib(pngerror.obj) 1
Error LNK2001 unresolved external symbol _frexp pngtest U:\LIBPNG\libpng-libpng16\projects\vstudio\pngtest\libpng16.lib(png.obj) 1
Error LNK2001 unresolved external symbol _modf pngtest U:\LIBPNG\libpng-libpng16\projects\vstudio\pngtest\libpng16.lib(png.obj) 1
Error LNK2001 unresolved external symbol __CIpow pngtest U:\LIBPNG\libpng-libpng16\projects\vstudio\pngtest\libpng16.lib(png.obj) 1
Error LNK2001 unresolved external symbol __setjmp3 pngtest U:\LIBPNG\libpng-libpng16\projects\vstudio\pngtest\libpng16.lib(png.obj) 1
Error LNK2001 unresolved external symbol __setjmp3 pngtest U:\LIBPNG\libpng-libpng16\projects\vstudio\pngtest\libpng16.lib(pngerror.obj) 1
Error LNK2001 unresolved external symbol _floor pngtest U:\LIBPNG\libpng-libpng16\projects\vstudio\pngtest\libpng16.lib(png.obj) 1
Error LNK2001 unresolved external symbol _floor pngtest U:\LIBPNG\libpng-libpng16\projects\vstudio\pngtest\libpng16.lib(pngrtran.obj) 1
Error LNK2001 unresolved external symbol _abort pngtest U:\LIBPNG\libpng-libpng16\projects\vstudio\pngtest\libpng16.lib(pngerror.obj) 1
Error LNK2001 unresolved external symbol _atof pngtest U:\LIBPNG\libpng-libpng16\projects\vstudio\pngtest\libpng16.lib(pngget.obj) 1
Error LNK2001 unresolved external symbol __gmtime64 pngtest U:\LIBPNG\libpng-libpng16\projects\vstudio\pngtest\libpng16.lib(pngwrite.obj) 1
Error LNK1120 16 unresolved externals pngtest U:\LIBPNG\libpng-libpng16\projects\vstudio\Release Library\pngtest.exe 1


together with a external library msvcrt.lib

Severity Code Description Project File Line Suppression State
Error LNK2001 unresolved external symbol _png_image_begin_read_from_file pngtest U:\\LIBPNG\libpng-libpng16\projects\vstudio\pngtest\pngtest.obj 1
Error LNK2001 unresolved external symbol _png_image_write_to_file pngtest U:\\LIBPNG\libpng-libpng16\projects\vstudio\pngtest\pngtest.obj 1
Error LNK1120 2 unresolved externals pngtest U:\\LIBPNG\libpng-libpng16\projects\vstudio\Release Library\pngtest.exe 1


Because of  :tongue:
/* READ APIs
* ---------
*
* The png_image passed to the read APIs must have been initialized by setting
* the png_controlp field 'opaque' to NULL (or, safer, memset the whole thing.)
*/
#ifdef PNG_STDIO_SUPPORTED
PNG_EXPORT(234, int, png_image_begin_read_from_file, (png_imagep image,
   const char *file_name));
   /* The named file is opened for read and the image header is filled in
    * from the PNG header in the file.
    */


Source "Test"
#define _NO_CRT_STDIO_INLINE //First String in Source Code!!!
#define WIN32_LEAN_AND_MEAN
#include <stdio.h>
#include "png.h"
//#include <stdlib.h>
#include <string.h>

//extern C
//{
int _fltused;

//#ifdef _M_IX86 // following functions are needed only for 32-bit architecture

__declspec(naked) void _ftol2()
{
__asm
{
fistp qword ptr[esp - 8]
mov   edx, [esp - 4]
mov   eax, [esp - 8]
ret
}
}

__declspec(naked) void _ftol2_sse()
{
__asm
{
fistp dword ptr[esp - 4]
mov   eax, [esp - 4]
ret
}
}

//#endif
//}

int mainCRTStartup()
{
png_image image;
memset(&image, 0, sizeof(png_image));

image.version = PNG_IMAGE_VERSION;

int result = png_image_begin_read_from_file(&image, "reona_unknown.png");
printf("Read result: %d\r\n", result);

printf("Width: %d, Height: %d\r\n", image.width, image.height);

image.format = PNG_FORMAT_RGBA;

int row_stride = PNG_IMAGE_ROW_STRIDE(image);
int px_size = PNG_IMAGE_PIXEL_COMPONENT_SIZE(PNG_FORMAT_RGBA);

int stride_bytes = row_stride * px_size;
printf("Row stride: %d, pixel size: %d, stride in bytes: %d\r\n", row_stride, px_size, stride_bytes);

int size = PNG_IMAGE_SIZE(image);
printf("Size: %d\r\n", size);

char* buffer = (char*)malloc(size);
memset(buffer, 0, size);

result = png_image_finish_read(&image, NULL, buffer, row_stride, NULL);
printf("Read result: %d\r\n", result);

png_image w_image;
memset(&w_image, 0, sizeof(png_image));

w_image.version = PNG_IMAGE_VERSION;
w_image.width = image.width;
w_image.height = image.height;
w_image.format = image.format;

png_image_write_to_file(&w_image, "reona_w_unknown.png", 0, buffer, row_stride, NULL);

png_image_free(&w_image);
png_image_free(&image);

free(buffer);

return 0;
}

/* Generate a compiler error if there is an old png.h in the search path. */
typedef png_libpng_version_1_6_39_git Your_png_h_is_not_version_1_6_39_git;

LiaoMi

Second example  :biggrin:

#define _NO_CRT_STDIO_INLINE //First String in Source Code!!!
#define WIN32_LEAN_AND_MEAN
#include <stdio.h>
#include "png.h"
//#include <stdlib.h>
#include <string.h>

//extern C
//{
int _fltused;

//#ifdef _M_IX86 // following functions are needed only for 32-bit architecture

__declspec(naked) void _ftol2()
{
__asm
{
fistp qword ptr[esp - 8]
mov   edx, [esp - 4]
mov   eax, [esp - 8]
ret
}
}

__declspec(naked) void _ftol2_sse()
{
__asm
{
fistp dword ptr[esp - 4]
mov   eax, [esp - 4]
ret
}
}

//#endif
//}

/*
* A simple libpng example program
* http://zarb.org/~gc/html/libpng.html
*
* Modified by Yoshimasa Niwa to make it much simpler
* and support all defined color_type.
*
* To build, use the next instruction on OS X.
* $ brew install libpng
* $ clang -lz -lpng16 libpng_test.c
*
* Copyright 2002-2010 Guillaume Cottenceau.
*
* This software may be freely redistributed under the terms
* of the X11 license.
*
*/

//#include <stdlib.h>
//#include <stdio.h>

int width, height;
png_byte color_type;
png_byte bit_depth;
png_bytep *row_pointers = NULL;

void read_png_file(char *filename) {
  FILE *fp = fopen(filename, "rb");

  png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  if(!png) abort();

  png_infop info = png_create_info_struct(png);
  if(!info) abort();

  if(setjmp(png_jmpbuf(png))) abort();

  //Description
  //Initialize the default input / output functions for the PNG file to standard C streams.To replace the default readand write functions, use png_set_read_fn() and png_set_write_fn() respectively.

  png_init_io(png, fp);

  png_read_info(png, info);


  width      = png_get_image_width(png, info);
  height     = png_get_image_height(png, info);
  color_type = png_get_color_type(png, info);
  bit_depth  = png_get_bit_depth(png, info);

  // Read any color_type into 8bit depth, RGBA format.
  // See http://www.libpng.org/pub/png/libpng-manual.txt

  if(bit_depth == 16)
    png_set_strip_16(png);

  if(color_type == PNG_COLOR_TYPE_PALETTE)
    png_set_palette_to_rgb(png);

  // PNG_COLOR_TYPE_GRAY_ALPHA is always 8 or 16bit depth.
  if(color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
    png_set_expand_gray_1_2_4_to_8(png);

  if(png_get_valid(png, info, PNG_INFO_tRNS))
    png_set_tRNS_to_alpha(png);

  // These color_type don't have an alpha channel then fill it with 0xff.
  if(color_type == PNG_COLOR_TYPE_RGB ||
     color_type == PNG_COLOR_TYPE_GRAY ||
     color_type == PNG_COLOR_TYPE_PALETTE)
    png_set_filler(png, 0xFF, PNG_FILLER_AFTER);

  if(color_type == PNG_COLOR_TYPE_GRAY ||
     color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
    png_set_gray_to_rgb(png);

  png_read_update_info(png, info);

  if (row_pointers) abort();

  row_pointers = (png_bytep*)malloc(sizeof(png_bytep) * height);
  for(int y = 0; y < height; y++) {
    row_pointers[y] = (png_byte*)malloc(png_get_rowbytes(png,info));
  }

  png_read_image(png, row_pointers);

  fclose(fp);

  png_destroy_read_struct(&png, &info, NULL);
}

void write_png_file(char *filename) {
  int y;

  FILE *fp = fopen(filename, "wb");
  if(!fp) abort();

  png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  if (!png) abort();

  png_infop info = png_create_info_struct(png);
  if (!info) abort();

  if (setjmp(png_jmpbuf(png))) abort();

  png_init_io(png, fp);

  // Output is 8bit depth, RGBA format.
  png_set_IHDR(
    png,
    info,
    width, height,
    8,
    PNG_COLOR_TYPE_RGBA,
    PNG_INTERLACE_NONE,
    PNG_COMPRESSION_TYPE_DEFAULT,
    PNG_FILTER_TYPE_DEFAULT
  );
  png_write_info(png, info);

  // To remove the alpha channel for PNG_COLOR_TYPE_RGB format,
  // Use png_set_filler().
  //png_set_filler(png, 0, PNG_FILLER_AFTER);

  if (!row_pointers) abort();

  png_write_image(png, row_pointers);
  png_write_end(png, NULL);

  for(int y = 0; y < height; y++) {
    free(row_pointers[y]);
  }
  free(row_pointers);

  fclose(fp);

  png_destroy_write_struct(&png, &info);
}

void process_png_file() {
  for(int y = 0; y < height; y++) {
    png_bytep row = row_pointers[y];
    for(int x = 0; x < width; x++) {
      png_bytep px = &(row[x * 4]);
      // Do something awesome for each pixel here...
      //printf("%4d, %4d = RGBA(%3d, %3d, %3d, %3d)\n", x, y, px[0], px[1], px[2], px[3]);
    }
  }
}

int mainCRTStartup(int argc, char *argv[]) {
  if(argc != 3) abort();

  read_png_file(argv[1]);
  process_png_file();
  write_png_file(argv[2]);

  return 0;
}

/* Generate a compiler error if there is an old png.h in the search path. */
typedef png_libpng_version_1_6_39_git Your_png_h_is_not_version_1_6_39_git;


Here we also get an error related to the removal of the standard library
Severity Code Description Project File Line Suppression State
Error LNK2001 unresolved external symbol _png_init_io pngtest U:\LIBPNG\libpng-libpng16\projects\vstudio\pngtest\pngtest.obj 1
Error LNK1120 1 unresolved externals pngtest U:\LIBPNG\libpng-libpng16\projects\vstudio\Release Library\pngtest.exe 1


The reason is described in the documentation:
#ifdef PNG_STDIO_SUPPORTED
/* Initialize the input/output for the PNG file to the default functions. */
PNG_EXPORT(74, void, png_init_io, (png_structrp png_ptr, png_FILE_p fp));
#endif

Description
Initialize the default input/output functions for the PNG file to standard C streams. To replace the default read and write functions, use png_set_read_fn() and png_set_write_fn() respectively.

Biterider

Hi fearless, LiaoMi
Thank you very much for your information. I'll try it  :thumbsup:

Biterider

LiaoMi

Quote from: Biterider on October 10, 2022, 03:59:05 AM
Hi fearless, LiaoMi
Thank you very much for your information. I'll try it  :thumbsup:

Biterider

You will need to disable all the variables of the standard library (stdio.h), change the configuration of the library itself

#undef PNG_STDIO_SUPPORTED
#ifdef PNG_STDIO_SUPPORTED
   /* Required for the definition of FILE: */
//#  include <stdio.h>
#endif

Enable options in the main files
#define _NO_CRT_STDIO_INLINE
#define WIN32_LEAN_AND_MEAN

Turn on /NODEFAULTLIB
Disable all unnecessary options of the visual studio
Write stubs for some rare features (_ftol2_sse())

After that, you will have a small set of APIs that can be used separately through imports  :thumbsup:

TimoVJL

For x86?
https://learn.microsoft.com/en-us/cpp/build/reference/qifist-suppress-ftol?view=msvc-170
May the source be with you

jj2007

Quote from: hutch-- on October 10, 2022, 02:14:55 AM
I confess I don't see the problem with loading JPG PNG and a few other formats with GDI+. Just bundle it into a reusable library and you are free of external DLLs and libraries.

include \masm32\MasmBasic\Res\MbGui.asm
Event Paint
  GuiImage "\Masm32\examples\exampl04\car\car.jpg", fit
GuiEnd


Exactly, and it displays a png, too. Of course, there is Gdi+ under the hood - what else? :cool:

NoCforMe

MasmBasic: It slices. It dices. It cooks your waffles to a golden brown. It's a dessert topping AND a floor wax!
Assembly language programming should be fun. That's why I do it.

hutch--

Biterider,

All you need to do is knock up a few macros to initialise GDI+ and a couple of library procedures for loading multiple image formats and you can routinely load images via GDI+ with very little hassle. I have them in 64 bit and with my 32 bit PowerBASIC and it is not all that complex to do, it works well and the code is very small.

avcaballero

> Tired of taking a detour with GDI+ to load a PNG

I share this feeling, on some occasion it occurred to me to do the same, but I have never started the project, surely long and tedious.

NoCforMe

Does anyone know of any libraries (3rd party) that can load and save images other than BMP (JPG, GIF, PNG, Webp, etc.)? I'm sure there's something out there. It would be nice not to have to use GDI+, which isn't very ASM-friendly. (It can be done, but it's a pain in the ass.)

(Free would be nice.)
Assembly language programming should be fun. That's why I do it.

TimoVJL

May the source be with you

jj2007

Quote from: Biterider on October 10, 2022, 12:22:48 AMTired of taking a detour with GDI+ to load a PNG

Gdi+ is not a detour, it's part of Windows, and one that works surprisingly well. There is absolutely no need for any 3rd party library.

GuiParas equ "Gdi+ rocks", w500, h500
include \masm32\MasmBasic\Res\MbGui.asm
Event Paint
  GuiImage "\Masm32\examples\exampl04\car\car.jpg"
  GuiImage "http://masm32.com/board/index.php?action=dlattach;attach=13617;type=avatar", 560, 50
  GuiImage "http://masm32.com/board/index.php?action=dlattach;attach=2;type=avatar", 20, 200
  GuiImage "http://masm32.com/board/index.php?action=dlattach;attach=8508;type=avatar", 150, 200
  GuiImage "http://masm32.com/board/index.php?action=dlattach;attach=4013;type=avatar", 300, 200
  GuiImage "http://masm32.com/board/index.php?action=dlattach;attach=10315;type=avatar", 440, 200
Event Timer
  GuiCls ; only the last avatar needs this ;-)
GuiEnd