Titanium JIRA Archive
Titanium SDK/CLI (TIMOB)

[TIMOB-13436] iOS: CoverFlowView displays half image after image modification

GitHub Issuen/a
TypeBug
PriorityHigh
StatusClosed
ResolutionFixed
Resolution Date2013-04-18T21:48:34.000+0000
Affected Version/sn/a
Fix Version/s2013 Sprint 08 API, 2013 Sprint 08, Release 3.2.0
ComponentsiOS
Labelstriage
Reporternico verduin
AssigneeSabil Rahim
Created2013-04-04T16:57:08.000+0000
Updated2013-10-23T22:45:12.000+0000

Description

*Steps to Reproduce* - create a project with Alloy with a single CoverFlowView - add a couple of images - when a user clicks one of the images, modify the actual image as follows a) create a view with the actual image as background b) add a label text wit some text (i.e. Date()) c) save the view as image back to the original image file d) do a setImage () reloading the image with correct index *Actual Result* When the images are loaded the first time, they show up perfect When an image is peformed, only the top half of that image shows in the coverflowview When the app is killed and restarted, the correct images appear. The click even works perfect as the images are correctly changed *Expected Result* When an image is changed, it should display the full changed image. Not the top half. I have isolated this problem in a separate project and the results are the same.

Appc Support Team Notes

The attached project references the data directory. I have modified it to reference the resources folder; now simply drop the images into assets/iphone. I have also modified the index.xml; before the cover flow was being created off-screen. *index.xml*
<Alloy>
	<Window title="Test CoverFlowView" id="win" class="container">
        <CoverFlowView id="COVERFLOW" onClick="modifyImage"  platform="ios" width= "320" height="150">
        </CoverFlowView>
	</Window>
</Alloy>
*index.js*
var hover = $.getView('COVERFLOW');
// pointer to CoverFlowView on screen
var images = [];
var imagefiles = [];
var dir = Titanium.Filesystem.getFile(Ti.Filesystem.resourcesDirectory);
// Open the data folder
var dirItems = dir.getDirectoryListing();
// get a list of all files in this folder
var filename = null;
// contains the filename
var imagefile = null;
// contains the full image file name
var wissel = false;

// loop through the directory listing selecting all .JPG files
Ti.API.info(dirItems);
for (var i = 0; i < dirItems.length; i++) {
	// check if the file contains .JPG as extension
	// convert to string first
	filename = dirItems[i].toString();
	// if this is a .JPG file, then process it
	if (filename.indexOf('.JPG') >= 0) {
		// add  image to coverflow view
		var p = {};
		p.imageFile = Titanium.Filesystem.resourcesDirectory + filename;
		p.command = 'Add';
		AddImageToCoverFlowView(p);
		// save filename for later
		imagefiles.push(filename);
	}
}

function modifyImage(e) {
	// just change the time in the center of the image
	if (e.index < images.length) {
		var imageFile = Titanium.Filesystem.getFile(Titanium.Filesystem.resourcesDirectory, imagefiles[e.index]);
		if (imageFile.exists()) {
			// read the image first
			var image = imageFile.read();
			imageFile = null;
			// release the file handle
			// create a view to put the image in the background
			var vw = Ti.UI.createView({
				backgroundImage : image,
				width : 320,
				height : 200,
			});
			// get the current date time
			var txt = new Date();
			// create a label to put the date in
			var label = Ti.UI.createLabel({
				text : txt,
				width : Ti.UI.SIZE,
				height : Ti.UI.SIZE,
				backgroundColor : "#fff",
				color : "#000",
				font : {
					fontSize : 20,
					fontFamily : 'HelveticaNeue-Bold'
				},
				minimumFontSize : 8,
				textAlign : 'center'
			});
			// add the label to the view
			vw.add(label);
			// get an image of the new view
			var newImage = vw.toImage();
			// overwrite the old image
			var imageFile = Titanium.Filesystem.getFile(Titanium.Filesystem.resourcesDirectory, imagefiles[e.index]);
			if (imageFile.exists()) {
				imageFile.write(newImage);
			} else {
				alert('cannot find image');
			}
			// cleanup view and label
			vw.remove(label);
			vw = null;
			label = null;
			newImage = null;
			txt = null;
			// now the image is ready to be resaved on the coverflow
			var p = {};
			p.imageFile = Titanium.Filesystem.applicationDataDirectory + imagefiles[e.index];
			p.command = 'Change';
			p.index = e.index;
			AddImageToCoverFlowView(p);
		}
	}
}

