I think an unsatisfactory forward usually happens when something is prototyped(forwarded) but not implemented. I think everything implemented properly in my code, though.
I made a unit to use in a program but the unit is not compiling.
Above implementation, I have a few functions prototyped. They are defined below the "implementation" keyword as I think they should. I copy and pasted the function headers from their definitions to make sure they are exactly the same.
I'm using Delphi 4, btw.
There is about 330 lines of code so it is probably too much to post here. It is documented and quite clear for me, atleast. If someone would be willing to help figure out this bug, please send a message. My email address is greijos@hotmail.com or you can use programmersheaven to contact me too.
thanks for reading about my problem
Comments
if you cant figure it out, send the code to netgert@hotmail.com
: I think an unsatisfactory forward usually happens when something is prototyped(forwarded) but not implemented. I think everything implemented properly in my code, though.
:
: I made a unit to use in a program but the unit is not compiling.
: Above implementation, I have a few functions prototyped. They are defined below the "implementation" keyword as I think they should. I copy and pasted the function headers from their definitions to make sure they are exactly the same.
:
: I'm using Delphi 4, btw.
:
: There is about 330 lines of code so it is probably too much to post here. It is documented and quite clear for me, atleast. If someone would be willing to help figure out this bug, please send a message. My email address is greijos@hotmail.com or you can use programmersheaven to contact me too.
:
: thanks for reading about my problem
:
:
[hr][red][italic][b]N[/b][/red][blue]et[/blue][red][b]G[/b][/red][blue]ert[/italic][/blue][hr]
Here is my code. I know it is a lot(about 330 lines) but I hope someone is willing to figure out the problem.
[code]
unit JGCompression;
{
Author: Josh Greig
Date: June 30, 2004
Purpose:
Providing methods for manipulating JG compressed image files.
}
interface
uses sysutils,graphics;
function SaveBitmapToJGCF(bitmap1: graphics.tbitmap;fn: string): boolean;
function SetExtention(fn,extention: string): string;
const
Threshold = 100;
// a threshold for deciding whether to split a region or not to
implementation
type
pixel = tColor;
PixelArray = array[0..$FFFF] of pixel;
pPixelArray = ^PixelArray;
Colour24 = record
red,green,blue: byte;
end;
// define a record that will basically point to all the pixel data in a bitmap
BitmapReference = record
Width,Height: Cardinal; // dimensions of the bitmap referred to
Rows: array of pPixelarray; // dynamic array of pointers
end;
// this reference can allow for faster access to the pixel data in a tbitmap object
// this is very useful for the pixel manipulation required by the compression algorithms
procedure SaveCompressedPixelData(var f: file; bitmap1: tbitmap);
procedure SaveCompressedRegion(var f: file;
BR: BitmapReference;startX,startY: cardinal;N: byte);
procedure SetReference(var bitmap1: tbitmap;BR: BitmapReference);
function GetAverageColour(var BR: BitmapReference;top,left,size: cardinal): tColor;
function GetColourVarience(var BR: BitmapReference;top,left,size: cardinal;var avgc: tcolor): real;
procedure FreeBitmapReference(var BR: BitmapReference);
function SaveBitmapToJGCF(bitmap1: tbitmap;fn: string): boolean;
{
purpose:
storing a bitmap as a JGC file
inputs:
bitmap = the bitmap to save
fn = name of file
}
var
f: file;
w: word; // a word to temperarily store some values
b: byte; // temperarily stores 8-bit values
const
FormatKey = 'JGCF';
begin
result:=true;
// assign file
AssignFile(f,fn);
try
// rewrite file with a record size of 1
Rewrite(f,1);
except
on EAbstractError do // this exception needs to be changed
begin
result:=false; // indicate failure
end;
end; // end of try-except statement
if result then // if the exception did not occur
begin
// write the header section
begin
BlockWrite(f,FormatKey,4);
w:=0;
BlockWrite(f,w,2); // write the file format version number
w:=bitmap1.width;
BlockWrite(f,w,2); // write the width
w:=bitmap1.height;
BlockWrite(f,w,2); // write the height
b:=24; // bits per pixel
BlockWrite(f,b,1); // write the bits per pixel
// now, the header has been written to file
end;
bitmap1.pixelformat:=pf32bit;
// make sure the pixel data is stored using 32 bits for every pixel
// this assumption is used when using direct pixel data access using pointers
// write the compressed pixel data portion
SaveCompressedPixelData(f,bitmap1);
// close file
Close(f);
result:= true; // indicate success
end;
end;
procedure SaveCompressedPixelData(var f: file; bitmap1: tbitmap);
{
purpose: compresses data and stores it in the file
assumptions:
f is already open in a binary writing mode.
}
var
rx,ry: cardinal;
maxRX,maxRY: cardinal;
BR: BitmapReference;
begin
// make a reference to the bitmap so the data can be manipulated more efficiently
SetReference(bitmap1,BR);
// calculate the number of regions
maxRX:=(BR.width shl 4)+1;
maxRY:=(BR.Height shl 4)+1;
{
"shl 4" is a binary shift left 4 digits.
This is the same as deviding by 16 but more efficient.
}
for rY:=0 to maxRY do
// loop through rows of regions
begin
for rX:=0 to maxRX do
// loop through each region in each row
begin
// for each 16 by 16 region, compress it and save the data to file
SaveCompressedRegion(f,BR,rX shl 4,rY shl 4,16);
end;
end;
FreeBitmapReference(BR);
end;
procedure SaveCompressedRegion(var f: file;
BR: BitmapReference;startX,startY: cardinal;N: byte);
{
purpose: compressing information for a N by N pixel region
inputs:
f = file being written to (must be open in a binary writing mode)
BR = a reference to the bitmap being compressed
startX = coordinate of the left side of the region being compressed
startY = coordinate of the top side of the region being compressed
}
var
c: tcolor;
c24: Colour24;
p: pPixelArray;
begin
if (N=1) then// base case (individual pixel)
begin
p:= BR.Rows[startY];
c := p[startX];
c24.red := c;
c24.green := c shr 8;
c24.blue := c shr 16;
BlockWrite(f,N,1);
BlockWrite(f,c24,3);
end
else // general case
begin
if GetColourVarience(BR,top,left,N,c)>threshold then
begin // if lots of detail is in the region
// devide it up more
N:= N shr 1; // devide size by 2.
// compress each subregion separately
SaveCompressedRegion(f,BR,startX,startY,N);
SaveCompressedRegion(f,BR,startX+N,startY,N);
SaveCompressedRegion(f,BR,startX,startY+N,N);
SaveCompressedRegion(f,BR,startX+N,startY+N,N);
end
else // if very little detail is in the region
begin
// define the colour for the region
c24.red := c;
c24.green := c shr 8;
c24.blue := c shr 16;
BlockWrite(f,N,1); // define the size of the square
BlockWrite(f,c24,3); // define the colour for the square
end;
end;
end;
function GetColourVarience(var BR: BitmapReference;top,left,size: cardinal;avgc: tcolor): real;
{
purpose:
calculating the varience in colours throughout a region
}
var
r,g,b: byte; // average red, green, and blue values
c: tcolor; // average(mean) colour
maxX,maxY: cardinal; // x and y boundaries
x,y: cardinal; // coordinates of pixels
Area: cardinal; // number of pixels in region
total: double; // total of all variances
begin
maxX:=top+size-1;
maxY:=left+size-1;
if (maxX>=BR.Width) then
maxX:=BR.Width-1;
if (maxY>=BR.Height) then
maxY:=BR.Height-1;
avgc:=GetAverageColour(BR,top,left,size);
// extract the red, green and blue values
r:=avgc;
g:=avgc shr 8;
b:=avgc shr 16;
total:=0;
for y:=maxY downto top do
// loop through the rows of pixels
for x:=maxX downto left do
begin
c:=BR.Rows[y][x];
total:=total+
sqr((c and $FF)-r)+ // z-score squared
sqr((c shr 8 and $FF)-g)+ // z-score squared
sqr((c shr 16 and $FF)-b); // z-score squared
end;
Area:=(maxY-top+1)*(maxX-left+1);
result:=total/3/Area;
end;
function GetAverageColour(var BR: BitmapReference;top,left,size: cardinal): tColor;
{
purpose: calculating the average colour for a square region
inputs:
BR = reference to the bitmap containing these picels being averaged
top = top of the region
left = left of the region
size = length of a side of the square region(size must not be 0)
}
var
red,green,blue: cardinal;
Area: cardinal;
c: tcolor;
x,y: cardinal;
maxX,maxY: cardinal;
begin
// initialize the values to 0 before counting up all red, green, and blue values
red:=0;
green:=0;
blue:=0;
maxX:=left+size-1;
maxY:=top+size-1;
if (BR.Height<=maxY) then // if region overlaps bottom of bitmap
maxY:=BR.Height-1;
if (BR.Width<=maxX) then // if region overlaps right side of bitmap
maxX:=BR.Width-1;
for y:=maxY downto top do
for x:=maxX downto left do
begin
// get the colour of the pixel
c := BR.rows[y][x];
// add the red, green, and blue values to the counters
red:=red+(c and $FF);
green:=green+(c shr 8 and $FF);
blue:=blue+(c shr 16 and $FF);
end;
Area:=(maxY-top+1)*(maxX-left+1);
// calculate the number of pixels in the region
result:=((red div Area) and $FF)
or ((green div Area and $FF) shl 8)
or ((blue div Area and $FF) shl 16);
end;
procedure SetReference(var bitmap1: graphics.tbitmap;BR: BitmapReference);
{
BR becomes a reference to bitmap1.
}
var
y: cardinal; // y-coordinate or row number
begin
BR.Height:=bitmap1.height;
BR.Width:=bitmap1.Width;
SetLength(BR.Rows,BR.Height);
for y:=BR.Height-1 downto 0 do
// loop through rows
begin
// for each row, copy the address of pixel data in that row
BR.Rows[y]:=Bitmap1.scanline[y];
end;
end;
procedure FreeBitmapReference(var BR: BitmapReference);
begin
BR.Rows:=nil; // free the array of pointers
end;
function SetExtention(fn,extention: string): string;
{
purpose: setting the extention on the end of a file name
}
var
pos1: integer;
begin
for pos1:=length(fn) downto 1 do
begin
if fn[pos1]='.' then
break; // break the for-loop
end;
if pos1=1 then // if no '.' was found
result:=fn+'.'+extention
else
result:=copy(fn,1,pos1)+extention;
// replace the extention
end; // end of SetExtention
end.
[/code]
:
: Here is my code. I know it is a lot(about 330 lines) but I hope someone is willing to figure out the problem.
:
: [code]
: unit JGCompression;
: {
: Author: Josh Greig
: Date: June 30, 2004
: Purpose:
: Providing methods for manipulating JG compressed image files.
: }
: interface
: uses sysutils,graphics;
:
: function SaveBitmapToJGCF(bitmap1: graphics.tbitmap;fn: string): boolean;
: function SetExtention(fn,extention: string): string;
:
: const
: Threshold = 100;
: // a threshold for deciding whether to split a region or not to
:
: implementation
:
: type
: pixel = tColor;
: PixelArray = array[0..$FFFF] of pixel;
: pPixelArray = ^PixelArray;
:
: Colour24 = record
: red,green,blue: byte;
: end;
:
: // define a record that will basically point to all the pixel data in a bitmap
: BitmapReference = record
: Width,Height: Cardinal; // dimensions of the bitmap referred to
: Rows: array of pPixelarray; // dynamic array of pointers
: end;
: // this reference can allow for faster access to the pixel data in a tbitmap object
: // this is very useful for the pixel manipulation required by the compression algorithms
:
: procedure SaveCompressedPixelData(var f: file; bitmap1: tbitmap);
: procedure SaveCompressedRegion(var f: file;
: BR: BitmapReference;startX,startY: cardinal;N: byte);
: procedure SetReference(var bitmap1: tbitmap;BR: BitmapReference);
: function GetAverageColour(var BR: BitmapReference;top,left,size: cardinal): tColor;
: function GetColourVarience(var BR: BitmapReference;top,left,size: cardinal;var avgc: tcolor): real;
: procedure FreeBitmapReference(var BR: BitmapReference);
:
:
: function SaveBitmapToJGCF(bitmap1: tbitmap;fn: string): boolean;
: {
: purpose:
: storing a bitmap as a JGC file
: inputs:
: bitmap = the bitmap to save
: fn = name of file
: }
: var
: f: file;
: w: word; // a word to temperarily store some values
: b: byte; // temperarily stores 8-bit values
: const
: FormatKey = 'JGCF';
: begin
: result:=true;
: // assign file
: AssignFile(f,fn);
:
: try
: // rewrite file with a record size of 1
: Rewrite(f,1);
: except
: on EAbstractError do // this exception needs to be changed
: begin
: result:=false; // indicate failure
: end;
: end; // end of try-except statement
: if result then // if the exception did not occur
: begin
: // write the header section
: begin
: BlockWrite(f,FormatKey,4);
: w:=0;
: BlockWrite(f,w,2); // write the file format version number
: w:=bitmap1.width;
: BlockWrite(f,w,2); // write the width
: w:=bitmap1.height;
: BlockWrite(f,w,2); // write the height
: b:=24; // bits per pixel
: BlockWrite(f,b,1); // write the bits per pixel
: // now, the header has been written to file
: end;
: bitmap1.pixelformat:=pf32bit;
: // make sure the pixel data is stored using 32 bits for every pixel
: // this assumption is used when using direct pixel data access using pointers
:
:
: // write the compressed pixel data portion
: SaveCompressedPixelData(f,bitmap1);
:
:
: // close file
: Close(f);
: result:= true; // indicate success
: end;
: end;
:
: procedure SaveCompressedPixelData(var f: file; bitmap1: tbitmap);
: {
: purpose: compresses data and stores it in the file
: assumptions:
: f is already open in a binary writing mode.
: }
: var
: rx,ry: cardinal;
: maxRX,maxRY: cardinal;
: BR: BitmapReference;
: begin
: // make a reference to the bitmap so the data can be manipulated more efficiently
: SetReference(bitmap1,BR);
:
: // calculate the number of regions
: maxRX:=(BR.width shl 4)+1;
: maxRY:=(BR.Height shl 4)+1;
: {
: "shl 4" is a binary shift left 4 digits.
: This is the same as deviding by 16 but more efficient.
: }
: for rY:=0 to maxRY do
: // loop through rows of regions
: begin
: for rX:=0 to maxRX do
: // loop through each region in each row
: begin
: // for each 16 by 16 region, compress it and save the data to file
: SaveCompressedRegion(f,BR,rX shl 4,rY shl 4,16);
: end;
: end;
: FreeBitmapReference(BR);
: end;
:
: procedure SaveCompressedRegion(var f: file;
: BR: BitmapReference;startX,startY: cardinal;N: byte);
: {
: purpose: compressing information for a N by N pixel region
: inputs:
: f = file being written to (must be open in a binary writing mode)
: BR = a reference to the bitmap being compressed
: startX = coordinate of the left side of the region being compressed
: startY = coordinate of the top side of the region being compressed
: }
: var
: c: tcolor;
: c24: Colour24;
: p: pPixelArray;
: begin
: if (N=1) then// base case (individual pixel)
: begin
: p:= BR.Rows[startY];
: c := p[startX];
: c24.red := c;
: c24.green := c shr 8;
: c24.blue := c shr 16;
:
: BlockWrite(f,N,1);
: BlockWrite(f,c24,3);
: end
: else // general case
: begin
: if GetColourVarience(BR,top,left,N,c)>threshold then
: begin // if lots of detail is in the region
: // devide it up more
: N:= N shr 1; // devide size by 2.
:
: // compress each subregion separately
: SaveCompressedRegion(f,BR,startX,startY,N);
: SaveCompressedRegion(f,BR,startX+N,startY,N);
: SaveCompressedRegion(f,BR,startX,startY+N,N);
: SaveCompressedRegion(f,BR,startX+N,startY+N,N);
: end
: else // if very little detail is in the region
: begin
: // define the colour for the region
: c24.red := c;
: c24.green := c shr 8;
: c24.blue := c shr 16;
: BlockWrite(f,N,1); // define the size of the square
: BlockWrite(f,c24,3); // define the colour for the square
: end;
: end;
: end;
:
: function GetColourVarience(var BR: BitmapReference;top,left,size: cardinal;avgc: tcolor): real;
: {
: purpose:
: calculating the varience in colours throughout a region
: }
: var
: r,g,b: byte; // average red, green, and blue values
: c: tcolor; // average(mean) colour
: maxX,maxY: cardinal; // x and y boundaries
: x,y: cardinal; // coordinates of pixels
: Area: cardinal; // number of pixels in region
: total: double; // total of all variances
: begin
: maxX:=top+size-1;
: maxY:=left+size-1;
: if (maxX>=BR.Width) then
: maxX:=BR.Width-1;
: if (maxY>=BR.Height) then
: maxY:=BR.Height-1;
: avgc:=GetAverageColour(BR,top,left,size);
:
: // extract the red, green and blue values
: r:=avgc;
: g:=avgc shr 8;
: b:=avgc shr 16;
:
: total:=0;
: for y:=maxY downto top do
: // loop through the rows of pixels
: for x:=maxX downto left do
: begin
: c:=BR.Rows[y][x];
: total:=total+
: sqr((c and $FF)-r)+ // z-score squared
: sqr((c shr 8 and $FF)-g)+ // z-score squared
: sqr((c shr 16 and $FF)-b); // z-score squared
: end;
: Area:=(maxY-top+1)*(maxX-left+1);
: result:=total/3/Area;
: end;
:
: function GetAverageColour(var BR: BitmapReference;top,left,size: cardinal): tColor;
: {
: purpose: calculating the average colour for a square region
: inputs:
: BR = reference to the bitmap containing these picels being averaged
: top = top of the region
: left = left of the region
: size = length of a side of the square region(size must not be 0)
: }
: var
: red,green,blue: cardinal;
: Area: cardinal;
: c: tcolor;
: x,y: cardinal;
: maxX,maxY: cardinal;
: begin
: // initialize the values to 0 before counting up all red, green, and blue values
: red:=0;
: green:=0;
: blue:=0;
: maxX:=left+size-1;
: maxY:=top+size-1;
:
: if (BR.Height<=maxY) then // if region overlaps bottom of bitmap
: maxY:=BR.Height-1;
: if (BR.Width<=maxX) then // if region overlaps right side of bitmap
: maxX:=BR.Width-1;
:
: for y:=maxY downto top do
: for x:=maxX downto left do
: begin
: // get the colour of the pixel
: c := BR.rows[y][x];
:
: // add the red, green, and blue values to the counters
: red:=red+(c and $FF);
: green:=green+(c shr 8 and $FF);
: blue:=blue+(c shr 16 and $FF);
: end;
: Area:=(maxY-top+1)*(maxX-left+1);
: // calculate the number of pixels in the region
:
: result:=((red div Area) and $FF)
: or ((green div Area and $FF) shl 8)
: or ((blue div Area and $FF) shl 16);
: end;
:
: procedure SetReference(var bitmap1: graphics.tbitmap;BR: BitmapReference);
: {
: BR becomes a reference to bitmap1.
: }
: var
: y: cardinal; // y-coordinate or row number
: begin
: BR.Height:=bitmap1.height;
: BR.Width:=bitmap1.Width;
: SetLength(BR.Rows,BR.Height);
: for y:=BR.Height-1 downto 0 do
: // loop through rows
: begin
: // for each row, copy the address of pixel data in that row
: BR.Rows[y]:=Bitmap1.scanline[y];
: end;
: end;
:
: procedure FreeBitmapReference(var BR: BitmapReference);
: begin
: BR.Rows:=nil; // free the array of pointers
: end;
:
: function SetExtention(fn,extention: string): string;
: {
: purpose: setting the extention on the end of a file name
: }
: var
: pos1: integer;
: begin
: for pos1:=length(fn) downto 1 do
: begin
: if fn[pos1]='.' then
: break; // break the for-loop
: end;
: if pos1=1 then // if no '.' was found
: result:=fn+'.'+extention
: else
: result:=copy(fn,1,pos1)+extention;
: // replace the extention
: end; // end of SetExtention
:
: end.
: [/code]
:
Procedure declarations within the implementation section must be either marked by the "forward" directive, or must be implemented after the declaration. So the first SaveCompressedPixelData() must include the forward directive, as well as the other forwarded declarations.
: Procedure declarations within the implementation section must be either marked by the "forward" directive, or must be implemented after the declaration. So the first SaveCompressedPixelData() must include the forward directive, as well as the other forwarded declarations.
:
It works!
thanks a lot
netgert suggested that in an email before and I tried using forward with one function but it gave the same unsatisfactory forward error for that function. I just tried using the forward with all functions and it works fine now.