2 * Copyright (C) 2005-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
22 #if (defined HAVE_CONFIG_H) && (!defined WIN32)
27 #include "settings/AdvancedSettings.h"
28 #include "settings/GUISettings.h"
30 #include "filesystem/File.h"
31 #include "utils/log.h"
32 #include "utils/URIUtils.h"
33 #include "DllSwScale.h"
34 #include "guilib/Texture.h"
35 #include "guilib/imagefactory.h"
36 #if defined(HAS_OMXPLAYER)
37 #include "cores/omxplayer/OMXImage.h"
40 using namespace XFILE;
42 bool CPicture::CreateThumbnailFromSurface(const unsigned char *buffer, int width, int height, int stride, const CStdString &thumbFile)
44 CLog::Log(LOGDEBUG, "cached image '%s' size %dx%d", thumbFile.c_str(), width, height);
45 if (URIUtils::GetExtension(thumbFile).Equals(".jpg"))
47 #if defined(HAS_OMXPLAYER)
48 COMXImage *omxImage = new COMXImage();
49 if (omxImage && omxImage->CreateThumbnailFromSurface((BYTE *)buffer, width, height, XB_FMT_A8R8G8B8, stride, thumbFile.c_str()))
58 unsigned char *thumb = NULL;
59 unsigned int thumbsize=0;
60 IImage* pImage = ImageFactory::CreateLoader(thumbFile);
61 if(pImage == NULL || !pImage->CreateThumbnailFromSurface((BYTE *)buffer, width, height, XB_FMT_A8R8G8B8, stride, thumbFile.c_str(), thumb, thumbsize))
63 CLog::Log(LOGERROR, "Failed to CreateThumbnailFromSurface for %s", thumbFile.c_str());
69 if (file.OpenForWrite(thumbFile, true))
71 file.Write(thumb, thumbsize);
73 pImage->ReleaseThumbnailBuffer();
77 pImage->ReleaseThumbnailBuffer();
82 CThumbnailWriter::CThumbnailWriter(unsigned char* buffer, int width, int height, int stride, const CStdString& thumbFile)
88 m_thumbFile = thumbFile;
91 bool CThumbnailWriter::DoWork()
95 if (!CPicture::CreateThumbnailFromSurface(m_buffer, m_width, m_height, m_stride, m_thumbFile))
97 CLog::Log(LOGERROR, "CThumbnailWriter::DoWork unable to write %s", m_thumbFile.c_str());
106 bool CPicture::CacheTexture(CBaseTexture *texture, uint32_t &dest_width, uint32_t &dest_height, const std::string &dest)
108 return CacheTexture(texture->GetPixels(), texture->GetWidth(), texture->GetHeight(), texture->GetPitch(),
109 texture->GetOrientation(), dest_width, dest_height, dest);
112 bool CPicture::CacheTexture(uint8_t *pixels, uint32_t width, uint32_t height, uint32_t pitch, int orientation, uint32_t &dest_width, uint32_t &dest_height, const std::string &dest)
114 // if no max width or height is specified, don't resize
117 if (dest_height == 0)
118 dest_height = height;
120 uint32_t max_height = g_advancedSettings.m_imageRes;
121 if (g_advancedSettings.m_fanartRes > g_advancedSettings.m_imageRes)
122 { // a separate fanart resolution is specified - check if the image is exactly equal to this res
123 if (width * 9 == height * 16 && height >= g_advancedSettings.m_fanartRes)
124 { // special case for 16x9 images larger than the fanart res
125 max_height = g_advancedSettings.m_fanartRes;
128 uint32_t max_width = max_height * 16/9;
130 dest_height = std::min(dest_height, max_height);
131 dest_width = std::min(dest_width, max_width);
133 if (width > dest_width || height > dest_height || orientation)
135 bool success = false;
137 dest_width = std::min(width, dest_width);
138 dest_height = std::min(height, dest_height);
140 // create a buffer large enough for the resulting image
141 GetScale(width, height, dest_width, dest_height);
142 uint32_t *buffer = new uint32_t[dest_width * dest_height];
145 if (ScaleImage(pixels, width, height, pitch,
146 (uint8_t *)buffer, dest_width, dest_height, dest_width * 4))
148 if (!orientation || OrientateImage(buffer, dest_width, dest_height, orientation))
150 success = CreateThumbnailFromSurface((unsigned char*)buffer, dest_width, dest_height, dest_width * 4, dest);
158 { // no orientation needed
160 dest_height = height;
161 return CreateThumbnailFromSurface(pixels, width, height, pitch, dest);
166 bool CPicture::CreateTiledThumb(const std::vector<std::string> &files, const std::string &thumb)
171 unsigned int num_across = (unsigned int)ceil(sqrt((float)files.size()));
172 unsigned int num_down = (files.size() + num_across - 1) / num_across;
174 unsigned int tile_width = g_advancedSettings.GetThumbSize() / num_across;
175 unsigned int tile_height = g_advancedSettings.GetThumbSize() / num_down;
176 unsigned int tile_gap = 1;
177 bool success = false;
179 // create a buffer for the resulting thumb
180 uint32_t *buffer = (uint32_t *)calloc(g_advancedSettings.GetThumbSize() * g_advancedSettings.GetThumbSize(), 4);
181 for (unsigned int i = 0; i < files.size(); ++i)
183 int x = i % num_across;
184 int y = i / num_across;
186 unsigned int width = tile_width - 2*tile_gap, height = tile_height - 2*tile_gap;
187 CBaseTexture *texture = CTexture::LoadFromFile(files[i], width, height, g_guiSettings.GetBool("pictures.useexifrotation"));
188 if (texture && texture->GetWidth() && texture->GetHeight())
190 GetScale(texture->GetWidth(), texture->GetHeight(), width, height);
192 // scale appropriately
193 uint32_t *scaled = new uint32_t[width * height];
194 if (ScaleImage(texture->GetPixels(), texture->GetWidth(), texture->GetHeight(), texture->GetPitch(),
195 (uint8_t *)scaled, width, height, width * 4))
197 if (!texture->GetOrientation() || OrientateImage(scaled, width, height, texture->GetOrientation()))
199 success = true; // Flag that we at least had one succesfull image processed
200 // drop into the texture
201 unsigned int posX = x*tile_width + (tile_width - width)/2;
202 unsigned int posY = y*tile_height + (tile_height - height)/2;
203 uint32_t *dest = buffer + posX + posY*g_advancedSettings.GetThumbSize();
204 uint32_t *src = scaled;
205 for (unsigned int y = 0; y < height; ++y)
207 memcpy(dest, src, width*4);
208 dest += g_advancedSettings.GetThumbSize();
217 // now save to a file
219 success = CreateThumbnailFromSurface((uint8_t *)buffer, g_advancedSettings.GetThumbSize(), g_advancedSettings.GetThumbSize(),
220 g_advancedSettings.GetThumbSize() * 4, thumb);
226 void CPicture::GetScale(unsigned int width, unsigned int height, unsigned int &out_width, unsigned int &out_height)
228 float aspect = (float)width / height;
229 if ((unsigned int)(out_width / aspect + 0.5f) > out_height)
230 out_width = (unsigned int)(out_height * aspect + 0.5f);
232 out_height = (unsigned int)(out_width / aspect + 0.5f);
235 bool CPicture::ScaleImage(uint8_t *in_pixels, unsigned int in_width, unsigned int in_height, unsigned int in_pitch,
236 uint8_t *out_pixels, unsigned int out_width, unsigned int out_height, unsigned int out_pitch)
238 DllSwScale dllSwScale;
240 struct SwsContext *context = dllSwScale.sws_getContext(in_width, in_height, PIX_FMT_BGRA,
241 out_width, out_height, PIX_FMT_BGRA,
242 SWS_FAST_BILINEAR | SwScaleCPUFlags(), NULL, NULL, NULL);
244 uint8_t *src[] = { in_pixels, 0, 0, 0 };
245 int srcStride[] = { (int)in_pitch, 0, 0, 0 };
246 uint8_t *dst[] = { out_pixels , 0, 0, 0 };
247 int dstStride[] = { (int)out_pitch, 0, 0, 0 };
251 dllSwScale.sws_scale(context, src, srcStride, 0, in_height, dst, dstStride);
252 dllSwScale.sws_freeContext(context);
258 bool CPicture::OrientateImage(uint32_t *&pixels, unsigned int &width, unsigned int &height, int orientation)
260 // ideas for speeding these functions up: http://cgit.freedesktop.org/pixman/tree/pixman/pixman-fast-path.c
265 out = FlipHorizontal(pixels, width, height);
268 out = Rotate180CCW(pixels, width, height);
271 out = FlipVertical(pixels, width, height);
274 out = Transpose(pixels, width, height);
277 out = Rotate270CCW(pixels, width, height);
280 out = TransposeOffAxis(pixels, width, height);
283 out = Rotate90CCW(pixels, width, height);
286 CLog::Log(LOGERROR, "Unknown orientation %i", orientation);
292 bool CPicture::FlipHorizontal(uint32_t *&pixels, unsigned int &width, unsigned int &height)
294 // this can be done in-place easily enough
295 for (unsigned int y = 0; y < height; ++y)
297 uint32_t *line = pixels + y * width;
298 for (unsigned int x = 0; x < width / 2; ++x)
299 std::swap(line[x], line[width - 1 - x]);
304 bool CPicture::FlipVertical(uint32_t *&pixels, unsigned int &width, unsigned int &height)
306 // this can be done in-place easily enough
307 for (unsigned int y = 0; y < height / 2; ++y)
309 uint32_t *line1 = pixels + y * width;
310 uint32_t *line2 = pixels + (height - 1 - y) * width;
311 for (unsigned int x = 0; x < width; ++x)
312 std::swap(*line1++, *line2++);
317 bool CPicture::Rotate180CCW(uint32_t *&pixels, unsigned int &width, unsigned int &height)
319 // this can be done in-place easily enough
320 for (unsigned int y = 0; y < height / 2; ++y)
322 uint32_t *line1 = pixels + y * width;
323 uint32_t *line2 = pixels + (height - 1 - y) * width + width - 1;
324 for (unsigned int x = 0; x < width; ++x)
325 std::swap(*line1++, *line2--);
328 { // height is odd, so flip the middle row as well
329 uint32_t *line = pixels + (height - 1)/2 * width;
330 for (unsigned int x = 0; x < width / 2; ++x)
331 std::swap(line[x], line[width - 1 - x]);
336 bool CPicture::Rotate90CCW(uint32_t *&pixels, unsigned int &width, unsigned int &height)
338 uint32_t *dest = new uint32_t[width * height * 4];
341 unsigned int d_height = width, d_width = height;
342 for (unsigned int y = 0; y < d_height; y++)
344 const uint32_t *src = pixels + (d_height - 1 - y); // y-th col from right, starting at top
345 uint32_t *dst = dest + d_width * y; // y-th row from top, starting at left
346 for (unsigned int x = 0; x < d_width; x++)
354 std::swap(width, height);
360 bool CPicture::Rotate270CCW(uint32_t *&pixels, unsigned int &width, unsigned int &height)
362 uint32_t *dest = new uint32_t[width * height * 4];
366 unsigned int d_height = width, d_width = height;
367 for (unsigned int y = 0; y < d_height; y++)
369 const uint32_t *src = pixels + width * (d_width - 1) + y; // y-th col from left, starting at bottom
370 uint32_t *dst = dest + d_width * y; // y-th row from top, starting at left
371 for (unsigned int x = 0; x < d_width; x++)
380 std::swap(width, height);
384 bool CPicture::Transpose(uint32_t *&pixels, unsigned int &width, unsigned int &height)
386 uint32_t *dest = new uint32_t[width * height * 4];
390 unsigned int d_height = width, d_width = height;
391 for (unsigned int y = 0; y < d_height; y++)
393 const uint32_t *src = pixels + y; // y-th col from left, starting at top
394 uint32_t *dst = dest + d_width * y; // y-th row from top, starting at left
395 for (unsigned int x = 0; x < d_width; x++)
404 std::swap(width, height);
408 bool CPicture::TransposeOffAxis(uint32_t *&pixels, unsigned int &width, unsigned int &height)
410 uint32_t *dest = new uint32_t[width * height * 4];
414 unsigned int d_height = width, d_width = height;
415 for (unsigned int y = 0; y < d_height; y++)
417 const uint32_t *src = pixels + width * (d_width - 1) + (d_height - 1 - y); // y-th col from right, starting at bottom
418 uint32_t *dst = dest + d_width * y; // y-th row, starting at left
419 for (unsigned int x = 0; x < d_width; x++)
428 std::swap(width, height);