Silverfrost Forums

Welcome to our forums

IMPORT_BMP@ - equivalents for JPG, GIF, PNG ?

20 Aug 2013 7:34 #12892

I have an application which works just fine with IMPORT_BMP@ and IMPORT_PCX@ to import images bigger than the %gr window, and then scroll (using %vs, %hs) to view the parts that are not displayed. I would really like to do the same with JPG and GIF files, but there don't seem to be equivalent subroutines IMPORT_JPG@ or IMPORT_GIF@.

I know there is IMPORT_IMAGE@ which should import any of these graphic formats, but if I use this the scrolling doesn't work. Are there any example programs that show how I can use this to import images bigger than the window and then scroll to see the undisplayed parts?

I could of course use GET_DIB_BLOCK@ but if I understand correctly this supports only BMP and JPG, not GIF or PCX. I think it also would need major re-writing of the program, which I'd rather not do!

For any of the solutions, it would be very helpful if they also supported PNG format.

The purpose of the application is on-screen digitising - e.g. tracing over features in a photo to record geological boundaries. The photos are usually high resolution, hence the need for scrolling.

20 Aug 2013 8:13 #12893

Quoted from silicondale

I know there is IMPORT_IMAGE@ which should import any of these graphic formats, but if I use this the scrolling doesn't work. Are there any example programs that show how I can use this to import images bigger than the window and then scroll to see the undisplayed parts?

It goes something like this...

  1. Create a off-screen %gr graphics surface using CREATE_GRAPHICS_REGION@()
  2. Select the off-screen graphics surface using SELECT_GRAPHICS_OBJECT@()
  3. Import the image into the off-screen graphics surface using IMPORT_IMAGE@()
  4. Select the original %gr graphics surface back using SELECT_GRAPHICS_OBJECT@()
  5. Draw the portion of the image you want into the %gr graphics surface using COPY_GRAPHICS_REGION@()

Here is an old example project.

20 Aug 2013 8:25 #12894

Jalih - Once again, you're an absolute star!! Will try this and report back, but I'm confident your solution is the way to go, with minimum hassle.

.... tried it, and with a bit of adjustment it now works well! Many thanks.

21 Aug 2013 9:20 #12904

Jalih, as always, has a solution that reflects the epitome of computer science. I thought yesterday that there might be a simpler answer, and wasted a whole evening, as well as learning something.

My solution was to simply reimport the image with different offsets: viz:

      WINAPP
      OPTIONS (INTL, DREAL)
      PROGRAM SCROLL
      COMMON /GRAPHICS/ iXRES, IYRES, iHANDLE, N
      INCLUDE <WINDOWS.INS>
      INTEGER, EXTERNAL :: MOVEPHOTO
      IXRES=300; IYRES = 200;  iHANDLE = 99;  N = -1
      IA=WINIO@('%ca[TRIAL by shifting]&')
      IA=WINIO@('%sc&', MOVEPHOTO)
      IA=WINIO@('%`^gr[BLACK]&', IXRES, IYRES,  
     &           iHANDLE,  MOVEPHOTO)
      IA=WINIO@('%ff%nl%rj%12^bt[Shift NW]', MOVEPHOTO)
      STOP;   END
      INTEGER FUNCTION MOVEPHOTO()
      COMMON /GRAPHICS/ iXRES, IYRES, iHANDLE, N
      INCLUDE <WINDOWS.INS>
      MOVEPHOTO = 1 
      CALL DRAW_FILLED_RECTANGLE@ (0,0,IXRES,IYRES,RGB@(0,0,0))      
      N = MIN(N + 1, 30)
      CALL IMPORT_IMAGE@ ('CAT', -N*10, -N*10)
      RETURN; END
      RESOURCES
      CAT IMAGE '9845A.JPG'

What did I discover? Well, the first thing was that the photo of my cat was either too large, or in an unacceptable JPEG format. Instead of a meaningful error message, I was left with a runtime error bleating about a missing GIF file. The second thing is that if you don't use these IMPORT routines frequently, you forget the niceties of whether they are FUNCTION or SUBROUTINE, and precisely what needs to be in quote marks. I ended up with a much smaller JPEG of an old computer, and movement only up-and-left together (just to show it worked with negative offsets) - and it does, but there are critical 'gotchas', like if you scroll it off the visible area, and if you don't wipe the %gr each time.

