### ----------------------------------------------------
### -- GD::Raw
### -- Licenses: Artistic-2.0
### -- Authors: Dagur Valberg Johannsson, Raku Community
### -- File: lib/GD/Raw.rakumod
### ----------------------------------------------------
### -- Chunk 2 of 2
3, $.tcm64, $.tcm65, $.tcm66, $.tcm67, $.tcm68, $.tcm69, $.tcm70, $.tcm71, $.tcm72, $.tcm73, $.tcm74, $.tcm75, $.tcm76, $.tcm77, $.tcm78, $.tcm79, $.tcm80, $.tcm81, $.tcm82, $.tcm83, $.tcm84, $.tcm85, $.tcm86, $.tcm87, $.tcm88, $.tcm89, $.tcm90, $.tcm91, $.tcm92, $.tcm93, $.tcm94, $.tcm95, $.tcm96, $.tcm97, $.tcm98, $.tcm99, $.tcm100, $.tcm101, $.tcm102, $.tcm103, $.tcm104, $.tcm105, $.tcm106, $.tcm107, $.tcm108, $.tcm109, $.tcm110, $.tcm111, $.tcm112, $.tcm113, $.tcm114, $.tcm115, $.tcm116, $.tcm117, $.tcm118, $.tcm119, $.tcm120, $.tcm121, $.tcm122, $.tcm123, $.tcm124, $.tcm125, $.tcm126, $.tcm127, $.tcm128, $.tcm129, $.tcm130, $.tcm131, $.tcm132, $.tcm133, $.tcm134, $.tcm135, $.tcm136, $.tcm137, $.tcm138, $.tcm139, $.tcm140, $.tcm141, $.tcm142, $.tcm143, $.tcm144, $.tcm145, $.tcm146, $.tcm147, $.tcm148, $.tcm149, $.tcm150, $.tcm151, $.tcm152, $.tcm153, $.tcm154, $.tcm155, $.tcm156, $.tcm157, $.tcm158, $.tcm159, $.tcm160, $.tcm161, $.tcm162, $.tcm163, $.tcm164, $.tcm165, $.tcm166, $.tcm167, $.tcm168, $.tcm169, $.tcm170, $.tcm171, $.tcm172, $.tcm173, $.tcm174, $.tcm175, $.tcm176, $.tcm177, $.tcm178, $.tcm179, $.tcm180, $.tcm181, $.tcm182, $.tcm183, $.tcm184, $.tcm185, $.tcm186, $.tcm187, $.tcm188, $.tcm189, $.tcm190, $.tcm191, $.tcm192, $.tcm193, $.tcm194, $.tcm195, $.tcm196, $.tcm197, $.tcm198, $.tcm199, $.tcm200, $.tcm201, $.tcm202, $.tcm203, $.tcm204, $.tcm205, $.tcm206, $.tcm207, $.tcm208, $.tcm209, $.tcm210, $.tcm211, $.tcm212, $.tcm213, $.tcm214, $.tcm215, $.tcm216, $.tcm217, $.tcm218, $.tcm219, $.tcm220, $.tcm221, $.tcm222, $.tcm223, $.tcm224, $.tcm225, $.tcm226, $.tcm227, $.tcm228, $.tcm229, $.tcm230, $.tcm231, $.tcm232, $.tcm233, $.tcm234, $.tcm235, $.tcm236, $.tcm237, $.tcm238, $.tcm239, $.tcm240, $.tcm241, $.tcm242, $.tcm243, $.tcm244, $.tcm245, $.tcm246, $.tcm247, $.tcm248, $.tcm249, $.tcm250, $.tcm251, $.tcm252, $.tcm253, $.tcm254, $.tcm255, );

	has int32 $.styleLength;
	has int32 $.stylePos;
	has OpaquePointer $.style;
	has int32 $.interlace;
	has int32 $.thick;
