Pull to refresh

Художественные обои + погодный информер

Reading time 7 min
Views 1.6K

История


Мне всегда было интересно знать какая погода за окном, тем временем использовались разные погодные информеры и вот однажды по совету знакомого я набрел на данный сайт. У сайта была своя изюминка, которая заключалась в том, что сводка погоды выводилась на фоне художественных картин, которые хочу заметить приличного качества. Все эти прелести не оставили меня равнодушным и я добавил сайт в закладки. Время шло, из закладок сайт перекочевал в превьюшку для вкладок (speed dial), которая с периодичностью обновлялась, но всё равно чего-то не хватало. И, в конце концов, мне пришла идея — делать скриншоты сайта и выводить их обоями на рабочий стол.

Цель


Реализовать идею, затратив при этом как можно меньше «ресурсов» на реализацию и сделать так чтобы процесс от создания скриншота до замены обоев происходил незаметно.

Используемые средства

  1. PhantomJS — для получения скриншотов с веб ресурсов
  2. NConvert — для преобразования картинок в различные форматы
  3. Wallpaper — для обновления обоев в Windows Vista и 7
  4. VBScript — для выполнения всех необходимых команд
  5. Планировщик заданий Windows — для регулярного обновления обоев

Реализация


Первым делом скачиваем свежие версии PhantomJS, NConvert и Wallpaper.
Увы архив с файлом «wallpaper.exe» не доступен, поэтому его можно скачать из архива с исходниками к статье, ссылка на который будет опубликована в конце.
На момент написания статьи использовались PhantomJS 1.3.0 Windows (Static build) и NConvert v5.91. Затем создаем папку «meteo_wall», в ней создаем подпапку «tools». Переходим в эту подпапку и распаковываем содержание архива «PhantomJS» в одноименную папку. Так же в папку «tools» помещаем NConvert и wallpaper.exe. Далее необходимо будет скопировать из папки примеров файл «rasterize.js» и поместить его в папку «tools». Немного подправим файл «rasterize.js» для того, чтобы можно было указывать необходимое расширение скриншотов.
var page = new WebPage(),
    address, output, size;

if (phantom.args.length < 2 || phantom.args.length > 3) {
    console.log('Usage: rasterize.js URL filename [paperwidth*paperheight|paperformat]');
    console.log('  paper (pdf output) examples: "5in*7.5in", "10cm*20cm", "A4", "Letter"');
    phantom.exit();
} else {
    address = phantom.args[0];
    output = phantom.args[1];
    page.viewportSize = { width: 600, height: 600 };
    if (phantom.args.length === 3 && phantom.args[1].substr(-4) === ".pdf") {
        size = phantom.args[2].split('*');
        page.paperSize = size.length === 2 ? { width: size[0], height: size[1], border: '0px' }
                                           : { format: phantom.args[2], orientation: 'portrait', border: '1cm' };
    }/* xrays add */
	else if(phantom.args.length === 3){
		size = phantom.args[2].split('*');
		page.viewportSize = { width: size[0], height: size[1] };
    };/* end */
	page.open(address, function (status) {
        if (status !== 'success') {
            console.log('Unable to load the address!');
        } else {
            window.setTimeout(function () {
                page.render(output);
                phantom.exit();
            }, 200);
        }
    });
}

После чего можно приступать к написанию VBScript'a. Создаем файл «wallpaper.vbs» в папке «tools» и для начала описываем в нем необходимые и заполняем важные переменные:
Dim WshShell
Set WshShell = WScript.CreateObject("Wscript.Shell")

Dim url, history, logon
' заполняем важные переменные 
url = "http://www.artmeteo.ru/4335/" ' ссылка на город
history = 1 ' оставлять загруженные ранее картинки
logon = 1 ' изменять картинку в экран приветствия Windows

Признаюсь честно, до этого я не писал код на VBScript. Для того, чтобы получать скриншоты автоматически необходимо знать разрешение экрана:
' получаем расширение экрана
Dim obj, monSize
Set obj = CreateObject("htmlfile")
monSize = obj.parentWindow.screen.width & "*" & obj.parentWindow.screen.height

Далее:
' получаем необходимые пути
' получаем необходимые пути
Dim toolsPath, path
Set obj = CreateObject("Scripting.FileSystemObject") ' Получаем доступ к обьекту obj
toolsPath = obj.GetParentFolderName(WScript.ScriptFullName) & "\" ' путь до папки со скриптом
path = obj.GetParentFolderName(toolsPath) & "\" ' путь до главной папки

