Skip to content

Commit 03191d3

Browse files
Modest-asHafman08
andauthored
Feature/image buffer (#95)
* #93 (#94) Added the result byte array as parameter for polling the arrays. * update write to buffer API * fix spacing --------- Co-authored-by: Hafman08 <Hafman08@users.noreply.github.com>
1 parent 67fdf5c commit 03191d3

File tree

5 files changed

+133
-21
lines changed

5 files changed

+133
-21
lines changed

src/Docnet.Core/Converters/IImageBytesConverter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,6 @@ public interface IImageBytesConverter
66
/// Input is in B-G-R-A format.
77
/// </summary>
88
/// <param name="bytes">Image bytes.</param>
9-
byte[] Convert(byte[] bytes);
9+
void Convert(byte[] bytes);
1010
}
1111
}

src/Docnet.Core/Converters/NaiveTransparencyRemover.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public NaiveTransparencyRemover(byte red, byte green, byte blue)
2323
/// </summary>
2424
/// <param name="bytes">Image bytes.</param>
2525
/// <returns>Same B-G-R-A array with alpha filled with white color.</returns>
26-
public byte[] Convert(byte[] bytes)
26+
public void Convert(byte[] bytes)
2727
{
2828
for (var i = 0; i < bytes.Length / 4; i++)
2929
{
@@ -39,8 +39,6 @@ public byte[] Convert(byte[] bytes)
3939
bytes[j + 2] = (byte)((red * alpha + _backgroundRed * (255 - alpha)) >> 8);
4040
bytes[j + 3] = byte.MaxValue;
4141
}
42-
43-
return bytes;
4442
}
4543
}
4644
}

src/Docnet.Core/Readers/IPageReader.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,26 @@ public interface IPageReader : IDisposable
7070
/// </summary>
7171
byte[] GetImage(IImageBytesConverter converter, RenderFlags flags);
7272

73+
/// <summary>
74+
/// Return a byte representation
75+
/// of the page image.
76+
/// Byte array is formatted as
77+
/// B-G-R-A ordered list.
78+
/// Use result if you create the array before
79+
/// </summary>
80+
void WriteImageToBuffer(RenderFlags flags, byte[] result);
81+
82+
/// <summary>
83+
/// Return a byte representation
84+
/// of the page image.
85+
/// Byte array is formatted as
86+
/// B-G-R-A ordered list. Then it
87+
/// applies a predefined byte transformation
88+
/// to modify the image.
89+
/// Use result if you create the array before
90+
/// </summary>
91+
void WriteImageToBuffer(IImageBytesConverter converter, RenderFlags flags, byte[] result);
92+
7393
/// <summary>
7494
/// Renders the page onto a device context.
7595
/// </summary>

src/Docnet.Core/Readers/PageReader.cs

Lines changed: 41 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -177,10 +177,39 @@ private static int AdjustToRange(int coord, int range)
177177
}
178178

179179
/// <inheritdoc />
180-
public byte[] GetImage() => GetImage(0);
180+
public byte[] GetImage() => WriteImageToBufferInternal(0);
181181

182182
/// <inheritdoc />
183-
public byte[] GetImage(RenderFlags flags)
183+
public byte[] GetImage(RenderFlags flags) => WriteImageToBufferInternal(flags);
184+
185+
/// <inheritdoc />
186+
public byte[] GetImage(IImageBytesConverter converter) => GetImage(converter, 0);
187+
188+
/// <inheritdoc />
189+
public byte[] GetImage(IImageBytesConverter converter, RenderFlags flags)
190+
{
191+
var bytes = WriteImageToBufferInternal(flags);
192+
193+
converter.Convert(bytes);
194+
195+
return bytes;
196+
}
197+
198+
/// <inheritdoc />
199+
public void WriteImageToBuffer(RenderFlags flags, byte[] result)
200+
{
201+
WriteImageToBufferInternal(flags, result: result);
202+
}
203+
204+
/// <inheritdoc />
205+
public void WriteImageToBuffer(IImageBytesConverter converter, RenderFlags flags, byte[] result)
206+
{
207+
WriteImageToBufferInternal(flags, result: result);
208+
209+
converter.Convert(result);
210+
}
211+
212+
private byte[] WriteImageToBufferInternal(RenderFlags flags, byte[] result = null)
184213
{
185214
lock (DocLib.Lock)
186215
{
@@ -195,8 +224,14 @@ public byte[] GetImage(RenderFlags flags)
195224
}
196225

197226
var stride = fpdf_view.FPDFBitmapGetStride(bitmap);
227+
var length = stride * height;
228+
229+
result = result ?? new byte[length];
198230

199-
var result = new byte[stride * height];
231+
if (result.Length < length)
232+
{
233+
throw new DocnetException($"result array length should be greater or equal than {length}");
234+
}
200235

201236
try
202237
{
@@ -234,7 +269,7 @@ public byte[] GetImage(RenderFlags flags)
234269

235270
var buffer = fpdf_view.FPDFBitmapGetBuffer(bitmap);
236271

237-
Marshal.Copy(buffer, result, 0, result.Length);
272+
Marshal.Copy(buffer, result, 0, length);
238273
}
239274
}
240275
catch (Exception ex)
@@ -245,20 +280,9 @@ public byte[] GetImage(RenderFlags flags)
245280
{
246281
fpdf_view.FPDFBitmapDestroy(bitmap);
247282
}
248-
249-
return result;
250283
}
251-
}
252284

