Наложение копирайта на рисунки
Я с удовольствием делаю всякие штуки с графикой. Об одной такой маленькой фишке для ASP2 я расскажу на этой страничке. Контролы, выводящие графику, обращаются для вывода графики на специальную страничку примерно вот так.
Теперь посмотрим, куда именно они обращаются.
00001: <%@ Page Language="VB" AutoEventWireup="false" CodeFile="ImageFromDS.aspx.vb" Inherits="ImageFromDS" %> 00002: 00003: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 00004: 00005: <html xmlns="http://www.w3.org/1999/xhtml" > 00006: <head runat="server"> 00007: <title>Untitled Page</title> 00008: </head> 00009: <body> 00010: <form id="form1" runat="server"> 00011: <div> 00012: эта страничка - просто способ записать в поток браузера в формате IMAGE/BMP<br /> 00013: на URL этой странички можно сосластся при необходимости добавления рисунка из ДатаСета</div> 00014: </form> 00015: </body> 00016: </html>
00001: Partial Class ImageFromDS 00002: Inherits System.Web.UI.Page 00003: 00004: Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load 00005: Dim WorkNodes As New Global.SH.WorkingTovarList 'отбор на рабочем столе 00006: If Not (Session("WorkNodes") Is Nothing) Then WorkNodes = Session("WorkNodes") 00007: Dim i As String = Request.QueryString("i") 'какой рисунок из сессионного отбора надо отрисовать 00008: Dim OneTovarPos As SH.WorkingTovar 00009: For Each OneTovarPos In WorkNodes 00010: If OneTovarPos.TovarValue = i Then 00011: Response.ContentType = "image/bmp" 00012: 'Response.BinaryWrite(CType(OneTovarPos.PriceDS._MyPrice(0).MyImage(), Byte())) 00013: Try 00014: Response.BinaryWrite(SH.Common.AddRightToImage(OneTovarPos.PriceDS._MyPrice(0).MyImage())) 00015: Catch ex As Exception 00016: Response.BinaryWrite(SH.Common.AddRightToImage(Nothing)) 00017: End Try 00018: End If 00019: Next 00020: End Sub 00021: End Class
Этот текст составлен из расчета, что данные в ДатаСете не могут быть NULL. Поэтому тут может возникнуть исключение при отсутствии рисунка. В противном случае перехвата прерывания в строках 13-17 можно не делать. Теперь собственно функция наложения копирайта (она у меня лежит в GAC'е):
00001: Shared Function AddRightToImage(ByVal Buffer As Byte()) As Byte() 00002: Return AddRightToImage(Buffer, 200, 150) 00003: End Function 00004: Shared Function AddRightToImage(ByVal Buffer As Byte(), ByVal Width As Integer, ByVal Heigth As Integer) As Byte() 00005: Const FontHeight As Integer = 20 00006: Dim MyKist As New Drawing.Drawing2D.LinearGradientBrush(New Drawing.Point(0, Heigth - FontHeight), New Drawing.Point(0, Heigth), Drawing.Color.AliceBlue, Drawing.Color.Navy) 00007: Dim Z As New IO.MemoryStream 00008: Try 00009: If Buffer.Length > 0 Then 00010: Dim Y As New IO.MemoryStream(Buffer) 00011: Dim X As New Drawing.Bitmap(Y) 00012: Dim G As Drawing.Graphics = Drawing.Graphics.FromImage(X) 00013: G.DrawString("Soft-Help.Ru", New Drawing.Font("", FontHeight, Drawing.FontStyle.Italic, Drawing.GraphicsUnit.Pixel), MyKist, 35, Heigth - FontHeight - 5) 00014: 'тут главное - при выводе сохранить первоначальный формат рисунка 00015: Select Case X.RawFormat.Guid 00016: Case Drawing.Imaging.ImageFormat.Jpeg.Guid : X.Save(Z, System.Drawing.Imaging.ImageFormat.Jpeg) 00017: Case Drawing.Imaging.ImageFormat.Gif.Guid : X.Save(Z, System.Drawing.Imaging.ImageFormat.Gif) 00018: Case Drawing.Imaging.ImageFormat.Png.Guid : X.Save(Z, System.Drawing.Imaging.ImageFormat.Png) 00019: Case Else : X.Save(Z, System.Drawing.Imaging.ImageFormat.Gif) 00020: End Select 00021: End If 00022: Catch ex As Exception 00023: 'нету рисунка - в SQL-поле NULL 00024: Dim X As New Drawing.Bitmap(Width, Heigth) 00025: Dim G As Drawing.Graphics = Drawing.Graphics.FromImage(X) 00026: G.Clear(Drawing.Color.White) 00027: G.DrawString("Нет рисунка", New Drawing.Font("", FontHeight, Drawing.FontStyle.Italic, Drawing.GraphicsUnit.Pixel), Drawing.Brushes.Gainsboro, 40, 50) 00028: X.Save(Z, Drawing.Imaging.ImageFormat.Gif) 00029: End Try 00030: Return Z.ToArray 00031: 'либо можно было бы выводить прямо в поток браузера 00032: 'X.Save(Response.OutputStream, System.Drawing.Imaging.ImageFormat.Gif) 00033: End Function
Здесь все тривиально, лишь может быть надо пояснить, что КИСТЬ - это то, чем заполняется пространство между контурами. Она бывает разных типов, но в данном случае - это кисть линейной заливки. Второй важный момент - не потерять первоначальный формат рисунка, иными словами не преобразовать при выводе JPG в GIF. Результат будет плачевный, двадцать килобайт превратятся в 500 байт с соответвующей потерей качества.
В дальнейшем моя капча претерпела множество модификаций, а раз уж мы коснулись вопросов обработки графики - я покажу здесь еще один свой полезный класс для масштабирования графики:
00001: ''' <summary> 00002: ''' Уменьшить рисунок до заданной ширины 00003: ''' </summary> 00004: Public Shared Function StripSize(ByVal Buffer As Byte(), ByVal NewWidth As Integer) As Byte() 00005: Try 00006: If Buffer.Length > 0 And NewWidth > 0 Then 00007: Dim Out As New IO.MemoryStream 00008: Dim Buf As New IO.MemoryStream(Buffer) 00009: Dim Source As New Drawing.Bitmap(Buf,False) 00010: Dim Reduce As Double = Source.Width / NewWidth 00011: Dim Target As New Drawing.Bitmap(Source, NewWidth, Source.Height / Reduce) 00012: Select Case Target.RawFormat.Guid 00013: Case Drawing.Imaging.ImageFormat.MemoryBmp.Guid : Target.Save(Out, System.Drawing.Imaging.ImageFormat.Jpeg) 00014: Case Else : Throw New Exception("Неизвестный формат графического файла") 00015: End Select 00016: Return Out.ToArray 00017: Else 00018: Throw New Exception("StripSize.") 00019: End If 00020: Catch ex As Exception 00021: Throw New Exception("StripSize: " & ex.Message) 00022: End Try 00023: End Function
Здесь небольшое более позднее дополнение, которое родилось через год после написания первого варианта этой странички. Позднее, я понял, что ни контрол, ни страничка - не являются идеальным решением для вывода графики. Они удобны, особенно контрол - этого у них не отнимешь - контролы буксируются драг-анд-дропом прямо на web-форму. Однако есть некрасивое, но эффективное решение - хандлеры.
Некрасивость его проявляется в кривизне формирования ссылок на хандлер на основной страничке - оно выглядит примерно так:
Зато лишние события странички не возникают - и это гораздо эффективнее контрола или отдельной странички, которая была описана тут выше:
00001: <%@ WebHandler Language="VB" Class="GetImage" %> 00002: 00003: Imports System 00004: Imports System.Web 00005: 00006: Public Class GetImage : Implements IHttpHandler, IRequiresSessionState 00007: 00008: Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest 00009: If context.Current.Request.QueryString("J") <> Nothing Then 00010: ' 00011: 'выудим номер отображаемого рисунка в UserData 00012: ' 00013: Dim J As Integer = PP8_Helper.Unmask_QueryString("J", "Votpusk") 00014: ' 00015: 'ширина для преобразованного рисунка или 0 - без преобразования 00016: ' 00017: Dim W As Integer 00018: If context.Current.Request.QueryString("W") IsNot Nothing Then W = CInt(context.Current.Request.QueryString("W")) Else W = 0 00019: Dim CN As New System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings("Votpusk").ConnectionString) 00020: CN.Open() 00021: Dim CMD As New System.Data.SqlClient.SqlCommand("GetUserData", CN) 00022: CMD.CommandType = Data.CommandType.StoredProcedure 00023: CMD.Parameters.AddWithValue("I", J) 00024: Dim RDR As Data.SqlClient.SqlDataReader = CMD.ExecuteReader() 00025: If RDR.Read Then 00026: If Not IsDBNull(RDR("Data")) Then 00027: If W = 0 Then 00028: 'вывод в натуральную величину - без массштабированния, но с копирайтом 00029: context.Response.ContentType = "image/bmp" 00030: context.Response.Charset = "windows-1251" 00031: context.Response.BinaryWrite(Image.AddRightToImage(RDR("Data"))) 00032: Else 00033: 'вывод с масштабированием 00034: context.Response.ContentType = "image/bmp" 00035: context.Response.Charset = "windows-1251" 00036: context.Response.BinaryWrite(Image.StripSize(RDR("Data"), W)) 00037: End If 00038: End If 00039: End If 00040: RDR.Close() 00041: RDR = Nothing 00042: CMD = Nothing 00043: 'сбор статитстики о запросах на рисунки 00044: If System.Configuration.ConfigurationManager.AppSettings("ShowStatistic") Then 00045: Dim CMD1 As New System.Data.SqlClient.SqlCommand("AddImageShowStat", CN) 00046: CMD1.CommandType = Data.CommandType.StoredProcedure 00047: CMD1.Parameters.AddWithValue("ToData", J) 00048: CMD1.Parameters.AddWithValue("UserName", HttpContext.Current.User.Identity.Name) 00049: CMD1.Parameters.AddWithValue("IPaddress", HttpContext.Current.Request.UserHostAddress) 00050: CMD1.Parameters.AddWithValue("SessionID", HttpContext.Current.Session.SessionID) 00051: CMD1.Parameters.AddWithValue("Width", W) 00052: CMD1.ExecuteNonQuery() 00053: CMD1 = Nothing 00054: End If 00055: CN.Close() 00056: End If 00057: End Sub 00058: 00059: Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable 00060: Get 00061: Return False 00062: End Get 00063: End Property 00064: 00065: End Class
|