forums.ps2dev.org Forum Index forums.ps2dev.org
Homebrew PS2, PSP & PS3 Development Discussions
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Calling for ideas about builing image thumbnails

 
Post new topic   Reply to topic    forums.ps2dev.org Forum Index -> PSP Development
View previous topic :: View next topic  
Author Message
Tong



Joined: 20 Apr 2007
Posts: 10

PostPosted: Fri Apr 20, 2007 3:26 pm    Post subject: Calling for ideas about builing image thumbnails Reply with quote

Dear all, this is the first time for me to post a topic in this forum.

I am currently working on a PSP photo viewer in which users can see the previews of their images (PNG and JPG) before they open them, just like the one in Sony's XMB. I propose the following algorithms to show the previews:

1.Read the WHOLE picture into RAM and select some pixels form it to make the thumbnail;

2.Read the image row by row but only take some pixels to make the thumbnail.

Unfortunately, the above methods are found to be very inefficient and resource-consuming especially for large images. Does anyone have better ideas, or know any functions in libpng and libjpeg that are useful in building thumbnails? Thanks.
Back to top
View user's profile Send private message
rapso



Joined: 28 Mar 2005
Posts: 147

PostPosted: Fri Apr 20, 2007 5:33 pm    Post subject: Reply with quote

some jpg are progressive encoded, so they have already a thumbnail.
once you made the tumbnail, you could save it in the same place and next time just load it (most pictureviewer I know have this kind of caching), so it won't be that bad.

btw. I'd do methode 2 to generate the images, as some decompressed jpg might requiere more memory than the psp has.
Back to top
View user's profile Send private message
Tong



Joined: 20 Apr 2007
Posts: 10

PostPosted: Fri Apr 20, 2007 11:53 pm    Post subject: Reply with quote

I have just implemented method 2 using libpng to generate thumbnail images with sides 64px, and here is the codes.
Code:
//do some preparations here...

float SkipX=(float)ImgWidth/64,
   SkipY=(float)ImgHeight/64,
   TargetX=0, TargetY=0;
int StepX=0, StepY=0, ThumbX=0, ThumbY=0;
   
for(y = 0; y <ImgHeight; y++)
{   
   png_read_row(png_ptr, (u8*)tempLine, png_bytep_NULL); //read a row
       
   if (y==StepY)//if the row is the one we want
   {
      //select some pixels from the row
      for (TargetX=0, ThumbX=0; TargetX<(float)ImgWidth; TargetX+=SkipX, ThumbX++)
      {
         StepX=RoundOff(TargetX);
         ThumbData[ThumbY*64+ThumbX]=tempLine[StepX];
      }
      //next row
      ThumbY++;
      TargetY+=SkipY;
      StepY=RoundOff(TargetY);
   }
}

What I observe is that the time taken for it to generate a thumbnail is almost the SAME(some may longer) as reading the whole image. It is not surprising as I think each generation needs to read through the whole image. I wonder how SONY's photo viewer in XMB reads thumbnails, it can just finish all in a split second!!
Back to top
View user's profile Send private message
StrmnNrmn



Joined: 14 Feb 2007
Posts: 46
Location: London, UK

PostPosted: Sat Apr 21, 2007 7:08 pm    Post subject: Reply with quote

Tong wrote:
What I observe is that the time taken for it to generate a thumbnail is almost the SAME(some may longer) as reading the whole image. It is not surprising as I think each generation needs to read through the whole image.


You code is reading through the entire image, so it's always going to take at least as long. It sounds like you really need to cache the thumbnails you generate.

In terms of minimising the time spent generating the thumbnail data, you could use the graphics hardware just to blit from the source image down to your desired thumbnail size? It you do this, you'll also get bilinear filtering for free (or close to free) and it'll look much better than the point sampling method you're currently using. It'll take a bit of fiddling with render targets, but I'm sure it'll be far faster than anything you could achieve with the cpu.