253-
/// <inheritdoc />
254-
public byte[] GetImage(IImageBytesConverter converter) => GetImage(converter, 0);
255-
256-
/// <inheritdoc />
257-
public byte[] GetImage(IImageBytesConverter converter, RenderFlags flags)
258-
{
259-
var bytes = GetImage(flags);
260-
261-
return converter.Convert(bytes);
285+
return result;
262286
}
263287

264288
public void RenderDeviceContext(IntPtr deviceContext, Rectangle bounds) =>
@@ -295,4 +319,4 @@ public void Dispose()
295319
}
296320
}
297321
}
298-
}
322+
}

src/Docnet.Tests.Integration/PageReaderTests.cs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Buffers;
23
using System.Linq;
34
using System.Threading.Tasks;
45
using Docnet.Core.Converters;
@@ -339,6 +340,75 @@ public void GetImage_WhenAnnotationsRendered_ShouldHaveDifferentBytes(string fil
339340
});
340341
}
341342

343+
[Theory]
344+
[InlineData(Input.FromFile, "Docs/simple_3.pdf", null, 1)]
345+
[InlineData(Input.FromFile, "Docs/simple_0.pdf", null, 18)]
346+
[InlineData(Input.FromFile, "Docs/protected_0.pdf", "password", 0)]
347+
[InlineData(Input.FromBytes, "Docs/simple_3.pdf", null, 1)]
348+
[InlineData(Input.FromBytes, "Docs/simple_0.pdf", null, 18)]
349+
[InlineData(Input.FromBytes, "Docs/protected_0.pdf", "password", 0)]
350+
public void WriteImageToBufferWithResultByteAndNoRenderFlags_WhenCalled_ShouldReturnNonZeroRawByteArray(Input type, string filePath, string password, int pageIndex)
351+
{
352+
ExecuteForDocument(type, filePath, password, 1, pageIndex, pageReader =>
353+
{
354+
355+
var height = pageReader.GetPageHeight();
356+
var stride = 4 * pageReader.GetPageWidth(); //4 is for B-G-R-A format
357+
358+
var bytes = new byte[stride * height];
359+
360+
pageReader.WriteImageToBuffer(0, bytes);
361+
362+
Assert.True(bytes.Length > 0);
363+
Assert.NotEmpty(bytes.Where(x => x != 0));
364+
});
365+
}
366+
367+
[Theory]
368+
[InlineData(Input.FromFile, "Docs/simple_3.pdf", null, 1)]
369+
[InlineData(Input.FromFile, "Docs/simple_0.pdf", null, 18)]
370+
[InlineData(Input.FromFile, "Docs/protected_0.pdf", "password", 0)]
371+
[InlineData(Input.FromBytes, "Docs/simple_3.pdf", null, 1)]
372+
[InlineData(Input.FromBytes, "Docs/simple_0.pdf", null, 18)]
373+
[InlineData(Input.FromBytes, "Docs/protected_0.pdf", "password", 0)]
374+
public void WriteImageToBufferWithResultByteWithLowerLengthAndNoRenderFlags_WhenCalled_ShouldReturnException(Input type, string filePath, string password, int pageIndex)
375+
{
376+
ExecuteForDocument(type, filePath, password, 1, pageIndex, pageReader =>
377+
{
378+
var height = pageReader.GetPageHeight();
379+
var stride = 4 * pageReader.GetPageWidth(); //4 is for B-G-R-A format
380+
381+
var bytes = new byte[stride * height - 1];
382+
383+
384+
Assert.Throws<DocnetException>(() => pageReader.WriteImageToBuffer(0, bytes));
385+
});
386+
}
387+
388+
[Theory]
389+
[InlineData(Input.FromFile, "Docs/simple_3.pdf", null, 1)]
390+
[InlineData(Input.FromFile, "Docs/simple_0.pdf", null, 18)]
391+
[InlineData(Input.FromFile, "Docs/protected_0.pdf", "password", 0)]
392+
[InlineData(Input.FromBytes, "Docs/simple_3.pdf", null, 1)]
393+
[InlineData(Input.FromBytes, "Docs/simple_0.pdf", null, 18)]
394+
[InlineData(Input.FromBytes, "Docs/protected_0.pdf", "password", 0)]
395+
public void WriteImageToBufferWithResultFromArrayPoolNoRenderFlags_WhenCalled_ShouldReturnNonZeroRawByteArray(Input type, string filePath, string password, int pageIndex)
396+
{
397+
ExecuteForDocument(type, filePath, password, 1, pageIndex, pageReader =>
398+
{
399+
var height = pageReader.GetPageHeight();
400+
var stride = 4 * pageReader.GetPageWidth(); //4 is for B-G-R-A format
401+
var arrayPool = ArrayPool<byte>.Shared;
402+
var bytes = arrayPool.Rent(stride * height);
403+
404+
pageReader.WriteImageToBuffer(0, bytes);
405+
406+
Assert.True(bytes.Length > 0);
407+
Assert.NotEmpty(bytes.Where(x => x != 0));
408+
arrayPool.Return(bytes);
409+
});
410+
}
411+
342412
private static int GetNonZeroByteCount(Input type, string filePath, LibFixture fixture)
343413
{
344414
using (var reader = fixture.GetDocReader(type, filePath, null, 1000, 1000))

0 commit comments

Comments
 (0)