Lazarus

Programming => Graphics and Multimedia => Graphics => Topic started by: Timur Born on December 19, 2020, 05:22:17 pm

Title: Question: Handling large image files
Post by: Timur Born on December 19, 2020, 05:22:17 pm
Ahoi.

I am currently testing Lazarus vs. QT vs. whatever to decide which would be suitable to code an image viewer that launches fast, is able to load several large images for comparison and runs multi-threaded for all kinds of operations. GUI and processing back-end should be separated (and maybe even in different languages/processes) so that one stays reactive when the other is busy.

Since I would have to start from scratch learning the language(s) and IDEs I am doing preliminary checks and test on what is already offered. First I compared memory consumption of simple empty windows that Larazus/QT/VS start with when a new project is created in order to get an idea of launch times/resource-usage. Lazarus and QT both do well in this, even though VS C++ MFC was even smaller, .NET WinForms was unsurprisingly larger and WPF came surprisingly last by quite a gap.

For comparison of what each platform offers for image viewieng I downloaded several Lazarus/Pascal and QT based image-viewers and opened a 3 GB large uncompressed TIFF image. Furthermore I used this old example code for Lazarus to open and display an image (changed FileExistsUTF8 to FileExists to make it work):

https://lazplanet.blogspot.com/2013/05/a-simple-image-viewer-from-start-to.html (https://lazplanet.blogspot.com/2013/05/a-simple-image-viewer-from-start-to.html)

Unfortunately I was not able to open and display the test image via this code or the Lazarus based image viewers I could find. So any hints on where to start would be appreciated. I would also like to read shared experience on how well Lazarus is suited to handle this kind of coding challenge?!

PS: It's noteworthy that my favorite image viewer Faststone Image Viewer is said to be written in Delphi, but it's unfortunately stuck in 32-bit. I know/use/tested a lot of different commercial and free image viewers over the years and thus generally know their strengths and weaknesses.
Title: Re: Question: Handling large image files
Post by: Handoko on December 19, 2020, 07:48:25 pm
Hello Timur Born,
Welcome to the forum.

Unfortunately I was not able to open and display the test image ...

This simple demo shows how to load and show an image using Lazarus, try it:
https://forum.lazarus.freepascal.org/index.php/topic,37442.msg251587.html#msg251587

Because you want to develop an image viewer program, I should tell you not all graphics formats are supported and it depends on which library you are using. For example 2 versions of glSlideshow but the file format support are different (FCL-Image vs BGRABitmap):
https://forum.lazarus.freepascal.org/index.php/topic,35313.msg258981.html#msg258981

And here is the list of supported graphics libraries:
https://wiki.lazarus.freepascal.org/Graphics_libraries

... able to load several large images ...

Maybe you will be interested to read this:
https://forum.lazarus.freepascal.org/index.php/topic,50444.msg368161.html#msg368161
Title: Re: Question: Handling large image files
Post by: lainz on December 19, 2020, 07:51:21 pm
Have you tried LazPaint? Made by circular, is really fast.
Title: Re: Question: Handling large image files
Post by: Timur Born on December 19, 2020, 08:56:08 pm
Have you tried LazPaint? Made by circular, is really fast.
Thanks for the hint. I already tried LazPaint and LazView. It surprises me that LazPaint comes with its own file open dialog and said dialog already fails to open the image with a EOutofMemory error (TBGRAWinBitmap.RellocBitmap: Windows error 87).
Title: Re: Question: Handling large image files
Post by: Timur Born on December 19, 2020, 09:10:49 pm
Hello Timur Born,
Welcome to the forum.
Thanks for the warm welcome and the links, I will read through them.

One problem with image format files is that they seemingly cannot be decoded multi-threaded. I remember that I saw one viewer (maybe ACDSee) using two threads to decode the TIFF files, but overall it's one thread per image (JPEG, PNG, TIFF). This also is a bottleneck for modern PDF viewers when PDF files are image heavy.

After reading a bit in the last link provided it maybe makes sense to write the front-end (GUI) part in Lazarus and do the backend in C/C++. Currently I am only musing about possibilities.

It is worth mentioning that the QT based Nomacs viewer is very fast at viewing these large files, maybe even faster than anything I tried yet. Even only using a single-thread opens the displays the 3 gb TIFF file within 3 seconds and then all scrolling/zooming is smooth (contrary to XnViewMP or Ifranview). Memory consumption quite high, though (7.5 gb private after loading the 3 gb image).

