I finally figured out how to do this. It generates a native Photoshop PSD file, 3 channels, 8bits per pixel, 256x256 size image. I set all the header stuff as constants basically (though I didn't use the Const statement, I used Dim, and then set them with var = val type lines farther down, so I could later make routines to set the values at runtime). I set them as constants for now because Photoshop (having originated as Mac software) uses Big Endian number in its main file format. And unlike TIFF where you can set II for Intel format (little endian) or MM for Mac format (big endian), Photoshops files are REQUIRE the multibyte values to be big endian, and conversion routines are not trivial. So I opted (for now) to just create a test image generator program with fixed values for all the multibyte values (which is ALL of the entries in the header, so I have fixed width, fixed height, fixed bitdepth, etc). That's why it's more of a fixed size test image generator than a true graphics software or image converter. Though later I plan to expand this to use the CopyMemory API to create a Little to Big Endian converter so I can change these values at runtime.
This is my program's current code.
Code:
Private Sub Form_Load()
Dim Pix(255, 255, 2) As Byte
For y = 0 To 255
For x = 0 To 255
Pix(x, y, 0) = (x * 4) And 255
Pix(x, y, 1) = (y * 4) And 255
Pix(x, y, 2) = (x \ 64) * 17 + (y \ 64) * 68
Next x
Next y
Dim Sig As String
Dim Ver As Integer
Dim Reserved(5) As Byte
Dim Chan As Integer
Dim PHeight As Long
Dim PWidth As Long
Dim Depth As Integer
Dim PMode As Integer
Dim NullLen As Long
Dim CompMethod As Integer
Sig = "8BPS"
Ver = &H100
Chan = &H300
PHeight = &H10000
PWidth = &H10000
Depth = &H800
PMode = &H300
Open "c:\temp\test.psd" For Binary As #1
Put #1, 1, Sig
Put #1, , Ver
Put #1, , Reserved()
Put #1, , Chan
Put #1, , PHeight
Put #1, , PWidth
Put #1, , Depth
Put #1, , PMode
Put #1, , NullLen
Put #1, , NullLen
Put #1, , NullLen
Put #1, , CompMethod
Put #1, , Pix()
Close #1
End
End Sub
Private Type PSD_Format
Sig As String * 4
Ver As Integer
Reserved(5) As Byte
Chan As Integer
PHeight As Long
PWidth As Long
Depth As Integer
PMode As Integer
NullLen(2) As Long
CompMethod As Integer
End Type
Private Sub Form_Load()
Dim Pix(255, 255, 2) As Byte, x As Integer, y As Integer, PSD As PSD_Format
With PSD
.Sig = "8BPS"
.Ver = &H100
.Chan = &H300
.PHeight = &H10000
.PWidth = &H10000
.Depth = &H800
.PMode = &H300
End With
For y = 0 To 255
For x = 0 To 255
Pix(x, y, 0) = (x * 4) And 255
Pix(x, y, 1) = (y * 4) And 255
Pix(x, y, 2) = (x \ 64) * 17 + (y \ 64) * 68
Next x
Next y
Open "C:\Temp\Test.psd" For Binary As #1
Put #1, 1&, PSD
Put #1, , Pix()
Close #1
End
End Sub
On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
Actually those variables are all part of different structures. For example, NullLen is used 3 times because there are 3 optional structures, who's only mandatory part is the length field. To indicate you won't use the structure, the length must be 0. So NullLen is actually not part of the header, but rather is used 3 times to specify that those 3 optional structures are not present in the file. The actual PSD file header ends after PMode. And CompMethod is Compression Method, which is the one field in the single-field header for the image data structure (which of course is followed by the actual image data), and tells how the image data is compressed (or even if it is not compressed), where 0 is uncompressed, 1 is RLE compressed, 2 is ZIP compressed (normal ZIP), and 3 is ZIP compressed (with a predictive algorithm).
So putting all those data field into one header User Defined Type is technically not correct (even though it would work).
And I just now finished writing the two needed endian conversion functions, which utilize the CopyMemory API call. Below is the code needed for this.
Code:
Private Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (ByVal Destination As Long, ByVal Source As Long, ByVal Length As Long)
Private Function ConvEndInt(ByVal Value As Integer) As Integer
Dim tempval As Integer
CopyMemory VarPtr(tempval), VarPtr(Value) + 1, 1
CopyMemory VarPtr(tempval) + 1, VarPtr(Value), 1
ConvEndInt = tempval
End Function
Private Function ConvEndLong(ByVal Value As Long) As Long
Dim tempval As Long
CopyMemory VarPtr(tempval), VarPtr(Value) + 3, 1
CopyMemory VarPtr(tempval) + 1, VarPtr(Value) + 2, 1
CopyMemory VarPtr(tempval) + 2, VarPtr(Value) + 1, 1
CopyMemory VarPtr(tempval) + 3, VarPtr(Value), 1
ConvEndLong = tempval
End Function
And now I've finished my more complete implementation of the program. It converts Little-Endian numbers to the required Bit-Endian numbers at runtime. This particular sample program generates a 640x480 color test pattern, and saves it as a PSD file.
Code:
Private Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (ByVal Destination As Long, ByVal Source As Long, ByVal Length As Long)
Private Type PSD_Format
Sig As String * 4
Ver As Integer
Reserved(5) As Byte
ChanCount As Integer
ImageHeight As Long
ImageWidth As Long
BitDepth As Integer
ColorMode As Integer
End Type
Private Enum CMode
Bitmap = 0
IndexedColor = 1
Grayscale = 2
RGB = 3
CMYK = 4
Multichannel = 7
Duotone = 8
Lab = 9
End Enum
Private Function ConvEndInt(ByVal Value As Integer) As Integer
Dim tempval As Integer
CopyMemory VarPtr(tempval), VarPtr(Value) + 1, 1
CopyMemory VarPtr(tempval) + 1, VarPtr(Value), 1
ConvEndInt = tempval
End Function
Private Function ConvEndLong(ByVal Value As Long) As Long
Dim tempval As Long
CopyMemory VarPtr(tempval), VarPtr(Value) + 3, 1
CopyMemory VarPtr(tempval) + 1, VarPtr(Value) + 2, 1
CopyMemory VarPtr(tempval) + 2, VarPtr(Value) + 1, 1
CopyMemory VarPtr(tempval) + 3, VarPtr(Value), 1
ConvEndLong = tempval
End Function
Private Sub FillHeader(ByRef PSD_Header As PSD_Format, ByVal NumberOfChannels As Integer, ByVal ImgWidth As Long, ByVal ImgHeight As Long, ByVal ChannelBitDepth As Integer, ByVal ColorMode As CMode)
With PSD_Header
.Sig = "8BPS"
.Ver = &H100
.ChanCount = ConvEndInt(NumberOfChannels)
.ImageHeight = ConvEndLong(ImgHeight)
.ImageWidth = ConvEndLong(ImgWidth)
.BitDepth = ConvEndInt(ChannelBitDepth)
.ColorMode = ConvEndInt(ColorMode)
End With
End Sub
Private Sub Form_Load()
Dim PSD As PSD_Format
Dim Pix() As Byte
ReDim Pix(640 - 1, 480 - 1, 2)
FillHeader PSD, 3, 640, 480, 8, RGB
For y = 0 To 480 - 1
For x = 0 To 640 - 1
Pix(x, y, 0) = (x Mod 40) * (255 / 39)
Pix(x, y, 1) = (x \ 40) * (255 / 15)
Pix(x, y, 2) = y / (480 - 1) * 255
Next x
Next y
Open "c:\temp\test.psd" For Binary As #1
Put #1, 1, PSD
Put #1, , 0&
Put #1, , 0&
Put #1, , 0&
Put #1, , 0
Put #1, , Pix()
Close #1
End
End Sub
And yes the official PSD specification if VERY EXTENSIVE! It can save just about any type of data that can be in an image in Photoshop (layers, masks, alpha channels, thumbnails, slices, text boxes, etc). Basically it seems designed to save the entire internal state of a given image processing session for a given image. But once you figure out the minimum requirements to just save a basic image without all the fancy features, in this form it has fewer header fields than a standard Windows BMP file! Only downside is that it uses Big-Endian format, so any datafield that is a 2byte or 4byte integer has to be converted to Big-Endian prior to saving in the file. Also unike most image formats, it stores the color data in planar order (rather than interleaved order), so ALL of the red channel data goes first, then ALL the green channel data, then ALL the blue channel data. This though is very simple to fix in just changing how you Dim (or Redim) your pixel array in VB6.
In case you would like to know what the format is like, and see just how extensive the full specs are, read the attached PDF file. I got it from Adobe's webpage with their official specs http://www.adobe.com/devnet-apps/pho...50577409_72092
and then saving it and taking out the unneeded HTML code (parts for specs on tiff files, the page's table of contents, etc), and then saving the resulting web page to a PDF file (so when I posted it here I didn't need to upload a whole zip file with the CSS and JS files etc, as the PDF file contains all the webpage's needed formatting in one file).