I have a series of images that I want to make use of in an app. What I wanted to do is store them in an NSArray for easy identification within the drawRect: function.
I have created a .plist file, which details an NSDictionary with the keys simply ascending integer values, and the values corresponding to the image file names. This allows me to iterate through the dictionary and add a series of NSImage objects into the array. I am using a for loop here because the order is important and fast enumeration does not guarantee order of execution when reading from a dictionary!
Currently I am doing the following: (This is in a Subclass of NSView)
#property (strong) NSDictionary *imageNamesDict;
#property (strong) NSMutableArray *imageArray;
...
// in init method:
_imageNamesDict = [[NSDictionary alloc] initWithContentsOfFile:#"imageNames.plist"];
_imageArray = [[NSMutableArray alloc] initWithCapacity:[_imageNamesDict count]];
for (int i=0; i<_imageNamesDict.count; i++) {
NSString *key = [NSString stringWithFormat:#"%d", i];
[_imageArray addObject:[NSImage imageNamed:[_imageNamesDict objectForKey:key]];
}
// When I want to draw a particular image in drawRect:
int imageToDraw = 1;
// Get a pointer to the necessary image:
NSImage *theImage = [_imageArray objectAtIndex:imageToDraw];
// Draw the image
NSRect theRect = NSMakeRect (100,100, 0, 0);
[theImage drawInRect:theRect fromRect:NSZeroRect operation:NSCompositeCopy fraction:1.0];
This all appears to work properly, but with one quirk. I have noticed a small amount of lag that happens in drawing the display, but only when drawing a new image for the first time. Once each image has been seen at least once, I can re-draw any desired image with no lag whatsoever.
Is it that I am not loading the images properly, or is there some way that I can pre-cache each image when I create the objects to add to the for loop?
Thanks!
Assuming you have overcome the "... NSMutableDictionary instead of an NSMutableArray ..." problem pointed out in the comments, you are loading the images properly.
The lag you are describing is because [NSImage imageNamed: ] doesn't do all the work required to draw the image, so that is happening on your first draw.
You could probably get rid of the lag by drawing the images into an offscreen buffer as you add them to your array, something like:
// Create an offscreen buffer to draw in.
newImage = [[NSImage alloc] initWithSize:imageRect.size];
[newImage lockFocus];
for (int i=0; i<_imageNamesDict.count; i++) {
NSString *key = [NSString stringWithFormat:#"%d", i];
NSImage *theImage = [NSImage imageNamed:[_imageNamesDict objectForKey:key]];
[_imageArray addObject: theImage];
[theImage drawInRect:imageRect fromRect:NSZeroRect operation:NSCompositeCopy fraction:1.0];
}
[newImage unlockFocus];
[newImage release];
Related
I am trying to develop a software based on Kinect v2 and I need to keep the capturedframes in an array. I have a problem and I dont have any idea about it as follow.
The captured frames are processed by my processing class and the processed writable bitmap will be called as the source of the image box in my ui window which works perfectly and I have a realtime frames in my ui.
for example:
/// Color
_ProcessingInstance.ProcessColor(colorFrame);
ImageBoxRGB.Source = _ProcessingInstance.colorBitmap;
but when I want to assign this to an element of an array, all of the elements in array will be identical as the first frame!! I should mention that, this action is in the reading event which above action is there.
the code:
ColorFrames_Array[CapturingFrameCounter] = _ProcessingInstance.colorBitmap;
the equal check in intermediate window:
ColorFrames_Array[0].Equals(ColorFrames_Array[1])
true
ColorFrames_Array[0].Equals(ColorFrames_Array[2])
true
Please give me some hints about this problem. Any idea?
Thanks Yar
You are right and when I create a new instance, frames are saved correctly.
But my code was based on the Microsoft example and problem is that creating new instances makes the memory leakage because writablebitmap is not disposable.
similar problem is discussed in the following link which the frames are frizzed to the first frame and this is from the intrinsic properties of writeablebitmap:
http://www.wintellect.com/devcenter/jprosise/silverlight-s-big-image-problem-and-what-you-can-do-about-it
Therefore i use a strategy similar to the above solution and try to get a copy instead of the original bitmap frame. In this scenario, I have create a new writeblebitmap for each element of ColorFrames_Array[] at initialization step.
ColorFrames_Array = new riteableBitmap[MaximumFramesNumbers_Capturing];
for (int i=0; i < MaximumFramesNumbers_Capturing; ++i)
{
ColorFrames_Array[i] = new WriteableBitmap(color_width, color_height, 96.0, 96.0, PixelFormats.Bgr32, null);
}
and finally, use clone method to copy the bitmap frames to array elements.
ColorFrames_ArrayBuffer[CapturingFrameCounter] = _ProcessingInstance.colorBitmap.Clone();
While above solution works, but it has a huge memory leakage!!.
Therefore I use Array and .copypixel methods (of writeablebitmap) to copy the pixels of the frame to array and hold it (while the corresponding writeablebitmap will be disposed correctly without leakage).
public Array[] ColorPixels_Array;
for (int i=0; i< MaximumFramesNumbers_Capturing; ++i)
{
ColorPixels_Array[i]=new int[color_Width * color_Height];
}
colorBitmap.CopyPixels(ColorPixels_Array[Counter_CapturingFrame], color_Width * 4, 0);
Finally, when we want to save the arrays of pixels, we need to convert them new writeablebitmap instances and write them on hard.
wb = new WriteableBitmap(color_Width, color_Height, 96.0, 96.0, PixelFormats.Bgr32, null);
wb.WritePixels(new Int32Rect(0, 0, color_Width, color_Height)
, Ar_Px,
color_Width * 4, 0);
-(NSMutableArray *) botanicalPlant {
if (_botanicalPlant == nil) {
_botanicalPlant = [[NSMutableArray alloc] initWithObjects:#"Abelia", nil];
}
return _botanicalPlant;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.botanicalPlantName = [[BotanicalPlant alloc] init];
self.botanicalPlantNameLabel.text = []
}
I know this may be a simple question but Im stuck on this one. I have an array in NSObject of Botanical I just don't know how to call it in the viewDidLoad method for it to show up in my main view controller. I don't know what to put in the brackets to assign it to the text of the label.
You haven't shown enough code to answer your question for sure. But if botanicalPlant is a mutable array property on the BotanicalPlant class, then you could do something like:
BotanicalPlant *myBotanicalPlant = [[BotanicalPlant alloc] init];
NSMutableArray *namesArray = myBotanicalPlant.botanicalPlant;
self.botanicalPlantNameLabel.text = [namesArray firstObject];
Try This:
In your viewDidLoad method
NSMutableArray *arrayFromBotanicalMethod = [self botanicalPlant];
// Then set the text label from your new array that you created
self.botanicalPlantNameLabel.text = [arrayFromBotanicalMethod objectAtIndex:0];
This code is based on the limited information you provided. You basically create another array that will hold the returned array from your botanicalPlant method. Then you use the objectAtIndex message on the new array to get the text for the label.
Hope it helps.
I was wondering if it is possible to use the Texture2D.FromStream() in XNA to load a texture from the middle of a stream. The idea is that I have an animation system that saves the texture for the limb directly into the file that contains the other information, like timing, name, etc... My problem comes when trying to load the file, when it gets to the loading of the Texture. I get an InvalidOperationExecption, and no real detail. Here is my code so far:
Writing:
...
//writes the name
binWriter.Write(name);
if (texture != null)
{
binWriter.Write(true);
//save the texture into the stream
texture.SaveAsPng(binWriter.BaseStream, texture.Width, texture.Height);
}
else
binWriter.Write(false);
//writes the ID of the parent limb
binWriter.Write(system.getParentID((Limb)parent));
...
Reading:
...
string name = binReader.ReadString();
Texture2D tex = null;
//gets the texture if it exists
bool texture = binReader.ReadBoolean();
if (texture)
tex = Texture2D.FromStream(graphics, binReader.BaseStream);
//finds the index of the parent limb
int parentID = binReader.ReadInt32();
...
Any Ideas?
-Edit- Solved! I used the getData() and setData() methods, and wrote and read the data as an array of uints.
I have a UICollectionViewFlowLayout that basically does what I want, except for one thing - the correct alignment of UICollectionViewCells, when it is scrolling horizontally and with paging enabled.
What i basically want is this - scrolling pagewise over multiple pages:
See 1 here:
UICollectionView Pictures
My problem is, that i have multiple sections, always with this same layout, but when i scroll to the right, it gets empty (just background color), and when i scroll back to the first page (like the one above) i get a weird result:
See 2. in the link above
Apparently the index paths get somehow mixed up - and i really don't know why.
My collectionView:numberOfItemsInSection: method returns always "5", and my numberOfSectionsInCollectionView: returns "2" in this example. I have subclassed UICollectionViewFlowLayout with this:
static CGRect elementLayout[] = {
{20, 20, 649.333333, 294},
{20, 334, 314.666666, 294},
{688, 20.0, 314.666666, 294},
{354.666666, 334, 314.666666, 294},
{688, 334, 314.666666, 294},
};
-(NSArray*)layoutAttributesForElementsInRect:(CGRect)rect {
NSArray *attributes = [super layoutAttributesForElementsInRect:rect];
NSMutableArray *newAttributes = [NSMutableArray array];
for(int i = 0; i < [attributes count]; i++)
{
UICollectionViewLayoutAttributes* attrs = attributes[i];
attrs.frame = elementLayout[i];
[newAttributes addObject:attrs];
}
return newAttributes;
}
But if i don't subclass and try to make it with the standard delegate calls from UICollectionViewFlowLayout, then i get this:
See 3. in the link above
This scrolls correctly to the right, but with the wrong layout. What I expected, is that the cell with NSIndexPath [0, 1] will be on the right side of the "big" cell, and not under it. But even so, i would need the cell with NSIndexPath [0, 1] be aligned like in picture one.
Am I missing something here?
After a lot of trouble i eventually figured out, why the layout behaved strangely.
When having multiple sections, you will need to change the x-origin of every item rect by a multiple of the views width.
Even more interesting: If the UICollectionViewFlowLayout produces less cells than you anticipate, you one can override the indexPath of the UICollectionViewLayoutAttributes, to match the anticipated layout.
So the working configuration would be:
for(int i = 0; i < (countOfCellsAnticipated); i++)
{
UICollectionViewLayoutAttributes* attrs = attributes[i];
NSIndexPath* anticipatedIndexPath = [NSIndexPath indexPathForItem:i
inSection:sectionIndex];
attrs.indexPath = anticipatedIndexPath;
attrs.frame = recalculatedFrameInAbsoluteViewCoordinates;
[newAttributes addObject:attrs];
}
return newAttributes;
I have a predicament, in as much that I need to create an arbitrary amount of UIView Objects. I have an NSArray and what I need to do is create UIView Objects for the number of items in the array, so I got an int from the [NSArray count]; method, so I know the number of objects needing creating, but the way to implement this has me stumped. I'll include some psudocode below to attempt to give across what I need to do:
[UIView returnMultipleUIViewsForInt:[theArray count]];
Obviously that won't work, but some way of creating an arbitrary amount of objects at runtime, which I can work with would be good.
So in short:
I need to create a certain number of UIViews based upon the number of items in an array.
I then need to access each view that is created and use it as a regularly created view might be used, doing things like adding one of them as a subview to a different view.
- (NSArray *)createNumberOfViews:(NSInteger)number
{
NSMutableArray *viewArray = [NSMutableArray array];
for(NSInteger i = 0; i < number; i++)
{
UIView *view = [[UIView alloc] init];
// any setup you want to do would go here, e.g.:
// view.backgroundColor = [UIColor blueColor];
[viewArray addObject:view];
[view release];
}
return viewArray;
}
NSMutableArray *newViews = [NSMutableArray array];
for (int i=0; i<[theArray count]; ++i) {
UIView *view = [[UIView alloc] init];
[newViews addObject:view];
[view release];
}