Quote
This simple demo shows how to load and show an image using Lazarus, try it:
I am still trying to wrap my head around it. When I compile it as is then the window stays empty (no controls at all). Do I have to create the controls in the form editor and rename them according to the code? When I add controls it changes the code to fit in the new controls first.

Title: Re: Question: Handling large image files
Post by: circular on December 21, 2020, 08:21:55 am
Have you tried LazPaint? Made by circular, is really fast.
Thanks for the hint. I already tried LazPaint and LazView. It surprises me that LazPaint comes with its own file open dialog and said dialog already fails to open the image with a EOutofMemory error (TBGRAWinBitmap.RellocBitmap: Windows error 87).
LazPaint is not made for images larger than 256 Mb. It would be interesting for me to know though when the problem happens and whether it is a crash or just an error message.
Title: Re: Question: Handling large image files
Post by: Timur Born on December 21, 2020, 12:40:01 pm
LazPaint is able to open a 1539 mb non standard uncompressed TIFF file and its more standard 1350 mb variant, but it takes 8 minutes to do so instead of 3-10 seconds. Loading the preview in the load dialog only takes seconds, though still is slower than loading the whole image in Nomacs (QT + OpenCV based).

LazPaint hits over 280 mio virtual memory pagefaults while loading the image (580 - 750k per second), while Nomacs finishes at only 1.7 mio. There also seem to be more pagefaults while scrolling around the zoomed image, but I did not test that thoroughly.

Scrolling in the zoomed image is smooth between 200 - 500%, but more juddery below 200% and above 500% (when the grid shows up).

There also is a visible "rolling shutter" effect skewing straight lines during left/right scrolling because of the image is build/refreshed from top to bottom.

The error with the 3 gb file happens when the preview is supposed to be created in the load dialog, it does not crash and another image can be chosen/opened afterwards.

Judging from this observations it seems that building the backend on top of OpenCV seems like a good idea, which in turn points more towards C++. There are some OpenCV Delphi/Lazarus ports, but they don't seem to be actively maintained!?

Using a C++ backend in combination with a Lazarus UI might be viable, but I don't know how well this could be integrated (maybe even using 2 processes via inter-process communication via shared memory)?!
Title: Re: Question: Handling large image files
Post by: winni on December 21, 2020, 02:19:31 pm
Hi!

The biggest TIFF file on my disks is 668 MB,  8192 x4096 Pixel, RGB

The file loading takes 3..4 seconds
Resizing down and up happes in realtime
Moving  the image happes in realtime

One message while loading the image:
Code: Text  [Select][+][-]
  1. [DEBUG] Name com.canonical.AppMenu.Registrar does not exist on the session bus
  2.  

Whatever Lazpaint wants to tell me.
No problems.

Winni
Title: Re: Question: Handling large image files
Post by: avra on December 21, 2020, 03:46:31 pm
The error with the 3 gb file happens when the preview is supposed to be created in the load dialog, it does not crash and another image can be chosen/opened afterwards.
If image loader tries to load whole image into memory, then you should check if your compiled Lazarus application is 32-bit, or OS is 32-bit.

Have you looked into https://github.com/galfar/imaginglib ?
Title: Re: Question: Handling large image files
Post by: circular on December 21, 2020, 03:55:25 pm
Thanks for the infos Timur.

The decompression algorithms are a bit slow I suppose. Not sure where this could be optimized.

About the pagefaults I am not really surprised because the image data is stored in rows in BGRABitmap and the TIFF may be provided as a grid of images. Not the same layout. There may be other reasons that I am unaware of.

Another limitation is that images in LazPaint are reduced to fit a 8192x8192 maximum dimension. The long time when loading is probably due to this resampling (done with high quality).

So, all of this seems normal to me given the current implementation. Indeed you need another library for those big images.

Code: [Select]
[DEBUG] Name com.canonical.AppMenu.Registrar does not exist on the session busMaybe LCL trying to get a service on a Linux system.
Title: Re: Question: Handling large image files
Post by: Timur Born on December 21, 2020, 05:51:41 pm
Using 64 bit LazPaint + 64 W10 here. Images were uncompressed TIFF, but between 25200 and 32000 px on the long side. One could implement the image handling from scratch, but seeing how well Nomacs does on the performance front makes looking at OpenCV more tempting.