win1 = $.getView('win');
win1.open();

function AddImageToCoverFlowView(p) {
	Ti.API.info(p);
	// check if it is a change or add
	if ('command' in p) {
		switch (p.command) {

			case 'Add':
				// adds an image to the end of the CoverflowView
				var image = {
					image : p.imageFile,
					height : 150,
					width : 240
				};
				images.push(image);
				hover.setImages(images);
				break;

			case 'Change':
				// make sure there is an index
				if ('index' in p) {
					if (p.index < hover.images.length) {
						hover.setImage(parseInt(p.index), images[parseInt(p.index)]);
					}
				}
				break;
		}
	}
}

Attachments

FileDateSize
app.zip2013-04-05T05:50:46.000+00005767216
Sample JPGs.zip2013-04-05T05:52:34.000+0000381947

Comments

  1. Pedro Enrique 2013-04-04

    Please upload a sample project so that we can verify it.
  2. nico verduin 2013-04-05

    This is the app folder from my standard Alloy project. index.js contains all the code. index.xml the controller xml. for the rest no adjustments
  3. nico verduin 2013-04-05

    These are the 3 sample jpgs i have used. I put them manually in the documents folder of the ios simulator
  4. Daniel Sefton 2013-04-06

    Tested and confirmed on iOS 6 simulator with 3.0.2 GA and latest 3.1 CI. Use modified code in description.
  5. nico verduin 2013-04-06

    Just for my curiosity as this is my first reported bug :) on appcelerator. Confirmed means you guys have the same results as I had? And if so, what happens next?
  6. Daniel Sefton 2013-04-07

    Confirmed means we were able to reproduce the issue on our end. The issue has been escalated to engineering who will review it and evaluate a fix or workaround.
  7. Vishal Duggal 2013-04-10

    ok two things. 1. resourcesDirectory is read only. You might want to use applicationDataDirectory to write your images 2. iOS has a bug in the imageloader where we cache images from local files and do not reload them if the backing file changes. This I will file as a bug and fix in the next release. For your app you can use the blob from the toImage method directly. So here is code that works.
       var win = Ti.UI.createWindow({backgroundColor:'white'});
       
       var hover = Ti.UI.iOS.createCoverFlowView({
           width:320,
           height:200
       })
       
       var images = [];
       var imagefiles = [];
       var dir = Titanium.Filesystem.getFile(Ti.Filesystem.resourcesDirectory);
       // Open the data folder
       var dirItems = dir.getDirectoryListing();
       // get a list of all files in this folder
       var filename = null;
       // contains the filename
       var imagefile = null;
       // contains the full image file name
       var wissel = false;
        
       // loop through the directory listing selecting all .JPG files
       Ti.API.info(dirItems);
       for (var i = 0; i < dirItems.length; i++) {
           // check if the file contains .JPG as extension
           // convert to string first
           filename = dirItems[i].toString();
           // if this is a .JPG file, then process it
           if (filename.indexOf('.JPG') >= 0) {
               // add  image to coverflow view
               var p = {};
               p.imageFile = Titanium.Filesystem.resourcesDirectory + filename;
               p.command = 'Add';
               AddImageToCoverFlowView(p);
               // save filename for later
               imagefiles.push(filename);
           }
       }
       
       function modifyImage(e) {
           // just change the time in the center of the image
           if (e.index < images.length) {
               var imageFile = Titanium.Filesystem.getFile(Titanium.Filesystem.resourcesDirectory, imagefiles[e.index]);
               if (imageFile.exists()) {
                   // read the image first
                   var image = imageFile.read();
                   imageFile = null;
                   // release the file handle
                   // create a view to put the image in the background
                   var vw = Ti.UI.createView({
                       backgroundImage : image,
                       width : 320,
                       height : 200,
                   });
                   // get the current date time
                   var txt = new Date();
                   // create a label to put the date in
                   var label = Ti.UI.createLabel({
                       text : txt,
                       width : Ti.UI.SIZE,
                       height : Ti.UI.SIZE,
                       backgroundColor : "#fff",
                       color : "#000",
                       font : {
                           fontSize : 20,
                           fontFamily : 'HelveticaNeue-Bold'
                       },
                       minimumFontSize : 8,
                       textAlign : 'center'
                   });
                   // add the label to the view
                   vw.add(label);
                   // get an image of the new view
                   var newImage = vw.toImage();
                   // overwrite the old image
                   var newImageFile = Titanium.Filesystem.getFile(Titanium.Filesystem.applicationDataDirectory, imagefiles[e.index]);
                   if (newImageFile.exists() == false) {
                       newImageFile.createFile();
                   }
                   
                   if (newImageFile.exists()) {
                       newImageFile.write(newImage);
                   } else {
                       alert('cannot find image');
                       return;
                   }
                   
       
                   // now the image is ready to be resaved on the coverflow
                   var p = {};
                   p.imageFile = Titanium.Filesystem.applicationDataDirectory + imagefiles[e.index];
                   images[e.index].image = newImage;
                   p.command = 'Change';
                   p.index = e.index;
                   AddImageToCoverFlowView(p);
               }
           }
       }
       
       function AddImageToCoverFlowView(p) {
           Ti.API.info(p);
           // check if it is a change or add
           if ('command' in p) {
               switch (p.command) {
        
                   case 'Add':
                       // adds an image to the end of the CoverflowView
                       var image = {
                           image : p.imageFile,
                           height : 150,
                           width : 240
                       };
                       images.push(image);
                       hover.setImages(images);
                       break;
        
                   case 'Change':
                       // make sure there is an index
                       if ('index' in p) {
                           if (p.index < hover.images.length) {
                               hover.setImage(parseInt(p.index), images[parseInt(p.index)]);
                           }
                       }
                       break;
               }
           }
       }
       
       
       hover.addEventListener('click',modifyImage);
       
       win.add(hover);
       
       win.open();
       
  8. Vishal Duggal 2013-04-10

    Marking this as invalid, though I found a bug in the iOS image loader when triaging his bug.
  9. nico verduin 2013-04-10

    Hi Vishal Thanks for the info. I am actually only reading and writing in the application data directory. When the guys at Appcelerator tried to verify my issue, they changed the file. so that won't be a problem. I'll try your solution tomorrow and let you know the results. This is then the real (temp) change right? var newImage = vw.toImage(function(){Ti.API.info('FORCE SYNC')}); Thanks in advance Regards Nico
  10. Vishal Duggal 2013-04-11

    @nico Yes the only change required is to change the toImage method to the sync version and to use the blob directly instead of the files you write to due to the iOS bug. And no this is not a temp change. If you intend to use the resulting blob immediately you must use the sync version of the toImage method.
  11. nico verduin 2013-04-11

    Hi Vishal Something went wrong today. But I just checked en noticed I hadn't changed to new image file. I'll fix that tomorrow. One other question: The documentation for toImage() says: Parameters callback : Callback (optional) Function to be invoked upon completion. If non-null, this method will be performed asynchronously. If null, it will be performed immediately. On Tizen, this function is asynchronous only. The callback is mandatory and function always returns "undefined". Shouldn't it be the other way around based on your comments?
  12. Vishal Duggal 2013-04-11

    @nico, You're right. Let me see whats going on.
  13. Vishal Duggal 2013-04-11

    @ncio I have updated the test code above, you were right that with callback=nil the method is synchronous. I am also reopening the ticket to see why this does not work when using files though it works when using the blobs directly. You should be unblocked for now. We'll update the ticket with any additional info.
  14. nico verduin 2013-04-11

    @vishal: Just an idea. As I am modifying an image but not changing the filename. Could that be a reason? Actually it would be nice to have a sort of refresh() function of sorts to have it reload from disk. Then it should be solved right?
  15. Sabil Rahim 2013-04-17

    PR : [4180](https://github.com/appcelerator/titanium_mobile/pull/4180)

    TESTING INSTRUCTION

    Use the following [code](https://gist.github.com/srahim/5407896) in your app.js

    Make sure to include image files with .JPG extension in the resources folder of your app.

    Click on the coverflow image to update the image with the current timestamp. Make sure the image new image does not get cropped.
  16. Wilson Luu 2013-10-23

    Closing ticket as fixed. Using Sabil's test code, verified half images are not displayed in the CoverFlowView after selecting the images. Tested on: Titanium Studio, build: 3.2.0.201310230548 OS: Mac OS X Mountain Lion (10.8.5) SDK build: 3.2.0.v20131023140842 Ti CLI: 3.2.0 (72f7426b4ee6c2d2883c666d5b7e03906a16012f) Devices: iphone 5 (6.1.3), iphone 5c (7.0.1)

JSON Source