has int32 ($.alpha0, $.alpha1, $.alpha2, $.alpha3, $.alpha4, $.alpha5, $.alpha6, $.alpha7, $.alpha8, $.alpha9, $.alpha10, $.alpha11, $.alpha12, $.alpha13, $.alpha14, $.alpha15, $.alpha16, $.alpha17, $.alpha18, $.alpha19, $.alpha20, $.alpha21, $.alpha22, $.alpha23, $.alpha24, $.alpha25, $.alpha26, $.alpha27, $.alpha28, $.alpha29, $.alpha30, $.alpha31, $.alpha32, $.alpha33, $.alpha34, $.alpha35, $.alpha36, $.alpha37, $.alpha38, $.alpha39, $.alpha40, $.alpha41, $.alpha42, $.alpha43, $.alpha44, $.alpha45, $.alpha46, $.alpha47, $.alpha48, $.alpha49, $.alpha50, $.alpha51, $.alpha52, $.alpha53, $.alpha54, $.alpha55, $.alpha56, $.alpha57, $.alpha58, $.alpha59, $.alpha60, $.alpha61, $.alpha62, $.alpha63, $.alpha64, $.alpha65, $.alpha66, $.alpha67, $.alpha68, $.alpha69, $.alpha70, $.alpha71, $.alpha72, $.alpha73, $.alpha74, $.alpha75, $.alpha76, $.alpha77, $.alpha78, $.alpha79, $.alpha80, $.alpha81, $.alpha82, $.alpha83, $.alpha84, $.alpha85, $.alpha86, $.alpha87, $.alpha88, $.alpha89, $.alpha90, $.alpha91, $.alpha92, $.alpha93, $.alpha94, $.alpha95, $.alpha96, $.alpha97, $.alpha98, $.alpha99, $.alpha100, $.alpha101, $.alpha102, $.alpha103, $.alpha104, $.alpha105, $.alpha106, $.alpha107, $.alpha108, $.alpha109, $.alpha110, $.alpha111, $.alpha112, $.alpha113, $.alpha114, $.alpha115, $.alpha116, $.alpha117, $.alpha118, $.alpha119, $.alpha120, $.alpha121, $.alpha122, $.alpha123, $.alpha124, $.alpha125, $.alpha126, $.alpha127, $.alpha128, $.alpha129, $.alpha130, $.alpha131, $.alpha132, $.alpha133, $.alpha134, $.alpha135, $.alpha136, $.alpha137, $.alpha138, $.alpha139, $.alpha140, $.alpha141, $.alpha142, $.alpha143, $.alpha144, $.alpha145, $.alpha146, $.alpha147, $.alpha148, $.alpha149, $.alpha150, $.alpha151, $.alpha152, $.alpha153, $.alpha154, $.alpha155, $.alpha156, $.alpha157, $.alpha158, $.alpha159, $.alpha160, $.alpha161, $.alpha162, $.alpha163, $.alpha164, $.alpha165, $.alpha166, $.alpha167, $.alpha168, $.alpha169, $.alpha170, $.alpha171, $.alpha172, $.alpha173, $.alpha174, $.alpha175, $.alpha176, $.alpha177, $.alpha178, $.alpha179, $.alpha180, $.alpha181, $.alpha182, $.alpha183, $.alpha184, $.alpha185, $.alpha186, $.alpha187, $.alpha188, $.alpha189, $.alpha190, $.alpha191, $.alpha192, $.alpha193, $.alpha194, $.alpha195, $.alpha196, $.alpha197, $.alpha198, $.alpha199, $.alpha200, $.alpha201, $.alpha202, $.alpha203, $.alpha204, $.alpha205, $.alpha206, $.alpha207, $.alpha208, $.alpha209, $.alpha210, $.alpha211, $.alpha212, $.alpha213, $.alpha214, $.alpha215, $.alpha216, $.alpha217, $.alpha218, $.alpha219, $.alpha220, $.alpha221, $.alpha222, $.alpha223, $.alpha224, $.alpha225, $.alpha226, $.alpha227, $.alpha228, $.alpha229, $.alpha230, $.alpha231, $.alpha232, $.alpha233, $.alpha234, $.alpha235, $.alpha236, $.alpha237, $.alpha238, $.alpha239, $.alpha240, $.alpha241, $.alpha242, $.alpha243, $.alpha244, $.alpha245, $.alpha246, $.alpha247, $.alpha248, $.alpha249, $.alpha250, $.alpha251, $.alpha252, $.alpha253, $.alpha254, $.alpha255, );

	has int32 $.trueColor;
	has OpaquePointer $.tpixels;
	has int32 $.alphaBlendingFlag;
    has int32 $.saveAlphaFlag;
	has int32 $.AA;
	has int32 $.AA_color;
	has int32 $.AA_dont_blend;

	has int32 $.cx1;
	has int32 $.cy1;
	has int32 $.cx2;
	has int32 $.cy2;

	has uint32 $.res_x;
	has uint32 $.res_y;

	has int32 $.paletteQuantizationMethod;
	has int32 $.paletteQuantizationSpeed;
	has int32 $.paletteQuantizationMinQuality;
	has int32 $.paletteQuantizationMaxQuality;
	has int32 $.interpolation_id;
}
class gdImagePtr is repr('CStruct') is gdImageStruct { }