Nomacs fails mostly on the UI front, while my favorite FastStone Image Viewer fails at 64-bit (and the author not even answering mails from license owners).

Lazarus is very tempting to build a GUI app with, both being convenient and compiled native code. But having to reinvent the wheel for the backend while (C++ based) solutions are already out there is a big problem.
Title: Re: Question: Handling large image files
Post by: circular on December 21, 2020, 07:45:46 pm
That's understandable. You can use C++ libraries in FreePascal though.
Title: Re: Question: Handling large image files
Post by: Timur Born on December 21, 2020, 08:07:06 pm
I speculated as much. How easy or convoluted would that be? Can these be statically linked, too?
Title: Re: Question: Handling large image files
Post by: circular on December 21, 2020, 09:03:58 pm
In all cases, you need a "header" file, so a Pascal unit that defines the procedures (with cdecl keyword for C) and types.

It is possible to point directly to a library using the external keyword. That's the simple but I guess you can do that only if you are sure the library will be available. Otherwise it is also possible to statically link an object file (I never tried it personally). Here is the doc on external:
https://www.freepascal.org/docs-html/current/prog/progsu150.html

You can have more control over the dependency to the library. You need for this code that loads the library and retrieve the pointers to the procedures. Here is such file for example for WebP library: https://github.com/bgrabitmap/bgrabitmap/blob/master/bgrabitmap/libwebp.pas. That's more stuff to write because in this case you define variables that will contain the procedures and the code that actually loads the library. On the other hand, you can choose when to load/unload the library, do something else if the library is not present, etc.
Title: Re: Question: Handling large image files
Post by: Timur Born on December 22, 2020, 01:06:44 am
Have you looked into https://github.com/galfar/imaginglib ?
Sorry, I missed this part. But yes, I already looked into its compiled demos and tried LCL Imager. It does not support TIFF, so I had it open a PNG version of the 1.35 gb image. It is faster that LazPaint, but still far too slow in opening the preview and image.
Title: Re: Question: Handling large image files
Post by: Timur Born on December 22, 2020, 01:30:44 am
It is possible to point directly to a library using the external keyword. That's the simple but I guess you can do that only if you are sure the library will be available.
Thanks for the hints and extra information. Via its installer Nomacs installs OpenCV as as dll files of about 16 mb and 28 mb respective file-size. That's okish, but the whole of FastStone IV (likely Delphi) fits into the 16 mb size, including language files and plugins. FastStone launches a bit quicker to draw the window frame, but it's not faster until you reach the point where you can really use it. Long launch times is one thing that hampers ACDSee (and its Quick View module is limited is functions).

Quote
Otherwise it is also possible to statically link an object file (I never tried it personally). Here is the doc on external:
Is there an advantage to doing this?

Quote
You can have more control over the dependency to the library. You need for this code that loads the library and retrieve the pointers to the procedures.
...
On the other hand, you can choose when to load/unload the library, do something else if the library is not present, etc.
Is the load/unload the main advantage? It could be used to unload libraries like LibRaw when they are not needed (no raw files to be processed).
Title: Re: Question: Handling large image files
Post by: circular on December 22, 2020, 09:29:00 am
I don't think there is any advantage in static linking except that it produces just one binary file. It may make the startup time a bit longer if you include big libraries.

Quote
Is the load/unload the main advantage? It could be used to unload libraries like LibRaw when they are not needed (no raw files to be processed).
There is the load/unload advantage. This can reduce the startup time and memory usage as you may not need to load all libraries. Another advantage is that you can look for the library file in the hard drive and load the one you prefer. I use that on Linux to get the best fit:
https://github.com/bgrabitmap/bgrabitmap/blob/master/bgrabitmap/linuxlib.pas
Title: Re: Question: Handling large image files
Post by: avra on December 22, 2020, 10:48:01 am
...you can look for the library file in the hard drive and load the one you prefer. I use that on Linux to get the best fit:
https://github.com/bgrabitmap/bgrabitmap/blob/master/bgrabitmap/linuxlib.pas
Nice  8)
Title: Re: Question: Handling large image files
Post by: Timur Born on December 22, 2020, 11:10:44 am
Dummy question: Is the whole library compiled into the exe when it is statically linked, I thought that only the parts being used are?