' формируем необходимые пути и загружаем скриншот сайта 
Dim phantom, bmpname
phantom = toolsPath&"phantomjs\" ' путь до phantomjs
bmpname = path&"url.bmp " ' имя для bmp файла
WshShell.Run phantom & "phantomjs.exe " & toolsPath & "rasterize.js " & url & " " & bmpname & monSize, 0, True ' скачиваем картинку с сайта

Примечании: в конце последней строки используются параметры 0, True необходимые для того, чтобы код выполнился в фоне и дальнейшие команды, описанные в скрипте, ожидали выполнения этого кода.
Как можно заметить, то скриншот сохраняется в формате bmp, сделано это потому что версии ОС Windows младше Vista плохо воспринимают обои в другом формате. Далее определяем версию ОС:
Dim OSType
OSType = Left(Trim(WshShell.RegRead("HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\CurrentVersion")),1) ' определяем версию windows
Dim convert, n, time, jpgname, wallpaper

Так как скрипт должен быть максимально универсальным, но с разными версиями ОС нужно тоже считаться, то для начала описываем код для Windows Vista и 7:
If OSType>5 Then ' если это Windows Vista или Windows 7
	' преобразование из bmp в jpg
	Dim quality
	quality = 95 ' качество для jpg картинки
	convert = toolsPath & "nconvert.exe -out jpeg -q " & quality & " -i -overwrite -o "
	n = Now ' используем для сокращения глобальной переменной
	time = Right("00" & Day(n), 2) & "-" & Right("00" & Month(n), 2) & "-" & Right("00" & Year(n), 2) & "_" & Right("00" & Hour(n), 2) & "_" & Right("00" & Minute(n), 2) & "_" & Right("00" & Second(n), 2) ' создаем имя
	jpgname = path & time & ".jpg " ' имя для jpg файла
	WshShell.Run convert & jpgname & bmpname, 0, True ' преобразуем из bmp в jpeg

	' изменяем фон на текущую картинку
	wallpaper = WshShell.ExpandEnvironmentStrings("%APPDATA%") & "\Microsoft\Windows\Themes\TranscodedWallpaper.jpg" ' путь до обоев
	obj.CopyFile jpgname, wallpaper ' копируем jpg картинку в станд.папку для обоев
	WshShell.RegWrite "HKCU\Control Panel\Desktop\Wallpaper", wallpaper ' изменяем запись в реестре о пути до фона рабочего стола

	' картинка для logon
	Dim logonname
	logonname = WshShell.ExpandEnvironmentStrings("%windir%") & "\System32\oobe\info\backgrounds\backgroundDefault.jpg " ' путь до logon картинки
	If logon = 1 Then ' если нужно изменить logon
		Dim logonconvert, goodlogon
		Set file = obj.GetFile(jpgname) ' получаем инфу о картинке для logon
		If Round(file.size/1024) < 256 Then ' если картинка уже < 256, то продолжаем без подбора качества
			goodlogon = 1
			obj.CopyFile jpgname, logonname
		Else
			goodlogon = 0
			quality = quality - 3
		End If
		' подбираем качество картинки для logon
		While goodlogon = 0
			logonconvert = toolsPath & "nconvert.exe -out jpeg -q " & quality & " -i -overwrite -o " ' -canvas 1280 800 top-left 
			WshShell.Run logonconvert & logonname & bmpname, 0, True
			Set file = obj.GetFile(logonname) ' получаем инфу о картинке для logon
			If Round(file.size/1024) < 256 Then ' если размер < 256 Kb, то переходим дальше
				goodlogon = 1
			Else
				quality = quality - 3 ' иначе уменьшаем качество картинки
			End If
		Wend
		WshShell.RegWrite "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\LogonUI\Background\OEMBackground", 1, "REG_DWORD"
	Else
		If obj.FileExists(logonname) Then
			obj.DeleteFile logonname, True ' удаляем logon картинку, чтоб вернуть стандартную
		End If
	End If

	If history = 0 Then ' если не нужно сохранять историю картинок, то удаляем jpg картинку
		obj.DeleteFile jpgname, True
	End If

	WshShell.Run toolsPath & "wallpaper.exe", 0, True ' даем Windows понять что пора обновить обои