constant gdAntiAliased is export = -7;

sub gdImageSX($img) is export {
    return $img.sx;
}

sub gdImageSY($img) is export {
    return $img.sy;
}

sub gdImageColorsTotal($im) { $im.colorsTotal }
sub gdImageRed($im, Int $c) is export {
    $im.trueColor ?? gdTrueColorGetRed($c) !! "\$im.red$c".EVAL
}
sub gdImageGreen($im, Int $c) is export {
    $im.trueColor ?? gdTrueColorGetGreen($c) !! "\$im.green$c".EVAL
}
sub gdImageBlue($im, Int $c) is export {
    $im.trueColor ?? gdTrueColorGetBlue($c) !! "\$im.blue$c".EVAL
}
sub gdImageAlpha($im, Int $c) is export {
    $im.trueColor ?? gdTrueColorGetAlpha($c) !! "\$im.alpha$c".EVAL
}

sub fopen( Str $filename, Str $mode )
    returns OpaquePointer
    is native(LIB) is export { ... }

sub fclose(OpaquePointer)
    is native(LIB) is export { ... }

sub gdImageCreateFromJpeg(OpaquePointer $file)
    returns gdImagePtr
    is native(LIB) is export { ... }

sub gdImageCreateFromPng(OpaquePointer $file)
    returns gdImagePtr
    is native(LIB) is export { ... }

sub gdImageCreateFromGif(OpaquePointer $file)
    returns gdImagePtr
    is native(LIB) is export { ... }

sub gdImageCreateFromBmp(OpaquePointer $file)
    returns gdImagePtr
    is native(LIB) is export { ... }

sub gdImageCreateTrueColor(int32, int32)
    returns gdImagePtr
    is native(LIB) is export { ... }

sub gdImageCreate(int32, int32)
    returns gdImagePtr
    is native(LIB) is export { ... }

sub gdImageCreatePalette($x, $y) is export { gdImageCreate($x, $y) }

sub gdFree(OpaquePointer $m)
    # returns void
    is native(LIB) is export {*}

sub gdImageJpeg(gdImageStruct $image, OpaquePointer $file, int32 $quality where { $_ <= 95 })
    is native(LIB) is export { ... }

sub gdImagePng(gdImageStruct $image, OpaquePointer $file)
    is native(LIB) is export { ... }

sub gdImageGif(gdImageStruct $im, OpaquePointer $f)
    is native(LIB) is export { ... }

sub gdImageBmp(gdImageStruct $im, OpaquePointer $f, int32)
    is native(LIB) is export { ... }

sub gdImageArc (gdImagePtr $im, int32 $cx, int32 $cy, int32 $w, int32 $h,
    int32 $s, int32 $e, int32 $color)
    # returns void
    is native(LIB) is export {*}

sub gdImageFilledEllipse (gdImagePtr $im, int32 $cx, int32 $cy, int32 $w, int32 $h,
                                        int32 $color)
    # returns void
    is native(LIB) is export {*}

sub gdImageCopyResized(gdImageStruct $dst, gdImageStruct $src,
        int32 $dstX, int32 $dstY,
        int32 $srcX, int32 $srcY,
        int32 $dstW, int32 $dstH, int32 $srcW, int32 $srcH)
    is native(LIB) is export { ... }