I am not against dynamically linking, but I recently installed all MSVC redistributables via a single installer and it installed 24 different versions. Even with that I am sure one of the next installers is going to ask me to install some of it again.  >:D

The load/unload parts sure has its charm, depending on how taxing loads/unloads are during runtime.

One of the main reasons why you see me writing here instead of just enjoying user lala land is that I am really getting tired of all the unresponsiveness of desktop apps on expensive modern hardware. I keep throwing money at the problem, but still far too much time is spent on twiddling thumbs (watching animated circles/balls/"not responding") while resources are either unused or abused.

And then there is serious feature lack after decades of UI computing. Nomacs is fast, but you need to load multiple instances and half-manually sync them in order to compare images. And we get 3D in PDF, but there still is not a single Windows based PDF viewer that offers proper sorting of text search results (think files with hundreds/thousands of pages).
Title: Re: Question: Handling large image files
Post by: circular on December 22, 2020, 11:50:46 am
Dummy question: Is the whole library compiled into the exe when it is statically linked, I thought that only the parts being used are?
I suppose if the linker can sort things out.

I am not against dynamically linking, but I recently installed all MSVC redistributables via a single installer and it installed 24 different versions. Even with that I am sure one of the next installers is going to ask me to install some of it again.  >:D
Yes, relying on installed things on Windows is not great either in my experience. I prefer to supply the Dll next to the Exe if I can.

Quote
The load/unload parts sure has its charm, depending on how taxing loads/unloads are during runtime.
The taxing happens anyway. Either on startup, when loading the image, or maybe when the application is idle.

Quote
One of the main reasons why you see me writing here instead of just enjoying user lala land is that I am really getting tired of all the unresponsiveness of desktop apps on expensive modern hardware. I keep throwing money at the problem, but still far too much time is spent on twiddling thumbs (watching animated circles/balls/"not responding") while resources are either unused or abused.
I am sure we are many here to agree on that. It would be great that companies spend more time optimizing things rather than make the brand new thing.
Title: Re: Question: Handling large image files
Post by: avra on December 22, 2020, 02:49:20 pm
There is an interesting discussion how to speed up TIFF loading:
http://maptools-org.996276.n3.nabble.com/Fast-TIFF-Reading-on-Windows-td13424.html
Talk about using memory mapped files, adapting to file system block size, thread safe list of strips with each thread getting the next strip and reading it...

Quote
It is worth mentioning that the QT based Nomacs viewer is very fast at viewing these large files, maybe even faster than anything I tried yet. Even only using a single-thread opens the displays the 3 gb TIFF file within 3 seconds
Are you sure that whole 3GB of data are loaded in 3 seconds? That would render to 1GB per second which is very rare even with fastest M.2 SSDs. I would guess that for fast preview many tiff strips were skipped. For example, your preview window is 800x600 and your tiff image is 8000x6000. From that info and from info about tiff strips height in pixels, and from knowing the number of cpu cores available in your system, you can build a list of strips for multithreaded strips reading by prioritization of loading each n-th stip first to populate your preview window first, and then loading the rest of the strips when user thinks that all of it is already loaded. I am not aware of tiff image format details, so maybe you can also optimize loading of a single strip, by not loading all strip data at once.
Title: Re: Question: Handling large image files
Post by: avra on December 22, 2020, 03:07:11 pm
I have found libtiff, libjpeg and zlib for Delphi with all headers already translated to pascal and all debug and release libraries 32bit *.obj files for windows:
https://web.archive.org/web/20070202123132/http://www.awaresystems.be/imaging/tiff/delphi/LibTiffDelphi_Full.zip

