Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved png memory I/O performance. #241

Merged
merged 4 commits into from
Apr 22, 2017
Merged
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
278 changes: 278 additions & 0 deletions src/memio.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,278 @@
/*====================================================================*
- Copyright (C) 2017 Milner Technologies, Inc. This content is a
- component of Leptonica and is provided under the terms of the
- leptonica license.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
- 1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- 2. Redistributions in binary form must reproduce the Leptonica
- copyright notice, this list of conditions and the following
- disclaimer in the documentation and/or other materials
- provided with the distribution.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY
- CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*====================================================================*/

/*!
* \file memio.c
* <pre>
* libpng read/write callback replacements for performing memory I/O.
* </pre>
*/#ifdef HAVE_CONFIG_H`
#include "config_auto.h"
#endif /* HAVE_CONFIG_H */

#include <string.h>

#include "allheaders.h"

/* --------------------------------------------*/
#if HAVE_LIBPNG /* defined in environ.h */
/* --------------------------------------------*/

#include "memio.h"

/*
* <pre>Buffer allocation size. Set this small enough to avoid consuming unnecessary memory,
* but larger than an average image. </pre>
*/
#define BUFFER_SIZE 8192

/*
* <pre>
* libpng callback for writing an image into a linked list of memory buffers.
* </pre>
*/
void
memio_png_write_data(png_structp png_ptr, png_bytep data, png_size_t len)
{
MEMIODATA* thing;
MEMIODATA* last;
int written = 0;

PROCNAME("memio_png_write_data");

thing = (struct MemIOData*)png_get_io_ptr(png_ptr);
last = (struct MemIOData*)thing->m_Last;
if (last->m_Buffer == 0)
{
if (len > BUFFER_SIZE)
{
#ifdef __cplusplus
last->m_Buffer = new char[len];
#else
last->m_Buffer = LEPT_MALLOC(len);
#endif /* __cplusplus */
memcpy(last->m_Buffer, data, len);
last->m_Size = last->m_Count = len;
return;
}

#ifdef __cplusplus
last->m_Buffer = new char[BUFFER_SIZE];
#else
last->m_Buffer = LEPT_MALLOC(BUFFER_SIZE);
#endif /* __cplusplus */
last->m_Size = BUFFER_SIZE;
}

while (written < len)
{
if (last->m_Count == last->m_Size)
{
#ifdef __cplusplus
MEMIODATA* next = new MEMIODATA;
#else
MEMIODATA* next = LEPT_MALLOC(sizeof(MEMIODATA));
#endif /* __cplusplus */
next->m_Next = 0;
next->m_Count = 0;
next->m_Last = next;

last->m_Next = next;
last = thing->m_Last = next;

#ifdef __cplusplus
last->m_Buffer = new char[BUFFER_SIZE];
#else
last->m_Buffer = LEPT_MALLOC(BUFFER_SIZE);
#endif /* __cplusplus */
last->m_Size = BUFFER_SIZE;
}

/* following paragraph localizes vars only. */
{
int remainingSpace = last->m_Size - last->m_Count;
int remainingToWrite = len - written;
if (remainingSpace < remainingToWrite)
{
memcpy(last->m_Buffer + last->m_Count, data + written, remainingSpace);
written += remainingSpace;

last->m_Count += remainingSpace;
}
else
{
memcpy(last->m_Buffer + last->m_Count, data + written, remainingToWrite);
written += remainingToWrite;
last->m_Count += remainingToWrite;
}
}
}
}


/*
* <pre>
* Consolidate write buffers into a single buffer in the head of the linked list.
* </pre>
*/
void
memio_png_flush(MEMIODATA* pthing)
{
int amount = 0;
MEMIODATA* buffer = 0;
int copied = 0;
char* data = 0;

PROCNAME("memio_png_write_data");

/* if the data was contained in one buffer just give the buffer to the user. */
if (pthing->m_Next == 0)
{
return;
}

/* consolidate multiple buffers into one new one. */

/* add the buffer sizes together. */
amount = pthing->m_Count;
buffer = pthing->m_Next;
while (buffer != 0)
{
amount += buffer->m_Count;
buffer = buffer->m_Next;
}

/* copy data to a new buffer. */
#ifdef __cplusplus
data = new char[amount];
#else
data = LEPT_MALLOC(amount);
#endif /* __cplusplus */
memcpy(data, pthing->m_Buffer, pthing->m_Count);
copied = pthing->m_Count;

#ifdef __cplusplus
delete[] pthing->m_Buffer;
#else
LEPT_FREE(pthing->m_Buffer);
#endif /* __cplusplus */
pthing->m_Buffer = 0;
/* don't delete original "thing" because we don't control it. */

buffer = pthing->m_Next;
pthing->m_Next = 0;
while (buffer != 0 && copied < amount)
{
MEMIODATA* old;
memcpy(data + copied, buffer->m_Buffer, buffer->m_Count);
copied += buffer->m_Count;

old = buffer;
buffer = buffer->m_Next;

#ifdef __cplusplus
delete[] old->m_Buffer;
delete old;
#else
LEPT_FREE(old->m_Buffer);
LEPT_FREE(old);
#endif /* __cplusplus */
}

/*
assert(copied == amount);
*/

pthing->m_Buffer = data;
pthing->m_Count = copied;
pthing->m_Size = amount;
return;
}