If you want to keep your UI responsive while generating the thumbnails you could also look at shifting thumbnail generation to a separate thread?
Back to top
View user's profile Send private message Visit poster's website MSN Messenger
Brunni



Joined: 08 Oct 2005
Posts: 186

PostPosted: Sat Apr 21, 2007 7:24 pm    Post subject: Reply with quote

You can use the GPU to reduce your image size but it requires to load it entirely, and thus it's slow. You'd have to do it in a parallel thread I guess. Example (with OSLib):
Code:
//Creates a 64x64 image from an file
OSL_IMAGE *loadThumbnail(const char *filename)      {
   OSL_IMAGE *src, *dst, *oldDrawBuf = oslGetDrawBuffer();
   int oldBilinear = osl_bilinearFilterEnabled, oldDither = osl_ditheringEnabled;

   src = oslLoadImageFile(filename, OSL_IN_RAM, OSL_PF_8888);
   dst = oslCreateImage(64, 64, OSL_IN_VRAM, OSL_PF_5650);
   if (src && dst)         {
      oslSetDrawBuffer(dst);
      oslSetBilinearFilter(1);
      oslSetDithering(1);
      src->x = src->y = 0;
      src->stretchX = 64;
      src->stretchY = 64;
      oslDrawImage(src);
      oslSetDrawBuffer(oldDrawBuf);
      oslSetBilinearFilter(oldBilinear);
      oslSetDithering(oldDither);
   }
   if (src)
      oslDeleteImage(src);

   return dst;
}


Edit: sorry, my answer is not really helpful seeing what StrmnNrmn posted :-'
_________________
Sorry for my bad english
Oldschool library for PSP - PC version released


Last edited by Brunni on Sun Apr 22, 2007 9:34 pm; edited 4 times in total
Back to top
View user's profile Send private message
rapso



Joined: 28 Mar 2005
Posts: 147

PostPosted: Sat Apr 21, 2007 7:44 pm    Post subject: Reply with quote

Tong wrote:
I wonder how SONY's photo viewer in XMB reads thumbnails, it can just finish all in a split second!!
libpng and libjpg are not really fast. e.g. the intelJpgLib (no, there is no version for psp ;) ), could read about 20 320*200 jpg images per second on a Pentium200MMX (if I remeber correctly). so, if you want it faster, you'd have to improve the speed of the libs.
Afaik, some picture-viewer (lieg irfanview) cache the next image in advance. so if you step to the next image, you already have it.
you'd not even need threading.

currently you do something like:
Code:

wait for key
if key==next then
  load next image
  show next image

with a little modification you could do something like
Code:

wait for key
if key==next then
  show next image
  load next->next image
  memorize next->next as next image


so you'd first show the cached image and then, when the user is viewing it, you could already load the next image. if the user wants to see the next, he'd still wait some time if it's not cached yet, but probably still less waiting then in your current version.
Back to top
View user's profile Send private message
noxa



Joined: 05 Aug 2006
Posts: 39

PostPosted: Sat Apr 21, 2007 9:37 pm    Post subject: Reply with quote