Might help you.
Title: Re: Question: Handling large image files
Post by: circular on December 22, 2020, 05:35:03 pm
Are you sure that whole 3GB of data are loaded in 3 seconds? That would render to 1GB per second which is very rare even with fastest M.2 SSDs. I would guess that for fast preview many tiff strips were skipped. For example, your preview window is 800x600 and your tiff image is 8000x6000. From that info and from info about tiff strips height in pixels, and from knowing the number of cpu cores available in your system, you can build a list of strips for multithreaded strips reading by prioritization of loading each n-th stip first to populate your preview window first, and then loading the rest of the strips when user thinks that all of it is already loaded. I am not aware of tiff image format details, so maybe you can also optimize loading of a single strip, by not loading all strip data at once.
Indeed, the TIFF structure may help to do that. It depends how it was saved. The file can organized as strips or as tiles and if that's the case, you can for example extract only the tiles that are being displayed (zoom) or skip strips (unzoomed).
Title: Re: Question: Handling large image files
Post by: Timur Born on December 22, 2020, 06:11:38 pm
My M.2 does over 2 gb/s on sequential reads of large blocks and once its in cache any waiting time remaining is processing time by the application opening the file. It's still possible that the file is opened in stripes, but if that helps faster loading then the better.

Thanks for the link! As far as I understand the 32-bit .obj files cannot be used in 64-bit applications (and would thus not be able to handle 3 gb files)?

Title: Re: Question: Handling large image files
Post by: circular on December 22, 2020, 06:29:56 pm
Indeed you need object files with the same bit-ness
Title: Re: Question: Handling large image files
Post by: Timur Born on December 22, 2020, 06:34:04 pm
From that info and from info about tiff strips height in pixels, and from knowing the number of cpu cores available in your system, you can build a list of strips for multithreaded strips reading by prioritization of loading each n-th stip first to populate your preview window first, and then loading the rest of the strips when user thinks that all of it is already loaded. I am not aware of tiff image format details, so maybe you can also optimize loading of a single strip, by not loading all strip data at once.
Worth mentioning that I have not seen any image viewer load any image type multi-threaded (per single file). I may have seen 2 thread for TIFF once, but it's possible that one thread was just busy with the GUI (despite nothing but image loading happening). Nomacs at least uses multiple thread for thumbnail creation (one thread per file/thumbnail that is).
Title: Re: Question: Handling large image files
Post by: avra on December 23, 2020, 12:02:29 am
As far as I understand the 32-bit .obj files cannot be used in 64-bit applications (and would thus not be able to handle 3 gb files)?
Right, but that are libtiff object files and header translation are from 2007. Nothing stops you to make new libtiff object files for both 32-bit and 64-bit. Remember that 3 GB limit is just a speculation because of 32-bit limits and assumptions that whole file is loaded into memory at once. It may be something else. Clever 32-bit application should be able to handle almost unlimited image size at cost of speed.

Worth mentioning that I have not seen any image viewer load any image type multi-threaded (per single file). I may have seen 2 thread for TIFF once, but it's possible that one thread was just busy with the GUI (despite nothing but image loading happening). Nomacs at least uses multiple thread for thumbnail creation (one thread per file/thumbnail that is).
Well, link I provided discusses possible speed improvements for tiff reading. One of them is multithreaded strips reading. It's up to you if you want to try it or not.
Title: Re: Question: Handling large image files
Post by: Timur Born on December 23, 2020, 11:07:25 am
Thanks again.  ;)

At first I thought that XnViewMP and IrfanView may be among those few viewers that do not try to load the whole image into memory, because they only consume 2.2 gb after decoding the 3 gb testfile. Turns out that my 3 gb testfile really only should be 2.2 gb of data, I will have to check that again. I currently use XnViewMP when I need to do image comparison in images too large for FastStone. It's good enough once images are loaded, but its browser view is slow when it reads in those large files specs using only a single thread, even without thumbnails being viewed.

Overall I think that reading the whole file(s) into memory is preferred for smooth operation without lags and judder. All software I tried seems to handle large images that way (with 32-bit ones failing once size is too large).

Concerning multi-threaded decoding: In the past I thought that single-threaded decoding might be a bottleneck even for uncompressed files, but 3 seconds for a 3 gb file are fast enough. Handling of (de)compression would likely benefit from multi-threading, at least for Deflate/ZIP, but maybe not so much for LZW.
Title: Re: Question: Handling large image files
Post by: avra on December 23, 2020, 11:36:11 am
Reading the whole file(s) into memory is absolutely preferred for smooth operation without lags and judder.
I was not saying that you should not load the whole file into memory. I was saying that you could first read every n-th strip (depending on preview window size) to show super fast preview to the user, and then read all the rest of the strips. If you wish you can also use multithreading (if I remember the linked discussion well - some developers said that it does speed up loading), but it is not a must. This is just a theoretical discussion. Final decision is fully yours.
Title: Re: Question: Handling large image files
Post by: Timur Born on December 23, 2020, 11:37:11 am
Yes, this sounds like a good idea, similar to how progressive JPEGs are decoded. Thanks for the clarification. English is not my native language, so sometimes I misunderstand stuff.

