(ASP.NET) ASP.NET (2006 год)

Наложение копирайта на рисунки

Я с удовольствием делаю всякие штуки с графикой. Об одной такой маленькой фишке для 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


Comments ( )
<00>  <01>  <02>  <03>  <04>  <05>  <06>  <07>  <08>  <09>  <10>  <11>  <12>  <13>  <14>  <15>  <16>  <17>  <18>  <19>  <20>  <21>  <22>  <23
Link to this page: //www.vb-net.com/asp2/6/index.htm
<SITEMAP>  <MVC>  <ASP>  <NET>  <DATA>  <KIOSK>  <FLEX>  <SQL>  <NOTES>  <LINUX>  <MONO>  <FREEWARE>  <DOCS>  <ENG>  <CHAT ME>  <ABOUT ME>  < THANKS ME>