sub gdImageCopyResampled(gdImageStruct $dst, gdImageStruct $src,
    int32 $dstX, int32 $dstY, int32 $srcX, int32 $srcY, int32 $dstW, int32 $dstH, int32 $srcW, int32 $srcH)
    is native(LIB) is export { ... }

sub gdImageSetAntiAliased (gdImagePtr $im, int32 $c)
    #returns void
    is native(LIB) is export {*}

enum gdPixelateMode (
	GD_PIXELATE_UPPERLEFT => 0,
	GD_PIXELATE_AVERAGE => 1
);

sub gdImagePixelate(gdImagePtr $im, int32 $block_size, uint32 $mode)
    returns int32
    is native(LIB) is export {*}

sub gdImageScatter(gdImagePtr $im, int32 $sub, int32 $plus)
    returns int32
    is native(LIB) is export {*}

sub gdImageSmooth(gdImagePtr $im, num32 $weight)
    returns int32
    is native(LIB) is export {*}

sub gdImageMeanRemoval(gdImagePtr $im)
    returns int32
    is native(LIB) is export {*}

sub gdImageEmboss(gdImagePtr $im)
    returns int32
    is native(LIB) is export {*}

sub gdImageGaussianBlur(gdImagePtr $im)
    returns int32
    is native(LIB) is export {*}

sub gdImageEdgeDetectQuick(gdImagePtr $src)
    returns int32
    is native(LIB) is export {*}

sub gdImageSelectiveBlur(gdImagePtr $src)
    returns int32
    is native(LIB) is export {*}

sub gdImageColor(gdImagePtr $src, int32 $red, int32 $green, int32 $blue, int32 $alpha)
    returns int32
    is native(LIB) is export {*}

sub gdImageContrast(gdImagePtr $src, num64 $contrast)
    returns int32
    is native(LIB) is export {*}

sub gdImageBrightness(gdImagePtr $src, int32 $brightness)
    returns int32
    is native(LIB) is export {*}

sub gdImageGrayScale(gdImagePtr $src)
    returns int32
    is native(LIB) is export {*}

sub gdImageNegate(gdImagePtr $src)
    returns int32
    is native(LIB) is export {*}

sub gdImageSetThickness(gdImagePtr $im, int32 $thickness)
    #returns void
    is native(LIB) is export {*}

sub gdImageDestroy(gdImageStruct)
    is native(LIB) is export { ... }

sub gdImageGetTrueColorPixel(gdImagePtr $im, int32 $x, int32 $y)
    returns int32
    is native(LIB) is export {*}

sub gdImageSetPixel(gdImagePtr $im, int32 $x, int32 $y, int32 $color)
    # returns void
    is native(LIB) is export {*}

sub gdImageGetPixel(gdImagePtr $im, int32 $x, int32 $y)
    returns int32
    is native(LIB) is export {*}

sub gdImageLine (gdImagePtr $im, int32 $x1, int32 $y1, int32 $x2, int32 $y2, int32 $color)
    #returns void
    is native(LIB) is export {*}


sub gdTrueColorAlpha($r, $g, $b, $a) is export {
    ((($a) +< 24) +
	 (($r) +< 16) +
	 (($g) +< 8) +
	 ($b));
}

sub gdImageColorAllocate(gdImagePtr $im, int32 $r, int32 $g, int32 $b)
    returns int32
    is native(LIB) is export {*}

sub gdImageFilledRectangle(gdImagePtr $im, int32 $x1, int32 $y1, int32 $x2, int32 $y2, int32 $color)
    #returns void
    is native(LIB) is export {*}

class gdPoint is repr('CStruct') is export {
    has int32 $.x is rw = 0;
    has int32 $.y is rw = 0;
}

class gdPointPtr is repr('CStruct') is gdPoint { }

## Re-implement gdImagePolygon until NativeCall has a way
## to pass array of gdPointPtr
sub gdImagePolygon(gdImagePtr $im, @p, int32 $n, int32 $c) is export
{
	return if $n <= 0;

	gdImageLine($im, @p[0].x, @p[0].y, @p[$n - 1].x, @p[$n - 1].y, $c);
	gdImageOpenPolygon($im, @p, $n, $c);
}