On fast systems as mine it might not make much of a difference, though, because 3 seconds. Decompression of compressed images might gain more from multi-threading. Opening the same large image in a compressed format (like Deflate TIFF) takes much longer on my PC.
Title: Re: Question: Handling large image files
Post by: avra on December 23, 2020, 01:32:22 pm
It might be interesting to take a look at this:
https://github.com/libvips/libvips/wiki/Why-is-libvips-quick
That lib has C headers so should not be hard to convert them to Pascal.

This lib has COM object:
http://www.graphicsmagick.org/ImageMagickObject.html
That means that you can easily import it into IDE. For more info read this post: https://forum.lazarus.freepascal.org/index.php/topic,52586.msg388065.html#msg388065

And, of course, you might decide that you want to improve loading speed of some existing pascal tiff lib, or write your own.
Title: Re: Question: Handling large image files
Post by: Timur Born on December 23, 2020, 01:56:11 pm
Thank you, I will look into it. The last post of the thread you linked earlier refers to the Graphicsmagick library, which utilizes OpenMP. I am currently looking into this, too.
Title: Re: Question: Handling large image files
Post by: Timur Born on December 23, 2020, 02:29:13 pm
At least the Photoflow implementation of libvips suggests that it is too slow, both for loading and for zooming/scrolling a large image.

- Decompression of PNG images (Deflate) is single-threaded for decompression.

- Decoding after decompression of PNG or of uncompressed TIFF is done multi-threaded, but all threads only utilize about 15% (!) of their respective CPU core. As a result decoding is slow, surely nowhere near the OpenCV based Nomacs, despite the latter only using a single-thread.

- Scrolling and zooming creates new threads for milliseconds of time and the screen is drawn slow enough that you may have to wait seconds for zooming and see new content being build on screen for scrolling (aka blanks being filled gradually).

So for the time being I will concentrate further research on OpenCV and ImageMagick.
Title: Re: Question: Handling large image files
Post by: avra on December 24, 2020, 09:48:25 am
So for the time being I will concentrate further research on OpenCV and ImageMagick.
There is OpenCV Lazarus wrapper here: https://github.com/t-edson/LazarusOpenCV
That is for old OpenCV 2.4 version. OpenCV has deprecated C api with 3.0 and newer versions, and no one has bothered to flatten C++ headers to C for creating a pascal wrapper. If that version is fast enough for your needs then you do not need to search further. If you need newer OpenCV in pascal then prepare for flattening to C and then creating pascal wrappers, or try to use some older SWIG for that.

These can help with creating wrappers for C libraries or with converting some C code to pascal:
https://forum.lazarus.freepascal.org/index.php/topic,50811.0.html
https://wiki.freepascal.org/Creating_bindings_for_C_libraries
https://wiki.freepascal.org/Common_problems_when_converting_C_header_files
https://wiki.freepascal.org/Pascal_for_C_users
https://wiki.freepascal.org/C_to_Pascal

There were several SWIG based attempts to automate usage of C++ libraries in pascal, but although it worked, patches were never integrated into mainstream SWIG:
https://wiki.lazarus.freepascal.org/SWIG
Title: Re: Question: Handling large image files
Post by: Timur Born on December 24, 2020, 12:16:09 pm
Thanks again!

I am also further investigating libvips, as the available application implementations may not be representative of its possibilities. It should be able to load large images completely into memory given the right parameters, by default it uses disc access for images larger than 100 mb, though.

That being said, I am not sure if the extra work needed to use current implementations of these libraries and (re)learning of Pascal are worth the effort over just going the C(++) route then.
Title: Re: Question: Handling large image files
Post by: avra on December 24, 2020, 02:08:47 pm
I am not sure if the extra work needed to use current implementations of these libraries and (re)learning of Pascal are worth the effort over just going the C(++) route then.
Quite reasonable from time needed point of view. However if OpenCV 2.4 is good enough, or quick testing of COM lib and ActiveX controls of ImageMagick goes fine, you might end up in pascal train after all.  ;)
TinyPortal © 2005-2018