Дано:
1) Терминал Motorola (Symbol) MC3090 Windows CE 5.0
2) Принтер Zebra RW430
3) 1C:Предприятие 8.1 (УПП)
4) WiFi - точка доступа.
Решено не использовать всякие Mobile Logistic и прочие продукты сторонних производителей - да и дорабатывать их надо под задачи предприятия....
MC3090 - русский язык отображает, но русской консоли нет. Поиск по нету ничего вразумительного не дал - ни один руссификатор от Win Mobile не подходит.... Фиг с ним - решено: На терминале ввод ограничим максимум числами.
Далее стал думать - как собственно работать с 1С. На терминале есть клиент Remote Desctop - быстро навалял мини-формы для 1С, подключил принтер к компу - вуаля- печатать ярлыки можно...
А вот с остальным - затык! Штрих коды через терминал не почитаешь - лазер не работает пока ему пинка программно не дашь... DataWedge не выход...
Решено забить на Remote Desctop и взять в руки Compact Farmework в купе с Symbol EMDK for .Net
Реализовалось всё довольно быстро: в 1С реализован Web-сервис, в терминале - клиент. Плюсов дофига - никаких выгрузок-загрузок, не нужно SQL server CE и прочие Lite, нажал на терминале кнопочку- списочек документов получил, выбрал, пошел печатать ярлыки...
Ляпота....
Принтер RW420 в таком случае будет иметь свой IP и данные будут приходить на определенный порт в виде команд CPCL.
Тоже ляпота....
Стоп! Ляпота кончилась - в Zebra RW 420 нет шрифтов с кириллицей!
хотя по русски надо вывести всего две строчки.... Иэх...
Полазив в нете - ничего не нашел. Label Vista позволяет создать шрифт для принтера из шрифта True Type, НО! Только для первых 127 символов. Победить это не удалось. ZebraDesigner Font Downloader вообще работать отказался :(
После недолгих раздумий нашелся выход - печать в графике (выводить название товара в Bitmap и затем печатать на принтер). Плюсы - использование любых шрифтов.
Затык в том, что Zebra RW420 принимает только формат PCX. Конвертация в этот формат из изображений, поддерживаемых Compact Framework - отдельная песня...
Есть еще один вариант - использовать команду EG или CG. (Смотрите мануал по CPCL).
Методом тыка выбрана CG. (Кстати Label Vista всю этикетку загоняет в графику и печает с помощью этой самой команды).
Теперь надо думать как ей подсунуть картинку.
Вообщем, методом проб и ошибок задача была решена.
И вот решением её я и хочу с Вами поделиться. (это не конечный вариант, поскольку все константы затем были вынесены в настройки, а скорее наиболее понятная форма).
public static class BarCodePrinter
{
/// Печать этикетки
public static void PrintGoodsLabel(BarCode code, int count)
{
try
{
//Рисуем битмап с двумя строками (наименование товара и наименование серии)
var bmp = CreateBitmap(code.GoodsName, code.SerieName);
//Создаем заголовок формы (см. CPCL-programming manual)
var top = new StringBuilder();
top.AppendLine("! 0 200 200 400 " + count);
top.AppendLine("LABEL");
top.AppendLine("CONTRAST 0");
top.AppendLine("TONE 0");
top.AppendLine("SPEED 5");
top.AppendLine("PAGE-WIDTH 800");
top.AppendLine("GAP-SENSE 50");
top.AppendLine(";// PAGE 0000000008000400");
//формируется сама команда CG
top.Append("CG ");
top.Append(bmp.Width / 8 + " "); //Ширина рисунка в байтах
top.Append(bmp.Height + " "); //Высота рисунка в пикселях
top.Append(5 + " "); //x - координата рисунка на этикетке
top.Append(5 + " "); //y - координата рисунка на этикетке
//Конвертируем битмап в набор байтов для команды CG
var imgBuffer = BitmapToByteBuffer(bmp);
//Это будет нижняя часть этикетки
var bottom = new StringBuilder(Environment.NewLine);
//Вывод штрих-кода
bottom.AppendLine("BT 7 3 5");
bottom.AppendLine("B EAN13 5 1 200 120 115 " + code.Code);
bottom.AppendLine("BT OFF");
bottom.AppendLine("FORM");
bottom.AppendLine("PRINT");
//Отправляем на печать
SendToPrinter(top.ToString(), imgBuffer, bottom.ToString());
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Ошибка!", MessageBoxButtons.OK, MessageBoxIcon.Exclamation,
MessageBoxDefaultButton.Button1);
}
}
///Конвертация битмапа в байт-массив
private static byte[] BitmapToByteBuffer(Bitmap bmp)
{
var imgBuffer = new byte[bmp.Width/8*bmp.Height];
var i = 0;
for (var ycount = 0; ycount < bmp.Height; ycount++)
{
for (var xcount = 0; xcount < bmp.Width; xcount += 8) //формируем по 8 битов
{
//формируем байт (типа... можно, конечно и элегантней)
var b = bmp.GetPixel(xcount, ycount) == Color.Black ? 1 : 0;
for (var j = 1; j < 8; j++)
{
b <<= 1;
b += bmp.GetPixel(xcount + j, ycount) == Color.Black ? 1 : 0;
}
//байт за байтом добавляем к результату
imgBuffer[i] = (byte) b;
i++;
}
}
return imgBuffer;
}
///Выводим две строчки в битмап
private static Bitmap CreateBitmap(string first, string second)
{
var img = new Bitmap(784, 112, PixelFormat.Format16bppRgb555);
// PixelFormat.Format1bpp был бы, наверное, лучше (меньше по размеру), но он не поддерживается на Windows CE :(
var graphicImage = Graphics.FromImage(img);
graphicImage.Clear(Color.White);
var drawFont = new Font("Arial", 24, FontStyle.Bold);
var drawBrush = new SolidBrush(Color.Black);
const float x = 10.0F;
const float y = 10.0F;
graphicImage.DrawString(first, drawFont, drawBrush, x, y);
graphicImage.DrawString(second, drawFont, drawBrush, x, y + 30);
return img;
}
///Берём IP endpoint принтера
private static IPEndPoint GetPrinterEndPoint()
{
var address = IPAddress.Parse("192.168.0.221"); //адрес
if (address == null)
throw new NullReferenceException("Не указан адрес принтера!");
return new IPEndPoint(address, 6101); //и порт...
}
/// Печатаем...
private static void SendToPrinter(string top,byte[] imgBuffer, string bottom)
{
var printerEndPoint = GetPrinterEndPoint();
var clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
clientSocket.Connect(printerEndPoint);
clientSocket.Send(Encoding.ASCII.GetBytes(top)); //отправляем шапку
clientSocket.Send(imgBuffer); //отправляем картинку
clientSocket.Send(Encoding.ASCII.GetBytes(bottom)); //отправляем подвал (штрих-код и команда PRINT!)
clientSocket.Close(); // усё!!!
}
}
Ляпота...