Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is it possible to display an image in the EGOTextView? #17

Open
voicecho opened this issue Oct 19, 2012 · 7 comments
Open

Is it possible to display an image in the EGOTextView? #17

voicecho opened this issue Oct 19, 2012 · 7 comments

Comments

@voicecho
Copy link

I would like to insert a local image in to the EGOTextView, but i couldn't know hot to achieve this.

@Inza
Copy link

Inza commented Jun 30, 2013

+1

@Inza
Copy link

Inza commented Jul 6, 2013

Yes, it is possible.

You have to create your own class which conforms to EGOTextAttachmentCell, I created mine as subclass of UIView. I added UIImageView to this class.

Then you can add this class as attribute to part of text in NSAttributedString. Then you can set your NSAttributedString to EGOTextView as its attributedText property.

Your view which conformed to EGOTextAttachmentCell will be shown then.

But there are few obstacles. As I have tried it, this thing seems to be something like a preliminary support or so. Which means that it is not buggy but maybe somehow unfinished instead? Eg. EGOTextView will never remove these views automatically when you remove the attributed text part from the string. You have to remove them manually. Another issue is that it is up to you to have the UIImages shown on your cells stored somewhere.

And whole different story is when you want to save these things somewhere and recover them then :-D. Because there is no simple way how to save this NSAttributedString with custom attributes currently.

I have ended with saving just plain NSString in CoreData and images in .png file on disc. And in viewWillAppear I am reconstructing the "thing". I use macros like ##IMAGE##3## which I replace with parts of NSAttributedString with my cells added.

But is works great. But lot of work inside :-/. But I really can't imagine what would I do without EGOTextView! ;) Because all HTML based rich editors are bad for me.

@hughbe
Copy link

hughbe commented Sep 10, 2013

can you upload the code involved in the above description?? Thanks!

@dimasha8
Copy link

Yes. It would be great if you uploaded code with attached images. Thanks:)

@Inza
Copy link

Inza commented Sep 18, 2013

Hi guys, sry for delay, but I have so much work at www.juicymo.cz now ;).

Anyway, I have tried to use EGOTextView with images like I have posted above in app RapidNotes (www.rapidnotesapp.com). But this approach has few serious issue - you can download current version of the app to see it directly. When you add images to EGOTextView as attachement cells, the loupe shows text below them - I do not know how to prevent that. Another issue is with scrolling - or if you want: How to make the EGOTextView not to disappear below my keyboard when the text inside is extending. Another issue I had was that in my app EGOTextView crashed when I tried to make more than one instance of it - because of this I made my controller for editing singleton and I am reusing it (have to reset it's state to initial one before reuse => another bunch of work). But one after one issues with EGOTextView were multiplying in my app. Therefore I have decided to completely remove it form my app. Fortunately all I need is just an editor with one font/text style and images. And this can be achieved with one UITableView with two types of cells - one with image and another with UITextView. Right now I am remaking the editor for RapidNotes app.

But now to your issue: Here I am uploading relevant pieces of code which I have used for adding images to EGOTextView - but be warned - as I have said, finally I have been forced to remove it from my app anyway... (few weeks of fun with EGOTextView ;)) - I hope you will have better luck.

First of all the image attachements were probably never been made for this kind of usage but maybe for adding things like small icons or smiles to text. But here is the code:

I have and array of images paths in my controller called images and is is a NSMutableDictionary.

Then in viewWillAppear I call my insertPhotos method (self.editorView is my shared EGOTextView instance):

- (void)insertPhotos {
    NSMutableAttributedString *atrStr = [[NSMutableAttributedString alloc] initWithString:self.editorView.text attributes:self.editorView.defaultAttributes];

    [self clearAttachements];
    [self.imageAttachementCells removeAllObjects];

    for (NSString *imageName in self.images) {
        //UIImage *image = self.images[imageName];

        ImageEditorAttachmentCell *attachmentCell = [[ImageEditorAttachmentCell alloc] initWithImageURL:[[[AppDelegate sharedDelegate] applicationDocumentsDirectory] URLByAppendingPathComponent:imageName]];
        //ImageEditorAttachmentCell *attachmentCell = [[ImageEditorAttachmentCell alloc] initWithImage:image];
        attachmentCell.photoIdentifier = imageName;

        NSDictionary *attachmentDict = [NSDictionary dictionaryWithObject:attachmentCell forKey:EGOTextAttachmentAttributeName];
        NSAttributedString *imageStr = [[NSAttributedString alloc] initWithString:imageName attributes:attachmentDict];
        NSRange range = [[atrStr mutableString] rangeOfString:imageName];

        if (range.location != NSNotFound) {
            [atrStr replaceCharactersInRange:range withAttributedString:imageStr];
        }

        [self.imageAttachementCells addObject:attachmentCell];
    }

    self.editorView.attributedText = atrStr;
}

