bool CPicture::CreateTiledThumb(const std::vector<std::string> &files, const std::string &thumb) { if (!files.size()) return false; unsigned int num_across = (unsigned int)ceil(sqrt((float)files.size())); unsigned int num_down = (files.size() + num_across - 1) / num_across; unsigned int tile_width = g_advancedSettings.m_imageRes / num_across; unsigned int tile_height = g_advancedSettings.m_imageRes / num_down; unsigned int tile_gap = 1; bool success = false; // create a buffer for the resulting thumb uint32_t *buffer = (uint32_t *)calloc(g_advancedSettings.m_imageRes * g_advancedSettings.m_imageRes, 4); for (unsigned int i = 0; i < files.size(); ++i) { int x = i % num_across; int y = i / num_across; // load in the image unsigned int width = tile_width - 2*tile_gap, height = tile_height - 2*tile_gap; CBaseTexture *texture = CTexture::LoadFromFile(files[i], width, height, true); if (texture && texture->GetWidth() && texture->GetHeight()) { GetScale(texture->GetWidth(), texture->GetHeight(), width, height); // scale appropriately uint32_t *scaled = new uint32_t[width * height]; if (ScaleImage(texture->GetPixels(), texture->GetWidth(), texture->GetHeight(), texture->GetPitch(), (uint8_t *)scaled, width, height, width * 4)) { if (!texture->GetOrientation() || OrientateImage(scaled, width, height, texture->GetOrientation())) { success = true; // Flag that we at least had one successful image processed // drop into the texture unsigned int posX = x*tile_width + (tile_width - width)/2; unsigned int posY = y*tile_height + (tile_height - height)/2; uint32_t *dest = buffer + posX + posY*g_advancedSettings.m_imageRes; uint32_t *src = scaled; for (unsigned int y = 0; y < height; ++y) { memcpy(dest, src, width*4); dest += g_advancedSettings.m_imageRes; src += width; } } } delete[] scaled; } delete texture; } // now save to a file if (success) success = CreateThumbnailFromSurface((uint8_t *)buffer, g_advancedSettings.m_imageRes, g_advancedSettings.m_imageRes, g_advancedSettings.m_imageRes * 4, thumb); free(buffer); return success; }
CBaseTexture *CTextureCacheJob::LoadImage(const CStdString &image, unsigned int width, unsigned int height, const std::string &additional_info) { if (additional_info == "music") { // special case for embedded music images MUSIC_INFO::EmbeddedArt art; if (CMusicThumbLoader::GetEmbeddedThumb(image, art)) return CBaseTexture::LoadFromFileInMemory(&art.data[0], art.size, art.mime, width, height); } // Validate file URL to see if it is an image CFileItem file(image, false); if (!(file.IsPicture() && !(file.IsZIP() || file.IsRAR() || file.IsCBR() || file.IsCBZ() )) && !file.GetMimeType().Left(6).Equals("image/") && !file.GetMimeType().Equals("application/octet-stream")) // ignore non-pictures return NULL; CBaseTexture *texture = CBaseTexture::LoadFromFile(image, width, height, g_guiSettings.GetBool("pictures.useexifrotation")); if (!texture) return NULL; // EXIF bits are interpreted as: <flipXY><flipY*flipX><flipX> // where to undo the operation we apply them in reverse order <flipX>*<flipY*flipX>*<flipXY> // When flipped we have an additional <flipX> on the left, which is equivalent to toggling the last bit if (additional_info == "flipped") texture->SetOrientation(texture->GetOrientation() ^ 1); return texture; }
bool CTextureCacheJob::CacheTexture(CBaseTexture **out_texture) { // unwrap the URL as required bool flipped; unsigned int width, height; CStdString image = DecodeImageURL(m_url, width, height, flipped); m_details.updateable = UpdateableURL(image); // generate the hash m_details.hash = GetImageHash(image); if (m_details.hash.empty()) return false; else if (m_details.hash == m_oldHash) return true; CBaseTexture *texture = LoadImage(image, width, height, flipped); if (texture) { if (texture->HasAlpha()) m_details.file = m_cachePath + ".png"; else m_details.file = m_cachePath + ".jpg"; if (width > 0 && height > 0) CLog::Log(LOGDEBUG, "%s image '%s' at %dx%d with orientation %d as '%s'", m_oldHash.IsEmpty() ? "Caching" : "Recaching", image.c_str(), width, height, texture->GetOrientation(), m_details.file.c_str()); else CLog::Log(LOGDEBUG, "%s image '%s' fullsize with orientation %d as '%s'", m_oldHash.IsEmpty() ? "Caching" : "Recaching", image.c_str(), texture->GetOrientation(), m_details.file.c_str()); if (CPicture::CacheTexture(texture, width, height, CTextureCache::GetCachedPath(m_details.file))) { m_details.width = width; m_details.height = height; if (out_texture) // caller wants the texture *out_texture = texture; else delete texture; return true; } } delete texture; return false; }