protected ComicRead GetReader(long comicId) { ComicRead read = null; try { this.EntityContext.TryAttach(this.ActiveUser); Data.Comic comic = this.EntityContext.TryGetComic(comicId, this.ActiveUser, this.Friends); if (comic == null || !comic.IsPublished) { throw new Exception("Unable to find the requested comic."); } read = this.EntityContext.TryGetComicRead(comic, this.ActiveUser); if (read == null) { read = new ComicRead(); read.Comic = comic; read.Reader = this.ActiveUser; read.ReadTime = DateTime.Now; this.EntityContext.AddToComicRead(read); } } finally { this.EntityContext.TryDetach(this.ActiveUser); } return(read); }
public EmptyResult ReaderComment(long id) { try { this.EntityContext.TryAttach(this.ActiveUser); Data.Comic comic = this.EntityContext.TryGetComic(id, this.ActiveUser); if (comic != null) { comic.AuthorReference.Load(); UserEngage engage = this.GetUserEngage(comic.Author); comic.Author.UserEngageReference.Load(); UserEngageHistory history = comic.Author.UserEngageHistory .OrderByDescending(h => h.EngageTime) .FirstOrDefault(h => h.Engagement == UserEngageHistory.EngagementType.Comment); if (!engage.Unsubscribe && engage.Comment && (history == null || history.EngageTime <= DateTime.Now.AddDays(-1))) { ClientComic c = new ClientComic(comic); // create & save history history = new UserEngageHistory(); history.Engagement = UserEngageHistory.EngagementType.Comment; history.EngageTime = DateTime.Now; history.User = comic.Author; this.EntityContext.AddToUserEngageHistory(history); this.EntityContext.SaveChanges(); // Generate email message EmailManager email = new EmailManager(this.Server); Dictionary <string, string> data = new Dictionary <string, string>(); data.Add("id", history.EngageHistoryId.ToString()); data.Add("title", String.Format("New Comment - {0}", comic.Title)); data.Add("reader.name", this.ActiveUser.Nickname); data.Add("comic.title", comic.Title); data.Add("comic.readUrl", c.ReadUrl); // Send email email.SendEmail(comic.Author, "Comment.html", data); } } } finally { this.EntityContext.TryDetach(this.ActiveUser); } return(new EmptyResult()); }
public RedirectResult Random() { RedirectResult result; try { this.EntityContext.TryAttach(this.ActiveUser); Data.Comic comic = this.EntityContext.TryGetRandomComic(this.ActiveUser, this.Friends); if (comic == null || (comic.IsPrivate && !this.IsFriendOrSelf(comic.Author))) { throw new Exception("Unable to find the requested comic."); } result = this.Redirect(ComicUrlHelper.GetReadUrl(comic)); } finally { this.EntityContext.TryDetach(this.ActiveUser); } return(result); }
public JsonResult RenderProgress(string taskId) { CloudBlobContainer container = this.BlobClient.GetContainerReference(ComicConfigSectionGroup.Blob.TaskContainer); CloudBlobDirectory directory = container.GetDirectoryReference(ComicConfigSectionGroup.Blob.RenderTaskDirectory); CloudBlob blob = directory.GetBlobReference(taskId); XmlSerializer serializer = new XmlSerializer(typeof(RenderTask)); using (MemoryStream stream = new MemoryStream()) { blob.DownloadToStream(stream); stream.Seek(0, SeekOrigin.Begin); RenderTask task = (RenderTask)serializer.Deserialize(stream); if (task.OwnerUid != this.ActiveUser.Uid) { throw new Exception("Unknown task"); } ClientRenderTask clientTask = new ClientRenderTask(task); if (task.Status == TaskStatus.Complete && task.ComicId.HasValue) { // Load completed comic from database try { this.EntityContext.TryAttach(this.ActiveUser); Data.Comic comic = this.EntityContext.TryGetUnpublishedComic(task.ComicId.Value, this.ActiveUser); clientTask.Comic = new ClientComic(comic); } finally { this.EntityContext.TryDetach(this.ActiveUser); } } return(this.Json(clientTask, JsonRequestBehavior.AllowGet)); } throw new Exception("Unknown task"); }
protected void Init(Data.Comic source, ComicStat.ComicStatPeriod statsPeriod) { this.ComicId = source.ComicId; this.Uid = source.Uid; this.TemplateId = source.TemplateId; this.CreateTime = source.CreateTime; this.UpdateTime = source.UpdateTime; this.PublishTime = source.PublishTime; this.FeatureTime = source.FeatureTime; this.IsPublished = source.IsPublished; this.Title = source.Title; this.Description = source.Description; this.ShareText = source.ShareText; this.IsPrivate = source.IsPrivate; this.ReadUrl = ComicUrlHelper.GetReadUrl(source); this.ComicUrl = ComicUrlHelper.GetRenderUrl(source, RenderMode.Comic); this.ThumbUrl = ComicUrlHelper.GetRenderUrl(source, RenderMode.Thumb); this.FrameUrl = ComicUrlHelper.GetRenderUrl(source, RenderMode.Frame); this.FrameThumbUrl = ComicUrlHelper.GetRenderUrl(source, RenderMode.FrameThumb); this.RemixUrl = ComicUrlHelper.GetRemixUrl(source); this.Author = new ClientUser(source.Author); this.Stats = new ClientComicStat(source.PeriodStats(statsPeriod)); this.Template = new ClientTemplate(source.Template); if (source.ComicTextBubbles.IsLoaded) { this.Bubbles = source.ComicTextBubbles.ToList().Select(b => new ClientComicTextBubble(b)).ToList(); } if (source.ComicPhotos.IsLoaded) { this.Photos = source.ComicPhotos .OrderBy(p => p.TemplateItem.Ordinal) .ToList() .Select(p => new ClientPhoto(p.Photo)) .ToList(); } }
public ActionResult Delete(long?id) { try { this.EntityContext.TryAttach(this.ActiveUser); Data.Comic comic = this.EntityContext.TryGetAuthoredComic(id.Value, this.ActiveUser); if (comic == null) { throw new Exception(String.Format("Unable to find the requested comic '{0}'", id.Value)); } comic.IsDeleted = true; this.EntityContext.SaveChanges(); } finally { this.EntityContext.TryDetach(this.ActiveUser); } return(this.View()); }
private void ExecuteTask(object state) { CloudQueueMessage queueMessage = (CloudQueueMessage)state; this.Log.DebugFormat("Executing render task {0}", queueMessage.AsString); Data.Comic comic = null; RenderTask task = null; string connectionString = ConfigurationManager.ConnectionStrings["ComicModelContext"].ConnectionString; ComicModelContext entityContext = new ComicModelContext(connectionString); try { // Read task details from storage CloudBlobContainer container = this.BlobClient.GetContainerReference(ComicConfigSectionGroup.Blob.TaskContainer); CloudBlobDirectory directory = container.GetDirectoryReference(ComicConfigSectionGroup.Blob.RenderTaskDirectory); CloudBlob blob = directory.GetBlobReference(queueMessage.AsString); XmlSerializer serializer = new XmlSerializer(typeof(RenderTask)); using (MemoryStream stream = new MemoryStream()) { blob.DownloadToStream(stream); stream.Seek(0, SeekOrigin.Begin); task = (RenderTask)serializer.Deserialize(stream); task.Status = TaskStatus.Executing; this.UpdateTask(task); } User user = entityContext.TryGetUser(task.OwnerUid); FacebookClient facebook = new FacebookClient(task.FacebookToken); // Get template Template template = entityContext.ListTemplates().First(t => t.TemplateId == task.TemplateId); List <TemplateItem> templateItems = template.TemplateItems.OrderBy(t => t.Ordinal).ToList(); List <TextBubbleDirection> bubbles = entityContext.ListTextBubbles().SelectMany(b => b.TextBubbleDirections).ToList(); TextBubble speechBubble = entityContext.ListTextBubbles().First(b => b.Title == "speech"); TextBubble bubbleShout = entityContext.ListTextBubbles().First(b => b.Title == "shout"); TextBubble squareBubble = entityContext.ListTextBubbles().First(b => b.Title == "square"); comic = new Data.Comic(); entityContext.AddToComics(comic); comic.Author = user; comic.Template = template; comic.CreateTime = DateTime.Now; comic.UpdateTime = DateTime.Now; comic.PublishTime = null; comic.FeatureTime = null; comic.Title = ""; comic.Description = ""; comic.ShareText = ""; comic.IsPublished = false; comic.IsPrivate = false; comic.IsDeleted = false; comic.Locale = user.Locale ?? "en-US"; comic.StorageKey = Guid.NewGuid().ToString(); if (task.RemixComicId.HasValue) { comic.RemixedComic = entityContext.TryGetComic(task.RemixComicId.Value, user); } // Comic generator only used to size text ComicGenerator generator = new ComicGenerator(template.Width, template.Height); // Render effect parameters Dictionary <string, object> parameterValues = new Dictionary <string, object>(); switch (task.Effect) { case ComicEffectType.ColorSketch: case ComicEffectType.PencilSketch: parameterValues.Add("edging", 2); parameterValues.Add("coloring", 35); break; case ComicEffectType.Comic: default: parameterValues.Add("coloring", 6); break; } // Get photos for each frame for (int f = 0; f < task.Frames.Count && f < templateItems.Count; f++) { Photo photo = null; Bitmap image = null; string imageUrl = String.Empty; ComicGenerator.ImageAlign imageAlignment = ComicGenerator.ImageAlign.Center; Point tag = Point.Empty; bool tagConfident = false; if (task.PhotoSource == "Internal" && task.Frames[f].PhotoId.HasValue) { // Load image from database photo = entityContext.TryGetPhoto(task.Frames[f].PhotoId.Value); photo.ImageData = this.GetStoredImage(photo.StorageKey); image = new Bitmap(new MemoryStream(photo.ImageData)); } else { // Tagged facebook photos if (task.PhotoSource == "Tagged") { try { // List photos of the user Dictionary <string, object> args = new Dictionary <string, object>(); args.Add("limit", "50"); dynamic photoResult = facebook.Get(String.Format("/{0}/photos", task.Frames[f].Id), args); if (photoResult.data.Count > 0) { // Pick a random photo with 2 or fewer tags dynamic photoData = ((IList <dynamic>)photoResult.data) .OrderBy(p => Guid.NewGuid()) .FirstOrDefault(p => p.tags.data.Count <= 2); if (photoData != null) { imageUrl = (string)photoData.source; // Look for user tag location int id; dynamic tagData = ((IList <dynamic>)photoData.tags.data) .FirstOrDefault(t => int.TryParse(t.id, out id) && id == task.Frames[f].Id); if (tagData != null) { tag = new Point((int)Math.Round((double)tagData.x), (int)Math.Round((double)tagData.y)); tagConfident = false; } } } } catch (Exception x) { this.Log.Error("Unable to retrieve tagged photo from facebook.", x); } } // Look for any photo of the user else if (task.PhotoSource == "Any") { try { FaceRestAPI faceApi = this.CreateFaceApi(task.FacebookToken, user.Uid); List <string> ids = new List <string>(new string[] { String.Format("{0}@facebook.com", task.Frames[f].Id) }); FaceRestAPI.FaceAPI anyResult = faceApi.facebook_get(ids, null, "1", null, "random"); if (anyResult.status == "success" && anyResult.photos.Count > 0) { FaceRestAPI.Photo p = anyResult.photos[0]; imageUrl = p.url; tag = new Point((int)Math.Round(p.tags.First().mouth_center.x), (int)Math.Round(p.tags.First().mouth_center.y)); tagConfident = true; } } catch (Exception x) { this.Log.Error("Unable to retrieve photo through face.com api.", x); } } // Use profile photo as backup image if (String.IsNullOrEmpty(imageUrl)) { imageUrl = String.Format("https://graph.facebook.com/{0}/picture?access_token={1}&type=large", task.Frames[f].Id, facebook.AccessToken); } image = this.GetImage(imageUrl); // Find faces when confidence in tag location is low if (!tagConfident) { try { FaceRestAPI tagApi = this.CreateFaceApi(task.FacebookToken, user.Uid); //List<string> tagIds = new List<string>(new string[] { String.Format("{0}@facebook.com", task.Frames[f].Id) }); List <string> urls = new List <string>(new string[] { imageUrl }); FaceRestAPI.FaceAPI tagResult = tagApi.faces_detect(urls, null, "Normal", null, null); if (tagResult.status == "success" && tagResult.photos.Count > 0 && tagResult.photos[0].tags.Count > 0) { FaceRestAPI.Tag t = tagResult.photos[0].tags.First(); tag = new Point((int)Math.Round(t.mouth_center.x), (int)Math.Round(t.mouth_center.y)); tagConfident = true; } } catch (Exception x) { this.Log.Error("Unable to detected faces.", x); } } if (tag != Point.Empty && tag.Y <= image.Height / 3) { imageAlignment = ComicGenerator.ImageAlign.Top; } } // Resize to fit frame image = ComicGenerator.FitImage(new Size(templateItems[f].Width, templateItems[f].Height), image); // Apply render effect if (task.Effect != ComicEffectType.None) { RenderHelper effectHelper = new RenderHelper(image.Size); ImageRenderData renderResult = effectHelper.RenderEffect(image, task.Effect, parameterValues); image = new Bitmap(renderResult.RenderStream); } // Read raw photo into memory MemoryStream imageStream = new MemoryStream(); image.Save(imageStream, System.Drawing.Imaging.ImageFormat.Jpeg); imageStream.Seek(0, SeekOrigin.Begin); // Frame text bubbles if (!String.IsNullOrWhiteSpace(task.Frames[f].Message)) { ComicTextBubble comicBubble = new ComicTextBubble(); entityContext.AddToComicTextBubbles(comicBubble); comicBubble.Comic = comic; comicBubble.Text = task.Frames[f].Message; // Remove newlines comicBubble.Text = comicBubble.Text.Replace('\n', ' '); // Font size int fontSize = 7; if (comicBubble.Text.Length > 160) { fontSize = 6; } if (comicBubble.Text.Length > 200) { fontSize = 5; } comicBubble.Font = new Font(ComicGenerator.ComicFont, fontSize, FontStyle.Regular, GraphicsUnit.Point); // Shouting / excited? TextBubble bubble = speechBubble; if (comicBubble.Text.Contains('!') || Regex.Matches(comicBubble.Text, "[A-Z]").Count > comicBubble.Text.Length / 4) { bubble = bubbleShout; } // Calculate tag x/y coords relative to the whole comic if (tag != Point.Empty) { Size templateSize = new Size(templateItems[f].Width, templateItems[f].Height); Rectangle cropArea = ComicGenerator.GetCropImageSize(image.Size, templateSize, imageAlignment); tag.X = image.Size.Width * tag.X / 100 - cropArea.X + templateItems[f].X; tag.Y = image.Size.Height * tag.Y / 100 - cropArea.Y + templateItems[f].Y; } // Position text bubble this.PositionFrameBubble(comicBubble, image, generator, bubble, squareBubble, templateItems[f], tag, imageAlignment); // Add photo as template item photo = new Photo(); photo.User = user; photo.CreateTime = DateTime.Now; photo.ImageData = imageStream.ToArray(); photo.StorageKey = Guid.NewGuid().ToString(); photo.Width = image.Width; photo.Height = image.Height; entityContext.AddToPhotos(photo); } // Tag users //if (task.Frames[f].Id > 0) //{ // try // { // // Lookup existing user // User taggedUser = entityContext.TryGetUser(task.Frames[f].Id, true); // if (taggedUser == null) // { // // User doesn't exist in the db yet - grab from facebook // dynamic facebookUser = facebook.Get(String.Format("/{0}", task.Frames[f].Id)); // taggedUser = new User(); // taggedUser.Uid = long.Parse(facebookUser.id); // taggedUser.IsDeleted = false; // taggedUser.IsSubscribed = false; // taggedUser.Locale = facebookUser.locale; // taggedUser.Name = facebookUser.name; // taggedUser.Nickname = facebookUser.name; // taggedUser.FbLink = facebookUser.link; // entityContext.AddToUsers(taggedUser); // } // ComicTag comicTag = new ComicTag(); // comicTag.User = taggedUser; // comicTag.Comic = comic; // if (tag != Point.Empty) // { // comicTag.X = tag.X; // comicTag.Y = tag.Y; // } // } // catch (Exception x) // { // this.Log.ErrorFormat("Failed to tag user {0} in comic. {1}", task.Frames[f].Id, x.ToString()); // } //} ComicPhoto comicPhoto = new ComicPhoto(); comicPhoto.Comic = comic; comicPhoto.Photo = photo; comicPhoto.TemplateItem = templateItems[f]; comicPhoto.Alignment = imageAlignment; comic.ComicPhotos.Add(comicPhoto); // Update task progress task.CompletedOperations++; this.UpdateTask(task); } for (int b = 0; task.Bubbles != null && b < task.Bubbles.Count; b++) { ComicTextBubble comicBubble = new ComicTextBubble(); entityContext.AddToComicTextBubbles(comicBubble); comicBubble.Comic = comic; comicBubble.Text = task.Bubbles[b].Text; comicBubble.Font = new Font(ComicGenerator.ComicFont, 7, FontStyle.Regular, GraphicsUnit.Point); comicBubble.TextBubbleDirection = bubbles.First(d => d.TextBubbleDirectionId == task.Bubbles[b].TextBubbleDirectionId); comicBubble.Position = new Rectangle(new Point(task.Bubbles[b].X, task.Bubbles[b].Y), generator.MeasureText(comicBubble.Text, comicBubble.Font).ToSize()); } // Fix for position to x,y coordinates foreach (ComicTextBubble b in comic.ComicTextBubbles) { b.X = b.Position.X; b.Y = b.Position.Y; } this.SaveComic(comic, entityContext); task.CompletedOperations = task.TotalOperations; task.Status = TaskStatus.Complete; task.ComicId = comic.ComicId; this.UpdateTask(task); this.Log.DebugFormat("Completed render task {0}", task.TaskId); } catch (Exception x) { this.Log.Error("Unable to complete render task.", x); if (task != null) { task.Status = TaskStatus.Failed; this.UpdateTask(task); } if (comic != null) { this.Log.DebugFormat("Text bubble info [{0}] [{1}]", String.Join(",", comic.ComicTextBubbles.Select(b => b.ComicTextBubbleId.ToString()).ToArray()), String.Join(",", comic.ComicTextBubbles.Select(b => b.TextBubbleDirectionId.ToString()).ToArray())); } } }
public ClientComic(Data.Comic source, ComicStat.ComicStatPeriod statsPeriod) { this.Init(source, statsPeriod); }
public ClientComic(Data.Comic source) { this.Init(source, ComicStat.ComicStatPeriod.AllTime); }
public JsonResult Publish(long comicId, string title, string description, bool isPrivate) { Data.Comic comic = null; ClientComic c = null; try { this.EntityContext.TryAttach(this.ActiveUser); comic = this.EntityContext.TryGetUnpublishedComic(comicId, this.ActiveUser); if (comic == null || comic.Uid != this.ActiveUser.Uid) { throw new Exception("Could not find the requested comic."); } comic.Title = title; comic.Description = description; comic.IsPrivate = isPrivate; // Get bytecode from storage CloudBlobContainer container = this.BlobClient.GetContainerReference(ComicConfigSectionGroup.Blob.RenderContainer); CloudBlobDirectory directory = container.GetDirectoryReference(ComicConfigSectionGroup.Blob.ComicDirectory); CloudBlob blob = directory.GetBlobReference(comic.StorageKey); ClientComic clientComic = new ClientComic(comic); // Publish to facebook album for better visibility MemoryStream photoStream = new MemoryStream(); try { blob.DownloadToStream(photoStream); FacebookMediaObject fbMedia = new FacebookMediaObject { ContentType = "image/jpeg", FileName = String.Format("{0}.jpg", comic.StorageKey) }; fbMedia.SetValue(photoStream.ToArray()); Dictionary <string, object> photoParams = new Dictionary <string, object>(); photoParams.Add("message", String.Format("{0} - Remix this comic at {1}", comic.Description, clientComic.RemixUrl)); photoParams.Add("source", fbMedia); this.Facebook.Post("/me/photos", photoParams); } catch (Exception x) { this.Log.Error("Unable to publish comic to facebook album.", x); } finally { photoStream.Dispose(); } this.EntityContext.PublishComic(comic, this.ActiveUser); c = new ClientComic(comic); this.EntityContext.SaveChanges(); // Email notifications UserEngage engage = this.GetUserEngage(this.ActiveUser); if (!engage.Unsubscribe && engage.ComicCreate) { // create & save history UserEngageHistory history = new UserEngageHistory(); history.Engagement = UserEngageHistory.EngagementType.ComicCreate; history.EngageTime = DateTime.Now; history.User = this.ActiveUser; this.EntityContext.AddToUserEngageHistory(history); this.EntityContext.SaveChanges(); // Generate email message EmailManager email = new EmailManager(this.Server); Dictionary <string, string> data = new Dictionary <string, string>(); data.Add("id", history.EngageHistoryId.ToString()); data.Add("title", String.Format("New Comic - {0}", comic.Title)); data.Add("comic.title", c.Title); data.Add("comic.readUrl", c.ReadUrl); // Send email email.SendEmail(this.ActiveUser, "ComicCreate.html", data); } // Check for notifications of a remixed comic if (comic.RemixedComic != null) { engage = this.EntityContext.TryGetUserEngage(comic.RemixedComic.Author); ClientComic remixed = new ClientComic(comic.RemixedComic); if (!engage.Unsubscribe && engage.ComicRemix) { UserEngageHistory history = new UserEngageHistory(); history.Engagement = UserEngageHistory.EngagementType.ComicRemix; history.EngageTime = DateTime.Now; history.User = comic.RemixedComic.Author; this.EntityContext.AddToUserEngageHistory(history); this.EntityContext.SaveChanges(); // Generate email message EmailManager email = new EmailManager(this.Server); Dictionary <string, string> data = new Dictionary <string, string>(); data.Add("id", history.EngageHistoryId.ToString()); data.Add("title", String.Format("Remixed Comic - {0}", comic.Title)); data.Add("comic.title", c.Title); data.Add("comic.readUrl", c.ReadUrl); data.Add("remix.title", remixed.Title); data.Add("remix.readUrl", remixed.ReadUrl); // Send email email.SendEmail(comic.RemixedComic.Author, "ComicRemix.html", data); } } } finally { this.EntityContext.TryDetach(this.ActiveUser); } return(this.Json(c, JsonRequestBehavior.DenyGet)); }
public ActionResult Read(long comicId, string title) { ActionResult result; try { Data.Comic comic = null; //// Facebook shared comics //if (this.ActiveUser == null && this.HttpContext.Request.UrlReferrer != null && this.HttpContext.Request.UrlReferrer.Host.Contains("facebook.com")) //{ // comic = this.EntityContext.TryGetComic(comicId, null, true); // if (comic != null) // { // this.LoginGuestUser(comic.Author); // } //} //// Guest user logged in //else if (this.GuestUser != null) //{ // comic = this.EntityContext.TryGetComic(comicId, this.GuestUser); //} //else //{ // // All other entry points // this.EntityContext.TryAttach(this.ActiveUser); // comic = this.EntityContext.TryGetComic(comicId, this.ActiveUser, this.Friends); //} // Asume that if the user found the comic, they are allowed to read it (hard to track shares and whatnot) comic = this.EntityContext.TryGetComic(comicId); if (comic == null) { result = this.View("ReadNotFound"); } else { // Track read this.EntityContext.TryAttach(this.ActiveUser); ComicRead read = this.EntityContext.TryGetComicRead(comic, this.ActiveUser); try // Having an entity issue.. trying to track it down with this. { if (read == null) { read = new ComicRead(); read.Comic = comic; read.Reader = this.ActiveUser; read.ReadTime = DateTime.Now; if (this.ActiveUser != null) { this.EntityContext.AddToComicRead(read); this.EntityContext.SaveChanges(); } } } catch (Exception x) { this.Log.Error("Reader error", x); } finally { this.EntityContext.TryDetach(this.ActiveUser); } // Load tags comic.ComicTags.Load(); List <ClientComicTag> tags = comic.ComicTags.Select(t => new ClientComicTag(t)).ToList(); result = (ActionResult)this.View(new ViewRead(new ClientComic(comic), new ClientComicRead(read), tags)); } } finally { this.EntityContext.TryDetach(this.ActiveUser); } return(result); }
public ViewResult Create(long?id) { ClientComic comic = null; List <ClientTemplate> templates = this.EntityContext.ListTemplates() .ToList() .Select(t => new ClientTemplate(t)) .ToList(); foreach (ClientTemplate t in templates) { int width = Math.Min(t.Width, 734); double factor = Convert.ToDouble(width) / Convert.ToDouble(t.Width); t.Width = width; t.Height = Convert.ToInt32(Convert.ToDouble(t.Height) * factor); foreach (ClientTemplateItem i in t.TemplateItems) { i.Width = Convert.ToInt32(Convert.ToDouble(i.Width) * factor); i.Height = Convert.ToInt32(Convert.ToDouble(i.Height) * factor); i.X = Convert.ToInt32(Convert.ToDouble(i.X) * factor); i.Y = Convert.ToInt32(Convert.ToDouble(i.Y) * factor); } } if (id.HasValue) { // Facebook shared comics Data.Comic c = this.EntityContext.TryGetComic(id.Value, this.ActiveUser) ?? this.EntityContext.TryGetUnpublishedComic(id.Value, this.ActiveUser); if (c != null) { c.ComicTextBubbles.Load(); c.ComicPhotos.Load(); comic = new ClientComic(c); // inject newlines into text int maxWidth = templates.SelectMany(t => t.TemplateItems).Select(t => t.Width).Min(); Font measureFont = new Font(ComicGenerator.ComicFont, 7, FontStyle.Regular, GraphicsUnit.Point); ComicGenerator generator = new ComicGenerator(templates.Min(t => t.Width), templates.Min(t => t.Height)); foreach (ComicTextBubble bubble in c.ComicTextBubbles) { Size rawTextSize = generator.MeasureText(bubble.Text, maxWidth, measureFont).ToSize(); Size textSize = this.CalculateTextSize(bubble.Text, rawTextSize, bubble.TextBubbleDirection.TextBubble); textSize.Width = Math.Min(textSize.Width, maxWidth); // Don't exceede template item area textSize = generator.MeasureText(bubble.Text, textSize.Width, measureFont).ToSize(); textSize.Width += 6; // Measure error ? int lines = textSize.Height / measureFont.Height; int cutWidth = (bubble.Text.Length / lines) - 4; for (int l = 1; l < lines; l++) { int cut = cutWidth * l; int space = bubble.Text.IndexOf(' ', cut); if (space > 0) { bubble.Text = bubble.Text.ReplaceAt(space, '\n'); } } comic.Bubbles.First(b => b.ComicTextBubbleId == bubble.ComicTextBubbleId).Text = bubble.Text; } } } List <ClientTextBubbleDirection> bubbles = this.EntityContext.ListTextBubbles() .SelectMany(b => b.TextBubbleDirections) .ToList() .Select(d => new ClientTextBubbleDirection(d)) .ToList(); return(this.View(new ViewCreate(comic, templates, this.GetEffects(), bubbles))); }