I have my own class that creates PDF files and want to add image support. I can use PB binary reads and read the entire file and parse through it and was interested in getting away from that as well as being able to use the GDI+ functions to load an image of various types, interrogate the image for something I can understand and then inserting the image properly into the PDF document stream.
Is this something the GDI+ support include files can handle?
Rick Kelly
Not sure what exact filetypes pdf handles but should at least be jpg.
I forgot but when text's are inserted binary they usually inserted as zlib compressed string buffer (stream) which is easy to do.
Maybe images are handled similarly.
Would you like to share your class to generate the pdf as it is right now, just for my own use?
I know the basics how pdf works but it is some work to prepare code.
Quote from: Edwin Knoppert on May 05, 2014, 11:37:21 AM
Not sure what exact filetypes pdf handles but should at least be jpg.
I forgot but when text's are inserted binary they usually inserted as zlib compressed string buffer (stream) which is easy to do.
Maybe images are handled similarly.
Would you like to share your class to generate the pdf as it is right now, just for my own use?
I know the basics how pdf works but it is some work to prepare code.
I'm in the cleanup/polishing up phase. My interpretation is mainly for what I need - things such as text, lines and images so doesn't have all the bells and whistles.
Here is how I am capturing image data to use later on when generating the PDF file stream. PB10 and, of course, Jose's includes ;D
TYPE ImageAttributes
HorizontalResolution AS SINGLE
VerticalResolution AS SINGLE
ImagePixelHeight AS LONG
ImagePixelWidth AS LONG
ImageHeight AS DOUBLE
ImageWidth AS DOUBLE
ImageSize AS LONG
ImageDescriptorObject AS LONG
END TYPE
%PDF_MEASUREMENT = 72
INSTANCE ImageDescriptor AS IPOWERCOLLECTION
INSTANCE ImageStream AS IPOWERCOLLECTION
LET ImageDescriptor = CLASS "PowerCollection"
LET ImageStream = CLASS "PowerCollection"
------------------------------
METHOD AddImage(BYVAL sImageFile AS STRING) AS STRING
' Add a jpeg image
' If return string is blank, an error occurred
LOCAL sImageID AS WSTRING
LOCAL hStatus AS LONG
LOCAL nPixelFormat AS LONG
LOCAL hToken AS DWORD
LOCAL StartupInput AS GdiplusStartupInput
LOCAL pImage AS DWORD
LOCAL szImageFile AS WSTRINGZ * %MAX_PATH
LOCAL ImageGUID AS GUID
LOCAL uImageAttributes AS ImageAttributes
LOCAL nFile AS INTEGER
LOCAL nFileSize AS LONG
LOCAL sFileContents AS STRING
LOCAL nTotalImages AS LONG
LOCAL nWidth AS LONG
LOCAL nHeight AS LONG
sImageID = ""
szImageFile = sImageFile
' Startup GDI+
StartupInput.GdiplusVersion = 1
hStatus = GdiplusStartup(hToken, StartupInput, BYVAL %NULL)
IF hStatus <> %S_OK THEN
MSGBOX "Unable to start graphics subsystem."
METHOD = ""
EXIT METHOD
END IF
' Check if image file is valid
IF NOT ISFILE(szImageFile) THEN
MSGBOX szImageFile + " not found."
METHOD = ""
EXIT METHOD
END IF
' Load Image file
hStatus = GdipLoadImageFromFile(szImageFile, pImage)
IF hStatus <> %S_OK THEN
MSGBOX szImageFile + " is not a recognized image file."
GOTO AddImageExit
END IF
' Check if image format if JPEG
hStatus = GdipGetImageRawFormat(pImage,ImageGUID)
IF ImageGUID <> $ImageFormatJPEG THEN
MSGBOX szImageFile + " is not a JPEG image file."
GdipDisposeImage pImage
GOTO AddImageExit
END IF
' Check color depth
hStatus = GdipGetImagePixelFormat(pImage,nPixelFormat)
IF nPixelFormat <> %PixelFormat24bppRGB THEN
MSGBOX "JPEG color depth is not supported."
GdipDisposeImage pImage
GOTO AddImageExit
END IF
GdipGetImageHorizontalResolution(pImage,uImageAttributes.HorizontalResolution)
GdipGetImageVerticalResolution(pImage,uImageAttributes.VerticalResolution)
GdipGetImageWidth(pImage,uImageAttributes.ImagePixelWidth)
GdipGetImageHeight(pImage,uImageAttributes.ImagePixelHeight)
uImageAttributes.ImageWidth = uImageAttributes.ImagePixelWidth * %PDF_MEASUREMENT / uImageAttributes.HorizontalResolution
uImageAttributes.ImageHeight = uImageAttributes.ImagePixelHeight * %PDF_MEASUREMENT / uImageAttributes.VerticalResolution
' Release GDI+ Image
GdipDisposeImage pImage
' Get file size and raw stream
nFile = FREEFILE
OPEN szImageFile FOR BINARY AS nFile
uImageAttributes.ImageSize = LOF(nFile)
GET$ nFile, uImageAttributes.ImageSize, sFileContents
CLOSE nFile
' Save Image for reference
nTotalImages = ImageDescriptor.Count
INCR nTotalImages
sImageID = "I" + FORMAT$(nTotalImages)
ImageDescriptor.Add(sImageID,uImageAttributes AS STRING)
ImageStream.Add(sImageID,sFileContents)
AddImageExit:
' Shutdown GDI+
GdiplusShutdown hToken
METHOD = sImageID
END METHOD
The image object is then created and looks like this:
6 0 obj
<<
/Type /XObject
/Subtype /Image
/Filter /DCTDecode
/ColorSpace /DeviceRGB
/Width 133
/Height 129
/BitsPerComponent 8
/Length 9782
>>
stream
????? Raw JPEG stream
endstream
endobj
All my images are XOBJECT items and the PDF Procedure set then looks like (includes any referenced fonts as well):
8 0 obj
<< /ProcSet [ /PDF /Text /ImageC]
/XObject <<
/I1 6 0 R
>>
/Font <<
/F1 5 0 R
>>
>>
endobj
I'll post at attachment with the class when I'm done testing and am ready to begin using it myself.
Rick Kelly
I decided if you wanted to take a look at a "work in progress", I have no real issue with that. There is still a lot of work I've got to do. There are two includes and I combined them into one file.
Rick Kelly
stream
?? Raw JPEG stream
endstream
If so you can try the zlib string (compress)ion method (and thus not the other, zip file creation, functions).
Imo the output of that is placed 1:1 into the pdf.
I don't know and i am not going to investigate further :)
I have messed with text streams this to remove the trail message from a pdf :)
Cross post :)
That's a lot of work!
As i said, i am not pursuing it at this time, sorry.
Look for zlib114 dll and doc, this will prepare a stream buffer for you.
In my PwrDev used as:
Declare Function VD_ZLIB__compress Lib "ZLIB.DLL" Alias "compress"( ByRef dest As Any, ByRef destLen As Any, ByRef src As Any, ByVal srcLen As Long ) As Long
Function VD_ZLIB_Buffer_CompressEx( _
ByVal pDestData As Dword _
, ByVal nDestDataLen As Dword _
, ByVal pSrcData As Dword _
, ByVal nSrcDataLen As Dword _
, ByRef nErrorCode As Long _
) As Long
If VD_ZLIB_IsLoaded() = 0 Then Exit Function
nErrorCode = VD_ZLIB__compress( _
ByVal pDestData _
, nDestDataLen _
, ByVal pSrcData _
, nSrcDataLen _
)
If nErrorCode = %Z_OK Then Function = nDestDataLen
End Function
I'm going to be using a PB version posted at:
http://www.powerbasic.com/support/pbforums/showthread.php?t=54472&highlight=compression
(http://www.powerbasic.com/support/pbforums/showthread.php?t=54472&highlight=compression)
Quote from: Edwin Knoppert on May 06, 2014, 08:41:05 AM
stream
?? Raw JPEG stream
endstream
Yes, you just insert the raw JPEG into the stream.... ;)
Here is a sample pdf. I have page title centered, two numeric strings that I used right alignment on and underlined as well. I drew a rectangle and filled it and then for kicks, I added a circle. Finally, I added an image (that shiny blue sphere). Open the PDF up in notepad and you can see all the structure.
Rick
Are you saying that you have it working already?
Curious, in notepad i see JFIF for tag, did you insert the jpg file 1:1 or is it compressed to a string buffer first?
Maybe the compression sucks and JFIF is still shown haha.
Quote from: Edwin Knoppert on May 06, 2014, 09:16:59 AM
Are you saying that you have it working already?
Curious, in notepad i see JFIF for tag, did you insert the jpg file 1:1 or is it compressed to a string buffer first?
Maybe the compression sucks and JFIF is still shown haha.
The jpg file is inserted 1:1 just as I read it from disk without any changes.
I'm adding to the class incrementally and testing as I go so I've had a basic functional PDF structure from day 1 being generated and I've been working on this on and off for a few weeks now. What got me started was just how expensive PDF libraries were when I really didn't need all the fancy bells and whistles. What I'm giving up is because, for now, I'm not going to embed fonts, I have to stick to a few widely supported ones. You can see I have Arial and Times New Roman in there and I'll add Verdana and TreBuchet. You're free to add what fonts you want (I use Adobe AFM files, version 4.1 to build my arrays) and even dive in the nasty world of embedding fonts. I have a list of all the api's involved somewhere and it's not very well documented. It's likely, I'll add kerning to both the string size calculations and the text strings written. I'm a bit haphazard and eventually I'll have to clean it all up and organize things. What I want to do is to have all my low level PDF primitives methods in there and then wrap those with a method(s) that make using the class easier.
Rick
At this time i will not participate (and i don't see a time for that soon unf.) but i like you shared this code.
PDF is not incredible difficult for the more basic parts but it is some work.
Fonts are an issue yes, you may want to add several free fonts.
Hope you get what you asked for at this time :)
You may still consider to prepare compressed streams of text parts, it's easy to do.
:)
Quote from: Edwin Knoppert on May 06, 2014, 11:53:51 AM
You may still consider to prepare compressed streams of text parts, it's easy to do.
:)
As one of the last things I add, it will be to compress all page objects.
I still have the following "features" to add before I embed this class into my current app:
1. Column definitions - break a page up into x number of columns each with it's own attributes
2. Pass in a bunch of rows matching up to the columns and have them put on the page with one call
3. Page templates - set up instructions for all the stuff on a page that stays the same...a lot of reports are repeaters
4. Text kerning - heck, I have the KP pairs from the AFM files and might as well see how it works out. Have to check out if Adobe kerns or not
5. Multiline boxes where the class will put as many words on each line as it can and then wrap to the next line and stay in the defined box
6. Some mechanism for keeping track of when a page break is necessary under certain circumstances and do it automatically with some options to repeat section headers that are defined as part of the column(s) definitions.
7. Maybe some of the basic shading and pattern fills.
8. And, in all my "spare" time, read up on embedding fonts and study those API's and data structures.
Looks like a few more weeks already... ::)
Rick
I have my PDF class where I need it to begin using in my latest application.
You can get all the source, including a FF demo project at:
http://www.planetsquires.com/protect/forum/index.php?topic=3547.0
(http://www.planetsquires.com/protect/forum/index.php?topic=3547.0)
Rick Kelly
I don't have access to those forums but anyway.., i like to have the code but understand, at this time i'll not be able to help you.
So if you find me a taker then don't publish more.
Not sure if you where doing this for printing/preview matters.., i wrote a small topic on that.
Maybe an idea for some people..?
http://www.powerbasic.com/support/pbforums/showthread.php?t=54381