I imagine that if the image is a RESOURCE, then this is as quick as Jalih's solution, but if the file needs to be re-read each time, then it will be painfully slow.

Now where is that definition of hubris?

Eddie

21 Aug 2013 9:49 #12905

Hi Eddie - I'm really sorry to have been the cause of so much pain! I guess the original problem was my lack of understanding that IMPORT_BMP@ (and IMPORT_PCX@) work in a basically different way to IMPORT_IMAGE@, which seems to be a much newer and more logical approach. What I'm stuck with currently is a program which works fine with IMPORT_BMP@ for BMP files, and also works fine with IMPORT_IMAGE@ for JPG and GIF, but with different sets of code for scrolling. Both image formats work fine, but not sure if I have the courage to cut the safety wire, simplify my coding, and use IMPORT_IMAGE@ for everything!

I think also that I need to read the manual again because in another part of the system I'm using DIB_BLOCK coding for generating and exporting graphics, with an explicitly declared array holding all the pixels. But I'm not at all sure how this relates to the graphics surface used by IMPORT_IMAGE@

By the way, I'm not using a RESOURCE to define the image file, but the curly bracket filename '' because the file is selected at runtime. I construct the curly bracket character variable from the pathname returned by GET_FILTERED_FILE@. Slowly (re)learning the tricks.

17 Sep 2013 5:30 #13009

Norm's post on a related thread has prompted me to look at this problem of importing files. I have this need so that I can export them in an alternative format, especially my old .pcx files that are no longer supported by Microsoft Word.

There are a number of graphics file formats referenced in Clearwin+ including .jpg, .bmp, .gif, .pcx .emf and .png. ( any others ?)

Unfortunately Import_Image@ does not appear to support all formats and more importantly Get_DIB_Size@ or Get_IM_Info@ does not support getting size information on all formats. Am I wrong with this interpretation of Clearwin+ capability ?

What I am trying to do is to convert .jpg, .bmp, .gif or .pcx files to .png files. My preferred approach is to:

  1. find the size of the files,
  2. create a graphics region or DIB array
  3. import the file
  4. export the file to a .png file

I wanted to check: if there was a problem with large files ( > 2048 pixel dimension ) or if there is a restriction on the dimension, as a multiple/power of 2.

Can anyone help with a 2-dimensional matrix of the preferred clearwin+ routine to use for the above 4 actions for the 6+ graphics file formats ?

My testing today has thrown up a few unexpected errors, which are probably due to my lack of experience with Clearwin+. What does the error 'Curly bracket/integer form is not available in this context' mean ? Presumably it does not like the external file name in the WINAPI routine ?

John

17 Sep 2013 7:30 #13010

The error report seems quite clear. What does the code look like at this point?

18 Sep 2013 12:02 #13018

Paul,

The error is with import_image@ where the file name is ''. I think that there is a bit of variability in what is in the header of .jpg files, downloaded from cameras. My best estimate of the problem is the winapi does not like the format of the .jpg file header.

When I get time, I will try to identify how to import the different file formats. I have found the documentation of how to get the size of different file types a bit brief. It would be good if this could be summarised and include the graphics formats that are now supported.

I was surprised by the size of the resulting file when converting pictures from .jpg to .png. I still find .png format to be the prefered format for exporting charts, which I later import into reports.

John

18 Sep 2013 6:30 #13020

John

'' should work OK but not when the first character 'p' is a digit because, more generally. curly brackets can also be used with integer handles (for BITMAPs etc.).

18 Sep 2013 8:37 #13021

Quoted from JohnCampbell

What I am trying to do is to convert .jpg, .bmp, .gif or .pcx files to .png files. My preferred approach is to:

  1. find the size of the files,
  2. create a graphics region or DIB array
  3. import the file
  4. export the file to a .png file

If you just need to convert graphics file into another graphics file format, then I would use GDI+ Flat API Image functions.

Simple demo project here

MiniBASIC source for the FTN95 callable image2png() function:

##ifndef WIN32
##define WIN32
##endif
 
##ifdef WIN32
##define WIN32_LEAN_AND_MEAN
##endif
 
##include 'winsdk\\windef.mbi'
##include 'winsdk\\winbase.mbi'
##include 'winsdk\\wingdi.mbi'
##include 'winsdk\\winuser.mbi'

##NOCONSOLE 
##MAKEDLL 
##USES 'gdiplus.lib' 

type GdiplusStartupInput 
	int GdiplusVersion 
	int DebugEventCallback 
	int SuppressBackgroundThread 
	int SuppressExternalCodecs 
endtype

typedef GpImage uint


@API GdiplusStartup(uint *token, GdiplusStartupInput *inp, GdiplusStartupOutput *outp),int 
@API GdiplusShutdown(uint token)
@API GdipLoadImageFromFile(wstring filename, GpImage *image),int 
@API GdipSaveImageToFile(GpImage *image, wstring filename, CLSID *clsidEncoder, EncoderParameters *encoderParams),int
@API GdipDisposeImage(uint image)


export image2png
func image2png(string source, string target),int
  int result
	gpImage *image = NULL
	uint *token = NULL
	GdiplusStartupInput gsi(1,NULL,FALSE,FALSE)
	GUID pngClsid
	DEFINE_GUID(pngClsid, 0x557cf406,0x1a04,0x11d3,0x9a,0x73,0x00,0x00,0xf8,0x1e,0xf3,0x2e)

	GdiplusStartup(&token,gsi,NULL)

	result = GdipLoadImageFromFile(a2w(source),&image)
	if result <> 0 
		GdiplusShutdown(token)
		return FALSE 
	endif

	result = GdipSaveImageToFile(image,a2w(target),&pngClsid,NULL)
	GdipDisposeImage(image)
	GdiplusShutdown(token)
	if result <> 0 then return FALSE
	return TRUE
endf
18 Sep 2013 9:13 #13024

Jalih,

Thanks for the solution, but I wanted to do this with clearwin+ fortran calls.

I am trying to understand how to determine the size of a graphics file so that I can manage it in either a “drawing surface” or a “device independent bitmap” ( I think these are handled differently, or can their handles identify the difference ?) Possible file formats .jpg, .bmp, .gif, .pcx .emf and .png I don’t like the routine Import_image@ which works for .jpg, .bmp, .gif or .pcx; as it does not return the image size.

For .bmp, .gif or .pcx, the following routines could help, as they create a DIB block for the imported file, but how do you get the size of the returned DIB block?

Import_BMP@ : reads a .bmp file and creates a DIB handle Import_gif@ : reads a .gif file and creates a DIB handle Import_PCX@ : reads a .pcx file and returns a DIB handle

Does Get_Graphical_Resolution@ work after calling select_Graphics_Object@ for the DIB handle ? Alternatively, Get_DIB_Size@ might return this information, but it is only documented to work with .bmp files.

As for .png files, all I can do is export them. Can they be imported ?

I am probably showing my limited understanding of Clearwin+ but is there a more general solution available in Clearwin+

John

18 Sep 2013 12:12 #13025
  1. import_image@ works for .bmp, .gif, .pcx, .jpg, and .png files.

  2. get_im_info@ works for .bmp, .gif, and .pcx files (it needs extending so that it also works with .jpg and .png files)

  3. get_dib_size@ works for .bmp, .gif, .pcx, and .jpg files.

  4. There is an exported but undocumented function size_image that might give the dimensions of a png image but I have not tested it.

C_EXTERNAL SIZE_IMAGE 'size_image' (VAL, REF, REF)

SUBROUTINE SIZE_IMAGE(HANDLE, WIDTH, HEIGHT) INTEGER HANDLE,WIDTH,HEIGHT

HANDLE is input as the Microsoft handle for the image. WIDTH and HEIGHT are the output values.

Off hand I don't know how to get the input HANDLE. I will make a note that get_im_info@ needs extending.

19 Sep 2013 1:25 #13030

Paul,

Hopefully I can keep this post brief ! I am trying to understand the difference between 3 file import routines and how the resulting memory image can be used.

import_image@ : To paste an image on to a (%gr) drawing surface using an internal resource or an external file. Presumably this copies to the current drawing surface, that was selected via SELECT_GRAPHICS_OBJECT@( HANDLE ). HANDLE is defined by the programmer. get_dib_block@ : To read a BMP or JPEG format file into a character array, PARRAY. PARRAY is created using ALLOCATE and does not have a HANDLE. import_gif@ : Reads in a GIF file and returns a DIB handle to the image. Presumably this routine creates the memory allocation, which can be released via RELEASE_SCREEN_DIB@( HDIB )

Based on an understanding that Get_Point@ and Draw_Point@ are inefficient, I have previously tried to use %gr[USER_SURFACE] to manipulate the graphics area via the returned memory address “ptr”. This works well for the %gr window, but I have had trouble addressing other drawing surfaces selected via SELECT_GRAPHICS_OBJECT@. I am now looking at manipulating the graphics via a DIB array, but am confused by how these can have a returned HANDLE, but no PARRAY.

To overcome this, a possible way forward might be; I need to know the dimension of this returned DIB (essential information) Select this DIB using Select_Graphics_Object@, via it’;s returned HANDLE, (alternatively use DIB_Paint@ (handle) to copy to the current drawing surface which has been created to the correct size. ) Create a PARRAY of the right size, Use Recover_DIB_Block@ to obtain the image in PARRAY, so that I can manipulate the image for it’s full size.

There are essentially 4 different types of device independent bitmaps, which could be the same thing if “PTR”, “HANDLE” and PARRAY could be matched to the same location.

  1. %gr, Create_Graphics_Region@ and import_image@ have a programmer supplied HANDLE value.
  2. %gr[user_surface] has an array address “PTR” which is limited to the screen graphics surface.
  3. Import_gif@ or Get_Screen_DIB@ have returned handles and returned memory.
  4. Recover_DIB_Block@ and Display_DIB_Block@ transfer DIB between PARRAY and the current graphics device (is this the current drawing surface ?)

My expectation is that the current drawing surface is based on the image size and NOT the %gr window size. This can be created via Create_Graphics_Region@, if the handle or PARRAY can not be selected. I have successfully used drawing surfaces that are larger than %gr graphics device.

My main question is : Are there really 4 different image types in memory or are some interchangeable?

We need an up to date document which describes how to manage transferring information between these different ways of addressing images in memory and some indication of their efficiency.

John

19 Sep 2013 6:48 #13033

John

Thanks for the questions but frankly it would take me at least a working day to begin to find the answers. If you can find a way to reduce the task then I may be able to cope.

Paul

19 Sep 2013 7:51 #13035

Paul,

I think I am identifying a need for some documentation of how to shift between different in-memory graphics models and also more general import/export support for standard formats.

The standard formats are possibly .bmp .pcx .jpg .gif and .png, although Steve may include .emf ( which is quite different). These need to be supported in a more documented way.

For file import/export we need either Export_JPG@ and Export_PNG@ or make Export_Image@ and Import_Image@ documented for all 5 formats. (.jpg formats appear more difficult to use as there appears to be variability in their header structure. A warning of this might help)

We need to be able to interogate files or DIB handles for their size, as I can't see an easy way of getting this information. Get_DIB_Size@ or Get_IM_Size@ could be adapted for this ? ( Am I missing something, but I can't see how to get the size of a DIB Handle ? )

It would be good to have documentation or examples of moving between Create_Graphics_Region@, DIB_Handle or DIB_PARRAY formats.

Even identifying the difference between a programmer supplied handle and a returned handle would clarify a lot of problems I keep coming back to.

There must be a history for PARRAY and DIB_handle, as applying PARRAY to a DIB handle would be non-standard Fortran. Just having a guide on these and how to move between them woudl help.

If we could share a document, then perhaps a number of us could contribute to this document. I'd be pleased to help if we can find a way and a few of us have already commented on this post and have different experiences to share. Jalih, Steve, Eddie, Wilfred, Dan, Ian, Norm and others have all contributed to this recently and could help with their experience. Over the years, I keep coming back to these issues and forget what I learnt the previous time.

The results could be included in the FTN95 documentation under: Drawing device independent bitmaps Off-screen graphics Using image resources Graphics functions (Device independent bitmaps) All these could be enhanced to clarify the issues identified.

John

19 Sep 2013 1:05 #13038

John - Not sure if I'm the Steve you're referring to, but I have no need for .emf - what I need to use mainly is jpg, png, and gif. I also use svg - but this is a simple ASCII format dealt with by standard Fortran read/write and quite separate from all the others.

What you say about returning to this from time to time and forgetting the solutions you found before. I have been doing just the same! I agree there's a need for a consistent set of programmer documentation that deals with all the graphics together, and would be happy to do what I can to help with this.

  • Steve
20 Sep 2013 7:09 #13047

My mistake Steve, someone was using .emf formats.

Also, someone did produce a user guide for clearwin+ about a year ago, although I never did locate a copy. Perhaps we should review this and see how we go.

John

4 Apr 2014 2:21 #13924

It's downloadable from the documentation section http://www.silverfrost.com/23/ftn95/support/documentation.aspx

Some time ago it became obvious that Silverfrost didn't have access to all the documentation from Salford when they took over the compiler, and some of the manuals actually came from the user community. In particular, the early documentation for Clearwin+ (although you should read the ENH file installed in your system when you installed the compiler for later updates) and also the subroutine libraries for FTN77 still work, and are documented in the same place.

Eddie

5 Apr 2014 7:45 #13925

No, I meant http://www.silverfrost.com/manuals/clearwin.pdf

I had a go some time ago at writing a tutorial book, but long before I got finished I was distracted onto something else. Anyway, you already passed its level.

Eddie

21 Jun 2017 8:16 #19791

I'm returning to this for another requirement now. I need to READ image files (JPG, BMP and other formats) and extract RGB data pixel by pixel.

The best I can get is by using get_dib_block@ with BMP files. I can also use the same get_dib_block@ with JPG files - and in both cases I get the individual pixel R G B values out of PARRAY without a problem.

HOWEVER, this works only for small images (test image I have is 50 x 50 pixels) and a fixed array size. If I want images of unknown size - with size NX,NY determined by get_dib_size@ and then used to determine an allocatable array size PARRAY (3,NX,NY) it blows up- 'Reference through NULL Fortran POINTER'. I have checked and re-checked the code and can find nothing illegal. (22/6/17 - found workaround - see below - by not using /CHECK)

I wanted also to import other formats, PNG in particular. I have tried other routes to get the pixel-by-pixel data but none have worked. came to a dead end with import_image@ and import_bmp@ - it seems that the get_dib_block@ route is the only one that lets me get the data into an array, from which I cn extract individual pixels.

Any suggestions ?

Would be good to see a single general solution which handles multiple image formats and stores data in an array that is mapped to a drawing surface. What is currently available seems very inconsistent and chaotic!

Although I found a workaround by removing the /CHECK, is there something wrong with my dynamic allocation?

  character(len=1),allocatable:: parray(:,:,:) 

... call get_dib_size@ (filename,nx,ny,nbbp,ierr) ... allocate (parray(3,nx,ny),stat=istat) ... if (allocated(parray)) deallocate (parray)

If I test istat after the allocate command, I get istat= 1 when I am expecting it to be zero - the Fortran user guide has a list of iostat values: 1 is 'floating point arithmetic overflow' which is clearly not the problem here! Can't find a list of error codes for array allocation but presumably for some reason it's failing to set up the dynamic array, so maybe nothing to do with the image import.


Update 22/6/17. I noticed in ftn95.enh some mentions of problems with ALLOCATE when using /CHECK. So I removed the /CHECK and it works. But I thought those problems were supposed to have been fixed. I am using FTN95 v8.0

Please login to reply.