My day job deals with nothing but photos, so I've got some experience here :)
My suggestion is to go with epeg (http://www.enlightenment.org/Libraries/Epeg/) (or hack it up and change it to your liking like I did). It is incredibly fast at what it does, and combined with a few tricks (such as sampling at powers of two larger than what you want and then scaling down) you can get thumbnails that look just as good as ones taken from the real image.

Edit: epeg uses libjpeg. I haven't seen a PSP port, but it is POSIX-based and when I compiled it on OS X I didn't have to make any changes.
Back to top
View user's profile Send private message Visit poster's website
rapso



Joined: 28 Mar 2005
Posts: 147

PostPosted: Sat Apr 21, 2007 11:54 pm    Post subject: Reply with quote

noxa wrote:
Edit: epeg uses libjpeg. I haven't seen a PSP port, but it is POSIX-based and when I compiled it on OS X I didn't have to make any changes.
hmm... if it rely on libjpeg, then the only improvement is the downsampling speed, but I guess the decompression with huffman and DCT ist the really time consuming stuff.

noxa wrote:
My day job deals with nothing but photos, so I've got some experience here :)
sounds like you'd be watching playboy all day long ;););)
Back to top
View user's profile Send private message
noxa



Joined: 05 Aug 2006
Posts: 39

PostPosted: Mon Apr 23, 2007 6:42 am    Post subject: Reply with quote

rapso wrote:
hmm... if it rely on libjpeg, then the only improvement is the downsampling speed, but I guess the decompression with huffman and DCT ist the really time consuming stuff.

Wrong. It only reads the lines from the image it needs for the desired size image. As long as the underlying file APIs are smart enough (and from what I've seen of newlib, they should be), a lot of file IO can be saved. In my particular use of epeg, I was loading large (3k x 3k) jpegs on crappy macs with slow hdds, and saw a large performance increase (talking of orders of magnitude in terms of time required to load/decode images). Going from loading 3000 lines 3000 pixels long to 128 lines 3000 pixels long is a big win. Not only in file IO, but in memory - on a device like the PSP it would be impossible to load an image of that size - there is not enough RAM to hold the decoded contents. epeg does a good job keeping memory usage during decoding low (and with some modification it could be made much better).

This is exactly the kind of stuff that was mentioned above, only epeg works and deals with all the nasty stuff for you.

rapso wrote:
sounds like you'd be watching playboy all day long ;););)

Funny.....?
Back to top
View user's profile Send private message Visit poster's website
Tinnus



Joined: 29 Jul 2006
Posts: 67

PostPosted: Mon Apr 23, 2007 10:23 pm    Post subject: Reply with quote

How about that...
Code:
for(y = 0; y <ImgHeight; y++)
{   
   png_read_row(png_ptr, (u8*)tempLine, png_bytep_NULL); //read a row
       
   if (y==StepY)//if the row is the one we want
   {
      //select some pixels from the row

Code:
for(y = 0; y <ImgHeight; y++)
{   
   if (y==StepY)//if the row is the one we want
   {
      png_read_row(png_ptr, (u8*)tempLine, png_bytep_NULL); //read a row
      
      //select some pixels from the row

edit: and maybe decompress the temp line thing to VRAM, it should be a little faster than RAM too. Anyway, to get the best speed possible your best bet would probably be to hack the read_row code in libpng.
_________________
Let's see what the PSP reserves... well, I'd say anything is better than Palm OS.
Back to top
View user's profile Send private message
Tong



Joined: 20 Apr 2007
Posts: 10

PostPosted: Thu Apr 26, 2007 2:33 pm    Post subject: Reply with quote

Code:
for(y = 0; y <ImgHeight; y++)
{   
   if (y==StepY)//if the row is the one we want
   {
      png_read_row(png_ptr, (u8*)tempLine, png_bytep_NULL); //read a row
     
      //select some pixels from the row


Tinnus, you have made a big mistake! This routine does not work as sequential read is used in scanning rows. In another word, if you want to scan the last row, you have to scan all those rows before it.
Back to top
View user's profile Send private message
Tong



Joined: 20 Apr 2007
Posts: 10

PostPosted: Thu Apr 26, 2007 2:54 pm    Post subject: Reply with quote

A big thanks to all who had give ideas to me especially noxa and rapso. I have spent a couple of days hacking into libepeg as recommended by noxa and I am now making use of it. Well, this library is really fantastic as noxa said, it can generate thumbnails at a terribly high speed!

As there no libepeg for psp up to now, let me share how I compile and use it with those who are interested at this useful library.

1.Download and install libjpeg (necessary, libepeg relies on it).
2.Download libepeg form http://enlightenment.freedesktop.org/fetch.php?file=epeg-0.9.0.007.tar.gz
3.Unpack the package and go into src/lib directory.
4.Open “epeg_private.h” and remove line 16 “#include “config.h”” as it is useless to us.
5.“make” it using the following Makefile:
Code:
PSPSDK=$(shell psp-config --pspsdk-path)
PSPDIR=$(shell psp-config --psp-prefix)

TARGET_LIB = libepeg.a
OBJS = epeg_main.o

INCDIR = $(PSPSDK)/../include

CFLAGS = -O2 -G0 -Wall
CXXFLAGS = $(CFLAGS) -fno-exceptions -fno-rtti
ASFLAGS = $(CFLAGS)

LIBS = -ljpeg
include $(PSPSDK)/lib/build.mak

install: $(TARGET_LIB)
   @echo "Installing libepeg into $(PSPDIR)"
   @mkdir -p $(PSPDIR)/include $(PSPDIR)/lib
   @cp Epeg.h $(PSPDIR)/include
   @cp libepeg.a  $(PSPDIR)/lib
   @echo "Done"


6.If successful, you should find Epeg.h and libepeg.a in your psp dir. You can use it now.
Back to top
View user's profile Send private message
Tong



Joined: 20 Apr 2007
Posts: 10

PostPosted: Thu Apr 26, 2007 3:09 pm    Post subject: Reply with quote

Here is a simple example for outing a 128x96 thumbnail.

Code:
#include <stdio.h>
#include <stdlib.h>
#include <pspkernel.h>
#include <pspdebug.h>
#include <Epeg.h>

PSP_MODULE_INFO("epeg", 0, 1, 1);

#define printf pspDebugScreenPrintf

int main()
{
   pspDebugScreenInit();
   //paste codes for setting up callbacks here
   
   Epeg_Image *MyImage;
   printf("Opening and reading info.\n");
   if ((MyImage = epeg_file_open("Input.jpg"))==NULL)
   {
      printf("Cannot find Input.jpg, exiting...");
      sceKernelDelayThread(2000000);
      sceKernelExitGame();
   }
   
   int width, height;
   epeg_size_get(MyImage, &width, &height);
   printf("Original dimemsion: %dx%d\n", width, height);
   
   epeg_decode_size_set(MyImage, 128, 96); //key point: size of thumbnail
   epeg_quality_set (MyImage, 85);
   epeg_thumbnail_comments_enable (MyImage, 1);
   epeg_comment_set (MyImage, "thumbnail");
   
   printf("Encoding and saving thumbnail...\n");   
   epeg_file_output_set (MyImage, "Output.jpg");
   epeg_encode (MyImage); //this creates the file
   epeg_close (MyImage); //free all allocated resources
   
   printf("Done. Exiting...");
   sceKernelDelayThread(1000000);
   sceKernelExitGame();
    return 0;   
}


And its Makefile.

Code:
TARGET = Epeg
OBJS = main.o

CFLAGS = -O2 -G0 -Wall
CXXFLAGS = $(CFLAGS) -fno-exceptions -fno-rtti
ASFLAGS = $(CFLAGS)

LIBS = -lepeg -ljpeg

EXTRA_TARGETS = EBOOT.PBP
PSP_EBOOT_TITLE = libepeg sample

PSPSDK=$(shell psp-config --pspsdk-path)
include $(PSPSDK)/lib/build.mak


See the scary speed? Note: if we read the entire file into RAM and open it using Epeg_Image *epeg_memory_open (unsigned char *data, int size), the thumbnailing speed can be further increased.
Back to top
View user's profile Send private message
noxa



Joined: 05 Aug 2006
Posts: 39

PostPosted: Fri Apr 27, 2007 2:06 am    Post subject: Reply with quote

Glad it worked for you, and thanks for posting the results. For anyone looking in the future, this will be the thread to see :)
Back to top
View user's profile Send private message Visit poster's website
Tong



Joined: 20 Apr 2007
Posts: 10

PostPosted: Fri Apr 27, 2007 3:18 pm    Post subject: Reply with quote

noxa, do you know any similar libraries for PNG thumbnailing?
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    forums.ps2dev.org Forum Index -> PSP Development All times are GMT + 10 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group