Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 31 additions & 41 deletions src/Peachpie.Library.Graphics/Exif.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ public static PhpArray exif_read_data(Context ctx, string filename, string secti
//array.Add("FileDateTime", (int)File.GetCreationTime(filename).ToOADate());
array.Add("FileSize", (int)bytes.Length);

IImageInfo image;
ImageInfo image;

using (var ms = new MemoryStream(bytes))
{
Expand Down Expand Up @@ -130,9 +130,8 @@ static PhpValue ExifValueToPhpValue(object value)
{
if (value != null)
{
if (value is Array)
if (value is Array arr)
{
var arr = (Array)value;
var phparr = new PhpArray(arr.Length);

for (int i = 0; i < arr.Length; i++)
Expand Down Expand Up @@ -171,15 +170,15 @@ static bool TryAsDouble(object value, out double dval)
{
dval = 0.0;

if (value is float)
if (value is float f)
{
dval = (float)value;
dval = f;
return true;
}

if (value is double)
if (value is double d)
{
dval = (double)value;
dval = d;
return true;
}

Expand All @@ -190,45 +189,45 @@ static bool TryAsLong(object value, out long ival)
{
ival = 0;

if (value is int)
if (value is int i)
{
ival = (int)value;
ival = i;
return true;
}

if (value is long)
if (value is long l)
{
ival = (long)value;
ival = l;
return true;
}

if (value is uint)
if (value is uint u)
{
ival = (uint)value;
ival = u;
return true;
}

if (value is byte)
if (value is byte b)
{
ival = (byte)value;
ival = b;
return true;
}

if (value is sbyte)
if (value is sbyte sb)
{
ival = (sbyte)value;
ival = sb;
return true;
}

if (value is short)
if (value is short s)
{
ival = (short)value;
ival = s;
return true;
}

if (value is ushort)
if (value is ushort us)
{
ival = (ushort)value;
ival = us;
return true;
}

Expand Down Expand Up @@ -260,14 +259,7 @@ public static string exif_tagname(int index)
//}
//return null;

if (GetExifTagMap().TryGetValue((ushort)index, out var name))
{
return name;
}
else
{
return null;
}
return GetExifTagMap().GetValueOrDefault((ushort)index);
}

/// <summary>
Expand All @@ -284,7 +276,7 @@ Dictionary<ushort, string> BuildMap()
var props = typeof(ExifTag).GetProperties();
foreach (var p in props)
{
if (p.GetMethod.IsStatic && p.GetValue(null) is ExifTag exiftag)
if (p.GetMethod?.IsStatic == true && p.GetValue(null) is ExifTag exiftag)
{
map[(ushort)exiftag] = exiftag.ToString();
}
Expand Down Expand Up @@ -374,22 +366,20 @@ public static PhpString exif_thumbnail(Context ctx, string filename, PhpAlias wi
return default(PhpString);

// get thumbnail from <filename>'s content:
using (var ms = new MemoryStream(bytes))
try
{
try
//using (var image = Image.Load(bytes.AsSpan()))
{
// TODO: Image.Identify needs a new overload that returns the format.
using (var image = Image.Load(ms, out format))
{
// return byte[] ~ image.MetaData.ExifProfile{ this.data, this.thumbnailOffset, this.thumbnailLength }
thumbnail = image.Metadata.ExifProfile.CreateThumbnail<Rgba32>();
}
}
catch
{
return default(PhpString);
var imageInfo = Image.Identify(bytes.AsSpan());
// return byte[] ~ image.MetaData.ExifProfile{ this.data, this.thumbnailOffset, this.thumbnailLength }
imageInfo.Metadata.ExifProfile.TryCreateThumbnail<Rgba32>(out thumbnail);
}
}
catch
{
return default(PhpString);
}

if (thumbnail == null)
{
Expand Down
112 changes: 58 additions & 54 deletions src/Peachpie.Library.Graphics/FloodFillProcessor{TPixel}.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,69 +35,73 @@ protected override void OnFrameApply(ImageFrame<TPixel> source)
//var pixelSpan = source.GetPixelSpan();
//int rowLength = source.Width;

var segmentQueue = new Queue<(Point point, int rightEdge)>();
segmentQueue.Enqueue((_startPoint, _startPoint.X));

while (segmentQueue.Count > 0)
source.ProcessPixelRows(accessor =>
{
var (currentPoint, rightEdge) = segmentQueue.Dequeue();
var currentY = currentPoint.Y;
var currentX = currentPoint.X;

var rowSpan = source.GetPixelRowSpan(currentY);

int leftEdge;
leftEdge = currentX;
var segmentQueue = new Queue<(Point point, int rightEdge)>();
segmentQueue.Enqueue((_startPoint, _startPoint.X));

// Filling until reaching a border of specified color
if (_toBorder)
while (segmentQueue.Count > 0)
{
// Get the row segment to be colored
while (rightEdge + 1 < source.Width)
{
var edgeColor = GetPixel(rowSpan, rightEdge + 1);
if (edgeColor.Equals(_borderColor) || edgeColor.Equals(_fillColor))
break;
var (currentPoint, rightEdge) = segmentQueue.Dequeue();
var currentY = currentPoint.Y;
var currentX = currentPoint.X;

var rowSpan = accessor.GetRowSpan(currentY);
int leftEdge;
leftEdge = currentX;

rightEdge++;
// Filling until reaching a border of specified color
if (_toBorder)
{
// Get the row segment to be colored
while (rightEdge + 1 < source.Width)
{
var edgeColor = GetPixel(rowSpan, rightEdge + 1);
if (edgeColor.Equals(_borderColor) || edgeColor.Equals(_fillColor))
break;

rightEdge++;
}
while (leftEdge - 1 < source.Width)
{
var edgeColor = GetPixel(rowSpan, leftEdge - 1);
if (edgeColor.Equals(_borderColor) || edgeColor.Equals(_fillColor))
break;

leftEdge--;
}

// Actually color the row
SetPixelRow(rowSpan, leftEdge, rightEdge, _fillColor);

// Add the segments to be filled above and below to the queue
if (currentY > 0)
AddFillingSegmentsToQueueWithBorder(floodFrom, accessor.GetRowSpan(currentY - 1), segmentQueue, leftEdge, rightEdge, currentY - 1);
if (currentY + 1 < source.Height)
AddFillingSegmentsToQueueWithBorder(floodFrom, accessor.GetRowSpan(currentY + 1), segmentQueue, leftEdge, rightEdge, currentY + 1);
}
while (leftEdge - 1 < source.Width)
else
// Filling whole region of same color
{
var edgeColor = GetPixel(rowSpan, leftEdge - 1);
if (edgeColor.Equals(_borderColor) || edgeColor.Equals(_fillColor))
break;

leftEdge--;
// Get the row segment to be colored
while (rightEdge + 1 < source.Width && GetPixel(rowSpan, rightEdge + 1).Equals(floodFrom))
rightEdge++;
while (leftEdge > 0 && GetPixel(rowSpan, leftEdge - 1).Equals(floodFrom))
leftEdge--;

// Actually color the row
SetPixelRow(rowSpan, leftEdge, rightEdge, _fillColor);

// Add the segments to be filled above and below to the queue
if (currentY > 0)
AddFillingSegmentsToQueue(floodFrom, accessor.GetRowSpan(currentY - 1), segmentQueue, leftEdge, rightEdge, currentY - 1);
if (currentY + 1 < source.Height)
AddFillingSegmentsToQueue(floodFrom, accessor.GetRowSpan(currentY + 1), segmentQueue, leftEdge, rightEdge, currentY + 1);
}

// Actually color the row
SetPixelRow(rowSpan, leftEdge, rightEdge, _fillColor);

// Add the segments to be filled above and below to the queue
if (currentY > 0)
AddFillingSegmentsToQueueWithBorder(floodFrom, source.GetPixelRowSpan(currentY - 1), segmentQueue, leftEdge, rightEdge, currentY - 1);
if (currentY + 1 < source.Height)
AddFillingSegmentsToQueueWithBorder(floodFrom, source.GetPixelRowSpan(currentY + 1), segmentQueue, leftEdge, rightEdge, currentY + 1);
}
else
// Filling whole region of same color
{
// Get the row segment to be colored
while (rightEdge + 1 < source.Width && GetPixel(rowSpan, rightEdge + 1).Equals(floodFrom))
rightEdge++;
while (leftEdge > 0 && GetPixel(rowSpan, leftEdge - 1).Equals(floodFrom))
leftEdge--;

// Actually color the row
SetPixelRow(rowSpan, leftEdge, rightEdge, _fillColor);

// Add the segments to be filled above and below to the queue
if (currentY > 0)
AddFillingSegmentsToQueue(floodFrom, source.GetPixelRowSpan(currentY - 1), segmentQueue, leftEdge, rightEdge, currentY - 1);
if (currentY + 1 < source.Height)
AddFillingSegmentsToQueue(floodFrom, source.GetPixelRowSpan(currentY + 1), segmentQueue, leftEdge, rightEdge, currentY + 1);
}
}

});
}

private static void AddFillingSegmentsToQueue(TPixel floodFrom, Span<TPixel> rowSpan, Queue<(Point, int)> segmentQueue, int xStart, int xEnd, int y)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
<Description>Peachpie PHP language library functions for image processing.</Description>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.0" />
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta0010" />
<PackageReference Include="SixLabors.Fonts" Version="1.0.0-beta0013" />
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.10" />
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="2.1.6" />
<PackageReference Include="SixLabors.Fonts" Version="2.1.3" />

Copilot AI Jun 30, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The SixLabors.ImageSharp.Drawing package is at 2.1.6 while SixLabors.Fonts is at 2.1.3. Consider aligning minor/patch versions across related SixLabors packages to avoid potential compatibility issues.

Suggested change
<PackageReference Include="SixLabors.Fonts" Version="2.1.3" />
<PackageReference Include="SixLabors.Fonts" Version="2.1.6" />

Copilot uses AI. Check for mistakes.
</ItemGroup>

<ItemGroup>
Expand Down
Loading
Loading