An issue is that I have not found a way how to remove added attachement view - therefore I have created another NSMutableArray to maintain pointer at them to be able to remove them manually.

@property (nonatomic, strong) NSMutableArray *imageAttachementCells;

I remove them in my clearAttachements method:

- (void)clearAttachements {
    for (ImageEditorAttachmentCell *cell in self.imageAttachementCells) {
        [cell removeFromSuperview];
        cell.hidden = YES;
    }
}

Next when I am setting a new note to my controller I call my reset method (which resets the controller to it's initial state like I have noted before, if you do not reuse your controllers maybe you do not need this):

[self reset];

Code of the reset merhod is:

- (void)reset {
    if (self.imageAttachementCells) {
        [self.imageAttachementCells removeAllObjects];
    }

    self.isAddingPhoto = NO;

    if (!self.images) {
        self.images = [NSMutableDictionary dictionary];
    }

    [self.images removeAllObjects];
    for (Photo *photo in _note.photos) {
        NSString *photoImageName = [NSString stringWithFormat:kImagePlaceholderString, photo.identifier];
        NSString *image = @"XXX";

        [self.images setObject:image forKey:photoImageName];
    }
}

Next when I add a photo to my EGOTextView I am adding the path to image to my images dict and special placeholder to the text of my EGOTextView - these placeholder are replaced by attributed text with an attachement in the insertPhotos method above.

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
    [SVProgressHUD showWithStatus:@"Processing..."];

    // Create Photo
    Note *note = self.note;

    NSString *count = [NSString stringWithFormat:@"%d", [Photo countOfEntities]];
    NSString *photoImageName = [NSString stringWithFormat:kImagePlaceholderString, count];
    NSString *text = [NSString stringWithFormat:@"%@%@%@%@", self.editorView.text, kImageDelimeterStringBefore, photoImageName, kImageDelimeterStringAfter];
    self.editorView.text = text;

    // Here I save photos to my note...

    // Save Photo Image to disc
    UIImage *image = [((UIImage *)[info valueForKey:UIImagePickerControllerOriginalImage]) fixOrientation];

    [self.images setObject:@"XXX" forKey:photoImageName];

    [self savePhotoOnBackgroundWithImage:[image resizedImage:CGSizeMake(image.size.width / 2, image.size.height / 2) interpolationQuality:kCGInterpolationDefault] withName:photoImageName];

    [SVProgressHUD dismiss];

    [self.navigationController dismissViewControllerAnimated:YES completion:nil];
}

My savePhotoOnBackgroundWithImage method is:

- (void)savePhotoOnBackgroundWithImage:(UIImage *)image withName:(NSString *)photoImageName {
    NSData *pngData = UIImageJPEGRepresentation(image, 0.8);
    NSString *photoImageFileName = [[AppDelegate sharedDelegate] documentsPathForFileName:photoImageName];
    [pngData writeToFile:photoImageFileName atomically:YES]; // Write the file

    if ([self isEditorActive] == YES) { // these things are related to my scrolling issues... maybe you can skip them as well...
        [self.tableView beginUpdates];
        [self.tableView endUpdates];
        self.editorView.contentOffset = CGPointZero;

        if (self.tableView.contentOffset.y > self.tableHeaderView.frame.size.height/* && self.tableView.contentOffset.y < */) {
            [self.tableView setContentOffset:CGPointMake(0, self.tableHeaderView.frame.size.height) animated:YES];
        }
    }
}

Then I have relevant constants (for making text placeholders):

#define kImagePlaceholderString @"##IMAGE##%@##"
#define kImageDelimeterStringBefore @"\n\n"
#define kImageDelimeterStringAfter @"\n\n\n\n\n\n\n\n\n\n\n\n"

The newlines are the in order to make the text which is before and after a photo in EGOTextView to be before and after.

I hope I did not forgot something :-) - as you can see, this is more a desperate man solution instead of some stay-of-the-art code I could be proud of. So I wish you luck with it.

If you will have any more questions I am very happy to help.

@Inza
Copy link

Inza commented Sep 18, 2013

I forgot to add code of ImageEditorAttachmentCell, so here it is:

