В первой части мы рассмотрели некоторые детали реализации макета интерфейса приложения InstaFuzz . Вы можете получить исходный код приложения здесь, если хотите запустить его локально. В этой статье мы рассмотрим некоторые другие моменты, такие как использование перетаскивания, File API, Canvas и Web Workers.
Перетаскивания
Одна из вещей, которую поддерживает InstaFuzz, – это возможность перетаскивать файлы изображений непосредственно на большой черно-синий прямоугольник. Поддержка этого активируется путем обработки события drop в элементе CANVAS. Когда файл помещается в элемент HTML, браузер запускает событие «drop» для этого элемента и передает объект dataTransfer, который содержит свойство files , содержащее ссылку на список файлов, которые были удалены. Вот как это обрабатывается в приложении («picture» – это идентификатор элемента CANVAS на странице):
var pic = $ («# picture»); pic.bind («drop», function (e) suppressEvent (е); var files = e.originalEvent.dataTransfer.files; // больше кода здесь, чтобы открыть файл >); pic.bind («dragover», suppressEvent) .bind («dragenter», suppressEvent); function suppressEvent (e) e.stopPropagation (); e.preventDefault (); >
Свойство files представляет собой набор объектов File, которые затем можно использовать с File API для доступа к содержимому файла (рассматривается в следующем разделе). Мы также обрабатываем события перетаскивания и перетаскивания и в основном предотвращаем распространение этих событий в браузер, тем самым не давая браузеру обрабатывать удаление файла. Например, IE может выгрузить текущую страницу и в противном случае попытаться открыть файл напрямую.
Обмен файлами по LAN кабелю между двумя ПК ноутбуками
Файловый API
После удаления файла приложение пытается открыть изображение и отобразить его на холсте. Это делается с помощью File API . Файловый API – это спецификация W3C, которая позволяет веб-приложениям программным образом защищать доступ к файлам из локальной файловой системы. В InstaFuzz мы используем объект FileReader для чтения содержимого файла в виде строки URL-адреса данных, например, используя метод readAsDataURL :
var reader = new FileReader (); reader.onloadend = function (e2) drawImageToCanvas (e2.target.result); >; reader.readAsDataURL (файлы [0]);
Здесь files – это коллекция объектов File, полученных из функции, обрабатывающей событие drop в элементе CANVAS. Поскольку нас интересует только один файл, мы просто выбираем первый файл из коллекции и игнорируем остальные, если они есть. Фактическое содержимое файла загружается асинхронно, и после завершения загрузки происходит событие onloadend, где мы получаем содержимое файла в виде URL-адреса данных, который затем впоследствии рисуем на холсте.
Рендеринг фильтров
Теперь основной функциональностью здесь является, конечно, применение фильтров. Чтобы применить фильтр к изображению, нам нужен способ доступа к отдельным пикселям изображения. И прежде чем мы сможем получить доступ к пикселям, нам нужно фактически отобразить изображение на нашем холсте. Итак, давайте сначала посмотрим на код, который отображает изображение, выбранное пользователем, в элемент canvas.
Рендеринг изображений на холсте
Элемент canvas поддерживает рендеринг объектов Image с помощью метода drawImage . Для загрузки файла изображения в экземпляре Image InstaFuzz использует следующую служебную программу:
App.Namespace.define («InstaFuzz.Utils», loadImage: function (url, complete) var img = новое изображение (); img.src = url; img.onload = function () полный (IMG); >; > >);
Это позволяет приложению загружать объекты изображений с URL-адреса, используя следующий код:
function drawImageToCanvas (url) InstaFuzz.Utils.loadImage (url, function (img) // сохранить ссылку на исходное изображение sourceImage = img; mainRenderer.clearCanvas (); mainRenderer.renderImage (IMG); // загрузка превью фильтров изображения loadPreviews (IMG); >); >
Здесь mainRenderer – это экземпляр, созданный из функции конструктора FilterRenderer, определенной в filter-renderer.js . Приложение использует объекты FilterRenderer для управления элементами холста – как на панели предварительного просмотра, так и в основном элементе холста справа. Метод renderImage в FilterRenderer был определен так:
FilterRenderer.prototype.renderImage = function (img) var imageWidth = img.width; var imageHeight = img.height; var canvasWidth = this.size.width; var canvasHeight = this.size.height; вар ширина, высота; if ((imageWidth / imageHeight)> = (canvasWidth / canvasHeight)) ширина = холст ширина; height = (imageHeight * canvasWidth / imageWidth); > еще ширина = (imageWidth * canvasHeight / imageHeight); height = canvasHeight; > var x = (canvasWidth — ширина) / 2; var y = (canvasHeight — высота) / 2; this.context.drawImage (img, x, y, ширина, высота); >;
Это может показаться большим количеством кода, но все, что он в конечном итоге делает, – это выясняет лучший способ визуализации изображения в доступной области экрана с учетом соотношения сторон изображения. Ключевой фрагмент кода, который фактически отображает изображение на холсте, находится в последней строке метода. Элемент контекста ссылается на 2D-контекст, полученный из объекта canvas путем вызова его метода getContext .
Получение пикселей с холста
Теперь, когда изображение отрендерено, нам понадобится доступ к отдельным пикселям, чтобы применить все доступные фильтры. Это легко получить, вызвав getImageData для объекта контекста холста. Вот как это называет InstaFuzz из instafuzz.js .
var imageData = renderer.context.getImageData ( 0, 0, renderer.size.width, renderer.size.height);
Объект, возвращаемый getImageData, обеспечивает доступ к отдельным пикселям через его свойство данных, которое, в свою очередь, представляет собой объект в виде массива, который содержит коллекцию байтовых значений, где каждое значение представляет цвет, отображаемый для одного канала одного пикселя.
Каждый пиксель представлен 4 байтами, которые определяют значения для красного, зеленого, синего и альфа-каналов. Он также имеет длину свойство, которое возвращает длину буфера. Если у вас есть 2D-координата, вы можете легко преобразовать ее в индекс в этот массив, используя следующий код. Значения интенсивности цвета каждого канала варьируются от 0 до 255. Вот полезная функция от filters.js, которая принимает в качестве входных данных объект данных изображения вместе с 2D-координатами для пикселя, интересующего вызывающего, и возвращает объект, содержащий значения цвета:
function getPixel (imageData, x, y) var data = imageData.data, index = 0; // нормализуем x и y и вычисляем индекс х = (х <0)? (imageData.width + x): x; у = (у <0)? (imageData.height + y): y; index = (x + y * imageData.width) * 4; возвращение r: данные [индекс], g: данные [индекс + 1], б: данные [индекс + 2] >; >
Применение фильтров
Теперь, когда у нас есть доступ к отдельным пикселям, применить фильтр довольно просто. Здесь, например, функция, которая применяет взвешенный фильтр градаций серого к изображению. Он просто выбирает интенсивности из красного, зеленого и синего каналов и суммирует их после применения коэффициента умножения для каждого канала, а затем назначает результат для всех 3 каналов.
// Фильтр «Взвешенные оттенки серого» Filters.addFilter ( название: «Весовая шкала серого», apply: function (imageData) var w = imageData.width, h = imageData.height; var data = imageData.data; индекс var; для (var y = 0; y для (var x = 0; x index = (x + y * imageData.width) * 4; переменная яркость = parseInt ((данные [индекс + 0] * 0,3) + (данные [индекс + 1] + 0,59) + (данные [индекс + 2] * 0,11)); данные [индекс + 0] = данные [индекс + 1] = данные [индекс + 2] = яркость; > Filters.notifyProgress (imageData, x, y, this); > Filters.notifyProgress (imageData, w, h, this); > >);
После применения фильтра мы можем отразить это на холсте, вызвав метод putImageData, передав в измененный объект данных изображения. В то время как взвешенный фильтр в градациях серого довольно прост, большинство других фильтров используют технику обработки изображений, известную как свертка . Код для всех фильтров доступен в filters.js, и фильтры свертки были перенесены из кода C, доступного здесь .
Веб-работники
Как вы можете себе представить, выполнение всего этого перебора чисел для применения фильтров может занять много времени. Например, фильтр размытия в движении использует матрицу фильтра 9 × 9 для вычисления нового значения для каждого отдельного пикселя и фактически является наиболее интенсивным процессором среди всех этих фильтров. Если бы мы выполняли все эти вычисления в потоке пользовательского интерфейса браузера, то приложение по существу зависало бы каждый раз, когда применялся фильтр. Чтобы обеспечить отзывчивый пользовательский опыт, приложение делегирует основные задачи обработки изображений в фоновый скрипт, используя поддержку W3C Web Workers в современных браузерах.
Веб-работники позволяют веб-приложениям запускать сценарии в фоновой задаче, которая выполняется параллельно с потоком пользовательского интерфейса. Связь между рабочим и потоком пользовательского интерфейса осуществляется путем передачи сообщений с помощью API postMessage . На обоих концах (т. Е. Поток пользовательского интерфейса и рабочий) это проявляется как уведомление о событии, которое вы можете обработать. Вы можете только передавать «данные» между рабочими и потоком пользовательского интерфейса, то есть вы не можете передавать ничего, что связано с пользовательским интерфейсом – например, вы не можете передавать элементы DOM работнику из потока пользовательского интерфейса.
В InstaFuzz рабочий реализован в файле filter-worker.js . Все, что он делает в работнике – это обрабатывает событие onmessage и применяет фильтр, а затем передает результаты обратно через postMessage . Как выясняется, даже если мы не можем передать элементы DOM (что означает, что мы не можем просто передать элемент CANVAS работнику, чтобы применить фильтр), мы можем фактически передать объект данных изображения, возвращенный методом getImageData, который мы обсуждали ранее. , Вот код обработки фильтра из filter-worker.js :
importScripts («ns.js», «filters.js»); var tag = null; onmessage = function (e) var opt = e.data; var imageData = opt.imageData; вар фильтр; tag = opt.tag; filter = InstaFuzz.Filters.getFilter (opt.filterKey); var start = Date.now (); filter.apply (ImageData); var end = Date.now (); PostMessage ( тип: «изображение», imageData: imageData, filterId: filter.id, тег: тег, TimeTaken: конец — начало >); >
Первая строка включает некоторые файлы сценариев, от которых зависит рабочий, вызывая importScripts . Это похоже на включение файла JavaScript в документ HTML с использованием тега SCRIPT. Затем мы устанавливаем обработчик для события onmessage, в ответ на который мы просто применяем рассматриваемый фильтр и передаем результат обратно в поток пользовательского интерфейса, вызывая postMessage . Достаточно просто!
Код, который инициализирует работника, находится в instafuzz.js и выглядит так:
var worker = new Worker («js / filter-worker.js»);
Не много ли это? Когда сообщение отправляется рабочим в поток пользовательского интерфейса, мы обрабатываем его, определяя обработчик для события onmessage в рабочем объекте. Вот как это делается в InstaFuzz :
worker.onmessage = function (e) var isPreview = e.data.tag; switch (e.data.type) case «image»: if (isPreview) previewRenderers [e.data.filterId]. context.putImageData ( e.data.imageData, 0, 0); > еще mainRenderer.context.putImageData ( e.data.imageData, 0, 0); > перемена; // больше кода здесь > >;
Код должен быть достаточно понятным. Он просто выбирает объект данных изображения, отправленный рабочим, и применяет его к контекстному объекту соответствующего холста, вызывая отображение измененного изображения на экране. Планирование фильтра для преобразования с рабочим одинаково просто. Вот процедура, которая выполняет эту функцию в InstaFuzz :
функция scheduleFilter (filterId, визуализатор, img, isPreview, resetRender) if (resetRender) renderer.clearCanvas (); renderer.renderImage (IMG); > var imageData = renderer.context.getImageData ( 0, 0, renderer.size.width, renderer.size.height); worker.postMessage ( imageData: imageData, ширина: imageData.width, высота: imageData.height, filterKey: filterId, tag: isPreview >); >
Завершение
Источник для InstaFuzz доступен для скачивания здесь . Мы увидели, что довольно сложные пользовательские интерфейсы возможны сегодня с такими технологиями HTML5, как Canvas, Drag / Drop, File API и Web Workers. Поддержка всех этих технологий довольно хороша почти во всех современных браузерах. Одна вещь, которую мы не затронули, это вопрос совместимости приложения со старыми браузерами. По правде говоря, это нетривиальная, но необходимая задача, о которой я надеюсь рассказать в следующей статье.
Источник: coderlessons.com
Организация шаринга файлов в приложении на С#
Недавно мне пришлось работать над интересным проектом, в котором заказчик просил реализовать обмен файлами через интернет, соответственно с прямым доступом прямо из приложения.
- Отображение списка файлов.
- Загрузка и скачивание через интерфейс программы.
- Скрытая авторизация без участия пользователя.
Первые проблемы
- DropBox
- Box.com
- Windows Live SkyDrive
- Ge.tt
Файлы для всех
Ge.tt предоставляет пользователю бесплатное хранилище объемом 2Гб. Для взаимодействия с облаком, необходимо создать приложение и получить APIKey. Документация довольно скудная, но все необходимые функции есть. Условия использования полностью соответствуют требованиям заказчика. Модель авторизации простая: POST запрос с параметрами Email + Password + APIToken.
Бонус к этому, готовая динамическая библиотека с реализацией необходимых функций, с ней мы и будем работать.
Реализация
Структура хранилища определяется следующим образом:
- Shares (Шары) — отдельные элементы (папки) содержащие структуры.
- Files (Файлы) — непосредственно структура с файлами.
То есть каждая шара может включать в себя список файлов, таким образом можно создавать тематические разделы, соответствующие, например расширению файла.
Опишем основной алгоритм:
- Авторизация.
- Обновление шар.
- Получение списка файлов в шарах.
- Загрузка файла.
Авторизация
Подключаем библиотеку к нашему проекту:
using Gett;
Для безопасности не рекомендую хранить логин и пароль в чистом виде, используйте шифрование.
Получаем файлы
Как я уже писал, чтобы получить список файлов необходимо выбрать определенную шару. Сделаем вывод списка шар в listBoxShare, тогда при клике по элементу будем подгружать список файлов в listBoxFiles:
user.RefreshMe();//POST запрос this.listBox_Share.Items.Clear(); this.listBox_Files.Items.Clear(); this.listBox_Share.Items.AddRange(user.Shares.GetShares()); //Добавление диапазона шар в listBox // Gett.Sharing.GettShare[] _shares = user.Shares.GetShares(); //Пример добавление шар в массив, если необходимо
Получение информации о файлах аналогичный процесс. В событии SelectedIndexChanged у listBox_Share пишем код:
private void listBoxShare_SelectedIndexChanged(object sender, EventArgs e) < this.listBox_Files.Items.Clear(); if (this.listBox_Share.SelectedItem is Gett.Sharing.GettShare)// проверка типа данных < Gett.Sharing.GettShare share = (Gett.Sharing.GettShare)this.listBox_Share.SelectedItem;//присвоение переменной выделенного элемента this.listBox_Files.Items.AddRange(share.Files);// добавление диапазона данных о файлах в listBox_Files ListFileList = new List();// пример создания массива с информацией о файлах > >
- Количество загрузок.
- Порядковый номер.
- Полное имя.
- URL.
- Размер.
- Дата загрузки.
Чтобы получить необходимые свойства нужно обратиться к нужному элементу, и вызвать свойство Info:
string name= FileList[0].Info.FileName;//имя файла в нулевом индексе массива long size = FileList[0].Info.Size;//размер файла
Теперь скачаем файл. Пишем код, напимер для того же SelectedIndexChanged:
if (this.listBox_Files.SelectedItem is Gett.Sharing.GettFile)// проверка типа данных < Gett.Sharing.GettFile file = (Gett.Sharing.GettFile)this.listBox_Files.SelectedItem;//получение экземпляра файла SaveFileDialog saveDialog = new SaveFileDialog();//инициализируем saveDialog для сохранения файла saveDialog.OverwritePrompt = true; saveDialog.FileName = file.Info.FileName; if (saveDialog.ShowDialog() == DialogResult.OK) < file.DownloadFileAsync(saveDialog.FileName);// ассинхронная загрузка >
Дальше дело вашей фантазии: удаляйте, переименовывайте файлы, создавайте каталоги. API открывает широкие возможности для реализации любых идей. Хорошая идея залог успеха!
Источник: habr.com
Многопоточное клиент-серверное приложение для обмена файлами Java
Доработаем этот проект по Вашим требованиям, напишите подробности нам в Телеграм
Курсовая работа (Задание):
Разработка клиент-серверного приложения для обмена файлами на языке программирования Java.
Вступление
Для того, чтобы иметь возможность передавать файлы между клиентом и сервером, существует протокол TCP/IP.
TCP – протокол управления передачей. Он служит для обеспечения и установление надежного соединения между двумя устройствами и надежную передачу данных. При этом протокол TCP контролирует оптимальный размер передаваемого пакета данных, осуществляя новую посылку при сбое передачи.
IP – интернет протокол или адресный протокол – основа всей архитектуры передачи данных. Протокол IP служит для доставки сетевого пакета данных по нужному адресу. При этом информация разбивается на пакеты, которые независимо передвигаются по сети до нужного адресата.
Постановка задачи
Задачей проекта является разработка клиент-серверного приложения для обмена файлами на языке программирования Java.
Цели и функции приложения:
- Многопоточный сервер
- Удобный и понятный интерфейс клиента
- Работа с базой данных MySQL
- Создание приватных комнат для обмена файлами
- Информационное окно с логированием действий приложения
- Поддержка архивации выбранным клиентом файлов
- Поддержка передачи и приёма архивов с файлами
Содержание отчета к программе
В отчете находятся все необходимые диаграммы к нашей программе, такие как:
- Схема работы стороны сервера и клиента
- Диаграмма Usecase
- Диаграмма Statechart
- Диаграмма Sequence
- Диаграмма ООП классов
Также, присутствуют все скриншоты с описанием каждого действия пользователя в программе.
Как мы можем увидеть из сриншота, в пояснительной записке содержится 27 страниц.
Описание архитектуры приложения
На рисунке 1 представлена схема работы, которая показывает, как работает наша программа на стороне сервера и клиента.
Для гибкости разработки программы будем взаимодействовать с объектно-ориентированным программированием. На рисунке 2 представлена UML диаграмма классов на стороне сервера.
На рисунке 3 представлена UML диаграмма классов на стороне клиента.
Пример исходного кода
Руководство пользователя
Поскольку наше приложение по архитектуре клиент-сервер, то в первую очередь нам нужно запустить сервер, который в свою очередь открывает локальное соединение и работает на порту 8030. На рисунке 4 приведена форма сервера.
Рассмотрим сторону клиента, главная форма клиентского приложения представлена на рисунке 5.
Скриншот архива с проектом
Содержание архива
- Исходный код клиентского приложения
- Исходный код серверного приложения
- Отчет с 27 страницами + бонус презентация со скриншотами к проекту
- Pictures — картинки с описания программы со studlearn
- Автор работы: Alekseev
Купить 2700,00
Сразу после оплаты Вы сможете скачать работу и мы вышлем дополнительно файл с работой на электронную почту. Исходник программ Вы сможете отредактировать, как Вам нужно.
Комментарии
Комментарии (0)
Здесь еще никто не оставлял свои комментарии, будь первым!
Источник: studlearn.com