Википедия:Песочница
Это песочница для экспериментов с вики-разметкой. Чтобы начать редактировать эту страницу, нажмите кнопку «Править код» в верхнем меню. Не бойтесь ничего поломать: эта страница создана для опытов! |
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Net;
using System.Windows.Forms;
using System.Security.Authentication;
using System.Text;
using System.Text.RegularExpressions;
using System.Web.Script.Serialization;
using System.Threading;
namespace GettyImagesDownloader
{
class Downloader
{
WebClient wc;
Action<string> updateStatus;
string imageId;
string downloadType;
string compUrl;
int compSize;
string customerId;
string sharedKey;
string authHeader;
byte[] sfi;
int width;
int height;
int tileSize;
string key;
Image imageH;
Image imageV;
Image imageT;
Bitmap bitmap;
Graphics graphics;
string ReadString(BinaryReader br)
{
var sb = new StringBuilder();
for (;;)
{
var b = br.ReadByte();
if (b == 0x00)
return sb.ToString();
sb.Append(Encoding.ASCII.GetString(new[] { b }));
}
}
void DownloadSfi()
{
updateStatus("Downloading image data... ");
wc.Headers.Add("Accept", authHeader);
sfi = wc.DownloadData(
$"https://images.smartframe.net/sfis/{customerId}/{imageId}/2560w.sfi");
}
void ParseSfi()
{
updateStatus("Processing image data... ");
var br = new BinaryReader(new MemoryStream(sfi));
var s1 = ReadString(br);
if (!s1.StartsWith("PBS2"))
throw new Exception();
var s1s = s1.Substring(4).Split(';');
width = int.Parse(s1s[0]);
height = int.Parse(s1s[1]);
int jpegHsize = int.Parse(s1s[2]);
if (jpegHsize != 0)
imageH = Image.FromStream(new MemoryStream(br.ReadBytes(jpegHsize)), true);
int jpegVsize = int.Parse(ReadString(br));
if (jpegVsize != 0)
imageV = Image.FromStream(new MemoryStream(br.ReadBytes(jpegVsize)), true);
ReadString(br);
tileSize = int.Parse(ReadString(br));
ReadString(br);
var key1 = ReadString(br);
int jpegTsize = int.Parse(ReadString(br));
imageT = Image.FromStream(new MemoryStream(br.ReadBytes(jpegTsize)), true);
ReadString(br);
if (br.BaseStream.Position != br.BaseStream.Length)
throw new Exception();
key = string.Concat(sharedKey.ToCharArray().Zip(
key1.ToCharArray(), (f, s) => new string(new char[] { f, s })));
}
void RenderSfi()
{
bitmap = new Bitmap(width, height,
PixelFormat.Format24bppRgb);
graphics = Graphics.FromImage(bitmap);
if (imageH != null)
graphics.DrawImage(imageH, 0, height - imageH.Height);
if (imageV != null)
graphics.DrawImage(imageV, width - imageV.Width, 0);
int tileCountX = width / tileSize;
int tileCountY = height / tileSize;
var Y = new int[tileCountY];
var T = new int[tileCountY, tileCountX];
for (var y = 0; y < tileCountY; y++)
{
Y[y] = tileCountX;
for (var x = 0; x < tileCountX; x++)
T[y, x] = -1;
}
var y3 = tileCountY;
for (var y1 = 0; y1 < tileCountY; y1++)
{
for (var x1 = 0; x1 < tileCountX; x1++)
{
var i = y1 * tileCountX + x1;
var s1 = key[i % key.Length] % y3;
var s1c = 0;
for (var y2 = 0; y2 < tileCountY; y2++)
{
if (Y[y2] != 0 && s1 == s1c++)
{
var s2c = 0;
var s2 = key[x1 % key.Length] % Y[y2];
for (var x2 = 0; x2 < tileCountX; x2++)
{
if (T[y2, x2] == -1 && s2 == s2c++)
{
T[y2, x2] = i;
Y[y2]--;
if (Y[y2] == 0)
y3--;
graphics.DrawImage(
imageT,
x1 * tileSize,
y1 * tileSize,
new Rectangle(
x2 * (tileSize + 8),
y2 * (tileSize + 8),
tileSize,
tileSize),
GraphicsUnit.Pixel);
break;
}
}
}
}
}
}
updateStatus("Saving image data... ");
string filename = $"{imageId}_sfi.png";
bitmap.Save(filename);
updateStatus($"File is saved: {filename}");
}
bool ReadId(string input)
{
var m = Regex.Match(input, "(/|^)([0-9]+)(\\?|$)");
if (!m.Success)
{
updateStatus("Wrong input format");
return false;
}
imageId = m.Groups[2].Value;
return true;
}
void SelectDownloadType()
{
updateStatus("Selecting download type... ");
wc = new WebClient();
try
{
wc.DownloadString(
$"https://embed.gettyimages.com/oembed?url=http://gty.im/{imageId}");
downloadType = "sfi";
}
catch (WebException e)
{
HttpWebResponse r = e.Response as HttpWebResponse;
if (r != null)
if (r.StatusCode == HttpStatusCode.NotFound)
downloadType = "comp";
}
if (downloadType == null)
throw new Exception();
}
void GetSfiProperties()
{
updateStatus("Obtaining sfi properties... ");
var wb = wc.DownloadString(
"https://static.smartframe.net/getty-bridge/widgets-bridge.js");
var m = Regex.Match(wb,
"https://embed\\.smartframe\\.net/([0-9a-f]+)\\.js");
customerId = m.Groups[1].Value;
var sf = wc.DownloadString(
$"https://static.smartframe.net/sf/{customerId}/smartframe.js");
m = Regex.Match(sf, "sharedKey:'([0-9a-f]+)'");
sharedKey = m.Groups[1].Value;
m = Regex.Match(sf, "downloadImageAcceptHeader:'([^']+)'");
authHeader = m.Groups[1].Value;
wc.Headers.Add("Accept", authHeader);
// Trigger image generation
wc.DownloadData($"https://sfm.smartframe.net/sfm/{customerId}/{imageId}.sfm");
}
void GetCompUrl()
{
updateStatus("Obtaining comp URL... ");
var gid = wc.DownloadString($"https://www.gettyimages.com/detail/{imageId}");
var m = Regex.Match(gid,
"<script>window\\.currentAsset *= *(\\{[^<]+)window\\.currentPreferences *= *\\{\\}");
if (!m.Success)
throw new Exception();
var jsonString = m.Groups[1].Value;
var jss = new JavaScriptSerializer();
var json = jss.DeserializeObject(jsonString) as Dictionary<string, object>;
if (json.ContainsKey("compUrl"))
{
compUrl = json["compUrl"] as string;
compSize = 594;
}
if (json.ContainsKey("galleryComp1024Url"))
{
compUrl = json["galleryComp1024Url"] as string;
compSize = 1024;
}
if (json.ContainsKey("galleryHighResCompUrl"))
{
compUrl = json["galleryHighResCompUrl"] as string;
compSize = 2048;
}
if (compUrl == null)
throw new Exception();
}
void DownloadAndSaveComp()
{
updateStatus("Downloading image data... ");
var jpgData = wc.DownloadData(compUrl);
updateStatus("Saving image data... ");
string filename = $"{imageId}_comp_{compSize}.jpg";
File.WriteAllBytes(filename, jpgData);
updateStatus($"File is saved: {filename}");
}
public const SslProtocols _Tls12 = (SslProtocols)0x00000C00;
public const SecurityProtocolType Tls12 = (SecurityProtocolType)_Tls12;
public void Download(string input, Action<string> updateStatus)
{
// www.gettyimages.com refuses to work with TLS 1.1
ServicePointManager.SecurityProtocol = Tls12;
this.updateStatus = updateStatus;
if (!ReadId(input))
return;
SelectDownloadType();
if (downloadType == "sfi")
{
GetSfiProperties();
DownloadSfi();
ParseSfi();
RenderSfi();
}
else if (downloadType == "comp")
{
GetCompUrl();
DownloadAndSaveComp();
}
}
}
public class MainForm : Form
{
TableLayoutPanel tableLayoutPanel;
Label inputLabel;
TextBox inputTextBox;
Button downloadButton;
StatusStrip statusStrip;
ToolStripStatusLabel statusLabel;
void UpdateStatus(string status)
{
Invoke(new Action(() => statusLabel.Text = status));
}
private void InputTextBox_KeyDown(object sender, KeyEventArgs e)
{
if (e.Control && e.KeyCode == Keys.A)
{
inputTextBox.SelectAll();
e.SuppressKeyPress = true;
}
}
private void DownloadButton_Click(object sender, EventArgs e)
{
inputTextBox.Enabled = false;
downloadButton.Enabled = false;
new Thread(() =>
{
try
{
new Downloader().Download(
inputTextBox.Text, UpdateStatus);
}
catch (Exception ex)
{
Invoke(new Action(() =>
{
statusLabel.Text = "Failed";
MessageBox.Show(
ex.ToString(),
"Download failed",
MessageBoxButtons.OK,
MessageBoxIcon.Exclamation);
}));
}
Invoke(new Action(() =>
{
inputTextBox.Enabled = true;
downloadButton.Enabled = true;
inputTextBox.Focus();
}));
})
{
IsBackground = true
}.Start();
}
public MainForm()
{
InitializeComponent();
}
private void InitializeComponent()
{
tableLayoutPanel = new TableLayoutPanel();
inputLabel = new Label();
inputTextBox = new TextBox();
downloadButton = new Button();
statusStrip = new StatusStrip();
statusLabel = new ToolStripStatusLabel();
tableLayoutPanel.SuspendLayout();
statusStrip.SuspendLayout();
SuspendLayout();
tableLayoutPanel.ColumnCount = 1;
tableLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100f));
tableLayoutPanel.Controls.Add(inputLabel, 0, 0);
tableLayoutPanel.Controls.Add(inputTextBox, 0, 1);
tableLayoutPanel.Controls.Add(downloadButton, 0, 2);
tableLayoutPanel.Dock = DockStyle.Fill;
tableLayoutPanel.Padding = new Padding(4);
tableLayoutPanel.RowCount = 3;
tableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Absolute, 16f));
tableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 100f));
tableLayoutPanel.RowStyles.Add(new RowStyle());
tableLayoutPanel.TabIndex = 0;
inputLabel.Dock = DockStyle.Fill;
inputLabel.Text = "Enter image identifier or URL:";
inputTextBox.Dock = DockStyle.Fill;
inputTextBox.Multiline = true;
inputTextBox.TabIndex = 1;
inputTextBox.KeyDown += InputTextBox_KeyDown;
downloadButton.Anchor = AnchorStyles.None;
downloadButton.Size = new Size(100, 26);
downloadButton.TabIndex = 2;
downloadButton.Text = "Download";
downloadButton.Click += DownloadButton_Click;
statusStrip.Items.AddRange(new ToolStripItem[] { statusLabel});
statusStrip.RenderMode = ToolStripRenderMode.Professional;
statusStrip.SizingGrip = false;
statusLabel.ForeColor = SystemColors.GrayText;
statusLabel.Text = "Idle";
AcceptButton = downloadButton;
AutoScaleDimensions = new SizeF(6f, 13f);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(304, 142);
Controls.Add(tableLayoutPanel);
Controls.Add(statusStrip);
MinimumSize = new Size(190, 140);
ShowIcon = false;
StartPosition = FormStartPosition.CenterScreen;
Text = "GettyImagesDownloader";
tableLayoutPanel.ResumeLayout(false);
tableLayoutPanel.PerformLayout();
statusStrip.ResumeLayout(false);
statusStrip.PerformLayout();
ResumeLayout(false);
PerformLayout();
}
[STAThread]
public static void Main()
{
Application.EnableVisualStyles();
Application.Run(new MainForm());
}
}
}