ImageEditorAttachmentCell.h

//
//  ImageEditorAttachmentCell.h
//  RapidNotes
//
//  Created by Tomáš Jukin on 02.07.2013.
//  Copyright (c) 2013 Juicymo s.r.o. All rights reserved.
//

#import "EGOTextView.h"

#define kImageEditorAttachmentCellImageHeight 300

@interface ImageEditorAttachmentCell : UIView <EGOTextAttachmentCell>

@property (nonatomic, strong) NSString *photoIdentifier;

- (id)initWithImage:(UIImage *)image;
- (id)initWithImageURL:(NSURL *)imageURL;

@end

ImageEditorAttachmentCell.m

//
//  ImageEditorAttachmentCell.m
//  RapidNotes
//
//  Created by Tomáš Jukin on 02.07.2013.
//  Copyright (c) 2013 Juicymo s.r.o. All rights reserved.
//

#import "ImageEditorAttachmentCell.h"

#import "NewNoteViewController.h"
#import <SDWebImage/UIImageView+WebCache.h>
#import <UIImageView+UIActivityIndicatorForSDWebImage.h>

@interface ImageEditorAttachmentCell ()

@property (nonatomic, strong) UIImageView *imageView;
@property (nonatomic, strong) UIButton *actionButton;

@end

@implementation ImageEditorAttachmentCell

- (id)initWithImage:(UIImage *)image {
    CGRect frame = CGRectMake(0, 0, (320 - 26) - 6, kImageEditorAttachmentCellImageHeight);

    self = [self initWithFrame:frame];

    if (self) {
        self.clipsToBounds = YES;

        self.imageView = [[UIImageView alloc] init];
        self.imageView.backgroundColor = [UIColor darkGrayColor];
        self.imageView.image = image;
        self.imageView.contentMode = UIViewContentModeScaleAspectFill;
        self.imageView.frame = CGRectMake(3, 3, ((320 - 26) - 6) - 6, kImageEditorAttachmentCellImageHeight - 6);
        self.imageView.clipsToBounds = YES;

        [self addSubview:self.imageView];

        self.actionButton = [UIButton buttonWithType:UIButtonTypeCustom];
        self.actionButton.frame = frame;
        self.actionButton.backgroundColor = [UIColor clearColor];
        [self.actionButton addTarget:[NewNoteViewController sharedInstance] action:@selector(showPhotoDetailForPhotoIdentifier:) forControlEvents:UIControlEventTouchUpInside];

        [self addSubview:self.actionButton];
    }

    return self;
}

- (id)initWithImageURL:(NSURL *)imageURL {
    CGRect frame = CGRectMake(0, 0, (320 - 26) - 6, kImageEditorAttachmentCellImageHeight);

    self = [self initWithFrame:frame];

    if (self) {
        self.clipsToBounds = YES;

        self.imageView = [[UIImageView alloc] init];
        self.imageView.backgroundColor = [UIColor blackColor];
        self.imageView.contentMode = UIViewContentModeScaleAspectFill;
        self.imageView.frame = CGRectMake(3, 3, ((320 - 26) - 6) - 6, kImageEditorAttachmentCellImageHeight - 6);
        self.imageView.clipsToBounds = YES;

        [self addSubview:self.imageView];

        self.actionButton = [UIButton buttonWithType:UIButtonTypeCustom];
        self.actionButton.frame = frame;
        self.actionButton.backgroundColor = [UIColor clearColor];
        [self.actionButton addTarget:[NewNoteViewController sharedInstance] action:@selector(showPhotoDetailForPhotoIdentifier:) forControlEvents:UIControlEventTouchUpInside];

        [self addSubview:self.actionButton];

        [self.imageView setImageWithURL:imageURL usingActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
    }

    return self;
}

- (id)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];

    if (self) {
        self.backgroundColor = [UIColor colorWithRed:0.275 green:0.298 blue:0.290 alpha:1.000];
    }

    return self;
}

- (UIView *)egoAttachmentView {
    return self;
}

@end

As you can see, I am loading the images async. via SDWebImage+WebCache library. Try do the same ;).

@Inza
Copy link

Inza commented Sep 18, 2013

Yop, and BTW feel free to reuse my ImageEditorAttachmentCell class but please leave my copyright in comments of your files.

Maybe enormego could be interested to add this class directly to EGOTextView distribution? ;)

I know it needs some cleanup - I have photo size hardcoded in the code, etc. But the general idea should be OK...?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants