This may have been asked and answered already; my apologies if I missed it, but I can't seem to find what I'm looking for here.
I'd like to get a library for JPEG images, preferably free of course. Nothing fancy; I really only need to be able to read and save images.
I tried to download Intel's library, but can't use it (I'm still running XP and it seems to be made for a later OS version).
Any help appreciated!
Hello,
Image display functions (http://masm32.com/board/index.php?topic=6852.0)
Screenshot with small size (http://masm32.com/board/index.php?topic=4828.0)
What exactly do you want to achieve? Here is a snippet that rotates all files dragged over the exe, using Gdi+ GdipImageRotateFlip:
include \masm32\MasmBasic\Res\MbGui.asm ; download (http://masm32.com/board/index.php?topic=94.0)
SetGlobals imgCt
GetFiles CL ; translate commandline to an array of files
mov imgCt, eax ; drag some files over the exe
Event Paint
GuiImageCallback ImgSave
dec imgCt
.if Sign?
MsgBox 0, Str$("%i files converted", Files$(?)), "Hi", MB_OK
Exit
.else
GuiImage Files$(imgCt), fit ; paint the image, fit to window
.endif
EndOfEvents
ImgSave: ; user-defined callback function
gdi+ GdipImageRotateFlip, giImage, 1 ; giImage stands for GuiImageCallBackObject
SaveImageToFile Cat$(Left$(Files$(imgCt), Rinstr(Files$(imgCt), ".jpg", 1)-1)+"_rotated.jpg")
GuiCls ; trigger one Paint event for each file
ret
GuiEnd
Quote from: Vortex on November 10, 2018, 04:15:49 AM
Hello,
Image display functions (http://masm32.com/board/index.php?topic=6852.0)
Screenshot with small size (http://masm32.com/board/index.php?topic=4828.0)
Thanks, but those don't do me any good as I'm using a 32-bit OS (XP). Any other suggestions?
I hate to have to tell you this but your forum name "NoCforMe" is probably the main obstruction to you getting what you are after. People who write many different computer languages all have to deal with an OS that is written primarily in C and while in this case, assemblers deal with C formats just fine, if you shut the door on C you have shut the door on much of what the OS has to offer.
You could look at GDIPLUS for at least some of what you are after but appreciate that there is no easy path to get what you are after.
Hello NoCforMe,
Those examples are working under Windows XP 32-bit :
http://masm32.com/board/index.php?topic=4828.msg51959#msg51959 ( Screenshot with small size )
http://masm32.com/board/index.php?topic=4731.msg51075#msg51075 ( level lower the compression in images jpg )
Attached is the image library for Windows XP 32-bit.
Quote from: Vortex on November 10, 2018, 07:58:01 PM
Attached is the image library for Windows XP 32-bit.
Thanks for that; I'll play with it. Couple things, though: any documentation? I guess I can figure out how to make it work from the sample code provided, but no details. And there doesn't seem to be a function to save to a JPEG. Anyhow, thanks again.
I realised that my example above doesn't work in my XP VM, and I wonder why... here is the SaveImageToFile macro showing the 4 Gdi+ functions used in bold, IMHO they should work in XP:
SaveImageToFile MACRO siFileW, quality:=<0>
push ebx
push ecx
push eax ; hBmp slot
mov ebx, wRec$(repargA(siFileW))
mov ecx, esp
gdi+ GdipCloneImage, giImage, ecx
GetEncoderCLSID PROTO :DWORD
invoke GetEncoderCLSID, ebx
mov ecx, stack
gdi+ GdipSaveImageToFile, ecx, ebx, eax, quality
pop ecx
gdi+ GdipDisposeImage, ecx
pop ecx
pop ebx
ENDM
Hi NoCforMe,
QuoteAnd there doesn't seem to be a function to save to a JPEG.
Did you check the links I posted above? They save bitmaps as JPEGs and they are commented.
José Roca's forum explains a lot about the GDI+ functions :
http://www.jose.it-berater.org/smfforum/index.php?board=277.60
The GDI+ has it's own workflow to deal with images so you need to create your function to convert images to JPEG.
an example
;------------------------------------------------------------
invoke _Open ,0,0,chr$("Image",0,"*.bmp;*.jpg;*.png",0,0) ; select image
.if eax
mov FileName,eax
printf("Load Image From:%s\n",FileName)
invoke UnicodeStr,FileName,ADDR _buffer ;str to wstr
invoke GdipLoadImageFromFile,ADDR _buffer,addr Img ;Load Image
.if eax == 0
mov pencoderClsid,rv( GetEncoderClsid,chr$("image/jpeg") )
invoke _SaveAs ,0,0,chr$("JPEG Image",0,"*.jpg",0,0) ; select file name
.if eax
mov FileName,eax
invoke UnicodeStr,FileName,ADDR _buffer ;str to wstr
printf("Save Image To:%s\n",FileName)
invoke GdipSaveImageToFile,Img,ADDR _buffer,pencoderClsid,0 ;SaveImageTo
.if eax == 0
printf("success\n",FileName)
.endif
.endif
invoke GdipDisposeImage,Img
.endif
.endif
;------------------------------------------------------------
Quote from: mabdelouahab on November 12, 2018, 08:18:30 AM
an example
This is basically what I posted above, but it doesn't work on XP.
It works in Windows 2000 as well.
I mean the mabdelouahab code, your masm basic looks buggy because you are popping ecx out of nowhere, but I will not delve deeper into such a complex artifact, sorry.
Quote from: AW on November 13, 2018, 01:30:56 AMbuggy because you are popping ecx out of nowhere
It works fine:
- on Win7-64
- on XP when debugged with Olly
- on XP when run through DebugHeap.exe (http://masm32.com/board/index.php?topic=94.msg55745#msg55745)
- but GdipSaveImageToFile fails silently on XP when
not run with Olly or DebugHeap.
Mysteries of Windows 8)
Quote from: jj2007 on November 13, 2018, 02:36:58 AM
- but GdipSaveImageToFile fails silently on XP when not run with Olly or DebugHeap.
So
Try this.
invoke GdipSaveImageToFile,Img,ADDR _buffer,pencoderClsid,0 ;SaveImageTo
.if eax == 0
printf("success\n",FileName)
.else
printf("GdipSaveImageToFile ERR: %X\n",EAX)
.endif
Let's find out what's wrong with you.
Quote
GpStatusOk EQU 0
GpStatusGenericError EQU 1
GpStatusInvalidParameter EQU 2
GpStatusOutOfMemory EQU 3
GpStatusObjectBusy EQU 4
GpStatusInsufficientBuffer EQU 5
GpStatusNotImplemented EQU 6
GpStatusWin32Error EQU 7
GpStatusWrongState EQU 8
GpStatusAborted EQU 9
GpStatusFileNotFound EQU 10
GpStatusValueOverflow EQU 11
GpStatusAccessDenied EQU 12
GpStatusUnknownImageFormat EQU 13
GpStatusFontFamilyNotFound EQU 14
GpStatusFontStyleNotFound EQU 15
GpStatusNotTrueTypeFont EQU 16
GpStatusUnsupportedGdiplusVersion EQU 17
GpStatusGdiplusNotInitialized EQU 18
GpStatusPropertyNotFound EQU 19
GpStatusPropertyNotSupported EQU 20
In my whole life I don't remember ever finding an undocumented Windows bug, it was always a bug in my own code. :(
mabdelouahab's application works fine both on Windows XP 32-bit and Windows PE based on XP 32-bit.
Quote from: mabdelouahab on November 13, 2018, 03:57:20 AMLet's find out what's wrong with you.
Nothing is wrong with me, mabdelouahab. And I use a much more sophisticated gdi+ error checking.
Fact is that
a) your executable gets refused by my Win32 XP VM, which may simply be a manifest problem
b) I can re-build it, and then it runs on my VM
c) my executable runs fine on various configurations
d) but it crashes without warning and without errors in exactly one configuration: the normal execution on Win XP 8)
EDIT: I found the culprit:
GetEncoderCLSID proc uses esi edi ebx fileW$
LOCAL extW, encNum, encSize, pImageCodecInfo, mimeBuffer[32]:BYTE, encBuffer[8000]:BYTE ; typical size is 1040 bytes
mov edi, fileW$
push edi
call MbStrLenW
lea edi, [edi+2*eax]
:badgrin:
So, it is a bug in your masm basic code, not a mysterious Windows bug.
I know I shouldn't feed the troll, but actually, where did I write it was a Windows bug?
Quote from: hutch-- on November 10, 2018, 07:32:46 PM
I hate to have to tell you this [...]
No you don't, but let's continue:
Quotebut your forum name "NoCforMe" is probably the main obstruction to you getting what you are after. People who write many different computer languages all have to deal with an OS that is written primarily in C and while in this case, assemblers deal with C formats just fine, if you shut the door on C you have shut the door on much of what the OS has to offer.
Since you brought this up, I'm going to reply to you. So when I posted a perfectly valid, reasonable question here about programming, you chose to scold me for my choice of usernames, rather than help me. Really? Does my name really bug you all that much? My, you must be pretty thin-skinned to get up on your high horse like that. (Besides which, I actually did get a bunch of helpful replies, in spite of my stupid username!)
Look: I don't like to use C,
for my own projects. I'm not working in production, making stuff that will be sold into the marketplace. It's strictly for my own amusement. I prefer plain old MASM, the tools which you offer here. I don't even like to use macros for the most part. Just my taste is all. And I've got absolutely nothing against anyone else using any damn language they please to program. Hell, I've coded COBOL in a past life (and as a side note, it was exactly the right tool for the job, for payroll and accounting applications). So please don't lecture me about my "handle".
QuoteYou could look at GDIPLUS for at least some of what you are after but appreciate that there is no easy path to get what you are after.
Now
that is actually potentially helpful to me. See my next posting below here.
Now I'm thinking about using GDI+. But first I've got to understand it a bit better.
Let's take opening a JPEG image from a file and displaying it. Reading MSDN, it appears I first need to use the Bitmap method to obtain the image (see here (https://docs.microsoft.com/en-us/windows/desktop/api/gdiplusheaders/nf-gdiplusheaders-bitmap-bitmap%28inconstwchar_inbool%29)), then use the Graphics method to display it (see here (https://docs.microsoft.com/en-us/windows/desktop/api/gdiplusgraphics/nl-gdiplusgraphics-graphics)). Fine. But I'm really confused by the Graphics stuff. Assuming I need to use the Graphics:DrawImage method, that page shows more than a dozen of them. Which one do I use?
MASM32 appears to have GDI+ support baked into it, but I'm confused about how to use it since it doesn't seem to be documented anywhere that I can see. Looking at gdiplus.inc, I see a dozen prototypes for GdipDrawImageXXXX, where XXXX is I, PointRect, PointRectI, Points, etc. Where do I find descriptions of these functions so I can use them.?
And is it really as easy as that, calling Bitmap:Bitmap, then Graphics:DrawImage?
As I said, all I really want to do at this point is open a JPEG and display it, optionally resize it, and save it back to disk.
I assume I can use something like StretchBlt() to resize an image?
Thanks in advance for any help!
:biggrin:
Here is the problem, generally people who jump up on their high horse tend to fall off the other side and land on their arse. When you take the disposition that you exclude the sum total of C based API code, you are asking other people to translate it for you which is an unreasonable demand. We all have to suffer lousy Microsoft documentation and most have been doing it for years.
The old GDI does many things OK, its not fast enough for animation or gaming but more than capable for presentation graphics. At best GDI+ is very badly documented and Microsoft only support high level wrappers in C++. The best reference material that is easily available was written by Jose Roca in PowerBASIC.
You are basically stuck with the same irritation that the rest of us are, lousy documentation and the need for "some C for Me".
Quote from: hutch-- on December 05, 2018, 11:40:33 AM
:biggrin:
You are basically stuck with the same irritation that the rest of us are, lousy documentation and the need for "some C for Me".
OK, I get it. But I figure that since those functions (C++ "methods" that have been given library names) are in your (MASM32's) library, they must be usable, right? Is there any way to figure out which is which, what parameters these functions take? Otherwise why would you have bothered to include them in the first place?
If there's some other library out there that would do the simple things I'm after I'd be happy to use it. So far none of the suggestions given in this thread have proven usable to me (some were 64-bit, others didn't have the functionality I needed). So I'll wait here patiently ...
Quote from: hutch-- on December 05, 2018, 11:40:33 AM
The old GDI does many things OK, its not fast enough for animation or gaming but more than capable for presentation graphics.
Except that plain old GDI doesn't have any built-in support for JPEG, right?
> So I'll wait here patiently ...
That will not get you anywhere. Like the rest of us you have to go look for it yourself. Asking for a jpg library is assuming there is one for you to use and that may not be the case. I did suggest that you try GDI+ but I warned you that the documentation is very bad. I downloaded an old PLATFORMSDK dated about 2006 to try and get better reference but it was no better than Jose Roca's basic help file.
I have a little GDI+ done in 64 bit but only for loading image files, mainly for toolbars and background images, I have not decyphered writing a bitmap image back to disk as a jpg.
Maybe this will help. I stumbled upon this page (https://referencesource.microsoft.com/#System.Drawing/commonui/System/Drawing/Bitmap.cs,e1ba6ce9c451889d) at Microsoft's Reference Source, which I didn't even know existed. There I found the following somewhat self-documenting prototypes for all 12 of the GdipDrawImageXXXX() functions:
internal static extern int GdipDrawImage(HandleRef graphics, HandleRef image, float x, float y);
internal static extern int GdipDrawImageI(HandleRef graphics, HandleRef image, int x, int y);
internal static extern int GdipDrawImageRect(HandleRef graphics, HandleRef image, float x,
float y, float width, float height);
internal static extern int GdipDrawImageRectI(HandleRef graphics, HandleRef image, int x,
int y, int width, int height);
internal static extern int GdipDrawImagePoints(HandleRef graphics, HandleRef image,
HandleRef points, int count);
internal static extern int GdipDrawImagePointsI(HandleRef graphics, HandleRef image,
HandleRef points, int count);
internal static extern int GdipDrawImagePointRect(HandleRef graphics, HandleRef image, float x,
float y, float srcx, float srcy,
float srcwidth, float srcheight,
int srcunit);
internal static extern int GdipDrawImagePointRectI(HandleRef graphics, HandleRef image, int x,
int y, int srcx, int srcy,
int srcwidth, int srcheight,
int srcunit);
internal static extern int GdipDrawImageRectRect(HandleRef graphics, HandleRef image,
float dstx, float dsty,
float dstwidth, float dstheight,
float srcx, float srcy,
float srcwidth, float srcheight,
int srcunit, HandleRef imageAttributes,
Graphics.DrawImageAbort callback, HandleRef callbackdata);
internal static extern int GdipDrawImageRectRectI(HandleRef graphics, HandleRef image,
int dstx, int dsty,
int dstwidth, int dstheight,
int srcx, int srcy,
int srcwidth, int srcheight,
int srcunit, HandleRef imageAttributes,
Graphics.DrawImageAbort callback, HandleRef callbackdata);
internal static extern int GdipDrawImagePointsRect(HandleRef graphics, HandleRef image,
HandleRef points, int count, float srcx,
float srcy, float srcwidth,
float srcheight, int srcunit,
HandleRef imageAttributes,
Graphics.DrawImageAbort callback, HandleRef callbackdata);
internal static extern int GdipDrawImagePointsRectI(HandleRef graphics, HandleRef image,
HandleRef points, int count, int srcx,
int srcy, int srcwidth,
int srcheight, int srcunit,
HandleRef imageAttributes,
Graphics.DrawImageAbort callback, HandleRef callbackdata);
Now we know that the "I" functions use integer arguments while the others use floats. Still leaves some mysteries to clear up, like that first parameter, HandleRef graphics. How do I get that handle? Apparently it's not just a DC like you'd use with GDI. If I could figure that out I could start displaying images with GDI+.
[Breaking News] Just found this in MS ref.source:
internal static extern int GdipCreateFromHDC(HandleRef hdc, out IntPtr graphics);
So it looks like I pass it in an hDC and a pointer to a "graphics" (it's a DWORD, who cares?), then pass "graphics" to DrawImage(). I think I'll try it.
:t
Well, I got it to work. Code posted below, zip file includes the image whose name is hard-coded.
It works, but not the way it should. Question: Why is the image so much smaller than full size? Someone's doing some kind of scaling here. Further experimentation needed ...
;============================================
; -- JPEG testbed, using GDI+ --
;
;============================================
include \masm32\include\masm32rt.inc
include \masm32\include\gdiplus.inc
includelib \masm32\lib\gdiplus.lib
;============================================
; Defines, macros, prototypes, etc.
;============================================
WinMain PROTO :DWORD
$mainWinWidth EQU 600
$mainWinHeight EQU 500
;===== Window styles: =====
$mainWinStyles EQU WS_OVERLAPPEDWINDOW OR WS_CLIPCHILDREN OR WS_VISIBLE
;===== Window background colors: =====
$bkRED EQU 254
$bkGRN EQU 243
$bkBLUE EQU 199
$BkColor EQU $bkRED OR ($bkGRN SHL 8) OR ($bkBLUE SHL 16)
;============================================
; HERE BE DATA
;============================================
.data
WC WNDCLASSEX < SIZEOF WNDCLASSEX, \
CS_HREDRAW or CS_VREDRAW or CS_BYTEALIGNWINDOW, \
NULL, \ ;lpfnWndProc
NULL, \ ;cbClsExtra
NULL, \ ;cbWndExtra
NULL, \ ;hInstance
NULL, \ ;hIcon
NULL, \ ;hCursor
NULL, \ ;hbrBackground
NULL, \ ;lpszMenuName
NULL, \ ;lpszClassName
NULL > ;hIconSm
GDIinputStruct GdiplusStartupInput <1, NULL, FALSE, 0>
MainClassName DB "JPEGtest", 0
MainTitleText DB "JPEG Testbed", 0
; Name is in Unicode:
JPEGfilename DB 't', 0, 'e', 0, 's', 0, 't', 0, '.', 0, 'j', 0, 'p', 0, 'g', 0, 0
;============================================
; UNINITIALIZED DATA
;============================================
.data?
MainWinHandle HWND ?
GDItoken DD ?
;============================================
; CODE LIVES HERE
;============================================
.code
start: INVOKE GetModuleHandle, NULL
MOV WC.hInstance, EAX
INVOKE WinMain, EAX
INVOKE ExitProcess, EAX
;====================================================================
; Mainline proc
;====================================================================
WinMain PROC hInst:DWORD
LOCAL msg:MSG, brush:HBRUSH, wX:DWORD, wY:DWORD, gpRect:RECT
; Create brush to set background color:
INVOKE CreateSolidBrush, $BkColor
MOV brush, EAX
; Register class for parent window:
MOV WC.lpfnWndProc, OFFSET MainWindowProc
MOV EAX, brush
MOV WC.hbrBackground, EAX
MOV WC.lpszClassName, OFFSET MainClassName
MOV WC.hIcon, NULL
INVOKE LoadCursor, NULL, IDC_ARROW
MOV WC.hCursor, EAX
INVOKE RegisterClassEx, OFFSET WC
INVOKE GetSystemMetrics, SM_CXSCREEN
MOV EDX, $mainWinWidth
CALL CenterDim
MOV wX, EAX
INVOKE GetSystemMetrics, SM_CYSCREEN
MOV EDX, $mainWinHeight
CALL CenterDim
MOV wY, EAX
; Create our main window:
INVOKE CreateWindowEx, WS_EX_OVERLAPPEDWINDOW, OFFSET MainClassName,
OFFSET MainTitleText, $mainWinStyles, wX, wY, $mainWinWidth,
$mainWinHeight, NULL, NULL, hInst, NULL
MOV MainWinHandle, EAX
;******** Initialize GDI+: ********
INVOKE GdiplusStartup, OFFSET GDItoken, OFFSET GDIinputStruct, NULL
;============= Message loop ===================
msgloop:
INVOKE GetMessage, ADDR msg, NULL, 0, 0
OR EAX, EAX ;EAX = 0 = exit
JZ exit99
INVOKE TranslateMessage, ADDR msg
INVOKE DispatchMessage, ADDR msg
JMP msgloop
exit99: INVOKE GdiplusShutdown, GDItoken
MOV EAX, msg.wParam
RET
WinMain ENDP
;====================================================================
; Main Window Proc
;====================================================================
MainWindowProc PROC hWin:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD
LOCAL hDC:HDC, gdiHgraphics:DWORD, gdiHbitmap:DWORD
LOCAL ps:PAINTSTRUCT
MOV EAX, uMsg
CMP EAX, WM_PAINT
JE do_paint
CMP EAX, WM_CLOSE
JE do_close
dodefault:
; use DefWindowProc for all other messages:
INVOKE DefWindowProc, hWin, uMsg, wParam, lParam
RET
do_paint:
INVOKE BeginPaint, hWin, ADDR ps
MOV hDC, EAX
; Open JPEG file:
INVOKE GdipLoadImageFromFile, OFFSET JPEGfilename, ADDR gdiHbitmap
; Get graphics "object" from DC handle:
INVOKE GdipCreateFromHDC, hDC, ADDR gdiHgraphics
; Display image:
INVOKE GdipDrawImageI, gdiHgraphics, gdiHbitmap, 50, 50
INVOKE EndPaint, hWin, ADDR ps
XOR EAX, EAX
RET
do_close:
INVOKE PostQuitMessage, NULL
MOV EAX, TRUE
RET
MainWindowProc ENDP
;====================================================================
; CenterDim
;
; Returns half screen dimension (X or Y) minus half window dimension
;
; On entry,
; EAX = screen dimension
; EDX = window dimension
;
; Returns:
; sdim/2 - wdim/2
;====================================================================
CenterDim PROC
SHR EAX, 1 ;divide screen dimension by 2
SHR EDX, 1 ;divide window dimension by 2
SUB EAX, EDX
RET ;Return w/# in EAX
CenterDim ENDP
END start
Gdi+ is a little bit old, therefore it is difficult to find good documentation. But if you don't need high speed for games, it is still a very powerful API.
Attached a file that I use for my stuff, containing documentation of 600+ Gdi+ functions. It's RTF, opens best in RichMasm but also in WordPad or MS Word.
Hope it helps, Jochen