sub gdImageOpenPolygon(gdImagePtr $im, @p, int32 $n, int32 $c) is export
{
	return if $n <= 0;

	my $lx = @p[0].x;
	my $ly = @p[0].y;
    for 1..($n-1) -> $i {
        my ($x, $y) = (@p[$i].x, @p[$i].y);
        gdImageLine($im, $lx, $ly, $x, $y, $c);
        ($lx, $ly) = ($x, $y);
    }
}

## Re-implementation - until there is a way to properly pass gdPointPtr array with NativeCall.
##
## This re-implementation has some hacks. Some sanity checks are removed. It does
## not allocate and modify im.polyInts as it does in the original implementation.
##
## It does however pass the unittests from libgd, so I guess it's OK-ish
sub gdImageFilledPolygon($im is rw, @p, int32 $n, int32 $c) is export {

    return if $n <= 0;

    my $fill_color = $c == gdAntiAliased ?? $im.AA_color !! $c;

    sub gdMalloc($size) {
        sub malloc(uint32) returns OpaquePointer is native(LIB) {*}
        return malloc($size);
    }

    sub gdRealloc($ptr, uint32 $size)
    {
        sub realloc(OpaquePointer $ptr, uint32 $size)
            returns OpaquePointer is native(LIB) {*}

        return realloc($ptr, $size);
    }

    sub gdReallocEx ($ptr, $size)
    {
        my $newPtr = gdRealloc($ptr, $size);
        gdFree $ptr if (!$newPtr && $ptr);
        return $newPtr;
    }

    my $sizeofint = 32;

	if (!$im.polyAllocated) {
        #$im.polyInts = gdMalloc($sizeofint * $n);
        #if (!$im.polyInts) {
		#	return;
		#}
        #$im.polyAllocated = $n;
	}
	if ($im.polyAllocated < $n) {
        #while ($im.polyAllocated < $n) {
		#	$im.polyAllocated *= 2;
		#}
		#$im.polyInts = gdReallocEx($im.polyInts, $sizeofint * $im.polyAllocated);
		#return unless $im.polyInts;
	}
	my $miny = @p[0].y;
	my $maxy = @p[0].y;
	loop (my $i = 1; ($i < $n); $i++) {
		if (@p[$i].y < $miny) {
			$miny = @p[$i].y;
		}
		if (@p[$i].y > $maxy) {
			$maxy = @p[$i].y;
		}
	}
	my $pmaxy = $maxy;
    # 2.0.16: Optimization by Ilia Chipitsine -- don't waste time offscreen */
    # 2.0.26: clipping rectangle is even better
	if ($miny < $im.cy1) {
		$miny = $im.cy1;
	}
	if ($maxy > $im.cy2) {
		$maxy = $im.cy2;
	}
    # Fix in 1.3: count a vertex only once
	loop (my $y = $miny; ($y <= $maxy); $y++) {
		my $ints = 0;
        my @polyInts; # HACK
		loop (my $i = 0; ($i < $n); $i++) {
            my ($x1, $x2);
            my $ind1 = $i ?? $i - 1 !! $n - 1;
            my $ind2 = $i ?? $i !! 0;
			my $y1 = @p[$ind1].y;
			my $y2 = @p[$ind2].y;
			if ($y1 < $y2) {
				$x1 = @p[$ind1].x;
				$x2 = @p[$ind2].x;
			}
            elsif ($y1 > $y2) {
				$y2 = @p[$ind1].y;
				$y1 = @p[$ind2].y;
				$x2 = @p[$ind1].x;
				$x1 = @p[$ind2].x;
			} else {
				next;
			}

            # Do the following math as float intermediately, and round to ensure
            # that Polygon and FilledPolygon for the same set of points have the
            # same footprint.

			if (($y >= $y1) && ($y < $y2)) {
				@polyInts[$ints++] = floor ( (($y - $y1) * ($x2 - $x1)) /
				                               ($y2 - $y1) + 0.5 + $x1);
			} elsif (($y == $pmaxy) && ($y == $y2)) {
				@polyInts[$ints++] = $x2;
			}
		}

        #  2.0.26: polygons pretty much always have less than 100 points,
		#  and most of the time they have considerably less. For such trivial
		#  cases, insertion sort is a good choice. Also a good choice for
		#  future implementations that may wish to indirect through a table.
		loop ($i = 1; ($i < $ints); $i++) {
			my $index = @polyInts[$i];
			my $j = $i;
			while (($j > 0) && (@polyInts[$j - 1] > $index)) {
				@polyInts[$j] = @polyInts[$j - 1];
				$j--;
			}
			@polyInts[$j] = $index;
		}
		loop ($i = 0; ($i < ($ints - 1)); $i += 2) {
            # 2.0.29: back to gdImageLine to prevent segfaults when
            #performing a pattern fill
            gdImageLine($im, @polyInts[$i], $y, @polyInts[$i + 1], $y,
            $fill_color);
		}
	}
    # If we are drawing this AA, then redraw the border with AA lines.
    # This doesn't work as well as I'd like, but it doesn't clash either.
	if $c == gdAntiAliased {
		gdImagePolygon($im, @p, $n, $c);
	}
}