Можно заметить, что в этом коде происходит изменение logon картинки(картинка экрана приветствия), к которой применяются требования Windows. Суть этих требований заключается в том, что файл не может быть больше 256 Кб, поэтому происходит запуск цикла по уменьшению качества картинки, пока не будет достигнут допустимый порог ограничения.
Теперь пришёл черед описать код для младших версий ОС Windows:
Else ' если это младшие версии Windows
	' изменяем фон на текущую картинку
	wallpaper = WshShell.ExpandEnvironmentStrings("%appdata%") & "\Wallpaper.bmp" ' путь до обоев
	obj.CopyFile bmpname, wallpaper ' копируем bmp картинку в станд.папку для обоев
	WshShell.RegWrite "HKCU\Control Panel\Desktop\Wallpaper", wallpaper ' изменяем запись в реестре о пути до фона рабочего стола

	' картинка для logon
	Dim Background, Winlogon
	If logon = 1 Then ' если нужно изменить logon
		Background = 1
		Winlogon = 0
		WshShell.RegWrite "HKEY_USERS\.DEFAULT\Control Panel\Desktop\TileWallpaper", 1, "REG_SZ" ' Значение: (0 = по умолчанию; 1 = плитка (замостить))
	Else
		Background = 0
		wallpaper = ""
		Winlogon = 1
	End If
	WshShell.RegWrite "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\LogonUI\Background\OEMBackground", Background, "REG_DWORD" ' изменяем состояние исользования стандартной logon картинки 
	WshShell.RegWrite "HKEY_USERS\.DEFAULT\Control Panel\Desktop\Wallpaper", wallpaper, "REG_SZ"' изменяем запись в реестре о пути до logon картинки
	' WshShell.RegWrite "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\LogonType", Winlogon, "REG_DWORD" ' 1 - используется страница приветствия, 0 - используется классический вход в систему

	If history = 1 Then ' если нужно сохранять историю картинок, то удаляем преобразуем картинку из bmp в jpg (95% качество)
		convert = toolsPath & "nconvert.exe -out jpeg -q 95 -overwrite -o "
		n = Now
		time = Right("00" & Day(n), 2) & "-" & Right("00" & Month(n), 2) & "-" & Right("00" & Year(n), 2) & "_" & Right("00" & Hour(n), 2) & "_" & Right("00" & Minute(n), 2) & "_" & Right("00" & Second(n), 2) ' создаем имя
		jpgname = path & time & ".jpg "
		WshShell.Run convert & jpgname & bmpname, 0, True ' из bmp в jpg
	End If

	WshShell.Run "%windir%\System32\RUNDLL32.EXE user32.dll,UpdatePerUserSystemParameters", 0, True ' даем винде понять что пора обновить обои
End If

Заключительные «окорды» скрипта:

obj.DeleteFile bmpname, True ' удаляем bmp картинку
Set WshShell = Nothing

На этом написания скрипта закончено. Автоматическое выполнение скрипта, например каждые 5 минут, сделаем, воспользовавшись встроенным планировщиком заданий Windows. Для этого создаем новое задание и указываем в качестве запускаемой программы путь до скрипта «wallpaper.vbs», а так же не забываем в свойствах для срабатывания триггера выбрать ежедневно и повтор каждые 5 минут.

Итоги


Работа скрипта проверена на 2 компьютерах с Windows 7, на одном с Windows 2003 Server и на одном с Windows XP. Для того чтобы в Windows XP были видны изменения экрана приветствия необходимо либо в «Панель управления -> Учетные записи пользователей -> Изменения входа пользователей в систему» убрать галочку с пункта «Использовать страницу приветствия», либо раскомментировать 100 строку в исходнике скрипта. Исходники скрипта, со всем дополнительным софтом можно забрать от сюда.

Обновления


Появилась возможность проверить работу скрипта на ещё одном компьютере с Windows 7, но удачный запуск не увенчался успехом. Проблема заключалась в том, что появлялась ошибка об отсутствии пути до файла, в котором хранится картинка экрана приветствия. Опытным путем было найдено решение, которое заключается либо в создании вручную следующего пути "%windir%\System32\oobe\info\backgrounds\", либо в изменении параметров контроля учетных записей(UAC) до самого низкого, с последующей перезагрузкой компьютера и обновлением скрипта, который можно скачать здесь.
Tags:
Hubs:
-2
Comments 6
Comments Comments 6

Articles