-
-
Save nbergont/8963892 to your computer and use it in GitHub Desktop.
| import QtQuick 2.0 | |
| import Qt.labs.folderlistmodel 2.0 | |
| /** | |
| --- QML Ken Burns slideshow --- | |
| Work well on Raspberry Pi (resize image 1920*1600 max before ...) | |
| call : | |
| qmlscene slideshow.qml path="/home/img" | |
| qmlscene.exe slideshow.qml path="/C:/test/img" | |
| **/ | |
| Rectangle { | |
| id: root | |
| width: 800 | |
| height: 600 | |
| color: "black" | |
| focus: true | |
| Keys.onEscapePressed :{ | |
| Qt.quit(); | |
| } | |
| //Slideshow options : | |
| property int slide_duration: 7000 //ms | |
| property int fade_duration: 800 | |
| //Load 2 slides | |
| Loader {id:img1; transformOrigin: Item.TopLeft; sourceComponent: slide;} | |
| Loader {id:img2; transformOrigin: Item.TopLeft; sourceComponent: slide;} | |
| property variant current_img: img1 | |
| //Input images files | |
| FolderListModel{ | |
| id: img_files | |
| folder : "file://" + Qt.application.arguments[2].split("=")[1] | |
| nameFilters: ["*.jpg", "*.jpeg", "*.png"] | |
| showDirs : false | |
| property int index: 0 | |
| property variant rlist: [] | |
| function getNextUrl(){ | |
| if(index >= rlist.length) | |
| shuffleList(); | |
| return img_files.get(rlist[index++], "fileURL"); //filePath | |
| } | |
| //Fisher-Yates shuffle algorithm. | |
| function shuffleArray(array) { | |
| for (var i = array.length - 1; i > 0; i--) { | |
| var j = Math.floor(Math.random() * (i + 1)); | |
| var temp = array[i]; | |
| array[i] = array[j]; | |
| array[j] = temp; | |
| } | |
| return array; | |
| } | |
| function shuffleList() | |
| { | |
| console.log("Shuffle..."); | |
| var list = []; | |
| for(var i=0; i<img_files.count; i++) | |
| list.push(i); | |
| shuffleArray(list); | |
| rlist = list; | |
| index = 0; | |
| } | |
| //Initialisation | |
| onDataChanged: { | |
| console.log(img_files.count+ " images found"); | |
| shuffleList(); | |
| //Force la lecture de la 1ere image | |
| img1.item.asynchronous = false | |
| img1.item.visible = true; | |
| img1.item.load_next_slide(); | |
| img2.item.load_next_slide(); | |
| img1.item.asynchronous = true; | |
| mtimer.start(); | |
| } | |
| } | |
| //Main timer | |
| Timer{ | |
| id:mtimer | |
| interval: slide_duration-fade_duration | |
| repeat: true | |
| triggeredOnStart : true | |
| onTriggered: { | |
| current_img.item.fadein(); | |
| current_img = (current_img == img1 ? img2 : img1); //Swap img | |
| current_img.item.fadeout(); | |
| } | |
| } | |
| //Slide component | |
| Component { | |
| id: slide | |
| Image { | |
| id: img | |
| asynchronous : true | |
| cache: false | |
| fillMode: Image.PreserveAspectFit | |
| //visible: true | |
| opacity: 0 | |
| width: root.width | |
| height: root.height | |
| //Max painted size (RPI limitations) | |
| sourceSize.width: 1920 | |
| sourceSize.height: 1600 | |
| property real from_scale: 1 | |
| property real to_scale: 1 | |
| property real from_x: 0 | |
| property real to_x: 0 | |
| property real from_y: 0 | |
| property real to_y: 0 | |
| function randRange(a, b){return Math.random()*Math.abs(a-b) + Math.min(a,b);} | |
| function randChoice(n){return Math.round(Math.random()*(n-1));} | |
| function randDirection(){return (Math.random() >= 0.5) ? 1 : -1;} | |
| function fadein(){ | |
| //Check image loading... | |
| if(status != Image.Ready){ | |
| console.log("LOAD ERROR", source); | |
| return; | |
| } | |
| //Fit in view | |
| var img_ratio = paintedWidth/paintedHeight; | |
| var scale = (height == paintedHeight) ? width/paintedWidth : height/paintedHeight; | |
| //Find random directions | |
| if(img_ratio < 1){ //Rotated | |
| from_scale = scale*0.8;//Un-zoom on 16/9 viewer... | |
| to_scale = from_scale; | |
| from_y = 0; | |
| to_y = 0; | |
| from_x = randDirection()*(paintedHeight*from_scale-height)/2; | |
| to_x = 0; | |
| } | |
| else if(img_ratio > 2){ //Panorama | |
| from_scale = scale; | |
| to_scale = from_scale; | |
| from_y = randDirection()*(paintedWidth*from_scale-width)/2; | |
| to_y = -from_y; | |
| from_x = 0; | |
| to_x = 0; | |
| } | |
| else { //Normal | |
| var type = randChoice(3); | |
| switch(type) | |
| { | |
| case 0: //Zoom in | |
| from_scale = scale; | |
| to_scale = scale*1.4; | |
| from_y = 0; | |
| to_y = 0; | |
| from_x = 0; | |
| to_x = 0; | |
| break; | |
| case 1: //Zoom out | |
| from_scale = scale*1.4; | |
| to_scale = scale; | |
| from_y = 0; | |
| to_y = 0; | |
| from_x = 0; | |
| to_x = 0; | |
| break; | |
| default: //Fixed zoom | |
| from_scale = scale*1.2; | |
| to_scale = from_scale; | |
| break; | |
| } | |
| //Random x,y | |
| var from_max_y = (paintedWidth*from_scale-width)/2; | |
| var to_max_y = (paintedWidth*to_scale-width)/2; | |
| from_y = randRange(-from_max_y, from_max_y); | |
| to_y = randRange(-to_max_y, to_max_y); | |
| var from_max_x = (paintedHeight*from_scale-height)/2; | |
| var to_max_x = (paintedHeight*to_scale-height)/2; | |
| from_x = randRange(-from_max_x, from_max_x); | |
| to_x = randRange(-to_max_x, to_max_x); | |
| } | |
| visible = true; | |
| afadein.start(); | |
| } | |
| function fadeout(){ | |
| afadeout.start(); | |
| } | |
| function load_next_slide(){ | |
| visible = false; | |
| source = img_files.getNextUrl(); | |
| console.log(source); | |
| } | |
| ParallelAnimation{ | |
| id: afadein | |
| NumberAnimation {target: img; property: "opacity"; from: 0; to: 1; duration: fade_duration; easing.type: Easing.InOutQuad;} | |
| NumberAnimation {target: img; property: "y"; from: from_x; to: to_x; duration: slide_duration; } | |
| NumberAnimation {target: img; property: "x"; from: from_y; to: to_y; duration: slide_duration; } | |
| NumberAnimation {target: img; property: "scale"; from: from_scale; to: to_scale; duration: slide_duration; } | |
| } | |
| SequentialAnimation { | |
| id: afadeout; | |
| NumberAnimation{ target: img; property: "opacity"; from: 1; to: 0; duration: fade_duration; easing.type: Easing.InOutQuad;} | |
| ScriptAction { script: img.load_next_slide(); } | |
| } | |
| } | |
| } | |
| } |
It is the limitation of Raspberry Pi texture size ! (exact limit is 2048*2048)
Hi!
I am quite new to Qt/QML but your source is a good inspiration - I wonder, if somebody could tell me, how I could include "QtGraphicalEffects" such as "HueSaturation" into the QML? I just wanted to use them to apply some "filters" to adjust brightness, contrast etc.
Thanks a lot,
Sven
Thank you, this works really well.
I'm completely new to Qt/QML and struggled to get qmlscene working initially. For some reason I couldn't get the hardware acceleration to work in Jessie. However, I found a prebuilt version of Qt5 for Raspbian Wheezy and some instructions at the following page https://www.raspberrypi.org/forums/viewtopic.php?t=70784&p=526245
Thanks again for posting this.
Hi,
can someone explain to me, where the following limitation for the RPI comes from ( code lines 111-113)?
Thanks a lot,
Ben