/*
* <pre>
* libpng callback that reads an image from a single memory buffer.
* </pre>
*/
void
memio_png_read_data(png_structp png_ptr, png_bytep outBytes, png_size_t byteCountToRead)
{
PROCNAME("memio_png_read_data");

MEMIODATA* thing = (MEMIODATA*)png_get_io_ptr(png_ptr);

memcpy(outBytes, thing->m_Buffer + thing->m_Count, byteCountToRead);
thing->m_Count += byteCountToRead;
}

void
memio_free(MEMIODATA* pthing)
{
MEMIODATA* buffer;

PROCNAME("memio_free");

if (pthing->m_Buffer != 0)
{
#ifdef __cplusplus
delete[] pthing->m_Buffer;
#else
LEPT_FREE(pthing->m_Buffer);
#endif /* __cplusplus */
}

pthing->m_Buffer = 0;
buffer = pthing->m_Next;
while (buffer != 0)
{
MEMIODATA* old = buffer;
buffer = buffer->m_Next;

#ifdef __cplusplus
if (old->m_Buffer != 0)
{
delete[] old->m_Buffer;
}

delete old;
#else
if (old->m_Buffer != 0)
{
LEPT_FREE(old->m_Buffer);
}

LEPT_FREE(old);
#endif /* __cplusplus */
}
}

/* --------------------------------------------*/
#endif /* HAVE_LIBPNG */
/* --------------------------------------------*/
101 changes: 101 additions & 0 deletions src/memio.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*====================================================================*
- Copyright (C) 2017 Milner Technologies, Inc. This content is a
- component of leptonica and is provided under the terms of the
- Leptonica license.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
- 1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- 2. Redistributions in binary form must reproduce the Leptonica
- copyright notice, this list of conditions and the following
- disclaimer in the documentation and/or other materials
- provided with the distribution.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY
- CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*====================================================================*/

/*!
* \file memio.h
* <pre>
* libpng read/write callback replacements for performing memory I/O.
* </pre>
*/

#ifndef LEPTONICA_MEMIO_H
#define LEPTONICA_MEMIO_H

/* --------------------------------------------*/
#if HAVE_LIBPNG /* defined in environ.h */
/* --------------------------------------------*/

#include <png.h>

/*
* <pre>
* A node in a linked list of memory buffers that hold I/O content.
* </pre>
*/
struct MemIOData
{
/*
* <pre>Pointer to this node's I/O content.</pre>
*/
char* m_Buffer;

/*
* <pre>The number of I/O content bytes read or written to m_Buffer.</pre>
*/
int m_Count;

/*
* <pre>The allocated size of m_Buffer.</pre>
*/
int m_Size;

/*
* <pre>Pointer to the next node in the list. Zero if this is the last node.</pre>
*/
struct MemIOData* m_Next;

/*
* <pre>Pointer to the last node in the linked list. The last node is where new
* content is written.</pre>
*/
struct MemIOData* m_Last;
};

typedef struct MemIOData MEMIODATA;

#ifndef NO_PROTOS

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

void memio_png_write_data(png_structp png_ptr, png_bytep data, png_size_t length);
void memio_png_flush(MEMIODATA* pthing);
void memio_png_read_data(png_structp png_ptr, png_bytep outBytes, png_size_t byteCountToRead);
void memio_free(MEMIODATA* pthing);

#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* NO_PROTOS */

/* --------------------------------------------*/
#endif /* HAVE_LIBPNG */
/* --------------------------------------------*/

#endif
Loading