i found an issue with Photo Library Images. It not displaying first time in my View,Image View is blank while loading first time.
Because i found Asset Library block working on another thread.After reloading my View ,I can see all the Images. However first time the Image Views are Blank.
can any one tell me a good way to deal with the problem
It working with Bundle Images.
also some times console shows that
app is crashing due to Program received signal: “0”. Data Formatters temporarily unavailable, will re-try after a 'continue'. (Unknown error loading shared library "/Developer/usr/lib/libXcodeDebuggerSupport.dylib")
My Code:
for (int j = 0; j<9; j++)
{
//allocating View
UIView *smallView = [[UIView alloc] initWithFrame:CGRectMake(xCordImage, yCordImage, 200, 190)];
// allocating ImageView
imageViewTopic = [[[UIImageView alloc] init] autorelease];
typedef void (^ALAssetsLibraryAssetForURLResultBlock)(ALAsset *asset);
typedef void (^ALAssetsLibraryAccessFailureBlock)(NSError *error);
ALAssetsLibraryAssetForURLResultBlock resultblock = ^(ALAsset *myasset)
{
ALAssetRepresentation *rep = [myasset defaultRepresentation];
CGImageRef iref = [rep fullResolutionImage];
UIImage *images;
if (iref) {
images = [UIImage imageWithCGImage:iref];
}
else {
images = [UIImage imageNamed:#"Nofile.png"];
}
imageViewTopic .image = images ;
};
ALAssetsLibraryAccessFailureBlock failureblock = ^(NSError *myerror)
{
imageViewTopic .image = [UIImage imageNamed:#"Nofile.png"];
NSLog(#"booya, cant get image - %#",[myerror localizedDescription]);
};
NSString *string ;
MyClass *obj = [imageFileNameArray objectAtIndex:j];
**//obj.fileName contains ALAsset URL of a Image**
string = obj.fileName;
NSURL *asseturl = [NSURL URLWithString:string];
ALAssetsLibrary* assetslibrary = [[[ALAssetsLibrary alloc] init] autorelease];
[assetslibrary assetForURL:asseturl resultBlock:resultblock
failureBlock:failureblock];
imageViewTopic.userInteractionEnabled = YES;
imageViewTopic.frame = CGRectMake(0,0, 200, 150);
[currentView addSubview:scroller];
**// adding the imageView to View**
[smallView addSubview:imageViewTopic];
[myView addSubview:smallView];
[scroller addSubview:myView];
}
I am using this method to show images in scroll view with lazy loading. It works well.
First initialize the value of j1. And data is the image data coming from loop from an array.
dispatch_async(dispatch_get_global_queue(0,0), ^{
NSData * data = [[NSData alloc] initWithContentsOfURL:url];
if ( data == nil )
return;
dispatch_async(dispatch_get_main_queue(), ^{
__block int j1=_j;
// WARNING: is the cell still using the same data by this point??
// NSURL *url = [NSURL URLWithString: imageName];
UIImage *image = [UIImage imageWithData: data]; //image.size.height
image1=[[UIImageView alloc] initWithFrame:CGRectMake(j1,10,image.size.width,image.size.height)];
image1.image=image;
CALayer *layer = [image1 layer];
[layer setMasksToBounds:YES];
[layer setCornerRadius:0.0]; //note that when radius is 0, the border is a rectangle
[layer setBorderWidth:3.0];
[layer setBorderColor:[[UIColor whiteColor] CGColor]];
[portfolio_scroll addSubview:image1];
});
});
_j = _j+ 320;
Related
I want to have a similar functionality as in the Photos app on the iPhone in my Scrollview. So I've added all images to my scrollview like this and it works nicely.
-(void)prepareScrollView
{
for(int i =0;i<[self.layoverPhotoAssets count];i++){
PHAsset *asset = self.layoverPhotoAssets[i];
UIImageView *imageView = [[UIImageView alloc] init];
int x = self.scrollView.frame.size.width * i;
imageView.frame = CGRectMake(x, 0, self.scrollView.frame.size.width, self.scrollView.frame.size.height);
imageView.contentMode = UIViewContentModeScaleAspectFit;
PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
options.resizeMode = PHImageRequestOptionsResizeModeFast;
options.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat; //I only want the highest possible quality
options.synchronous = NO;
options.networkAccessAllowed = YES;
[[PHImageManager defaultManager] requestImageForAsset:asset targetSize:self.scrollView.frame.size contentMode:PHImageContentModeAspectFill options:options resultHandler:^(UIImage *result, NSDictionary *info) {
dispatch_async(dispatch_get_main_queue(), ^{
if(result){
imageView.image = result;
}
});
}];
[self.scrollView setContentSize:CGSizeMake(self.scrollView.frame.size.width * (i + 1), self.scrollView.frame.size.height)];
//self.scrollView.contentSize= ;
[self.scrollView addSubview:imageView];
}
}
However I have 2 questions:
1. Like this, all images will be loaded at once. Memory wise this is quite bad. How can I improve that without worsening the user experience?
2. How can I make the image itself zoomable?
I am using below code to get the images from server. i want to get dynamicaly height of image and add image in scrollview.
From below code when i get the height outside the dispatch_async method it shows zero.
How i can get the dynamically height of image with async image load.
- (void)viewDidLoad {
[self LoadViewPublicEvents];
}
-(void) LoadViewPublicEvents
{
for (int i=0;i<arrayPublicEvents.count;i++)
{
UIImageView *img_vw1=[[UIImageView alloc] init];
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:#"http://abc.us/uploads/event/%#",[[arrayPublicEvents objectAtIndex:i] valueForKey:#"image"]]]];
UIImage *images = [[UIImage alloc]initWithData:imageData];
dispatch_async(dispatch_get_main_queue(), ^{
img_vw1.image = images;
scaledHeight = images.size.height;
});
});
NSLog(#"%f",scaledHeight); // it print zero
img_vw1.backgroundColor=[UIColor clearColor];
img_vw1.frame=CGRectMake(0,y+5,screen_width,197);
[img_vw1 setContentMode:UIViewContentModeScaleAspectFit];
img_vw1.backgroundColor=[UIColor clearColor];
[self.scrll_vw addSubview:img_vw1];
}
}
Thanks in advance
Your code:
NSLog(#"%f",scaledHeight); // it print zero
img_vw1.backgroundColor=[UIColor clearColor];
img_vw1.frame=CGRectMake(0,y+5,screen_width,197);
[img_vw1 setContentMode:UIViewContentModeScaleAspectFit];
img_vw1.backgroundColor=[UIColor clearColor];
[self.scrll_vw addSubview:img_vw1];
Is being executed, before you loaded the image.
Thus you have to either wait (herefore you could use semaphores until the thread has finished) OR you place it inside of your block.
As you want to modify the UI it makes sense to place it into the main block:
UIImageView *img_vw1=[[UIImageView alloc] init];
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:#"http://abc.us/uploads/event/%#",[[arrayPublicEvents objectAtIndex:i] valueForKey:#"image"]]]];
UIImage *images = [[UIImage alloc]initWithData:imageData];
dispatch_async(dispatch_get_main_queue(), ^{
img_vw1.image = images;
scaledHeight = images.size.height;
NSLog(#"%f",scaledHeight); // it print zero
img_vw1.backgroundColor=[UIColor clearColor];
img_vw1.frame=CGRectMake(0,y+5,screen_width,197);
[img_vw1 setContentMode:UIViewContentModeScaleAspectFit];
img_vw1.backgroundColor=[UIColor clearColor];
[self.scrll_vw addSubview:img_vw1];
});
});
For more information, here is a link to Apple's documentation: https://developer.apple.com/library/content/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html
I have UIScrollView that contains images from the server.
I should put Activity Indicator while the image is currently loading.
UIScrollView contains dynamic number of images from the server.
May I know how can I add activity indicators on each page while the image is loading and remove once image is loaded.
Here's my code to retrieve images:
NSDictionary *items = [NSDictionary dictionaryWithObject:dictInfo forKey:#"images"];
imageList = [items objectForKey:#"images"];
NSArray *img = [imageList objectForKey:#"list"];
NSInteger imgCount = [img count];
buttonArray = [[NSMutableArray alloc] init];
for (int i=0; i<imgCount; i++) {
NSDictionary *imgDict = [img objectAtIndex:i];
// REQUEST FOR IMAGES
NSString *imgPath = [imgDict objectForKey:#"image_slot"];
NSString *imgURL = imgPath;
__block ASIHTTPRequest *requestImage = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:imgURL]];
[requestImage setCompletionBlock:^{
imgView = [UIImage imageWithData:[requestImage responseData]];
if (imgURL.length) {
[pendingRequests removeObjectForKey:imgURL];
}
scrollView.userInteractionEnabled = YES;
scrollView.exclusiveTouch = YES;
scrollView.canCancelContentTouches = YES;
scrollView.delaysContentTouches = YES;
scrollView.bounces = NO;
CGRect frame;
frame.origin.x = self.scrollView.frame.size.width * i;
frame.origin.y = 0;
frame.size = self.scrollView.frame.size;
SWTUIButton *imgBtn = [[SWTUIButton alloc] initWithFrame:frame];
imgBtn.url = [requestImage.userInfo objectForKey:#"rURL"];
[imgBtn setImage:imgView forState:UIControlStateNormal];
imgBtn.backgroundColor = [UIColor clearColor];
[imgBtn addTarget:self action:#selector(buttonpushed:) forControlEvents:UIControlEventTouchUpInside];
[scrollView addSubview:imgBtn];
[buttonArray addObject:imgBtn];
[imgBtn release];
self.scrollView.contentSize = CGSizeMake(self.scrollView.frame.size.width * img.count, self.scrollView.frame.size.height);
}];
I highly suggest you use NINetworkImageView from https://github.com/jverkoey/nimbus project.
It's very light and useful.
It has a delegate method to let you know when an image is loaded.
What you basically need to do is:
1. create an NINetworkImageView for each page, just like you do with UIImageView, and call set
NINetworkImageView* networkImageView = [[[NINetworkImageView alloc] initWithImage:initialImage]
autorelease];
networkImageView.delegate = self;
networkImageView.contentMode = UIViewContentModeCenter;
[networkImageView setPathToNetworkImage:
#"http://farm3.static.flickr.com/2484/3929945380_deef6f4962_z.jpg"
forDisplaySize: CGSizeMake(kImageDimensions, kImageDimensions)];
https://github.com/jverkoey/nimbus/tree/master/examples/photos/NetworkPhotoAlbums
the add the indicator to the networkImageView as a subview.
implement the delegate as follows:
-(void)networkImageView:(NINetworkImageView *)imageView didLoadImage:(UIImage *)image {
[imageView removeAllSubviews];
}
the end result would be a much smaller code for doing the same thing.
I'm parsing my data on this way:
NSDictionary *item = [tableData objectAtIndex:[indexPath row]];
[[cell textLabel] setText:[item objectForKey:#"title"]];
[[cell detailTextLabel] setText:[item objectForKey:#"description"]];
But is there a way to parse an cell image? Normally it's
UIImage *cellImage = [UIImage imageNamed:#"image.png"];
cell.imageView.image = cellImage;
But i'm searching for a way like
[[cell UIImage cellimage] ....
Something like that so i can parse an image url from json in it
is that possible?
NSURL *url = [NSURL URLWithString:[item objectForKey:#"image"]];
NSData *data = [NSData dataWithContentsOfURL:url];
cell.imageView.image = [UIImage imageWithData:data];
Set a max width for the image
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar // called when keyboard search button pressed
{
[spinner startAnimating];
spinner.hidden=NO;
NSLog( #" Searchbar text = %#",searchBar.text);
strSearch=searchBar.text;
strSearch=[strSearch stringByReplacingOccurrencesOfString:#" " withString:#"+"];
[searchBar resignFirstResponder];
[self searchGooglePhotos];
}
- (void)searchBarCancelButtonClicked:(UISearchBar *) searchBar // called when cancel button pressed
{
[searchBar resignFirstResponder];
}
-(void)searchGooglePhotos
{
// Build the string to call the Flickr API
NSString *urlString = [NSString stringWithFormat:#"http://ajax.googleapis.com/ajax/services/search/images?v=1.0&q=%#",strSearch];
NSLog(#"urlarrystring is := %#",urlString);
// Create NSURL string from formatted string
NSURL *url = [NSURL URLWithString:urlString];
// Setup and start async download
NSURLRequest *request = [[NSURLRequest alloc] initWithURL: url];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection release];
[request release];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// Store incoming data into a string
NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
// Create a dictionary from the JSON string
NSDictionary *respone = [jsonString JSONValue];
//NSLog(#"result dict is :%#",respone);
// Build an array from the dictionary for easy access to each entry
urlarry = [[[respone valueForKey:#"responseData"] valueForKey:#"results"]valueForKey:#"url"];
NSArray *title = [[[respone valueForKey:#"responseData"] valueForKey:#"results"]valueForKey:#"title"];
MoreUrlarry=[[[respone valueForKey:#"responseData"] valueForKey:#"cursor"]valueForKey:#"moreResultsUrl"];
[urlarry retain];
NSLog(#"photourlarry is :%#",urlarry);
NSLog(#"phototitle is :%#",title);
NSLog(#"photoMoreUrlarry is :%#",MoreUrlarry);
NSData *data2;
NSString *str=[[NSString alloc] init];
[scrl removeFromSuperview];
[displayview removeFromSuperview];
scrl=[[UIScrollView alloc] initWithFrame:CGRectMake(0, 44,320, 430)];
[scrl setContentSize:CGSizeMake(320*[urlarry count], 430)];
scrl.pagingEnabled=YES;
//==========
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// Assign activity indicator to the pre-defined property (so it can be removed when image loaded)
//self.activityIndicator = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(55, 67, 25, 25)];
// Start it animating and add it to the view
// Create multiple imageviews to simulate a 'real' application with multiple images
CGFloat verticalPosition = 10;
int i = 1;
for (i=1; i<5; i++) {
// Set vertical position of image in view.
if (i > 1) {
verticalPosition = verticalPosition+85;
}
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(122, verticalPosition, 80, 80)];
imageView.tag = i;
[self.view addSubview:imageView];
// set the image to be loaded (using the same one here but could/would be different)
NSString *str123=[urlarry objectAtIndex:i-1];
NSURL *imgURL = [NSURL URLWithString:str123];
// Create an array with the URL and imageView tag to
// reference the correct imageView in background thread.
NSMutableArray *arr = [[NSArray alloc] initWithObjects:imgURL, [NSString stringWithFormat:#"%d", i], nil ];
// Start a background thread by calling method to load the image
[self performSelectorInBackground:#selector(loadImageInBackground:) withObject:arr];
}
[pool release];
/*
int x=10,y=50,p=250,q=20;
for (int i=0; i<[urlarry count]; i++)
{
str=[NSString stringWithString:[urlarry objectAtIndex:i]];
data2 = [NSData dataWithContentsOfURL:[NSURL URLWithString:str]];
Favimage = [[UIImage alloc]initWithData:data2];
markButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[markButton setFrame:CGRectMake(p, q, 35,20)];
markButton.tag=i;
NSLog(#"tag is :%d",markButton.tag);
//[imgButton setTitle:[NSString stringWithFormat:#"%i",i] forState:UIControlStateNormal];
//imgButton.contentMode=UIViewContentModeScaleAspectFit;
// [imgButton setBackgroundImage:[UIImage imageNamed:#"no.png"]forState:UIControlStateNormal];
//[imgButton setImage:[Favimage imageScaledToFitSize:CGSizeMake(300, 320)] forState:UIControlStateNormal];
[markButton addTarget:self action:#selector(mark_buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
[scrl addSubview:markButton];
UIButton *imgButton = [UIButton buttonWithType:UIButtonTypeCustom];
[imgButton setFrame:CGRectMake(x, y, 300,320)];
imgButton.tag=i;
NSLog(#"tag is :%d",imgButton.tag);
//[imgButton setTitle:[NSString stringWithFormat:#"%i",i] forState:UIControlStateNormal];
imgButton.contentMode=UIViewContentModeScaleAspectFit;
// [imgButton setBackgroundImage:[UIImage imageNamed:#"no.png"]forState:UIControlStateNormal];
[imgButton setImage:[Favimage imageScaledToFitSize:CGSizeMake(300, 320)] forState:UIControlStateNormal];
[imgButton addTarget:self action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
//[imgButton setImage:Favimage forState:UIControlStateNormal];
[scrl addSubview:imgButton];
//UIImageView *imageview=[[UIImageView alloc] initWithFrame:CGRectMake(x, y, 90, 90)];
// [imageview setImage:Favimage];
// [scrl addSubview:imageview];
NSLog(#"value of x=%d",x);
NSLog(#"value of y=%d",y);
NSLog(#"value of p=%d",p);
NSLog(#"value of q=%d",q);
NSLog(#"str is : %#",str);
if (y>=30 )
{
//x=15;
x=x+320;
}
if (q>=0 )
{
//x=15;
p=p+320;
}
//else
// {
// y=y+;
// }
}*/
[spinner stopAnimating];
spinner.hidden=TRUE;
[self.view addSubview:scrl];
btnmore.hidden=NO;
//NSLog(#"str is : %#",str);
// NSLog(#"j is : %d",j);
// NSLog(#"p is : %d",p);
}
- (void) loadImageInBackground:(NSArray *)urlAndTagReference {
NSLog(#"Received URL for tagID: %#", urlAndTagReference);
// Create a pool
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// Retrieve the remote image. Retrieve the imgURL from the passed in array
NSData *imgData = [NSData dataWithContentsOfURL:[urlAndTagReference objectAtIndex:0]];
UIImage *img = [[UIImage alloc] initWithData:imgData];
// Create an array with the URL and imageView tag to
// reference the correct imageView in background thread.
NSMutableArray *arr = [[NSArray alloc] initWithObjects:img, [urlAndTagReference objectAtIndex:1], nil ];
// Image retrieved, call main thread method to update image, passing it the downloaded UIImage
[self performSelectorOnMainThread:#selector(assignImageToImageView:) withObject:arr waitUntilDone:YES];
}
- (void) assignImageToImageView:(NSArray *)imgAndTagReference
{
// Create a pool
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// loop
for (UIImageView *checkView in [self.view subviews] ) {
NSLog(#"Checking tag: %d against passed in tag %d",[checkView tag], [[imgAndTagReference objectAtIndex:1] intValue]);
if ([checkView tag] == [[imgAndTagReference objectAtIndex:1] intValue]) {
// Found imageView from tag, update with img
[checkView setImage:[imgAndTagReference objectAtIndex:0]];
//set contentMode to scale aspect to fit
checkView.contentMode = UIViewContentModeScaleAspectFit;
//change width of frame
CGRect frame = checkView.frame;
frame.size.width = 80;
checkView.frame = frame;
}
}
// release the pool
[pool release];
// Remove the activity indicator created in ViewDidLoad()
//[self.activityIndicator removeFromSuperview];
}
-(void)buttonPressed:(id)sender
{
UIButton *imgButton = (UIButton *)sender;
int q=imgButton.tag;
string=[[NSString alloc] init];
string=[NSString stringWithString:[urlarry objectAtIndex:q]];
// NSLog(#"aap str is :%#",appDel.appstr);
// [self.navigationController pushViewController:objimv animated:YES];
}
Okay... I want to save the visible rectangle of the IKImageView image only.
My problem is that, somehow, if I had an image in portrait mode it will be not saved in the right orientation. I drawing the image with this code:
[sourceImg drawInRect:targetRect fromRect:sourceRect operation:NSCompositeSourceOver fraction:1.0f];
On the other side if I draw the image with this code:
[sourceImg drawAtPoint:NSZeroPoint fromRect:sourceRect operation:NSCompositeSourceOver fraction:1.0f];
It will be in the right orientation, but edits like zooming are lost. I mean it will save the right cut out, but unfortunately not in the right size.
Here is the code how I load the image:
- (IBAction)imageSelectionButtonAction:(id)sender {
NSLog(#"%s", __FUNCTION__);
NSOpenPanel *panel = [NSOpenPanel openPanel];
id model = [self getModel];
if (imageView) {
[panel setAllowedFileTypes:[NSImage imageFileTypes]];
[panel beginSheetModalForWindow:[[NSApplication sharedApplication] mainWindow] completionHandler:^(NSInteger returnCode) {
if (returnCode == 1) {
NSURL *imageUrl = [panel URL];
CGImageRef image = NULL;
CGImageSourceRef isr = CGImageSourceCreateWithURL( (__bridge CFURLRef)imageUrl, NULL);
if (isr) {
NSDictionary *options = [NSDictionary dictionaryWithObject: (id)kCFBooleanTrue forKey: (id) kCGImageSourceShouldCache];
image = CGImageSourceCreateImageAtIndex(isr, 0, (__bridge CFDictionaryRef)options);
if (image) {
_imageProperties = (__bridge_transfer NSDictionary*)CGImageSourceCopyPropertiesAtIndex(isr, 0, (__bridge CFDictionaryRef)_imageProperties);
_imageUTType = (__bridge NSString*)CGImageSourceGetType(isr);
}
CFRelease(isr);
}
if (image) {
[imageView setImage:image imageProperties:_imageProperties];
CGImageRelease(image);
}
[[model saveTempMutabDict] setValue:[imageUrl absoluteString] forKey:#"tempImage"];
}
}];
return;
}
}
And here is the code how I save it:
- (void)saveImage:(NSString *)path {
// get the current image from the image view
CGImageRef sourceImgRef = [imageView image];
NSRect targetRect = [imageView visibleRect];
NSImage *sourceImg = [[NSImage alloc] initWithCGImage:sourceImgRef size:NSZeroSize];
NSMutableDictionary *thisTiffDict = [_imageProperties valueForKey:#"{TIFF}"];
NSInteger theOrientation = [[thisTiffDict valueForKey:#"Orientation"] integerValue];
NSImage *targetImg = nil;
if (theOrientation == 6) {
targetImg = [[NSImage alloc] initWithSize:NSMakeSize([imageView frame].size.height, [imageView frame].size.width)];
} else {
targetImg = [[NSImage alloc] initWithSize:NSMakeSize([imageView frame].size.width, [imageView frame].size.height)];
}
NSRect sourceRect = [imageView convertViewRectToImageRect:targetRect];
[targetImg lockFocus];
[[NSGraphicsContext currentContext] setImageInterpolation:NSImageInterpolationHigh];
[sourceImg drawAtPoint:NSZeroPoint fromRect:sourceRect operation:NSCompositeSourceOver fraction:1.0f];
[targetImg unlockFocus];
_saveOptions = [[IKSaveOptions alloc] initWithImageProperties:_imageProperties imageUTType: _imageUTType];
NSString * newUTType = [_saveOptions imageUTType];
CGImageRef targetImgRef = [targetImg CGImageForProposedRect:NULL context:[NSGraphicsContext currentContext] hints:nil];
if (targetImgRef) {
NSURL *url = [NSURL fileURLWithPath: path];
CGImageDestinationRef dest = CGImageDestinationCreateWithURL((__bridge CFURLRef)url, (__bridge CFStringRef)newUTType, 1, NULL);
if (dest) {
CGImageDestinationAddImage(dest, targetImgRef, (__bridge CFDictionaryRef)[_saveOptions imageProperties]);
CGImageDestinationFinalize(dest);
CFRelease(dest);
}
}
}
I have no idea what I'm doing wrong?
Thank you
Jens