sub gdImageColorExactAlpha(gdImagePtr $im, int32 $r, int32 $g, int32 $b, int32 $a)
    returns int32
    is native(LIB) is export {*}

sub gdImageColorResolve(gdImagePtr $im, int32 $r, int32 $g, int32 $b)
    returns int32
    is native(LIB) is export {*}

# Based on gdImageColorExactAlpha and gdImageColorClosestAlpha
sub gdImageColorResolveAlpha(gdImagePtr $im, int32 $r, int32 $g, int32 $b, int32 $a)
    returns int32
    is native(LIB) is export {*}

sub gdImageSetInterpolationMethod(gdImagePtr $im, int32 $id) #gdInterpolationMethod $id)
    returns int32
    is native(LIB) is export {*}

# Segfaults with GD 2.1 (for me). Works with 2.2
sub gdImageScale(gdImagePtr $src, uint32 $new_width, uint32 $new_height)
    returns gdImagePtr
    is native(LIB) is export {*}

sub gdImageRotateInterpolated(gdImagePtr $src, num32 $angle, int32 $bgcolor)
    returns gdImagePtr
    is native(LIB) is export {*}


# Need GD 2.2 for these.
sub gdMajorVersion()
    returns int32
    is native(LIB) is export {*}

sub gdMinorVersion()
    returns int32
    is native(LIB) is export {*}

sub gdReleaseVersion()
    returns int32
    is native(LIB) is export {*}
sub gdExtraVersion(void)
    returns Str
    is native(LIB) is export {*}

sub gdVersionString()
    returns Str
    is native(LIB) is export {*}

sub gdImageCopyGaussianBlurred(gdImagePtr $src, int32 $radius, num64 $sigma)
    returns gdImagePtr
    is native(LIB) is export {*}

=begin pod

=head1 NAME

GD::Raw - Low level language bindings to GD Graphics Library

=head1 SYNOPSIS

=begin code :lang<raku>

use GD::Raw;

my $fh = fopen("my-image.png", "rb");
my $img = gdImageCreateFromPng($fh);
LEAVE gdImageDestroy($_) with $img;

say "Image resolution is ", gdImageSX($img), "x", gdImageSX($img);

=end code

=head1 DESCRIPTION

C<GD::Raw> is a low level language bindings to LibGD. It does not attempt to
provide you with an rakuish interface, but tries to stay as close to its C<C>
origin as possible.

LibGD is large and this module far from covers it all. Feel free to add anything
your missing and submit a pull request!

=head1 AUTHORS

=item Dagur Valberg Johannsson
=item Raku Community

=head1 COPYRIGHT AND LICENSE

Copyright 2013 - 2018 Dagur Valberg Johannsson

Copyright 2024 Raku Community

This library is free software; you can redistribute it and/or modify it under the Artistic License 2.0.

=end pod

# vim: expandtab shiftwidth=4


